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