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