Scippy

SCIP

Solving Constraint Integer Programs

cons_nonlinear.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB) */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file cons_nonlinear.c
26  * @ingroup DEFPLUGINS_CONS
27  * @brief constraint handler for nonlinear constraints specified by algebraic expressions
28  * @author Ksenia Bestuzheva
29  * @author Benjamin Mueller
30  * @author Felipe Serrano
31  * @author Stefan Vigerske
32  */
33 
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35 
36 #ifdef SCIP_DEBUG
37 #define ENFO_LOGGING
38 #endif
39 
40 /* enable to get log output for enforcement */
41 /* #define ENFO_LOGGING */
42 /* define to get enforcement logging into file */
43 /* #define ENFOLOGFILE "consexpr_enfo.log" */
44 
45 /* define to get more debug output from domain propagation */
46 /* #define DEBUG_PROP */
47 
48 /*lint -e440*/
49 /*lint -e441*/
50 /*lint -e528*/
51 /*lint -e666*/
52 /*lint -e777*/
53 /*lint -e866*/
54 
55 #include <ctype.h>
56 #include "scip/cons_nonlinear.h"
57 #include "scip/nlhdlr.h"
58 #include "scip/expr_var.h"
59 #include "scip/expr_sum.h"
60 #include "scip/expr_value.h"
61 #include "scip/expr_pow.h"
62 #include "scip/nlhdlr_convex.h"
63 #include "scip/cons_linear.h"
64 #include "scip/cons_varbound.h"
65 #include "scip/cons_and.h"
67 #include "scip/heur_subnlp.h"
68 #include "scip/heur_trysol.h"
69 #include "scip/nlpi_ipopt.h" /* for SCIPsolveLinearEquationsIpopt */
70 #include "scip/debug.h"
71 #include "scip/dialog_default.h"
72 
73 
74 /* fundamental constraint handler properties */
75 #define CONSHDLR_NAME "nonlinear"
76 #define CONSHDLR_DESC "handler for nonlinear constraints specified by algebraic expressions"
77 #define CONSHDLR_ENFOPRIORITY -60 /**< priority of the constraint handler for constraint enforcing */
78 #define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
79 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
80  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
81 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
82 
83 /* optional constraint handler properties */
84 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
85 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
86 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
87 
88 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
89 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
90 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
91 
92 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
93 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
94 
95 /* properties of the nonlinear constraint handler statistics table */
96 #define TABLE_NAME_NONLINEAR "cons_nonlinear"
97 #define TABLE_DESC_NONLINEAR "nonlinear constraint handler statistics"
98 #define TABLE_POSITION_NONLINEAR 14600 /**< the position of the statistics table */
99 #define TABLE_EARLIEST_STAGE_NONLINEAR SCIP_STAGE_TRANSFORMED /**< output of the statistics table is only printed from this stage onwards */
101 /* properties of the nonlinear handler statistics table */
102 #define TABLE_NAME_NLHDLR "nlhdlr"
103 #define TABLE_DESC_NLHDLR "nonlinear handler statistics"
104 #define TABLE_POSITION_NLHDLR 14601 /**< the position of the statistics table */
105 #define TABLE_EARLIEST_STAGE_NLHDLR SCIP_STAGE_PRESOLVING /**< output of the statistics table is only printed from this stage onwards */
107 #define DIALOG_NAME "nlhdlrs"
108 #define DIALOG_DESC "display nonlinear handlers"
109 #define DIALOG_ISSUBMENU FALSE
111 #define VERTEXPOLY_MAXPERTURBATION 1e-3 /**< maximum perturbation */
112 #define VERTEXPOLY_USEDUALSIMPLEX TRUE /**< use dual or primal simplex algorithm? */
113 #define VERTEXPOLY_RANDNUMINITSEED 20181029 /**< seed for random number generator, which is used to move points away from the boundary */
114 #define VERTEXPOLY_ADJUSTFACETFACTOR 1e1 /**< adjust resulting facets in checkRikun() up to a violation of this value times lpfeastol */
116 #define BRANCH_RANDNUMINITSEED 20191229 /**< seed for random number generator, which is used to select from several similar good branching candidates */
118 #define BILIN_MAXNAUXEXPRS 10 /**< maximal number of auxiliary expressions per bilinear term */
120 /** translate from one value of infinity to another
121  *
122  * if val is &ge; infty1, then give infty2, else give val
123  */
124 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
126 /** translates x to 2^x for non-negative integer x */
127 #define POWEROFTWO(x) (0x1u << (x))
129 #ifdef ENFO_LOGGING
130 #define ENFOLOG(x) if( SCIPgetSubscipDepth(scip) == 0 && SCIPgetVerbLevel(scip) >= SCIP_VERBLEVEL_NORMAL ) { x }
131 FILE* enfologfile = NULL;
132 #else
133 #define ENFOLOG(x)
134 #endif
135 
136 /*
137  * Data structures
138  */
139 
140 /** enforcement data of an expression */
141 typedef struct
142 {
143  SCIP_NLHDLR* nlhdlr; /**< nonlinear handler */
144  SCIP_NLHDLREXPRDATA* nlhdlrexprdata; /**< data of nonlinear handler */
145  SCIP_NLHDLR_METHOD nlhdlrparticipation; /**< methods where nonlinear handler participates */
146  SCIP_Bool issepainit; /**< was the initsepa callback of nlhdlr called */
147  SCIP_Real auxvalue; /**< auxiliary value of expression w.r.t. currently enforced solution */
148  SCIP_Bool sepabelowusesactivity;/**< whether sepabelow uses activity of some expression */
149  SCIP_Bool sepaaboveusesactivity;/**< whether sepaabove uses activity of some expression */
151 
152 /** data stored by constraint handler in an expression that belongs to a nonlinear constraint */
153 struct SCIP_Expr_OwnerData
154 {
155  SCIP_CONSHDLR* conshdlr; /** nonlinear constraint handler */
156 
157  /* locks and monotonicity */
158  int nlockspos; /**< positive locks counter */
159  int nlocksneg; /**< negative locks counter */
160  SCIP_MONOTONE* monotonicity; /**< array containing monotonicity of expression w.r.t. each child */
161  int monotonicitysize; /**< length of monotonicity array */
162 
163  /* propagation (in addition to activity that is stored in expr) */
164  SCIP_INTERVAL propbounds; /**< bounds to propagate in reverse propagation */
165  unsigned int propboundstag; /**< tag to indicate whether propbounds are valid for the current propagation rounds */
166  SCIP_Bool inpropqueue; /**< whether expression is queued for propagation */
167 
168  /* enforcement of expr == auxvar (or expr <= auxvar, or expr >= auxvar) */
169  EXPRENFO** enfos; /**< enforcements */
170  int nenfos; /**< number of enforcements, or -1 if not initialized */
171  unsigned int lastenforced; /**< last enforcement round where expression was enforced successfully */
172  unsigned int nactivityusesprop; /**< number of nonlinear handlers whose activity computation (or domain propagation) depends on the activity of the expression */
173  unsigned int nactivityusessepa; /**< number of nonlinear handlers whose separation (estimate or enfo) depends on the activity of the expression */
174  unsigned int nauxvaruses; /**< number of nonlinear handlers whose separation uses an auxvar in the expression */
175  SCIP_VAR* auxvar; /**< auxiliary variable used for outer approximation cuts */
176 
177  /* branching */
178  SCIP_Real violscoresum; /**< sum of violation scores for branching stored for this expression */
179  SCIP_Real violscoremax; /**< max of violation scores for branching stored for this expression */
180  int nviolscores; /**< number of violation scores stored for this expression */
181  unsigned int violscoretag; /**< tag to decide whether a violation score of an expression needs to be initialized */
182 
183  /* additional data for variable expressions (TODO move into sub-struct?) */
184  SCIP_CONS** conss; /**< constraints in which this variable appears */
185  int nconss; /**< current number of constraints in conss */
186  int consssize; /**< length of conss array */
187  SCIP_Bool consssorted; /**< is the array of constraints sorted */
188 
189  int filterpos; /**< position of eventdata in SCIP's event filter, -1 if not catching events */
190 };
191 
192 /** constraint data for nonlinear constraints */
193 struct SCIP_ConsData
194 {
195  /* data that defines the constraint: expression and sides */
196  SCIP_EXPR* expr; /**< expression that represents this constraint */
197  SCIP_Real lhs; /**< left-hand side */
198  SCIP_Real rhs; /**< right-hand side */
199 
200  /* variables */
201  SCIP_EXPR** varexprs; /**< array containing all variable expressions */
202  int nvarexprs; /**< total number of variable expressions */
203  SCIP_Bool catchedevents; /**< do we catch events on variables? */
204 
205  /* constraint violation */
206  SCIP_Real lhsviol; /**< violation of left-hand side by current solution */
207  SCIP_Real rhsviol; /**< violation of right-hand side by current solution */
208  SCIP_Real gradnorm; /**< norm of gradient of constraint function in current solution (if evaluated) */
209  SCIP_Longint gradnormsoltag; /**< tag of solution used that gradnorm corresponds to */
210 
211  /* status flags */
212  unsigned int ispropagated:1; /**< did we propagate the current bounds already? */
213  unsigned int issimplified:1; /**< did we simplify the expression tree already? */
214 
215  /* locks */
216  int nlockspos; /**< number of positive locks */
217  int nlocksneg; /**< number of negative locks */
218 
219  /* repair infeasible solutions */
220  SCIP_VAR* linvardecr; /**< variable that may be decreased without making any other constraint infeasible, or NULL if none */
221  SCIP_VAR* linvarincr; /**< variable that may be increased without making any other constraint infeasible, or NULL if none */
222  SCIP_Real linvardecrcoef; /**< linear coefficient of linvardecr */
223  SCIP_Real linvarincrcoef; /**< linear coefficient of linvarincr */
224 
225  /* miscellaneous */
226  SCIP_EXPRCURV curv; /**< curvature of the root expression w.r.t. the original variables */
227  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
228  int consindex; /**< an index of the constraint that is unique among all expr-constraints in this SCIP instance and is constant */
229 };
230 
231 /** constraint upgrade method */
232 typedef struct
233 {
234  SCIP_DECL_NONLINCONSUPGD((*consupgd)); /**< method to call for upgrading nonlinear constraint */
235  int priority; /**< priority of upgrading method */
236  SCIP_Bool active; /**< is upgrading enabled */
238 
239 /** constraint handler data */
240 struct SCIP_ConshdlrData
241 {
242  /* nonlinear handler */
243  SCIP_NLHDLR** nlhdlrs; /**< nonlinear handlers */
244  int nnlhdlrs; /**< number of nonlinear handlers */
245  int nlhdlrssize; /**< size of nlhdlrs array */
246  SCIP_Bool indetect; /**< whether we are currently in detectNlhdlr */
247  SCIP_Bool registerusesactivitysepabelow; /**< a flag that is used only during \ref @detectNlhdlr() */
248  SCIP_Bool registerusesactivitysepaabove; /**< a flag that is used only during \ref @detectNlhdlr() */
249 
250  /* constraint upgrades */
251  CONSUPGRADE** consupgrades; /**< constraint upgrade methods for specializing nonlinear constraints */
252  int consupgradessize; /**< size of consupgrades array */
253  int nconsupgrades; /**< number of constraint upgrade methods */
254 
255  /* other plugins */
256  SCIP_EVENTHDLR* eventhdlr; /**< handler for variable bound change events */
257  SCIP_HEUR* subnlpheur; /**< a pointer to the subnlp heuristic, if available */
258  SCIP_HEUR* trysolheur; /**< a pointer to the trysol heuristic, if available */
259 
260  /* tags and counters */
261  int auxvarid; /**< unique id for the next auxiliary variable */
262  SCIP_Longint curboundstag; /**< tag indicating current variable bounds */
263  SCIP_Longint lastboundrelax; /**< tag when bounds where most recently relaxed */
264  SCIP_Longint lastvaractivitymethodchange; /**< tag when method used to evaluate activity of variables changed last */
265  unsigned int enforound; /**< total number of enforcement calls, including current one */
266  int lastconsindex; /**< last used consindex, plus one */
267 
268  /* activity intervals and domain propagation */
269  SCIP_DECL_EXPR_INTEVALVAR((*intevalvar)); /**< method currently used for activity calculation of variable expressions */
270  SCIP_Bool globalbounds; /**< whether global variable bounds should be used for activity calculation */
271  SCIP_QUEUE* reversepropqueue; /**< expression queue to be used in reverse propagation, filled by SCIPtightenExprIntervalNonlinear */
272  SCIP_Bool forceboundtightening; /**< whether bound change passed to SCIPtightenExprIntervalNonlinear should be forced */
273  unsigned int curpropboundstag; /**< tag indicating current propagation rounds, to match with expr->propboundstag */
274 
275  /* parameters */
276  int maxproprounds; /**< limit on number of propagation rounds for a set of constraints within one round of SCIP propagation */
277  SCIP_Bool propauxvars; /**< whether to check bounds of all auxiliary variable to seed reverse propagation */
278  char varboundrelax; /**< strategy on how to relax variable bounds during bound tightening */
279  SCIP_Real varboundrelaxamount; /**< by how much to relax variable bounds during bound tightening */
280  SCIP_Real conssiderelaxamount; /**< by how much to relax constraint sides during bound tightening */
281  SCIP_Real vp_maxperturb; /**< maximal relative perturbation of reference point */
282  SCIP_Real vp_adjfacetthreshold; /**< adjust computed facet up to a violation of this value times lpfeastol */
283  SCIP_Bool vp_dualsimplex; /**< whether to use dual simplex instead of primal simplex for facet computing LP */
284  SCIP_Bool reformbinprods; /**< whether to reformulate products of binary variables during presolving */
285  SCIP_Bool reformbinprodsand; /**< whether to use the AND constraint handler for reformulating binary products */
286  int reformbinprodsfac; /**< minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled) */
287  SCIP_Bool forbidmultaggrnlvar; /**< whether to forbid multiaggregation of variables that appear in a nonlinear term of a constraint */
288  SCIP_Bool tightenlpfeastol; /**< whether to tighten LP feasibility tolerance during enforcement, if it seems useful */
289  SCIP_Bool propinenforce; /**< whether to (re)run propagation in enforcement */
290  SCIP_Real weakcutthreshold; /**< threshold for when to regard a cut from an estimator as weak */
291  SCIP_Real strongcutmaxcoef; /**< "strong" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef] */
292  SCIP_Bool strongcutefficacy; /**< consider efficacy requirement when deciding whether a cut is "strong" */
293  SCIP_Bool forcestrongcut; /**< whether to force "strong" cuts in enforcement */
294  SCIP_Real enfoauxviolfactor; /**< an expression will be enforced if the "auxiliary" violation is at least enfoauxviolfactor times the "original" violation */
295  SCIP_Real weakcutminviolfactor; /**< retry with weak cuts for constraints with violation at least this factor of maximal violated constraints */
296  char rownotremovable; /**< whether to make rows to be non-removable in the node where they are added (can prevent some cycling): 'o'ff, in 'e'nforcement only, 'a'lways */
297  char violscale; /**< method how to scale violations to make them comparable (not used for feasibility check) */
298  char checkvarlocks; /**< whether variables contained in a single constraint should be forced to be at their lower or upper bounds ('d'isable, change 't'ype, add 'b'ound disjunction) */
299  int branchauxmindepth; /**< from which depth on to allow branching on auxiliary variables */
300  SCIP_Bool branchexternal; /**< whether to use external branching candidates for branching */
301  SCIP_Real branchhighviolfactor; /**< consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints */
302  SCIP_Real branchhighscorefactor; /**< consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables */
303  SCIP_Real branchviolweight; /**< weight by how much to consider the violation assigned to a variable for its branching score */
304  SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
305  SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
306  SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
307  SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
308  char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
309  char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
310  SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
311  char linearizeheursol; /**< whether tight linearizations of nonlinear constraints should be added to cutpool when some heuristics finds a new solution ('o'ff, on new 'i'ncumbents, on 'e'very solution) */
312  SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
313 
314  /* statistics */
315  SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
316  SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
317  SCIP_Longint ndesperatetightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing because we didn't know anything better */
318  SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
319  SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
320  SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
321  SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
322  SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
323 
324  /* facets of envelops of vertex-polyhedral functions */
325  SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
326  SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
327 
328  /* hashing of bilinear terms */
329  SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
330  SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
331  int nbilinterms; /**< total number of bilinear terms */
332  int bilintermssize; /**< size of bilinterms array */
333  int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
334 
335  /* branching */
336  SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
337  char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
338 
339  /* misc */
340  SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
341  SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
342  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
343 };
344 
345 /** branching candidate with various scores */
346 typedef struct
347 {
348  SCIP_EXPR* expr; /**< expression that holds branching candidate */
349  SCIP_Real auxviol; /**< aux-violation score of candidate */
350  SCIP_Real domain; /**< domain score of candidate */
351  SCIP_Real dual; /**< dual score of candidate */
352  SCIP_Real pscost; /**< pseudo-cost score of candidate */
353  SCIP_Real vartype; /**< variable type score of candidate */
354  SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
356 
357 /*
358  * Local methods
359  */
360 
361 /* forward declaration */
362 static
364  SCIP* scip, /**< SCIP data structure */
365  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
366  SCIP_EXPR* rootexpr, /**< expression */
367  SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
368  SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
369  int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
370  );
371 
372 /** frees auxiliary variables of expression, if any */
373 static
375  SCIP* scip, /**< SCIP data structure */
376  SCIP_EXPR* expr /**< expression which auxvar to free, if any */
377  )
378 {
379  SCIP_EXPR_OWNERDATA* mydata;
380 
381  assert(scip != NULL);
382  assert(expr != NULL);
383 
384  mydata = SCIPexprGetOwnerData(expr);
385  assert(mydata != NULL);
386 
387  if( mydata->auxvar == NULL )
388  return SCIP_OKAY;
389 
390  SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
391 
392  /* remove variable locks
393  * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
394  */
395  SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
396 
397  /* release auxiliary variable */
398  SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
399  assert(mydata->auxvar == NULL);
400 
401  return SCIP_OKAY;
402 }
403 
404 /** frees data used for enforcement of expression, that is, nonlinear handlers
405  *
406  * can also clear indicators whether expr needs enforcement methods, that is,
407  * free an associated auxiliary variable and reset the nactivityuses counts
408  */
409 static
411  SCIP* scip, /**< SCIP data structure */
412  SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
413  SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
414  )
415 {
416  SCIP_EXPR_OWNERDATA* mydata;
417  int e;
418 
419  mydata = SCIPexprGetOwnerData(expr);
420  assert(mydata != NULL);
421 
422  if( freeauxvar )
423  {
424  /* free auxiliary variable */
425  SCIP_CALL( freeAuxVar(scip, expr) );
426  assert(mydata->auxvar == NULL);
427 
428  /* reset count on activity and auxvar usage */
429  mydata->nactivityusesprop = 0;
430  mydata->nactivityusessepa = 0;
431  mydata->nauxvaruses = 0;
432  }
433 
434  /* free data stored by nonlinear handlers */
435  for( e = 0; e < mydata->nenfos; ++e )
436  {
437  SCIP_NLHDLR* nlhdlr;
438 
439  assert(mydata->enfos[e] != NULL);
440 
441  nlhdlr = mydata->enfos[e]->nlhdlr;
442  assert(nlhdlr != NULL);
443 
444  if( mydata->enfos[e]->issepainit )
445  {
446  /* call the separation deinitialization callback of the nonlinear handler */
447  SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
448  mydata->enfos[e]->issepainit = FALSE;
449  }
450 
451  /* free nlhdlr exprdata, if there is any and there is a method to free this data */
452  if( mydata->enfos[e]->nlhdlrexprdata != NULL )
453  {
454  SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
455  assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
456  }
457 
458  /* free enfo data */
459  SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
460  }
461 
462  /* free array with enfo data */
463  SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
464 
465  /* we need to look at this expression in detect again */
466  mydata->nenfos = -1;
467 
468  return SCIP_OKAY;
469 }
470 
471 /** callback that frees data that this conshdlr stored in an expression */
472 static
473 SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
474 {
475  assert(scip != NULL);
476  assert(expr != NULL);
477  assert(ownerdata != NULL);
478  assert(*ownerdata != NULL);
479 
480  /* expression should not be locked anymore */
481  assert((*ownerdata)->nlockspos == 0);
482  assert((*ownerdata)->nlocksneg == 0);
483 
484  SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
485 
486  /* expression should not be enforced anymore */
487  assert((*ownerdata)->nenfos <= 0);
488  assert((*ownerdata)->auxvar == NULL);
489 
490  if( SCIPisExprVar(scip, expr) )
491  {
492  SCIP_CONSHDLRDATA* conshdlrdata;
493  SCIP_VAR* var;
494 
495  /* there should be no constraints left that still use this variable */
496  assert((*ownerdata)->nconss == 0);
497  /* thus, there should also be no variable event catched (via this exprhdlr) */
498  assert((*ownerdata)->filterpos == -1);
499 
500  SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
501 
502  /* update var2expr hashmap in conshdlrdata */
503  conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
504  assert(conshdlrdata != NULL);
505 
506  var = SCIPgetVarExprVar(expr);
507  assert(var != NULL);
508 
509  /* remove var -> expr map from hashmap if present
510  * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
511  * if variable-expression stored for var is different, then also do nothing)
512  */
513  if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
514  {
515  SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
516  }
517  }
518 
519  SCIPfreeBlockMemory(scip, ownerdata);
520 
521  return SCIP_OKAY;
522 }
523 
524 static
525 SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
526 { /*lint --e{715}*/
527  assert(ownerdata != NULL);
528 
529  /* print nl handlers associated to expr */
530  if( ownerdata->nenfos > 0 )
531  {
532  int i;
533  SCIPinfoMessage(scip, file, " {");
534 
535  for( i = 0; i < ownerdata->nenfos; ++i )
536  {
537  SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
538  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
539  SCIPinfoMessage(scip, file, "a");
540  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
541  SCIPinfoMessage(scip, file, "u");
542  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
543  SCIPinfoMessage(scip, file, "o");
544  if( i < ownerdata->nenfos-1 )
545  SCIPinfoMessage(scip, file, ", ");
546  }
547 
548  SCIPinfoMessage(scip, file, "}");
549  }
550 
551  /* print aux var associated to expr */
552  if( ownerdata->auxvar != NULL )
553  {
554  SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
555  }
556  SCIPinfoMessage(scip, file, "\n");
557 
558  return SCIP_OKAY;
559 }
560 
561 /** possibly reevaluates and then returns the activity of the expression
562  *
563  * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
564  */
565 static
566 SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
567 {
568  SCIP_CONSHDLRDATA* conshdlrdata;
569 
570  assert(scip != NULL);
571  assert(expr != NULL);
572  assert(ownerdata != NULL);
573 
574  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
575  assert(conshdlrdata != NULL);
576 
577  if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
578  {
579  /* update activity of expression */
580  SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
581 
582  assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
583  }
584 
585  return SCIP_OKAY;
586 }
587 
588 /** callback that creates data that this conshdlr wants to store in an expression */
589 static
590 SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
591 {
592  assert(scip != NULL);
593  assert(expr != NULL);
594  assert(ownerdata != NULL);
595 
596  SCIP_CALL( SCIPallocClearBlockMemory(scip, ownerdata) );
597  (*ownerdata)->nenfos = -1;
598  (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
599 
600  if( SCIPisExprVar(scip, expr) )
601  {
602  SCIP_CONSHDLRDATA* conshdlrdata;
603  SCIP_VAR* var;
604 
605  (*ownerdata)->filterpos = -1;
606 
607  /* add to var2expr hashmap if not having expr for var yet */
608 
609  conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
610  assert(conshdlrdata != NULL);
611 
612  var = SCIPgetVarExprVar(expr);
613 
614  if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
615  {
616  /* store the variable expression in the hashmap */
617  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
618  }
619  else
620  {
621  /* if expr was just created, then it shouldn't already be stored as image of var */
622  assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
623  }
624  }
625  else
626  {
627  /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
628  (*ownerdata)->filterpos = -2;
629  }
630 
631  *ownerfree = exprownerFree;
632  *ownerprint = exprownerPrint;
633  *ownerevalactivity = exprownerEvalactivity;
634 
635  return SCIP_OKAY;
636 }
637 
638 /** creates a variable expression or retrieves from hashmap in conshdlr data */
639 static
641  SCIP* scip, /**< SCIP data structure */
642  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
643  SCIP_EXPR** expr, /**< pointer where to store expression */
644  SCIP_VAR* var /**< variable to be stored */
645  )
646 {
647  assert(conshdlr != NULL);
648  assert(expr != NULL);
649  assert(var != NULL);
650 
651  /* get variable expression representing the given variable if there is one already */
652  *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
653 
654  if( *expr == NULL )
655  {
656  /* create a new variable expression; this also captures the expression */
657  SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
658  assert(*expr != NULL);
659  /* exprownerCreate should have added var->expr to var2expr */
660  assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
661  }
662  else
663  {
664  /* only capture already existing expr to get a consistent uses-count */
665  SCIPcaptureExpr(*expr);
666  }
667 
668  return SCIP_OKAY;
669 }
670 
671 /* map var exprs to var-expr from var2expr hashmap */
672 static
673 SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
674 { /*lint --e{715}*/
675  SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
676 
677  assert(sourcescip != NULL);
678  assert(targetscip != NULL);
679  assert(sourceexpr != NULL);
680  assert(targetexpr != NULL);
681  assert(*targetexpr == NULL);
682  assert(mapexprdata != NULL);
683 
684  /* do not provide map if not variable */
685  if( !SCIPisExprVar(sourcescip, sourceexpr) )
686  return SCIP_OKAY;
687 
688  SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
689 
690  return SCIP_OKAY;
691 }
692 
693 /* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
694 static
695 SCIP_DECL_EXPR_MAPEXPR(mapexprtransvar)
696 { /*lint --e{715}*/
697  SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
698  SCIP_VAR* var;
699 
700  assert(sourcescip != NULL);
701  assert(targetscip != NULL);
702  assert(sourceexpr != NULL);
703  assert(targetexpr != NULL);
704  assert(*targetexpr == NULL);
705  assert(mapexprdata != NULL);
706 
707  /* do not provide map if not variable */
708  if( !SCIPisExprVar(sourcescip, sourceexpr) )
709  return SCIP_OKAY;
710 
711  var = SCIPgetVarExprVar(sourceexpr);
712  assert(var != NULL);
713 
714  /* transform variable */
715  SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
716  assert(var != NULL);
717 
718  SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
719 
720  return SCIP_OKAY;
721 }
722 
723 /** stores all variable expressions into a given constraint */
724 static
726  SCIP* scip, /**< SCIP data structure */
727  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
728  SCIP_CONSDATA* consdata /**< constraint data */
729  )
730 {
731  SCIP_CONSHDLRDATA* conshdlrdata;
732  int varexprssize;
733  int i;
734 
735  assert(consdata != NULL);
736 
737  /* skip if we have stored the variable expressions already */
738  if( consdata->varexprs != NULL )
739  return SCIP_OKAY;
740 
741  assert(consdata->varexprs == NULL);
742  assert(consdata->nvarexprs == 0);
743 
744  /* get an upper bound on number of variable expressions */
745  if( consdata->issimplified )
746  {
747  /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
748  * so we cannot have more variable expression than the number of active variables
749  */
750  varexprssize = SCIPgetNVars(scip);
751  }
752  else
753  {
754  SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
755  }
756 
757  /* create array to store all variable expressions */
758  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
759 
760  SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
761  assert(varexprssize >= consdata->nvarexprs);
762 
763  /* shrink array if there are less variables in the expression than in the problem */
764  if( varexprssize > consdata->nvarexprs )
765  {
766  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
767  }
768 
769  conshdlrdata = SCIPconshdlrGetData(conshdlr);
770  assert(conshdlrdata != NULL);
771  assert(conshdlrdata->var2expr != NULL);
772 
773  /* ensure that for every variable an entry exists in the var2expr hashmap
774  * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
775  */
776  for( i = 0; i < consdata->nvarexprs; ++i )
777  {
778  if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
779  {
780  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
781  }
782  }
783 
784  return SCIP_OKAY;
785 }
786 
787 /** frees all variable expression stored in storeVarExprs() */
788 static
790  SCIP* scip, /**< SCIP data structure */
791  SCIP_CONSDATA* consdata /**< constraint data */
792  )
793 {
794  int i;
795 
796  assert(consdata != NULL);
797 
798  /* skip if we have stored the variable expressions already*/
799  if( consdata->varexprs == NULL )
800  return SCIP_OKAY;
801 
802  assert(consdata->varexprs != NULL);
803  assert(consdata->nvarexprs >= 0);
804 
805  /* release variable expressions */
806  for( i = 0; i < consdata->nvarexprs; ++i )
807  {
808  assert(consdata->varexprs[i] != NULL);
809  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
810  assert(consdata->varexprs[i] == NULL);
811  }
812 
813  /* free variable expressions */
814  SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
815  consdata->varexprs = NULL;
816  consdata->nvarexprs = 0;
817 
818  return SCIP_OKAY;
819 }
820 
821 /** interval evaluation of variables as used in bound tightening
822  *
823  * Returns slightly relaxed local variable bounds of a variable as interval.
824  * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
825  */
826 static
827 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
828 {
829  SCIP_INTERVAL interval;
830  SCIP_CONSHDLRDATA* conshdlrdata;
831  SCIP_Real lb;
832  SCIP_Real ub;
833 
834  assert(scip != NULL);
835  assert(var != NULL);
836 
837  conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
838  assert(conshdlrdata != NULL);
839 
840  if( conshdlrdata->globalbounds )
841  {
842  lb = SCIPvarGetLbGlobal(var);
843  ub = SCIPvarGetUbGlobal(var);
844  }
845  else
846  {
847  lb = SCIPvarGetLbLocal(var);
848  ub = SCIPvarGetUbLocal(var);
849  }
850  assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
851 
852  /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
854  {
855  lb = EPSROUND(lb, 0.0); /*lint !e835*/
856  ub = EPSROUND(ub, 0.0); /*lint !e835*/
857  }
858 
859  /* integer variables should always have integral bounds in SCIP */
860  assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
861  assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
862 
863  switch( conshdlrdata->varboundrelax )
864  {
865  case 'n' : /* no relaxation */
866  break;
867 
868  case 'a' : /* relax by absolute value */
869  {
870  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
871  if( SCIPvarIsIntegral(var) )
872  break;
873 
874  if( !SCIPisInfinity(scip, -lb) )
875  {
876  /* reduce lb by epsilon, or to the next integer value, which ever is larger */
877  SCIP_Real bnd = floor(lb);
878  lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
879  }
880 
881  if( !SCIPisInfinity(scip, ub) )
882  {
883  /* increase ub by epsilon, or to the next integer value, which ever is smaller */
884  SCIP_Real bnd = ceil(ub);
885  ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
886  }
887 
888  break;
889  }
890 
891  case 'b' : /* relax always by absolute value */
892  {
893  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
894  if( SCIPvarIsIntegral(var) )
895  break;
896 
897  if( !SCIPisInfinity(scip, -lb) )
898  lb -= conshdlrdata->varboundrelaxamount;
899 
900  if( !SCIPisInfinity(scip, ub) )
901  ub += conshdlrdata->varboundrelaxamount;
902 
903  break;
904  }
905 
906  case 'r' : /* relax by relative value */
907  {
908  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
909  if( SCIPvarIsIntegral(var) )
910  break;
911 
912  /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
913  * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
914  * further, do not relax beyond next integer value
915  */
916  if( !SCIPisInfinity(scip, -lb) )
917  {
918  SCIP_Real bnd = floor(lb);
919  lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
920  }
921 
922  if( !SCIPisInfinity(scip, ub) )
923  {
924  SCIP_Real bnd = ceil(ub);
925  ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
926  }
927 
928  break;
929  }
930 
931  default :
932  {
933  SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
934  SCIPABORT();
935  break;
936  }
937  }
938 
939  /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
942  assert(lb <= ub);
943 
944  SCIPintervalSetBounds(&interval, lb, ub);
945 
946  return interval;
947 }
948 
949 /** compares two nonlinear constraints by its index
950  *
951  * Usable as compare operator in array sort functions.
952  */
953 static
954 SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
955 {
956  SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
957  SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
958 
959  assert(consdata1 != NULL);
960  assert(consdata2 != NULL);
961 
962  return consdata1->consindex - consdata2->consindex;
963 }
964 
965 /** processes variable fixing or bound change event */
966 static
967 SCIP_DECL_EVENTEXEC(processVarEvent)
968 { /*lint --e{715}*/
969  SCIP_EVENTTYPE eventtype;
970  SCIP_EXPR* expr;
971  SCIP_EXPR_OWNERDATA* ownerdata;
972 
973  eventtype = SCIPeventGetType(event);
975 
976  assert(eventdata != NULL);
977  expr = (SCIP_EXPR*) eventdata;
978  assert(SCIPisExprVar(scip, expr));
979 
980  SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
984 
985  ownerdata = SCIPexprGetOwnerData(expr);
986  assert(ownerdata != NULL);
987  /* we only catch varevents for variables in constraints, so there should be constraints */
988  assert(ownerdata->nconss > 0);
989  assert(ownerdata->conss != NULL);
990 
991  /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
992  * - propagation can only find something new if a bound was tightened
993  * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
994  * and we look at global changes (that is, we are not looking at boundchanges in probing)
995  */
997  {
998  SCIP_CONSDATA* consdata;
999  int c;
1000 
1001  for( c = 0; c < ownerdata->nconss; ++c )
1002  {
1003  assert(ownerdata->conss[c] != NULL);
1004  consdata = SCIPconsGetData(ownerdata->conss[c]);
1005 
1006  /* if bound tightening, then mark constraints to be propagated again
1007  * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1008  * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1009  * the locks don't help since they are not available separately for each constraint
1010  */
1011  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1012  {
1013  consdata->ispropagated = FALSE;
1014  SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1015  }
1016 
1017  /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1018  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !SCIPinProbing(scip) )
1019  {
1020  consdata->issimplified = FALSE;
1021  SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1022  }
1023  }
1024  }
1025 
1026  /* update curboundstag, lastboundrelax, and expr activity */
1027  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
1028  {
1029  SCIP_CONSHDLRDATA* conshdlrdata;
1030  SCIP_INTERVAL activity;
1031 
1032  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1033  assert(conshdlrdata != NULL);
1034 
1035  /* increase tag on bounds */
1036  ++conshdlrdata->curboundstag;
1037  assert(conshdlrdata->curboundstag > 0);
1038 
1039  /* remember also if we relaxed bounds now */
1040  if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1041  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1042 
1043  /* update the activity of the var-expr here immediately
1044  * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1045  */
1046  SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1047  /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1048 #ifdef DEBUG_PROP
1049  SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1050 #endif
1051  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1052  }
1053 
1054  return SCIP_OKAY;
1055 }
1056 
1057 /** registers event handler to catch variable events on variable
1058  *
1059  * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1060  * When an event occurs, all stored constraints are notified.
1061  */
1062 static
1064  SCIP* scip, /**< SCIP data structure */
1065  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1066  SCIP_EXPR* expr, /**< variable expression */
1067  SCIP_CONS* cons /**< nonlinear constraint */
1068  )
1069 {
1070  SCIP_EXPR_OWNERDATA* ownerdata;
1071 
1072  assert(eventhdlr != NULL);
1073  assert(expr != NULL);
1074  assert(SCIPisExprVar(scip, expr));
1075  assert(cons != NULL);
1076 
1077  ownerdata = SCIPexprGetOwnerData(expr);
1078  assert(ownerdata != NULL);
1079 
1080 #ifndef NDEBUG
1081  /* assert that constraint does not double-catch variable */
1082  {
1083  int i;
1084  for( i = 0; i < ownerdata->nconss; ++i )
1085  assert(ownerdata->conss[i] != cons);
1086  }
1087 #endif
1088 
1089  /* append cons to ownerdata->conss */
1090  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1091  ownerdata->conss[ownerdata->nconss++] = cons;
1092  /* we're not capturing the constraint here to avoid circular references */
1093 
1094  /* updated sorted flag */
1095  if( ownerdata->nconss <= 1 )
1096  ownerdata->consssorted = TRUE;
1097  else if( ownerdata->consssorted )
1098  ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1099 
1100  /* catch variable events, if not done so yet (first constraint) */
1101  if( ownerdata->filterpos < 0 )
1102  {
1103  SCIP_EVENTTYPE eventtype;
1104 
1105  assert(ownerdata->nconss == 1);
1106 
1108 
1109  SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1110  assert(ownerdata->filterpos >= 0);
1111  }
1112 
1113  return SCIP_OKAY;
1114 }
1115 
1116 /** catch variable events */
1117 static
1119  SCIP* scip, /**< SCIP data structure */
1120  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1121  SCIP_CONS* cons /**< constraint for which to catch bound change events */
1122  )
1123 {
1124  SCIP_CONSHDLRDATA* conshdlrdata;
1125  SCIP_CONSDATA* consdata;
1126  SCIP_EXPR* expr;
1127  int i;
1128 
1129  assert(eventhdlr != NULL);
1130  assert(cons != NULL);
1131 
1132  consdata = SCIPconsGetData(cons);
1133  assert(consdata != NULL);
1134  assert(consdata->varexprs != NULL);
1135  assert(consdata->nvarexprs >= 0);
1136 
1137  /* check if we have catched variable events already */
1138  if( consdata->catchedevents )
1139  return SCIP_OKAY;
1140 
1141  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1142  assert(conshdlrdata != NULL);
1143 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1144  assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1145 #endif
1146 
1147  SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1148 
1149  for( i = 0; i < consdata->nvarexprs; ++i )
1150  {
1151  expr = consdata->varexprs[i];
1152 
1153  assert(expr != NULL);
1154  assert(SCIPisExprVar(scip, expr));
1155 
1156  SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1157 
1158  /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1159  * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1160  */
1161  if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1162  {
1163  SCIP_INTERVAL activity;
1164  SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1165  /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1166  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1167 #ifdef DEBUG_PROP
1168  SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1169 #endif
1170  }
1171  }
1172 
1173  consdata->catchedevents = TRUE;
1174 
1175  return SCIP_OKAY;
1176 }
1177 
1178 /** unregisters event handler to catch variable events on variable
1179  *
1180  * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1181  * If this was the last constraint, then the event handler is unregistered for this variable.
1182  */
1183 static
1185  SCIP* scip, /**< SCIP data structure */
1186  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1187  SCIP_EXPR* expr, /**< variable expression */
1188  SCIP_CONS* cons /**< expr constraint */
1189  )
1190 {
1191  SCIP_EXPR_OWNERDATA* ownerdata;
1192  int pos;
1193 
1194  assert(eventhdlr != NULL);
1195  assert(expr != NULL);
1196  assert(SCIPisExprVar(scip, expr));
1197  assert(cons != NULL);
1198 
1199  ownerdata = SCIPexprGetOwnerData(expr);
1200  assert(ownerdata != NULL);
1201  assert(ownerdata->nconss > 0);
1202 
1203  if( ownerdata->conss[ownerdata->nconss-1] == cons )
1204  {
1205  pos = ownerdata->nconss-1;
1206  }
1207  else
1208  {
1209  if( !ownerdata->consssorted )
1210  {
1211  SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1212  ownerdata->consssorted = TRUE;
1213  }
1214 
1215  if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1216  {
1217  SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1218  return SCIP_ERROR;
1219  }
1220  assert(pos >= 0 && pos < ownerdata->nconss);
1221  }
1222  assert(ownerdata->conss[pos] == cons);
1223 
1224  /* move last constraint into position of removed constraint */
1225  if( pos < ownerdata->nconss-1 )
1226  {
1227  ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1228  ownerdata->consssorted = FALSE;
1229  }
1230  --ownerdata->nconss;
1231 
1232  /* drop variable events if that was the last constraint */
1233  if( ownerdata->nconss == 0 )
1234  {
1235  SCIP_EVENTTYPE eventtype;
1236 
1237  assert(ownerdata->filterpos >= 0);
1238 
1240 
1241  SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1242  ownerdata->filterpos = -1;
1243  }
1244 
1245  return SCIP_OKAY;
1246 }
1247 
1248 /** drop variable events */
1249 static
1251  SCIP* scip, /**< SCIP data structure */
1252  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1253  SCIP_CONS* cons /**< constraint for which to drop bound change events */
1254  )
1255 {
1256  SCIP_CONSDATA* consdata;
1257  int i;
1258 
1259  assert(eventhdlr != NULL);
1260  assert(cons != NULL);
1261 
1262  consdata = SCIPconsGetData(cons);
1263  assert(consdata != NULL);
1264 
1265  /* check if we have catched variable events already */
1266  if( !consdata->catchedevents )
1267  return SCIP_OKAY;
1268 
1269  assert(consdata->varexprs != NULL);
1270  assert(consdata->nvarexprs >= 0);
1271 
1272  SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1273 
1274  for( i = consdata->nvarexprs - 1; i >= 0; --i )
1275  {
1276  assert(consdata->varexprs[i] != NULL);
1277 
1278  SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1279  }
1280 
1281  consdata->catchedevents = FALSE;
1282 
1283  return SCIP_OKAY;
1284 }
1285 
1286 /** creates and captures a nonlinear constraint
1287  *
1288  * @attention Use copyexpr=FALSE only if expr is already "owned" by conshdlr, that is, if expressions were created with exprownerCreate() and ownerdata passed in the last two arguments
1289  */
1290 static
1292  SCIP* scip, /**< SCIP data structure */
1293  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1294  SCIP_CONS** cons, /**< pointer to hold the created constraint */
1295  const char* name, /**< name of constraint */
1296  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1297  SCIP_Real lhs, /**< left hand side of constraint */
1298  SCIP_Real rhs, /**< right hand side of constraint */
1299  SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1300  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1301  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1302  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1303  * Usually set to TRUE. */
1304  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1305  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1306  SCIP_Bool check, /**< should the constraint be checked for feasibility?
1307  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1308  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1309  * Usually set to TRUE. */
1310  SCIP_Bool local, /**< is constraint only valid locally?
1311  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1312  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1313  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1314  * adds coefficients to this constraint. */
1315  SCIP_Bool dynamic, /**< is constraint subject to aging?
1316  * Usually set to FALSE. Set to TRUE for own cuts which
1317  * are separated as constraints. */
1318  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1319  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1320  )
1321 {
1322  SCIP_CONSHDLRDATA* conshdlrdata;
1323  SCIP_CONSDATA* consdata;
1324 
1325  assert(conshdlr != NULL);
1326  assert(expr != NULL);
1327 
1328  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1329  assert(conshdlrdata != NULL);
1330 
1331  if( local && SCIPgetDepth(scip) != 0 )
1332  {
1333  SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1334  return SCIP_INVALIDCALL;
1335  }
1336 
1337  /* TODO we should allow for non-initial nonlinear constraints */
1338  if( !initial )
1339  {
1340  SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1341  return SCIP_INVALIDCALL;
1342  }
1343 
1344  /* create constraint data */
1345  SCIP_CALL( SCIPallocClearBlockMemory(scip, &consdata) );
1346 
1347  if( copyexpr )
1348  {
1349  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1350  SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1351  }
1352  else
1353  {
1354  consdata->expr = expr;
1355  SCIPcaptureExpr(consdata->expr);
1356  }
1357  consdata->lhs = lhs;
1358  consdata->rhs = rhs;
1359  consdata->consindex = conshdlrdata->lastconsindex++;
1360  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1361 
1362  /* create constraint */
1363  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1364  local, modifiable, dynamic, removable, FALSE) );
1365 
1366  return SCIP_OKAY;
1367 }
1368 
1369 /** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1370  *
1371  * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1372  * Assume that f(x) is associated with auxiliary variable z.
1373  *
1374  * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1375  * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1376  * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1377  * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1378  *
1379  * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1380  */
1381 static
1383  SCIP* scip, /**< SCIP data structure */
1384  SCIP_EXPR* expr, /**< expression */
1385  SCIP_SOL* sol, /**< solution that has been evaluated */
1386  SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1387  SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1388  )
1389 {
1390  SCIP_EXPR_OWNERDATA* ownerdata;
1391  SCIP_Real auxvarvalue;
1392 
1393  assert(expr != NULL);
1394 
1395  ownerdata = SCIPexprGetOwnerData(expr);
1396  assert(ownerdata != NULL);
1397  assert(ownerdata->auxvar != NULL);
1398 
1399  if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1400  {
1401  if( violunder != NULL )
1402  *violunder = TRUE;
1403  if( violover != NULL )
1404  *violover = TRUE;
1405  return SCIPinfinity(scip);
1406  }
1407 
1408  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1409 
1410  if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1411  {
1412  if( violunder != NULL )
1413  *violunder = FALSE;
1414  if( violover != NULL )
1415  *violover = TRUE;
1416  return auxvarvalue - SCIPexprGetEvalValue(expr);
1417  }
1418 
1419  if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1420  {
1421  if( violunder != NULL )
1422  *violunder = TRUE;
1423  if( violover != NULL )
1424  *violover = FALSE;
1425  return SCIPexprGetEvalValue(expr) - auxvarvalue;
1426  }
1427 
1428  if( violunder != NULL )
1429  *violunder = FALSE;
1430  if( violover != NULL )
1431  *violover = FALSE;
1432  return 0.0;
1433 }
1434 
1435 /** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1436  *
1437  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1438  * Assume that f(w) is associated with auxiliary variable z.
1439  *
1440  * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1441  * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1442  * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1443  * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1444  *
1445  * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1446  */
1447 static
1449  SCIP* scip, /**< SCIP data structure */
1450  SCIP_EXPR* expr, /**< expression */
1451  SCIP_Real auxvalue, /**< value of f(w) */
1452  SCIP_SOL* sol, /**< solution that has been evaluated */
1453  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1454  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1455  )
1456 {
1457  SCIP_EXPR_OWNERDATA* ownerdata;
1458  SCIP_Real auxvarvalue;
1459 
1460  assert(expr != NULL);
1461 
1462  ownerdata = SCIPexprGetOwnerData(expr);
1463  assert(ownerdata != NULL);
1464  assert(ownerdata->auxvar != NULL);
1465 
1466  if( auxvalue == SCIP_INVALID )
1467  {
1468  if( violunder != NULL )
1469  *violunder = TRUE;
1470  if( violover != NULL )
1471  *violover = TRUE;
1472  return SCIPinfinity(scip);
1473  }
1474 
1475  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1476 
1477  if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1478  {
1479  if( violunder != NULL )
1480  *violunder = FALSE;
1481  if( violover != NULL )
1482  *violover = TRUE;
1483  return auxvarvalue - auxvalue;
1484  }
1485 
1486  if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1487  {
1488  if( violunder != NULL )
1489  *violunder = TRUE;
1490  if( violover != NULL )
1491  *violover = FALSE;
1492  return auxvalue - auxvarvalue;
1493  }
1494 
1495  if( violunder != NULL )
1496  *violunder = FALSE;
1497  if( violover != NULL )
1498  *violover = FALSE;
1499 
1500  return 0.0;
1501 }
1502 
1503 /** computes violation of a constraint */
1504 static
1506  SCIP* scip, /**< SCIP data structure */
1507  SCIP_CONS* cons, /**< constraint */
1508  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1509  SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1510  )
1511 {
1512  SCIP_CONSDATA* consdata;
1513  SCIP_Real activity;
1514 
1515  assert(scip != NULL);
1516  assert(cons != NULL);
1517 
1518  consdata = SCIPconsGetData(cons);
1519  assert(consdata != NULL);
1520 
1521  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1522  activity = SCIPexprGetEvalValue(consdata->expr);
1523 
1524  /* consider constraint as violated if it is undefined in the current point */
1525  if( activity == SCIP_INVALID )
1526  {
1527  consdata->lhsviol = SCIPinfinity(scip);
1528  consdata->rhsviol = SCIPinfinity(scip);
1529  return SCIP_OKAY;
1530  }
1531 
1532  /* compute violations */
1533  consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1534  consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1535 
1536  return SCIP_OKAY;
1537 }
1538 
1539 /** returns absolute violation of a constraint
1540  *
1541  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1542  */
1543 static
1545  SCIP_CONS* cons /**< constraint */
1546  )
1547 {
1548  SCIP_CONSDATA* consdata;
1549 
1550  assert(cons != NULL);
1551 
1552  consdata = SCIPconsGetData(cons);
1553  assert(consdata != NULL);
1554 
1555  return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1556 }
1557 
1558 /** computes relative violation of a constraint
1559  *
1560  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1561  */
1562 static
1564  SCIP* scip, /**< SCIP data structure */
1565  SCIP_CONS* cons, /**< constraint */
1566  SCIP_Real* viol, /**< buffer to store violation */
1567  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1568  SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1569  )
1570 {
1571  SCIP_CONSHDLR* conshdlr;
1572  SCIP_CONSHDLRDATA* conshdlrdata;
1573  SCIP_CONSDATA* consdata;
1574  SCIP_Real scale;
1575 
1576  assert(cons != NULL);
1577  assert(viol != NULL);
1578 
1579  conshdlr = SCIPconsGetHdlr(cons);
1580  assert(conshdlr != NULL);
1581 
1582  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1583  assert(conshdlrdata != NULL);
1584 
1585  *viol = getConsAbsViolation(cons);
1586 
1587  if( conshdlrdata->violscale == 'n' )
1588  return SCIP_OKAY;
1589 
1590  if( SCIPisInfinity(scip, *viol) )
1591  return SCIP_OKAY;
1592 
1593  consdata = SCIPconsGetData(cons);
1594  assert(consdata != NULL);
1595 
1596  if( conshdlrdata->violscale == 'a' )
1597  {
1598  scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1599 
1600  /* consider value of side that is violated for scaling, too */
1601  if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1602  {
1603  assert(!SCIPisInfinity(scip, -consdata->lhs));
1604  scale = REALABS(consdata->lhs);
1605  }
1606  else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1607  {
1608  assert(!SCIPisInfinity(scip, consdata->rhs));
1609  scale = REALABS(consdata->rhs);
1610  }
1611 
1612  *viol /= scale;
1613  return SCIP_OKAY;
1614  }
1615 
1616  /* if not 'n' or 'a', then it has to be 'g' at the moment */
1617  assert(conshdlrdata->violscale == 'g');
1618  if( soltag == 0L || consdata->gradnormsoltag != soltag )
1619  {
1620  /* we need the varexprs to conveniently access the gradient */
1621  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1622 
1623  /* update cached value of norm of gradient */
1624  consdata->gradnorm = 0.0;
1625 
1626  /* compute gradient */
1627  SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1628 
1629  /* gradient evaluation error -> no scaling */
1630  if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1631  {
1632  int i;
1633  for( i = 0; i < consdata->nvarexprs; ++i )
1634  {
1635  SCIP_Real deriv;
1636 
1637  assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1638  deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1639  if( deriv == SCIP_INVALID )
1640  {
1641  /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1642  consdata->gradnorm = 0.0;
1643  break;
1644  }
1645 
1646  consdata->gradnorm += deriv*deriv;
1647  }
1648  }
1649  consdata->gradnorm = sqrt(consdata->gradnorm);
1650  consdata->gradnormsoltag = soltag;
1651  }
1652 
1653  *viol /= MAX(1.0, consdata->gradnorm);
1654 
1655  return SCIP_OKAY;
1656 }
1657 
1658 /** returns whether constraint is currently violated
1659  *
1660  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1661  */
1662 static
1664  SCIP* scip, /**< SCIP data structure */
1665  SCIP_CONS* cons /**< constraint */
1666  )
1667 {
1668  return getConsAbsViolation(cons) > SCIPfeastol(scip);
1669 }
1670 
1671 /** checks for a linear variable that can be increased or decreased without harming feasibility */
1672 static
1674  SCIP* scip, /**< SCIP data structure */
1675  SCIP_CONS* cons /**< constraint */
1676  )
1677 {
1678  SCIP_CONSDATA* consdata;
1679  int poslock;
1680  int neglock;
1681  int i;
1682 
1683  assert(cons != NULL);
1684 
1685  consdata = SCIPconsGetData(cons);
1686  assert(consdata != NULL);
1687 
1688  consdata->linvarincr = NULL;
1689  consdata->linvardecr = NULL;
1690  consdata->linvarincrcoef = 0.0;
1691  consdata->linvardecrcoef = 0.0;
1692 
1693  /* root expression is not a sum -> no unlocked linear variable available */
1694  if( !SCIPisExprSum(scip, consdata->expr) )
1695  return;
1696 
1697  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1698  {
1699  SCIP_EXPR* child;
1700 
1701  child = SCIPexprGetChildren(consdata->expr)[i];
1702  assert(child != NULL);
1703 
1704  /* check whether the child is a variable expression */
1705  if( SCIPisExprVar(scip, child) )
1706  {
1707  SCIP_VAR* var = SCIPgetVarExprVar(child);
1708  SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1709 
1710  if( coef > 0.0 )
1711  {
1712  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1713  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1714  }
1715  else
1716  {
1717  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1718  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1719  }
1721 
1722  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1723  {
1724  /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1725  * if we have already one candidate, then take the one where the loss in the objective function is less
1726  */
1727  if( (consdata->linvardecr == NULL) ||
1728  (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1729  {
1730  consdata->linvardecr = var;
1731  consdata->linvardecrcoef = coef;
1732  }
1733  }
1734 
1735  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1736  {
1737  /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1738  * if we have already one candidate, then take the one where the loss in the objective function is less
1739  */
1740  if( (consdata->linvarincr == NULL) ||
1741  (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1742  {
1743  consdata->linvarincr = var;
1744  consdata->linvarincrcoef = coef;
1745  }
1746  }
1747  }
1748  }
1749 
1750  assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1751  assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1752 
1753  if( consdata->linvarincr != NULL )
1754  {
1755  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1756  }
1757  if( consdata->linvardecr != NULL )
1758  {
1759  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1760  }
1761 }
1762 
1763 /** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1764  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1765  *
1766  * The method assumes that this is always possible and that not all constraints are feasible already.
1767  */
1768 static
1770  SCIP* scip, /**< SCIP data structure */
1771  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1772  SCIP_CONS** conss, /**< constraints to process */
1773  int nconss, /**< number of constraints */
1774  SCIP_SOL* sol, /**< solution to process */
1775  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1776  )
1777 {
1778  SCIP_CONSHDLRDATA* conshdlrdata;
1779  SCIP_SOL* newsol;
1780  int c;
1781 
1782  assert(scip != NULL);
1783  assert(conshdlr != NULL);
1784  assert(conss != NULL || nconss == 0);
1785  assert(success != NULL);
1786 
1787  *success = FALSE;
1788 
1789  /* don't propose new solutions if not in presolve or solving */
1791  return SCIP_OKAY;
1792 
1793  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1794  assert(conshdlrdata != NULL);
1795 
1796  if( sol != NULL )
1797  {
1798  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1799  }
1800  else
1801  {
1802  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1803  }
1804  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1805  SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1806  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1807 
1808  for( c = 0; c < nconss; ++c )
1809  {
1810  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1811  SCIP_Real viol = 0.0;
1812  SCIP_Real delta;
1813  SCIP_Real gap;
1814 
1815  assert(consdata != NULL);
1816 
1817  /* get absolute violation and sign */
1818  if( consdata->lhsviol > SCIPfeastol(scip) )
1819  viol = consdata->lhsviol; /* lhs - activity */
1820  else if( consdata->rhsviol > SCIPfeastol(scip) )
1821  viol = -consdata->rhsviol; /* rhs - activity */
1822  else
1823  continue; /* constraint is satisfied */
1824 
1825  if( consdata->linvarincr != NULL &&
1826  ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1827  {
1828  SCIP_VAR* var = consdata->linvarincr;
1829 
1830  /* compute how much we would like to increase var */
1831  delta = viol / consdata->linvarincrcoef;
1832  assert(delta > 0.0);
1833 
1834  /* if var has an upper bound, may need to reduce delta */
1835  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
1836  {
1837  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1838  delta = MIN(MAX(0.0, gap), delta);
1839  }
1840  if( SCIPisPositive(scip, delta) )
1841  {
1842  /* if variable is integral, round delta up so that it will still have an integer value */
1843  if( SCIPvarIsIntegral(var) )
1844  delta = SCIPceil(scip, delta);
1845 
1846  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1847  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1848  SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1849 
1850  /* adjust constraint violation, if satisfied go on to next constraint */
1851  viol -= consdata->linvarincrcoef * delta;
1852  if( SCIPisZero(scip, viol) )
1853  continue;
1854  }
1855  }
1856 
1857  assert(viol != 0.0);
1858  if( consdata->linvardecr != NULL &&
1859  ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1860  {
1861  SCIP_VAR* var = consdata->linvardecr;
1862 
1863  /* compute how much we would like to decrease var */
1864  delta = viol / consdata->linvardecrcoef;
1865  assert(delta < 0.0);
1866 
1867  /* if var has a lower bound, may need to reduce delta */
1868  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
1869  {
1870  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1871  delta = MAX(MIN(0.0, gap), delta);
1872  }
1873  if( SCIPisNegative(scip, delta) )
1874  {
1875  /* if variable is integral, round delta down so that it will still have an integer value */
1876  if( SCIPvarIsIntegral(var) )
1877  delta = SCIPfloor(scip, delta);
1878  SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1879  /*lint --e{613} */
1880  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1881  SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1882 
1883  /* adjust constraint violation, if satisfied go on to next constraint */
1884  viol -= consdata->linvardecrcoef * delta;
1885  if( SCIPisZero(scip, viol) )
1886  continue;
1887  }
1888  }
1889 
1890  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1891  break;
1892  }
1893 
1894  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1895  * then pass it to the trysol heuristic
1896  */
1897  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
1898  {
1899  SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1900 
1901  assert(conshdlrdata->trysolheur != NULL);
1902  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1903 
1904  *success = TRUE;
1905  }
1906 
1907  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1908 
1909  return SCIP_OKAY;
1910 }
1911 
1912 /** adds globally valid tight estimators in a given solution as cut to cutpool
1913  *
1914  * Called by addTightEstimatorCuts() for a specific expression, nlhdlr, and estimate-direction (over or under).
1915  */
1916 static
1918  SCIP* scip, /**< SCIP data structure */
1919  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1920  SCIP_CONS* cons, /**< constraint */
1921  SCIP_EXPR* expr, /**< expression */
1922  EXPRENFO* exprenfo, /**< expression enfo data, e.g., nlhdlr to use */
1923  SCIP_SOL* sol, /**< reference point where to estimate */
1924  SCIP_Bool overestimate, /**< whether to overestimate */
1925  SCIP_PTRARRAY* rowpreps /**< array for rowpreps */
1926  )
1927 {
1928  SCIP_Bool estimatesuccess = FALSE;
1929  SCIP_Bool branchscoresuccess = FALSE;
1930  int minidx;
1931  int maxidx;
1932  int r;
1933 
1934  assert(scip != NULL);
1935  assert(expr != NULL);
1936  assert(exprenfo != NULL);
1937  assert(rowpreps != NULL);
1938 
1939  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %sestimate using nlhdlr <%s> for expr %p (%s)\n",
1940  overestimate ? "over" : "under", SCIPnlhdlrGetName(exprenfo->nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr))); )
1941 
1942  SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, exprenfo->nlhdlr, expr, exprenfo->nlhdlrexprdata, sol,
1943  exprenfo->auxvalue, overestimate, overestimate ? SCIPinfinity(scip) : -SCIPinfinity(scip), FALSE, rowpreps, &estimatesuccess, &branchscoresuccess) );
1944 
1945  minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
1946  maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
1947  assert(estimatesuccess == (minidx <= maxidx));
1948 
1949  if( !estimatesuccess )
1950  {
1951  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n", SCIPnlhdlrGetName(exprenfo->nlhdlr)); )
1952  return SCIP_OKAY;
1953  }
1954 
1955  for( r = minidx; r <= maxidx; ++r )
1956  {
1957  SCIP_ROWPREP* rowprep;
1958  SCIP_ROW* row;
1959  SCIP_Real estimateval;
1960  int i;
1961 
1962  rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
1963  assert(rowprep != NULL);
1964  assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
1965 
1966  /* if estimators is only local valid, then skip */
1967  if( SCIProwprepIsLocal(rowprep) )
1968  {
1969  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip local estimator\n"); )
1970  SCIPfreeRowprep(scip, &rowprep);
1971  continue;
1972  }
1973 
1974  /* compute value of estimator */
1975  estimateval = -SCIProwprepGetSide(rowprep);
1976  for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
1977  estimateval += SCIProwprepGetCoefs(rowprep)[i] * SCIPgetSolVal(scip, sol, SCIProwprepGetVars(rowprep)[i]);
1978 
1979  /* if estimator value is not tight (or even "more than tight", e.g., when estimating in integer vars), then skip */
1980  if( (overestimate && !SCIPisFeasLE(scip, estimateval, SCIPexprGetEvalValue(expr))) ||
1981  (!overestimate && !SCIPisFeasGE(scip, estimateval, SCIPexprGetEvalValue(expr))) )
1982  {
1983  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip non-tight estimator with value %g, expr value %g\n", estimateval, SCIPexprGetEvalValue(expr)); )
1984  SCIPfreeRowprep(scip, &rowprep);
1985  continue;
1986  }
1987 
1988  /* complete estimator to cut and clean it up */
1989  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, SCIPgetExprAuxVarNonlinear(expr), -1.0) );
1990  SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, SCIPinfinity(scip), &estimatesuccess) );
1991 
1992  /* if cleanup failed or rowprep is local now, then skip */
1993  if( !estimatesuccess || SCIProwprepIsLocal(rowprep) )
1994  {
1995  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip after cleanup failed or made estimator locally valid\n"); )
1996  SCIPfreeRowprep(scip, &rowprep);
1997  continue;
1998  }
1999 
2000  /* generate row and add to cutpool */
2001  SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
2002 
2003  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
2004  SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
2005 
2006  SCIP_CALL( SCIPaddPoolCut(scip, row) );
2007  /* SCIPnlhdlrIncrementNSeparated(nlhdlr); */
2008 
2009  SCIP_CALL( SCIPreleaseRow(scip, &row) );
2010  SCIPfreeRowprep(scip, &rowprep);
2011  }
2012 
2013  SCIP_CALL( SCIPclearPtrarray(scip, rowpreps) );
2014 
2015  return SCIP_OKAY;
2016 }
2017 
2018 /** adds globally valid tight estimators in a given solution as cuts to cutpool
2019  *
2020  * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
2021  * For convex constraints, we would achieve this by linearizing.
2022  * To avoid checking explicitly for convexity, we compute estimators via any nlhdlr that didn't say it would
2023  * use bound information and check whether the estimator is tight.
2024  *
2025  * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
2026  * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
2027  */
2028 static
2030  SCIP* scip, /**< SCIP data structure */
2031  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2032  SCIP_CONS** conss, /**< constraints */
2033  int nconss, /**< number of constraints */
2034  SCIP_SOL* sol /**< reference point where to estimate */
2035  )
2036 {
2037  SCIP_CONSDATA* consdata;
2038  SCIP_Longint soltag;
2039  SCIP_EXPRITER* it;
2040  SCIP_EXPR* expr;
2041  SCIP_PTRARRAY* rowpreps;
2042  int c, e;
2043 
2044  assert(scip != NULL);
2045  assert(conshdlr != NULL);
2046  assert(conss != NULL || nconss == 0);
2047 
2048  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "add tight estimators in new solution from <%s> to cutpool\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
2049 
2050  /* TODO probably we just evaluated all expressions when checking the sol before it was added
2051  * would be nice to recognize this and skip reevaluating
2052  */
2053  soltag = SCIPgetExprNewSoltag(scip);
2054 
2055  SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
2056 
2057  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2060 
2061  for( c = 0; c < nconss; ++c )
2062  {
2063  /* skip constraints that are not enabled or deleted or have separation disabled */
2064  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
2065  continue;
2066  assert(SCIPconsIsActive(conss[c]));
2067 
2068  consdata = SCIPconsGetData(conss[c]);
2069  assert(consdata != NULL);
2070 
2071  /* TODO we could remember for which constraints there is a chance that we would add anything,
2072  * i.e., there is some convex-like expression, and skip other constraints
2073  */
2074 
2075  ENFOLOG(
2076  {
2077  int i;
2078  SCIPinfoMessage(scip, enfologfile, " constraint ");
2079  SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2080  SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2081  for( i = 0; i < consdata->nvarexprs; ++i )
2082  {
2083  SCIP_VAR* var;
2084  var = SCIPgetVarExprVar(consdata->varexprs[i]);
2085  SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2086  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
2087  }
2088  })
2089 
2090  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2091  assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2092 
2093  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2094  {
2095  SCIP_EXPR_OWNERDATA* ownerdata;
2096 
2097  ownerdata = SCIPexprGetOwnerData(expr);
2098  assert(ownerdata != NULL);
2099 
2100  /* we can only generate a cut from an estimator if there is an auxvar */
2101  if( ownerdata->auxvar == NULL )
2102  continue;
2103 
2104  /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2105  assert(SCIPexprGetEvalTag(expr) == soltag);
2106  assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
2107  SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2108 
2109  /* generate cuts from estimators of each nonlinear handler that provides estimates */
2110  for( e = 0; e < ownerdata->nenfos; ++e )
2111  {
2112  SCIP_NLHDLR* nlhdlr;
2113 
2114  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2115  assert(nlhdlr != NULL);
2116 
2117  /* skip nlhdlr that does not implement estimate (so it does enfo) */
2118  if( !SCIPnlhdlrHasEstimate(nlhdlr) )
2119  continue;
2120 
2121  /* skip nlhdlr that does not participate in separation or looks like it would give only locally-valid estimators
2122  * (because it uses activities on vars/auxvars)
2123  */
2124  if( ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) == 0 || ownerdata->enfos[e]->sepaaboveusesactivity) &&
2125  ((ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) == 0 || ownerdata->enfos[e]->sepabelowusesactivity) )
2126  continue;
2127 
2128  /* skip nlhdlr_default on sum, as the estimator doesn't depend on the reference point (expr is linear in auxvars) */
2129  if( SCIPisExprSum(scip, expr) && strcmp(SCIPnlhdlrGetName(nlhdlr), "default") == 0 )
2130  continue;
2131 
2132  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables, since some nlhdlr expect this before their estimate is called */
2133  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
2134  ENFOLOG(
2135  SCIPinfoMessage(scip, enfologfile, " expr ");
2136  SCIPprintExpr(scip, expr, enfologfile);
2137  SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g, nlhdlr <%s> auxvalue: %.15g\n",
2138  (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar), SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
2139  )
2140  /* due to setting values of auxvars to expr values in sol, the auxvalue should equal to expr evalvalue */
2141  assert(SCIPisEQ(scip, ownerdata->enfos[e]->auxvalue, SCIPexprGetEvalValue(expr)));
2142 
2143  /* if nlhdlr wants to be called for overestimate and does not use local bounds, then call estimate of nlhdlr */
2144  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) && !ownerdata->enfos[e]->sepaaboveusesactivity )
2145  {
2146  SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, TRUE, rowpreps) );
2147  }
2148 
2149  /* if nlhdlr wants to be called for underestimate and does not use local bounds, then call estimate of nlhdlr */
2150  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) && !ownerdata->enfos[e]->sepabelowusesactivity )
2151  {
2152  SCIP_CALL( addTightEstimatorCut(scip, conshdlr, conss[c], expr, ownerdata->enfos[e], sol, FALSE, rowpreps) );
2153  }
2154  }
2155  }
2156  }
2157 
2158  SCIPfreeExpriter(&it);
2159  SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
2160 
2161  return SCIP_OKAY;
2162 }
2163 
2164 /** processes the event that a new primal solution has been found */
2165 static
2166 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2168  SCIP_CONSHDLR* conshdlr;
2169  SCIP_CONSHDLRDATA* conshdlrdata;
2170  SCIP_SOL* sol;
2171 
2172  assert(scip != NULL);
2173  assert(event != NULL);
2174  assert(eventdata != NULL);
2175  assert(eventhdlr != NULL);
2176  assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND);
2177 
2178  conshdlr = (SCIP_CONSHDLR*)eventdata;
2179 
2180  if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2181  return SCIP_OKAY;
2182 
2183  sol = SCIPeventGetSol(event);
2184  assert(sol != NULL);
2185 
2186  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2187  assert(conshdlrdata != NULL);
2188 
2189  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2190  * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2191  * from the tree, but postprocessed via proposeFeasibleSolution
2192  */
2193  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2194  return SCIP_OKAY;
2195 
2196  SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2197 
2198  SCIP_CALL( addTightEstimatorCuts(scip, conshdlr, SCIPconshdlrGetConss(conshdlr), SCIPconshdlrGetNConss(conshdlr), sol) );
2199 
2200  return SCIP_OKAY;
2201 }
2202 
2203 /** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2204  *
2205  * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2206  * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2207  *
2208  * Nothing will happen if SCIP is not in presolve or solve.
2209  */
2210 static
2212  SCIP* scip, /**< SCIP data structure */
2213  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2214  SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2215  SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2216  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2217  int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2218  )
2219 {
2220  SCIP_VAR* var;
2221  SCIP_Bool tightenedlb;
2222  SCIP_Bool tightenedub;
2223  SCIP_Bool force;
2224 
2225  assert(scip != NULL);
2226  assert(conshdlr != NULL);
2227  assert(expr != NULL);
2228  assert(cutoff != NULL);
2229 
2230  /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2231  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, bounds));
2232 
2233  *cutoff = FALSE;
2234 
2235  /* do not tighten variable in problem stage (important for unittests)
2236  * TODO put some kind of #ifdef UNITTEST around this
2237  */
2239  return SCIP_OKAY;
2240 
2241  var = SCIPgetExprAuxVarNonlinear(expr);
2242  if( var == NULL )
2243  return SCIP_OKAY;
2244 
2245  /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2246  force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2247 
2248  /* try to tighten lower bound of (auxiliary) variable */
2249  SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2250  if( tightenedlb )
2251  {
2252  if( ntightenings != NULL )
2253  ++*ntightenings;
2254  SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2255  }
2256  if( *cutoff )
2257  {
2258  SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2259  return SCIP_OKAY;
2260  }
2261 
2262  /* try to tighten upper bound of (auxiliary) variable */
2263  SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2264  if( tightenedub )
2265  {
2266  if( ntightenings != NULL )
2267  ++*ntightenings;
2268  SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2269  }
2270  if( *cutoff )
2271  {
2272  SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2273  return SCIP_OKAY;
2274  }
2275 
2276  /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2277  * that seems unnecessary and we could easily undo this here, e.g.,
2278  * if( tightenedlb ) expr->activity.inf = bounds.inf
2279  */
2280 
2281  return SCIP_OKAY;
2282 }
2283 
2284 /** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2285  * and tries to tighten the bounds of the auxiliary variables accordingly
2286  */
2287 static
2289  SCIP* scip, /**< SCIP data structure */
2290  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2291  SCIP_EXPR* rootexpr, /**< expression */
2292  SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2293  SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2294  int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2295  )
2296 {
2297  SCIP_EXPRITER* it;
2298  SCIP_EXPR* expr;
2299  SCIP_EXPR_OWNERDATA* ownerdata;
2300  SCIP_CONSHDLRDATA* conshdlrdata;
2301 
2302  assert(scip != NULL);
2303  assert(rootexpr != NULL);
2304 
2305  if( infeasible != NULL )
2306  *infeasible = FALSE;
2307  if( ntightenings != NULL )
2308  *ntightenings = 0;
2309 
2310  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2311  assert(conshdlrdata != NULL);
2312 
2313  /* if value is valid and empty, then we cannot improve, so do nothing */
2314  if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2315  {
2316  SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2317 
2318  if( infeasible != NULL )
2319  *infeasible = TRUE;
2320 
2321  /* just update tag to curboundstag */
2322  SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2323 
2324  return SCIP_OKAY;
2325  }
2326 
2327  /* if value is up-to-date, then nothing to do */
2328  if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2329  {
2330  SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2331 
2332  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2333 
2334  return SCIP_OKAY;
2335  }
2336 
2337  ownerdata = SCIPexprGetOwnerData(rootexpr);
2338  assert(ownerdata != NULL);
2339 
2340  /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2341  * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2342  * during detect, we are in some in-between state where we may want to eval activity
2343  * on exprs that we did not notify about their activity usage
2344  */
2345  if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2346  {
2347 #ifdef DEBUG_PROP
2348  SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2349 #endif
2350  SCIPABORT();
2351  return SCIP_OKAY;
2352  }
2353 
2354  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2355  SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2357 
2358  for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2359  {
2360  switch( SCIPexpriterGetStageDFS(it) )
2361  {
2363  {
2364  /* skip child if it has been evaluated already */
2365  SCIP_EXPR* child;
2366 
2367  child = SCIPexpriterGetChildExprDFS(it);
2368  if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2369  {
2370  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(child)) && infeasible != NULL )
2371  *infeasible = TRUE;
2372 
2373  expr = SCIPexpriterSkipDFS(it);
2374  continue;
2375  }
2376 
2377  break;
2378  }
2379 
2381  {
2382  SCIP_INTERVAL activity;
2383 
2384  /* we should not have entered this expression if its activity was already up to date */
2385  assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2386 
2387  ownerdata = SCIPexprGetOwnerData(expr);
2388  assert(ownerdata != NULL);
2389 
2390  /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2391  * so we can assume that the activity is up to date for all these variables
2392  * UNLESS we changed the method used to evaluate activity of variable expressions
2393  * or we currently use global bounds (varevents are catched for local bound changes only)
2394  */
2395  if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2396  SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2397  {
2398 #ifndef NDEBUG
2399  SCIP_INTERVAL exprhdlrinterval;
2400 
2401  SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2402  assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2403  assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2404 #endif
2405 #ifdef DEBUG_PROP
2406  SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2407 #endif
2408  SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2409 
2410  break;
2411  }
2412 
2413  if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2414  {
2415  /* start with entire activity if current one is invalid */
2417  }
2419  {
2420  /* If already empty, then don't try to compute even better activity.
2421  * If cons_nonlinear were alone, then we should have noted that we are infeasible
2422  * so an assert(infeasible == NULL || *infeasible) should work here.
2423  * However, after reporting a cutoff due to expr->activity being empty,
2424  * SCIP may wander to a different node and call propagation again.
2425  * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2426  * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2427  * we will still have expr->activity being empty, but will have forgotten
2428  * that we found infeasibility here before (!2221#note_134120).
2429  * Therefore we just set *infeasibility=TRUE here and stop.
2430  */
2431  if( infeasible != NULL )
2432  *infeasible = TRUE;
2433  SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2434  break;
2435  }
2436  else
2437  {
2438  /* start with current activity, since it is valid */
2439  activity = SCIPexprGetActivity(expr);
2440  }
2441 
2442  /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2443  if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2444  {
2445 #ifdef DEBUG_PROP
2446  SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2447 #endif
2448  break;
2449  }
2450 
2451 #ifdef DEBUG_PROP
2452  SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2453  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2454  SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2455 #endif
2456 
2457  /* run interval eval of nonlinear handlers or expression handler */
2458  if( ownerdata->nenfos > 0 )
2459  {
2460  SCIP_NLHDLR* nlhdlr;
2461  SCIP_INTERVAL nlhdlrinterval;
2462  int e;
2463 
2464  /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2465  for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2466  {
2467  /* skip nlhdlr if it does not want to participate in activity computation */
2468  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2469  continue;
2470 
2471  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2472  assert(nlhdlr != NULL);
2473 
2474  /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2475  if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2476  continue;
2477 
2478  /* let nlhdlr evaluate current expression */
2479  nlhdlrinterval = activity;
2480  SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2481  &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2482 #ifdef DEBUG_PROP
2483  SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2484 #endif
2485 
2486  /* update activity by intersecting with computed activity */
2487  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2488 #ifdef DEBUG_PROP
2489  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2490 #endif
2491  }
2492  }
2493  else
2494  {
2495  /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2496  SCIP_INTERVAL exprhdlrinterval = activity;
2497  SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2498 #ifdef DEBUG_PROP
2499  SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2500 #endif
2501 
2502  /* update expr->activity by intersecting with computed activity */
2503  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2504 #ifdef DEBUG_PROP
2505  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2506 #endif
2507  }
2508 
2509  /* if expression is integral, then we try to tighten the interval bounds a bit
2510  * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2511  * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2512  * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2513  * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2514  * (constants should be ok, too)
2515  */
2516  if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2517  {
2518  if( activity.inf > -SCIP_INTERVAL_INFINITY )
2519  activity.inf = SCIPceil(scip, activity.inf);
2520  if( activity.sup < SCIP_INTERVAL_INFINITY )
2521  activity.sup = SCIPfloor(scip, activity.sup);
2522 #ifdef DEBUG_PROP
2523  SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2524 #endif
2525  }
2526 
2527  /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2528  * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2529  */
2530  if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2531  {
2532  SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2533  SCIPintervalSetEmpty(&activity);
2534  }
2535 
2536  /* now finally store activity in expr */
2537  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2538 
2540  {
2541  if( infeasible != NULL )
2542  *infeasible = TRUE;
2543  }
2544  else if( tightenauxvars && ownerdata->auxvar != NULL )
2545  {
2546  SCIP_Bool tighteninfeasible;
2547 
2548  SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2549  if( tighteninfeasible )
2550  {
2551  if( infeasible != NULL )
2552  *infeasible = TRUE;
2553  SCIPintervalSetEmpty(&activity);
2554  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2555  }
2556  }
2557 
2558  break;
2559  }
2560 
2561  default:
2562  /* you should never be here */
2563  SCIPerrorMessage("unexpected iterator stage\n");
2564  SCIPABORT();
2565  break;
2566  }
2567 
2568  expr = SCIPexpriterGetNext(it);
2569  }
2570 
2571  SCIPfreeExpriter(&it);
2572 
2573  return SCIP_OKAY;
2574 }
2575 
2576 /** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2577  *
2578  * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2579  *
2580  * If `subsetsufficient` is FALSE, then we require
2581  * - a change from an unbounded interval to a bounded one, or
2582  * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2583  * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2584  */
2585 static
2587  SCIP* scip, /**< SCIP data structure */
2588  SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2589  SCIP_INTERVAL newinterval, /**< new interval */
2590  SCIP_INTERVAL oldinterval /**< old interval */
2591  )
2592 {
2593  assert(scip != NULL);
2594  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
2595  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
2596 
2597  if( subsetsufficient )
2598  /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2599  return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2600 
2601  /* check whether lower bound of interval becomes finite */
2602  if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2603  return TRUE;
2604 
2605  /* check whether upper bound of interval becomes finite */
2606  if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
2607  return TRUE;
2608 
2609  /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2610  if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2611  return TRUE;
2612 
2613  /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2614  if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2615  return TRUE;
2616 
2617  /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2618  if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2619  return TRUE;
2620 
2621  return FALSE;
2622 }
2623 
2624 /** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2625  *
2626  * The expression will be traversed in breadth first search by using this queue.
2627  *
2628  * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2629  * forwardPropExpr() before calling this function.
2630  *
2631  * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2632  */
2633 static
2635  SCIP* scip, /**< SCIP data structure */
2636  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2637  SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2638  int* ntightenings /**< buffer to store the number of (variable) tightenings */
2639  )
2640 {
2641  SCIP_CONSHDLRDATA* conshdlrdata;
2642  SCIP_EXPR* expr;
2643  SCIP_EXPR_OWNERDATA* ownerdata;
2644 
2645  assert(infeasible != NULL);
2646  assert(ntightenings != NULL);
2647 
2648  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2649  assert(conshdlrdata != NULL);
2650 
2651  *ntightenings = 0;
2652 
2653  /* main loop that calls reverse propagation for expressions on the queue
2654  * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2655  */
2656  while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2657  {
2658  SCIP_INTERVAL propbounds;
2659  int e;
2660 
2661  expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2662  assert(expr != NULL);
2663 
2664  ownerdata = SCIPexprGetOwnerData(expr);
2665  assert(ownerdata != NULL);
2666 
2667  assert(ownerdata->inpropqueue);
2668  /* mark that the expression is not in the queue anymore */
2669  ownerdata->inpropqueue = FALSE;
2670 
2671  /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2672  * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2673  */
2674  assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2675  assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2676  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2677 
2678  /* this intersects propbounds with activity and auxvar bounds
2679  * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2680  * auxvar bounds separately, so disabling this for now
2681  */
2682 #ifdef SCIP_DISABLED_CODE
2683  propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2684  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, propbounds) )
2685  {
2686  *infeasible = TRUE;
2687  break;
2688  }
2689 #else
2690  propbounds = ownerdata->propbounds;
2691 #endif
2692 
2693  if( ownerdata->nenfos > 0 )
2694  {
2695  /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2696  for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2697  {
2698  SCIP_NLHDLR* nlhdlr;
2699  int nreds;
2700 
2701  /* skip nlhdlr if it does not want to participate in activity computation */
2702  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2703  continue;
2704 
2705  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2706  assert(nlhdlr != NULL);
2707 
2708  /* call the reverseprop of the nlhdlr */
2709 #ifdef SCIP_DEBUG
2710  SCIPdebugMsg(scip, "call reverse propagation for ");
2711  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2712  SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2713 #endif
2714 
2715  nreds = 0;
2716  SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2717  assert(nreds >= 0);
2718  *ntightenings += nreds;
2719  }
2720  }
2722  {
2723  /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2724  SCIP_INTERVAL* childrenbounds;
2725  int c;
2726 
2727 #ifdef SCIP_DEBUG
2728  SCIPdebugMsg(scip, "call reverse propagation for ");
2729  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2730  SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2731 #endif
2732 
2733  /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2734  * been initialized in detectNlhdlr yet (nenfos < 0)
2735  */
2736  assert(ownerdata->nenfos < 0);
2737 
2738  SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2739  for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2740  childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2741 
2742  /* call the reverseprop of the exprhdlr */
2743  SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2744 
2745  if( !*infeasible )
2746  for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2747  {
2748  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2749  }
2750 
2751  SCIPfreeBufferArray(scip, &childrenbounds);
2752  }
2753  }
2754 
2755  /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2756  while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2757  {
2758  expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2759  assert(expr != NULL);
2760 
2761  ownerdata = SCIPexprGetOwnerData(expr);
2762  assert(ownerdata != NULL);
2763 
2764  /* mark that the expression is not in the queue anymore */
2765  ownerdata->inpropqueue = FALSE;
2766  }
2767 
2768  return SCIP_OKAY;
2769 }
2770 
2771 /** calls domain propagation for a given set of constraints
2772  *
2773  * The algorithm alternates calls of forward and reverse propagation.
2774  * Forward propagation ensures that activity of expressions is up to date.
2775  * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2776  * [lhs,rhs] interval as starting point.
2777  *
2778  * The propagation algorithm works as follows:
2779  * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2780  * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2781  * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2782  * provide tighter bounds
2783  * 3. apply reverse propagation to all collected expressions; don't explore
2784  * sub-expressions which have not changed since the beginning of the propagation loop
2785  * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2786  *
2787  * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2788  * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2789  * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2790  *
2791  * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2792  * e.g., try less to propagate on convex constraints?
2793  */
2794 static
2796  SCIP* scip, /**< SCIP data structure */
2797  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2798  SCIP_CONS** conss, /**< constraints to propagate */
2799  int nconss, /**< total number of constraints */
2800  SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2801  SCIP_RESULT* result, /**< pointer to store the result */
2802  int* nchgbds /**< buffer to add the number of changed bounds */
2803  )
2804 {
2805  SCIP_CONSHDLRDATA* conshdlrdata;
2806  SCIP_CONSDATA* consdata;
2807  SCIP_EXPR_OWNERDATA* ownerdata;
2808  SCIP_Bool cutoff = FALSE;
2809  SCIP_INTERVAL conssides;
2810  int ntightenings;
2811  int roundnr;
2812  SCIP_EXPRITER* revpropcollectit = NULL;
2813  int i;
2814 
2815  assert(scip != NULL);
2816  assert(conshdlr != NULL);
2817  assert(conss != NULL);
2818  assert(nconss >= 0);
2819  assert(result != NULL);
2820  assert(nchgbds != NULL);
2821  assert(*nchgbds >= 0);
2822 
2823  /* no constraints to propagate */
2824  if( nconss == 0 )
2825  {
2826  *result = SCIP_DIDNOTRUN;
2827  return SCIP_OKAY;
2828  }
2829 
2830  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2831  assert(conshdlrdata != NULL);
2832 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2833  assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2834 #endif
2835  assert(!conshdlrdata->globalbounds);
2836 
2837  *result = SCIP_DIDNOTFIND;
2838  roundnr = 0;
2839 
2840  /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2841  conshdlrdata->forceboundtightening = force;
2842 
2843  /* invalidate all propbounds (probably not needed) */
2844  ++conshdlrdata->curpropboundstag;
2845 
2846  /* create iterator that we will use if we need to look at all auxvars */
2847  if( conshdlrdata->propauxvars )
2848  {
2849  SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2850  }
2851 
2852  /* main propagation loop */
2853  do
2854  {
2855  SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2856 
2857  assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2858 
2859  /* apply forward propagation (update expression activities)
2860  * and add promising root expressions into queue for reversepropagation
2861  */
2862  for( i = 0; i < nconss; ++i )
2863  {
2864  consdata = SCIPconsGetData(conss[i]);
2865  assert(consdata != NULL);
2866 
2867  /* skip deleted, non-active, or propagation-disabled constraints */
2868  if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2869  continue;
2870 
2871  /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2872  * activity didn't change
2873  */
2874  if( consdata->ispropagated )
2875  continue;
2876 
2877  /* update activities in expression */
2878  SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2879  SCIPdebugPrintCons(scip, conss[i], NULL);
2880 
2881  ntightenings = 0;
2882  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2883  assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2884 
2885  if( cutoff )
2886  {
2887  SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2888  *result = SCIP_CUTOFF;
2889  break;
2890  }
2891 
2892  ownerdata = SCIPexprGetOwnerData(consdata->expr);
2893 
2894  /* TODO for a constraint that only has an auxvar for consdata->expr (e.g., convex quadratic), we could also just do the if(TRUE)-branch */
2895  if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2896  {
2897  /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2898  * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2899  * so taking auxvar bounds is enough)
2900  */
2901  if( ownerdata->auxvar == NULL )
2902  {
2903  /* relax sides by SCIPepsilon() and handle infinite sides */
2904  SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2905  SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2906  SCIPintervalSetBounds(&conssides, lhs, rhs);
2907  }
2908  else
2909  {
2910  conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2911  }
2912  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2913  }
2914  else
2915  {
2916  /* check whether bounds of any auxvar used in constraint provides a tightening
2917  * (for the root expression, bounds of auxvar are initially set to constraint sides)
2918  * but skip exprs that have an auxvar, but do not participate in propagation
2919  */
2920  SCIP_EXPR* expr;
2921 
2922  assert(revpropcollectit != NULL);
2923  SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2924  for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2925  {
2926  ownerdata = SCIPexprGetOwnerData(expr);
2927  assert(ownerdata != NULL);
2928 
2929  if( ownerdata->auxvar == NULL )
2930  continue;
2931 
2932  if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2933  continue;
2934 
2935  conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2936  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2937  }
2938  }
2939 
2940  if( cutoff )
2941  {
2942  SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2943  *result = SCIP_CUTOFF;
2944  break;
2945  }
2946 
2947  assert(ntightenings >= 0);
2948  if( ntightenings > 0 )
2949  {
2950  *nchgbds += ntightenings;
2951  *result = SCIP_REDUCEDDOM;
2952  }
2953 
2954  /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2955  consdata->ispropagated = TRUE;
2956  }
2957 
2958  /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2959  SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2960  assert(ntightenings >= 0);
2961  assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2962 
2963  if( cutoff )
2964  {
2965  SCIPdebugMsg(scip, " -> cutoff\n");
2966  *result = SCIP_CUTOFF;
2967  break;
2968  }
2969 
2970  if( ntightenings > 0 )
2971  {
2972  *nchgbds += ntightenings;
2973  *result = SCIP_REDUCEDDOM;
2974  }
2975  }
2976  while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2977 
2978  if( conshdlrdata->propauxvars )
2979  {
2980  SCIPfreeExpriter(&revpropcollectit);
2981  }
2982 
2983  conshdlrdata->forceboundtightening = FALSE;
2984 
2985  /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2986  ++conshdlrdata->curpropboundstag;
2987 
2988  return SCIP_OKAY;
2989 }
2990 
2991 /** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2992  *
2993  * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2994  *
2995  * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2996  * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2997  */
2998 static
3000  SCIP* scip, /**< SCIP data structure */
3001  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3002  SCIP_CONS** conss, /**< constraints to propagate */
3003  int nconss, /**< total number of constraints */
3004  SCIP_RESULT* result, /**< pointer to store the result */
3005  int* nchgbds /**< buffer to add the number of changed bounds */
3006  )
3007 {
3008  SCIP_CONSDATA* consdata;
3009  SCIP_EXPRITER* it;
3010  SCIP_EXPR* expr;
3011  SCIP_EXPR_OWNERDATA* ownerdata;
3012  SCIP_Bool cutoff = FALSE;
3013  int ntightenings;
3014  int c;
3015  int e;
3016 
3017  assert(scip != NULL);
3018  assert(conshdlr != NULL);
3019  assert(conss != NULL);
3020  assert(nconss >= 0);
3021  assert(result != NULL);
3022  assert(nchgbds != NULL);
3023  assert(*nchgbds >= 0);
3024 
3025 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
3026  assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
3027 #endif
3028  assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
3029  assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
3030 
3031  *result = SCIP_DIDNOTFIND;
3032 
3033  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3035 
3036  for( c = 0; c < nconss && !cutoff; ++c )
3037  {
3038  /* skip deleted, non-active, or propagation-disabled constraints */
3039  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
3040  continue;
3041 
3042  consdata = SCIPconsGetData(conss[c]);
3043  assert(consdata != NULL);
3044 
3045  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
3046  {
3047  ownerdata = SCIPexprGetOwnerData(expr);
3048  assert(ownerdata != NULL);
3049 
3050  /* call reverseprop for those nlhdlr that participate in this expr's activity computation
3051  * this will propagate the current activity
3052  */
3053  for( e = 0; e < ownerdata->nenfos; ++e )
3054  {
3055  SCIP_NLHDLR* nlhdlr;
3056  assert(ownerdata->enfos[e] != NULL);
3057 
3058  nlhdlr = ownerdata->enfos[e]->nlhdlr;
3059  assert(nlhdlr != NULL);
3060  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
3061  continue;
3062 
3063  SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
3064  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
3065  ntightenings = 0;
3066  SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
3067  SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
3068 
3069  if( cutoff )
3070  {
3071  /* stop everything if we detected infeasibility */
3072  SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
3073  *result = SCIP_CUTOFF;
3074  break;
3075  }
3076 
3077  assert(ntightenings >= 0);
3078  if( ntightenings > 0 )
3079  {
3080  *nchgbds += ntightenings;
3081  *result = SCIP_REDUCEDDOM;
3082  }
3083  }
3084  }
3085  }
3086 
3087  /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
3088  SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
3089  assert(ntightenings >= 0);
3090 
3091  if( cutoff )
3092  {
3093  SCIPdebugMsg(scip, " -> cutoff\n");
3094  *result = SCIP_CUTOFF;
3095  }
3096  else if( ntightenings > 0 )
3097  {
3098  *nchgbds += ntightenings;
3099  *result = SCIP_REDUCEDDOM;
3100  }
3101 
3102  SCIPfreeExpriter(&it);
3103 
3104  /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
3105  ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
3106 
3107  return SCIP_OKAY;
3108 }
3109 
3110 /** propagates variable locks through expression and adds locks to variables */
3111 static
3113  SCIP* scip, /**< SCIP data structure */
3114  SCIP_EXPR* expr, /**< expression */
3115  int nlockspos, /**< number of positive locks */
3116  int nlocksneg /**< number of negative locks */
3117  )
3118 {
3119  SCIP_EXPR_OWNERDATA* ownerdata;
3120  SCIP_EXPRITER* it;
3121  SCIP_EXPRITER_USERDATA ituserdata;
3122 
3123  assert(expr != NULL);
3124 
3125  /* if no locks, then nothing to propagate */
3126  if( nlockspos == 0 && nlocksneg == 0 )
3127  return SCIP_OKAY;
3128 
3129  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3132  assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3133 
3134  /* store locks in root node */
3135  ituserdata.intvals[0] = nlockspos;
3136  ituserdata.intvals[1] = nlocksneg;
3137  SCIPexpriterSetCurrentUserData(it, ituserdata);
3138 
3139  while( !SCIPexpriterIsEnd(it) )
3140  {
3141  /* collect locks */
3142  ituserdata = SCIPexpriterGetCurrentUserData(it);
3143  nlockspos = ituserdata.intvals[0];
3144  nlocksneg = ituserdata.intvals[1];
3145 
3146  ownerdata = SCIPexprGetOwnerData(expr);
3147 
3148  switch( SCIPexpriterGetStageDFS(it) )
3149  {
3151  {
3152  if( SCIPisExprVar(scip, expr) )
3153  {
3154  /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3155  SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3156  }
3157 
3158  /* add locks to expression */
3159  ownerdata->nlockspos += nlockspos;
3160  ownerdata->nlocksneg += nlocksneg;
3161 
3162  /* add monotonicity information if expression has been locked for the first time */
3163  if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3165  {
3166  int i;
3167 
3168  assert(ownerdata->monotonicity == NULL);
3169  assert(ownerdata->monotonicitysize == 0);
3170 
3171  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3172  ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3173 
3174  /* store the monotonicity for each child */
3175  for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3176  {
3177  SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3178  }
3179  }
3180  break;
3181  }
3182 
3184  {
3185  /* remove monotonicity information if expression has been unlocked */
3186  if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3187  {
3188  assert(ownerdata->monotonicitysize > 0);
3189  /* keep this assert for checking whether someone changed an expression without updating locks properly */
3190  assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3191 
3192  SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3193  ownerdata->monotonicitysize = 0;
3194  }
3195  break;
3196  }
3197 
3199  {
3200  SCIP_MONOTONE monotonicity;
3201 
3202  /* get monotonicity of child */
3203  /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3204  * SCIPcallExprMonotonicity
3205  */
3206  monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3207 
3208  /* compute resulting locks of the child expression */
3209  switch( monotonicity )
3210  {
3211  case SCIP_MONOTONE_INC:
3212  ituserdata.intvals[0] = nlockspos;
3213  ituserdata.intvals[1] = nlocksneg;
3214  break;
3215  case SCIP_MONOTONE_DEC:
3216  ituserdata.intvals[0] = nlocksneg;
3217  ituserdata.intvals[1] = nlockspos;
3218  break;
3219  case SCIP_MONOTONE_UNKNOWN:
3220  ituserdata.intvals[0] = nlockspos + nlocksneg;
3221  ituserdata.intvals[1] = nlockspos + nlocksneg;
3222  break;
3223  case SCIP_MONOTONE_CONST:
3224  ituserdata.intvals[0] = 0;
3225  ituserdata.intvals[1] = 0;
3226  break;
3227  }
3228  /* set locks in child expression */
3229  SCIPexpriterSetChildUserData(it, ituserdata);
3230 
3231  break;
3232  }
3233 
3234  default :
3235  /* you should never be here */
3236  SCIPABORT();
3237  break;
3238  }
3239 
3240  expr = SCIPexpriterGetNext(it);
3241  }
3242 
3243  SCIPfreeExpriter(&it);
3244 
3245  return SCIP_OKAY;
3246 }
3247 
3248 /** main function for adding locks to expressions and variables
3249  *
3250  * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3251  * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3252  * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3253  * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3254  * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3255  * the computed monotonicity information of each expression until all locks of an expression have been removed,
3256  * which implies that updating the monotonicity information during the next locking of this expression does not
3257  * break existing locks.
3258  *
3259  * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3260  * locks from an expression and repropagating them after the structural changes have been applied.
3261  * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3262  * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3263  */
3264 static
3266  SCIP* scip, /**< SCIP data structure */
3267  SCIP_CONS* cons, /**< nonlinear constraint */
3268  int nlockspos, /**< number of positive rounding locks */
3269  int nlocksneg /**< number of negative rounding locks */
3270  )
3271 {
3272  SCIP_CONSDATA* consdata;
3273 
3274  assert(cons != NULL);
3275 
3276  if( nlockspos == 0 && nlocksneg == 0 )
3277  return SCIP_OKAY;
3278 
3279  consdata = SCIPconsGetData(cons);
3280  assert(consdata != NULL);
3281 
3282  /* no constraint sides -> nothing to lock */
3283  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3284  return SCIP_OKAY;
3285 
3286  /* remember locks */
3287  consdata->nlockspos += nlockspos;
3288  consdata->nlocksneg += nlocksneg;
3289 
3290  assert(consdata->nlockspos >= 0);
3291  assert(consdata->nlocksneg >= 0);
3292 
3293  /* compute locks for lock propagation */
3294  if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3295  {
3296  SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3297  }
3298  else if( !SCIPisInfinity(scip, consdata->rhs) )
3299  {
3300  SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3301  }
3302  else
3303  {
3304  assert(!SCIPisInfinity(scip, -consdata->lhs));
3305  SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3306  }
3307 
3308  return SCIP_OKAY;
3309 }
3310 
3311 /** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3312 static
3314  SCIP* scip, /**< SCIP data structure */
3315  SCIP_CONS* cons /**< nonlinear constraint */
3316  )
3317 {
3318  SCIP_CONSDATA* consdata;
3319 
3320  assert(scip != NULL);
3321  assert(cons != NULL);
3322 
3323  consdata = SCIPconsGetData(cons);
3324  assert(consdata != NULL);
3325  assert(consdata->expr != NULL);
3326 
3327  if( consdata->nlrow != NULL )
3328  {
3329  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3330  }
3331 
3332  /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3333  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3334  0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3335 
3336  if( SCIPisExprSum(scip, consdata->expr) )
3337  {
3338  /* if root is a sum, then split into linear and nonlinear terms */
3339  SCIP_EXPR* nonlinpart;
3340  SCIP_EXPR* child;
3341  SCIP_Real* coefs;
3342  int i;
3343 
3344  coefs = SCIPgetCoefsExprSum(consdata->expr);
3345 
3346  /* constant term of sum */
3347  SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3348 
3349  /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3350  SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3351 
3352  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3353  {
3354  child = SCIPexprGetChildren(consdata->expr)[i];
3355  if( SCIPisExprVar(scip, child) )
3356  {
3357  /* linear term */
3358  SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3359  }
3360  else
3361  {
3362  /* nonlinear term */
3363  SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3364  }
3365  }
3366 
3367  if( SCIPexprGetNChildren(nonlinpart) > 0 )
3368  {
3369  /* add expression to nlrow (this will make a copy) */
3370  SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3371  }
3372  SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3373  }
3374  else
3375  {
3376  SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3377  }
3378 
3379  return SCIP_OKAY;
3380 }
3381 
3382 /** compares enfodata by enforcement priority of nonlinear handler
3383  *
3384  * If handlers have same enforcement priority, then compare by detection priority, then by name.
3385  */
3386 static
3387 SCIP_DECL_SORTPTRCOMP(enfodataCmp)
3389  SCIP_NLHDLR* h1;
3390  SCIP_NLHDLR* h2;
3391 
3392  assert(elem1 != NULL);
3393  assert(elem2 != NULL);
3394 
3395  h1 = ((EXPRENFO*)elem1)->nlhdlr;
3396  h2 = ((EXPRENFO*)elem2)->nlhdlr;
3397 
3398  assert(h1 != NULL);
3399  assert(h2 != NULL);
3400 
3403 
3406 
3407  return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3408 }
3409 
3410 /** install nlhdlrs in one expression */
3411 static
3413  SCIP* scip, /**< SCIP data structure */
3414  SCIP_EXPR* expr, /**< expression for which to run detection routines */
3415  SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3416  )
3417 {
3418  SCIP_EXPR_OWNERDATA* ownerdata;
3419  SCIP_CONSHDLRDATA* conshdlrdata;
3420  SCIP_NLHDLR_METHOD enforcemethodsallowed;
3421  SCIP_NLHDLR_METHOD enforcemethods;
3422  SCIP_NLHDLR_METHOD enforcemethodsnew;
3423  SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3424  SCIP_NLHDLR_METHOD nlhdlrparticipating;
3425  SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3426  int enfossize; /* allocated length of expr->enfos array */
3427  int h;
3428 
3429  assert(expr != NULL);
3430 
3431  ownerdata = SCIPexprGetOwnerData(expr);
3432  assert(ownerdata != NULL);
3433 
3434  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3435  assert(conshdlrdata != NULL);
3436  assert(conshdlrdata->auxvarid >= 0);
3437  assert(!conshdlrdata->indetect);
3438 
3439  /* there should be no enforcer yet and detection should not even have considered expr yet */
3440  assert(ownerdata->nenfos < 0);
3441  assert(ownerdata->enfos == NULL);
3442 
3443  /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3444  * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3445  * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3446  * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3447  * - if no one uses activity, then do not need activity methods
3448  */
3449  enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3450  if( ownerdata->nauxvaruses == 0 )
3451  enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3452  else
3453  {
3454  if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3455  enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3456  if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3457  enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3458  }
3459  if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3460  enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3461 
3462  /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3463  assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3464 
3465  /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3466  enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3467 
3468  ownerdata->nenfos = 0;
3469  enfossize = 2;
3470  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3471  conshdlrdata->indetect = TRUE;
3472 
3473  SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3474  cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3475  (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3476  (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3477  (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3478 
3479  for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3480  {
3481  SCIP_NLHDLR* nlhdlr;
3482 
3483  nlhdlr = conshdlrdata->nlhdlrs[h];
3484  assert(nlhdlr != NULL);
3485 
3486  /* skip disabled nlhdlrs */
3487  if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3488  continue;
3489 
3490  /* call detect routine of nlhdlr */
3491  nlhdlrexprdata = NULL;
3492  enforcemethodsnew = enforcemethods;
3493  nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3494  conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3495  conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3496  /* coverity[forward_null] */
3497  SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3498 
3499  /* nlhdlr might have claimed more than needed: clean up sepa flags */
3500  nlhdlrparticipating &= enforcemethodsallowed;
3501 
3502  /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3503  assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3504 
3505  /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3506  * They are also cleaned up here to ensure that only the needed methods are claimed.
3507  */
3508  nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3509 
3510  /* nlhdlr needs to participate for the methods it is enforcing */
3511  assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3512 
3513  if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3514  {
3515  /* nlhdlr might not have detected anything, or all set flags might have been removed by
3516  * clean up; in the latter case, we may need to free nlhdlrexprdata */
3517 
3518  /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3519  if( nlhdlrexprdata != NULL )
3520  {
3521  SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3522  }
3523  /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3524  assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3525 
3526  SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3527 
3528  continue;
3529  }
3530 
3531  SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3532  SCIPnlhdlrGetName(nlhdlr),
3533  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3534  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3535  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3536 
3537  /* store nlhdlr and its data */
3538  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3539  SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3540  ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3541  ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3542  ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3543  ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3544  ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3545  ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3546  ownerdata->nenfos++;
3547 
3548  /* update enforcement flags */
3549  enforcemethods = enforcemethodsnew;
3550  }
3551 
3552  conshdlrdata->indetect = FALSE;
3553 
3554  /* stop if an enforcement method is missing but we are already in solving stage
3555  * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3556  */
3557  if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3558  {
3559  SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3560  return SCIP_ERROR;
3561  }
3562 
3563  assert(ownerdata->nenfos > 0);
3564 
3565  /* sort nonlinear handlers by enforcement priority, in decreasing order */
3566  if( ownerdata->nenfos > 1 )
3567  SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3568 
3569  /* resize enfos array to be nenfos long */
3570  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3571 
3572  return SCIP_OKAY;
3573 }
3574 
3575 /** detect nlhdlrs that can handle the expressions */
3576 static
3578  SCIP* scip, /**< SCIP data structure */
3579  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3580  SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3581  int nconss /**< total number of constraints */
3582  )
3583 {
3584  SCIP_CONSHDLRDATA* conshdlrdata;
3585  SCIP_CONSDATA* consdata;
3586  SCIP_EXPR* expr;
3587  SCIP_EXPR_OWNERDATA* ownerdata;
3588  SCIP_EXPRITER* it;
3589  int i;
3590 
3591  assert(conss != NULL || nconss == 0);
3592  assert(nconss >= 0);
3593  assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING || SCIPgetStage(scip) == SCIP_STAGE_INITSOLVE || SCIPgetStage(scip) == SCIP_STAGE_SOLVING); /* should only be called in presolve or initsolve or consactive */
3594 
3595  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3596  assert(conshdlrdata != NULL);
3597 
3598  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3600 
3601  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3602  {
3603  /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3604  * for example, this happens if globally valid nonlinear constraints are added during the tree search
3605  */
3607  conshdlrdata->globalbounds = TRUE;
3608  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3609  }
3610 
3611  for( i = 0; i < nconss; ++i )
3612  {
3613  assert(conss != NULL && conss[i] != NULL);
3614 
3615  consdata = SCIPconsGetData(conss[i]);
3616  assert(consdata != NULL);
3617  assert(consdata->expr != NULL);
3618 
3619  /* if a constraint is separated, we currently need it to be initial, too
3620  * this is because INITLP will create the auxiliary variables that are used for any separation
3621  * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3622  */
3623  assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3624 
3625  ownerdata = SCIPexprGetOwnerData(consdata->expr);
3626  assert(ownerdata != NULL);
3627 
3628  /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3629  * then we would normally skip to run DETECT again
3630  * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3631  * thus, if expr is the root expression, we rerun DETECT
3632  */
3633  if( ownerdata->nenfos > 0 )
3634  {
3635  SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3636  assert(ownerdata->nenfos < 0);
3637  }
3638 
3639  /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3640  * this way we can treat the root expression like any other expression when enforcing via separation
3641  * if constraint will be propagated, then register activity usage of root expression
3642  * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3643  */
3644  conshdlrdata->indetect = TRUE;
3645  SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, consdata->expr,
3646  SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && (SCIPconsIsSeparated(conss[i]) || SCIPconsIsEnforced(conss[i])),
3647  SCIPconsIsPropagated(conss[i]),
3648  FALSE, FALSE) );
3649  conshdlrdata->indetect = FALSE;
3650 
3651  /* compute integrality information for all subexpressions */
3652  SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3653 
3654  /* run detectNlhdlr on all expr where required */
3655  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3656  {
3657  ownerdata = SCIPexprGetOwnerData(expr);
3658  assert(ownerdata != NULL);
3659 
3660  /* skip exprs that we already looked at */
3661  if( ownerdata->nenfos >= 0 )
3662  continue;
3663 
3664  /* if there is use of the auxvar, then someone requires that
3665  * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3666  * thus, we need to find nlhdlrs that separate or estimate
3667  * if there is use of the activity, then there is someone requiring that
3668  * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3669  * thus, we need to find nlhdlrs that do interval-evaluation
3670  */
3671  if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3672  {
3673  SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3674 
3675  assert(ownerdata->nenfos >= 0);
3676  }
3677  else
3678  {
3679  /* remember that we looked at this expression during detectNlhdlrs
3680  * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3681  * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3682  * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3683  */
3684  ownerdata->nenfos = 0;
3685  }
3686  }
3687 
3688  /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3689  if( SCIPconsIsPropagated(conss[i]) )
3690  consdata->ispropagated = FALSE;
3691  }
3692 
3693  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3694  {
3695  /* ensure that the local bounds are used again when reevaluating the expressions later;
3696  * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3697  */
3699  conshdlrdata->globalbounds = FALSE;
3700  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3701  }
3702  else
3703  {
3704  /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3706  }
3707 
3708  SCIPfreeExpriter(&it);
3709 
3710  return SCIP_OKAY;
3711 }
3712 
3713 /** initializes (pre)solving data of constraints
3714  *
3715  * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3716  * not be modified.
3717  * In particular, this function
3718  * - runs the detection method of nlhldrs
3719  * - looks for unlocked linear variables
3720  * - checks curvature (if not in presolve)
3721  * - creates and add row to NLP (if not in presolve)
3722  *
3723  * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3724  * e.g., it should be called in INITSOL and for constraints that are added during solve.
3725  */
3726 static
3728  SCIP* scip, /**< SCIP data structure */
3729  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3730  SCIP_CONS** conss, /**< constraints */
3731  int nconss /**< number of constraints */
3732  )
3733 {
3734  int c;
3735 
3736  for( c = 0; c < nconss; ++c )
3737  {
3738  /* check for a linear variable that can be increase or decreased without harming feasibility */
3739  findUnlockedLinearVar(scip, conss[c]);
3740 
3742  {
3743  SCIP_CONSDATA* consdata;
3744  SCIP_Bool success = FALSE;
3745 
3746  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3747  assert(consdata != NULL);
3748  assert(consdata->expr != NULL);
3749 
3750  if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3751  {
3752  /* call the curvature detection algorithm of the convex nonlinear handler
3753  * Check only for those curvature that may result in a convex inequality, i.e.,
3754  * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3755  * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3756  */
3757  if( !SCIPisInfinity(scip, -consdata->lhs) )
3758  {
3759  SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3760  if( success )
3761  consdata->curv = SCIP_EXPRCURV_CONCAVE;
3762  }
3763  if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3764  {
3765  SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3766  if( success )
3767  consdata->curv = SCIP_EXPRCURV_CONVEX;
3768  }
3769  }
3770  else
3771  {
3772  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3773  {
3774  SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3775  consdata->curv = SCIP_EXPRCURV_LINEAR;
3776  }
3777  else
3778  {
3779  consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3780  }
3781  }
3782  SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3783 
3784  /* add nlrow representation to NLP, if NLP had been constructed */
3785  if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
3786  {
3787  if( consdata->nlrow == NULL )
3788  {
3789  SCIP_CALL( createNlRow(scip, conss[c]) );
3790  assert(consdata->nlrow != NULL);
3791  }
3792  SCIPnlrowSetCurvature(consdata->nlrow, consdata->curv);
3793  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3794  }
3795  }
3796  }
3797 
3798  /* register non linear handlers */
3799  SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3800 
3801  return SCIP_OKAY;
3802 }
3803 
3804 /** deinitializes (pre)solving data of constraints
3805  *
3806  * This removes the initialization data created in initSolve().
3807  *
3808  * This function can be called in presolve and solve.
3809  *
3810  * TODO At the moment, it should not be called for a constraint if there are other constraints
3811  * that use the same expressions but still require their nlhdlr.
3812  * We should probably only decrement the auxvar and activity usage for the root expr and then
3813  * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3814  */
3815 static
3817  SCIP* scip, /**< SCIP data structure */
3818  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3819  SCIP_CONS** conss, /**< constraints */
3820  int nconss /**< number of constraints */
3821  )
3822 {
3823  SCIP_EXPRITER* it;
3824  SCIP_EXPR* expr;
3825  SCIP_CONSDATA* consdata;
3826  SCIP_Bool rootactivityvalid;
3827  int c;
3828 
3829  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3832 
3833  /* call deinitialization callbacks of expression and nonlinear handlers
3834  * free nonlinear handlers information from expressions
3835  * remove auxiliary variables and nactivityuses counts from expressions
3836  */
3837  for( c = 0; c < nconss; ++c )
3838  {
3839  assert(conss != NULL);
3840  assert(conss[c] != NULL);
3841 
3842  consdata = SCIPconsGetData(conss[c]);
3843  assert(consdata != NULL);
3844  assert(consdata->expr != NULL);
3845 
3846  /* check and remember whether activity in root is valid */
3847  rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3848 
3849  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3850  {
3851  SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3852 
3853  /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3854  SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3855 
3856  /* remove quadratic info */
3857  SCIPfreeExprQuadratic(scip, expr);
3858 
3859  if( rootactivityvalid )
3860  {
3861  /* ensure activity is valid if consdata->expr activity is valid
3862  * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3863  * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3864  * so this childs activity would be invalid, which can generate confusion
3865  */
3866  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
3867  }
3868  }
3869 
3870  if( consdata->nlrow != NULL )
3871  {
3872  /* remove row from NLP, if still in solving
3873  * if we are in exitsolve, the whole NLP will be freed anyway
3874  */
3875  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3876  {
3877  SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3878  }
3879 
3880  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3881  }
3882 
3883  /* forget about linear variables that can be increased or decreased without harming feasibility */
3884  consdata->linvardecr = NULL;
3885  consdata->linvarincr = NULL;
3886 
3887  /* forget about curvature */
3888  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3889  }
3890 
3891  SCIPfreeExpriter(&it);
3892 
3893  return SCIP_OKAY;
3894 }
3895 
3896 /** helper method to decide whether a given expression is product of at least two binary variables */
3897 static
3899  SCIP* scip, /**< SCIP data structure */
3900  SCIP_EXPR* expr /**< expression */
3901  )
3902 {
3903  int i;
3904 
3905  assert(expr != NULL);
3906 
3907  /* check whether the expression is a product */
3908  if( !SCIPisExprProduct(scip, expr) )
3909  return FALSE;
3910 
3911  /* don't consider products with a coefficient != 1 and products with a single child
3912  * simplification will take care of this expression later
3913  */
3914  if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3915  return FALSE;
3916 
3917  for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3918  {
3919  SCIP_EXPR* child;
3920  SCIP_VAR* var;
3921  SCIP_Real ub;
3922  SCIP_Real lb;
3923 
3924  child = SCIPexprGetChildren(expr)[i];
3925  assert(child != NULL);
3926 
3927  if( !SCIPisExprVar(scip, child) )
3928  return FALSE;
3929 
3930  var = SCIPgetVarExprVar(child);
3931  lb = SCIPvarGetLbLocal(var);
3932  ub = SCIPvarGetUbLocal(var);
3933 
3934  /* check whether variable is integer and has [0,1] as variable bounds */
3935  if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3936  return FALSE;
3937  }
3938 
3939  return TRUE;
3940 }
3941 
3942 /** helper method to collect all bilinear binary product terms */
3943 static
3945  SCIP* scip, /**< SCIP data structure */
3946  SCIP_EXPR* sumexpr, /**< sum expression */
3947  SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3948  SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3949  int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3950  int* nterms /**< pointer to store the total number of bilinear binary terms */
3951  )
3952 {
3953  int i;
3954 
3955  assert(sumexpr != NULL);
3956  assert(SCIPisExprSum(scip, sumexpr));
3957  assert(xs != NULL);
3958  assert(ys != NULL);
3959  assert(childidxs != NULL);
3960  assert(nterms != NULL);
3961 
3962  *nterms = 0;
3963 
3964  for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3965  {
3966  SCIP_EXPR* child;
3967 
3968  child = SCIPexprGetChildren(sumexpr)[i];
3969  assert(child != NULL);
3970 
3971  if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3972  {
3975 
3976  assert(x != NULL);
3977  assert(y != NULL);
3978 
3979  if( x != y )
3980  {
3981  xs[*nterms] = x;
3982  ys[*nterms] = y;
3983  childidxs[*nterms] = i;
3984  ++(*nterms);
3985  }
3986  }
3987  }
3988 
3989  return SCIP_OKAY;
3990 }
3991 
3992 /** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3993 static
3995  SCIP* scip, /**< SCIP data structure */
3996  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3997  SCIP_CONS* cons, /**< constraint */
3998  SCIP_VAR* facvar, /**< variable that has been factorized */
3999  SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
4000  SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
4001  int nvars, /**< total number of variables in sum_j c_ij x_j */
4002  SCIP_EXPR** newexpr, /**< pointer to store the new expression */
4003  int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4004  )
4005 {
4006  SCIP_VAR* auxvar;
4007  SCIP_CONS* newcons;
4008  SCIP_Real minact = 0.0;
4009  SCIP_Real maxact = 0.0;
4010  SCIP_Bool integral = TRUE;
4011  char name [SCIP_MAXSTRLEN];
4012  int i;
4013 
4014  assert(facvar != NULL);
4015  assert(vars != NULL);
4016  assert(nvars > 1);
4017  assert(newexpr != NULL);
4018 
4019  /* compute minimum and maximum activity of sum_j c_ij x_j */
4020  /* TODO could compute minact and maxact for facvar=0 and facvar=1 separately, taking implied bounds into account, allowing for possibly tighter big-M's below */
4021  for( i = 0; i < nvars; ++i )
4022  {
4023  minact += MIN(coefs[i], 0.0);
4024  maxact += MAX(coefs[i], 0.0);
4025  integral = integral && SCIPisIntegral(scip, coefs[i]);
4026  }
4027  assert(minact <= maxact);
4028 
4029  /* create and add auxiliary variable */
4030  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4031  SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
4032  SCIP_CALL( SCIPaddVar(scip, auxvar) );
4033 
4034  /* create and add z - maxact x <= 0 */
4035  if( !SCIPisZero(scip, maxact) )
4036  {
4037  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4038  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
4039  SCIP_CALL( SCIPaddCons(scip, newcons) );
4040  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4041  if( naddconss != NULL )
4042  ++(*naddconss);
4043  }
4044 
4045  /* create and add 0 <= z - minact x */
4046  if( !SCIPisZero(scip, minact) )
4047  {
4048  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4049  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
4050  SCIP_CALL( SCIPaddCons(scip, newcons) );
4051  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4052  if( naddconss != NULL )
4053  ++(*naddconss);
4054  }
4055 
4056  /* create and add minact <= sum_j c_j x_j - z + minact x_i */
4057  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4058  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
4059  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4060  if( !SCIPisZero(scip, minact) )
4061  {
4062  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
4063  }
4064  SCIP_CALL( SCIPaddCons(scip, newcons) );
4065  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4066  if( naddconss != NULL )
4067  ++(*naddconss);
4068 
4069  /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
4070  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
4071  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
4072  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
4073  if( !SCIPisZero(scip, maxact) )
4074  {
4075  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
4076  }
4077  SCIP_CALL( SCIPaddCons(scip, newcons) );
4078  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4079  if( naddconss != NULL )
4080  ++(*naddconss);
4081 
4082  /* create variable expression */
4083  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
4084 
4085  /* release auxvar */
4086  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
4087 
4088  return SCIP_OKAY;
4089 }
4090 
4091 /** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
4092 static
4094  SCIP* scip, /**< SCIP data structure */
4095  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4096  SCIP_CONS* cons, /**< constraint */
4097  SCIP_EXPR* sumexpr, /**< expression */
4098  int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
4099  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
4100  int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
4101  )
4102 {
4103  SCIP_EXPR** exprs = NULL;
4104  SCIP_VAR** tmpvars = NULL;
4105  SCIP_VAR** vars = NULL;
4106  SCIP_VAR** xs = NULL;
4107  SCIP_VAR** ys = NULL;
4108  SCIP_Real* exprcoefs = NULL;
4109  SCIP_Real* tmpcoefs = NULL;
4110  SCIP_Real* sumcoefs;
4111  SCIP_Bool* isused = NULL;
4112  int* childidxs = NULL;
4113  int* count = NULL;
4114  int nchildren;
4115  int nexprs = 0;
4116  int nterms;
4117  int nvars;
4118  int ntotalvars;
4119  int i;
4120 
4121  assert(sumexpr != NULL);
4122  assert(minterms > 1);
4123  assert(newexpr != NULL);
4124 
4125  *newexpr = NULL;
4126 
4127  /* check whether sumexpr is indeed a sum */
4128  if( !SCIPisExprSum(scip, sumexpr) )
4129  return SCIP_OKAY;
4130 
4131  nchildren = SCIPexprGetNChildren(sumexpr);
4132  sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4133  nvars = SCIPgetNVars(scip);
4134  ntotalvars = SCIPgetNTotalVars(scip);
4135 
4136  /* check whether there are enough terms available */
4137  if( nchildren < minterms )
4138  return SCIP_OKAY;
4139 
4140  /* allocate memory */
4141  SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4142  SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4143  SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4144 
4145  /* collect all bilinear binary product terms */
4146  SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4147 
4148  /* check whether there are enough terms available */
4149  if( nterms < minterms )
4150  goto TERMINATE;
4151 
4152  /* store how often each variable appears in a bilinear binary product */
4153  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
4154  SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4155  SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4156 
4157  SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4158  SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4159  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
4160  SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
4161 
4162  for( i = 0; i < nterms; ++i )
4163  {
4164  int xidx;
4165  int yidx;
4166 
4167  assert(xs[i] != NULL);
4168  assert(ys[i] != NULL);
4169 
4170  xidx = SCIPvarGetIndex(xs[i]);
4171  assert(xidx < ntotalvars);
4172  yidx = SCIPvarGetIndex(ys[i]);
4173  assert(yidx < ntotalvars);
4174 
4175  ++count[xidx];
4176  ++count[yidx];
4177 
4178  SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4179  SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4180  }
4181 
4182  /* sort variables; don't change order of count array because it depends on problem indices */
4183  {
4184  int* tmpcount;
4185 
4186  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4187  SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4188  SCIPfreeBufferArray(scip, &tmpcount);
4189  }
4190 
4191  for( i = 0; i < nvars; ++i )
4192  {
4193  SCIP_VAR* facvar = vars[i];
4194  int ntmpvars = 0;
4195  int j;
4196 
4197  /* skip candidate if there are not enough terms left */
4198  if( count[SCIPvarGetIndex(vars[i])] < minterms )
4199  continue;
4200 
4201  SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4202 
4203  /* collect variables for x_i * sum_j c_ij x_j */
4204  for( j = 0; j < nterms; ++j )
4205  {
4206  int childidx = childidxs[j];
4207  assert(childidx >= 0 && childidx < nchildren);
4208 
4209  if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4210  {
4211  SCIP_Real coef;
4212  int xidx;
4213  int yidx;
4214 
4215  coef = sumcoefs[childidx];
4216  assert(coef != 0.0);
4217 
4218  /* collect corresponding variable */
4219  tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4220  tmpcoefs[ntmpvars] = coef;
4221  ++ntmpvars;
4222 
4223  /* update counters */
4224  xidx = SCIPvarGetIndex(xs[j]);
4225  assert(xidx < ntotalvars);
4226  yidx = SCIPvarGetIndex(ys[j]);
4227  assert(yidx < ntotalvars);
4228  --count[xidx];
4229  --count[yidx];
4230  assert(count[xidx] >= 0);
4231  assert(count[yidx] >= 0);
4232 
4233  /* mark term to be used */
4234  isused[childidx] = TRUE;
4235  }
4236  }
4237  assert(ntmpvars >= minterms);
4238  assert(SCIPvarGetIndex(facvar) < ntotalvars);
4239  assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4240 
4241  /* create required constraints and store the generated expression */
4242  SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4243  exprcoefs[nexprs] = 1.0;
4244  ++nexprs;
4245  }
4246 
4247  /* factorization was only successful if at least one expression has been generated */
4248  if( nexprs > 0 )
4249  {
4250  int nexprsold = nexprs;
4251 
4252  /* add all children of the sum that have not been used */
4253  for( i = 0; i < nchildren; ++i )
4254  {
4255  if( !isused[i] )
4256  {
4257  exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4258  exprcoefs[nexprs] = sumcoefs[i];
4259  ++nexprs;
4260  }
4261  }
4262 
4263  /* create a new sum expression */
4264  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4265 
4266  /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4267  for( i = 0; i < nexprsold; ++i )
4268  {
4269  SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4270  }
4271  }
4272 
4273 TERMINATE:
4274  /* free memory */
4275  SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4276  SCIPfreeBufferArrayNull(scip, &tmpvars);
4277  SCIPfreeBufferArrayNull(scip, &exprcoefs);
4278  SCIPfreeBufferArrayNull(scip, &exprs);
4279  SCIPfreeBufferArrayNull(scip, &vars);
4280  SCIPfreeBufferArrayNull(scip, &isused);
4281  SCIPfreeBufferArrayNull(scip, &count);
4282  SCIPfreeBufferArray(scip, &childidxs);
4283  SCIPfreeBufferArray(scip, &ys);
4284  SCIPfreeBufferArray(scip, &xs);
4285 
4286  return SCIP_OKAY;
4287 }
4288 
4289 /** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4290 static
4292  SCIP* scip, /**< SCIP data structure */
4293  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4294  SCIP_EXPR* prodexpr, /**< product expression */
4295  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4296  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4297  SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4298  )
4299 {
4300  SCIP_VAR** vars;
4301  SCIP_CONS* cons;
4302  SCIP_Real* coefs;
4303  SCIP_VAR* w;
4304  char* name;
4305  int nchildren;
4306  int i;
4307 
4308  assert(conshdlr != NULL);
4309  assert(prodexpr != NULL);
4310  assert(SCIPisExprProduct(scip, prodexpr));
4311  assert(newexpr != NULL);
4312 
4313  nchildren = SCIPexprGetNChildren(prodexpr);
4314  assert(nchildren >= 2);
4315 
4316  /* memory to store the variables of the variable expressions (+1 for w) and their name */
4317  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4318  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4319  SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4320 
4321  /* prepare the names of the variable and the constraints */
4322  strcpy(name, "binreform");
4323  for( i = 0; i < nchildren; ++i )
4324  {
4325  vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
4326  coefs[i] = 1.0;
4327  assert(vars[i] != NULL);
4328  (void) strcat(name, "_");
4329  (void) strcat(name, SCIPvarGetName(vars[i]));
4330  }
4331 
4332  /* create and add variable */
4333  SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4334  SCIP_CALL( SCIPaddVar(scip, w) );
4335  SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4336 
4337  /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4338  if( nchildren == 2 && !empathy4and )
4339  {
4340  SCIP_VAR* x = vars[0];
4341  SCIP_VAR* y = vars[1];
4342 
4343  assert(x != NULL);
4344  assert(y != NULL);
4345  assert(x != y);
4346 
4347  /* create and add x - w >= 0 */
4348  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4349  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4350  SCIP_CALL( SCIPaddCons(scip, cons) );
4351  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4352 
4353  /* create and add y - w >= 0 */
4354  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4355  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4356  SCIP_CALL( SCIPaddCons(scip, cons) );
4357  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4358 
4359  /* create and add x + y - w <= 1 */
4360  vars[2] = w;
4361  coefs[2] = -1.0;
4362  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4363  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4364  SCIP_CALL( SCIPaddCons(scip, cons) );
4365  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4366 
4367  /* update number of added constraints */
4368  if( naddconss != NULL )
4369  *naddconss += 3;
4370  }
4371  else
4372  {
4373  /* create, add, and release AND constraint */
4374  SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4375  SCIP_CALL( SCIPaddCons(scip, cons) );
4376  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4377  SCIPdebugMsg(scip, " create AND constraint\n");
4378 
4379  /* update number of added constraints */
4380  if( naddconss != NULL )
4381  *naddconss += 1;
4382  }
4383 
4384  /* create variable expression */
4385  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4386 
4387  /* release created variable */
4388  SCIP_CALL( SCIPreleaseVar(scip, &w) );
4389 
4390  /* free memory */
4391  SCIPfreeBufferArray(scip, &name);
4392  SCIPfreeBufferArray(scip, &coefs);
4393  SCIPfreeBufferArray(scip, &vars);
4394 
4395  return SCIP_OKAY;
4396 }
4397 
4398 /** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4399 static
4401  SCIP* scip, /**< SCIP data structure */
4402  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4403  SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4404  SCIP_EXPR* prodexpr, /**< product expression */
4405  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4406  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4407  int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4408  )
4409 {
4410  SCIP_CONSHDLRDATA* conshdlrdata;
4411  int nchildren;
4412 
4413  assert(prodexpr != NULL);
4414  assert(newexpr != NULL);
4415 
4416  *newexpr = NULL;
4417 
4418  /* only consider products of binary variables */
4419  if( !isBinaryProduct(scip, prodexpr) )
4420  return SCIP_OKAY;
4421 
4422  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4423  assert(conshdlrdata != NULL);
4424  nchildren = SCIPexprGetNChildren(prodexpr);
4425  assert(nchildren >= 2);
4426 
4427  /* check whether there is already an expression that represents the product */
4428  if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4429  {
4430  *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4431  assert(*newexpr != NULL);
4432 
4433  /* capture expression */
4434  SCIPcaptureExpr(*newexpr);
4435  }
4436  else
4437  {
4438  SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4439 
4440  if( nchildren == 2 )
4441  {
4442  SCIP_CLIQUE** xcliques;
4443  SCIP_VAR* x;
4444  SCIP_VAR* y;
4445  SCIP_Bool found_clique = FALSE;
4446  int c;
4447 
4448  /* get variables from the product expression */
4449  x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4450  assert(x != NULL);
4451  y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4452  assert(y != NULL);
4453  assert(x != y);
4454 
4455  /* first try to find a clique containing both variables */
4456  xcliques = SCIPvarGetCliques(x, TRUE);
4457 
4458  /* look in cliques containing x */
4459  for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4460  {
4461  if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4462  {
4463  /* create zero value expression */
4464  SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4465 
4466  if( nchgcoefs != NULL )
4467  *nchgcoefs += 1;
4468 
4469  found_clique = TRUE;
4470  break;
4471  }
4472 
4473  if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4474  {
4475  /* create variable expression for x */
4476  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4477 
4478  if( nchgcoefs != NULL )
4479  *nchgcoefs += 2;
4480 
4481  found_clique = TRUE;
4482  break;
4483  }
4484  }
4485 
4486  if( !found_clique )
4487  {
4488  xcliques = SCIPvarGetCliques(x, FALSE);
4489 
4490  /* look in cliques containing complement of x */
4491  for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4492  {
4493  if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4494  {
4495  /* create variable expression for y */
4496  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4497 
4498  if( nchgcoefs != NULL )
4499  *nchgcoefs += 1;
4500 
4501  found_clique = TRUE;
4502  break;
4503  }
4504 
4505  if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4506  {
4507  /* create sum expression */
4508  SCIP_EXPR* sum_children[2];
4509  SCIP_Real sum_coefs[2];
4510  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4511  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4512  sum_coefs[0] = 1.0;
4513  sum_coefs[1] = 1.0;
4514  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4515 
4516  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4517  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4518 
4519  if( nchgcoefs != NULL )
4520  *nchgcoefs += 3;
4521 
4522  found_clique = TRUE;
4523  break;
4524  }
4525  }
4526  }
4527 
4528  /* if the variables are not in a clique, do standard linearization */
4529  if( !found_clique )
4530  {
4531  SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4532  }
4533  }
4534  else
4535  {
4536  /* linearize binary product using an AND constraint because nchildren > 2 */
4537  SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4538  }
4539 
4540  /* hash variable expression */
4541  SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4542  }
4543 
4544  return SCIP_OKAY;
4545 }
4546 
4547 /** helper function to replace binary products in a given constraint */
4548 static
4550  SCIP* scip, /**< SCIP data structure */
4551  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4552  SCIP_CONS* cons, /**< constraint */
4553  SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4554  SCIP_EXPRITER* it, /**< expression iterator */
4555  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4556  int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4557  )
4558 {
4559  SCIP_CONSHDLRDATA* conshdlrdata;
4560  SCIP_CONSDATA* consdata;
4561  SCIP_EXPR* expr;
4562 
4563  assert(conshdlr != NULL);
4564  assert(cons != NULL);
4565  assert(exprmap != NULL);
4566  assert(it != NULL);
4567 
4568  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4569  assert(conshdlrdata != NULL);
4570 
4571  consdata = SCIPconsGetData(cons);
4572  assert(consdata != NULL);
4573  assert(consdata->expr != NULL);
4574 
4575  SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4576 
4577  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4578  {
4579  SCIP_EXPR* newexpr = NULL;
4580  SCIP_EXPR* childexpr;
4581  int childexpridx;
4582 
4583  childexpridx = SCIPexpriterGetChildIdxDFS(it);
4584  assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4585  childexpr = SCIPexpriterGetChildExprDFS(it);
4586  assert(childexpr != NULL);
4587 
4588  /* try to factorize variables in a sum expression that contains several products of binary variables */
4589  if( conshdlrdata->reformbinprodsfac > 1 )
4590  {
4591  SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4592  }
4593 
4594  /* try to create an expression that represents a product of binary variables */
4595  if( newexpr == NULL )
4596  {
4597  SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4598  }
4599 
4600  if( newexpr != NULL )
4601  {
4602  assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4603 
4604  /* replace product expression */
4605  SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4606 
4607  /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4608  SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4609 
4610  /* mark the constraint to not be simplified anymore */
4611  consdata->issimplified = FALSE;
4612  }
4613  }
4614 
4615  return SCIP_OKAY;
4616 }
4617 
4618 /** reformulates products of binary variables during presolving in the following way:
4619  *
4620  * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4621  * Each term \f$x_i x_j\f$ is reformulated with the help of an extra (implicit integer) variable \f$z_{ij}\f$ in {0,1}:
4622  * \f[
4623  * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4624  * \f]
4625  *
4626  * Before reformulating \f$x_i x_j\f$ in this way, it is checked whether there is a clique that contains \f$x_i\f$ and \f$x_j\f$.
4627  * These cliques allow for a better reformulation. There are four cases:
4628  *
4629  * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4630  * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4631  * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4632  * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4633  *
4634  * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4635  *
4636  * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4637  * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4638  * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4639  * Such a lower sum is reformulated with only one extra variable w_i:
4640  * \f{align}{
4641  * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4642  * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4643  * \text{minact}\, x_i & \leq w_i, \\
4644  * w_i &\leq \text{maxact}\, x_i, \\
4645  * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4646  * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4647  * \f}
4648  * We mark \f$w_i\f$ to be implicit integer if all \f$Q_{ij}\f$ are integer. After each replacement of a lower sum, it
4649  * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4650  * of terms are prioritized.
4651  */
4652 static
4654  SCIP* scip, /**< SCIP data structure */
4655  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4656  SCIP_CONS** conss, /**< constraints */
4657  int nconss, /**< total number of constraints */
4658  int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4659  int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4660  )
4661 {
4662  SCIP_CONSHDLRDATA* conshdlrdata;
4663  SCIP_HASHMAP* exprmap;
4664  SCIP_EXPRITER* it;
4665  int c;
4666 
4667  assert(conshdlr != NULL);
4668 
4669  /* no nonlinear constraints or binary variables -> skip */
4670  if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4671  return SCIP_OKAY;
4672  assert(conss != NULL);
4673 
4674  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4675  assert(conshdlrdata != NULL);
4676 
4677  /* create expression hash map */
4678  SCIP_CALL( SCIPhashmapCreate(&exprmap, SCIPblkmem(scip), SCIPgetNVars(scip)) );
4679 
4680  /* create expression iterator */
4681  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4684 
4685  SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4686 
4687  for( c = 0; c < nconss; ++c )
4688  {
4689  SCIP_CONSDATA* consdata;
4690  SCIP_EXPR* newexpr = NULL;
4691 
4692  assert(conss[c] != NULL);
4693 
4694  consdata = SCIPconsGetData(conss[c]);
4695  assert(consdata != NULL);
4696 
4697  /* try to reformulate the root expression */
4698  if( conshdlrdata->reformbinprodsfac > 1 )
4699  {
4700  SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4701  }
4702 
4703  /* release the root node if another expression has been found */
4704  if( newexpr != NULL )
4705  {
4706  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4707  consdata->expr = newexpr;
4708 
4709  /* mark constraint to be not simplified anymore */
4710  consdata->issimplified = FALSE;
4711  }
4712 
4713  /* replace each product of binary variables separately */
4714  SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4715  }
4716 
4717  /* free memory */
4718  SCIPhashmapFree(&exprmap);
4719  SCIPfreeExpriter(&it);
4720 
4721  return SCIP_OKAY;
4722 }
4723 
4724 /** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4725  *
4726  * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4727  * Then scale by -1 if
4728  * - \f$n_+ < n_-\f$, or
4729  * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4730  */
4731 static
4733  SCIP* scip, /**< SCIP data structure */
4734  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4735  SCIP_CONS* cons, /**< nonlinear constraint */
4736  SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4737  )
4738 {
4739  SCIP_CONSDATA* consdata;
4740  int i;
4741 
4742  assert(cons != NULL);
4743 
4744  consdata = SCIPconsGetData(cons);
4745  assert(consdata != NULL);
4746 
4747  if( SCIPisExprSum(scip, consdata->expr) )
4748  {
4749  SCIP_Real* coefs;
4750  SCIP_Real constant;
4751  int nchildren;
4752  int counter = 0;
4753 
4754  coefs = SCIPgetCoefsExprSum(consdata->expr);
4755  constant = SCIPgetConstantExprSum(consdata->expr);
4756  nchildren = SCIPexprGetNChildren(consdata->expr);
4757 
4758  /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4759  if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4760  {
4761  SCIP_EXPR* expr;
4762  expr = consdata->expr;
4763 
4764  consdata->expr = SCIPexprGetChildren(expr)[0];
4765  assert(!SCIPisExprSum(scip, consdata->expr));
4766 
4767  SCIPcaptureExpr(consdata->expr);
4768 
4769  SCIPswapReals(&consdata->lhs, &consdata->rhs);
4770  consdata->lhs = -consdata->lhs;
4771  consdata->rhs = -consdata->rhs;
4772 
4773  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4774  *changed = TRUE;
4775  return SCIP_OKAY;
4776  }
4777 
4778  /* compute n_+ - n_i */
4779  for( i = 0; i < nchildren; ++i )
4780  counter += coefs[i] > 0 ? 1 : -1;
4781 
4782  if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4783  {
4784  SCIP_EXPR* expr;
4785  SCIP_Real* newcoefs;
4786 
4787  /* allocate memory */
4788  SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4789 
4790  for( i = 0; i < nchildren; ++i )
4791  newcoefs[i] = -coefs[i];
4792 
4793  /* create a new sum expression */
4794  SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4795 
4796  /* replace expression in constraint data and scale sides */
4797  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4798  consdata->expr = expr;
4799  SCIPswapReals(&consdata->lhs, &consdata->rhs);
4800  consdata->lhs = -consdata->lhs;
4801  consdata->rhs = -consdata->rhs;
4802 
4803  /* free memory */
4804  SCIPfreeBufferArray(scip, &newcoefs);
4805 
4806  *changed = TRUE;
4807  }
4808  }
4809 
4810  return SCIP_OKAY;
4811 }
4812 
4813 /** forbid multiaggrations of variables that appear nonlinear in constraints */
4814 static
4816  SCIP* scip, /**< SCIP data structure */
4817  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4818  SCIP_CONS** conss, /**< constraints */
4819  int nconss /**< number of constraints */
4820  )
4821 {
4822  SCIP_EXPRITER* it;
4823  SCIP_CONSDATA* consdata;
4824  SCIP_EXPR* expr;
4825  int c;
4826 
4827  assert(scip != NULL);
4828  assert(conshdlr != NULL);
4829 
4830  if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4831  return SCIP_OKAY;
4832 
4833  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4835 
4836  for( c = 0; c < nconss; ++c )
4837  {
4838  consdata = SCIPconsGetData(conss[c]);
4839  assert(consdata != NULL);
4840 
4841  /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4842  * i.e., skip children of sum that are variables
4843  */
4844  if( SCIPisExprSum(scip, consdata->expr) )
4845  {
4846  int i;
4847  SCIP_EXPR* child;
4848  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4849  {
4850  child = SCIPexprGetChildren(consdata->expr)[i];
4851 
4852  /* skip variable expression, as they correspond to a linear term */
4853  if( SCIPisExprVar(scip, child) )
4854  continue;
4855 
4856  for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4857  if( SCIPisExprVar(scip, expr) )
4858  {
4860  }
4861  }
4862  }
4863  else
4864  {
4865  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4866  if( SCIPisExprVar(scip, expr) )
4867  {
4869  }
4870  }
4871  }
4872 
4873  SCIPfreeExpriter(&it);
4874 
4875  return SCIP_OKAY;
4876 }
4877 
4878 /** simplifies expressions and replaces common subexpressions for a set of constraints
4879  * @todo put the constant to the constraint sides
4880  */
4881 static
4883  SCIP* scip, /**< SCIP data structure */
4884  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4885  SCIP_CONS** conss, /**< constraints */
4886  int nconss, /**< total number of constraints */
4887  SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4888  SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4889  int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4890  int* naddconss, /**< counter to add number of added constraints, or NULL */
4891  int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4892  )
4893 {
4894  SCIP_CONSHDLRDATA* conshdlrdata;
4895  SCIP_CONSDATA* consdata;
4896  int* nlockspos;
4897  int* nlocksneg;
4898  SCIP_Bool havechange;
4899  int i;
4900 
4901  assert(scip != NULL);
4902  assert(conshdlr != NULL);
4903  assert(conss != NULL);
4904  assert(nconss > 0);
4905  assert(infeasible != NULL);
4906 
4907  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4908  assert(conshdlrdata != NULL);
4909 
4910  /* update number of canonicalize calls */
4911  ++(conshdlrdata->ncanonicalizecalls);
4912 
4913  SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4914 
4915  *infeasible = FALSE;
4916 
4917  /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4918  havechange = conshdlrdata->ncanonicalizecalls == 1;
4919 
4920  /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4921  SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4922 
4923  /* allocate memory for storing locks of each constraint */
4924  SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4925  SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4926 
4927  /* unlock all constraints */
4928  for( i = 0; i < nconss; ++i )
4929  {
4930  assert(conss[i] != NULL);
4931 
4932  consdata = SCIPconsGetData(conss[i]);
4933  assert(consdata != NULL);
4934 
4935  /* remember locks */
4936  nlockspos[i] = consdata->nlockspos;
4937  nlocksneg[i] = consdata->nlocksneg;
4938 
4939  /* remove locks */
4940  SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4941  assert(consdata->nlockspos == 0);
4942  assert(consdata->nlocksneg == 0);
4943  }
4944 
4945 #ifndef NDEBUG
4946  /* check whether all locks of each expression have been removed */
4947  for( i = 0; i < nconss; ++i )
4948  {
4949  SCIP_EXPR* expr;
4950  SCIP_EXPRITER* it;
4951 
4952  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4953 
4954  consdata = SCIPconsGetData(conss[i]);
4955  assert(consdata != NULL);
4956 
4957  SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_RTOPOLOGIC, TRUE) );
4958  for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4959  {
4960  assert(expr != NULL);
4961  assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4962  assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4963  }
4964  SCIPfreeExpriter(&it);
4965  }
4966 #endif
4967 
4968  /* reformulate products of binary variables */
4969  if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4970  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4971  {
4972  int tmpnaddconss = 0;
4973  int tmpnchgcoefs = 0;
4974 
4975  /* call this function before simplification because expressions might not be simplified after reformulating
4976  * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4977  */
4978  SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4979 
4980  /* update counters */
4981  if( naddconss != NULL )
4982  *naddconss += tmpnaddconss;
4983  if( nchgcoefs != NULL )
4984  *nchgcoefs += tmpnchgcoefs;
4985 
4986  /* check whether at least one expression has changed */
4987  if( tmpnaddconss + tmpnchgcoefs > 0 )
4988  havechange = TRUE;
4989  }
4990 
4991  for( i = 0; i < nconss; ++i )
4992  {
4993  consdata = SCIPconsGetData(conss[i]);
4994  assert(consdata != NULL);
4995 
4996  /* call simplify for each expression */
4997  if( !consdata->issimplified && consdata->expr != NULL )
4998  {
4999  SCIP_EXPR* simplified;
5000  SCIP_Bool changed;
5001 
5002  changed = FALSE;
5003  SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
5004  consdata->issimplified = TRUE;
5005 
5006  if( changed )
5007  havechange = TRUE;
5008 
5009  /* If root expression changed, then we need to take care updating the locks as well (the consdata is the one holding consdata->expr "as a child").
5010  * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
5011  */
5012  if( simplified != consdata->expr )
5013  {
5014  assert(changed);
5015 
5016  /* release old expression */
5017  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
5018 
5019  /* store simplified expression */
5020  consdata->expr = simplified;
5021  }
5022  else
5023  {
5024  /* The simplify captures simplified in any case, also if nothing has changed.
5025  * Therefore, we have to release it here.
5026  */
5027  SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
5028  }
5029 
5030  if( *infeasible )
5031  break;
5032 
5033  /* scale constraint sides */
5034  SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
5035 
5036  if( changed )
5037  havechange = TRUE;
5038 
5039  /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
5040  if( SCIPisExprValue(scip, consdata->expr) )
5041  {
5042  SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5043  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
5044  (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
5045  {
5046  SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
5047  SCIPdebugPrintCons(scip, conss[i], NULL);
5048  *infeasible = TRUE;
5049  break;
5050  }
5051  else
5052  {
5053  SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5054  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
5055  if( ndelconss != NULL )
5056  ++*ndelconss;
5057  havechange = TRUE;
5058  }
5059  }
5060  }
5061  }
5062 
5063  /* replace common subexpressions */
5064  if( havechange && !*infeasible )
5065  {
5066  SCIP_CONS** consssorted;
5067  SCIP_EXPR** rootexprs;
5068  SCIP_Bool replacedroot;
5069 
5070  SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
5071  for( i = 0; i < nconss; ++i )
5072  rootexprs[i] = SCIPconsGetData(conss[i])->expr;
5073 
5074  SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
5075 
5076  /* update pointer to root expr in constraints, if any has changed
5077  * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
5078  */
5079  if( replacedroot )
5080  for( i = 0; i < nconss; ++i )
5081  SCIPconsGetData(conss[i])->expr = rootexprs[i];
5082 
5083  SCIPfreeBufferArray(scip, &rootexprs);
5084 
5085  /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
5086  * been changed after simplification; now we completely recollect all variable expression and variable events
5087  */
5088 
5089  /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
5090  * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
5091  */
5092  SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
5093  SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
5094 
5095  for( i = nconss-1; i >= 0; --i )
5096  {
5097  assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
5098  if( SCIPconsIsDeleted(consssorted[i]) )
5099  continue;
5100 
5101  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5102  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
5103  }
5104  for( i = 0; i < nconss; ++i )
5105  {
5106  if( SCIPconsIsDeleted(consssorted[i]) )
5107  continue;
5108 
5109  SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
5110  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
5111  }
5112 
5113  SCIPfreeBufferArray(scip, &consssorted);
5114 
5115  /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
5116  * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
5117  * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
5118  */
5119  SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
5120  }
5121 
5122  /* restore locks */
5123  for( i = 0; i < nconss; ++i )
5124  {
5125  if( SCIPconsIsDeleted(conss[i]) )
5126  continue;
5127 
5128  SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5129  }
5130 
5131  /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5132  * TODO can we skip this in presoltiming fast?
5133  */
5134  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5135  {
5136  /* reset one of the number of detections counter to count only current presolving round */
5137  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5138  SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5139 
5140  SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5141  }
5142 
5143  /* free allocated memory */
5144  SCIPfreeBufferArray(scip, &nlocksneg);
5145  SCIPfreeBufferArray(scip, &nlockspos);
5146 
5147  SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5148 
5149  return SCIP_OKAY;
5150 }
5151 
5152 /** merges constraints that have the same root expression */
5153 static
5155  SCIP* scip, /**< SCIP data structure */
5156  SCIP_CONS** conss, /**< constraints to process */
5157  int nconss, /**< number of constraints */
5158  SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5159  )
5160 {
5161  SCIP_HASHMAP* expr2cons;
5162  SCIP_Bool* updatelocks;
5163  int* nlockspos;
5164  int* nlocksneg;
5165  int c;
5166 
5167  assert(success != NULL);
5168 
5169  *success = FALSE;
5170 
5171  /* not enough constraints available */
5172  if( nconss <= 1 )
5173  return SCIP_OKAY;
5174 
5175  SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5176  SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5177  SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5178  SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5179 
5180  for( c = 0; c < nconss; ++c )
5181  {
5182  SCIP_CONSDATA* consdata;
5183 
5184  /* ignore deleted constraints */
5185  if( SCIPconsIsDeleted(conss[c]) )
5186  continue;
5187 
5188  consdata = SCIPconsGetData(conss[c]);
5189  assert(consdata != NULL);
5190 
5191  /* add expression to the hash map if not seen so far */
5192  if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5193  {
5194  SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5195  }
5196  else
5197  {
5198  SCIP_CONSDATA* imgconsdata;
5199  int idx;
5200 
5201  idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5202  assert(idx >= 0 && idx < nconss);
5203 
5204  imgconsdata = SCIPconsGetData(conss[idx]);
5205  assert(imgconsdata != NULL);
5206  assert(imgconsdata->expr == consdata->expr);
5207 
5208  SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5209  SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5210 
5211  /* check whether locks need to be updated */
5212  if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5213  || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5214  {
5215  nlockspos[idx] = imgconsdata->nlockspos;
5216  nlocksneg[idx] = imgconsdata->nlocksneg;
5217  SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5218  updatelocks[idx] = TRUE;
5219  }
5220 
5221  /* update constraint sides */
5222  imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5223  imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5224 
5225  /* delete constraint */
5226  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5227  *success = TRUE;
5228  }
5229  }
5230 
5231  /* restore locks of updated constraints */
5232  if( *success )
5233  {
5234  for( c = 0; c < nconss; ++c )
5235  {
5236  if( updatelocks[c] )
5237  {
5238  SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5239  }
5240  }
5241  }
5242 
5243  /* free memory */
5244  SCIPfreeBufferArray(scip, &nlocksneg);
5245  SCIPfreeBufferArray(scip, &nlockspos);
5246  SCIPfreeBufferArray(scip, &updatelocks);
5247  SCIPhashmapFree(&expr2cons);
5248 
5249  return SCIP_OKAY;
5250 }
5251 
5252 /** interval evaluation of variables as used in redundancy check
5253  *
5254  * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5255  */
5256 static
5257 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5258 { /*lint --e{715}*/
5259  SCIP_CONSHDLRDATA* conshdlrdata;
5260  SCIP_INTERVAL interval;
5261  SCIP_Real lb;
5262  SCIP_Real ub;
5263 
5264  assert(scip != NULL);
5265  assert(var != NULL);
5266 
5267  conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5268  assert(conshdlrdata != NULL);
5269 
5270  if( conshdlrdata->globalbounds )
5271  {
5272  lb = SCIPvarGetLbGlobal(var);
5273  ub = SCIPvarGetUbGlobal(var);
5274  }
5275  else
5276  {
5277  lb = SCIPvarGetLbLocal(var);
5278  ub = SCIPvarGetUbLocal(var);
5279  }
5280  assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5281 
5282  /* relax variable bounds, if there are bounds and variable is not fixed
5283  * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5284  */
5285  if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5286  {
5287  if( !SCIPisInfinity(scip, -lb) )
5288  lb -= SCIPfeastol(scip);
5289 
5290  if( !SCIPisInfinity(scip, ub) )
5291  ub += SCIPfeastol(scip);
5292  }
5293 
5294  /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5295  lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
5297  assert(lb <= ub);
5298 
5299  SCIPintervalSetBounds(&interval, lb, ub);
5300 
5301  return interval;
5302 }
5303 
5304 /** removes constraints that are always feasible or very simple
5305  *
5306  * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5307  * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5308  * might violate variable bounds by up to feastol, too.
5309  * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5310  *
5311  * Also removes constraints of the form lhs &le; variable &le; rhs.
5312  *
5313  * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5314  *
5315  * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5316  * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5317  * would appear as if the constraint is redundant.
5318  */
5319 static
5321  SCIP* scip, /**< SCIP data structure */
5322  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5323  SCIP_CONS** conss, /**< constraints to propagate */
5324  int nconss, /**< total number of constraints */
5325  SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5326  int* ndelconss, /**< buffer to add the number of deleted constraints */
5327  int* nchgbds /**< buffer to add the number of variable bound tightenings */
5328  )
5329 {
5330  SCIP_CONSHDLRDATA* conshdlrdata;
5331  SCIP_CONSDATA* consdata;
5332  SCIP_INTERVAL activity;
5333  SCIP_INTERVAL sides;
5334  int i;
5335 
5336  assert(scip != NULL);
5337  assert(conshdlr != NULL);
5338  assert(conss != NULL);
5339  assert(nconss >= 0);
5340  assert(cutoff != NULL);
5341  assert(ndelconss != NULL);
5342  assert(nchgbds != NULL);
5343 
5344  /* no constraints to check */
5345  if( nconss == 0 )
5346  return SCIP_OKAY;
5347 
5348  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5349  assert(conshdlrdata != NULL);
5350 
5351  /* increase curboundstag and set lastvaractivitymethodchange
5352  * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5353  * for the redundancy check differently than for domain propagation
5354  * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5355  */
5356  ++conshdlrdata->curboundstag;
5357  assert(conshdlrdata->curboundstag > 0);
5358  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5359  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5360  conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5361 
5362  SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5363 
5364  *cutoff = FALSE;
5365  for( i = 0; i < nconss; ++i )
5366  {
5367  if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5368  continue;
5369 
5370  consdata = SCIPconsGetData(conss[i]);
5371  assert(consdata != NULL);
5372 
5373  /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5374  if( SCIPisExprValue(scip, consdata->expr) )
5375  {
5376  SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5377 
5378  if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5379  (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5380  {
5381  SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5382  *cutoff = TRUE;
5383 
5384  goto TERMINATE;
5385  }
5386 
5387  SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5388 
5389  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5390  ++*ndelconss;
5391 
5392  continue;
5393  }
5394 
5395  /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5396  if( SCIPisExprVar(scip, consdata->expr) )
5397  {
5398  SCIP_VAR* var;
5399  SCIP_Bool tightened;
5400 
5401  var = SCIPgetVarExprVar(consdata->expr);
5402  assert(var != NULL);
5403 
5404  SCIPdebugMsg(scip, "variable constraint <%s> can be made redundant: <%s>[%g,%g] in [%g,%g]\n", SCIPconsGetName(conss[i]), SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), consdata->lhs, consdata->rhs);
5405 
5406  /* ensure that variable bounds are within constraint sides */
5407  if( !SCIPisInfinity(scip, -consdata->lhs) )
5408  {
5409  SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5410 
5411  if( tightened )
5412  ++*nchgbds;
5413 
5414  if( *cutoff )
5415  goto TERMINATE;
5416  }
5417 
5418  if( !SCIPisInfinity(scip, consdata->rhs) )
5419  {
5420  SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5421 
5422  if( tightened )
5423  ++*nchgbds;
5424 
5425  if( *cutoff )
5426  goto TERMINATE;
5427  }
5428 
5429  /* delete the (now) redundant constraint locally */
5430  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5431  ++*ndelconss;
5432 
5433  continue;
5434  }
5435 
5436  /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5437  * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5438  * variable bounds by up to feastol
5439  * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5440  */
5441  SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5442  SCIPdebugPrintCons(scip, conss[i], NULL);
5443 
5444  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5445  assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5446 
5447  /* it is unlikely that we detect infeasibility by doing forward propagation */
5448  if( *cutoff )
5449  {
5450  SCIPdebugMsg(scip, " -> cutoff\n");
5451  goto TERMINATE;
5452  }
5453 
5454  assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5455  activity = SCIPexprGetActivity(consdata->expr);
5456 
5457  /* relax sides by feastol
5458  * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5459  */
5460  SCIPintervalSetBounds(&sides,
5461  SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5462  SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5463 
5464  if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5465  {
5466  SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5467 
5468  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5469  ++*ndelconss;
5470 
5471  continue;
5472  }
5473 
5474  SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5475  }
5476 
5477 TERMINATE:
5478  /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5479  ++conshdlrdata->curboundstag;
5480  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5481  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5482  conshdlrdata->intevalvar = intEvalVarBoundTightening;
5483 
5484  return SCIP_OKAY;
5485 }
5486 
5487 /** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5488 static
5490  SCIP* scip, /**< SCIP data structure */
5491  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5492  SCIP_CONS* cons, /**< source constraint to try to convert */
5493  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5494  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5495  int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5496  )
5497 {
5498  SCIP_CONSHDLRDATA* conshdlrdata;
5499  SCIP_CONSDATA* consdata;
5500  SCIP_CONS** upgdconss;
5501  int upgdconsssize;
5502  int nupgdconss_;
5503  int i;
5504 
5505  assert(scip != NULL);
5506  assert(conshdlr != NULL);
5507  assert(cons != NULL);
5508  assert(!SCIPconsIsModifiable(cons));
5509  assert(upgraded != NULL);
5510  assert(nupgdconss != NULL);
5511  assert(naddconss != NULL);
5512 
5513  *upgraded = FALSE;
5514 
5515  nupgdconss_ = 0;
5516 
5517  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5518  assert(conshdlrdata != NULL);
5519 
5520  /* if there are no upgrade methods, we can stop */
5521  if( conshdlrdata->nconsupgrades == 0 )
5522  return SCIP_OKAY;
5523 
5524  upgdconsssize = 2;
5525  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5526 
5527  /* call the upgrading methods */
5528  SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5529  SCIPdebugPrintCons(scip, cons, NULL);
5530 
5531  consdata = SCIPconsGetData(cons);
5532  assert(consdata != NULL);
5533 
5534  /* try all upgrading methods in priority order in case the upgrading step is enable */
5535  for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5536  {
5537  if( !conshdlrdata->consupgrades[i]->active )
5538  continue;
5539 
5540  assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5541 
5542  SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5543 
5544  while( nupgdconss_ < 0 )
5545  {
5546  /* upgrade function requires more memory: resize upgdconss and call again */
5547  assert(-nupgdconss_ > upgdconsssize);
5548  upgdconsssize = -nupgdconss_;
5549  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5550 
5551  SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5552 
5553  assert(nupgdconss_ != 0);
5554  }
5555 
5556  if( nupgdconss_ > 0 )
5557  {
5558  /* got upgrade */
5559  int j;
5560 
5561  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5562 
5563  /* add the upgraded constraints to the problem and forget them */
5564  for( j = 0; j < nupgdconss_; ++j )
5565  {
5566  SCIPdebugMsgPrint(scip, "\t");
5567  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5568 
5569  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5570  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5571  }
5572 
5573  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5574  *nupgdconss += 1;
5575  *naddconss += nupgdconss_ - 1;
5576  *upgraded = TRUE;
5577 
5578  /* delete upgraded constraint */
5579  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5580  SCIP_CALL( SCIPdelCons(scip, cons) );
5581 
5582  break;
5583  }
5584  }
5585 
5586  SCIPfreeBufferArray(scip, &upgdconss);
5587 
5588  return SCIP_OKAY;
5589 }
5590 
5591 /** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5592  * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5593  * variable bounds, and is not binary
5594  */
5595 static
5597  SCIP* scip, /**< SCIP data structure */
5598  SCIP_EXPR* expr /**< variable expression */
5599  )
5600 {
5601  SCIP_VAR* var;
5602  SCIP_EXPR_OWNERDATA* ownerdata;
5603 
5604  assert(SCIPisExprVar(scip, expr));
5605 
5606  var = SCIPgetVarExprVar(expr);
5607  assert(var != NULL);
5608 
5609  ownerdata = SCIPexprGetOwnerData(expr);
5610  assert(ownerdata != NULL);
5611 
5612  return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5613  && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5614  && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5615  && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var))
5617  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5618 }
5619 
5620 /** removes all variable expressions that are contained in a given expression from a hash map */
5621 static
5623  SCIP* scip, /**< SCIP data structure */
5624  SCIP_EXPR* expr, /**< expression */
5625  SCIP_EXPRITER* it, /**< expression iterator */
5626  SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5627  )
5628 {
5629  SCIP_EXPR* e;