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 50 /**< 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 branchfracweight; /**< weight by how much to consider fractionality of integer variables in branching score for spatial branching */
313  SCIP_Real branchdualweight; /**< weight by how much to consider the dual values of rows that contain a variable for its branching score */
314  SCIP_Real branchpscostweight; /**< weight by how much to consider the pseudo cost of a variable for its branching score */
315  SCIP_Real branchdomainweight; /**< weight by how much to consider the domain width in branching score */
316  SCIP_Real branchvartypeweight;/**< weight by how much to consider variable type in branching score */
317  char branchscoreagg; /**< how to aggregate several branching scores given for the same expression ('a'verage, 'm'aximum, or 's'um) */
318  char branchviolsplit; /**< method used to split violation in expression onto variables ('u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width) */
319  SCIP_Real branchpscostreliable; /**< minimum pseudo-cost update count required to consider pseudo-costs reliable */
320  SCIP_Real branchmixfractional; /**< minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables */
321  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) */
322  SCIP_Bool assumeconvex; /**< whether to assume that any constraint is convex */
323 
324  /* statistics */
325  SCIP_Longint nweaksepa; /**< number of times we used "weak" cuts for enforcement */
326  SCIP_Longint ntightenlp; /**< number of times we requested solving the LP with a smaller feasibility tolerance when enforcing */
327  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 */
328  SCIP_Longint ndesperatebranch; /**< number of times we branched on some variable because normal enforcement was not successful */
329  SCIP_Longint ndesperatecutoff; /**< number of times we cut off a node in enforcement because no branching candidate could be found */
330  SCIP_Longint nforcelp; /**< number of times we forced solving the LP when enforcing a pseudo solution */
331  SCIP_CLOCK* canonicalizetime; /**< time spend for canonicalization */
332  SCIP_Longint ncanonicalizecalls; /**< number of times we called canonicalization */
333 
334  /* facets of envelops of vertex-polyhedral functions */
335  SCIP_RANDNUMGEN* vp_randnumgen; /**< random number generator used to perturb reference point */
336  SCIP_LPI* vp_lp[SCIP_MAXVERTEXPOLYDIM+1]; /**< LPs used to compute facets for functions of different dimension */
337 
338  /* hashing of bilinear terms */
339  SCIP_HASHTABLE* bilinhashtable; /**< hash table for bilinear terms */
340  SCIP_CONSNONLINEAR_BILINTERM* bilinterms; /**< bilinear terms */
341  int nbilinterms; /**< total number of bilinear terms */
342  int bilintermssize; /**< size of bilinterms array */
343  int bilinmaxnauxexprs; /**< maximal number of auxiliary expressions per bilinear term */
344 
345  /* branching */
346  SCIP_RANDNUMGEN* branchrandnumgen; /**< random number generated used in branching variable selection */
347  char branchpscostupdatestrategy; /**< value of parameter branching/lpgainnormalize */
348 
349  /* misc */
350  SCIP_Bool checkedvarlocks; /**< whether variables contained in a single constraint have been already considered */
351  SCIP_HASHMAP* var2expr; /**< hashmap to map SCIP variables to variable-expressions */
352  int newsoleventfilterpos; /**< filter position of new solution event handler, if caught */
353 };
354 
355 /** branching candidate with various scores */
356 typedef struct
357 {
358  SCIP_EXPR* expr; /**< expression that holds branching candidate, NULL if candidate is due to fractionality of integer variable */
359  SCIP_VAR* var; /**< variable that is branching candidate */
360  SCIP_Real auxviol; /**< aux-violation score of candidate */
361  SCIP_Real domain; /**< domain score of candidate */
362  SCIP_Real dual; /**< dual score of candidate */
363  SCIP_Real pscost; /**< pseudo-cost score of candidate */
364  SCIP_Real vartype; /**< variable type score of candidate */
365  SCIP_Real fractionality; /**< fractionality score of candidate */
366  SCIP_Real weighted; /**< weighted sum of other scores, see scoreBranchingCandidates() */
368 
369 /*
370  * Local methods
371  */
372 
373 /* forward declaration */
374 static
376  SCIP* scip, /**< SCIP data structure */
377  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
378  SCIP_EXPR* rootexpr, /**< expression */
379  SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
380  SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
381  int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
382  );
383 
384 /** frees auxiliary variables of expression, if any */
385 static
387  SCIP* scip, /**< SCIP data structure */
388  SCIP_EXPR* expr /**< expression which auxvar to free, if any */
389  )
390 {
391  SCIP_EXPR_OWNERDATA* mydata;
392 
393  assert(scip != NULL);
394  assert(expr != NULL);
395 
396  mydata = SCIPexprGetOwnerData(expr);
397  assert(mydata != NULL);
398 
399  if( mydata->auxvar == NULL )
400  return SCIP_OKAY;
401 
402  SCIPdebugMsg(scip, "remove auxiliary variable <%s> for expression %p\n", SCIPvarGetName(mydata->auxvar), (void*)expr);
403 
404  /* remove variable locks
405  * as this is a relaxation-only variable, no other plugin should use it for deducing any type of reductions or cutting planes
406  */
407  SCIP_CALL( SCIPaddVarLocks(scip, mydata->auxvar, -1, -1) );
408 
409  /* release auxiliary variable */
410  SCIP_CALL( SCIPreleaseVar(scip, &mydata->auxvar) );
411  assert(mydata->auxvar == NULL);
412 
413  return SCIP_OKAY;
414 }
415 
416 /** frees data used for enforcement of expression, that is, nonlinear handlers
417  *
418  * can also clear indicators whether expr needs enforcement methods, that is,
419  * free an associated auxiliary variable and reset the nactivityuses counts
420  */
421 static
423  SCIP* scip, /**< SCIP data structure */
424  SCIP_EXPR* expr, /**< expression whose enforcement data will be released */
425  SCIP_Bool freeauxvar /**< whether aux var should be released and activity usage counts be reset */
426  )
427 {
428  SCIP_EXPR_OWNERDATA* mydata;
429  int e;
430 
431  mydata = SCIPexprGetOwnerData(expr);
432  assert(mydata != NULL);
433 
434  if( freeauxvar )
435  {
436  /* free auxiliary variable */
437  SCIP_CALL( freeAuxVar(scip, expr) );
438  assert(mydata->auxvar == NULL);
439 
440  /* reset count on activity and auxvar usage */
441  mydata->nactivityusesprop = 0;
442  mydata->nactivityusessepa = 0;
443  mydata->nauxvaruses = 0;
444  }
445 
446  /* free data stored by nonlinear handlers */
447  for( e = 0; e < mydata->nenfos; ++e )
448  {
449  SCIP_NLHDLR* nlhdlr;
450 
451  assert(mydata->enfos[e] != NULL);
452 
453  nlhdlr = mydata->enfos[e]->nlhdlr;
454  assert(nlhdlr != NULL);
455 
456  if( mydata->enfos[e]->issepainit )
457  {
458  /* call the separation deinitialization callback of the nonlinear handler */
459  SCIP_CALL( SCIPnlhdlrExitsepa(scip, nlhdlr, expr, mydata->enfos[e]->nlhdlrexprdata) );
460  mydata->enfos[e]->issepainit = FALSE;
461  }
462 
463  /* free nlhdlr exprdata, if there is any and there is a method to free this data */
464  if( mydata->enfos[e]->nlhdlrexprdata != NULL )
465  {
466  SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &mydata->enfos[e]->nlhdlrexprdata) );
467  assert(mydata->enfos[e]->nlhdlrexprdata == NULL);
468  }
469 
470  /* free enfo data */
471  SCIPfreeBlockMemory(scip, &mydata->enfos[e]);
472  }
473 
474  /* free array with enfo data */
475  SCIPfreeBlockMemoryArrayNull(scip, &mydata->enfos, mydata->nenfos);
476 
477  /* we need to look at this expression in detect again */
478  mydata->nenfos = -1;
479 
480  return SCIP_OKAY;
481 }
482 
483 /** callback that frees data that this conshdlr stored in an expression */
484 static
485 SCIP_DECL_EXPR_OWNERFREE(exprownerFree)
486 {
487  assert(scip != NULL);
488  assert(expr != NULL);
489  assert(ownerdata != NULL);
490  assert(*ownerdata != NULL);
491 
492  /* expression should not be locked anymore */
493  assert((*ownerdata)->nlockspos == 0);
494  assert((*ownerdata)->nlocksneg == 0);
495 
496  SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
497 
498  /* expression should not be enforced anymore */
499  assert((*ownerdata)->nenfos <= 0);
500  assert((*ownerdata)->auxvar == NULL);
501 
502  if( SCIPisExprVar(scip, expr) )
503  {
504  SCIP_CONSHDLRDATA* conshdlrdata;
505  SCIP_VAR* var;
506 
507  /* there should be no constraints left that still use this variable */
508  assert((*ownerdata)->nconss == 0);
509  /* thus, there should also be no variable event catched (via this exprhdlr) */
510  assert((*ownerdata)->filterpos == -1);
511 
512  SCIPfreeBlockMemoryArrayNull(scip, &(*ownerdata)->conss, (*ownerdata)->consssize);
513 
514  /* update var2expr hashmap in conshdlrdata */
515  conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
516  assert(conshdlrdata != NULL);
517 
518  var = SCIPgetVarExprVar(expr);
519  assert(var != NULL);
520 
521  /* remove var -> expr map from hashmap if present
522  * (if no variable-expression stored for var hashmap, then the var hasn't been used in any constraint, so do nothing
523  * if variable-expression stored for var is different, then also do nothing)
524  */
525  if( SCIPhashmapGetImage(conshdlrdata->var2expr, var) == (void*)expr )
526  {
527  SCIP_CALL( SCIPhashmapRemove(conshdlrdata->var2expr, var) );
528  }
529  }
530 
531  SCIPfreeBlockMemory(scip, ownerdata);
532 
533  return SCIP_OKAY;
534 }
535 
536 static
537 SCIP_DECL_EXPR_OWNERPRINT(exprownerPrint)
538 { /*lint --e{715}*/
539  assert(ownerdata != NULL);
540 
541  /* print nl handlers associated to expr */
542  if( ownerdata->nenfos > 0 )
543  {
544  int i;
545  SCIPinfoMessage(scip, file, " {");
546 
547  for( i = 0; i < ownerdata->nenfos; ++i )
548  {
549  SCIPinfoMessage(scip, file, "%s:", SCIPnlhdlrGetName(ownerdata->enfos[i]->nlhdlr));
550  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY )
551  SCIPinfoMessage(scip, file, "a");
552  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW )
553  SCIPinfoMessage(scip, file, "u");
554  if( ownerdata->enfos[i]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE )
555  SCIPinfoMessage(scip, file, "o");
556  if( i < ownerdata->nenfos-1 )
557  SCIPinfoMessage(scip, file, ", ");
558  }
559 
560  SCIPinfoMessage(scip, file, "}");
561  }
562 
563  /* print aux var associated to expr */
564  if( ownerdata->auxvar != NULL )
565  {
566  SCIPinfoMessage(scip, file, " (<%s> in [%g, %g])", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbLocal(ownerdata->auxvar), SCIPvarGetUbLocal(ownerdata->auxvar));
567  }
568  SCIPinfoMessage(scip, file, "\n");
569 
570  return SCIP_OKAY;
571 }
572 
573 /** possibly reevaluates and then returns the activity of the expression
574  *
575  * Reevaluate activity if currently stored is not up to date (some bound was changed since last evaluation).
576  */
577 static
578 SCIP_DECL_EXPR_OWNEREVALACTIVITY(exprownerEvalactivity)
579 {
580  SCIP_CONSHDLRDATA* conshdlrdata;
581 
582  assert(scip != NULL);
583  assert(expr != NULL);
584  assert(ownerdata != NULL);
585 
586  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
587  assert(conshdlrdata != NULL);
588 
589  if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
590  {
591  /* update activity of expression */
592  SCIP_CALL( forwardPropExpr(scip, ownerdata->conshdlr, expr, FALSE, NULL, NULL) );
593 
594  assert(SCIPexprGetActivityTag(expr) == conshdlrdata->curboundstag);
595  }
596 
597  return SCIP_OKAY;
598 }
599 
600 /** callback that creates data that this conshdlr wants to store in an expression */
601 static
602 SCIP_DECL_EXPR_OWNERCREATE(exprownerCreate)
603 {
604  assert(scip != NULL);
605  assert(expr != NULL);
606  assert(ownerdata != NULL);
607 
608  SCIP_CALL( SCIPallocClearBlockMemory(scip, ownerdata) );
609  (*ownerdata)->nenfos = -1;
610  (*ownerdata)->conshdlr = (SCIP_CONSHDLR*)ownercreatedata;
611 
612  if( SCIPisExprVar(scip, expr) )
613  {
614  SCIP_CONSHDLRDATA* conshdlrdata;
615  SCIP_VAR* var;
616 
617  (*ownerdata)->filterpos = -1;
618 
619  /* add to var2expr hashmap if not having expr for var yet */
620 
621  conshdlrdata = SCIPconshdlrGetData((*ownerdata)->conshdlr);
622  assert(conshdlrdata != NULL);
623 
624  var = SCIPgetVarExprVar(expr);
625 
626  if( !SCIPhashmapExists(conshdlrdata->var2expr, (void*)var) )
627  {
628  /* store the variable expression in the hashmap */
629  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, (void*)var, (void*)expr) );
630  }
631  else
632  {
633  /* if expr was just created, then it shouldn't already be stored as image of var */
634  assert(SCIPhashmapGetImage(conshdlrdata->var2expr, (void*)var) != (void*)expr);
635  }
636  }
637  else
638  {
639  /* just so that we can use filterpos to recognize whether an expr is a varexpr if not having a SCIP pointer around */
640  (*ownerdata)->filterpos = -2;
641  }
642 
643  *ownerfree = exprownerFree;
644  *ownerprint = exprownerPrint;
645  *ownerevalactivity = exprownerEvalactivity;
646 
647  return SCIP_OKAY;
648 }
649 
650 /** creates a variable expression or retrieves from hashmap in conshdlr data */
651 static
653  SCIP* scip, /**< SCIP data structure */
654  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
655  SCIP_EXPR** expr, /**< pointer where to store expression */
656  SCIP_VAR* var /**< variable to be stored */
657  )
658 {
659  assert(conshdlr != NULL);
660  assert(expr != NULL);
661  assert(var != NULL);
662 
663  /* get variable expression representing the given variable if there is one already */
664  *expr = (SCIP_EXPR*) SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*) var);
665 
666  if( *expr == NULL )
667  {
668  /* create a new variable expression; this also captures the expression */
669  SCIP_CALL( SCIPcreateExprVar(scip, expr, var, exprownerCreate, (void*)conshdlr) );
670  assert(*expr != NULL);
671  /* exprownerCreate should have added var->expr to var2expr */
672  assert(SCIPhashmapGetImage(SCIPconshdlrGetData(conshdlr)->var2expr, (void*)var) == (void*)*expr);
673  }
674  else
675  {
676  /* only capture already existing expr to get a consistent uses-count */
677  SCIPcaptureExpr(*expr);
678  }
679 
680  return SCIP_OKAY;
681 }
682 
683 /* map var exprs to var-expr from var2expr hashmap */
684 static
685 SCIP_DECL_EXPR_MAPEXPR(mapexprvar)
686 { /*lint --e{715}*/
687  SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
688 
689  assert(sourcescip != NULL);
690  assert(targetscip != NULL);
691  assert(sourceexpr != NULL);
692  assert(targetexpr != NULL);
693  assert(*targetexpr == NULL);
694  assert(mapexprdata != NULL);
695 
696  /* do not provide map if not variable */
697  if( !SCIPisExprVar(sourcescip, sourceexpr) )
698  return SCIP_OKAY;
699 
700  SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, SCIPgetVarExprVar(sourceexpr)) );
701 
702  return SCIP_OKAY;
703 }
704 
705 /* map var exprs to var-expr from var2expr hashmap corresponding to transformed var */
706 static
707 SCIP_DECL_EXPR_MAPEXPR(mapexprtransvar)
708 { /*lint --e{715}*/
709  SCIP_CONSHDLR* conshdlr = (SCIP_CONSHDLR*)mapexprdata;
710  SCIP_VAR* var;
711 
712  assert(sourcescip != NULL);
713  assert(targetscip != NULL);
714  assert(sourceexpr != NULL);
715  assert(targetexpr != NULL);
716  assert(*targetexpr == NULL);
717  assert(mapexprdata != NULL);
718 
719  /* do not provide map if not variable */
720  if( !SCIPisExprVar(sourcescip, sourceexpr) )
721  return SCIP_OKAY;
722 
723  var = SCIPgetVarExprVar(sourceexpr);
724  assert(var != NULL);
725 
726  /* transform variable */
727  SCIP_CALL( SCIPgetTransformedVar(sourcescip, var, &var) );
728  assert(var != NULL);
729 
730  SCIP_CALL( createExprVar(targetscip, conshdlr, targetexpr, var) );
731 
732  return SCIP_OKAY;
733 }
734 
735 /** stores all variable expressions into a given constraint */
736 static
738  SCIP* scip, /**< SCIP data structure */
739  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
740  SCIP_CONSDATA* consdata /**< constraint data */
741  )
742 {
743  SCIP_CONSHDLRDATA* conshdlrdata;
744  int varexprssize;
745  int i;
746 
747  assert(consdata != NULL);
748 
749  /* skip if we have stored the variable expressions already */
750  if( consdata->varexprs != NULL )
751  return SCIP_OKAY;
752 
753  assert(consdata->varexprs == NULL);
754  assert(consdata->nvarexprs == 0);
755 
756  /* get an upper bound on number of variable expressions */
757  if( consdata->issimplified )
758  {
759  /* if simplified, then we should have removed inactive variables and replaced common subexpressions,
760  * so we cannot have more variable expression than the number of active variables
761  */
762  varexprssize = SCIPgetNVars(scip);
763  }
764  else
765  {
766  SCIP_CALL( SCIPgetExprNVars(scip, consdata->expr, &varexprssize) );
767  }
768 
769  /* create array to store all variable expressions */
770  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize) );
771 
772  SCIP_CALL( SCIPgetExprVarExprs(scip, consdata->expr, consdata->varexprs, &(consdata->nvarexprs)) );
773  assert(varexprssize >= consdata->nvarexprs);
774 
775  /* shrink array if there are less variables in the expression than in the problem */
776  if( varexprssize > consdata->nvarexprs )
777  {
778  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->varexprs, varexprssize, consdata->nvarexprs) );
779  }
780 
781  conshdlrdata = SCIPconshdlrGetData(conshdlr);
782  assert(conshdlrdata != NULL);
783  assert(conshdlrdata->var2expr != NULL);
784 
785  /* ensure that for every variable an entry exists in the var2expr hashmap
786  * when removing duplicate subexpressions it can happen that a var->varexpr map was removed from the hashmap
787  */
788  for( i = 0; i < consdata->nvarexprs; ++i )
789  {
790  if( !SCIPhashmapExists(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i])) )
791  {
792  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->var2expr, SCIPgetVarExprVar(consdata->varexprs[i]), consdata->varexprs[i]) );
793  }
794  }
795 
796  return SCIP_OKAY;
797 }
798 
799 /** frees all variable expression stored in storeVarExprs() */
800 static
802  SCIP* scip, /**< SCIP data structure */
803  SCIP_CONSDATA* consdata /**< constraint data */
804  )
805 {
806  int i;
807 
808  assert(consdata != NULL);
809 
810  /* skip if we have stored the variable expressions already*/
811  if( consdata->varexprs == NULL )
812  return SCIP_OKAY;
813 
814  assert(consdata->varexprs != NULL);
815  assert(consdata->nvarexprs >= 0);
816 
817  /* release variable expressions */
818  for( i = 0; i < consdata->nvarexprs; ++i )
819  {
820  assert(consdata->varexprs[i] != NULL);
821  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->varexprs[i]) );
822  assert(consdata->varexprs[i] == NULL);
823  }
824 
825  /* free variable expressions */
826  SCIPfreeBlockMemoryArrayNull(scip, &consdata->varexprs, consdata->nvarexprs);
827  consdata->varexprs = NULL;
828  consdata->nvarexprs = 0;
829 
830  return SCIP_OKAY;
831 }
832 
833 /** interval evaluation of variables as used in bound tightening
834  *
835  * Returns slightly relaxed local variable bounds of a variable as interval.
836  * Does not relax beyond integer values, thus does not relax bounds on integer variables at all.
837  */
838 static
839 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarBoundTightening)
840 {
841  SCIP_INTERVAL interval;
842  SCIP_CONSHDLRDATA* conshdlrdata;
843  SCIP_Real lb;
844  SCIP_Real ub;
845 
846  assert(scip != NULL);
847  assert(var != NULL);
848 
849  conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
850  assert(conshdlrdata != NULL);
851 
852  if( conshdlrdata->globalbounds )
853  {
854  lb = SCIPvarGetLbGlobal(var);
855  ub = SCIPvarGetUbGlobal(var);
856  }
857  else
858  {
859  lb = SCIPvarGetLbLocal(var);
860  ub = SCIPvarGetUbLocal(var);
861  }
862  assert(lb <= ub); /* SCIP should ensure that variable bounds are not contradicting */
863 
864  /* implicit integer variables may have non-integer bounds, apparently (run space25a) */
866  {
867  lb = EPSROUND(lb, 0.0); /*lint !e835*/
868  ub = EPSROUND(ub, 0.0); /*lint !e835*/
869  }
870 
871  /* integer variables should always have integral bounds in SCIP */
872  assert(EPSFRAC(lb, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
873  assert(EPSFRAC(ub, 0.0) == 0.0 || !SCIPvarIsIntegral(var)); /*lint !e835*/
874 
875  switch( conshdlrdata->varboundrelax )
876  {
877  case 'n' : /* no relaxation */
878  break;
879 
880  case 'a' : /* relax by absolute value */
881  {
882  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
883  if( SCIPvarIsIntegral(var) )
884  break;
885 
886  if( !SCIPisInfinity(scip, -lb) )
887  {
888  /* reduce lb by epsilon, or to the next integer value, which ever is larger */
889  SCIP_Real bnd = floor(lb);
890  lb = MAX(bnd, lb - conshdlrdata->varboundrelaxamount);
891  }
892 
893  if( !SCIPisInfinity(scip, ub) )
894  {
895  /* increase ub by epsilon, or to the next integer value, which ever is smaller */
896  SCIP_Real bnd = ceil(ub);
897  ub = MIN(bnd, ub + conshdlrdata->varboundrelaxamount);
898  }
899 
900  break;
901  }
902 
903  case 'b' : /* relax always by absolute value */
904  {
905  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
906  if( SCIPvarIsIntegral(var) )
907  break;
908 
909  if( !SCIPisInfinity(scip, -lb) )
910  lb -= conshdlrdata->varboundrelaxamount;
911 
912  if( !SCIPisInfinity(scip, ub) )
913  ub += conshdlrdata->varboundrelaxamount;
914 
915  break;
916  }
917 
918  case 'r' : /* relax by relative value */
919  {
920  /* do not look at integer variables, they already have integral bounds, so wouldn't be relaxed */
921  if( SCIPvarIsIntegral(var) )
922  break;
923 
924  /* relax bounds by epsilon*max(1,|bnd|), instead of just epsilon as in case 'a', thus we trust the first log(epsilon) digits
925  * however, when domains get small, relaxing can excessively weaken bound tightening, thus do only fraction of |ub-lb| if that is smaller
926  * further, do not relax beyond next integer value
927  */
928  if( !SCIPisInfinity(scip, -lb) )
929  {
930  SCIP_Real bnd = floor(lb);
931  lb = MAX(bnd, lb - MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(lb)), 0.001 * REALABS(ub-lb)));
932  }
933 
934  if( !SCIPisInfinity(scip, ub) )
935  {
936  SCIP_Real bnd = ceil(ub);
937  ub = MIN(bnd, ub + MIN(conshdlrdata->varboundrelaxamount * MAX(1.0, REALABS(ub)), 0.001 * REALABS(ub-lb)));
938  }
939 
940  break;
941  }
942 
943  default :
944  {
945  SCIPerrorMessage("Unsupported value '%c' for varboundrelax option.\n", conshdlrdata->varboundrelax);
946  SCIPABORT();
947  break;
948  }
949  }
950 
951  /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
954  assert(lb <= ub);
955 
956  SCIPintervalSetBounds(&interval, lb, ub);
957 
958  return interval;
959 }
960 
961 /** compares two nonlinear constraints by its index
962  *
963  * Usable as compare operator in array sort functions.
964  */
965 static
966 SCIP_DECL_SORTPTRCOMP(compIndexConsNonlinear)
967 {
968  SCIP_CONSDATA* consdata1 = SCIPconsGetData((SCIP_CONS*)elem1);
969  SCIP_CONSDATA* consdata2 = SCIPconsGetData((SCIP_CONS*)elem2);
970 
971  assert(consdata1 != NULL);
972  assert(consdata2 != NULL);
973 
974  return consdata1->consindex - consdata2->consindex;
975 }
976 
977 /** processes variable fixing or bound change event */
978 static
979 SCIP_DECL_EVENTEXEC(processVarEvent)
980 { /*lint --e{715}*/
981  SCIP_EVENTTYPE eventtype;
982  SCIP_EXPR* expr;
983  SCIP_EXPR_OWNERDATA* ownerdata;
984  SCIP_Bool boundtightened = FALSE;
985 
986  eventtype = SCIPeventGetType(event);
988 
989  assert(eventdata != NULL);
990  expr = (SCIP_EXPR*) eventdata;
991  assert(SCIPisExprVar(scip, expr));
992 
993  SCIPdebugMsg(scip, " exec event %" SCIP_EVENTTYPE_FORMAT " for variable <%s> (local [%g,%g], global [%g,%g])\n", eventtype,
997 
998  ownerdata = SCIPexprGetOwnerData(expr);
999  assert(ownerdata != NULL);
1000  /* we only catch varevents for variables in constraints, so there should be constraints */
1001  assert(ownerdata->nconss > 0);
1002  assert(ownerdata->conss != NULL);
1003 
1004  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
1005  boundtightened = TRUE;
1006 
1007  /* usually, if fixing a variable results in a boundchange, we should have seen a boundtightened-event as well
1008  * however, if the boundchange is smaller than epsilon, such an event will be omitted
1009  * but we still want to make sure the activity of the var-expr is reevaluated (mainly to avoid a failing assert) in this case
1010  * since we cannot easily see whether a variable bound was actually changed in a varfixed event, we treat any varfixed event
1011  * as a boundtightening (and usually it is, I would think)
1012  */
1013  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
1014  boundtightened = TRUE;
1015 
1016  /* if a variable is changed to implicit-integer and has a fractional bound, then the behavior of intEvalVarBoundTightening is changing,
1017  * because we will round the bounds and no longer consider relaxing them
1018  * we will mark corresponding constraints as not-propagated in this case to get the tightened bounds on the var-expr
1019  * (mainly to avoid a failing assert, see github issue #70)
1020  * 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
1021  */
1022  if( (eventtype & SCIP_EVENTTYPE_TYPECHANGED) && (SCIPeventGetNewtype(event) == SCIP_VARTYPE_IMPLINT) &&
1023  (!EPSISINT(SCIPvarGetLbGlobal(SCIPeventGetVar(event)), 0.0) || !EPSISINT(SCIPvarGetUbGlobal(SCIPeventGetVar(event)), 0.0)) ) /*lint !e835*/
1024  boundtightened = TRUE;
1025 
1026  /* notify constraints that use this variable expression (expr) to repropagate and possibly resimplify
1027  * - propagation can only find something new if a bound was tightened
1028  * - simplify can only find something new if a var is fixed (or maybe a bound is tightened)
1029  * and we look at global changes (that is, we are not looking at boundchanges in probing)
1030  */
1031  if( boundtightened )
1032  {
1033  SCIP_CONSDATA* consdata;
1034  int c;
1035 
1036  for( c = 0; c < ownerdata->nconss; ++c )
1037  {
1038  assert(ownerdata->conss[c] != NULL);
1039  consdata = SCIPconsGetData(ownerdata->conss[c]);
1040 
1041  /* if bound tightening, then mark constraints to be propagated again
1042  * TODO we could try be more selective here and only trigger a propagation if a relevant bound has changed,
1043  * that is, we don't need to repropagate x + ... <= rhs if only the upper bound of x has been tightened
1044  * the locks don't help since they are not available separately for each constraint
1045  */
1046  consdata->ispropagated = FALSE;
1047  SCIPdebugMsg(scip, " marked <%s> for propagate\n", SCIPconsGetName(ownerdata->conss[c]));
1048 
1049  /* if still in presolve (but not probing), then mark constraints to be unsimplified */
1050  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !SCIPinProbing(scip) )
1051  {
1052  consdata->issimplified = FALSE;
1053  SCIPdebugMsg(scip, " marked <%s> for simplify\n", SCIPconsGetName(ownerdata->conss[c]));
1054  }
1055  }
1056  }
1057 
1058  /* update curboundstag, lastboundrelax, and expr activity */
1059  if( (eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) || boundtightened )
1060  {
1061  SCIP_CONSHDLRDATA* conshdlrdata;
1062  SCIP_INTERVAL activity;
1063 
1064  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
1065  assert(conshdlrdata != NULL);
1066 
1067  /* increase tag on bounds */
1068  ++conshdlrdata->curboundstag;
1069  assert(conshdlrdata->curboundstag > 0);
1070 
1071  /* remember also if we relaxed bounds now */
1072  if( eventtype & SCIP_EVENTTYPE_BOUNDRELAXED )
1073  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
1074 
1075  /* update the activity of the var-expr here immediately
1076  * (we could call expr->activity = intevalvar(var, consdhlr) directly, but then the exprhdlr statistics are not updated)
1077  */
1078  SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, conshdlrdata->intevalvar, conshdlrdata) );
1079  /* activity = conshdlrdata->intevalvar(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1080 #ifdef DEBUG_PROP
1081  SCIPdebugMsg(scip, " var-exprhdlr::inteval = [%.20g, %.20g]\n", activity.inf, activity.sup);
1082 #endif
1083  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1084  }
1085 
1086  return SCIP_OKAY;
1087 }
1088 
1089 /** registers event handler to catch variable events on variable
1090  *
1091  * Additionally, the given constraint is stored in the ownerdata of the variable-expression.
1092  * When an event occurs, all stored constraints are notified.
1093  */
1094 static
1096  SCIP* scip, /**< SCIP data structure */
1097  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1098  SCIP_EXPR* expr, /**< variable expression */
1099  SCIP_CONS* cons /**< nonlinear constraint */
1100  )
1101 {
1102  SCIP_EXPR_OWNERDATA* ownerdata;
1103 
1104  assert(eventhdlr != NULL);
1105  assert(expr != NULL);
1106  assert(SCIPisExprVar(scip, expr));
1107  assert(cons != NULL);
1108 
1109  ownerdata = SCIPexprGetOwnerData(expr);
1110  assert(ownerdata != NULL);
1111 
1112 #ifndef NDEBUG
1113  /* assert that constraint does not double-catch variable */
1114  {
1115  int i;
1116  for( i = 0; i < ownerdata->nconss; ++i )
1117  assert(ownerdata->conss[i] != cons);
1118  }
1119 #endif
1120 
1121  /* append cons to ownerdata->conss */
1122  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->conss, &ownerdata->consssize, ownerdata->nconss + 1) );
1123  ownerdata->conss[ownerdata->nconss++] = cons;
1124  /* we're not capturing the constraint here to avoid circular references */
1125 
1126  /* updated sorted flag */
1127  if( ownerdata->nconss <= 1 )
1128  ownerdata->consssorted = TRUE;
1129  else if( ownerdata->consssorted )
1130  ownerdata->consssorted = compIndexConsNonlinear(ownerdata->conss[ownerdata->nconss-2], ownerdata->conss[ownerdata->nconss-1]) > 0;
1131 
1132  /* catch variable events, if not done so yet (first constraint) */
1133  if( ownerdata->filterpos < 0 )
1134  {
1135  SCIP_EVENTTYPE eventtype;
1136 
1137  assert(ownerdata->nconss == 1);
1138 
1140 
1141  SCIP_CALL( SCIPcatchVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, &ownerdata->filterpos) );
1142  assert(ownerdata->filterpos >= 0);
1143  }
1144 
1145  return SCIP_OKAY;
1146 }
1147 
1148 /** catch variable events */
1149 static
1151  SCIP* scip, /**< SCIP data structure */
1152  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1153  SCIP_CONS* cons /**< constraint for which to catch bound change events */
1154  )
1155 {
1156  SCIP_CONSHDLRDATA* conshdlrdata;
1157  SCIP_CONSDATA* consdata;
1158  SCIP_EXPR* expr;
1159  int i;
1160 
1161  assert(eventhdlr != NULL);
1162  assert(cons != NULL);
1163 
1164  consdata = SCIPconsGetData(cons);
1165  assert(consdata != NULL);
1166  assert(consdata->varexprs != NULL);
1167  assert(consdata->nvarexprs >= 0);
1168 
1169  /* check if we have catched variable events already */
1170  if( consdata->catchedevents )
1171  return SCIP_OKAY;
1172 
1173  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1174  assert(conshdlrdata != NULL);
1175 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
1176  assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
1177 #endif
1178 
1179  SCIPdebugMsg(scip, "catchVarEvents for %s\n", SCIPconsGetName(cons));
1180 
1181  for( i = 0; i < consdata->nvarexprs; ++i )
1182  {
1183  expr = consdata->varexprs[i];
1184 
1185  assert(expr != NULL);
1186  assert(SCIPisExprVar(scip, expr));
1187 
1188  SCIP_CALL( catchVarEvent(scip, eventhdlr, expr, cons) );
1189 
1190  /* from now on, activity of var-expr will usually be updated in processVarEvent if variable bound is changing
1191  * since we just registered this eventhdlr, we should make sure that the activity is also up to date now
1192  */
1193  if( SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag )
1194  {
1195  SCIP_INTERVAL activity;
1196  SCIP_CALL( SCIPcallExprInteval(scip, expr, &activity, intEvalVarBoundTightening, conshdlrdata) );
1197  /* activity = intEvalVarBoundTightening(scip, SCIPgetVarExprVar(expr), conshdlrdata); */
1198  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
1199 #ifdef DEBUG_PROP
1200  SCIPdebugMsg(scip, "var-exprhdlr::inteval for var <%s> = [%.20g, %.20g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), activity.inf, activity.sup);
1201 #endif
1202  }
1203  }
1204 
1205  consdata->catchedevents = TRUE;
1206 
1207  return SCIP_OKAY;
1208 }
1209 
1210 /** unregisters event handler to catch variable events on variable
1211  *
1212  * The given constraint is removed from the constraints array in the ownerdata of the variable-expression.
1213  * If this was the last constraint, then the event handler is unregistered for this variable.
1214  */
1215 static
1217  SCIP* scip, /**< SCIP data structure */
1218  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1219  SCIP_EXPR* expr, /**< variable expression */
1220  SCIP_CONS* cons /**< expr constraint */
1221  )
1222 {
1223  SCIP_EXPR_OWNERDATA* ownerdata;
1224  int pos;
1225 
1226  assert(eventhdlr != NULL);
1227  assert(expr != NULL);
1228  assert(SCIPisExprVar(scip, expr));
1229  assert(cons != NULL);
1230 
1231  ownerdata = SCIPexprGetOwnerData(expr);
1232  assert(ownerdata != NULL);
1233  assert(ownerdata->nconss > 0);
1234 
1235  if( ownerdata->conss[ownerdata->nconss-1] == cons )
1236  {
1237  pos = ownerdata->nconss-1;
1238  }
1239  else
1240  {
1241  if( !ownerdata->consssorted )
1242  {
1243  SCIPsortPtr((void**)ownerdata->conss, compIndexConsNonlinear, ownerdata->nconss);
1244  ownerdata->consssorted = TRUE;
1245  }
1246 
1247  if( !SCIPsortedvecFindPtr((void**)ownerdata->conss, compIndexConsNonlinear, cons, ownerdata->nconss, &pos) )
1248  {
1249  SCIPerrorMessage("Constraint <%s> not in constraint array of expression for variable <%s>\n", SCIPconsGetName(cons), SCIPvarGetName(SCIPgetVarExprVar(expr)));
1250  return SCIP_ERROR;
1251  }
1252  assert(pos >= 0 && pos < ownerdata->nconss);
1253  }
1254  assert(ownerdata->conss[pos] == cons);
1255 
1256  /* move last constraint into position of removed constraint */
1257  if( pos < ownerdata->nconss-1 )
1258  {
1259  ownerdata->conss[pos] = ownerdata->conss[ownerdata->nconss-1];
1260  ownerdata->consssorted = FALSE;
1261  }
1262  --ownerdata->nconss;
1263 
1264  /* drop variable events if that was the last constraint */
1265  if( ownerdata->nconss == 0 )
1266  {
1267  SCIP_EVENTTYPE eventtype;
1268 
1269  assert(ownerdata->filterpos >= 0);
1270 
1272 
1273  SCIP_CALL( SCIPdropVarEvent(scip, SCIPgetVarExprVar(expr), eventtype, eventhdlr, (SCIP_EVENTDATA*)expr, ownerdata->filterpos) );
1274  ownerdata->filterpos = -1;
1275  }
1276 
1277  return SCIP_OKAY;
1278 }
1279 
1280 /** drop variable events */
1281 static
1283  SCIP* scip, /**< SCIP data structure */
1284  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1285  SCIP_CONS* cons /**< constraint for which to drop bound change events */
1286  )
1287 {
1288  SCIP_CONSDATA* consdata;
1289  int i;
1290 
1291  assert(eventhdlr != NULL);
1292  assert(cons != NULL);
1293 
1294  consdata = SCIPconsGetData(cons);
1295  assert(consdata != NULL);
1296 
1297  /* check if we have catched variable events already */
1298  if( !consdata->catchedevents )
1299  return SCIP_OKAY;
1300 
1301  assert(consdata->varexprs != NULL);
1302  assert(consdata->nvarexprs >= 0);
1303 
1304  SCIPdebugMsg(scip, "dropVarEvents for %s\n", SCIPconsGetName(cons));
1305 
1306  for( i = consdata->nvarexprs - 1; i >= 0; --i )
1307  {
1308  assert(consdata->varexprs[i] != NULL);
1309 
1310  SCIP_CALL( dropVarEvent(scip, eventhdlr, consdata->varexprs[i], cons) );
1311  }
1312 
1313  consdata->catchedevents = FALSE;
1314 
1315  return SCIP_OKAY;
1316 }
1317 
1318 /** creates and captures a nonlinear constraint
1319  *
1320  * @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
1321  */
1322 static
1324  SCIP* scip, /**< SCIP data structure */
1325  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1326  SCIP_CONS** cons, /**< pointer to hold the created constraint */
1327  const char* name, /**< name of constraint */
1328  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
1329  SCIP_Real lhs, /**< left hand side of constraint */
1330  SCIP_Real rhs, /**< right hand side of constraint */
1331  SCIP_Bool copyexpr, /**< whether to copy the expression or reuse the given expr (capture it) */
1332  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1333  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1334  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1335  * Usually set to TRUE. */
1336  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1337  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1338  SCIP_Bool check, /**< should the constraint be checked for feasibility?
1339  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1340  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1341  * Usually set to TRUE. */
1342  SCIP_Bool local, /**< is constraint only valid locally?
1343  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1344  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1345  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1346  * adds coefficients to this constraint. */
1347  SCIP_Bool dynamic, /**< is constraint subject to aging?
1348  * Usually set to FALSE. Set to TRUE for own cuts which
1349  * are separated as constraints. */
1350  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
1351  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1352  )
1353 {
1354  SCIP_CONSHDLRDATA* conshdlrdata;
1355  SCIP_CONSDATA* consdata;
1356 
1357  assert(conshdlr != NULL);
1358  assert(expr != NULL);
1359 
1360  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1361  assert(conshdlrdata != NULL);
1362 
1363  if( local && SCIPgetDepth(scip) != 0 )
1364  {
1365  SCIPerrorMessage("Locally valid nonlinear constraints are not supported, yet.\n");
1366  return SCIP_INVALIDCALL;
1367  }
1368 
1369  /* TODO we should allow for non-initial nonlinear constraints */
1370  if( !initial )
1371  {
1372  SCIPerrorMessage("Non-initial nonlinear constraints are not supported, yet.\n");
1373  return SCIP_INVALIDCALL;
1374  }
1375 
1376  /* create constraint data */
1377  SCIP_CALL( SCIPallocClearBlockMemory(scip, &consdata) );
1378 
1379  if( copyexpr )
1380  {
1381  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
1382  SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
1383  }
1384  else
1385  {
1386  consdata->expr = expr;
1387  SCIPcaptureExpr(consdata->expr);
1388  }
1389  consdata->lhs = lhs;
1390  consdata->rhs = rhs;
1391  consdata->consindex = conshdlrdata->lastconsindex++;
1392  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
1393 
1394  /* create constraint */
1395  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1396  local, modifiable, dynamic, removable, FALSE) );
1397 
1398  return SCIP_OKAY;
1399 }
1400 
1401 /** returns absolute violation for auxvar relation in an expression w.r.t. original variables
1402  *
1403  * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
1404  * Assume that f(x) is associated with auxiliary variable z.
1405  *
1406  * If there are negative locks, then return the violation of z &le; f(x) and sets `violover` to TRUE.
1407  * If there are positive locks, then return the violation of z &ge; f(x) and sets `violunder` to TRUE.
1408  * Of course, if there both negative and positive locks, then return the violation of z = f(x).
1409  * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1410  *
1411  * @note This does not reevaluate the violation, but assumes that the expression has been evaluated
1412  */
1413 static
1415  SCIP* scip, /**< SCIP data structure */
1416  SCIP_EXPR* expr, /**< expression */
1417  SCIP_SOL* sol, /**< solution that has been evaluated */
1418  SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
1419  SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
1420  )
1421 {
1422  SCIP_EXPR_OWNERDATA* ownerdata;
1423  SCIP_Real auxvarvalue;
1424 
1425  assert(expr != NULL);
1426 
1427  ownerdata = SCIPexprGetOwnerData(expr);
1428  assert(ownerdata != NULL);
1429  assert(ownerdata->auxvar != NULL);
1430 
1431  if( SCIPexprGetEvalValue(expr) == SCIP_INVALID )
1432  {
1433  if( violunder != NULL )
1434  *violunder = TRUE;
1435  if( violover != NULL )
1436  *violover = TRUE;
1437  return SCIPinfinity(scip);
1438  }
1439 
1440  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1441 
1442  if( ownerdata->nlocksneg > 0 && auxvarvalue > SCIPexprGetEvalValue(expr) )
1443  {
1444  if( violunder != NULL )
1445  *violunder = FALSE;
1446  if( violover != NULL )
1447  *violover = TRUE;
1448  return auxvarvalue - SCIPexprGetEvalValue(expr);
1449  }
1450 
1451  if( ownerdata->nlockspos > 0 && SCIPexprGetEvalValue(expr) > auxvarvalue )
1452  {
1453  if( violunder != NULL )
1454  *violunder = TRUE;
1455  if( violover != NULL )
1456  *violover = FALSE;
1457  return SCIPexprGetEvalValue(expr) - auxvarvalue;
1458  }
1459 
1460  if( violunder != NULL )
1461  *violunder = FALSE;
1462  if( violover != NULL )
1463  *violover = FALSE;
1464  return 0.0;
1465 }
1466 
1467 /** returns absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
1468  *
1469  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
1470  * Assume that f(w) is associated with auxiliary variable z.
1471  *
1472  * If there are negative locks, then return the violation of z &le; f(w) and sets `violover` to TRUE.
1473  * If there are positive locks, then return the violation of z &ge; f(w) and sets `violunder` to TRUE.
1474  * Of course, if there both negative and positive locks, then return the violation of z = f(w).
1475  * If f could not be evaluated, then return SCIPinfinity() and set both `violover` and `violunder` to TRUE.
1476  *
1477  * @note This does not reevaluate the violation, but assumes that f(w) is passed in with auxvalue.
1478  */
1479 static
1481  SCIP* scip, /**< SCIP data structure */
1482  SCIP_EXPR* expr, /**< expression */
1483  SCIP_Real auxvalue, /**< value of f(w) */
1484  SCIP_SOL* sol, /**< solution that has been evaluated */
1485  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
1486  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
1487  )
1488 {
1489  SCIP_EXPR_OWNERDATA* ownerdata;
1490  SCIP_Real auxvarvalue;
1491 
1492  assert(expr != NULL);
1493 
1494  ownerdata = SCIPexprGetOwnerData(expr);
1495  assert(ownerdata != NULL);
1496  assert(ownerdata->auxvar != NULL);
1497 
1498  if( auxvalue == SCIP_INVALID )
1499  {
1500  if( violunder != NULL )
1501  *violunder = TRUE;
1502  if( violover != NULL )
1503  *violover = TRUE;
1504  return SCIPinfinity(scip);
1505  }
1506 
1507  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
1508 
1509  if( ownerdata->nlocksneg > 0 && auxvarvalue > auxvalue )
1510  {
1511  if( violunder != NULL )
1512  *violunder = FALSE;
1513  if( violover != NULL )
1514  *violover = TRUE;
1515  return auxvarvalue - auxvalue;
1516  }
1517 
1518  if( ownerdata->nlockspos > 0 && auxvalue > auxvarvalue )
1519  {
1520  if( violunder != NULL )
1521  *violunder = TRUE;
1522  if( violover != NULL )
1523  *violover = FALSE;
1524  return auxvalue - auxvarvalue;
1525  }
1526 
1527  if( violunder != NULL )
1528  *violunder = FALSE;
1529  if( violover != NULL )
1530  *violover = FALSE;
1531 
1532  return 0.0;
1533 }
1534 
1535 /** computes violation of a constraint */
1536 static
1538  SCIP* scip, /**< SCIP data structure */
1539  SCIP_CONS* cons, /**< constraint */
1540  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1541  SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0. */
1542  )
1543 {
1544  SCIP_CONSDATA* consdata;
1545  SCIP_Real activity;
1546 
1547  assert(scip != NULL);
1548  assert(cons != NULL);
1549 
1550  consdata = SCIPconsGetData(cons);
1551  assert(consdata != NULL);
1552 
1553  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
1554  activity = SCIPexprGetEvalValue(consdata->expr);
1555 
1556  /* consider constraint as violated if it is undefined in the current point */
1557  if( activity == SCIP_INVALID )
1558  {
1559  consdata->lhsviol = SCIPinfinity(scip);
1560  consdata->rhsviol = SCIPinfinity(scip);
1561  return SCIP_OKAY;
1562  }
1563 
1564  /* compute violations */
1565  consdata->lhsviol = SCIPisInfinity(scip, -consdata->lhs) ? -SCIPinfinity(scip) : consdata->lhs - activity;
1566  consdata->rhsviol = SCIPisInfinity(scip, consdata->rhs) ? -SCIPinfinity(scip) : activity - consdata->rhs;
1567 
1568  return SCIP_OKAY;
1569 }
1570 
1571 /** returns absolute violation of a constraint
1572  *
1573  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1574  */
1575 static
1577  SCIP_CONS* cons /**< constraint */
1578  )
1579 {
1580  SCIP_CONSDATA* consdata;
1581 
1582  assert(cons != NULL);
1583 
1584  consdata = SCIPconsGetData(cons);
1585  assert(consdata != NULL);
1586 
1587  return MAX3(0.0, consdata->lhsviol, consdata->rhsviol);
1588 }
1589 
1590 /** computes relative violation of a constraint
1591  *
1592  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1593  */
1594 static
1596  SCIP* scip, /**< SCIP data structure */
1597  SCIP_CONS* cons, /**< constraint */
1598  SCIP_Real* viol, /**< buffer to store violation */
1599  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
1600  SCIP_Longint soltag /**< tag that uniquely identifies the solution (with its values), or 0 */
1601  )
1602 {
1603  SCIP_CONSHDLR* conshdlr;
1604  SCIP_CONSHDLRDATA* conshdlrdata;
1605  SCIP_CONSDATA* consdata;
1606  SCIP_Real scale;
1607 
1608  assert(cons != NULL);
1609  assert(viol != NULL);
1610 
1611  conshdlr = SCIPconsGetHdlr(cons);
1612  assert(conshdlr != NULL);
1613 
1614  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1615  assert(conshdlrdata != NULL);
1616 
1617  *viol = getConsAbsViolation(cons);
1618 
1619  if( conshdlrdata->violscale == 'n' )
1620  return SCIP_OKAY;
1621 
1622  if( SCIPisInfinity(scip, *viol) )
1623  return SCIP_OKAY;
1624 
1625  consdata = SCIPconsGetData(cons);
1626  assert(consdata != NULL);
1627 
1628  if( conshdlrdata->violscale == 'a' )
1629  {
1630  scale = MAX(1.0, REALABS(SCIPexprGetEvalValue(consdata->expr)));
1631 
1632  /* consider value of side that is violated for scaling, too */
1633  if( consdata->lhsviol > 0.0 && REALABS(consdata->lhs) > scale )
1634  {
1635  assert(!SCIPisInfinity(scip, -consdata->lhs));
1636  scale = REALABS(consdata->lhs);
1637  }
1638  else if( consdata->rhsviol > 0.0 && REALABS(consdata->rhs) > scale )
1639  {
1640  assert(!SCIPisInfinity(scip, consdata->rhs));
1641  scale = REALABS(consdata->rhs);
1642  }
1643 
1644  *viol /= scale;
1645  return SCIP_OKAY;
1646  }
1647 
1648  /* if not 'n' or 'a', then it has to be 'g' at the moment */
1649  assert(conshdlrdata->violscale == 'g');
1650  if( soltag == 0L || consdata->gradnormsoltag != soltag )
1651  {
1652  /* we need the varexprs to conveniently access the gradient */
1653  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
1654 
1655  /* update cached value of norm of gradient */
1656  consdata->gradnorm = 0.0;
1657 
1658  /* compute gradient */
1659  SCIP_CALL( SCIPevalExprGradient(scip, consdata->expr, sol, soltag) );
1660 
1661  /* gradient evaluation error -> no scaling */
1662  if( SCIPexprGetDerivative(consdata->expr) != SCIP_INVALID )
1663  {
1664  int i;
1665  for( i = 0; i < consdata->nvarexprs; ++i )
1666  {
1667  SCIP_Real deriv;
1668 
1669  assert(SCIPexprGetDiffTag(consdata->expr) == SCIPexprGetDiffTag(consdata->varexprs[i]));
1670  deriv = SCIPexprGetDerivative(consdata->varexprs[i]);
1671  if( deriv == SCIP_INVALID )
1672  {
1673  /* SCIPdebugMsg(scip, "gradient evaluation error for component %d\n", i); */
1674  consdata->gradnorm = 0.0;
1675  break;
1676  }
1677 
1678  consdata->gradnorm += deriv*deriv;
1679  }
1680  }
1681  consdata->gradnorm = sqrt(consdata->gradnorm);
1682  consdata->gradnormsoltag = soltag;
1683  }
1684 
1685  *viol /= MAX(1.0, consdata->gradnorm);
1686 
1687  return SCIP_OKAY;
1688 }
1689 
1690 /** returns whether constraint is currently violated
1691  *
1692  * @note This does not reevaluate the violation, but assumes that computeViolation() has been called before.
1693  */
1694 static
1696  SCIP* scip, /**< SCIP data structure */
1697  SCIP_CONS* cons /**< constraint */
1698  )
1699 {
1700  return getConsAbsViolation(cons) > SCIPfeastol(scip);
1701 }
1702 
1703 /** checks for a linear variable that can be increased or decreased without harming feasibility */
1704 static
1706  SCIP* scip, /**< SCIP data structure */
1707  SCIP_CONS* cons /**< constraint */
1708  )
1709 {
1710  SCIP_CONSDATA* consdata;
1711  int poslock;
1712  int neglock;
1713  int i;
1714 
1715  assert(cons != NULL);
1716 
1717  consdata = SCIPconsGetData(cons);
1718  assert(consdata != NULL);
1719 
1720  consdata->linvarincr = NULL;
1721  consdata->linvardecr = NULL;
1722  consdata->linvarincrcoef = 0.0;
1723  consdata->linvardecrcoef = 0.0;
1724 
1725  /* root expression is not a sum -> no unlocked linear variable available */
1726  if( !SCIPisExprSum(scip, consdata->expr) )
1727  return;
1728 
1729  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
1730  {
1731  SCIP_EXPR* child;
1732 
1733  child = SCIPexprGetChildren(consdata->expr)[i];
1734  assert(child != NULL);
1735 
1736  /* check whether the child is a variable expression */
1737  if( SCIPisExprVar(scip, child) )
1738  {
1739  SCIP_VAR* var = SCIPgetVarExprVar(child);
1740  SCIP_Real coef = SCIPgetCoefsExprSum(consdata->expr)[i];
1741 
1742  if( coef > 0.0 )
1743  {
1744  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1745  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1746  }
1747  else
1748  {
1749  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
1750  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
1751  }
1753 
1754  if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) - neglock == 0 )
1755  {
1756  /* for a*x + f(y) \in [lhs, rhs], we can decrease x without harming other constraints
1757  * if we have already one candidate, then take the one where the loss in the objective function is less
1758  */
1759  if( (consdata->linvardecr == NULL) ||
1760  (SCIPvarGetObj(consdata->linvardecr) / consdata->linvardecrcoef > SCIPvarGetObj(var) / coef) )
1761  {
1762  consdata->linvardecr = var;
1763  consdata->linvardecrcoef = coef;
1764  }
1765  }
1766 
1767  if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) - poslock == 0 )
1768  {
1769  /* for a*x + f(y) \in [lhs, rhs], we can increase x without harm
1770  * if we have already one candidate, then take the one where the loss in the objective function is less
1771  */
1772  if( (consdata->linvarincr == NULL) ||
1773  (SCIPvarGetObj(consdata->linvarincr) / consdata->linvarincrcoef > SCIPvarGetObj(var) / coef) )
1774  {
1775  consdata->linvarincr = var;
1776  consdata->linvarincrcoef = coef;
1777  }
1778  }
1779  }
1780  }
1781 
1782  assert(consdata->linvarincr == NULL || consdata->linvarincrcoef != 0.0);
1783  assert(consdata->linvardecr == NULL || consdata->linvardecrcoef != 0.0);
1784 
1785  if( consdata->linvarincr != NULL )
1786  {
1787  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvarincr));
1788  }
1789  if( consdata->linvardecr != NULL )
1790  {
1791  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvardecr));
1792  }
1793 }
1794 
1795 /** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
1796  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
1797  *
1798  * The method assumes that this is always possible and that not all constraints are feasible already.
1799  */
1800 static
1802  SCIP* scip, /**< SCIP data structure */
1803  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1804  SCIP_CONS** conss, /**< constraints to process */
1805  int nconss, /**< number of constraints */
1806  SCIP_SOL* sol, /**< solution to process */
1807  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
1808  )
1809 {
1810  SCIP_CONSHDLRDATA* conshdlrdata;
1811  SCIP_SOL* newsol;
1812  int c;
1813 
1814  assert(scip != NULL);
1815  assert(conshdlr != NULL);
1816  assert(conss != NULL || nconss == 0);
1817  assert(success != NULL);
1818 
1819  *success = FALSE;
1820 
1821  /* don't propose new solutions if not in presolve or solving */
1823  return SCIP_OKAY;
1824 
1825  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1826  assert(conshdlrdata != NULL);
1827 
1828  if( sol != NULL )
1829  {
1830  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
1831  }
1832  else
1833  {
1834  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
1835  }
1836  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
1837  SCIPdebugMsg(scip, "attempt to make solution from <%s> feasible by shifting linear variable\n",
1838  sol != NULL ? (SCIPsolGetHeur(sol) != NULL ? SCIPheurGetName(SCIPsolGetHeur(sol)) : "tree") : "LP");
1839 
1840  for( c = 0; c < nconss; ++c )
1841  {
1842  SCIP_CONSDATA* consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
1843  SCIP_Real viol = 0.0;
1844  SCIP_Real delta;
1845  SCIP_Real gap;
1846 
1847  assert(consdata != NULL);
1848 
1849  /* get absolute violation and sign */
1850  if( consdata->lhsviol > SCIPfeastol(scip) )
1851  viol = consdata->lhsviol; /* lhs - activity */
1852  else if( consdata->rhsviol > SCIPfeastol(scip) )
1853  viol = -consdata->rhsviol; /* rhs - activity */
1854  else
1855  continue; /* constraint is satisfied */
1856 
1857  if( consdata->linvarincr != NULL &&
1858  ((viol > 0.0 && consdata->linvarincrcoef > 0.0) || (viol < 0.0 && consdata->linvarincrcoef < 0.0)) )
1859  {
1860  SCIP_VAR* var = consdata->linvarincr;
1861 
1862  /* compute how much we would like to increase var */
1863  delta = viol / consdata->linvarincrcoef;
1864  assert(delta > 0.0);
1865 
1866  /* if var has an upper bound, may need to reduce delta */
1867  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
1868  {
1869  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
1870  delta = MIN(MAX(0.0, gap), delta);
1871  }
1872  if( SCIPisPositive(scip, delta) )
1873  {
1874  /* if variable is integral, round delta up so that it will still have an integer value */
1875  if( SCIPvarIsIntegral(var) )
1876  delta = SCIPceil(scip, delta);
1877 
1878  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
1879  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy lhs-violation %g of cons <%s>\n",
1880  SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c])); /*lint !e613*/
1881 
1882  /* adjust constraint violation, if satisfied go on to next constraint */
1883  viol -= consdata->linvarincrcoef * delta;
1884  if( SCIPisZero(scip, viol) )
1885  continue;
1886  }
1887  }
1888 
1889  assert(viol != 0.0);
1890  if( consdata->linvardecr != NULL &&
1891  ((viol > 0.0 && consdata->linvardecrcoef < 0.0) || (viol < 0.0 && consdata->linvardecrcoef > 0.0)) )
1892  {
1893  SCIP_VAR* var = consdata->linvardecr;
1894 
1895  /* compute how much we would like to decrease var */
1896  delta = viol / consdata->linvardecrcoef;
1897  assert(delta < 0.0);
1898 
1899  /* if var has a lower bound, may need to reduce delta */
1900  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
1901  {
1902  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
1903  delta = MAX(MIN(0.0, gap), delta);
1904  }
1905  if( SCIPisNegative(scip, delta) )
1906  {
1907  /* if variable is integral, round delta down so that it will still have an integer value */
1908  if( SCIPvarIsIntegral(var) )
1909  delta = SCIPfloor(scip, delta);
1910  SCIP_CALL( SCIPincSolVal(scip, newsol, consdata->linvardecr, delta) );
1911  /*lint --e{613} */
1912  SCIPdebugMsg(scip, "increase <%s> by %g to %g to remedy rhs-violation %g of cons <%s>\n",
1913  SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var), viol, SCIPconsGetName(conss[c]));
1914 
1915  /* adjust constraint violation, if satisfied go on to next constraint */
1916  viol -= consdata->linvardecrcoef * delta;
1917  if( SCIPisZero(scip, viol) )
1918  continue;
1919  }
1920  }
1921 
1922  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
1923  break;
1924  }
1925 
1926  /* if we have a solution that should satisfy all quadratic constraints and has a better objective than the current upper bound,
1927  * then pass it to the trysol heuristic
1928  */
1929  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
1930  {
1931  SCIPdebugMsg(scip, "pass solution with objective val %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
1932 
1933  assert(conshdlrdata->trysolheur != NULL);
1934  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
1935 
1936  *success = TRUE;
1937  }
1938 
1939  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
1940 
1941  return SCIP_OKAY;
1942 }
1943 
1944 /** notify nonlinear handlers to add linearization in new solution that has been found
1945  *
1946  * The idea is that nonlinear handlers add globally valid tight estimators in a given solution as cuts to the cutpool.
1947  *
1948  * Essentially we want to ensure that the LP relaxation is tight in the new solution, if possible.
1949  * As the nonlinear handlers define the extended formulation, they should know whether it is possible to generate a
1950  * cut that is valid and supporting in the given solution.
1951  * For example, for convex constraints, we achieve this by linearizing.
1952  * For SOC, we also linearize, but on a a convex reformulation.
1953  *
1954  * Since linearization may happen in auxiliary variables, we ensure that auxiliary variables are set
1955  * to the eval-value of its expression, i.e., we change sol so it is also feasible in the extended formulation.
1956  */
1957 static
1959  SCIP* scip, /**< SCIP data structure */
1960  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1961  SCIP_CONS** conss, /**< constraints */
1962  int nconss, /**< number of constraints */
1963  SCIP_SOL* sol, /**< reference point where to estimate */
1964  SCIP_Bool solisbest /**< whether solution is best */
1965  )
1966 {
1967  SCIP_CONSDATA* consdata;
1968  SCIP_Longint soltag;
1969  SCIP_EXPRITER* it;
1970  SCIP_EXPR* expr;
1971  int c, e;
1972 
1973  assert(scip != NULL);
1974  assert(conshdlr != NULL);
1975  assert(conss != NULL || nconss == 0);
1976 
1977  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "call nlhdlr sollinearize in new solution from <%s>\n", SCIPheurGetName(SCIPsolGetHeur(sol))); )
1978 
1979  /* TODO probably we just evaluated all expressions when checking the sol before it was added
1980  * would be nice to recognize this and skip reevaluating
1981  */
1982  soltag = SCIPgetExprNewSoltag(scip);
1983 
1984  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
1987 
1988  for( c = 0; c < nconss; ++c )
1989  {
1990  /* skip constraints that are not enabled or deleted or have separation disabled */
1991  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
1992  continue;
1993  assert(SCIPconsIsActive(conss[c]));
1994 
1995  consdata = SCIPconsGetData(conss[c]);
1996  assert(consdata != NULL);
1997 
1998  ENFOLOG(
1999  {
2000  int i;
2001  SCIPinfoMessage(scip, enfologfile, " constraint ");
2002  SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
2003  SCIPinfoMessage(scip, enfologfile, "\n and point\n");
2004  for( i = 0; i < consdata->nvarexprs; ++i )
2005  {
2006  SCIP_VAR* var;
2007  var = SCIPgetVarExprVar(consdata->varexprs[i]);
2008  SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
2009  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
2010  }
2011  })
2012 
2013  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, soltag) );
2014  assert(SCIPexprGetEvalValue(consdata->expr) != SCIP_INVALID);
2015 
2016  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
2017  {
2018  SCIP_EXPR_OWNERDATA* ownerdata;
2019 
2020  ownerdata = SCIPexprGetOwnerData(expr);
2021  assert(ownerdata != NULL);
2022 
2023  /* set value for auxvar in sol to value of expr, in case it is used to compute estimators higher up of this expression */
2024  assert(SCIPexprGetEvalTag(expr) == soltag);
2025  assert(SCIPexprGetEvalValue(expr) != SCIP_INVALID);
2026  if( ownerdata->auxvar != NULL )
2027  {
2028  SCIP_CALL( SCIPsetSolVal(scip, sol, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
2029  }
2030 
2031  /* let nonlinear handler generate cuts by calling the sollinearize callback */
2032  for( e = 0; e < ownerdata->nenfos; ++e )
2033  {
2034  /* call sollinearize callback, if implemented by nlhdlr */
2035  SCIP_CALL( SCIPnlhdlrSollinearize(scip, conshdlr, conss[c],
2036  ownerdata->enfos[e]->nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol, solisbest,
2037  ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE,
2038  ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) );
2039  }
2040  }
2041  }
2042 
2043  SCIPfreeExpriter(&it);
2044 
2045  return SCIP_OKAY;
2046 }
2047 
2048 /** processes the event that a new primal solution has been found */
2049 static
2050 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
2052  SCIP_CONSHDLR* conshdlr;
2053  SCIP_CONSHDLRDATA* conshdlrdata;
2054  SCIP_SOL* sol;
2055 
2056  assert(scip != NULL);
2057  assert(event != NULL);
2058  assert(eventdata != NULL);
2059  assert(eventhdlr != NULL);
2060  assert(SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND);
2061 
2062  conshdlr = (SCIP_CONSHDLR*)eventdata;
2063 
2064  if( SCIPconshdlrGetNConss(conshdlr) == 0 )
2065  return SCIP_OKAY;
2066 
2067  sol = SCIPeventGetSol(event);
2068  assert(sol != NULL);
2069 
2070  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2071  assert(conshdlrdata != NULL);
2072 
2073  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
2074  * the reason for ignoring trysol solutions is that they may come ~~from an NLP solve in sepalp, where we already added linearizations, or are~~
2075  * from the tree, but postprocessed via proposeFeasibleSolution
2076  */
2077  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
2078  return SCIP_OKAY;
2079 
2080  SCIPdebugMsg(scip, "caught new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)));
2081 
2082  SCIP_CALL( notifyNlhdlrNewsol(scip, conshdlr, SCIPconshdlrGetConss(conshdlr), SCIPconshdlrGetNConss(conshdlr), sol, (SCIPeventGetType(event) & SCIP_EVENTTYPE_BESTSOLFOUND) != 0) );
2083 
2084  return SCIP_OKAY;
2085 }
2086 
2087 /** tightens the bounds of the auxiliary variable associated with an expression (or original variable if being a variable-expression) according to given bounds
2088  *
2089  * The given bounds may very well be the exprs activity (when called from forwardPropExpr()), but can also be some
2090  * tighter bounds (when called from SCIPtightenExprIntervalNonlinear()).
2091  *
2092  * Nothing will happen if SCIP is not in presolve or solve.
2093  */
2094 static
2096  SCIP* scip, /**< SCIP data structure */
2097  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2098  SCIP_EXPR* expr, /**< expression whose auxvar is to be tightened */
2099  SCIP_INTERVAL bounds, /**< bounds to be used for tightening (must not be empty) */
2100  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
2101  int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
2102  )
2103 {
2104  SCIP_VAR* var;
2105  SCIP_Bool tightenedlb;
2106  SCIP_Bool tightenedub;
2107  SCIP_Bool force;
2108 
2109  assert(scip != NULL);
2110  assert(conshdlr != NULL);
2111  assert(expr != NULL);
2112  assert(cutoff != NULL);
2113 
2114  /* the given bounds must not be empty (we could cope, but we shouldn't be called in this situation) */
2115  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, bounds));
2116 
2117  *cutoff = FALSE;
2118 
2119  var = SCIPgetExprAuxVarNonlinear(expr);
2120  if( var == NULL )
2121  return SCIP_OKAY;
2122 
2123  /* force tightening if conshdlrdata says so or it would mean fixing the variable */
2124  force = SCIPconshdlrGetData(conshdlr)->forceboundtightening || SCIPisEQ(scip, bounds.inf, bounds.sup);
2125 
2126  /* try to tighten lower bound of (auxiliary) variable */
2127  SCIP_CALL( SCIPtightenVarLb(scip, var, bounds.inf, force, cutoff, &tightenedlb) );
2128  if( tightenedlb )
2129  {
2130  if( ntightenings != NULL )
2131  ++*ntightenings;
2132  SCIPdebugMsg(scip, "tightened lb on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), force);
2133  }
2134  if( *cutoff )
2135  {
2136  SCIPdebugMsg(scip, "cutoff when tightening lb on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.inf);
2137  return SCIP_OKAY;
2138  }
2139 
2140  /* try to tighten upper bound of (auxiliary) variable */
2141  SCIP_CALL( SCIPtightenVarUb(scip, var, bounds.sup, force, cutoff, &tightenedub) );
2142  if( tightenedub )
2143  {
2144  if( ntightenings != NULL )
2145  ++*ntightenings;
2146  SCIPdebugMsg(scip, "tightened ub on auxvar <%s> to %.15g (forced:%u)\n", SCIPvarGetName(var), SCIPvarGetUbLocal(var), force);
2147  }
2148  if( *cutoff )
2149  {
2150  SCIPdebugMsg(scip, "cutoff when tightening ub on auxvar <%s> to %.15g\n", SCIPvarGetName(var), bounds.sup);
2151  return SCIP_OKAY;
2152  }
2153 
2154  /* TODO expr->activity should have been reevaluated now due to boundchange-events, but it used to relax bounds
2155  * that seems unnecessary and we could easily undo this here, e.g.,
2156  * if( tightenedlb ) expr->activity.inf = bounds.inf
2157  */
2158 
2159  return SCIP_OKAY;
2160 }
2161 
2162 /** propagate bounds of the expressions in a given expression tree (that is, updates activity intervals)
2163  * and tries to tighten the bounds of the auxiliary variables accordingly
2164  */
2165 static
2167  SCIP* scip, /**< SCIP data structure */
2168  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2169  SCIP_EXPR* rootexpr, /**< expression */
2170  SCIP_Bool tightenauxvars, /**< should the bounds of auxiliary variables be tightened? */
2171  SCIP_Bool* infeasible, /**< buffer to store whether the problem is infeasible (NULL if not needed) */
2172  int* ntightenings /**< buffer to store the number of auxiliary variable tightenings (NULL if not needed) */
2173  )
2174 {
2175  SCIP_EXPRITER* it;
2176  SCIP_EXPR* expr;
2177  SCIP_EXPR_OWNERDATA* ownerdata;
2178  SCIP_CONSHDLRDATA* conshdlrdata;
2179 
2180  assert(scip != NULL);
2181  assert(rootexpr != NULL);
2182 
2183  if( infeasible != NULL )
2184  *infeasible = FALSE;
2185  if( ntightenings != NULL )
2186  *ntightenings = 0;
2187 
2188  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2189  assert(conshdlrdata != NULL);
2190 
2191  /* if value is valid and empty, then we cannot improve, so do nothing */
2192  if( SCIPexprGetActivityTag(rootexpr) >= conshdlrdata->lastboundrelax && SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr)) )
2193  {
2194  SCIPdebugMsg(scip, "stored activity of root expr is empty and valid (activitytag >= lastboundrelax (%" SCIP_LONGINT_FORMAT ")), skip forwardPropExpr -> cutoff\n", conshdlrdata->lastboundrelax);
2195 
2196  if( infeasible != NULL )
2197  *infeasible = TRUE;
2198 
2199  /* just update tag to curboundstag */
2200  SCIPexprSetActivity(rootexpr, SCIPexprGetActivity(rootexpr), conshdlrdata->curboundstag);
2201 
2202  return SCIP_OKAY;
2203  }
2204 
2205  /* if value is up-to-date, then nothing to do */
2206  if( SCIPexprGetActivityTag(rootexpr) == conshdlrdata->curboundstag )
2207  {
2208  SCIPdebugMsg(scip, "activitytag of root expr equals curboundstag (%" SCIP_LONGINT_FORMAT "), skip forwardPropExpr\n", conshdlrdata->curboundstag);
2209 
2210  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(rootexpr))); /* handled in previous if() */
2211 
2212  return SCIP_OKAY;
2213  }
2214 
2215  ownerdata = SCIPexprGetOwnerData(rootexpr);
2216  assert(ownerdata != NULL);
2217 
2218  /* if activity of rootexpr is not used, but expr participated in detect (nenfos >= 0), then we do nothing
2219  * it seems wrong to be called for such an expression (unless we are in detect at the moment), so I add a SCIPABORT()
2220  * during detect, we are in some in-between state where we may want to eval activity
2221  * on exprs that we did not notify about their activity usage
2222  */
2223  if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect)
2224  {
2225 #ifdef DEBUG_PROP
2226  SCIPdebugMsg(scip, "root expr activity is not used but enfo initialized, skip inteval\n");
2227 #endif
2228  SCIPABORT();
2229  return SCIP_OKAY;
2230  }
2231 
2232  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2233  SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2235 
2236  for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); )
2237  {
2238  switch( SCIPexpriterGetStageDFS(it) )
2239  {
2241  {
2242  /* skip child if it has been evaluated already */
2243  SCIP_EXPR* child;
2244 
2245  child = SCIPexpriterGetChildExprDFS(it);
2246  if( conshdlrdata->curboundstag == SCIPexprGetActivityTag(child) )
2247  {
2248  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(child)) && infeasible != NULL )
2249  *infeasible = TRUE;
2250 
2251  expr = SCIPexpriterSkipDFS(it);
2252  continue;
2253  }
2254 
2255  break;
2256  }
2257 
2259  {
2260  SCIP_INTERVAL activity;
2261 
2262  /* we should not have entered this expression if its activity was already up to date */
2263  assert(SCIPexprGetActivityTag(expr) < conshdlrdata->curboundstag);
2264 
2265  ownerdata = SCIPexprGetOwnerData(expr);
2266  assert(ownerdata != NULL);
2267 
2268  /* for var exprs where varevents are catched, activity is updated immediately when the varbound has been changed
2269  * so we can assume that the activity is up to date for all these variables
2270  * UNLESS we changed the method used to evaluate activity of variable expressions
2271  * or we currently use global bounds (varevents are catched for local bound changes only)
2272  */
2273  if( SCIPisExprVar(scip, expr) && ownerdata->filterpos >= 0 &&
2274  SCIPexprGetActivityTag(expr) >= conshdlrdata->lastvaractivitymethodchange && !conshdlrdata->globalbounds )
2275  {
2276 #ifndef NDEBUG
2277  SCIP_INTERVAL exprhdlrinterval;
2278 
2279  SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2280  assert(SCIPisRelEQ(scip, exprhdlrinterval.inf, SCIPexprGetActivity(expr).inf));
2281  assert(SCIPisRelEQ(scip, exprhdlrinterval.sup, SCIPexprGetActivity(expr).sup));
2282 #endif
2283 #ifdef DEBUG_PROP
2284  SCIPdebugMsg(scip, "skip interval evaluation of expr for var <%s> [%g,%g]\n", SCIPvarGetName(SCIPgetVarExprVar(expr)), SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2285 #endif
2286  SCIPexprSetActivity(expr, SCIPexprGetActivity(expr), conshdlrdata->curboundstag);
2287 
2288  break;
2289  }
2290 
2291  if( SCIPexprGetActivityTag(expr) < conshdlrdata->lastboundrelax )
2292  {
2293  /* start with entire activity if current one is invalid */
2295  }
2297  {
2298  /* If already empty, then don't try to compute even better activity.
2299  * If cons_nonlinear were alone, then we should have noted that we are infeasible
2300  * so an assert(infeasible == NULL || *infeasible) should work here.
2301  * However, after reporting a cutoff due to expr->activity being empty,
2302  * SCIP may wander to a different node and call propagation again.
2303  * If no bounds in a nonlinear constraint have been relaxed when switching nodes
2304  * (so expr->activitytag >= conshdlrdata->lastboundrelax), then
2305  * we will still have expr->activity being empty, but will have forgotten
2306  * that we found infeasibility here before (!2221#note_134120).
2307  * Therefore we just set *infeasibility=TRUE here and stop.
2308  */
2309  if( infeasible != NULL )
2310  *infeasible = TRUE;
2311  SCIPdebugMsg(scip, "expr %p already has empty activity -> cutoff\n", (void*)expr);
2312  break;
2313  }
2314  else
2315  {
2316  /* start with current activity, since it is valid */
2317  activity = SCIPexprGetActivity(expr);
2318  }
2319 
2320  /* if activity of expr is not used, but expr participated in detect (nenfos >= 0), then do nothing */
2321  if( ownerdata->nenfos >= 0 && ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && !conshdlrdata->indetect )
2322  {
2323 #ifdef DEBUG_PROP
2324  SCIPdebugMsg(scip, "expr %p activity is not used but enfo initialized, skip inteval\n", (void*)expr);
2325 #endif
2326  break;
2327  }
2328 
2329 #ifdef DEBUG_PROP
2330  SCIPdebugMsg(scip, "interval evaluation of expr %p ", (void*)expr);
2331  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2332  SCIPdebugMsgPrint(scip, ", current activity = [%.20g, %.20g]\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2333 #endif
2334 
2335  /* run interval eval of nonlinear handlers or expression handler */
2336  if( ownerdata->nenfos > 0 )
2337  {
2338  SCIP_NLHDLR* nlhdlr;
2339  SCIP_INTERVAL nlhdlrinterval;
2340  int e;
2341 
2342  /* for expressions with enforcement, nlhdlrs take care of interval evaluation */
2343  for( e = 0; e < ownerdata->nenfos && !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, activity); ++e )
2344  {
2345  /* skip nlhdlr if it does not want to participate in activity computation */
2346  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2347  continue;
2348 
2349  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2350  assert(nlhdlr != NULL);
2351 
2352  /* skip nlhdlr if it does not provide interval evaluation (so it may only provide reverse propagation) */
2353  if( !SCIPnlhdlrHasIntEval(nlhdlr) )
2354  continue;
2355 
2356  /* let nlhdlr evaluate current expression */
2357  nlhdlrinterval = activity;
2358  SCIP_CALL( SCIPnlhdlrInteval(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2359  &nlhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2360 #ifdef DEBUG_PROP
2361  SCIPdebugMsg(scip, " nlhdlr <%s>::inteval = [%.20g, %.20g]", SCIPnlhdlrGetName(nlhdlr), nlhdlrinterval.inf, nlhdlrinterval.sup);
2362 #endif
2363 
2364  /* update activity by intersecting with computed activity */
2365  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, nlhdlrinterval);
2366 #ifdef DEBUG_PROP
2367  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2368 #endif
2369  }
2370  }
2371  else
2372  {
2373  /* for node without enforcement (before or during detect), call the callback of the exprhdlr directly */
2374  SCIP_INTERVAL exprhdlrinterval = activity;
2375  SCIP_CALL( SCIPcallExprInteval(scip, expr, &exprhdlrinterval, conshdlrdata->intevalvar, conshdlrdata) );
2376 #ifdef DEBUG_PROP
2377  SCIPdebugMsg(scip, " exprhdlr <%s>::inteval = [%.20g, %.20g]", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), exprhdlrinterval.inf, exprhdlrinterval.sup);
2378 #endif
2379 
2380  /* update expr->activity by intersecting with computed activity */
2381  SCIPintervalIntersectEps(&activity, SCIPepsilon(scip), activity, exprhdlrinterval);
2382 #ifdef DEBUG_PROP
2383  SCIPdebugMsgPrint(scip, " -> new activity: [%.20g, %.20g]\n", activity.inf, activity.sup);
2384 #endif
2385  }
2386 
2387  /* if expression is integral, then we try to tighten the interval bounds a bit
2388  * this should undo the addition of some unnecessary safety added by use of nextafter() in interval arithmetics, e.g., when doing pow()
2389  * it would be ok to use ceil() and floor(), but for safety we use SCIPceil and SCIPfloor for now
2390  * do this only if using boundtightening-inteval and not in redundancy check (there we really want to relax all variables)
2391  * boundtightening-inteval does not relax integer variables, so can omit expressions without children
2392  * (constants should be ok, too)
2393  */
2394  if( SCIPexprIsIntegral(expr) && conshdlrdata->intevalvar == intEvalVarBoundTightening && SCIPexprGetNChildren(expr) > 0 )
2395  {
2396  if( activity.inf > -SCIP_INTERVAL_INFINITY )
2397  activity.inf = SCIPceil(scip, activity.inf);
2398  if( activity.sup < SCIP_INTERVAL_INFINITY )
2399  activity.sup = SCIPfloor(scip, activity.sup);
2400 #ifdef DEBUG_PROP
2401  SCIPdebugMsg(scip, " applying integrality: [%.20g, %.20g]\n", activity.inf, activity.sup);
2402 #endif
2403  }
2404 
2405  /* mark the current node to be infeasible if either the lower/upper bound is above/below +/- SCIPinfinity()
2406  * TODO this is a problem if dual-presolve fixed a variable to +/- infinity
2407  */
2408  if( SCIPisInfinity(scip, activity.inf) || SCIPisInfinity(scip, -activity.sup) )
2409  {
2410  SCIPdebugMsg(scip, "cut off due to activity [%g,%g] beyond infinity\n", activity.inf, activity.sup);
2411  SCIPintervalSetEmpty(&activity);
2412  }
2413 
2414  /* now finally store activity in expr */
2415  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2416 
2418  {
2419  if( infeasible != NULL )
2420  *infeasible = TRUE;
2421  }
2422  else if( tightenauxvars && ownerdata->auxvar != NULL )
2423  {
2424  SCIP_Bool tighteninfeasible;
2425 
2426  SCIP_CALL( tightenAuxVarBounds(scip, conshdlr, expr, activity, &tighteninfeasible, ntightenings) );
2427  if( tighteninfeasible )
2428  {
2429  if( infeasible != NULL )
2430  *infeasible = TRUE;
2431  SCIPintervalSetEmpty(&activity);
2432  SCIPexprSetActivity(expr, activity, conshdlrdata->curboundstag);
2433  }
2434  }
2435 
2436  break;
2437  }
2438 
2439  default:
2440  /* you should never be here */
2441  SCIPerrorMessage("unexpected iterator stage\n");
2442  SCIPABORT();
2443  break;
2444  }
2445 
2446  expr = SCIPexpriterGetNext(it);
2447  }
2448 
2449  SCIPfreeExpriter(&it);
2450 
2451  return SCIP_OKAY;
2452 }
2453 
2454 /** returns whether intersecting `oldinterval` with `newinterval` would provide a properly smaller interval
2455  *
2456  * If `subsetsufficient` is TRUE, then the intersection being smaller than oldinterval is sufficient.
2457  *
2458  * If `subsetsufficient` is FALSE, then we require
2459  * - a change from an unbounded interval to a bounded one, or
2460  * - or a change from an unfixed (width > epsilon) to a fixed interval, or
2461  * - a minimal tightening of one of the interval bounds as defined by SCIPis{Lb,Ub}Better().
2462  */
2463 static
2465  SCIP* scip, /**< SCIP data structure */
2466  SCIP_Bool subsetsufficient, /**< whether the intersection being a proper subset of oldinterval is sufficient */
2467  SCIP_INTERVAL newinterval, /**< new interval */
2468  SCIP_INTERVAL oldinterval /**< old interval */
2469  )
2470 {
2471  assert(scip != NULL);
2472  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, newinterval));
2473  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, oldinterval));
2474 
2475  if( subsetsufficient )
2476  /* oldinterval \cap newinterval < oldinterval iff not oldinterval is subset of newinterval */
2477  return !SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, oldinterval, newinterval);
2478 
2479  /* check whether lower bound of interval becomes finite */
2480  if( oldinterval.inf <= -SCIP_INTERVAL_INFINITY && newinterval.inf > -SCIP_INTERVAL_INFINITY )
2481  return TRUE;
2482 
2483  /* check whether upper bound of interval becomes finite */
2484  if( oldinterval.sup >= SCIP_INTERVAL_INFINITY && newinterval.sup > SCIP_INTERVAL_INFINITY )
2485  return TRUE;
2486 
2487  /* check whether intersection will have width <= epsilon, if oldinterval doesn't have yet */
2488  if( !SCIPisEQ(scip, oldinterval.inf, oldinterval.sup) && SCIPisEQ(scip, MAX(oldinterval.inf, newinterval.inf), MIN(oldinterval.sup, newinterval.sup)) )
2489  return TRUE;
2490 
2491  /* check whether lower bound on interval will be better by SCIP's quality measures for boundchanges */
2492  if( SCIPisLbBetter(scip, newinterval.inf, oldinterval.inf, oldinterval.sup) )
2493  return TRUE;
2494 
2495  /* check whether upper bound on interval will be better by SCIP's quality measures for boundchanges */
2496  if( SCIPisUbBetter(scip, newinterval.sup, oldinterval.inf, oldinterval.sup) )
2497  return TRUE;
2498 
2499  return FALSE;
2500 }
2501 
2502 /** propagates bounds for each sub-expression in the `reversepropqueue` by starting from the root expressions
2503  *
2504  * The expression will be traversed in breadth first search by using this queue.
2505  *
2506  * @note Calling this function requires feasible intervals for each sub-expression; this is guaranteed by calling
2507  * forwardPropExpr() before calling this function.
2508  *
2509  * @note Calling this function with `*infeasible` = TRUE will only empty the queue.
2510  */
2511 static
2513  SCIP* scip, /**< SCIP data structure */
2514  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2515  SCIP_Bool* infeasible, /**< buffer to update whether an expression's bounds were propagated to an empty interval */
2516  int* ntightenings /**< buffer to store the number of (variable) tightenings */
2517  )
2518 {
2519  SCIP_CONSHDLRDATA* conshdlrdata;
2520  SCIP_EXPR* expr;
2521  SCIP_EXPR_OWNERDATA* ownerdata;
2522 
2523  assert(infeasible != NULL);
2524  assert(ntightenings != NULL);
2525 
2526  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2527  assert(conshdlrdata != NULL);
2528 
2529  *ntightenings = 0;
2530 
2531  /* main loop that calls reverse propagation for expressions on the queue
2532  * when reverseprop finds a tightening for an expression, then that expression is added to the queue (within the reverseprop call)
2533  */
2534  while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) && !(*infeasible) )
2535  {
2536  SCIP_INTERVAL propbounds;
2537  int e;
2538 
2539  expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2540  assert(expr != NULL);
2541 
2542  ownerdata = SCIPexprGetOwnerData(expr);
2543  assert(ownerdata != NULL);
2544 
2545  assert(ownerdata->inpropqueue);
2546  /* mark that the expression is not in the queue anymore */
2547  ownerdata->inpropqueue = FALSE;
2548 
2549  /* since the expr was in the propagation queue, the propbounds should belong to current propagation and should not be empty
2550  * (propbounds being entire doesn't make much sense, so assert this for now, too, but that could be removed)
2551  */
2552  assert(ownerdata->propboundstag == conshdlrdata->curpropboundstag);
2553  assert(!SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2554  assert(!SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, ownerdata->propbounds));
2555 
2556  /* this intersects propbounds with activity and auxvar bounds
2557  * I doubt this would be much helpful, since propbounds are already subset of activity and we also propagate
2558  * auxvar bounds separately, so disabling this for now
2559  */
2560 #ifdef SCIP_DISABLED_CODE
2561  propbounds = SCIPgetExprBoundsNonlinear(scip, expr);
2562  if( SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, propbounds) )
2563  {
2564  *infeasible = TRUE;
2565  break;
2566  }
2567 #else
2568  propbounds = ownerdata->propbounds;
2569 #endif
2570 
2571  if( ownerdata->nenfos > 0 )
2572  {
2573  /* for nodes with enforcement, call reverse propagation callbacks of nlhdlrs */
2574  for( e = 0; e < ownerdata->nenfos && !*infeasible; ++e )
2575  {
2576  SCIP_NLHDLR* nlhdlr;
2577  int nreds;
2578 
2579  /* skip nlhdlr if it does not want to participate in activity computation */
2580  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2581  continue;
2582 
2583  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2584  assert(nlhdlr != NULL);
2585 
2586  /* call the reverseprop of the nlhdlr */
2587 #ifdef SCIP_DEBUG
2588  SCIPdebugMsg(scip, "call reverse propagation for ");
2589  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2590  SCIPdebugMsgPrint(scip, " in [%g,%g] using nlhdlr <%s>\n", propbounds.inf, propbounds.sup, SCIPnlhdlrGetName(nlhdlr));
2591 #endif
2592 
2593  nreds = 0;
2594  SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, propbounds, infeasible, &nreds) );
2595  assert(nreds >= 0);
2596  *ntightenings += nreds;
2597  }
2598  }
2600  {
2601  /* if expr without enforcement (before detect), call reverse propagation callback of exprhdlr directly */
2602  SCIP_INTERVAL* childrenbounds;
2603  int c;
2604 
2605 #ifdef SCIP_DEBUG
2606  SCIPdebugMsg(scip, "call reverse propagation for ");
2607  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
2608  SCIPdebugMsgPrint(scip, " in [%g,%g] using exprhdlr <%s>\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
2609 #endif
2610 
2611  /* if someone added an expr without nlhdlr into the reversepropqueue, then this must be because its enfo hasn't
2612  * been initialized in detectNlhdlr yet (nenfos < 0)
2613  */
2614  assert(ownerdata->nenfos < 0);
2615 
2616  SCIP_CALL( SCIPallocBufferArray(scip, &childrenbounds, SCIPexprGetNChildren(expr)) );
2617  for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2618  childrenbounds[c] = SCIPgetExprBoundsNonlinear(scip, SCIPexprGetChildren(expr)[c]);
2619 
2620  /* call the reverseprop of the exprhdlr */
2621  SCIP_CALL( SCIPcallExprReverseprop(scip, expr, propbounds, childrenbounds, infeasible) );
2622 
2623  if( !*infeasible )
2624  for( c = 0; c < SCIPexprGetNChildren(expr); ++c )
2625  {
2626  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, SCIPexprGetChildren(expr)[c], childrenbounds[c], infeasible, ntightenings) );
2627  }
2628 
2629  SCIPfreeBufferArray(scip, &childrenbounds);
2630  }
2631  }
2632 
2633  /* reset inpropqueue for all remaining expr's in queue (can happen in case of early stop due to infeasibility) */
2634  while( !SCIPqueueIsEmpty(conshdlrdata->reversepropqueue) )
2635  {
2636  expr = (SCIP_EXPR*) SCIPqueueRemove(conshdlrdata->reversepropqueue);
2637  assert(expr != NULL);
2638 
2639  ownerdata = SCIPexprGetOwnerData(expr);
2640  assert(ownerdata != NULL);
2641 
2642  /* mark that the expression is not in the queue anymore */
2643  ownerdata->inpropqueue = FALSE;
2644  }
2645 
2646  return SCIP_OKAY;
2647 }
2648 
2649 /** calls domain propagation for a given set of constraints
2650  *
2651  * The algorithm alternates calls of forward and reverse propagation.
2652  * Forward propagation ensures that activity of expressions is up to date.
2653  * Reverse propagation tries to derive tighter variable bounds by reversing the activity computation, using the constraints
2654  * [lhs,rhs] interval as starting point.
2655  *
2656  * The propagation algorithm works as follows:
2657  * 1. apply forward propagation (update activities) for all constraints not marked as propagated
2658  * 2. if presolve or propauxvars is disabled: collect expressions for which the constraint sides provide tighter bounds
2659  * if solve and propauxvars is enabled: collect expressions for which auxvars (including those in root exprs)
2660  * provide tighter bounds
2661  * 3. apply reverse propagation to all collected expressions; don't explore
2662  * sub-expressions which have not changed since the beginning of the propagation loop
2663  * 4. if we have found enough tightenings go to 1, otherwise leave propagation loop
2664  *
2665  * @note After calling forward propagation for a constraint, we mark this constraint as propagated. This flag might be
2666  * reset during the reverse propagation when we find a bound tightening of a variable expression contained in the
2667  * constraint. Resetting this flag is done in the EVENTEXEC callback of the event handler
2668  *
2669  * TODO should we distinguish between expressions where activity information is used for separation and those where not,
2670  * e.g., try less to propagate on convex constraints?
2671  */
2672 static
2674  SCIP* scip, /**< SCIP data structure */
2675  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2676  SCIP_CONS** conss, /**< constraints to propagate */
2677  int nconss, /**< total number of constraints */
2678  SCIP_Bool force, /**< force tightening even if below bound strengthening tolerance */
2679  SCIP_RESULT* result, /**< pointer to store the result */
2680  int* nchgbds /**< buffer to add the number of changed bounds */
2681  )
2682 {
2683  SCIP_CONSHDLRDATA* conshdlrdata;
2684  SCIP_CONSDATA* consdata;
2685  SCIP_EXPR_OWNERDATA* ownerdata;
2686  SCIP_Bool cutoff = FALSE;
2687  SCIP_INTERVAL conssides;
2688  int ntightenings;
2689  int roundnr;
2690  SCIP_EXPRITER* revpropcollectit = NULL;
2691  int i;
2692 
2693  assert(scip != NULL);
2694  assert(conshdlr != NULL);
2695  assert(conss != NULL);
2696  assert(nconss >= 0);
2697  assert(result != NULL);
2698  assert(nchgbds != NULL);
2699  assert(*nchgbds >= 0);
2700 
2701  /* no constraints to propagate */
2702  if( nconss == 0 )
2703  {
2704  *result = SCIP_DIDNOTRUN;
2705  return SCIP_OKAY;
2706  }
2707 
2708  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2709  assert(conshdlrdata != NULL);
2710 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2711  assert(conshdlrdata->intevalvar == intEvalVarBoundTightening);
2712 #endif
2713  assert(!conshdlrdata->globalbounds);
2714 
2715  *result = SCIP_DIDNOTFIND;
2716  roundnr = 0;
2717 
2718  /* tightenAuxVarBounds() needs to know whether boundtightenings are to be forced */
2719  conshdlrdata->forceboundtightening = force;
2720 
2721  /* invalidate all propbounds (probably not needed) */
2722  ++conshdlrdata->curpropboundstag;
2723 
2724  /* create iterator that we will use if we need to look at all auxvars */
2725  if( conshdlrdata->propauxvars )
2726  {
2727  SCIP_CALL( SCIPcreateExpriter(scip, &revpropcollectit) );
2728  }
2729 
2730  /* main propagation loop */
2731  do
2732  {
2733  SCIPdebugMsg(scip, "start propagation round %d\n", roundnr);
2734 
2735  assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2736 
2737  /* apply forward propagation (update expression activities)
2738  * and add promising root expressions into queue for reversepropagation
2739  */
2740  for( i = 0; i < nconss; ++i )
2741  {
2742  consdata = SCIPconsGetData(conss[i]);
2743  assert(consdata != NULL);
2744 
2745  /* skip deleted, non-active, or propagation-disabled constraints */
2746  if( SCIPconsIsDeleted(conss[i]) || !SCIPconsIsActive(conss[i]) || !SCIPconsIsPropagationEnabled(conss[i]) )
2747  continue;
2748 
2749  /* skip already propagated constraints, i.e., constraints where no (original) variable has changed and thus
2750  * activity didn't change
2751  */
2752  if( consdata->ispropagated )
2753  continue;
2754 
2755  /* update activities in expression */
2756  SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s> (round %d): ", SCIPconsGetName(conss[i]), roundnr);
2757  SCIPdebugPrintCons(scip, conss[i], NULL);
2758 
2759  ntightenings = 0;
2760  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, TRUE, &cutoff, &ntightenings) );
2761  assert(cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
2762 
2763  if( cutoff )
2764  {
2765  SCIPdebugMsg(scip, " -> cutoff in forwardPropExpr (due to domain error or auxvar tightening) of constraint <%s>\n", SCIPconsGetName(conss[i]));
2766  *result = SCIP_CUTOFF;
2767  break;
2768  }
2769 
2770  ownerdata = SCIPexprGetOwnerData(consdata->expr);
2771 
2772  /* 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 */
2773  if( !conshdlrdata->propauxvars || ownerdata->auxvar == NULL )
2774  {
2775  /* check whether constraint sides (relaxed by epsilon) or auxvar bounds provide a tightening
2776  * (if we have auxvar (not in presolve), then bounds of the auxvar are initially set to constraint sides,
2777  * so taking auxvar bounds is enough)
2778  */
2779  if( ownerdata->auxvar == NULL )
2780  {
2781  /* relax sides by SCIPepsilon() and handle infinite sides */
2782  SCIP_Real lhs = SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - conshdlrdata->conssiderelaxamount;
2783  SCIP_Real rhs = SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + conshdlrdata->conssiderelaxamount;
2784  SCIPintervalSetBounds(&conssides, lhs, rhs);
2785  }
2786  else
2787  {
2788  conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2789  }
2790  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, consdata->expr, conssides, &cutoff, &ntightenings) );
2791  }
2792  else
2793  {
2794  /* check whether bounds of any auxvar used in constraint provides a tightening
2795  * (for the root expression, bounds of auxvar are initially set to constraint sides)
2796  * but skip exprs that have an auxvar, but do not participate in propagation
2797  */
2798  SCIP_EXPR* expr;
2799 
2800  assert(revpropcollectit != NULL);
2801  SCIP_CALL( SCIPexpriterInit(revpropcollectit, consdata->expr, SCIP_EXPRITER_BFS, FALSE) );
2802  for( expr = SCIPexpriterGetCurrent(revpropcollectit); !SCIPexpriterIsEnd(revpropcollectit) && !cutoff; expr = SCIPexpriterGetNext(revpropcollectit) )
2803  {
2804  ownerdata = SCIPexprGetOwnerData(expr);
2805  assert(ownerdata != NULL);
2806 
2807  if( ownerdata->auxvar == NULL )
2808  continue;
2809 
2810  if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
2811  continue;
2812 
2813  conssides = intEvalVarBoundTightening(scip, ownerdata->auxvar, (void*)conshdlrdata);
2814  SCIP_CALL( SCIPtightenExprIntervalNonlinear(scip, expr, conssides, &cutoff, &ntightenings) );
2815  }
2816  }
2817 
2818  if( cutoff )
2819  {
2820  SCIPdebugMsg(scip, " -> cutoff after intersect with conssides of constraint <%s>\n", SCIPconsGetName(conss[i]));
2821  *result = SCIP_CUTOFF;
2822  break;
2823  }
2824 
2825  assert(ntightenings >= 0);
2826  if( ntightenings > 0 )
2827  {
2828  *nchgbds += ntightenings;
2829  *result = SCIP_REDUCEDDOM;
2830  }
2831 
2832  /* mark constraint as propagated; this will be reset via the event system when we find a variable tightening */
2833  consdata->ispropagated = TRUE;
2834  }
2835 
2836  /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2837  SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2838  assert(ntightenings >= 0);
2839  assert(SCIPqueueIsEmpty(conshdlrdata->reversepropqueue));
2840 
2841  if( cutoff )
2842  {
2843  SCIPdebugMsg(scip, " -> cutoff\n");
2844  *result = SCIP_CUTOFF;
2845  break;
2846  }
2847 
2848  if( ntightenings > 0 )
2849  {
2850  *nchgbds += ntightenings;
2851  *result = SCIP_REDUCEDDOM;
2852  }
2853  }
2854  while( ntightenings > 0 && ++roundnr < conshdlrdata->maxproprounds );
2855 
2856  if( conshdlrdata->propauxvars )
2857  {
2858  SCIPfreeExpriter(&revpropcollectit);
2859  }
2860 
2861  conshdlrdata->forceboundtightening = FALSE;
2862 
2863  /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2864  ++conshdlrdata->curpropboundstag;
2865 
2866  return SCIP_OKAY;
2867 }
2868 
2869 /** calls the reverseprop callbacks of all nlhdlrs in all expressions in all constraints using activity as bounds
2870  *
2871  * This is meant to propagate any domain restrictions on functions onto variable bounds, if possible.
2872  *
2873  * Assumes that activities are still valid and curpropboundstag does not need to be increased.
2874  * Therefore, a good place to call this function is immediately after propConss() or after forwardPropExpr() if outside propagation.
2875  */
2876 static
2878  SCIP* scip, /**< SCIP data structure */
2879  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2880  SCIP_CONS** conss, /**< constraints to propagate */
2881  int nconss, /**< total number of constraints */
2882  SCIP_RESULT* result, /**< pointer to store the result */
2883  int* nchgbds /**< buffer to add the number of changed bounds */
2884  )
2885 {
2886  SCIP_CONSDATA* consdata;
2887  SCIP_EXPRITER* it;
2888  SCIP_EXPR* expr;
2889  SCIP_EXPR_OWNERDATA* ownerdata;
2890  SCIP_Bool cutoff = FALSE;
2891  int ntightenings;
2892  int c;
2893  int e;
2894 
2895  assert(scip != NULL);
2896  assert(conshdlr != NULL);
2897  assert(conss != NULL);
2898  assert(nconss >= 0);
2899  assert(result != NULL);
2900  assert(nchgbds != NULL);
2901  assert(*nchgbds >= 0);
2902 
2903 #ifndef CR_API /* this assert may not work in unittests due to having this code compiled twice, #3543 */
2904  assert(SCIPconshdlrGetData(conshdlr)->intevalvar == intEvalVarBoundTightening);
2905 #endif
2906  assert(!SCIPconshdlrGetData(conshdlr)->globalbounds);
2907  assert(SCIPqueueIsEmpty(SCIPconshdlrGetData(conshdlr)->reversepropqueue));
2908 
2909  *result = SCIP_DIDNOTFIND;
2910 
2911  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
2913 
2914  for( c = 0; c < nconss && !cutoff; ++c )
2915  {
2916  /* skip deleted, non-active, or propagation-disabled constraints */
2917  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) || !SCIPconsIsPropagationEnabled(conss[c]) )
2918  continue;
2919 
2920  consdata = SCIPconsGetData(conss[c]);
2921  assert(consdata != NULL);
2922 
2923  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !cutoff; expr = SCIPexpriterGetNext(it) )
2924  {
2925  ownerdata = SCIPexprGetOwnerData(expr);
2926  assert(ownerdata != NULL);
2927 
2928  /* call reverseprop for those nlhdlr that participate in this expr's activity computation
2929  * this will propagate the current activity
2930  */
2931  for( e = 0; e < ownerdata->nenfos; ++e )
2932  {
2933  SCIP_NLHDLR* nlhdlr;
2934  assert(ownerdata->enfos[e] != NULL);
2935 
2936  nlhdlr = ownerdata->enfos[e]->nlhdlr;
2937  assert(nlhdlr != NULL);
2938  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_ACTIVITY) == 0 )
2939  continue;
2940 
2941  SCIPdebugMsg(scip, "propExprDomains calling reverseprop for expression %p [%g,%g]\n", (void*)expr,
2942  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup);
2943  ntightenings = 0;
2944  SCIP_CALL( SCIPnlhdlrReverseprop(scip, conshdlr, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata,
2945  SCIPexprGetActivity(expr), &cutoff, &ntightenings) );
2946 
2947  if( cutoff )
2948  {
2949  /* stop everything if we detected infeasibility */
2950  SCIPdebugMsg(scip, "detect infeasibility for constraint <%s> during reverseprop()\n", SCIPconsGetName(conss[c]));
2951  *result = SCIP_CUTOFF;
2952  break;
2953  }
2954 
2955  assert(ntightenings >= 0);
2956  if( ntightenings > 0 )
2957  {
2958  *nchgbds += ntightenings;
2959  *result = SCIP_REDUCEDDOM;
2960  }
2961  }
2962  }
2963  }
2964 
2965  /* apply backward propagation (if cutoff is TRUE, then this call empties the queue) */
2966  SCIP_CALL( reversePropQueue(scip, conshdlr, &cutoff, &ntightenings) );
2967  assert(ntightenings >= 0);
2968 
2969  if( cutoff )
2970  {
2971  SCIPdebugMsg(scip, " -> cutoff\n");
2972  *result = SCIP_CUTOFF;
2973  }
2974  else if( ntightenings > 0 )
2975  {
2976  *nchgbds += ntightenings;
2977  *result = SCIP_REDUCEDDOM;
2978  }
2979 
2980  SCIPfreeExpriter(&it);
2981 
2982  /* invalidate propbounds in all exprs, so noone accidentally uses them outside propagation */
2983  ++SCIPconshdlrGetData(conshdlr)->curpropboundstag;
2984 
2985  return SCIP_OKAY;
2986 }
2987 
2988 /** propagates variable locks through expression and adds locks to variables */
2989 static
2991  SCIP* scip, /**< SCIP data structure */
2992  SCIP_EXPR* expr, /**< expression */
2993  int nlockspos, /**< number of positive locks */
2994  int nlocksneg /**< number of negative locks */
2995  )
2996 {
2997  SCIP_EXPR_OWNERDATA* ownerdata;
2998  SCIP_EXPRITER* it;
2999  SCIP_EXPRITER_USERDATA ituserdata;
3000 
3001  assert(expr != NULL);
3002 
3003  /* if no locks, then nothing to propagate */
3004  if( nlockspos == 0 && nlocksneg == 0 )
3005  return SCIP_OKAY;
3006 
3007  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3010  assert(SCIPexpriterGetCurrent(it) == expr); /* iterator should not have moved */
3011 
3012  /* store locks in root node */
3013  ituserdata.intvals[0] = nlockspos;
3014  ituserdata.intvals[1] = nlocksneg;
3015  SCIPexpriterSetCurrentUserData(it, ituserdata);
3016 
3017  while( !SCIPexpriterIsEnd(it) )
3018  {
3019  /* collect locks */
3020  ituserdata = SCIPexpriterGetCurrentUserData(it);
3021  nlockspos = ituserdata.intvals[0];
3022  nlocksneg = ituserdata.intvals[1];
3023 
3024  ownerdata = SCIPexprGetOwnerData(expr);
3025 
3026  switch( SCIPexpriterGetStageDFS(it) )
3027  {
3029  {
3030  if( SCIPisExprVar(scip, expr) )
3031  {
3032  /* if a variable, then also add nlocksneg/nlockspos via SCIPaddVarLocks() */
3033  SCIP_CALL( SCIPaddVarLocks(scip, SCIPgetVarExprVar(expr), nlocksneg, nlockspos) );
3034  }
3035 
3036  /* add locks to expression */
3037  ownerdata->nlockspos += nlockspos;
3038  ownerdata->nlocksneg += nlocksneg;
3039 
3040  /* add monotonicity information if expression has been locked for the first time */
3041  if( ownerdata->nlockspos == nlockspos && ownerdata->nlocksneg == nlocksneg && SCIPexprGetNChildren(expr) > 0
3043  {
3044  int i;
3045 
3046  assert(ownerdata->monotonicity == NULL);
3047  assert(ownerdata->monotonicitysize == 0);
3048 
3049  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->monotonicity, SCIPexprGetNChildren(expr)) );
3050  ownerdata->monotonicitysize = SCIPexprGetNChildren(expr);
3051 
3052  /* store the monotonicity for each child */
3053  for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3054  {
3055  SCIP_CALL( SCIPcallExprMonotonicity(scip, expr, i, &ownerdata->monotonicity[i]) );
3056  }
3057  }
3058  break;
3059  }
3060 
3062  {
3063  /* remove monotonicity information if expression has been unlocked */
3064  if( ownerdata->nlockspos == 0 && ownerdata->nlocksneg == 0 && ownerdata->monotonicity != NULL )
3065  {
3066  assert(ownerdata->monotonicitysize > 0);
3067  /* keep this assert for checking whether someone changed an expression without updating locks properly */
3068  assert(ownerdata->monotonicitysize == SCIPexprGetNChildren(expr));
3069 
3070  SCIPfreeBlockMemoryArray(scip, &ownerdata->monotonicity, ownerdata->monotonicitysize);
3071  ownerdata->monotonicitysize = 0;
3072  }
3073  break;
3074  }
3075 
3077  {
3078  SCIP_MONOTONE monotonicity;
3079 
3080  /* get monotonicity of child */
3081  /* NOTE: the monotonicity stored in an expression might be different from the result obtained by
3082  * SCIPcallExprMonotonicity
3083  */
3084  monotonicity = ownerdata->monotonicity != NULL ? ownerdata->monotonicity[SCIPexpriterGetChildIdxDFS(it)] : SCIP_MONOTONE_UNKNOWN;
3085 
3086  /* compute resulting locks of the child expression */
3087  switch( monotonicity )
3088  {
3089  case SCIP_MONOTONE_INC:
3090  ituserdata.intvals[0] = nlockspos;
3091  ituserdata.intvals[1] = nlocksneg;
3092  break;
3093  case SCIP_MONOTONE_DEC:
3094  ituserdata.intvals[0] = nlocksneg;
3095  ituserdata.intvals[1] = nlockspos;
3096  break;
3097  case SCIP_MONOTONE_UNKNOWN:
3098  ituserdata.intvals[0] = nlockspos + nlocksneg;
3099  ituserdata.intvals[1] = nlockspos + nlocksneg;
3100  break;
3101  case SCIP_MONOTONE_CONST:
3102  ituserdata.intvals[0] = 0;
3103  ituserdata.intvals[1] = 0;
3104  break;
3105  }
3106  /* set locks in child expression */
3107  SCIPexpriterSetChildUserData(it, ituserdata);
3108 
3109  break;
3110  }
3111 
3112  default :
3113  /* you should never be here */
3114  SCIPABORT();
3115  break;
3116  }
3117 
3118  expr = SCIPexpriterGetNext(it);
3119  }
3120 
3121  SCIPfreeExpriter(&it);
3122 
3123  return SCIP_OKAY;
3124 }
3125 
3126 /** main function for adding locks to expressions and variables
3127  *
3128  * Locks for a nonlinear constraint are used to update locks for all sub-expressions and variables.
3129  * Locks of expressions depend on the monotonicity of expressions w.r.t. their children, e.g.,
3130  * consider the constraint \f$x^2 \leq 1\f$ with \f$x \in [-2,-1]\f$ implies an up-lock for the root
3131  * expression (pow) and a down-lock for its child \f$x\f$ because \f$x^2\f$ is decreasing on [-2,-1].
3132  * Since the monotonicity (and thus the locks) might also depend on variable bounds, the function remembers
3133  * the computed monotonicity information of each expression until all locks of an expression have been removed,
3134  * which implies that updating the monotonicity information during the next locking of this expression does not
3135  * break existing locks.
3136  *
3137  * @note When modifying the structure of an expression, e.g., during simplification, it is necessary to remove all
3138  * locks from an expression and repropagating them after the structural changes have been applied.
3139  * Because of existing common sub-expressions, it might be necessary to remove the locks of all constraints
3140  * to ensure that an expression is unlocked (see canonicalizeConstraints() for an example)
3141  */
3142 static
3144  SCIP* scip, /**< SCIP data structure */
3145  SCIP_CONS* cons, /**< nonlinear constraint */
3146  int nlockspos, /**< number of positive rounding locks */
3147  int nlocksneg /**< number of negative rounding locks */
3148  )
3149 {
3150  SCIP_CONSDATA* consdata;
3151 
3152  assert(cons != NULL);
3153 
3154  if( nlockspos == 0 && nlocksneg == 0 )
3155  return SCIP_OKAY;
3156 
3157  consdata = SCIPconsGetData(cons);
3158  assert(consdata != NULL);
3159 
3160  /* no constraint sides -> nothing to lock */
3161  if( SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, -consdata->lhs) )
3162  return SCIP_OKAY;
3163 
3164  /* remember locks */
3165  consdata->nlockspos += nlockspos;
3166  consdata->nlocksneg += nlocksneg;
3167 
3168  assert(consdata->nlockspos >= 0);
3169  assert(consdata->nlocksneg >= 0);
3170 
3171  /* compute locks for lock propagation */
3172  if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
3173  {
3174  SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos + nlocksneg, nlockspos + nlocksneg));
3175  }
3176  else if( !SCIPisInfinity(scip, consdata->rhs) )
3177  {
3178  SCIP_CALL( propagateLocks(scip, consdata->expr, nlockspos, nlocksneg));
3179  }
3180  else
3181  {
3182  assert(!SCIPisInfinity(scip, -consdata->lhs));
3183  SCIP_CALL( propagateLocks(scip, consdata->expr, nlocksneg, nlockspos));
3184  }
3185 
3186  return SCIP_OKAY;
3187 }
3188 
3189 /** create a nonlinear row representation of a nonlinear constraint and stores them in consdata */
3190 static
3192  SCIP* scip, /**< SCIP data structure */
3193  SCIP_CONS* cons /**< nonlinear constraint */
3194  )
3195 {
3196  SCIP_CONSDATA* consdata;
3197 
3198  assert(scip != NULL);
3199  assert(cons != NULL);
3200 
3201  consdata = SCIPconsGetData(cons);
3202  assert(consdata != NULL);
3203  assert(consdata->expr != NULL);
3204 
3205  if( consdata->nlrow != NULL )
3206  {
3207  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3208  }
3209 
3210  /* better curvature info will be set in initSolve() just before nlrow is added to NLP */
3211  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
3212  0, NULL, NULL, NULL, consdata->lhs, consdata->rhs, SCIP_EXPRCURV_UNKNOWN) );
3213 
3214  if( SCIPisExprSum(scip, consdata->expr) )
3215  {
3216  /* if root is a sum, then split into linear and nonlinear terms */
3217  SCIP_EXPR* nonlinpart;
3218  SCIP_EXPR* child;
3219  SCIP_Real* coefs;
3220  int i;
3221 
3222  coefs = SCIPgetCoefsExprSum(consdata->expr);
3223 
3224  /* constant term of sum */
3225  SCIP_CALL( SCIPchgNlRowConstant(scip, consdata->nlrow, SCIPgetConstantExprSum(consdata->expr)) );
3226 
3227  /* a sum-expression that will hold the nonlinear terms and be passed to the nlrow eventually */
3228  SCIP_CALL( SCIPcreateExprSum(scip, &nonlinpart, 0, NULL, NULL, 0.0, exprownerCreate, (void*)SCIPconsGetHdlr(cons)) );
3229 
3230  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
3231  {
3232  child = SCIPexprGetChildren(consdata->expr)[i];
3233  if( SCIPisExprVar(scip, child) )
3234  {
3235  /* linear term */
3236  SCIP_CALL( SCIPaddLinearCoefToNlRow(scip, consdata->nlrow, SCIPgetVarExprVar(child), coefs[i]) );
3237  }
3238  else
3239  {
3240  /* nonlinear term */
3241  SCIP_CALL( SCIPappendExprSumExpr(scip, nonlinpart, child, coefs[i]) );
3242  }
3243  }
3244 
3245  if( SCIPexprGetNChildren(nonlinpart) > 0 )
3246  {
3247  /* add expression to nlrow (this will make a copy) */
3248  SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, nonlinpart) );
3249  }
3250  SCIP_CALL( SCIPreleaseExpr(scip, &nonlinpart) );
3251  }
3252  else
3253  {
3254  SCIP_CALL( SCIPsetNlRowExpr(scip, consdata->nlrow, consdata->expr) );
3255  }
3256 
3257  return SCIP_OKAY;
3258 }
3259 
3260 /** compares enfodata by enforcement priority of nonlinear handler
3261  *
3262  * If handlers have same enforcement priority, then compare by detection priority, then by name.
3263  */
3264 static
3265 SCIP_DECL_SORTPTRCOMP(enfodataCmp)
3267  SCIP_NLHDLR* h1;
3268  SCIP_NLHDLR* h2;
3269 
3270  assert(elem1 != NULL);
3271  assert(elem2 != NULL);
3272 
3273  h1 = ((EXPRENFO*)elem1)->nlhdlr;
3274  h2 = ((EXPRENFO*)elem2)->nlhdlr;
3275 
3276  assert(h1 != NULL);
3277  assert(h2 != NULL);
3278 
3281 
3284 
3285  return strcmp(SCIPnlhdlrGetName(h1), SCIPnlhdlrGetName(h2));
3286 }
3287 
3288 /** install nlhdlrs in one expression */
3289 static
3291  SCIP* scip, /**< SCIP data structure */
3292  SCIP_EXPR* expr, /**< expression for which to run detection routines */
3293  SCIP_CONS* cons /**< constraint for which expr == consdata->expr, otherwise NULL */
3294  )
3295 {
3296  SCIP_EXPR_OWNERDATA* ownerdata;
3297  SCIP_CONSHDLRDATA* conshdlrdata;
3298  SCIP_NLHDLR_METHOD enforcemethodsallowed;
3299  SCIP_NLHDLR_METHOD enforcemethods;
3300  SCIP_NLHDLR_METHOD enforcemethodsnew;
3301  SCIP_NLHDLR_METHOD nlhdlrenforcemethods;
3302  SCIP_NLHDLR_METHOD nlhdlrparticipating;
3303  SCIP_NLHDLREXPRDATA* nlhdlrexprdata;
3304  int enfossize; /* allocated length of expr->enfos array */
3305  int h;
3306 
3307  assert(expr != NULL);
3308 
3309  ownerdata = SCIPexprGetOwnerData(expr);
3310  assert(ownerdata != NULL);
3311 
3312  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
3313  assert(conshdlrdata != NULL);
3314  assert(conshdlrdata->auxvarid >= 0);
3315  assert(!conshdlrdata->indetect);
3316 
3317  /* there should be no enforcer yet and detection should not even have considered expr yet */
3318  assert(ownerdata->nenfos < 0);
3319  assert(ownerdata->enfos == NULL);
3320 
3321  /* check which enforcement methods are required by setting flags in enforcemethods for those that are NOT required
3322  * - if no auxiliary variable is used, then do not need sepabelow or sepaabove
3323  * - if auxiliary variable is used, but nobody positively (up) locks expr -> only need to enforce expr >= auxvar -> no need for underestimation
3324  * - if auxiliary variable is used, but nobody negatively (down) locks expr -> only need to enforce expr <= auxvar -> no need for overestimation
3325  * - if no one uses activity, then do not need activity methods
3326  */
3327  enforcemethods = SCIP_NLHDLR_METHOD_NONE;
3328  if( ownerdata->nauxvaruses == 0 )
3329  enforcemethods |= SCIP_NLHDLR_METHOD_SEPABOTH;
3330  else
3331  {
3332  if( ownerdata->nlockspos == 0 ) /* no need for underestimation */
3333  enforcemethods |= SCIP_NLHDLR_METHOD_SEPABELOW;
3334  if( ownerdata->nlocksneg == 0 ) /* no need for overestimation */
3335  enforcemethods |= SCIP_NLHDLR_METHOD_SEPAABOVE;
3336  }
3337  if( ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 )
3338  enforcemethods |= SCIP_NLHDLR_METHOD_ACTIVITY;
3339 
3340  /* it doesn't make sense to have been called on detectNlhdlr, if the expr isn't used for anything */
3341  assert(enforcemethods != SCIP_NLHDLR_METHOD_ALL);
3342 
3343  /* all methods that have not been flagged above are the ones that we want to be handled by nlhdlrs */
3344  enforcemethodsallowed = ~enforcemethods & SCIP_NLHDLR_METHOD_ALL;
3345 
3346  ownerdata->nenfos = 0;
3347  enfossize = 2;
3348  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize) );
3349  conshdlrdata->indetect = TRUE;
3350 
3351  SCIPdebugMsg(scip, "detecting nlhdlrs for %s expression %p (%s); requiring%s%s%s\n",
3352  cons != NULL ? "root" : "non-root", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
3353  (enforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 ? "" : " sepabelow",
3354  (enforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 ? "" : " sepaabove",
3355  (enforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0 ? "" : " activity");
3356 
3357  for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
3358  {
3359  SCIP_NLHDLR* nlhdlr;
3360 
3361  nlhdlr = conshdlrdata->nlhdlrs[h];
3362  assert(nlhdlr != NULL);
3363 
3364  /* skip disabled nlhdlrs */
3365  if( !SCIPnlhdlrIsEnabled(nlhdlr) )
3366  continue;
3367 
3368  /* call detect routine of nlhdlr */
3369  nlhdlrexprdata = NULL;
3370  enforcemethodsnew = enforcemethods;
3371  nlhdlrparticipating = SCIP_NLHDLR_METHOD_NONE;
3372  conshdlrdata->registerusesactivitysepabelow = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3373  conshdlrdata->registerusesactivitysepaabove = FALSE; /* SCIPregisterExprUsageNonlinear() as called by detect may set this to TRUE */
3374  /* coverity[var_deref_model] */
3375  SCIP_CALL( SCIPnlhdlrDetect(scip, ownerdata->conshdlr, nlhdlr, expr, cons, &enforcemethodsnew, &nlhdlrparticipating, &nlhdlrexprdata) );
3376 
3377  /* nlhdlr might have claimed more than needed: clean up sepa flags */
3378  nlhdlrparticipating &= enforcemethodsallowed;
3379 
3380  /* detection is only allowed to augment to nlhdlrenforcemethods, so previous enforcemethods must still be set */
3381  assert((enforcemethodsnew & enforcemethods) == enforcemethods);
3382 
3383  /* Because of the previous assert, nlhdlrenforcenew ^ enforcemethods are the methods enforced by this nlhdlr.
3384  * They are also cleaned up here to ensure that only the needed methods are claimed.
3385  */
3386  nlhdlrenforcemethods = (enforcemethodsnew ^ enforcemethods) & enforcemethodsallowed;
3387 
3388  /* nlhdlr needs to participate for the methods it is enforcing */
3389  assert((nlhdlrparticipating & nlhdlrenforcemethods) == nlhdlrenforcemethods);
3390 
3391  if( nlhdlrparticipating == SCIP_NLHDLR_METHOD_NONE )
3392  {
3393  /* nlhdlr might not have detected anything, or all set flags might have been removed by
3394  * clean up; in the latter case, we may need to free nlhdlrexprdata */
3395 
3396  /* free nlhdlr exprdata, if there is any and there is a method to free this data */
3397  if( nlhdlrexprdata != NULL )
3398  {
3399  SCIP_CALL( SCIPnlhdlrFreeexprdata(scip, nlhdlr, expr, &nlhdlrexprdata) );
3400  }
3401  /* nlhdlr cannot have added an enforcement method if it doesn't participate (actually redundant due to previous asserts) */
3402  assert(nlhdlrenforcemethods == SCIP_NLHDLR_METHOD_NONE);
3403 
3404  SCIPdebugMsg(scip, "nlhdlr <%s> detect unsuccessful\n", SCIPnlhdlrGetName(nlhdlr));
3405 
3406  continue;
3407  }
3408 
3409  SCIPdebugMsg(scip, "nlhdlr <%s> detect successful; sepabelow: %s, sepaabove: %s, activity: %s\n",
3410  SCIPnlhdlrGetName(nlhdlr),
3411  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPABELOW) != 0) ? "participating" : "no",
3412  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0) ? "participating" : "no",
3413  ((nlhdlrenforcemethods & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "enforcing" : ((nlhdlrparticipating & SCIP_NLHDLR_METHOD_ACTIVITY) != 0) ? "participating" : "no");
3414 
3415  /* store nlhdlr and its data */
3416  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &ownerdata->enfos, &enfossize, ownerdata->nenfos+1) );
3417  SCIP_CALL( SCIPallocBlockMemory(scip, &ownerdata->enfos[ownerdata->nenfos]) );
3418  ownerdata->enfos[ownerdata->nenfos]->nlhdlr = nlhdlr;
3419  ownerdata->enfos[ownerdata->nenfos]->nlhdlrexprdata = nlhdlrexprdata;
3420  ownerdata->enfos[ownerdata->nenfos]->nlhdlrparticipation = nlhdlrparticipating;
3421  ownerdata->enfos[ownerdata->nenfos]->issepainit = FALSE;
3422  ownerdata->enfos[ownerdata->nenfos]->sepabelowusesactivity = conshdlrdata->registerusesactivitysepabelow;
3423  ownerdata->enfos[ownerdata->nenfos]->sepaaboveusesactivity = conshdlrdata->registerusesactivitysepaabove;
3424  ownerdata->nenfos++;
3425 
3426  /* update enforcement flags */
3427  enforcemethods = enforcemethodsnew;
3428  }
3429 
3430  conshdlrdata->indetect = FALSE;
3431 
3432  /* stop if an enforcement method is missing but we are already in solving stage
3433  * (as long as the expression provides its callbacks, the default nlhdlr should have provided all enforcement methods)
3434  */
3435  if( enforcemethods != SCIP_NLHDLR_METHOD_ALL && SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3436  {
3437  SCIPerrorMessage("no nonlinear handler provided some of the required enforcement methods\n");
3438  return SCIP_ERROR;
3439  }
3440 
3441  assert(ownerdata->nenfos > 0);
3442 
3443  /* sort nonlinear handlers by enforcement priority, in decreasing order */
3444  if( ownerdata->nenfos > 1 )
3445  SCIPsortDownPtr((void**)ownerdata->enfos, enfodataCmp, ownerdata->nenfos);
3446 
3447  /* resize enfos array to be nenfos long */
3448  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &ownerdata->enfos, enfossize, ownerdata->nenfos) );
3449 
3450  return SCIP_OKAY;
3451 }
3452 
3453 /** detect nlhdlrs that can handle the expressions */
3454 static
3456  SCIP* scip, /**< SCIP data structure */
3457  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3458  SCIP_CONS** conss, /**< constraints for which to run nlhdlr detect */
3459  int nconss /**< total number of constraints */
3460  )
3461 {
3462  SCIP_CONSHDLRDATA* conshdlrdata;
3463  SCIP_CONSDATA* consdata;
3464  SCIP_EXPR* expr;
3465  SCIP_EXPR_OWNERDATA* ownerdata;
3466  SCIP_EXPRITER* it;
3467  int i;
3468 
3469  assert(conss != NULL || nconss == 0);
3470  assert(nconss >= 0);
3471  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 */
3472 
3473  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3474  assert(conshdlrdata != NULL);
3475 
3476  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3478 
3479  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3480  {
3481  /* ensure that activities are recomputed w.r.t. the global variable bounds if CONSACTIVE is called in a local node;
3482  * for example, this happens if globally valid nonlinear constraints are added during the tree search
3483  */
3485  conshdlrdata->globalbounds = TRUE;
3486  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3487  }
3488 
3489  for( i = 0; i < nconss; ++i )
3490  {
3491  assert(conss != NULL && conss[i] != NULL);
3492 
3493  consdata = SCIPconsGetData(conss[i]);
3494  assert(consdata != NULL);
3495  assert(consdata->expr != NULL);
3496 
3497  /* if a constraint is separated, we currently need it to be initial, too
3498  * this is because INITLP will create the auxiliary variables that are used for any separation
3499  * TODO we may relax this with a little more programming effort when required, see also TODO in INITLP
3500  */
3501  assert((!SCIPconsIsSeparated(conss[i]) && !SCIPconsIsEnforced(conss[i])) || SCIPconsIsInitial(conss[i]));
3502 
3503  ownerdata = SCIPexprGetOwnerData(consdata->expr);
3504  assert(ownerdata != NULL);
3505 
3506  /* because of common sub-expressions it might happen that we already detected a nonlinear handler and added it to the expr
3507  * then we would normally skip to run DETECT again
3508  * HOWEVER: most likely we have been running DETECT with cons == NULL, which may interest less nlhdlrs
3509  * thus, if expr is the root expression, we rerun DETECT
3510  */
3511  if( ownerdata->nenfos > 0 )
3512  {
3513  SCIP_CALL( freeEnfoData(scip, consdata->expr, FALSE) );
3514  assert(ownerdata->nenfos < 0);
3515  }
3516 
3517  /* if constraint will be enforced, and we are in solve, then ensure auxiliary variable for root expression
3518  * this way we can treat the root expression like any other expression when enforcing via separation
3519  * if constraint will be propagated, then register activity usage of root expression
3520  * this can trigger a call to forwardPropExpr, for which we better have the indetect flag set
3521  */
3522  conshdlrdata->indetect = TRUE;
3523  SCIP_CALL( SCIPregisterExprUsageNonlinear(scip, consdata->expr,
3524  SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && (SCIPconsIsSeparated(conss[i]) || SCIPconsIsEnforced(conss[i])),
3525  SCIPconsIsPropagated(conss[i]),
3526  FALSE, FALSE) );
3527  conshdlrdata->indetect = FALSE;
3528 
3529  /* compute integrality information for all subexpressions */
3530  SCIP_CALL( SCIPcomputeExprIntegrality(scip, consdata->expr) );
3531 
3532  /* run detectNlhdlr on all expr where required */
3533  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3534  {
3535  ownerdata = SCIPexprGetOwnerData(expr);
3536  assert(ownerdata != NULL);
3537 
3538  /* skip exprs that we already looked at */
3539  if( ownerdata->nenfos >= 0 )
3540  continue;
3541 
3542  /* if there is use of the auxvar, then someone requires that
3543  * auxvar == expr (or auxvar >= expr or auxvar <= expr) or we are at the root expression (expr==consdata->expr)
3544  * thus, we need to find nlhdlrs that separate or estimate
3545  * if there is use of the activity, then there is someone requiring that
3546  * activity of this expression is updated; this someone would also benefit from better bounds on the activity of this expression
3547  * thus, we need to find nlhdlrs that do interval-evaluation
3548  */
3549  if( ownerdata->nauxvaruses > 0 || ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 )
3550  {
3551  SCIP_CALL( detectNlhdlr(scip, expr, expr == consdata->expr ? conss[i] : NULL) );
3552 
3553  assert(ownerdata->nenfos >= 0);
3554  }
3555  else
3556  {
3557  /* remember that we looked at this expression during detectNlhdlrs
3558  * even though we have not actually run detectNlhdlr, because no nlhdlr showed interest in this expr,
3559  * in some situations (forwardPropExpr, to be specific) we will have to distinguish between exprs for which
3560  * we have not initialized enforcement yet (nenfos < 0) and expressions which are just not used in enforcement (nenfos == 0)
3561  */
3562  ownerdata->nenfos = 0;
3563  }
3564  }
3565 
3566  /* include this constraint into the next propagation round because the added nlhdlr may do find tighter bounds now */
3567  if( SCIPconsIsPropagated(conss[i]) )
3568  consdata->ispropagated = FALSE;
3569  }
3570 
3571  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPgetDepth(scip) != 0 )
3572  {
3573  /* ensure that the local bounds are used again when reevaluating the expressions later;
3574  * this is only needed if CONSACTIVE is called in a local node (see begin of this function)
3575  */
3577  conshdlrdata->globalbounds = FALSE;
3578  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
3579  }
3580  else
3581  {
3582  /* ensure that all activities (except for var-exprs) are reevaluated since better methods may be available now */
3584  }
3585 
3586  SCIPfreeExpriter(&it);
3587 
3588  return SCIP_OKAY;
3589 }
3590 
3591 /** initializes (pre)solving data of constraints
3592  *
3593  * This initializes data in a constraint that is used for separation, propagation, etc, and assumes that expressions will
3594  * not be modified.
3595  * In particular, this function
3596  * - runs the detection method of nlhldrs
3597  * - looks for unlocked linear variables
3598  * - checks curvature (if not in presolve)
3599  * - creates and add row to NLP (if not in presolve)
3600  *
3601  * This function can be called in presolve and solve and can be called several times with different sets of constraints,
3602  * e.g., it should be called in INITSOL and for constraints that are added during solve.
3603  */
3604 static
3606  SCIP* scip, /**< SCIP data structure */
3607  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3608  SCIP_CONS** conss, /**< constraints */
3609  int nconss /**< number of constraints */
3610  )
3611 {
3612  int c;
3613 
3614  for( c = 0; c < nconss; ++c )
3615  {
3616  /* check for a linear variable that can be increase or decreased without harming feasibility */
3617  findUnlockedLinearVar(scip, conss[c]);
3618 
3620  {
3621  SCIP_CONSDATA* consdata;
3622  SCIP_Bool success = FALSE;
3623 
3624  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3625  assert(consdata != NULL);
3626  assert(consdata->expr != NULL);
3627 
3628  if( !SCIPconshdlrGetData(conshdlr)->assumeconvex )
3629  {
3630  /* call the curvature detection algorithm of the convex nonlinear handler
3631  * Check only for those curvature that may result in a convex inequality, i.e.,
3632  * whether f(x) is concave when f(x) >= lhs and/or f(x) is convex when f(x) <= rhs.
3633  * Also we can assume that we are nonlinear, so do not check for convex if already concave.
3634  */
3635  if( !SCIPisInfinity(scip, -consdata->lhs) )
3636  {
3637  SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONCAVE, &success, NULL) );
3638  if( success )
3639  consdata->curv = SCIP_EXPRCURV_CONCAVE;
3640  }
3641  if( !success && !SCIPisInfinity(scip, consdata->rhs) )
3642  {
3643  SCIP_CALL( SCIPhasExprCurvature(scip, consdata->expr, SCIP_EXPRCURV_CONVEX, &success, NULL) );
3644  if( success )
3645  consdata->curv = SCIP_EXPRCURV_CONVEX;
3646  }
3647  }
3648  else
3649  {
3650  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
3651  {
3652  SCIPwarningMessage(scip, "Nonlinear constraint <%s> has finite left- and right-hand side, but constraints/nonlinear/assumeconvex is enabled.\n", SCIPconsGetName(conss[c]));
3653  consdata->curv = SCIP_EXPRCURV_LINEAR;
3654  }
3655  else
3656  {
3657  consdata->curv = !SCIPisInfinity(scip, consdata->rhs) ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
3658  }
3659  }
3660  SCIPdebugMsg(scip, "root curvature of constraint %s = %d\n", SCIPconsGetName(conss[c]), consdata->curv);
3661 
3662  /* add nlrow representation to NLP, if NLP had been constructed */
3663  if( SCIPisNLPConstructed(scip) && SCIPconsIsActive(conss[c]) )
3664  {
3665  if( consdata->nlrow == NULL )
3666  {
3667  SCIP_CALL( createNlRow(scip, conss[c]) );
3668  assert(consdata->nlrow != NULL);
3669  }
3670  SCIPsetNlRowCurvature(scip, consdata->nlrow, consdata->curv);
3671  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
3672  }
3673  }
3674  }
3675 
3676  /* register non linear handlers */
3677  SCIP_CALL( detectNlhdlrs(scip, conshdlr, conss, nconss) );
3678 
3679  return SCIP_OKAY;
3680 }
3681 
3682 /** deinitializes (pre)solving data of constraints
3683  *
3684  * This removes the initialization data created in initSolve().
3685  *
3686  * This function can be called in presolve and solve.
3687  *
3688  * TODO At the moment, it should not be called for a constraint if there are other constraints
3689  * that use the same expressions but still require their nlhdlr.
3690  * We should probably only decrement the auxvar and activity usage for the root expr and then
3691  * proceed as in detectNlhdlrs(), i.e., free enfo data only where none is used.
3692  */
3693 static
3695  SCIP* scip, /**< SCIP data structure */
3696  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3697  SCIP_CONS** conss, /**< constraints */
3698  int nconss /**< number of constraints */
3699  )
3700 {
3701  SCIP_EXPRITER* it;
3702  SCIP_EXPR* expr;
3703  SCIP_CONSDATA* consdata;
3704  SCIP_Bool rootactivityvalid;
3705  int c;
3706 
3707  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
3710 
3711  /* call deinitialization callbacks of expression and nonlinear handlers
3712  * free nonlinear handlers information from expressions
3713  * remove auxiliary variables and nactivityuses counts from expressions
3714  */
3715  for( c = 0; c < nconss; ++c )
3716  {
3717  assert(conss != NULL);
3718  assert(conss[c] != NULL);
3719 
3720  consdata = SCIPconsGetData(conss[c]);
3721  assert(consdata != NULL);
3722  assert(consdata->expr != NULL);
3723 
3724  /* check and remember whether activity in root is valid */
3725  rootactivityvalid = SCIPexprGetActivityTag(consdata->expr) >= SCIPconshdlrGetData(conshdlr)->lastboundrelax;
3726 
3727  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
3728  {
3729  SCIPdebugMsg(scip, "exitsepa and free nonlinear handler data for expression %p\n", (void*)expr);
3730 
3731  /* remove nonlinear handlers in expression and their data and auxiliary variables; reset activityusage count */
3732  SCIP_CALL( freeEnfoData(scip, expr, TRUE) );
3733 
3734  /* remove quadratic info */
3735  SCIPfreeExprQuadratic(scip, expr);
3736 
3737  if( rootactivityvalid )
3738  {
3739  /* ensure activity is valid if consdata->expr activity is valid
3740  * this is mainly to ensure that we do not leave invalid activities in parts of the expression tree where activity was not used,
3741  * e.g., an expr's activity was kept up to date by a nlhdlr, but without using some childs activity
3742  * so this childs activity would be invalid, which can generate confusion
3743  */
3744  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
3745  }
3746  }
3747 
3748  if( consdata->nlrow != NULL )
3749  {
3750  /* remove row from NLP, if still in solving
3751  * if we are in exitsolve, the whole NLP will be freed anyway
3752  */
3753  if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING )
3754  {
3755  SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
3756  }
3757 
3758  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
3759  }
3760 
3761  /* forget about linear variables that can be increased or decreased without harming feasibility */
3762  consdata->linvardecr = NULL;
3763  consdata->linvarincr = NULL;
3764 
3765  /* forget about curvature */
3766  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
3767  }
3768 
3769  SCIPfreeExpriter(&it);
3770 
3771  return SCIP_OKAY;
3772 }
3773 
3774 /** helper method to decide whether a given expression is product of at least two binary variables */
3775 static
3777  SCIP* scip, /**< SCIP data structure */
3778  SCIP_EXPR* expr /**< expression */
3779  )
3780 {
3781  int i;
3782 
3783  assert(expr != NULL);
3784 
3785  /* check whether the expression is a product */
3786  if( !SCIPisExprProduct(scip, expr) )
3787  return FALSE;
3788 
3789  /* don't consider products with a coefficient != 1 and products with a single child
3790  * simplification will take care of this expression later
3791  */
3792  if( SCIPexprGetNChildren(expr) <= 1 || SCIPgetCoefExprProduct(expr) != 1.0 )
3793  return FALSE;
3794 
3795  for( i = 0; i < SCIPexprGetNChildren(expr); ++i )
3796  {
3797  SCIP_EXPR* child;
3798  SCIP_VAR* var;
3799  SCIP_Real ub;
3800  SCIP_Real lb;
3801 
3802  child = SCIPexprGetChildren(expr)[i];
3803  assert(child != NULL);
3804 
3805  if( !SCIPisExprVar(scip, child) )
3806  return FALSE;
3807 
3808  var = SCIPgetVarExprVar(child);
3809  lb = SCIPvarGetLbLocal(var);
3810  ub = SCIPvarGetUbLocal(var);
3811 
3812  /* check whether variable is integer and has [0,1] as variable bounds */
3813  if( !SCIPvarIsIntegral(var) || !SCIPisEQ(scip, lb, 0.0) || !SCIPisEQ(scip, ub, 1.0) )
3814  return FALSE;
3815  }
3816 
3817  return TRUE;
3818 }
3819 
3820 /** helper method to collect all bilinear binary product terms */
3821 static
3823  SCIP* scip, /**< SCIP data structure */
3824  SCIP_EXPR* sumexpr, /**< sum expression */
3825  SCIP_VAR** xs, /**< array to collect first variable of each bilinear binary product */
3826  SCIP_VAR** ys, /**< array to collect second variable of each bilinear binary product */
3827  int* childidxs, /**< array to store the index of the child of each stored bilinear binary product */
3828  int* nterms /**< pointer to store the total number of bilinear binary terms */
3829  )
3830 {
3831  int i;
3832 
3833  assert(sumexpr != NULL);
3834  assert(SCIPisExprSum(scip, sumexpr));
3835  assert(xs != NULL);
3836  assert(ys != NULL);
3837  assert(childidxs != NULL);
3838  assert(nterms != NULL);
3839 
3840  *nterms = 0;
3841 
3842  for( i = 0; i < SCIPexprGetNChildren(sumexpr); ++i )
3843  {
3844  SCIP_EXPR* child;
3845 
3846  child = SCIPexprGetChildren(sumexpr)[i];
3847  assert(child != NULL);
3848 
3849  if( SCIPexprGetNChildren(child) == 2 && isBinaryProduct(scip, child) )
3850  {
3853 
3854  assert(x != NULL);
3855  assert(y != NULL);
3856 
3857  if( x != y )
3858  {
3859  xs[*nterms] = x;
3860  ys[*nterms] = y;
3861  childidxs[*nterms] = i;
3862  ++(*nterms);
3863  }
3864  }
3865  }
3866 
3867  return SCIP_OKAY;
3868 }
3869 
3870 /** helper method to reformulate \f$x_i \sum_j c_{ij} x_j\f$ */
3871 static
3873  SCIP* scip, /**< SCIP data structure */
3874  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3875  SCIP_CONS* cons, /**< constraint */
3876  SCIP_VAR* facvar, /**< variable that has been factorized */
3877  SCIP_VAR** vars, /**< variables of sum_j c_ij x_j */
3878  SCIP_Real* coefs, /**< coefficients of sum_j c_ij x_j */
3879  int nvars, /**< total number of variables in sum_j c_ij x_j */
3880  SCIP_EXPR** newexpr, /**< pointer to store the new expression */
3881  int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3882  )
3883 {
3884  SCIP_VAR* auxvar;
3885  SCIP_CONS* newcons;
3886  SCIP_Real minact = 0.0;
3887  SCIP_Real maxact = 0.0;
3888  SCIP_Bool integral = TRUE;
3889  char name [SCIP_MAXSTRLEN];
3890  int i;
3891 
3892  assert(facvar != NULL);
3893  assert(vars != NULL);
3894  assert(nvars > 1);
3895  assert(newexpr != NULL);
3896 
3897  /* compute minimum and maximum activity of sum_j c_ij x_j */
3898  /* 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 */
3899  for( i = 0; i < nvars; ++i )
3900  {
3901  minact += MIN(coefs[i], 0.0);
3902  maxact += MAX(coefs[i], 0.0);
3903  integral = integral && SCIPisIntegral(scip, coefs[i]);
3904  }
3905  assert(minact <= maxact);
3906 
3907  /* create and add auxiliary variable */
3908  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3909  SCIP_CALL( SCIPcreateVarBasic(scip, &auxvar, name, minact, maxact, 0.0, integral ? SCIP_VARTYPE_IMPLINT : SCIP_VARTYPE_CONTINUOUS) );
3910  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3911 
3912  /* create and add z - maxact x <= 0 */
3913  if( !SCIPisZero(scip, maxact) )
3914  {
3915  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3916  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -maxact, -SCIPinfinity(scip), 0.0) );
3917  SCIP_CALL( SCIPaddCons(scip, newcons) );
3918  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3919  if( naddconss != NULL )
3920  ++(*naddconss);
3921  }
3922 
3923  /* create and add 0 <= z - minact x */
3924  if( !SCIPisZero(scip, minact) )
3925  {
3926  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3927  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &newcons, name, auxvar, facvar, -minact, 0.0, SCIPinfinity(scip)) );
3928  SCIP_CALL( SCIPaddCons(scip, newcons) );
3929  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3930  if( naddconss != NULL )
3931  ++(*naddconss);
3932  }
3933 
3934  /* create and add minact <= sum_j c_j x_j - z + minact x_i */
3935  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3936  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, minact, SCIPinfinity(scip)) );
3937  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3938  if( !SCIPisZero(scip, minact) )
3939  {
3940  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, minact) );
3941  }
3942  SCIP_CALL( SCIPaddCons(scip, newcons) );
3943  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3944  if( naddconss != NULL )
3945  ++(*naddconss);
3946 
3947  /* create and add sum_j c_j x_j - z + maxact x_i <= maxact */
3948  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_4", SCIPconsGetName(cons), SCIPvarGetName(facvar));
3949  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &newcons, name, nvars, vars, coefs, -SCIPinfinity(scip), maxact) );
3950  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, auxvar, -1.0) );
3951  if( !SCIPisZero(scip, maxact) )
3952  {
3953  SCIP_CALL( SCIPaddCoefLinear(scip, newcons, facvar, maxact) );
3954  }
3955  SCIP_CALL( SCIPaddCons(scip, newcons) );
3956  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3957  if( naddconss != NULL )
3958  ++(*naddconss);
3959 
3960  /* create variable expression */
3961  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, auxvar) );
3962 
3963  /* release auxvar */
3964  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3965 
3966  return SCIP_OKAY;
3967 }
3968 
3969 /** helper method to generate an expression for a sum of products of binary variables; note that the method captures the generated expression */
3970 static
3972  SCIP* scip, /**< SCIP data structure */
3973  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3974  SCIP_CONS* cons, /**< constraint */
3975  SCIP_EXPR* sumexpr, /**< expression */
3976  int minterms, /**< minimum number of terms in a the sum of x_i sum_j c_j x_j */
3977  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the binary quadratic */
3978  int* naddconss /**< pointer to update the total number of added constraints (might be NULL) */
3979  )
3980 {
3981  SCIP_EXPR** exprs = NULL;
3982  SCIP_VAR** tmpvars = NULL;
3983  SCIP_VAR** vars = NULL;
3984  SCIP_VAR** xs = NULL;
3985  SCIP_VAR** ys = NULL;
3986  SCIP_Real* exprcoefs = NULL;
3987  SCIP_Real* tmpcoefs = NULL;
3988  SCIP_Real* sumcoefs;
3989  SCIP_Bool* isused = NULL;
3990  int* childidxs = NULL;
3991  int* count = NULL;
3992  int nchildren;
3993  int nexprs = 0;
3994  int nterms;
3995  int nvars;
3996  int ntotalvars;
3997  int i;
3998 
3999  assert(sumexpr != NULL);
4000  assert(minterms > 1);
4001  assert(newexpr != NULL);
4002 
4003  *newexpr = NULL;
4004 
4005  /* check whether sumexpr is indeed a sum */
4006  if( !SCIPisExprSum(scip, sumexpr) )
4007  return SCIP_OKAY;
4008 
4009  nchildren = SCIPexprGetNChildren(sumexpr);
4010  sumcoefs = SCIPgetCoefsExprSum(sumexpr);
4011  nvars = SCIPgetNVars(scip);
4012  ntotalvars = SCIPgetNTotalVars(scip);
4013 
4014  /* check whether there are enough terms available */
4015  if( nchildren < minterms )
4016  return SCIP_OKAY;
4017 
4018  /* allocate memory */
4019  SCIP_CALL( SCIPallocBufferArray(scip, &xs, nchildren) );
4020  SCIP_CALL( SCIPallocBufferArray(scip, &ys, nchildren) );
4021  SCIP_CALL( SCIPallocBufferArray(scip, &childidxs, nchildren) );
4022 
4023  /* collect all bilinear binary product terms */
4024  SCIP_CALL( getBilinearBinaryTerms(scip, sumexpr, xs, ys, childidxs, &nterms) );
4025 
4026  /* check whether there are enough terms available */
4027  if( nterms < minterms )
4028  goto TERMINATE;
4029 
4030  /* store how often each variable appears in a bilinear binary product */
4031  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, SCIPgetVars(scip), nvars) );
4032  SCIP_CALL( SCIPallocClearBufferArray(scip, &count, ntotalvars) );
4033  SCIP_CALL( SCIPallocClearBufferArray(scip, &isused, nchildren) );
4034 
4035  SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nchildren) );
4036  SCIP_CALL( SCIPallocBufferArray(scip, &exprcoefs, nchildren) );
4037  SCIP_CALL( SCIPallocBufferArray(scip, &tmpvars, MIN(nterms, nvars)) );
4038  SCIP_CALL( SCIPallocBufferArray(scip, &tmpcoefs, MIN(nterms, nvars)) );
4039 
4040  for( i = 0; i < nterms; ++i )
4041  {
4042  int xidx;
4043  int yidx;
4044 
4045  assert(xs[i] != NULL);
4046  assert(ys[i] != NULL);
4047 
4048  xidx = SCIPvarGetIndex(xs[i]);
4049  assert(xidx < ntotalvars);
4050  yidx = SCIPvarGetIndex(ys[i]);
4051  assert(yidx < ntotalvars);
4052 
4053  ++count[xidx];
4054  ++count[yidx];
4055 
4056  SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(xs[i]), count[xidx]);
4057  SCIPdebugMsg(scip, "increase counter for %s to %d\n", SCIPvarGetName(ys[i]), count[yidx]);
4058  }
4059 
4060  /* sort variables; don't change order of count array because it depends on problem indices */
4061  {
4062  int* tmpcount;
4063 
4064  SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpcount, count, nvars) );
4065  SCIPsortDownIntPtr(tmpcount, (void**)vars, nvars);
4066  SCIPfreeBufferArray(scip, &tmpcount);
4067  }
4068 
4069  for( i = 0; i < nvars; ++i )
4070  {
4071  SCIP_VAR* facvar = vars[i];
4072  int ntmpvars = 0;
4073  int j;
4074 
4075  /* skip candidate if there are not enough terms left */
4076  if( count[SCIPvarGetIndex(vars[i])] < minterms )
4077  continue;
4078 
4079  SCIPdebugMsg(scip, "consider facvar = %s with count = %d\n", SCIPvarGetName(facvar), count[SCIPvarGetIndex(vars[i])]);
4080 
4081  /* collect variables for x_i * sum_j c_ij x_j */
4082  for( j = 0; j < nterms; ++j )
4083  {
4084  int childidx = childidxs[j];
4085  assert(childidx >= 0 && childidx < nchildren);
4086 
4087  if( !isused[childidx] && (xs[j] == facvar || ys[j] == facvar) )
4088  {
4089  SCIP_Real coef;
4090  int xidx;
4091  int yidx;
4092 
4093  coef = sumcoefs[childidx];
4094  assert(coef != 0.0);
4095 
4096  /* collect corresponding variable */
4097  tmpvars[ntmpvars] = (xs[j] == facvar) ? ys[j] : xs[j];
4098  tmpcoefs[ntmpvars] = coef;
4099  ++ntmpvars;
4100 
4101  /* update counters */
4102  xidx = SCIPvarGetIndex(xs[j]);
4103  assert(xidx < ntotalvars);
4104  yidx = SCIPvarGetIndex(ys[j]);
4105  assert(yidx < ntotalvars);
4106  --count[xidx];
4107  --count[yidx];
4108  assert(count[xidx] >= 0);
4109  assert(count[yidx] >= 0);
4110 
4111  /* mark term to be used */
4112  isused[childidx] = TRUE;
4113  }
4114  }
4115  assert(ntmpvars >= minterms);
4116  assert(SCIPvarGetIndex(facvar) < ntotalvars);
4117  assert(count[SCIPvarGetIndex(facvar)] == 0); /* facvar should not appear in any other bilinear term */
4118 
4119  /* create required constraints and store the generated expression */
4120  SCIP_CALL( reformulateFactorizedBinaryQuadratic(scip, conshdlr, cons, facvar, tmpvars, tmpcoefs, ntmpvars, &exprs[nexprs], naddconss) );
4121  exprcoefs[nexprs] = 1.0;
4122  ++nexprs;
4123  }
4124 
4125  /* factorization was only successful if at least one expression has been generated */
4126  if( nexprs > 0 )
4127  {
4128  int nexprsold = nexprs;
4129 
4130  /* add all children of the sum that have not been used */
4131  for( i = 0; i < nchildren; ++i )
4132  {
4133  if( !isused[i] )
4134  {
4135  exprs[nexprs] = SCIPexprGetChildren(sumexpr)[i];
4136  exprcoefs[nexprs] = sumcoefs[i];
4137  ++nexprs;
4138  }
4139  }
4140 
4141  /* create a new sum expression */
4142  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, nexprs, exprs, exprcoefs, SCIPgetConstantExprSum(sumexpr), exprownerCreate, (void*)conshdlr) );
4143 
4144  /* release all expressions that have been generated by reformulateFactorizedBinaryQuadratic() */
4145  for( i = 0; i < nexprsold; ++i )
4146  {
4147  SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
4148  }
4149  }
4150 
4151 TERMINATE:
4152  /* free memory */
4153  SCIPfreeBufferArrayNull(scip, &tmpcoefs);
4154  SCIPfreeBufferArrayNull(scip, &tmpvars);
4155  SCIPfreeBufferArrayNull(scip, &exprcoefs);
4156  SCIPfreeBufferArrayNull(scip, &exprs);
4157  SCIPfreeBufferArrayNull(scip, &vars);
4158  SCIPfreeBufferArrayNull(scip, &isused);
4159  SCIPfreeBufferArrayNull(scip, &count);
4160  SCIPfreeBufferArray(scip, &childidxs);
4161  SCIPfreeBufferArray(scip, &ys);
4162  SCIPfreeBufferArray(scip, &xs);
4163 
4164  return SCIP_OKAY;
4165 }
4166 
4167 /** helper method to create an AND constraint or varbound constraints for a given binary product expression */
4168 static
4170  SCIP* scip, /**< SCIP data structure */
4171  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4172  SCIP_EXPR* prodexpr, /**< product expression */
4173  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4174  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4175  SCIP_Bool empathy4and /**< whether to use an AND constraint, if possible */
4176  )
4177 {
4178  SCIP_VAR** vars;
4179  SCIP_CONS* cons;
4180  SCIP_Real* coefs;
4181  SCIP_VAR* w;
4182  char* name;
4183  int nchildren;
4184  int i;
4185 
4186  assert(conshdlr != NULL);
4187  assert(prodexpr != NULL);
4188  assert(SCIPisExprProduct(scip, prodexpr));
4189  assert(newexpr != NULL);
4190 
4191  nchildren = SCIPexprGetNChildren(prodexpr);
4192  assert(nchildren >= 2);
4193 
4194  /* memory to store the variables of the variable expressions (+1 for w) and their name */
4195  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nchildren + 1) );
4196  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nchildren + 1) );
4197  SCIP_CALL( SCIPallocBufferArray(scip, &name, nchildren * (SCIP_MAXSTRLEN + 1) + 20) );
4198 
4199  /* prepare the names of the variable and the constraints */
4200  /* coverity[secure_coding] */
4201  strcpy(name, "binreform");
4202  for( i = 0; i < nchildren; ++i )
4203  {
4204  vars[i] = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[i]);
4205  coefs[i] = 1.0;
4206  assert(vars[i] != NULL);
4207  (void) strcat(name, "_");
4208  (void) strcat(name, SCIPvarGetName(vars[i]));
4209  }
4210 
4211  /* create and add variable */
4212  SCIP_CALL( SCIPcreateVarBasic(scip, &w, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT) );
4213  SCIP_CALL( SCIPaddVar(scip, w) );
4214  SCIPdebugMsg(scip, " created auxiliary variable %s\n", name);
4215 
4216  /* use variable bound constraints if it is a bilinear product and there is no empathy for an AND constraint */
4217  if( nchildren == 2 && !empathy4and )
4218  {
4219  SCIP_VAR* x = vars[0];
4220  SCIP_VAR* y = vars[1];
4221 
4222  assert(x != NULL);
4223  assert(y != NULL);
4224  assert(x != y);
4225 
4226  /* create and add x - w >= 0 */
4227  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_1", SCIPvarGetName(x), SCIPvarGetName(y));
4228  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, x, w, -1.0, 0.0, SCIPinfinity(scip)) );
4229  SCIP_CALL( SCIPaddCons(scip, cons) );
4230  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4231 
4232  /* create and add y - w >= 0 */
4233  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_2", SCIPvarGetName(x), SCIPvarGetName(y));
4234  SCIP_CALL( SCIPcreateConsBasicVarbound(scip, &cons, name, y, w, -1.0, 0.0, SCIPinfinity(scip)) );
4235  SCIP_CALL( SCIPaddCons(scip, cons) );
4236  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4237 
4238  /* create and add x + y - w <= 1 */
4239  vars[2] = w;
4240  coefs[2] = -1.0;
4241  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "binreform_%s_%s_3", SCIPvarGetName(x), SCIPvarGetName(y));
4242  SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name, 3, vars, coefs, -SCIPinfinity(scip), 1.0) );
4243  SCIP_CALL( SCIPaddCons(scip, cons) );
4244  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4245 
4246  /* update number of added constraints */
4247  if( naddconss != NULL )
4248  *naddconss += 3;
4249  }
4250  else
4251  {
4252  /* create, add, and release AND constraint */
4253  SCIP_CALL( SCIPcreateConsBasicAnd(scip, &cons, name, w, nchildren, vars) );
4254  SCIP_CALL( SCIPaddCons(scip, cons) );
4255  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
4256  SCIPdebugMsg(scip, " create AND constraint\n");
4257 
4258  /* update number of added constraints */
4259  if( naddconss != NULL )
4260  *naddconss += 1;
4261  }
4262 
4263  /* create variable expression */
4264  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, w) );
4265 
4266  /* release created variable */
4267  SCIP_CALL( SCIPreleaseVar(scip, &w) );
4268 
4269  /* free memory */
4270  SCIPfreeBufferArray(scip, &name);
4271  SCIPfreeBufferArray(scip, &coefs);
4272  SCIPfreeBufferArray(scip, &vars);
4273 
4274  return SCIP_OKAY;
4275 }
4276 
4277 /** helper method to generate an expression for the product of binary variables; note that the method captures the generated expression */
4278 static
4280  SCIP* scip, /**< SCIP data structure */
4281  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4282  SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4283  SCIP_EXPR* prodexpr, /**< product expression */
4284  SCIP_EXPR** newexpr, /**< pointer to store the expression that represents the product */
4285  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4286  int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4287  )
4288 {
4289  SCIP_CONSHDLRDATA* conshdlrdata;
4290  int nchildren;
4291 
4292  assert(prodexpr != NULL);
4293  assert(newexpr != NULL);
4294 
4295  *newexpr = NULL;
4296 
4297  /* only consider products of binary variables */
4298  if( !isBinaryProduct(scip, prodexpr) )
4299  return SCIP_OKAY;
4300 
4301  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4302  assert(conshdlrdata != NULL);
4303  nchildren = SCIPexprGetNChildren(prodexpr);
4304  assert(nchildren >= 2);
4305 
4306  /* check whether there is already an expression that represents the product */
4307  if( SCIPhashmapExists(exprmap, (void*)prodexpr) )
4308  {
4309  *newexpr = (SCIP_EXPR*) SCIPhashmapGetImage(exprmap, (void*)prodexpr);
4310  assert(*newexpr != NULL);
4311 
4312  /* capture expression */
4313  SCIPcaptureExpr(*newexpr);
4314  }
4315  else
4316  {
4317  SCIPdebugMsg(scip, " product expression %p has been considered for the first time\n", (void*)prodexpr);
4318 
4319  if( nchildren == 2 )
4320  {
4321  SCIP_CLIQUE** xcliques;
4322  SCIP_VAR* x;
4323  SCIP_VAR* y;
4324  SCIP_Bool found_clique = FALSE;
4325  int c;
4326 
4327  /* get variables from the product expression */
4328  x = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[0]);
4329  assert(x != NULL);
4330  y = SCIPgetVarExprVar(SCIPexprGetChildren(prodexpr)[1]);
4331  assert(y != NULL);
4332  assert(x != y);
4333 
4334  /* first try to find a clique containing both variables */
4335  xcliques = SCIPvarGetCliques(x, TRUE);
4336 
4337  /* look in cliques containing x */
4338  for( c = 0; c < SCIPvarGetNCliques(x, TRUE); ++c )
4339  {
4340  if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* x + y <= 1 => x*y = 0 */
4341  {
4342  /* create zero value expression */
4343  SCIP_CALL( SCIPcreateExprValue(scip, newexpr, 0.0, exprownerCreate, (void*)conshdlr) );
4344 
4345  if( nchgcoefs != NULL )
4346  *nchgcoefs += 1;
4347 
4348  found_clique = TRUE;
4349  break;
4350  }
4351 
4352  if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* x + (1-y) <= 1 => x*y = x */
4353  {
4354  /* create variable expression for x */
4355  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, x) );
4356 
4357  if( nchgcoefs != NULL )
4358  *nchgcoefs += 2;
4359 
4360  found_clique = TRUE;
4361  break;
4362  }
4363  }
4364 
4365  if( !found_clique )
4366  {
4367  xcliques = SCIPvarGetCliques(x, FALSE);
4368 
4369  /* look in cliques containing complement of x */
4370  for( c = 0; c < SCIPvarGetNCliques(x, FALSE); ++c )
4371  {
4372  if( SCIPcliqueHasVar(xcliques[c], y, TRUE) ) /* (1-x) + y <= 1 => x*y = y */
4373  {
4374  /* create variable expression for y */
4375  SCIP_CALL( createExprVar(scip, conshdlr, newexpr, y) );
4376 
4377  if( nchgcoefs != NULL )
4378  *nchgcoefs += 1;
4379 
4380  found_clique = TRUE;
4381  break;
4382  }
4383 
4384  if( SCIPcliqueHasVar(xcliques[c], y, FALSE) ) /* (1-x) + (1-y) <= 1 => x*y = x + y - 1 */
4385  {
4386  /* create sum expression */
4387  SCIP_EXPR* sum_children[2];
4388  SCIP_Real sum_coefs[2];
4389  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[0], x) );
4390  SCIP_CALL( createExprVar(scip, conshdlr, &sum_children[1], y) );
4391  sum_coefs[0] = 1.0;
4392  sum_coefs[1] = 1.0;
4393  SCIP_CALL( SCIPcreateExprSum(scip, newexpr, 2, sum_children, sum_coefs, -1.0, exprownerCreate, (void*)conshdlr) );
4394 
4395  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[0]) );
4396  SCIP_CALL( SCIPreleaseExpr(scip, &sum_children[1]) );
4397 
4398  if( nchgcoefs != NULL )
4399  *nchgcoefs += 3;
4400 
4401  found_clique = TRUE;
4402  break;
4403  }
4404  }
4405  }
4406 
4407  /* if the variables are not in a clique, do standard linearization */
4408  if( !found_clique )
4409  {
4410  SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4411  }
4412  }
4413  else
4414  {
4415  /* linearize binary product using an AND constraint because nchildren > 2 */
4416  SCIP_CALL( getBinaryProductExprDo(scip, conshdlr, prodexpr, newexpr, naddconss, conshdlrdata->reformbinprodsand) );
4417  }
4418 
4419  /* hash variable expression */
4420  SCIP_CALL( SCIPhashmapInsert(exprmap, (void*)prodexpr, *newexpr) );
4421  }
4422 
4423  return SCIP_OKAY;
4424 }
4425 
4426 /** helper function to replace binary products in a given constraint */
4427 static
4429  SCIP* scip, /**< SCIP data structure */
4430  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4431  SCIP_CONS* cons, /**< constraint */
4432  SCIP_HASHMAP* exprmap, /**< map to remember generated variables for visited product expressions */
4433  SCIP_EXPRITER* it, /**< expression iterator */
4434  int* naddconss, /**< pointer to update the total number of added constraints (might be NULL) */
4435  int* nchgcoefs /**< pointer to update the total number of changed coefficients (might be NULL) */
4436  )
4437 {
4438  SCIP_CONSHDLRDATA* conshdlrdata;
4439  SCIP_CONSDATA* consdata;
4440  SCIP_EXPR* expr;
4441 
4442  assert(conshdlr != NULL);
4443  assert(cons != NULL);
4444  assert(exprmap != NULL);
4445  assert(it != NULL);
4446 
4447  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4448  assert(conshdlrdata != NULL);
4449 
4450  consdata = SCIPconsGetData(cons);
4451  assert(consdata != NULL);
4452  assert(consdata->expr != NULL);
4453 
4454  SCIPdebugMsg(scip, " check constraint %s\n", SCIPconsGetName(cons));
4455 
4456  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4457  {
4458  SCIP_EXPR* newexpr = NULL;
4459  SCIP_EXPR* childexpr;
4460  int childexpridx;
4461 
4462  childexpridx = SCIPexpriterGetChildIdxDFS(it);
4463  assert(childexpridx >= 0 && childexpridx < SCIPexprGetNChildren(expr));
4464  childexpr = SCIPexpriterGetChildExprDFS(it);
4465  assert(childexpr != NULL);
4466 
4467  /* try to factorize variables in a sum expression that contains several products of binary variables */
4468  if( conshdlrdata->reformbinprodsfac > 1 )
4469  {
4470  SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, cons, childexpr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4471  }
4472 
4473  /* try to create an expression that represents a product of binary variables */
4474  if( newexpr == NULL )
4475  {
4476  SCIP_CALL( getBinaryProductExpr(scip, conshdlr, exprmap, childexpr, &newexpr, naddconss, nchgcoefs) );
4477  }
4478 
4479  if( newexpr != NULL )
4480  {
4481  assert(naddconss == NULL || *naddconss > 0 || nchgcoefs == NULL || *nchgcoefs > 0);
4482 
4483  /* replace product expression */
4484  SCIP_CALL( SCIPreplaceExprChild(scip, expr, childexpridx, newexpr) );
4485 
4486  /* note that the expression has been captured by getBinaryProductExpr and SCIPreplaceExprChild */
4487  SCIP_CALL( SCIPreleaseExpr(scip, &newexpr) );
4488 
4489  /* mark the constraint to not be simplified anymore */
4490  consdata->issimplified = FALSE;
4491  }
4492  }
4493 
4494  return SCIP_OKAY;
4495 }
4496 
4497 /** reformulates products of binary variables during presolving in the following way:
4498  *
4499  * Let \f$\sum_{i,j} Q_{ij} x_i x_j\f$ be a subexpression that only contains binary variables.
4500  * 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}:
4501  * \f[
4502  * z_{ij} \leq x_i, \qquad z_{ij} \leq x_j, \qquad x_i + x_j - z_{ij} \leq 1.
4503  * \f]
4504  *
4505  * 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$.
4506  * These cliques allow for a better reformulation. There are four cases:
4507  *
4508  * 1. \f$x_i + x_j \leq 1\f$ implies that \f$x_i x_j = 0\f$
4509  * 2. \f$x_i + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i\f$
4510  * 3. \f$(1 - x_i) + x_j \leq 1\f$ implies \f$x_i x_j = x_j\f$
4511  * 4. \f$(1 - x_i) + (1 - x_j) \leq 1\f$ implies \f$x_i x_j = x_i + x_j - 1\f$
4512  *
4513  * The reformulation using \f$z_{ij}\f$ or the cliques is implemented in getBinaryProductExpr().
4514  *
4515  * Introducing too many extra variables and constraints can have a negative impact on the performance (e.g., due to
4516  * slow probing). For this reason, it is checked in getFactorizedBinaryQuadraticExpr() whether \f$\sum_{i,j} Q_{ij} x_i x_j\f$
4517  * contains large (&ge; `reformbinprodsfac` parameter) lower sums of the form \f$x_i \sum_j Q_{ij} x_j\f$.
4518  * Such a lower sum is reformulated with only one extra variable w_i:
4519  * \f{align}{
4520  * \text{maxact} & := \sum_j \max(0, Q_{ij}), \\
4521  * \text{minact} & := \sum_j \min(0, Q_{ij}), \\
4522  * \text{minact}\, x_i & \leq w_i, \\
4523  * w_i &\leq \text{maxact}\, x_i, \\
4524  * \text{minact} &\leq \sum_j Q_{ij} x_j - w_i + \text{minact}\, x_i \\
4525  * \text{maxact} &\geq \sum_j Q_{ij} x_j - w_i + \text{maxact}\, x_i
4526  * \f}
4527  * 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
4528  * is checked whether there are enough terms left to factorize other binary variables. Lower sums with a larger number
4529  * of terms are prioritized.
4530  */
4531 static
4533  SCIP* scip, /**< SCIP data structure */
4534  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4535  SCIP_CONS** conss, /**< constraints */
4536  int nconss, /**< total number of constraints */
4537  int* naddconss, /**< pointer to store the total number of added constraints (might be NULL) */
4538  int* nchgcoefs /**< pointer to store the total number of changed coefficients (might be NULL) */
4539  )
4540 {
4541  SCIP_CONSHDLRDATA* conshdlrdata;
4542  SCIP_HASHMAP* exprmap;
4543  SCIP_EXPRITER* it;
4544  int c;
4545 
4546  assert(conshdlr != NULL);
4547 
4548  /* no nonlinear constraints or binary variables -> skip */
4549  if( nconss == 0 || SCIPgetNBinVars(scip) == 0 )
4550  return SCIP_OKAY;
4551  assert(conss != NULL);
4552 
4553  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4554  assert(conshdlrdata != NULL);
4555 
4556  /* create expression hash map */
4557  SCIP_CALL( SCIPhashmapCreate(&exprmap, SCIPblkmem(scip), SCIPgetNVars(scip)) );
4558 
4559  /* create expression iterator */
4560  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4563 
4564  SCIPdebugMsg(scip, "call presolveBinaryProducts()\n");
4565 
4566  for( c = 0; c < nconss; ++c )
4567  {
4568  SCIP_CONSDATA* consdata;
4569  SCIP_EXPR* newexpr = NULL;
4570 
4571  assert(conss[c] != NULL);
4572 
4573  consdata = SCIPconsGetData(conss[c]);
4574  assert(consdata != NULL);
4575 
4576  /* try to reformulate the root expression */
4577  if( conshdlrdata->reformbinprodsfac > 1 )
4578  {
4579  SCIP_CALL( getFactorizedBinaryQuadraticExpr(scip, conshdlr, conss[c], consdata->expr, conshdlrdata->reformbinprodsfac, &newexpr, naddconss) );
4580  }
4581 
4582  /* release the root node if another expression has been found */
4583  if( newexpr != NULL )
4584  {
4585  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4586  consdata->expr = newexpr;
4587 
4588  /* mark constraint to be not simplified anymore */
4589  consdata->issimplified = FALSE;
4590  }
4591 
4592  /* replace each product of binary variables separately */
4593  SCIP_CALL( replaceBinaryProducts(scip, conshdlr, conss[c], exprmap, it, naddconss, nchgcoefs) );
4594  }
4595 
4596  /* free memory */
4597  SCIPhashmapFree(&exprmap);
4598  SCIPfreeExpriter(&it);
4599 
4600  return SCIP_OKAY;
4601 }
4602 
4603 /** scales the sides of the constraint \f$\ell \leq \sum_i c_i f_i(x) \leq r\f$.
4604  *
4605  * Let \f$n_+\f$ the number of positive coefficients \f$c_i\f$ and \f$n_-\f$ be the number of negative coefficients.
4606  * Then scale by -1 if
4607  * - \f$n_+ < n_-\f$, or
4608  * - \f$n_+ = n_-\f$ and \f$r = \infty\f$.
4609  */
4610 static
4612  SCIP* scip, /**< SCIP data structure */
4613  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
4614  SCIP_CONS* cons, /**< nonlinear constraint */
4615  SCIP_Bool* changed /**< buffer to store if the expression of cons changed */
4616  )
4617 {
4618  SCIP_CONSDATA* consdata;
4619  int i;
4620 
4621  assert(cons != NULL);
4622 
4623  consdata = SCIPconsGetData(cons);
4624  assert(consdata != NULL);
4625 
4626  if( SCIPisExprSum(scip, consdata->expr) )
4627  {
4628  SCIP_Real* coefs;
4629  SCIP_Real constant;
4630  int nchildren;
4631  int counter = 0;
4632 
4633  coefs = SCIPgetCoefsExprSum(consdata->expr);
4634  constant = SCIPgetConstantExprSum(consdata->expr);
4635  nchildren = SCIPexprGetNChildren(consdata->expr);
4636 
4637  /* handle special case when constraint is l <= -f(x) <= r and f(x) not a sum: simplfy ensures f is not a sum */
4638  if( nchildren == 1 && constant == 0.0 && coefs[0] == -1.0 )
4639  {
4640  SCIP_EXPR* expr;
4641  expr = consdata->expr;
4642 
4643  consdata->expr = SCIPexprGetChildren(expr)[0];
4644  assert(!SCIPisExprSum(scip, consdata->expr));
4645 
4646  SCIPcaptureExpr(consdata->expr);
4647 
4648  SCIPswapReals(&consdata->lhs, &consdata->rhs);
4649  consdata->lhs = -consdata->lhs;
4650  consdata->rhs = -consdata->rhs;
4651 
4652  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
4653  *changed = TRUE;
4654  return SCIP_OKAY;
4655  }
4656 
4657  /* compute n_+ - n_i */
4658  for( i = 0; i < nchildren; ++i )
4659  counter += coefs[i] > 0 ? 1 : -1;
4660 
4661  if( counter < 0 || (counter == 0 && SCIPisInfinity(scip, consdata->rhs)) )
4662  {
4663  SCIP_EXPR* expr;
4664  SCIP_Real* newcoefs;
4665 
4666  /* allocate memory */
4667  SCIP_CALL( SCIPallocBufferArray(scip, &newcoefs, nchildren) );
4668 
4669  for( i = 0; i < nchildren; ++i )
4670  newcoefs[i] = -coefs[i];
4671 
4672  /* create a new sum expression */
4673  SCIP_CALL( SCIPcreateExprSum(scip, &expr, nchildren, SCIPexprGetChildren(consdata->expr), newcoefs, -constant, exprownerCreate, (void*)conshdlr) );
4674 
4675  /* replace expression in constraint data and scale sides */
4676  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4677  consdata->expr = expr;
4678  SCIPswapReals(&consdata->lhs, &consdata->rhs);
4679  consdata->lhs = -consdata->lhs;
4680  consdata->rhs = -consdata->rhs;
4681 
4682  /* free memory */
4683  SCIPfreeBufferArray(scip, &newcoefs);
4684 
4685  *changed = TRUE;
4686  }
4687  }
4688 
4689  return SCIP_OKAY;
4690 }
4691 
4692 /** forbid multiaggrations of variables that appear nonlinear in constraints */
4693 static
4695  SCIP* scip, /**< SCIP data structure */
4696  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4697  SCIP_CONS** conss, /**< constraints */
4698  int nconss /**< number of constraints */
4699  )
4700 {
4701  SCIP_EXPRITER* it;
4702  SCIP_CONSDATA* consdata;
4703  SCIP_EXPR* expr;
4704  int c;
4705 
4706  assert(scip != NULL);
4707  assert(conshdlr != NULL);
4708 
4709  if( !SCIPconshdlrGetData(conshdlr)->forbidmultaggrnlvar )
4710  return SCIP_OKAY;
4711 
4712  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4714 
4715  for( c = 0; c < nconss; ++c )
4716  {
4717  consdata = SCIPconsGetData(conss[c]);
4718  assert(consdata != NULL);
4719 
4720  /* if root expression is sum, then forbid multiaggregation only for variables that are not in linear terms of sum,
4721  * i.e., skip children of sum that are variables
4722  */
4723  if( SCIPisExprSum(scip, consdata->expr) )
4724  {
4725  int i;
4726  SCIP_EXPR* child;
4727  for( i = 0; i < SCIPexprGetNChildren(consdata->expr); ++i )
4728  {
4729  child = SCIPexprGetChildren(consdata->expr)[i];
4730 
4731  /* skip variable expression, as they correspond to a linear term */
4732  if( SCIPisExprVar(scip, child) )
4733  continue;
4734 
4735  for( expr = SCIPexpriterRestartDFS(it, child); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4736  if( SCIPisExprVar(scip, expr) )
4737  {
4739  }
4740  }
4741  }
4742  else
4743  {
4744  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4745  if( SCIPisExprVar(scip, expr) )
4746  {
4748  }
4749  }
4750  }
4751 
4752  SCIPfreeExpriter(&it);
4753 
4754  return SCIP_OKAY;
4755 }
4756 
4757 /** simplifies expressions and replaces common subexpressions for a set of constraints
4758  * @todo put the constant to the constraint sides
4759  */
4760 static
4762  SCIP* scip, /**< SCIP data structure */
4763  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4764  SCIP_CONS** conss, /**< constraints */
4765  int nconss, /**< total number of constraints */
4766  SCIP_PRESOLTIMING presoltiming, /**< presolve timing (SCIP_PRESOLTIMING_ALWAYS if not in presolving) */
4767  SCIP_Bool* infeasible, /**< buffer to store whether infeasibility has been detected */
4768  int* ndelconss, /**< counter to add number of deleted constraints, or NULL */
4769  int* naddconss, /**< counter to add number of added constraints, or NULL */
4770  int* nchgcoefs /**< counter to add number of changed coefficients, or NULL */
4771  )
4772 {
4773  SCIP_CONSHDLRDATA* conshdlrdata;
4774  SCIP_CONSDATA* consdata;
4775  int* nlockspos;
4776  int* nlocksneg;
4777  SCIP_Bool havechange;
4778  int i;
4779 
4780  assert(scip != NULL);
4781  assert(conshdlr != NULL);
4782  assert(conss != NULL);
4783  assert(nconss > 0);
4784  assert(infeasible != NULL);
4785 
4786  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4787  assert(conshdlrdata != NULL);
4788 
4789  /* update number of canonicalize calls */
4790  ++(conshdlrdata->ncanonicalizecalls);
4791 
4792  SCIP_CALL( SCIPstartClock(scip, conshdlrdata->canonicalizetime) );
4793 
4794  *infeasible = FALSE;
4795 
4796  /* set havechange to TRUE in the first call of canonicalize; otherwise we might not replace common subexpressions */
4797  havechange = conshdlrdata->ncanonicalizecalls == 1;
4798 
4799  /* free nonlinear handlers information from expressions */ /* TODO can skip this in first presolve round */
4800  SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
4801 
4802  /* allocate memory for storing locks of each constraint */
4803  SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
4804  SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
4805 
4806  /* unlock all constraints */
4807  for( i = 0; i < nconss; ++i )
4808  {
4809  assert(conss[i] != NULL);
4810 
4811  consdata = SCIPconsGetData(conss[i]);
4812  assert(consdata != NULL);
4813 
4814  /* remember locks */
4815  nlockspos[i] = consdata->nlockspos;
4816  nlocksneg[i] = consdata->nlocksneg;
4817 
4818  /* remove locks */
4819  SCIP_CALL( addLocks(scip, conss[i], -consdata->nlockspos, -consdata->nlocksneg) );
4820  assert(consdata->nlockspos == 0);
4821  assert(consdata->nlocksneg == 0);
4822  }
4823 
4824 #ifndef NDEBUG
4825  /* check whether all locks of each expression have been removed */
4826  for( i = 0; i < nconss; ++i )
4827  {
4828  SCIP_EXPR* expr;
4829  SCIP_EXPRITER* it;
4830 
4831  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
4832 
4833  consdata = SCIPconsGetData(conss[i]);
4834  assert(consdata != NULL);
4835 
4836  SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_RTOPOLOGIC, TRUE) );
4837  for( expr = consdata->expr; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
4838  {
4839  assert(expr != NULL);
4840  assert(SCIPexprGetOwnerData(expr)->nlocksneg == 0);
4841  assert(SCIPexprGetOwnerData(expr)->nlockspos == 0);
4842  }
4843  SCIPfreeExpriter(&it);
4844  }
4845 #endif
4846 
4847  /* reformulate products of binary variables */
4848  if( conshdlrdata->reformbinprods && SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING
4849  && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) )
4850  {
4851  int tmpnaddconss = 0;
4852  int tmpnchgcoefs = 0;
4853 
4854  /* call this function before simplification because expressions might not be simplified after reformulating
4855  * binary products; the detection of some nonlinear handlers might assume that expressions are simplified
4856  */
4857  SCIP_CALL( presolveBinaryProducts(scip, conshdlr, conss, nconss, &tmpnaddconss, &tmpnchgcoefs) );
4858 
4859  /* update counters */
4860  if( naddconss != NULL )
4861  *naddconss = tmpnaddconss;
4862  if( nchgcoefs != NULL )
4863  *nchgcoefs = tmpnchgcoefs;
4864 
4865  /* check whether at least one expression has changed */
4866  if( tmpnaddconss + tmpnchgcoefs > 0 )
4867  havechange = TRUE;
4868  }
4869 
4870  for( i = 0; i < nconss; ++i )
4871  {
4872  consdata = SCIPconsGetData(conss[i]);
4873  assert(consdata != NULL);
4874 
4875  /* call simplify for each expression */
4876  if( !consdata->issimplified && consdata->expr != NULL )
4877  {
4878  SCIP_EXPR* simplified;
4879  SCIP_Bool changed;
4880 
4881  changed = FALSE;
4882  SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, infeasible, exprownerCreate, (void*)conshdlr) );
4883  consdata->issimplified = TRUE;
4884 
4885  if( changed )
4886  havechange = TRUE;
4887 
4888  /* 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").
4889  * If root expression did not change, some subexpression may still have changed, but the locks were taking care of in the corresponding SCIPreplaceExprChild() call.
4890  */
4891  if( simplified != consdata->expr )
4892  {
4893  assert(changed);
4894 
4895  /* release old expression */
4896  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
4897 
4898  /* store simplified expression */
4899  consdata->expr = simplified;
4900  }
4901  else
4902  {
4903  /* The simplify captures simplified in any case, also if nothing has changed.
4904  * Therefore, we have to release it here.
4905  */
4906  SCIP_CALL( SCIPreleaseExpr(scip, &simplified) );
4907  }
4908 
4909  if( *infeasible )
4910  break;
4911 
4912  /* scale constraint sides */
4913  SCIP_CALL( scaleConsSides(scip, conshdlr, conss[i], &changed) );
4914 
4915  if( changed )
4916  havechange = TRUE;
4917 
4918  /* handle constant root expression; either the problem is infeasible or the constraint is redundant */
4919  if( SCIPisExprValue(scip, consdata->expr) )
4920  {
4921  SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
4922  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasNegative(scip, value - consdata->lhs)) ||
4923  (!SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasPositive(scip, value - consdata->rhs)) )
4924  {
4925  SCIPdebugMsg(scip, "<%s> with constant expression found infeasible\n", SCIPconsGetName(conss[i]));
4926  SCIPdebugPrintCons(scip, conss[i], NULL);
4927  *infeasible = TRUE;
4928  break;
4929  }
4930  else
4931  {
4932  SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
4933  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
4934  if( ndelconss != NULL )
4935  ++*ndelconss;
4936  havechange = TRUE;
4937  }
4938  }
4939  }
4940  }
4941 
4942  /* replace common subexpressions */
4943  if( havechange && !*infeasible )
4944  {
4945  SCIP_CONS** consssorted;
4946  SCIP_EXPR** rootexprs;
4947  SCIP_Bool replacedroot;
4948 
4949  SCIP_CALL( SCIPallocBufferArray(scip, &rootexprs, nconss) );
4950  for( i = 0; i < nconss; ++i )
4951  rootexprs[i] = SCIPconsGetData(conss[i])->expr;
4952 
4953  SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, rootexprs, nconss, &replacedroot) );
4954 
4955  /* update pointer to root expr in constraints, if any has changed
4956  * SCIPreplaceCommonSubexpressions will have released the old expr and captures the new one
4957  */
4958  if( replacedroot )
4959  for( i = 0; i < nconss; ++i )
4960  SCIPconsGetData(conss[i])->expr = rootexprs[i];
4961 
4962  SCIPfreeBufferArray(scip, &rootexprs);
4963 
4964  /* TODO this is a possibly expensive way to update the variable expressions stored inside an expression which might have
4965  * been changed after simplification; now we completely recollect all variable expression and variable events
4966  */
4967 
4968  /* Each variable stores the constraints for which it catched varbound events sorted by the constraint index.
4969  * Thus, for performance reasons, it is better to call dropVarEvents in descending order of constraint index.
4970  */
4971  SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
4972  SCIPsortPtr((void**)consssorted, compIndexConsNonlinear, nconss);
4973 
4974  for( i = nconss-1; i >= 0; --i )
4975  {
4976  assert(i == 0 || compIndexConsNonlinear((void*)consssorted[i-1], (void*)consssorted[i]) < 0);
4977  if( SCIPconsIsDeleted(consssorted[i]) )
4978  continue;
4979 
4980  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
4981  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
4982  }
4983  for( i = 0; i < nconss; ++i )
4984  {
4985  if( SCIPconsIsDeleted(consssorted[i]) )
4986  continue;
4987 
4988  SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(consssorted[i])) );
4989  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
4990  }
4991 
4992  SCIPfreeBufferArray(scip, &consssorted);
4993 
4994  /* forbid multiaggregation for nonlinear variables again (in case new variables appeared now)
4995  * a multiaggregation of a nonlinear variable can yield to a large increase in expressions due to
4996  * expanding terms in simplify, e.g. ,(sum_i x_i)^2, so we just forbid these
4997  */
4998  SCIP_CALL( forbidNonlinearVariablesMultiaggration(scip, conshdlr, conss, nconss) );
4999  }
5000 
5001  /* restore locks */
5002  for( i = 0; i < nconss; ++i )
5003  {
5004  if( SCIPconsIsDeleted(conss[i]) )
5005  continue;
5006 
5007  SCIP_CALL( addLocks(scip, conss[i], nlockspos[i], nlocksneg[i]) );
5008  }
5009 
5010  /* run nlhdlr detect if in presolving stage (that is, not in exitpre)
5011  * TODO can we skip this in presoltiming fast?
5012  */
5013  if( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING && !*infeasible )
5014  {
5015  /* reset one of the number of detections counter to count only current presolving round */
5016  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
5017  SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
5018 
5019  SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
5020  }
5021 
5022  /* free allocated memory */
5023  SCIPfreeBufferArray(scip, &nlocksneg);
5024  SCIPfreeBufferArray(scip, &nlockspos);
5025 
5026  SCIP_CALL( SCIPstopClock(scip, conshdlrdata->canonicalizetime) );
5027 
5028  return SCIP_OKAY;
5029 }
5030 
5031 /** merges constraints that have the same root expression */
5032 static
5034  SCIP* scip, /**< SCIP data structure */
5035  SCIP_CONS** conss, /**< constraints to process */
5036  int nconss, /**< number of constraints */
5037  SCIP_Bool* success /**< pointer to store whether at least one constraint could be deleted */
5038  )
5039 {
5040  SCIP_HASHMAP* expr2cons;
5041  SCIP_Bool* updatelocks;
5042  int* nlockspos;
5043  int* nlocksneg;
5044  int c;
5045 
5046  assert(success != NULL);
5047 
5048  *success = FALSE;
5049 
5050  /* not enough constraints available */
5051  if( nconss <= 1 )
5052  return SCIP_OKAY;
5053 
5054  SCIP_CALL( SCIPhashmapCreate(&expr2cons, SCIPblkmem(scip), nconss) );
5055  SCIP_CALL( SCIPallocClearBufferArray(scip, &updatelocks, nconss) );
5056  SCIP_CALL( SCIPallocBufferArray(scip, &nlockspos, nconss) );
5057  SCIP_CALL( SCIPallocBufferArray(scip, &nlocksneg, nconss) );
5058 
5059  for( c = 0; c < nconss; ++c )
5060  {
5061  SCIP_CONSDATA* consdata;
5062 
5063  /* ignore deleted constraints */
5064  if( SCIPconsIsDeleted(conss[c]) )
5065  continue;
5066 
5067  consdata = SCIPconsGetData(conss[c]);
5068  assert(consdata != NULL);
5069 
5070  /* add expression to the hash map if not seen so far */
5071  if( !SCIPhashmapExists(expr2cons, (void*)consdata->expr) )
5072  {
5073  SCIP_CALL( SCIPhashmapInsertInt(expr2cons, (void*)consdata->expr, c) );
5074  }
5075  else
5076  {
5077  SCIP_CONSDATA* imgconsdata;
5078  int idx;
5079 
5080  idx = SCIPhashmapGetImageInt(expr2cons, (void*)consdata->expr);
5081  assert(idx >= 0 && idx < nconss);
5082 
5083  imgconsdata = SCIPconsGetData(conss[idx]);
5084  assert(imgconsdata != NULL);
5085  assert(imgconsdata->expr == consdata->expr);
5086 
5087  SCIPdebugMsg(scip, "merge constraint %g <= %s <= %g with %g <= %s <= %g\n", consdata->lhs,
5088  SCIPconsGetName(conss[c]), consdata->rhs, imgconsdata->lhs, SCIPconsGetName(conss[idx]), imgconsdata->rhs);
5089 
5090  /* check whether locks need to be updated */
5091  if( !updatelocks[idx] && ((SCIPisInfinity(scip, -imgconsdata->lhs) && !SCIPisInfinity(scip, -consdata->lhs))
5092  || (SCIPisInfinity(scip, imgconsdata->rhs) && !SCIPisInfinity(scip, consdata->rhs))) )
5093  {
5094  nlockspos[idx] = imgconsdata->nlockspos;
5095  nlocksneg[idx] = imgconsdata->nlocksneg;
5096  SCIP_CALL( addLocks(scip, conss[idx], -imgconsdata->nlockspos, -imgconsdata->nlocksneg) );
5097  updatelocks[idx] = TRUE;
5098  }
5099 
5100  /* update constraint sides */
5101  imgconsdata->lhs = MAX(imgconsdata->lhs, consdata->lhs);
5102  imgconsdata->rhs = MIN(imgconsdata->rhs, consdata->rhs);
5103 
5104  /* delete constraint */
5105  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
5106  *success = TRUE;
5107  }
5108  }
5109 
5110  /* restore locks of updated constraints */
5111  if( *success )
5112  {
5113  for( c = 0; c < nconss; ++c )
5114  {
5115  if( updatelocks[c] )
5116  {
5117  SCIP_CALL( addLocks(scip, conss[c], nlockspos[c], nlocksneg[c]) );
5118  }
5119  }
5120  }
5121 
5122  /* free memory */
5123  SCIPfreeBufferArray(scip, &nlocksneg);
5124  SCIPfreeBufferArray(scip, &nlockspos);
5125  SCIPfreeBufferArray(scip, &updatelocks);
5126  SCIPhashmapFree(&expr2cons);
5127 
5128  return SCIP_OKAY;
5129 }
5130 
5131 /** interval evaluation of variables as used in redundancy check
5132  *
5133  * Returns local variable bounds of a variable, relaxed by feastol, as interval.
5134  */
5135 static
5136 SCIP_DECL_EXPR_INTEVALVAR(intEvalVarRedundancyCheck)
5137 { /*lint --e{715}*/
5138  SCIP_CONSHDLRDATA* conshdlrdata;
5139  SCIP_INTERVAL interval;
5140  SCIP_Real lb;
5141  SCIP_Real ub;
5142 
5143  assert(scip != NULL);
5144  assert(var != NULL);
5145 
5146  conshdlrdata = (SCIP_CONSHDLRDATA*)intevalvardata;
5147  assert(conshdlrdata != NULL);
5148 
5149  if( conshdlrdata->globalbounds )
5150  {
5151  lb = SCIPvarGetLbGlobal(var);
5152  ub = SCIPvarGetUbGlobal(var);
5153  }
5154  else
5155  {
5156  lb = SCIPvarGetLbLocal(var);
5157  ub = SCIPvarGetUbLocal(var);
5158  }
5159  assert(lb <= ub); /* can SCIP ensure by now that variable bounds are not contradicting? */
5160 
5161  /* relax variable bounds, if there are bounds and variable is not fixed
5162  * (actually some assert complains if trying SCIPisRelEQ if both bounds are at different infinity)
5163  */
5164  if( !(SCIPisInfinity(scip, -lb) && SCIPisInfinity(scip, ub)) && !SCIPisRelEQ(scip, lb, ub) )
5165  {
5166  if( !SCIPisInfinity(scip, -lb) )
5167  lb -= SCIPfeastol(scip);
5168 
5169  if( !SCIPisInfinity(scip, ub) )
5170  ub += SCIPfeastol(scip);
5171  }
5172 
5173  /* convert SCIPinfinity() to SCIP_INTERVAL_INFINITY */
5174  lb = -infty2infty(SCIPinfinity(scip), SCIP_INTERVAL_INFINITY, -lb);
5176  assert(lb <= ub);
5177 
5178  SCIPintervalSetBounds(&interval, lb, ub);
5179 
5180  return interval;
5181 }
5182 
5183 /** removes constraints that are always feasible or very simple
5184  *
5185  * Checks whether the activity of constraint functions is a subset of the constraint sides (relaxed by feastol).
5186  * To compute the activity, we use forwardPropExpr(), but relax variable bounds by feastol, because solutions to be checked
5187  * might violate variable bounds by up to feastol, too.
5188  * This is the main reason why the redundancy check is not done in propConss(), which relaxes variable bounds by epsilon only.
5189  *
5190  * Also removes constraints of the form lhs &le; variable &le; rhs.
5191  *
5192  * @todo it would be sufficient to check constraints for which we know that they are not currently violated by a valid solution
5193  *
5194  * @note This could should not run during solving, because the forwardProp takes the bounds of auxiliary variables into account.
5195  * For the root expression, these bounds are already set to the constraint sides, so that the activity of every expression
5196  * would appear as if the constraint is redundant.
5197  */
5198 static
5200  SCIP* scip, /**< SCIP data structure */
5201  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5202  SCIP_CONS** conss, /**< constraints to propagate */
5203  int nconss, /**< total number of constraints */
5204  SCIP_Bool* cutoff, /**< pointer to store whether infeasibility has been identified */
5205  int* ndelconss, /**< buffer to add the number of deleted constraints */
5206  int* nchgbds /**< buffer to add the number of variable bound tightenings */
5207  )
5208 {
5209  SCIP_CONSHDLRDATA* conshdlrdata;
5210  SCIP_CONSDATA* consdata;
5211  SCIP_INTERVAL activity;
5212  SCIP_INTERVAL sides;
5213  int i;
5214 
5215  assert(scip != NULL);
5216  assert(conshdlr != NULL);
5217  assert(conss != NULL);
5218  assert(nconss >= 0);
5219  assert(cutoff != NULL);
5220  assert(ndelconss != NULL);
5221  assert(nchgbds != NULL);
5222 
5223  /* no constraints to check */
5224  if( nconss == 0 )
5225  return SCIP_OKAY;
5226 
5227  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5228  assert(conshdlrdata != NULL);
5229 
5230  /* increase curboundstag and set lastvaractivitymethodchange
5231  * we do this here to trigger a reevaluation of all variable bounds, since we will relax variable bounds
5232  * for the redundancy check differently than for domain propagation
5233  * we also update lastboundrelax to ensure activites of all expressions are indeed reevaluated
5234  */
5235  ++conshdlrdata->curboundstag;
5236  assert(conshdlrdata->curboundstag > 0);
5237  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5238  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5239  conshdlrdata->intevalvar = intEvalVarRedundancyCheck;
5240 
5241  SCIPdebugMsg(scip, "checking %d constraints for redundancy\n", nconss);
5242 
5243  *cutoff = FALSE;
5244  for( i = 0; i < nconss; ++i )
5245  {
5246  if( !SCIPconsIsActive(conss[i]) || SCIPconsIsDeleted(conss[i]) )
5247  continue;
5248 
5249  consdata = SCIPconsGetData(conss[i]);
5250  assert(consdata != NULL);
5251 
5252  /* handle constant expressions separately: either the problem is infeasible or the constraint is redundant */
5253  if( SCIPisExprValue(scip, consdata->expr) )
5254  {
5255  SCIP_Real value = SCIPgetValueExprValue(consdata->expr);
5256 
5257  if( (!SCIPisInfinity(scip, -consdata->lhs) && value < consdata->lhs - SCIPfeastol(scip)) ||
5258  (!SCIPisInfinity(scip, consdata->rhs) && value > consdata->rhs + SCIPfeastol(scip)) )
5259  {
5260  SCIPdebugMsg(scip, "constant constraint <%s> is infeasible: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5261  *cutoff = TRUE;
5262 
5263  goto TERMINATE;
5264  }
5265 
5266  SCIPdebugMsg(scip, "constant constraint <%s> is redundant: %g in [%g,%g] ", SCIPconsGetName(conss[i]), value, consdata->lhs, consdata->rhs);
5267 
5268  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5269  ++*ndelconss;
5270 
5271  continue;
5272  }
5273 
5274  /* handle variable expressions separately: tighten variable bounds to constraint sides, then remove constraint (now redundant) */
5275  if( SCIPisExprVar(scip, consdata->expr) )
5276  {
5277  SCIP_VAR* var;
5278  SCIP_Bool tightened;
5279 
5280  var = SCIPgetVarExprVar(consdata->expr);
5281  assert(var != NULL);
5282 
5283  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);
5284 
5285  /* ensure that variable bounds are within constraint sides */
5286  if( !SCIPisInfinity(scip, -consdata->lhs) )
5287  {
5288  SCIP_CALL( SCIPtightenVarLb(scip, var, consdata->lhs, TRUE, cutoff, &tightened) );
5289 
5290  if( tightened )
5291  ++*nchgbds;
5292 
5293  if( *cutoff )
5294  goto TERMINATE;
5295  }
5296 
5297  if( !SCIPisInfinity(scip, consdata->rhs) )
5298  {
5299  SCIP_CALL( SCIPtightenVarUb(scip, var, consdata->rhs, TRUE, cutoff, &tightened) );
5300 
5301  if( tightened )
5302  ++*nchgbds;
5303 
5304  if( *cutoff )
5305  goto TERMINATE;
5306  }
5307 
5308  /* delete the (now) redundant constraint locally */
5309  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5310  ++*ndelconss;
5311 
5312  continue;
5313  }
5314 
5315  /* reevaluate expression activity, now using intEvalVarRedundancyCheck
5316  * we relax variable bounds by feastol here, as solutions that are checked later can also violate
5317  * variable bounds by up to feastol
5318  * (relaxing fixed variables seems to be too much, but they would be removed by presolve soon anyway)
5319  */
5320  SCIPdebugMsg(scip, "call forwardPropExpr() for constraint <%s>: ", SCIPconsGetName(conss[i]));
5321  SCIPdebugPrintCons(scip, conss[i], NULL);
5322 
5323  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, FALSE, cutoff, NULL) );
5324  assert(*cutoff || !SCIPintervalIsEmpty(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(consdata->expr)));
5325 
5326  /* it is unlikely that we detect infeasibility by doing forward propagation */
5327  if( *cutoff )
5328  {
5329  SCIPdebugMsg(scip, " -> cutoff\n");
5330  goto TERMINATE;
5331  }
5332 
5333  assert(SCIPexprGetActivityTag(consdata->expr) == conshdlrdata->curboundstag);
5334  activity = SCIPexprGetActivity(consdata->expr);
5335 
5336  /* relax sides by feastol
5337  * we could accept every solution that violates constraints up to feastol as redundant, so this is the most permissive we can be
5338  */
5339  SCIPintervalSetBounds(&sides,
5340  SCIPisInfinity(scip, -consdata->lhs) ? -SCIP_INTERVAL_INFINITY : consdata->lhs - SCIPfeastol(scip),
5341  SCIPisInfinity(scip, consdata->rhs) ? SCIP_INTERVAL_INFINITY : consdata->rhs + SCIPfeastol(scip));
5342 
5343  if( SCIPintervalIsSubsetEQ(SCIP_INTERVAL_INFINITY, activity, sides) )
5344  {
5345  SCIPdebugMsg(scip, " -> redundant: activity [%g,%g] within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5346 
5347  SCIP_CALL( SCIPdelConsLocal(scip, conss[i]) );
5348  ++*ndelconss;
5349 
5350  continue;
5351  }
5352 
5353  SCIPdebugMsg(scip, " -> not redundant: activity [%g,%g] not within sides [%g,%g]\n", activity.inf, activity.sup, consdata->lhs, consdata->rhs);
5354  }
5355 
5356 TERMINATE:
5357  /* make sure all activities are reevaluated again, since we relaxed bounds in a different way */
5358  ++conshdlrdata->curboundstag;
5359  conshdlrdata->lastvaractivitymethodchange = conshdlrdata->curboundstag;
5360  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
5361  conshdlrdata->intevalvar = intEvalVarBoundTightening;
5362 
5363  return SCIP_OKAY;
5364 }
5365 
5366 /** tries to automatically convert a nonlinear constraint into a more specific and more specialized constraint */
5367 static
5369  SCIP* scip, /**< SCIP data structure */
5370  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
5371  SCIP_CONS* cons, /**< source constraint to try to convert */
5372  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
5373  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
5374  int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
5375  )
5376 {
5377  SCIP_CONSHDLRDATA* conshdlrdata;
5378  SCIP_CONSDATA* consdata;
5379  SCIP_CONS** upgdconss;
5380  int upgdconsssize;
5381  int nupgdconss_;
5382  int i;
5383 
5384  assert(scip != NULL);
5385  assert(conshdlr != NULL);
5386  assert(cons != NULL);
5387  assert(!SCIPconsIsModifiable(cons));
5388  assert(upgraded != NULL);
5389  assert(nupgdconss != NULL);
5390  assert(naddconss != NULL);
5391 
5392  *upgraded = FALSE;
5393 
5394  nupgdconss_ = 0;
5395 
5396  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5397  assert(conshdlrdata != NULL);
5398 
5399  /* if there are no upgrade methods, we can stop */
5400  if( conshdlrdata->nconsupgrades == 0 )
5401  return SCIP_OKAY;
5402 
5403  upgdconsssize = 2;
5404  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
5405 
5406  /* call the upgrading methods */
5407  SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods): ", SCIPconsGetName(cons), conshdlrdata->nconsupgrades);
5408  SCIPdebugPrintCons(scip, cons, NULL);
5409 
5410  consdata = SCIPconsGetData(cons);
5411  assert(consdata != NULL);
5412 
5413  /* try all upgrading methods in priority order in case the upgrading step is enable */
5414  for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
5415  {
5416  if( !conshdlrdata->consupgrades[i]->active )
5417  continue;
5418 
5419  assert(conshdlrdata->consupgrades[i]->consupgd != NULL);
5420 
5421  SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5422 
5423  while( nupgdconss_ < 0 )
5424  {
5425  /* upgrade function requires more memory: resize upgdconss and call again */
5426  assert(-nupgdconss_ > upgdconsssize);
5427  upgdconsssize = -nupgdconss_;
5428  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
5429 
5430  SCIP_CALL( conshdlrdata->consupgrades[i]->consupgd(scip, cons, consdata->nvarexprs, &nupgdconss_, upgdconss, upgdconsssize) );
5431 
5432  assert(nupgdconss_ != 0);
5433  }
5434 
5435  if( nupgdconss_ > 0 )
5436  {
5437  /* got upgrade */
5438  int j;
5439 
5440  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
5441 
5442  /* add the upgraded constraints to the problem and forget them */
5443  for( j = 0; j < nupgdconss_; ++j )
5444  {
5445  SCIPdebugMsgPrint(scip, "\t");
5446  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
5447 
5448  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
5449  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
5450  }
5451 
5452  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
5453  *nupgdconss += 1;
5454  *naddconss += nupgdconss_ - 1;
5455  *upgraded = TRUE;
5456 
5457  /* delete upgraded constraint */
5458  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
5459  SCIP_CALL( SCIPdelCons(scip, cons) );
5460 
5461  break;
5462  }
5463  }
5464 
5465  SCIPfreeBufferArray(scip, &upgdconss);
5466 
5467  return SCIP_OKAY;
5468 }
5469 
5470 /** returns whether the variable of a given variable expression is a candidate for presolveSingleLockedVars(), i.e.,
5471  * the variable is only contained in a single nonlinear constraint, has no objective coefficient, has finite
5472  * variable bounds, and is not binary
5473  */
5474 static
5476  SCIP* scip, /**< SCIP data structure */
5477  SCIP_EXPR* expr /**< variable expression */
5478  )
5479 {
5480  SCIP_VAR* var;
5481  SCIP_EXPR_OWNERDATA* ownerdata;
5482 
5483  assert(SCIPisExprVar(scip, expr));
5484 
5485  var = SCIPgetVarExprVar(expr);
5486  assert(var != NULL);
5487 
5488  ownerdata = SCIPexprGetOwnerData(expr);
5489  assert(ownerdata != NULL);
5490 
5491  return SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlocksneg
5492  && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == ownerdata->nlockspos
5493  && ownerdata->nconss == 1 && SCIPisZero(scip, SCIPvarGetObj(var))
5494  && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var))
5496  && !SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
5497 }
5498 
5499 /** removes all variable expressions that are contained in a given expression from a hash map */
5500 static
5502  SCIP* scip, /**< SCIP data structure */
5503  SCIP_EXPR* expr, /**< expression */
5504  SCIP_EXPRITER* it, /**< expression iterator */
5505  SCIP_HASHMAP* exprcands /**< map to hash variable expressions */
5506  )
5507 {
5508  SCIP_EXPR* e;
5509 
5510  for( e = SCIPexpriterRestartDFS(it, expr); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
5511  {
5512  if( SCIPisExprVar(scip, e) && SCIPhashmapExists(exprcands, (void*)e) )
5513  {
5514  SCIP_CALL( SCIPhashmapRemove(exprcands, (void*)e) );
5515  }
5516  }
5517 
5518  return SCIP_OKAY;
5519 }
5520 
5521 /** presolving method to fix a variable \f$x_i\f$ to one of its bounds if the variable is only contained in a single
5522  * nonlinear constraint g(x) &le; rhs (&ge; lhs) if g() is concave (convex) in \f$x_i\f$
5523  *
5524  * If a continuous variable has bounds [0,1], then the variable type is changed to be binary.
5525  * Otherwise, a bound disjunction constraint is added.
5526  *
5527  * @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
5528  * @todo extend this to cases where a variable can appear in a monomial with an exponent, essentially relax
5529  * 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
5530  * on this (probably have one or two flags per variable and update this whenever another \f$x^{p_i}\f$ is found)
5531  */
5532 static
5534  SCIP* scip, /**< SCIP data structure */
5535  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
5536  SCIP_CONS* cons, /**< nonlinear constraint */
5537  int* nchgvartypes, /**< pointer to store the total number of changed variable types */
5538  int* naddconss, /**< pointer to store the total number of added constraints */
5539  SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5540  )
5541 {
5542  SCIP_CONSHDLRDATA* conshdlrdata;
5543  SCIP_CONSDATA* consdata;
5544  SCIP_EXPR** singlelocked;
5545  SCIP_HASHMAP* exprcands;
5546  SCIP_Bool hasbounddisj;
5547  SCIP_Bool haslhs;
5548  SCIP_Bool hasrhs;
5549  int nsinglelocked = 0;
5550  int i;
5551 
5552  assert(conshdlr != NULL);
5553  assert(cons != NULL);
5554  assert(nchgvartypes != NULL);
5555  assert(naddconss != NULL);
5556  assert(infeasible != NULL);
5557 
5558  *nchgvartypes = 0;
5559  *naddconss = 0;
5560  *infeasible = FALSE;
5561 
5562  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5563  assert(conshdlrdata != NULL);
5564  consdata = SCIPconsGetData(cons);
5565  assert(consdata != NULL);
5566 
5567  /* only consider constraints with one finite side */
5568  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) )
5569  return SCIP_OKAY;
5570 
5571  /* only consider sum expressions */
5572  if( !SCIPisExprSum(scip, consdata->expr) )
5573  return SCIP_OKAY;
5574 
5575  /* remember which side is finite */
5576  haslhs = !SCIPisInfinity(scip, -consdata->lhs);
5577  hasrhs = !SCIPisInfinity(scip, consdata->rhs);
5578 
5579  /* allocate memory */
5580  SCIP_CALL( SCIPhashmapCreate(&exprcands, SCIPblkmem(scip), consdata->nvarexprs) );
5581  SCIP_CALL( SCIPallocBufferArray(scip, &singlelocked, consdata->nvarexprs) );
5582 
5583  /* check all variable expressions for single locked variables */
5584  for( i = 0; i < consdata->nvarexprs; ++i )
5585  {
5586  assert(consdata->varexprs[i] != NULL);
5587 
5588  if( isSingleLockedCand(scip, consdata->varexprs[i]) )
5589  {
5590  SCIP_CALL( SCIPhashmapInsert(exprcands, (void*)consdata->varexprs[i], NULL) );
5591  singlelocked[nsinglelocked++] = consdata->varexprs[i];
5592  }
5593  }
5594  SCIPdebugMsg(scip, "found %d single locked variables for constraint %s\n", nsinglelocked, SCIPconsGetName(cons));
5595 
5596  if( nsinglelocked > 0 )
5597  {
5598  SCIP_EXPR** children;
5599  SCIP_EXPRITER* it;
5600  int nchildren;
5601 
5602  children = SCIPexprGetChildren(consdata->expr);
5603  nchildren = SCIPexprGetNChildren(consdata->expr);
5604 
5605  /* create iterator */
5606  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
5609 
5610  for( i = 0; i < nchildren; ++i )
5611  {
5612  SCIP_EXPR* child;
5613  SCIP_Real coef;
5614 
5615  child = children[i];
5616  assert(child != NULL);
5617  coef = SCIPgetCoefsExprSum(consdata->expr)[i];
5618 
5619  /* ignore linear terms */
5620  if( SCIPisExprVar(scip, child) )
5621  continue;
5622 
5623  /* consider products prod_j f_j(x); ignore f_j(x) if it is a single variable, otherwise iterate through the
5624  * expression that represents f_j and remove each variable expression from exprcands
5625  */
5626  else if( SCIPisExprProduct(scip, child) )
5627  {
5628  int j;
5629 
5630  for( j = 0; j < SCIPexprGetNChildren(child); ++j )
5631  {
5632  SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[j];
5633 
5634  if( !SCIPisExprVar(scip, grandchild) )
5635  {
5636  /* mark all variable expressions that are contained in the expression */
5637  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5638  }
5639  }
5640  }
5641  /* fixing a variable x to one of its bounds is only valid for ... +x^p >= lhs or ... -x^p <= rhs if p = 2k
5642  * for an integer k >= 1
5643  */
5644  else if( SCIPisExprPower(scip, child) )
5645  {
5646  SCIP_EXPR* grandchild = SCIPexprGetChildren(child)[0];
5647  SCIP_Real exponent = SCIPgetExponentExprPow(child);
5648  SCIP_Bool valid;
5649 
5650  /* check for even integral exponent */
5651  valid = exponent > 1.0 && fmod(exponent, 2.0) == 0.0;
5652 
5653  if( !valid || !SCIPisExprVar(scip, grandchild) || (hasrhs && coef > 0.0) || (haslhs && coef < 0.0) )
5654  {
5655  /* mark all variable expressions that are contained in the expression */
5656  SCIP_CALL( removeSingleLockedVars(scip, grandchild, it, exprcands) );
5657  }
5658  }
5659  /* all other cases cannot be handled */
5660  else
5661  {
5662  /* mark all variable expressions that are contained in the expression */
5663  SCIP_CALL( removeSingleLockedVars(scip, child, it, exprcands) );
5664  }
5665  }
5666 
5667  /* free expression iterator */
5668  SCIPfreeExpriter(&it);
5669  }
5670 
5671  /* check whether the bound disjunction constraint handler is available */
5672  hasbounddisj = SCIPfindConshdlr(scip, "bounddisjunction") != NULL;
5673 
5674  /* fix variable to one of its bounds by either changing its variable type or adding a disjunction constraint */
5675  for( i = 0; i < nsinglelocked; ++i )
5676  {
5677  /* only consider expressions that are still contained in the exprcands map */
5678  if( SCIPhashmapExists(exprcands, (void*)singlelocked[i]) )
5679  {
5680  SCIP_CONS* newcons;
5681  SCIP_VAR* vars[2];
5682  SCIP_BOUNDTYPE boundtypes[2];
5683  SCIP_Real bounds[2];
5684  char name[SCIP_MAXSTRLEN];
5685  SCIP_VAR* var;
5686 
5687  var = SCIPgetVarExprVar(singlelocked[i]);
5688  assert(var != NULL);
5689  SCIPdebugMsg(scip, "found single locked variable %s in [%g,%g] that can be fixed to one of its bounds\n",
5691 
5692  /* try to change the variable type to binary */
5693  if( conshdlrdata->checkvarlocks == 't' && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0) && SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0) )
5694  {
5695  assert(SCIPvarGetType(var) != SCIP_VARTYPE_BINARY);
5696  SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_BINARY, infeasible) );
5697  ++(*nchgvartypes);
5698 
5699  if( *infeasible )
5700  {
5701  SCIPdebugMsg(scip, "detect infeasibility after changing variable type of <%s>\n", SCIPvarGetName(var));
5702  break;
5703  }
5704  }
5705  /* add bound disjunction constraint if bounds of the variable are finite */
5706  else if( hasbounddisj && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5707  {
5708  vars[0] = var;
5709  vars[1] = var;
5710  boundtypes[0] = SCIP_BOUNDTYPE_LOWER;
5711  boundtypes[1] = SCIP_BOUNDTYPE_UPPER;
5712  bounds[0] = SCIPvarGetUbGlobal(var);
5713  bounds[1] = SCIPvarGetLbGlobal(var);
5714 
5715  SCIPdebugMsg(scip, "add bound disjunction constraint for %s\n", SCIPvarGetName(var));
5716 
5717  /* create, add, and release bound disjunction constraint */
5718  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "quadvarbnddisj_%s", SCIPvarGetName(var));
5719  SCIP_CALL( SCIPcreateConsBounddisjunction(scip, &newcons, name, 2, vars, boundtypes, bounds, TRUE, TRUE,
5720  TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5721  SCIP_CALL( SCIPaddCons(scip, newcons) );
5722  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
5723  ++(*naddconss);
5724  }
5725  }
5726  }
5727 
5728  /* free memory */
5729  SCIPfreeBufferArray(scip, &singlelocked);
5730  SCIPhashmapFree(&exprcands);
5731 
5732  return SCIP_OKAY;
5733 }
5734 
5735 /** presolving method to check if there is a single linear continuous variable that can be made implicit integer */
5736 static
5738  SCIP* scip, /**< SCIP data structure */
5739  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5740  SCIP_CONS** conss, /**< nonlinear constraints */
5741  int nconss, /**< total number of nonlinear constraints */
5742  int* nchgvartypes, /**< pointer to update the total number of changed variable types */
5743  SCIP_Bool* infeasible /**< pointer to store whether problem is infeasible */
5744  )
5745 {
5746  int c;
5747 
5748  assert(scip != NULL);
5749  assert(conshdlr != NULL);
5750  assert(conss != NULL || nconss == 0);
5751  assert(nchgvartypes != NULL);
5752  assert(infeasible != NULL);
5753 
5754  *infeasible = FALSE;
5755 
5756  /* nothing can be done if there are no binary and integer variables available */
5757  if( SCIPgetNBinVars(scip) == 0 && SCIPgetNIntVars(scip) == 0 )
5758  return SCIP_OKAY;
5759 
5760  /* no continuous var can be made implicit-integer if there are no continuous variables */
5761  if( SCIPgetNContVars(scip) == 0 )
5762  return SCIP_OKAY;
5763 
5764  for( c = 0; c < nconss; ++c )
5765  {
5766  SCIP_CONSDATA* consdata;
5767  SCIP_EXPR** children;
5768  int nchildren;
5769  SCIP_Real* coefs;
5770  SCIP_EXPR* cand = NULL;
5771  SCIP_Real candcoef = 0.0;
5772  int i;
5773 
5774  assert(conss != NULL && conss[c] != NULL);
5775 
5776  consdata = SCIPconsGetData(conss[c]);
5777  assert(consdata != NULL);
5778 
5779  /* the constraint must be an equality constraint */
5780  if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
5781  continue;
5782 
5783  /* the root expression needs to be a sum expression */
5784  if( !SCIPisExprSum(scip, consdata->expr) )
5785  continue;
5786 
5787  children = SCIPexprGetChildren(consdata->expr);
5788  nchildren = SCIPexprGetNChildren(consdata->expr);
5789 
5790  /* the sum expression must have at least two children
5791  * (with one child, we would look for a coef*x = constant, which is presolved away anyway)
5792  */
5793  if( nchildren <= 1 )
5794  continue;
5795 
5796  coefs = SCIPgetCoefsExprSum(consdata->expr);
5797 
5798  /* find first continuous variable and get value of its coefficient */
5799  for( i = 0; i < nchildren; ++i )
5800  {
5801  if( !SCIPisExprVar(scip, children[i]) || SCIPvarIsIntegral(SCIPgetVarExprVar(children[i])) )
5802  continue;
5803 
5804  candcoef = coefs[i];
5805  assert(candcoef != 0.0);
5806 
5807  /* lhs/rhs - constant divided by candcoef must be integral
5808  * if not, break with cand == NULL, so give up
5809  */
5810  if( SCIPisIntegral(scip, (consdata->lhs - SCIPgetConstantExprSum(consdata->expr)) / candcoef) )
5811  cand = children[i];
5812 
5813  break;
5814  }
5815 
5816  /* no suitable continuous variable found */
5817  if( cand == NULL )
5818  continue;
5819 
5820  /* check whether all other coefficients are integral when diving by candcoef and all other children are integral */
5821  for( i = 0; i < nchildren; ++i )
5822  {
5823  if( children[i] == cand )
5824  continue;
5825 
5826  /* child i must be integral */
5827  if( !SCIPexprIsIntegral(children[i]) )
5828  {
5829  cand = NULL;
5830  break;
5831  }
5832 
5833  /* coefficient of child i must be integral if diving by candcoef */
5834  if( !SCIPisIntegral(scip, coefs[i] / candcoef) ) /*lint !e414*/
5835  {
5836  cand = NULL;
5837  break;
5838  }
5839  }
5840 
5841  if( cand == NULL )
5842  continue;
5843 
5844  SCIPdebugMsg(scip, "make variable <%s> implicit integer due to constraint <%s>\n",
5846 
5847  /* change variable type */
5848  SCIP_CALL( SCIPchgVarType(scip, SCIPgetVarExprVar(cand), SCIP_VARTYPE_IMPLINT, infeasible) );
5849 
5850  if( *infeasible )
5851  return SCIP_OKAY;
5852 
5853  /* mark expression as being integral (as would be done by expr_var.c in the next round of updating integrality info) */
5855  }
5856 
5857  return SCIP_OKAY;
5858 }
5859 
5860 /** creates auxiliary variable for a given expression
5861  *
5862  * @note for a variable expression it does nothing
5863  * @note this function can only be called in stage SCIP_STAGE_SOLVING
5864  */
5865 static
5867  SCIP* scip, /**< SCIP data structure */
5868  SCIP_EXPR* expr /**< expression */
5869  )
5870 {
5871  SCIP_EXPR_OWNERDATA* ownerdata;
5872  SCIP_CONSHDLRDATA* conshdlrdata;
5873  SCIP_VARTYPE vartype;
5874  SCIP_INTERVAL activity;
5875  char name[SCIP_MAXSTRLEN];
5876 
5877  assert(scip != NULL);
5878  assert(expr != NULL);
5879 
5880  ownerdata = SCIPexprGetOwnerData(expr);
5881  assert(ownerdata != NULL);
5882  assert(ownerdata->nauxvaruses > 0);
5883 
5884  /* if we already have auxvar, then do nothing */
5885  if( ownerdata->auxvar != NULL )
5886  return SCIP_OKAY;
5887 
5888  /* if expression is a variable-expression, then do nothing */
5889  if( SCIPisExprVar(scip, expr) )
5890  return SCIP_OKAY;
5891 
5892  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
5893  {
5894  SCIPerrorMessage("it is not possible to create auxiliary variables during stage=%d\n", SCIPgetStage(scip));
5895  return SCIP_INVALIDCALL;
5896  }
5897 
5898  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
5899  assert(conshdlrdata != NULL);
5900  assert(conshdlrdata->auxvarid >= 0);
5901 
5902  /* it doesn't harm much to have an auxvar for a constant, as this can be handled well by the default hdlr,
5903  * but it usually indicates a missing simplify
5904  * if we find situations where we need to have an auxvar for a constant, then remove this assert
5905  */
5906  assert(!SCIPisExprValue(scip, expr));
5907 
5908  /* create and capture auxiliary variable */
5909  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "auxvar_%s_%d", SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), conshdlrdata->auxvarid);
5910  ++conshdlrdata->auxvarid;
5911 
5912  /* type of auxiliary variable depends on integrality information of the expression */
5914 
5915  /* get activity of expression to initialize variable bounds, if something valid is available (evalActivity was called in initSepa) */
5916  if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
5917  {
5918  activity = SCIPexprGetActivity(expr);
5919  /* we cannot handle a domain error here at the moment, but it seems unlikely that it could occur
5920  * if it appear, then we could change code to handle this properly, but for now we just ensure that we continue correctly
5921  * and abort in debug mode only
5922  */
5924  {
5925  SCIPABORT();
5927  }
5928  }
5929  else
5931 
5932  /* if root node, then activity is globally valid, so use it to initialize the global bounds of the auxvar
5933  * otherwise, we create var without bounds here and use activity to set local bounds below (needs to be after adding var)
5934  */
5935  if( SCIPgetDepth(scip) == 0 )
5936  {
5937  SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, MAX(-SCIPinfinity(scip), activity.inf), MIN(SCIPinfinity(scip), activity.sup), 0.0, vartype) );
5938  }
5939  else
5940  {
5941  SCIP_CALL( SCIPcreateVarBasic(scip, &ownerdata->auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0, vartype) );
5942  }
5943 
5944  /* mark the auxiliary variable to be added for the relaxation only
5945  * this prevents SCIP to create linear constraints from cuts or conflicts that contain auxiliary variables,
5946  * or to copy the variable to a subscip
5947  */
5948  SCIPvarMarkRelaxationOnly(ownerdata->auxvar);
5949 
5950  SCIP_CALL( SCIPaddVar(scip, ownerdata->auxvar) );
5951 
5952  SCIPdebugMsg(scip, "added auxiliary variable <%s> [%g,%g] for expression %p\n", SCIPvarGetName(ownerdata->auxvar), SCIPvarGetLbGlobal(ownerdata->auxvar), SCIPvarGetUbGlobal(ownerdata->auxvar), (void*)expr);
5953 
5954  /* add variable locks in both directions
5955  * TODO should be sufficient to lock only according to expr->nlockspos/neg,
5956  * but then we need to also update the auxvars locks when the expr locks change
5957  */
5958  SCIP_CALL( SCIPaddVarLocks(scip, ownerdata->auxvar, 1, 1) );
5959 
5960 #ifdef WITH_DEBUG_SOLUTION
5961  if( SCIPdebugIsMainscip(scip) )
5962  {
5963  /* store debug solution value of auxiliary variable
5964  * assumes that expression has been evaluated in debug solution before
5965  */
5966  SCIP_CALL( SCIPdebugAddSolVal(scip, ownerdata->auxvar, SCIPexprGetEvalValue(expr)) );
5967  }
5968 #endif
5969 
5970  if( SCIPgetDepth(scip) > 0 )
5971  {
5972  /* initialize local bounds to (locally valid) activity */
5973  SCIP_Bool cutoff;
5974  SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, activity, &cutoff, NULL) );
5975  assert(!cutoff); /* should not happen as activity wasn't empty and variable is new */
5976  }
5977 
5978  return SCIP_OKAY;
5979 }
5980 
5981 /** initializes separation for constraint
5982  *
5983  * - ensures that activities are up to date in all expressions
5984  * - creates auxiliary variables where required
5985  * - calls propExprDomains() to possibly tighten auxvar bounds
5986  * - calls separation initialization callback of nlhdlrs
5987  */
5988 static
5990  SCIP* scip, /**< SCIP data structure */
5991  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
5992  SCIP_CONS** conss, /**< constraints */
5993  int nconss, /**< number of constraints */
5994  SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
5995  )
5996 {
5997  SCIP_CONSDATA* consdata;
5998  SCIP_CONSHDLRDATA* conshdlrdata;
5999  SCIP_EXPRITER* it;
6000  SCIP_EXPR* expr;
6001  SCIP_RESULT result;
6002  SCIP_VAR* auxvar;
6003  int nreductions = 0;
6004  int c, e;
6005 
6006  assert(scip != NULL);
6007  assert(conshdlr != NULL);
6008  assert(conss != NULL || nconss == 0);
6009  assert(nconss >= 0);
6010  assert(infeasible != NULL);
6011 
6012  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6013  assert(conshdlrdata != NULL);
6014 
6015  /* start with new propbounds (just to be sure, should not be needed) */
6016  ++conshdlrdata->curpropboundstag;
6017 
6018  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6020 
6021  /* first ensure activities are up to date and create auxvars */
6022  *infeasible = FALSE;
6023  for( c = 0; c < nconss; ++c )
6024  {
6025  assert(conss != NULL);
6026  assert(conss[c] != NULL);
6027 
6028  consdata = SCIPconsGetData(conss[c]);
6029  assert(consdata != NULL);
6030  assert(consdata->expr != NULL);
6031 
6032 #ifdef WITH_DEBUG_SOLUTION
6033  if( SCIPdebugIsMainscip(scip) )
6034  {
6035  SCIP_SOL* debugsol;
6036 
6037  SCIP_CALL( SCIPdebugGetSol(scip, &debugsol) );
6038 
6039  if( debugsol != NULL ) /* it can be compiled WITH_DEBUG_SOLUTION, but still no solution given */
6040  {
6041  /* evaluate expression in debug solution, so we can set the solution value of created auxiliary variables
6042  * in createAuxVar()
6043  */
6044  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, debugsol, 0) );
6045  }
6046  }
6047 #endif
6048 
6049  /* ensure we have a valid activity for auxvars and propExprDomains() call below */
6050  SCIP_CALL( SCIPevalExprActivity(scip, consdata->expr) );
6051 
6052  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6053  {
6054  if( SCIPexprGetOwnerData(expr)->nauxvaruses > 0 )
6055  {
6056  SCIP_CALL( createAuxVar(scip, expr) );
6057  }
6058  }
6059 
6060  auxvar = SCIPexprGetOwnerData(consdata->expr)->auxvar;
6061  if( auxvar != NULL )
6062  {
6063  SCIPdebugMsg(scip, "tighten auxvar <%s> bounds using constraint sides [%g,%g]\n",
6064  SCIPvarGetName(auxvar), consdata->lhs, consdata->rhs);
6065  /* change the bounds of the auxiliary variable of the root node to [lhs,rhs] */
6066  SCIP_CALL( SCIPtightenVarLb(scip, auxvar, consdata->lhs, TRUE, infeasible, NULL) );
6067  if( *infeasible )
6068  {
6069  SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar lb (%g) using lhs of constraint (%g)\n", SCIPvarGetLbLocal(auxvar), consdata->lhs);
6070  break;
6071  }
6072 
6073  SCIP_CALL( SCIPtightenVarUb(scip, auxvar, consdata->rhs, TRUE, infeasible, NULL) );
6074  if( *infeasible )
6075  {
6076  SCIPdebugMsg(scip, "infeasibility detected while tightening auxvar ub (%g) using rhs of constraint (%g)\n", SCIPvarGetUbLocal(auxvar), consdata->rhs);
6077  break;
6078  }
6079  }
6080  }
6081 
6082  /* now run a special version of reverseprop to ensure that important bound information (like function domains) is stored in bounds of auxvars,
6083  * since sometimes they cannot be recovered from activity evaluation even after some rounds of domain propagation
6084  * (e.g., log(x*y), which becomes log(w), w=x*y
6085  * log(w) implies w >= 0, but we may not be able to derive bounds on x and y such that w >= 0 is ensured)
6086  */
6087  SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &result, &nreductions) );
6088  if( result == SCIP_CUTOFF )
6089  *infeasible = TRUE;
6090 
6091  /* now call initsepa of nlhdlrs
6092  * TODO skip if !SCIPconsIsInitial(conss[c]) ?
6093  * but at the moment, initSepa() is called from INITLP anyway, so we have SCIPconsIsInitial(conss[c]) anyway
6094  */
6096  for( c = 0; c < nconss && !*infeasible; ++c )
6097  {
6098  assert(conss != NULL);
6099  assert(conss[c] != NULL);
6100 
6101  consdata = SCIPconsGetData(conss[c]);
6102  assert(consdata != NULL);
6103  assert(consdata->expr != NULL);
6104 
6105  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it) && !*infeasible; expr = SCIPexpriterGetNext(it) )
6106  {
6107  SCIP_EXPR_OWNERDATA* ownerdata;
6108 
6109  ownerdata = SCIPexprGetOwnerData(expr);
6110  assert(ownerdata != NULL);
6111 
6112  if( ownerdata->nauxvaruses == 0 )
6113  continue;
6114 
6115  for( e = 0; e < ownerdata->nenfos; ++e )
6116  {
6117  SCIP_NLHDLR* nlhdlr;
6118  SCIP_Bool underestimate;
6119  SCIP_Bool overestimate;
6120  assert(ownerdata->enfos[e] != NULL);
6121 
6122  /* skip if initsepa was already called, e.g., because this expression is also part of a constraint
6123  * which participated in a previous initSepa() call
6124  */
6125  if( ownerdata->enfos[e]->issepainit )
6126  continue;
6127 
6128  /* only call initsepa if it will actually separate */
6129  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
6130  continue;
6131 
6132  nlhdlr = ownerdata->enfos[e]->nlhdlr;
6133  assert(nlhdlr != NULL);
6134 
6135  /* only init sepa if there is an initsepa callback */
6136  if( !SCIPnlhdlrHasInitSepa(nlhdlr) )
6137  continue;
6138 
6139  /* check whether expression needs to be under- or overestimated */
6140  overestimate = ownerdata->nlocksneg > 0;
6141  underestimate = ownerdata->nlockspos > 0;
6142  assert(underestimate || overestimate);
6143 
6144  SCIPdebugMsg(scip, "initsepa under=%u over=%u for expression %p\n", underestimate, overestimate, (void*)expr);
6145 
6146  /* call the separation initialization callback of the nonlinear handler */
6147  SCIP_CALL( SCIPnlhdlrInitsepa(scip, conshdlr, conss[c], nlhdlr, expr,
6148  ownerdata->enfos[e]->nlhdlrexprdata, overestimate, underestimate, infeasible) );
6149  ownerdata->enfos[e]->issepainit = TRUE;
6150 
6151  if( *infeasible )
6152  {
6153  /* stop everything if we detected infeasibility */
6154  SCIPdebugMsg(scip, "detect infeasibility for constraint %s during initsepa()\n", SCIPconsGetName(conss[c]));
6155  break;
6156  }
6157  }
6158  }
6159  }
6160 
6161  SCIPfreeExpriter(&it);
6162 
6163  return SCIP_OKAY;
6164 }
6165 
6166 /** returns whether we are ok to branch on auxiliary variables
6167  *
6168  * Currently returns whether depth of node in B&B tree is at least value of constraints/nonlinear/branching/aux parameter.
6169  */
6170 static
6172  SCIP* scip, /**< SCIP data structure */
6173  SCIP_CONSHDLR* conshdlr /**< constraint handler */
6174  )
6175 {
6176  SCIP_CONSHDLRDATA* conshdlrdata;
6177 
6178  assert(conshdlr != NULL);
6179 
6180  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6181  assert(conshdlrdata != NULL);
6182 
6183  return conshdlrdata->branchauxmindepth <= SCIPgetDepth(scip);
6184 }
6185 
6186 /** gets weight of variable when splitting violation score onto several variables in an expression */
6187 static
6189  SCIP* scip, /**< SCIP data structure */
6190  SCIP_CONSHDLR* conshdlr, /**< expr constraint handler */
6191  SCIP_VAR* var, /**< variable */
6192  SCIP_SOL* sol /**< current solution */
6193  )
6194 {
6195  SCIP_CONSHDLRDATA* conshdlrdata;
6196 
6197  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6198  assert(conshdlrdata != NULL);
6199 
6200  switch( conshdlrdata->branchviolsplit )
6201  {
6202  case 'u' : /* uniform: everyone gets the same score */
6203  return 1.0;
6204 
6205  case 'm' : /* midness of solution: 0.5 if in middle of domain, 0.05 if close to lower or upper bound */
6206  {
6207  SCIP_Real weight;
6208  weight = MIN(SCIPgetSolVal(scip, sol, var) - SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var) - SCIPgetSolVal(scip, sol, var)) / (SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
6209  return MAX(0.05, weight);
6210  }
6211 
6212  case 'd' : /* domain width */
6213  return SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6214 
6215  case 'l' : /* logarithmic domain width: log-scale if width is below 0.1 or above 10, otherwise actual width */
6216  {
6217  SCIP_Real width = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6218  assert(width > 0.0);
6219  if( width > 10.0 )
6220  return 10.0*log10(width);
6221  if( width < 0.1 )
6222  return 0.1/(-log10(width));
6223  return width;
6224  }
6225 
6226  default :
6227  SCIPerrorMessage("invalid value for parameter constraints/expr/branching/violsplit");
6228  SCIPABORT();
6229  return SCIP_INVALID;
6230  }
6231 }
6232 
6233 /** adds violation-branching score to a set of expressions, thereby distributing the score
6234  *
6235  * Each expression must either be a variable expression or have an aux-variable.
6236  *
6237  * If unbounded variables are present, each unbounded var gets an even score.
6238  * If no unbounded variables, then parameter constraints/nonlinear/branching/violsplit decides weight for each var.
6239  */
6240 static
6241 void addExprsViolScore(
6242  SCIP* scip, /**< SCIP data structure */
6243  SCIP_EXPR** exprs, /**< expressions where to add branching score */
6244  int nexprs, /**< number of expressions */
6245  SCIP_Real violscore, /**< violation-branching score to add to expression */
6246  SCIP_SOL* sol, /**< current solution */
6247  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6248  )
6249 {
6250  SCIP_CONSHDLR* conshdlr;
6251  SCIP_VAR* var;
6252  SCIP_Real weight;
6253  SCIP_Real weightsum = 0.0; /* sum of weights over all candidates with bounded domain */
6254  int nunbounded = 0; /* number of candidates with unbounded domain */
6255  int i;
6256 
6257  assert(exprs != NULL);
6258  assert(nexprs > 0);
6259  assert(success != NULL);
6260 
6261  if( nexprs == 1 )
6262  {
6263  SCIPaddExprViolScoreNonlinear(scip, exprs[0], violscore);
6264  SCIPdebugMsg(scip, "add score %g to <%s>[%g,%g]\n", violscore,
6266  *success = TRUE;
6267  return;
6268  }
6269 
6270  conshdlr = SCIPexprGetOwnerData(exprs[0])->conshdlr;
6271 
6272  for( i = 0; i < nexprs; ++i )
6273  {
6274  var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6275  assert(var != NULL);
6276 
6277  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6278  ++nunbounded;
6279  else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6280  weightsum += getViolSplitWeight(scip, conshdlr, var, sol);
6281  }
6282 
6283  *success = FALSE;
6284  for( i = 0; i < nexprs; ++i )
6285  {
6286  var = SCIPgetExprAuxVarNonlinear(exprs[i]);
6287  assert(var != NULL);
6288 
6289  if( nunbounded > 0 )
6290  {
6291  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6292  {
6293  SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore / nunbounded);
6294  SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore / nunbounded,
6295  100.0/nunbounded, violscore,
6297  *success = TRUE;
6298  }
6299  }
6300  else if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6301  {
6302  assert(weightsum > 0.0);
6303 
6304  weight = getViolSplitWeight(scip, conshdlr, var, sol);
6305  SCIPaddExprViolScoreNonlinear(scip, exprs[i], violscore * weight / weightsum);
6306  SCIPdebugMsg(scip, "add score %g (%g%% of %g) to <%s>[%g,%g]\n", violscore * weight / weightsum,
6307  100*weight / weightsum, violscore,
6309  *success = TRUE;
6310  }
6311  else
6312  {
6313  SCIPdebugMsg(scip, "skip score for fixed variable <%s>[%g,%g]\n",
6315  }
6316  }
6317 }
6318 
6319 /** adds violation-branching score to children of expression for given auxiliary variables
6320  *
6321  * Iterates over the successors of `expr` to find expressions that are associated with one of the given auxiliary variables.
6322  * Adds violation-branching scores to all found exprs by means of SCIPaddExprsViolScoreNonlinear().
6323  *
6324  * @note This method may modify the given auxvars array by means of sorting.
6325  */
6326 static
6328  SCIP* scip, /**< SCIP data structure */
6329  SCIP_EXPR* expr, /**< expression where to start searching */
6330  SCIP_Real violscore, /**< violation score to add to expression */
6331  SCIP_VAR** auxvars, /**< auxiliary variables for which to find expression */
6332  int nauxvars, /**< number of auxiliary variables */
6333  SCIP_SOL* sol, /**< current solution (NULL for the LP solution) */
6334  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
6335  )
6336 {
6337  SCIP_EXPRITER* it;
6338  SCIP_VAR* auxvar;
6339  SCIP_EXPR** exprs;
6340  int nexprs;
6341  int pos;
6342 
6343  assert(scip != NULL);
6344  assert(expr != NULL);
6345  assert(auxvars != NULL);
6346  assert(success != NULL);
6347 
6348  /* sort variables to make lookup below faster */
6349  SCIPsortPtr((void**)auxvars, SCIPvarComp, nauxvars);
6350 
6351  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6353 
6354  SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nauxvars) );
6355  nexprs = 0;
6356 
6357  for( expr = SCIPexpriterGetNext(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6358  {
6359  auxvar = SCIPgetExprAuxVarNonlinear(expr);
6360  if( auxvar == NULL )
6361  continue;
6362 
6363  /* if auxvar of expr is contained in auxvars array, add branching score to expr */
6364  if( SCIPsortedvecFindPtr((void**)auxvars, SCIPvarComp, auxvar, nauxvars, &pos) )
6365  {
6366  assert(auxvars[pos] == auxvar);
6367 
6368  SCIPdebugMsg(scip, "adding branchingscore for expr %p with auxvar <%s>\n", (void*)expr, SCIPvarGetName(auxvar));
6369  exprs[nexprs++] = expr;
6370 
6371  if( nexprs == nauxvars )
6372  break;
6373  }
6374  }
6375 
6376  SCIPfreeExpriter(&it);
6377 
6378  if( nexprs > 0 )
6379  {
6380  SCIP_CALL( SCIPaddExprsViolScoreNonlinear(scip, exprs, nexprs, violscore, sol, success) );
6381  }
6382  else
6383  *success = FALSE;
6384 
6385  SCIPfreeBufferArray(scip, &exprs);
6386 
6387  return SCIP_OKAY;
6388 }
6389 
6390 /** registers all unfixed variables in violated constraints as branching candidates */
6391 static
6393  SCIP* scip, /**< SCIP data structure */
6394  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6395  SCIP_CONS** conss, /**< constraints */
6396  int nconss, /**< number of constraints */
6397  int* nnotify /**< counter for number of notifications performed */
6398  )
6399 {
6400  SCIP_CONSDATA* consdata;
6401  SCIP_VAR* var;
6402  int c;
6403  int i;
6404 
6405  assert(conshdlr != NULL);
6406  assert(conss != NULL || nconss == 0);
6407  assert(nnotify != NULL);
6408 
6409  *nnotify = 0;
6410 
6411  for( c = 0; c < nconss; ++c )
6412  {
6413  assert(conss != NULL && conss[c] != NULL);
6414 
6415  consdata = SCIPconsGetData(conss[c]);
6416  assert(consdata != NULL);
6417 
6418  /* consider only violated constraints */
6419  if( !isConsViolated(scip, conss[c]) )
6420  continue;
6421 
6422  /* register all variables that have not been fixed yet */
6423  assert(consdata->varexprs != NULL);
6424  for( i = 0; i < consdata->nvarexprs; ++i )
6425  {
6426  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6427  assert(var != NULL);
6428 
6429  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6430  {
6432  ++(*nnotify);
6433  }
6434  }
6435  }
6436 
6437  return SCIP_OKAY;
6438 }
6439 
6440 /** registers all variables in violated constraints with branching scores as external branching candidates */
6441 static
6443  SCIP* scip, /**< SCIP data structure */
6444  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6445  SCIP_CONS** conss, /**< constraints */
6446  int nconss, /**< number of constraints */
6447  SCIP_Bool* success /**< buffer to store whether at least one branching candidate was added */
6448  )
6449 {
6450  SCIP_CONSDATA* consdata;
6451  SCIP_EXPRITER* it = NULL;
6452  int c;
6453 
6454  assert(conshdlr != NULL);
6455  assert(success != NULL);
6456 
6457  *success = FALSE;
6458 
6459  if( branchAuxNonlinear(scip, conshdlr) )
6460  {
6461  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6463  }
6464 
6465  /* register external branching candidates */
6466  for( c = 0; c < nconss; ++c )
6467  {
6468  assert(conss != NULL && conss[c] != NULL);
6469 
6470  consdata = SCIPconsGetData(conss[c]);
6471  assert(consdata != NULL);
6472  assert(consdata->varexprs != NULL);
6473 
6474  /* consider only violated constraints */
6475  if( !isConsViolated(scip, conss[c]) )
6476  continue;
6477 
6478  if( !branchAuxNonlinear(scip, conshdlr) )
6479  {
6480  int i;
6481 
6482  /* if not branching on auxvars, then violation-branching scores will have been added to original variables
6483  * only, so we can loop over variable expressions
6484  */
6485  for( i = 0; i < consdata->nvarexprs; ++i )
6486  {
6487  SCIP_Real violscore;
6488  SCIP_Real lb;
6489  SCIP_Real ub;
6490  SCIP_VAR* var;
6491 
6492  violscore = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6493 
6494  /* skip variable expressions that do not have a violation score */
6495  if( violscore == 0.0 )
6496  continue;
6497 
6498  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6499  assert(var != NULL);
6500 
6501  lb = SCIPvarGetLbLocal(var);
6502  ub = SCIPvarGetUbLocal(var);
6503 
6504  /* consider variable for branching if it has not been fixed yet */
6505  if( !SCIPisEQ(scip, lb, ub) )
6506  {
6507  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6508  SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6509  *success = TRUE;
6510  }
6511  else
6512  {
6513  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6514  }
6515 
6516  /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6517  * several times as external branching candidate, see SCIPgetExprViolScoreNonlinear()
6518  */
6519  SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6520  }
6521  }
6522  else
6523  {
6524  SCIP_EXPR* expr;
6525  SCIP_VAR* var;
6526  SCIP_Real lb;
6527  SCIP_Real ub;
6528  SCIP_Real violscore;
6529 
6530  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6531  {
6532  violscore = SCIPgetExprViolScoreNonlinear(expr);
6533  if( violscore == 0.0 )
6534  continue;
6535 
6536  /* if some nlhdlr added a branching score for this expression, then it considered this expression as a
6537  * variable, so this expression should either be an original variable or have an auxiliary variable
6538  */
6539  var = SCIPgetExprAuxVarNonlinear(expr);
6540  assert(var != NULL);
6541 
6542  lb = SCIPvarGetLbLocal(var);
6543  ub = SCIPvarGetUbLocal(var);
6544 
6545  /* consider variable for branching if it has not been fixed yet */
6546  if( !SCIPisEQ(scip, lb, ub) )
6547  {
6548  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " add variable <%s>[%g,%g] as extern branching candidate with score %g\n", SCIPvarGetName(var), lb, ub, violscore); )
6549 
6550  SCIP_CALL( SCIPaddExternBranchCand(scip, var, violscore, SCIP_INVALID) );
6551  *success = TRUE;
6552  }
6553  else
6554  {
6555  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6556  }
6557  }
6558  }
6559  }
6560 
6561  if( it != NULL )
6562  SCIPfreeExpriter(&it);
6563 
6564  return SCIP_OKAY;
6565 }
6566 
6567 /** collect branching candidates from violated constraints
6568  *
6569  * Fills array with expressions that serve as branching candidates.
6570  * Collects those expressions that have a branching score assigned and stores the score in the auxviol field of the
6571  * branching candidate.
6572  *
6573  * If branching on aux-variables is allowed, then iterate through expressions of violated constraints, otherwise iterate
6574  * through variable-expressions only.
6575  */
6576 static
6578  SCIP* scip, /**< SCIP data structure */
6579  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6580  SCIP_CONS** conss, /**< constraints to process */
6581  int nconss, /**< number of constraints */
6582  SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
6583  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6584  SCIP_Longint soltag, /**< tag of solution */
6585  BRANCHCAND* cands, /**< array where to store candidates, must be at least SCIPgetNVars() long */
6586  int* ncands /**< number of candidates found */
6587  )
6588 {
6589  SCIP_CONSHDLRDATA* conshdlrdata;
6590  SCIP_CONSDATA* consdata;
6591  SCIP_EXPRITER* it = NULL;
6592  int c;
6593  int attempt;
6594  SCIP_VAR* var;
6595 
6596  assert(scip != NULL);
6597  assert(conshdlr != NULL);
6598  assert(cands != NULL);
6599  assert(ncands != NULL);
6600 
6601  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6602  assert(conshdlrdata != NULL);
6603 
6604  if( branchAuxNonlinear(scip, conshdlr) )
6605  {
6606  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
6608  }
6609 
6610  *ncands = 0;
6611  for( attempt = 0; attempt < 2; ++attempt )
6612  {
6613  /* collect branching candidates from violated constraints
6614  * in the first attempt, consider only constraints with large violation
6615  * in the second attempt, consider all remaining violated constraints
6616  */
6617  for( c = 0; c < nconss; ++c )
6618  {
6619  SCIP_Real consviol;
6620 
6621  assert(conss != NULL && conss[c] != NULL);
6622 
6623  /* consider only violated constraints */
6624  if( !isConsViolated(scip, conss[c]) )
6625  continue;
6626 
6627  consdata = SCIPconsGetData(conss[c]);
6628  assert(consdata != NULL);
6629  assert(consdata->varexprs != NULL);
6630 
6631  SCIP_CALL( getConsRelViolation(scip, conss[c], &consviol, sol, soltag) );
6632 
6633  if( attempt == 0 && consviol < conshdlrdata->branchhighviolfactor * maxrelconsviol )
6634  continue;
6635  else if( attempt == 1 && consviol >= conshdlrdata->branchhighviolfactor * maxrelconsviol )
6636  continue;
6637 
6638  if( !branchAuxNonlinear(scip, conshdlr) )
6639  {
6640  int i;
6641 
6642  /* if not branching on auxvars, then violation-branching scores will be available for original variables
6643  * only, so we can loop over variable expressions
6644  * unfortunately, we don't know anymore which constraint contributed the violation-branching score to the
6645  * variable, therefore we invalidate the score of a variable after processing it.
6646  */
6647  for( i = 0; i < consdata->nvarexprs; ++i )
6648  {
6649  SCIP_Real lb;
6650  SCIP_Real ub;
6651 
6652  /* skip variable expressions that do not have a valid violation score */
6653  if( conshdlrdata->enforound != SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag )
6654  continue;
6655 
6656  var = SCIPgetVarExprVar(consdata->varexprs[i]);
6657  assert(var != NULL);
6658 
6659  lb = SCIPvarGetLbLocal(var);
6660  ub = SCIPvarGetUbLocal(var);
6661 
6662  /* skip already fixed variable */
6663  if( SCIPisEQ(scip, lb, ub) )
6664  {
6665  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6666  continue;
6667  }
6668 
6669  assert(*ncands + 1 < SCIPgetNVars(scip));
6670  cands[*ncands].expr = consdata->varexprs[i];
6671  cands[*ncands].var = var;
6672  cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(consdata->varexprs[i]);
6673  ++(*ncands);
6674 
6675  /* invalidate violscore-tag, so that we do not register variables that appear in multiple constraints
6676  * several times as external branching candidate */
6677  SCIPexprGetOwnerData(consdata->varexprs[i])->violscoretag = 0;
6678  }
6679  }
6680  else
6681  {
6682  SCIP_EXPR* expr;
6683  SCIP_Real lb;
6684  SCIP_Real ub;
6685 
6686  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
6687  {
6688  if( SCIPexprGetOwnerData(expr)->violscoretag != conshdlrdata->enforound )
6689  continue;
6690 
6691  /* if some nlhdlr added a branching score for this expression, then it considered this expression as
6692  * variables, so this expression should either be an original variable or have an auxiliary variable
6693  */
6694  var = SCIPgetExprAuxVarNonlinear(expr);
6695  assert(var != NULL);
6696 
6697  lb = SCIPvarGetLbLocal(var);
6698  ub = SCIPvarGetUbLocal(var);
6699 
6700  /* skip already fixed variable */
6701  if( SCIPisEQ(scip, lb, ub) )
6702  {
6703  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip fixed variable <%s>[%.15g,%.15g]\n", SCIPvarGetName(var), lb, ub); )
6704  continue;
6705  }
6706 
6707  assert(*ncands + 1 < SCIPgetNVars(scip));
6708  cands[*ncands].expr = expr;
6709  cands[*ncands].var = var;
6710  cands[*ncands].auxviol = SCIPgetExprViolScoreNonlinear(expr);
6711  ++(*ncands);
6712  }
6713  }
6714  }
6715 
6716  /* if we have branching candidates, then we don't need another attempt */
6717  if( *ncands > 0 )
6718  break;
6719  }
6720 
6721  if( it != NULL )
6722  SCIPfreeExpriter(&it);
6723 
6724  return SCIP_OKAY;
6725 }
6726 
6727 /** computes a branching score for a variable that reflects how important branching on this variable would be for
6728  * improving the dual bound from the LP relaxation
6729  *
6730  * Assume the Lagrangian for the current LP is something of the form
6731  * L(x,z,lambda) = c'x + sum_i lambda_i (a_i'x - z_i + b_i) + ...
6732  * where x are the original variables, z the auxiliary variables,
6733  * and a_i'x - z_i + b_i <= 0 are the rows of the LP.
6734  *
6735  * Assume that a_i'x + b_i <= z_i was derived from some nonlinear constraint f(x) <= z and drop index i.
6736  * If we could have used not only an estimator, but the actual function f(x), then this would
6737  * have contributed lambda*(f(x) - z) to the Lagrangian function (though the value of z would be different).
6738  * Using a lot of handwaving, we claim that
6739  * lambda_i * (f(x) - a_i'x + b_i)
6740  * is a value that can be used to quantity how much improving the estimator a'x + b <= z could change the dual bound.
6741  * If an estimator depended on local bounds, then it could be improved by branching.
6742  * We use row-is-local as proxy for estimator-depending-on-lower-bounds.
6743  *
6744  * 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.
6745  * To scale, we divide by the LP objective value (if >1).
6746  *
6747  * TODO if we branch only on original variables, we neglect here estimators that are build on auxiliary variables;
6748  * these are affected by the bounds on original variables indirectly (through forward-propagation)
6749  *
6750  * TODO if we branch also on auxiliary variables, then separating z from the x-variables in the row a'x+b <= z should happen;
6751  * in effect, we should go from the row to the expression for which it was generated and consider only variables that
6752  * would also be branching candidates
6753  */
6754 static
6756  SCIP* scip, /**< SCIP data structure */
6757  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
6758  SCIP_VAR* var /**< variable */
6759  )
6760 {
6761  SCIP_COL* col;
6762  SCIP_ROW** rows;
6763  int nrows;
6764  int r;
6765  SCIP_Real dualscore;
6766 
6767  assert(scip != NULL);
6768  assert(conshdlr != NULL);
6769  assert(var != NULL);
6770 
6771  /* if LP not solved, then the dual branching score is not available */
6773  return 0.0;
6774 
6775  /* if var is not in the LP, then the dual branching score is not available */
6777  return 0.0;
6778 
6779  col = SCIPvarGetCol(var);
6780  assert(col != NULL);
6781 
6782  if( !SCIPcolIsInLP(col) )
6783  return 0.0;
6784 
6785  nrows = SCIPcolGetNLPNonz(col); /* TODO there is a big warning on when not to use this method; is the check for SCIPcolIsInLP sufficient? */
6786  rows = SCIPcolGetRows(col);
6787 
6788  /* SCIPinfoMessage(scip, enfologfile, " dualscoring <%s>\n", SCIPvarGetName(var)); */
6789 
6790  /* aggregate duals from all rows from consexpr with non-zero dual
6791  * TODO: this is a quick-and-dirty implementation, and not used by default
6792  * in the long run, this should be either removed or replaced by a proper implementation
6793  */
6794  dualscore = 0.0;
6795  for( r = 0; r < nrows; ++r )
6796  {
6797  SCIP_Real estimategap;
6798  const char* estimategapstr;
6799 
6800  /* rows from cuts that may be replaced by tighter ones after branching are the interesting ones
6801  * these would typically be local, unless they are created at the root node
6802  * so not check for local now, but trust that estimators that do not improve after branching will have an estimategap of 0
6803  if( !SCIProwIsLocal(rows[r]) )
6804  continue;
6805  */
6806  if( SCIProwGetOriginConshdlr(rows[r]) != conshdlr )
6807  continue;
6808  if( SCIPisZero(scip, SCIProwGetDualsol(rows[r])) )
6809  continue;
6810 
6811  estimategapstr = strstr(SCIProwGetName(rows[r]), "_estimategap=");
6812  if( estimategapstr == NULL ) /* gap not stored, maybe because it was 0 */
6813  continue;
6814  estimategap = atof(estimategapstr + 13);
6815  assert(estimategap >= 0.0);
6816  if( !SCIPisFinite(estimategap) || SCIPisHugeValue(scip, estimategap) )
6817  estimategap = SCIPgetHugeValue(scip);
6818 
6819  /* SCIPinfoMessage(scip, enfologfile, " row <%s> contributes %g*|%g|: ", SCIProwGetName(rows[r]), estimategap, SCIProwGetDualsol(rows[r]));
6820  SCIP_CALL( SCIPprintRow(scip, rows[r], enfologfile) ); */
6821 
6822  dualscore += estimategap * REALABS(SCIProwGetDualsol(rows[r]));
6823  }
6824 
6825  /* divide by optimal value of LP for scaling */
6826  dualscore /= MAX(1.0, REALABS(SCIPgetLPObjval(scip)));
6827 
6828  return dualscore;
6829 }
6830 
6831 /** computes branching scores (including weighted score) for a set of candidates
6832  *
6833  * For each candidate in the array, compute and store the various branching scores (violation, pseudo-costs, vartype, domainwidth).
6834  * For pseudo-costs, it's possible that the score is not available, in which case cands[c].pscost will be set to SCIP_INVALID.
6835  *
6836  * For each score, compute the maximum over all candidates.
6837  *
6838  * Then compute for each candidate a "weighted" score using the weights as specified by parameters
6839  * and the scores as previously computed, but scale each score to be in [0,1], i.e., divide each score by the maximum
6840  * score of all candidates.
6841  * Further divide by the sum of all weights where a score was available (even if the score was 0).
6842  *
6843  * For example:
6844  * - Let variable x have violation-score 10.0 and pseudo-cost-score 5.0.
6845  * - Let variable y have violation-score 12.0 but no pseudo-cost-score (because it hasn't yet been branched on sufficiently often).
6846  * - Assuming violation is weighted by 2.0 and pseudo-costs are weighted by 3.0.
6847  * - 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.
6848  * The weighted score for y will be (2.0 * 12.0/12.0) / 2.0 = 1.0.
6849  */
6850 static
6852  SCIP* scip, /**< SCIP data structure */
6853  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6854  BRANCHCAND* cands, /**< branching candidates */
6855  int ncands, /**< number of candidates */
6856  SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
6857  SCIP_SOL* sol /**< solution to enforce (NULL for the LP solution) */
6858  )
6859 {
6860  SCIP_CONSHDLRDATA* conshdlrdata;
6861  BRANCHCAND maxscore;
6862  int c;
6863 
6864  assert(scip != NULL);
6865  assert(conshdlr != NULL);
6866  assert(cands != NULL);
6867  assert(ncands > 0);
6868 
6869  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6870  assert(conshdlrdata != NULL);
6871 
6872  /* initialize counts to 0 */
6873  memset(&maxscore, 0, sizeof(BRANCHCAND));
6874 
6875  for( c = 0; c < ncands; ++c )
6876  {
6877  if( conshdlrdata->branchviolweight > 0.0 )
6878  {
6879  /* cands[c].auxviol was set in collectBranchingCandidates, so only update maxscore here */
6880  maxscore.auxviol = MAX(maxscore.auxviol, cands[c].auxviol);
6881  }
6882 
6883  if( conshdlrdata->branchfracweight > 0.0 && SCIPvarGetType(cands[c].var) <= SCIP_VARTYPE_INTEGER )
6884  {
6885  /* when collecting for branching on fractionality (cands[c].expr == NULL), only fractional integer variables
6886  * should appear as candidates here and their fractionality should have been recorded in branchingIntegralOrNonlinear
6887  */
6888  assert(cands[c].expr != NULL || cands[c].fractionality > 0.0);
6889 
6890  if( considerfracnl && cands[c].fractionality == 0.0 )
6891  {
6892  /* for an integer variable that is subject to spatial branching, we also record the fractionality (but separately from auxviol)
6893  * if considerfracnl is TRUE; this way, we can give preference to fractional integer nonlinear variables
6894  */
6895  SCIP_Real solval;
6896  SCIP_Real rounded;
6897 
6898  solval = SCIPgetSolVal(scip, NULL, cands[c].var);
6899  rounded = SCIPround(scip, solval);
6900 
6901  cands[c].fractionality = REALABS(solval - rounded);
6902  }
6903 
6904  maxscore.fractionality = MAX(cands[c].fractionality, maxscore.fractionality);
6905  }
6906  else
6907  cands[c].fractionality = 0.0;
6908 
6909  if( conshdlrdata->branchdomainweight > 0.0 && cands[c].expr != NULL )
6910  {
6911  SCIP_Real domainwidth;
6912  SCIP_VAR* var;
6913 
6914  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6915  assert(var != NULL);
6916 
6917  /* get domain width, taking infinity at 1e20 on purpose */
6918  domainwidth = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
6919 
6920  /* domain-score is going to be log(2*infinity / domainwidth) if domain width >= 1
6921  * and log(2 * infinity * MAX(epsilon, domainwidth)) for domain width < 1
6922  * the idea is to penalize very large and very small domains
6923  */
6924  if( domainwidth >= 1.0 )
6925  cands[c].domain = log10(2 * SCIPinfinity(scip) / domainwidth);
6926  else
6927  cands[c].domain = log10(2 * SCIPinfinity(scip) * MAX(SCIPepsilon(scip), domainwidth));
6928 
6929  maxscore.domain = MAX(cands[c].domain, maxscore.domain);
6930  }
6931  else
6932  cands[c].domain = 0.0;
6933 
6934  if( conshdlrdata->branchdualweight > 0.0 && cands[c].expr != NULL )
6935  {
6936  SCIP_VAR* var;
6937 
6938  var = SCIPgetExprAuxVarNonlinear(cands[c].expr);
6939  assert(var != NULL);
6940 
6941  cands[c].dual = getDualBranchscore(scip, conshdlr, var);
6942  maxscore.dual = MAX(cands[c].dual, maxscore.dual);
6943  }
6944  else
6945  cands[c].dual = 0.0;
6946 
6947  if( conshdlrdata->branchpscostweight > 0.0 && SCIPgetNObjVars(scip) > 0 )
6948  {
6949  SCIP_VAR* var;
6950 
6951  var = cands[c].var;
6952  assert(var != NULL);
6953 
6954  if( cands[c].expr != NULL )
6955  {
6956  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6957  cands[c].pscost = SCIP_INVALID;
6958  else
6959  {
6960  SCIP_Real brpoint;
6961  SCIP_Real pscostdown;
6962  SCIP_Real pscostup;
6963  char strategy;
6964 
6965  /* decide how to compute pseudo-cost scores
6966  * this should be consistent with the way how pseudo-costs are updated in the core, which is decided by
6967  * branching/lpgainnormalize for continuous variables and move in LP-value for non-continuous variables
6968  */
6970  strategy = conshdlrdata->branchpscostupdatestrategy;
6971  else
6972  strategy = 'l';
6973 
6974  brpoint = SCIPgetBranchingPoint(scip, var, SCIP_INVALID);
6975 
6976  /* branch_relpscost deems pscosts as reliable, if the pseudo-count is at least something between 1 and 4
6977  * or it uses some statistical tests involving SCIPisVarPscostRelerrorReliable
6978  * For here, I use a simple #counts >= branchpscostreliable.
6979  * TODO use SCIPgetVarPseudocostCount() instead?
6980  */
6981  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
6982  {
6983  switch( strategy )
6984  {
6985  case 's' :
6986  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint)));
6987  break;
6988  case 'd' :
6989  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var)));
6990  break;
6991  case 'l' :
6992  if( SCIPisInfinity(scip, SCIPgetSolVal(scip, sol, var)) )
6993  pscostdown = SCIP_INVALID;
6994  else if( SCIPgetSolVal(scip, sol, var) <= SCIPadjustedVarUb(scip, var, brpoint) )
6995  pscostdown = SCIPgetVarPseudocostVal(scip, var, 0.0);
6996  else
6997  pscostdown = SCIPgetVarPseudocostVal(scip, var, -(SCIPgetSolVal(scip, NULL, var) - SCIPadjustedVarUb(scip, var, brpoint)));
6998  break;
6999  default :
7000  SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7001  pscostdown = SCIP_INVALID;
7002  }
7003  }
7004  else
7005  pscostdown = SCIP_INVALID;
7006 
7007  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7008  {
7009  switch( strategy )
7010  {
7011  case 's' :
7012  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarUb(scip, var, brpoint) - SCIPvarGetLbLocal(var));
7013  break;
7014  case 'd' :
7015  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPvarGetUbLocal(var) - SCIPadjustedVarLb(scip, var, brpoint));
7016  break;
7017  case 'l' :
7018  if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, sol, var)) )
7019  pscostup = SCIP_INVALID;
7020  else if( SCIPgetSolVal(scip, NULL, var) >= SCIPadjustedVarLb(scip, var, brpoint) )
7021  pscostup = SCIPgetVarPseudocostVal(scip, var, 0.0);
7022  else
7023  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPadjustedVarLb(scip, var, brpoint) - SCIPgetSolVal(scip, NULL, var) );
7024  break;
7025  default :
7026  SCIPerrorMessage("pscost update strategy %c unknown\n", strategy);
7027  pscostup = SCIP_INVALID;
7028  }
7029  }
7030  else
7031  pscostup = SCIP_INVALID;
7032 
7033  /* TODO if both are valid, we get pscostdown*pscostup, but does this compare well with vars were only pscostdown or pscostup is used?
7034  * maybe we should use (pscostdown+pscostup)/2 or sqrt(pscostdown*pscostup) ?
7035  */
7036  if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7037  cands[c].pscost = SCIP_INVALID;
7038  else if( pscostdown == SCIP_INVALID )
7039  cands[c].pscost = pscostup;
7040  else if( pscostup == SCIP_INVALID )
7041  cands[c].pscost = pscostdown;
7042  else
7043  cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7044  }
7045  }
7046  else
7047  {
7048  SCIP_Real pscostdown;
7049  SCIP_Real pscostup;
7050  SCIP_Real solval;
7051 
7052  solval = SCIPgetSolVal(scip, NULL, cands[c].var);
7053 
7054  /* the calculation for pscostdown/up follows SCIPgetVarPseudocostScore(),
7055  * i.e., set solvaldelta to the (negated) difference between variable value and rounded down value for pscostdown
7056  * and different between variable value and rounded up value for pscostup
7057  */
7058  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_DOWNWARDS) >= conshdlrdata->branchpscostreliable )
7059  pscostdown = SCIPgetVarPseudocostVal(scip, var, SCIPfeasCeil(scip, solval - 1.0) - solval);
7060  else
7061  pscostdown = SCIP_INVALID;
7062 
7063  if( SCIPgetVarPseudocostCountCurrentRun(scip, var, SCIP_BRANCHDIR_UPWARDS) >= conshdlrdata->branchpscostreliable )
7064  pscostup = SCIPgetVarPseudocostVal(scip, var, SCIPfeasFloor(scip, solval + 1.0) - solval);
7065  else
7066  pscostup = SCIP_INVALID;
7067 
7068  /* TODO see above for nonlinear variable case */
7069  if( pscostdown == SCIP_INVALID && pscostup == SCIP_INVALID )
7070  cands[c].pscost = SCIP_INVALID;
7071  else if( pscostdown == SCIP_INVALID )
7072  cands[c].pscost = pscostup;
7073  else if( pscostup == SCIP_INVALID )
7074  cands[c].pscost = pscostdown;
7075  else
7076  cands[c].pscost = SCIPgetBranchScore(scip, NULL, pscostdown, pscostup); /* pass NULL for var to avoid multiplication with branch-factor */
7077  }
7078 
7079  if( cands[c].pscost != SCIP_INVALID )
7080  maxscore.pscost = MAX(cands[c].pscost, maxscore.pscost);
7081  }
7082  else
7083  cands[c].pscost = SCIP_INVALID;
7084 
7085  if( conshdlrdata->branchvartypeweight > 0.0 )
7086  {
7087  switch( SCIPvarGetType(cands[c].var) )
7088  {
7089  case SCIP_VARTYPE_BINARY :
7090  cands[c].vartype = 1.0;
7091  break;
7092  case SCIP_VARTYPE_INTEGER :
7093  cands[c].vartype = 0.1;
7094  break;
7095  case SCIP_VARTYPE_IMPLINT :
7096  cands[c].vartype = 0.01;
7097  break;
7099  default:
7100  cands[c].vartype = 0.0;
7101  }
7102  maxscore.vartype = MAX(cands[c].vartype, maxscore.vartype);
7103  }
7104  }
7105 
7106  /* now compute a weighted score for each candidate from the single scores
7107  * the single scores are scaled to be in [0,1] for this
7108  */
7109  for( c = 0; c < ncands; ++c )
7110  {
7111  SCIP_Real weightsum;
7112 
7113  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " scoring <%8s>[%7.1g,%7.1g]:(", SCIPvarGetName(cands[c].var), SCIPvarGetLbLocal(cands[c].var), SCIPvarGetUbLocal(cands[c].var)); )
7114 
7115  cands[c].weighted = 0.0;
7116  weightsum = 0.0;
7117 
7118  if( maxscore.auxviol > 0.0 )
7119  {
7120  cands[c].weighted += conshdlrdata->branchviolweight * cands[c].auxviol / maxscore.auxviol;
7121  weightsum += conshdlrdata->branchviolweight;
7122 
7123  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(viol)", conshdlrdata->branchviolweight, cands[c].auxviol / maxscore.auxviol); )
7124  }
7125 
7126  if( maxscore.fractionality > 0.0 )
7127  {
7128  cands[c].fractionality += conshdlrdata->branchfracweight * cands[c].fractionality / maxscore.fractionality;
7129  weightsum += conshdlrdata->branchfracweight;
7130 
7131  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(frac)", conshdlrdata->branchfracweight, cands[c].fractionality / maxscore.fractionality); )
7132  }
7133 
7134  if( maxscore.domain > 0.0 )
7135  {
7136  cands[c].weighted += conshdlrdata->branchdomainweight * cands[c].domain / maxscore.domain;
7137  weightsum += conshdlrdata->branchdomainweight;
7138 
7139  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(domain)", conshdlrdata->branchdomainweight, cands[c].domain / maxscore.domain); )
7140  }
7141 
7142  if( maxscore.dual > 0.0 )
7143  {
7144  cands[c].weighted += conshdlrdata->branchdualweight * cands[c].dual / maxscore.dual;
7145  weightsum += conshdlrdata->branchdualweight;
7146 
7147  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(dual)", conshdlrdata->branchdualweight, cands[c].dual / maxscore.dual); )
7148  }
7149 
7150  if( maxscore.pscost > 0.0 )
7151  {
7152  /* use pseudo-costs only if available */
7153  if( cands[c].pscost != SCIP_INVALID )
7154  {
7155  cands[c].weighted += conshdlrdata->branchpscostweight * cands[c].pscost / maxscore.pscost;
7156  weightsum += conshdlrdata->branchpscostweight;
7157 
7158  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%7.2g(pscost)", conshdlrdata->branchpscostweight, cands[c].pscost / maxscore.pscost); )
7159  }
7160  else
7161  {
7162  /* do not add pscostscore, if not available, also do not add into weightsum */
7163  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " +0.0* n/a(pscost)"); )
7164  }
7165  }
7166 
7167  if( maxscore.vartype > 0.0 )
7168  {
7169  cands[c].weighted += conshdlrdata->branchvartypeweight * cands[c].vartype / maxscore.vartype;
7170  weightsum += conshdlrdata->branchvartypeweight;
7171 
7172  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %+g*%6.2g(vartype)", conshdlrdata->branchvartypeweight, cands[c].vartype / maxscore.vartype); )
7173  }
7174 
7175  assert(weightsum > 0.0); /* we should have got at least one valid score */
7176  cands[c].weighted /= weightsum;
7177 
7178  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " ) / %g = %g\n", weightsum, cands[c].weighted); )
7179  }
7180 }
7181 
7182 /** compare two branching candidates by their weighted score
7183  *
7184  * if weighted score is equal, use variable index of (aux)var
7185  * if variables are the same, then use whether variable was added due to nonlinearity or fractionality
7186  */
7187 static
7188 SCIP_DECL_SORTINDCOMP(branchcandCompare)
7190  BRANCHCAND* cands = (BRANCHCAND*)dataptr;
7191 
7192  if( cands[ind1].weighted != cands[ind2].weighted )
7193  return cands[ind1].weighted < cands[ind2].weighted ? -1 : 1;
7194 
7195  if( cands[ind1].var != cands[ind2].var )
7196  return SCIPvarGetIndex(cands[ind1].var) - SCIPvarGetIndex(cands[ind2].var);
7197 
7198  return cands[ind1].expr != NULL ? 1 : -1;
7199 }
7200 
7201 /** picks a candidate from array of branching candidates */
7202 static
7204  SCIP* scip, /**< SCIP data structure */
7205  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7206  BRANCHCAND* cands, /**< branching candidates */
7207  int ncands, /**< number of candidates */
7208  SCIP_Bool considerfracnl, /**< whether to consider fractionality for spatial branching candidates */
7209  BRANCHCAND** selected /**< buffer to store selected branching candidates */
7210 )
7211 {
7212  SCIP_CONSHDLRDATA* conshdlrdata;
7213  int* perm;
7214  int c;
7215  int left;
7216  int right;
7217  SCIP_Real threshold;
7218 
7219  assert(cands != NULL);
7220  assert(ncands >= 1);
7221  assert(selected != NULL);
7222 
7223  if( ncands == 1 )
7224  {
7225  *selected = cands;
7226  return SCIP_OKAY;
7227  }
7228 
7229  /* if there are more than one candidate, then compute scores and select */
7230 
7231  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7232  assert(conshdlrdata != NULL);
7233 
7234  /* compute additional scores on branching candidates and weighted score */
7235  scoreBranchingCandidates(scip, conshdlr, cands, ncands, considerfracnl, NULL);
7236 
7237  /* sort candidates by weighted score */
7238  SCIP_CALL( SCIPallocBufferArray(scip, &perm, ncands) );
7239  SCIPsortDown(perm, branchcandCompare, (void*)cands, ncands);
7240 
7241  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g)\n", ncands,
7242  SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7243  SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7244 
7245  /* binary search to find first low-scored (score below branchhighscorefactor * maximal-score) candidate */
7246  left = 0;
7247  right = ncands - 1;
7248  threshold = conshdlrdata->branchhighscorefactor * cands[perm[0]].weighted;
7249  while( left < right )
7250  {
7251  int mid = (left + right) / 2;
7252  if( cands[perm[mid]].weighted >= threshold )
7253  left = mid + 1;
7254  else
7255  right = mid;
7256  }
7257  assert(left <= ncands);
7258 
7259  if( left < ncands )
7260  {
7261  if( cands[perm[left]].weighted >= threshold )
7262  {
7263  assert(left + 1 == ncands || cands[perm[left + 1]].weighted < threshold);
7264  ncands = left + 1;
7265  }
7266  else
7267  {
7268  assert(cands[perm[left]].weighted < threshold);
7269  ncands = left;
7270  }
7271  }
7272  assert(ncands > 0);
7273 
7274  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " %d branching candidates <%s>(%g)...<%s>(%g) after removing low scores\n", ncands,
7275  SCIPvarGetName(cands[perm[0]].var), cands[perm[0]].weighted,
7276  SCIPvarGetName(cands[perm[ncands - 1]].var), cands[perm[ncands - 1]].weighted); )
7277 
7278  if( ncands > 1 )
7279  {
7280  /* choose at random from candidates 0..ncands-1 */
7281  if( conshdlrdata->branchrandnumgen == NULL )
7282  {
7283  SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->branchrandnumgen, BRANCH_RANDNUMINITSEED, TRUE) );
7284  }
7285  c = SCIPrandomGetInt(conshdlrdata->branchrandnumgen, 0, ncands - 1);
7286  *selected = &cands[perm[c]];
7287  }
7288  else
7289  *selected = &cands[perm[0]];
7290 
7291  SCIPfreeBufferArray(scip, &perm);
7292 
7293  return SCIP_OKAY;
7294 }
7295 
7296 /** do spatial branching or register branching candidates */
7297 static
7299  SCIP* scip, /**< SCIP data structure */
7300  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7301  SCIP_CONS** conss, /**< constraints to process */
7302  int nconss, /**< number of constraints */
7303  SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7304  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7305  SCIP_Longint soltag, /**< tag of solution */
7306  SCIP_RESULT* result /**< pointer to store the result of branching */
7307  )
7308 {
7309  SCIP_CONSHDLRDATA* conshdlrdata;
7310  BRANCHCAND* cands;
7311  int ncands;
7312  BRANCHCAND* selected = NULL;
7313  SCIP_NODE* downchild;
7314  SCIP_NODE* eqchild;
7315  SCIP_NODE* upchild;
7316 
7317  assert(conshdlr != NULL);
7318  assert(result != NULL);
7319 
7320  *result = SCIP_DIDNOTFIND;
7321 
7322  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7323  assert(conshdlrdata != NULL);
7324 
7325  if( conshdlrdata->branchexternal )
7326  {
7327  /* just register branching candidates as external */
7328  SCIP_Bool success;
7329 
7330  SCIP_CALL( registerBranchingCandidates(scip, conshdlr, conss, nconss, &success) );
7331  if( success )
7332  *result = SCIP_INFEASIBLE;
7333 
7334  return SCIP_OKAY;
7335  }
7336 
7337  /* collect branching candidates and their auxviol-score */
7338  SCIP_CALL( SCIPallocBufferArray(scip, &cands, SCIPgetNVars(scip)) );
7339  SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, cands, &ncands) );
7340 
7341  /* if no unfixed branching candidate in all violated constraint, then it's probably numerics that prevented us to separate or decide a cutoff
7342  * we will return here and let the fallbacks in consEnfo() decide how to proceed
7343  */
7344  if( ncands == 0 )
7345  goto TERMINATE;
7346 
7347  /* here we include fractionality of integer variables into the branching score
7348  * but if we know there will be no fractional integer variables, then we can shortcut and turn this off
7349  */
7350  SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, SCIPgetNLPBranchCands(scip) > 0, &selected) );
7351  assert(selected != NULL);
7352  assert(selected->expr != NULL);
7353 
7354  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " branching on variable <%s>[%g,%g]\n", SCIPvarGetName(selected->var),
7355  SCIPvarGetLbLocal(selected->var), SCIPvarGetUbLocal(selected->var)); )
7356 
7357  SCIP_CALL( SCIPbranchVarVal(scip, selected->var, SCIPgetBranchingPoint(scip, selected->var, SCIP_INVALID), &downchild, &eqchild,
7358  &upchild) );
7359  if( downchild != NULL || eqchild != NULL || upchild != NULL )
7360  *result = SCIP_BRANCHED;
7361  else
7362  /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
7363  *result = SCIP_REDUCEDDOM;
7364 
7365  TERMINATE:
7366  SCIPfreeBufferArray(scip, &cands);
7367 
7368  return SCIP_OKAY;
7369 }
7370 
7371 /** call enforcement or estimate callback of nonlinear handler
7372  *
7373  * Calls the enforcement callback, if available.
7374  * Otherwise, calls the estimate callback, if available, and constructs a cut from the estimator.
7375  *
7376  * If cut is weak, but estimator is not tight, tries to add branching candidates.
7377  */
7378 static
7380  SCIP* scip, /**< SCIP main data structure */
7381  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7382  SCIP_CONS* cons, /**< nonlinear constraint */
7383  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
7384  SCIP_EXPR* expr, /**< expression */
7385  SCIP_NLHDLREXPRDATA* nlhdlrexprdata, /**< nonlinear handler data of expression */
7386  SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
7387  SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
7388  SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
7389  SCIP_Bool separated, /**< whether another nonlinear handler already added a cut for this expression */
7390  SCIP_Bool allowweakcuts, /**< whether we allow for weak cuts */
7391  SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7392  SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7393  SCIP_RESULT* result /**< pointer to store the result */
7394  )
7395 {
7396  assert(result != NULL);
7397 
7398  /* call enforcement callback of the nlhdlr */
7399  SCIP_CALL( SCIPnlhdlrEnfo(scip, conshdlr, cons, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7400  allowweakcuts, separated, inenforcement, branchcandonly, result) );
7401 
7402  /* if it was not running (e.g., because it was not available) or did not find anything, then try with estimator callback */
7403  if( *result != SCIP_DIDNOTRUN && *result != SCIP_DIDNOTFIND )
7404  {
7405  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> succeeded with result %d\n",
7406  SCIPnlhdlrGetName(nlhdlr), *result); )
7407  return SCIP_OKAY;
7408  }
7409  else
7410  {
7411  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enfo of nlhdlr <%s> did not succeed with result %d\n", SCIPnlhdlrGetName(nlhdlr), *result); )
7412  }
7413 
7414  *result = SCIP_DIDNOTFIND;
7415 
7416  /* now call the estimator callback of the nlhdlr */
7417  if( SCIPnlhdlrHasEstimate(nlhdlr) )
7418  {
7419  SCIP_VAR* auxvar;
7420  SCIP_Bool sepasuccess = FALSE;
7421  SCIP_Bool branchscoresuccess = FALSE;
7422  SCIP_PTRARRAY* rowpreps;
7423  int minidx;
7424  int maxidx;
7425  int r;
7426  SCIP_ROWPREP* rowprep;
7427 
7428  SCIP_CALL( SCIPcreatePtrarray(scip, &rowpreps) );
7429 
7430  auxvar = SCIPgetExprAuxVarNonlinear(expr);
7431  assert(auxvar != NULL);
7432 
7433  SCIP_CALL( SCIPnlhdlrEstimate(scip, conshdlr, nlhdlr, expr, nlhdlrexprdata, sol, auxvalue, overestimate,
7434  SCIPgetSolVal(scip, sol, auxvar), inenforcement, rowpreps, &sepasuccess, &branchscoresuccess) );
7435 
7436  minidx = SCIPgetPtrarrayMinIdx(scip, rowpreps);
7437  maxidx = SCIPgetPtrarrayMaxIdx(scip, rowpreps);
7438 
7439  assert((sepasuccess && minidx <= maxidx) || (!sepasuccess && minidx > maxidx));
7440 
7441  if( !sepasuccess )
7442  {
7443  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s failed\n",
7444  SCIPnlhdlrGetName(nlhdlr)); )
7445  }
7446 
7447  for( r = minidx; r <= maxidx; ++r )
7448  {
7449  rowprep = (SCIP_ROWPREP*) SCIPgetPtrarrayVal(scip, rowpreps, r);
7450 
7451  assert(rowprep != NULL);
7452  assert(SCIProwprepGetSidetype(rowprep) == (overestimate ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT));
7453 
7454  if( !branchcandonly )
7455  {
7456  /* complete estimator to cut */
7457  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, auxvar, -1.0) );
7458 
7459  /* add the cut and/or branching scores
7460  * (branching scores that could be added here are to deal with bad numerics of cuts; we skip these if branchcandonly)
7461  */
7462  SCIP_CALL( SCIPprocessRowprepNonlinear(scip, nlhdlr, cons, expr, rowprep, overestimate, auxvar,
7463  auxvalue, allowweakcuts, branchscoresuccess, inenforcement, sol, result) );
7464  }
7465 
7466  SCIPfreeRowprep(scip, &rowprep);
7467  }
7468 
7469  if( branchcandonly && branchscoresuccess )
7470  {
7471  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s added branching candidates\n", SCIPnlhdlrGetName(nlhdlr)); )
7472  *result = SCIP_BRANCHED;
7473  }
7474 
7475  SCIP_CALL( SCIPfreePtrarray(scip, &rowpreps) );
7476  }
7477 
7478  return SCIP_OKAY;
7479 }
7480 
7481 /** tries to enforce violation in an expression by separation, bound tightening, or finding a branching candidate
7482  *
7483  * if not inenforcement, then we should be called by consSepa(), and thus only try separation
7484  */
7485 static
7487  SCIP* scip, /**< SCIP data structure */
7488  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
7489  SCIP_CONS* cons, /**< nonlinear constraint */
7490  SCIP_EXPR* expr, /**< expression */
7491  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
7492  SCIP_Longint soltag, /**< tag of solution */
7493  SCIP_Bool allowweakcuts, /**< whether we allow weak cuts */
7494  SCIP_Bool inenforcement, /**< whether we are in enforcement (and not just separation) */
7495  SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7496  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7497  )
7498 {
7499  SCIP_CONSHDLRDATA* conshdlrdata;
7500  SCIP_EXPR_OWNERDATA* ownerdata;
7501  SCIP_Real origviol;
7502  SCIP_Bool underestimate;
7503  SCIP_Bool overestimate;
7504  SCIP_Real auxviol;
7505  SCIP_Bool auxunderestimate;
7506  SCIP_Bool auxoverestimate;
7507  SCIP_RESULT hdlrresult;
7508  int e;
7509 
7510  assert(scip != NULL);
7511  assert(expr != NULL);
7512  assert(result != NULL);
7513 
7514  ownerdata = SCIPexprGetOwnerData(expr);
7515  assert(ownerdata != NULL);
7516  assert(ownerdata->auxvar != NULL); /* there must be a variable attached to the expression in order to construct a cut here */
7517 
7518  *result = SCIP_DIDNOTFIND;
7519 
7520  /* make sure that this expression has been evaluated */
7521  SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
7522 
7523  /* decide whether under- or overestimate is required and get amount of violation */
7524  origviol = getExprAbsOrigViolation(scip, expr, sol, &underestimate, &overestimate);
7525 
7526  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7527  assert(conshdlrdata != NULL);
7528 
7529  /* no sufficient violation w.r.t. the original variables -> skip expression */
7530  if( !overestimate && !underestimate )
7531  {
7532  return SCIP_OKAY;
7533  }
7534 
7535  /* check aux-violation w.r.t. each nonlinear handlers and try to enforce when there is a decent violation */
7536  for( e = 0; e < ownerdata->nenfos; ++e )
7537  {
7538  SCIP_NLHDLR* nlhdlr;
7539 
7540  /* skip nlhdlr that do not want to participate in any separation */
7541  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
7542  continue;
7543 
7544  /* if looking for branching candidates only, then skip nlhdlr that wouldn't created branching candidates */
7545  if( branchcandonly && !ownerdata->enfos[e]->sepaaboveusesactivity && !ownerdata->enfos[e]->sepabelowusesactivity )
7546  continue;
7547 
7548  nlhdlr = ownerdata->enfos[e]->nlhdlr;
7549  assert(nlhdlr != NULL);
7550 
7551  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
7552  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
7553  ENFOLOG(
7554  SCIPinfoMessage(scip, enfologfile, " expr ");
7555  SCIPprintExpr(scip, expr, enfologfile);
7556  SCIPinfoMessage(scip, enfologfile, " (%p): evalvalue %.15g auxvarvalue %.15g [%.15g,%.15g], nlhdlr <%s> " \
7557  "auxvalue: %.15g\n", (void*)expr, SCIPexprGetEvalValue(expr), SCIPgetSolVal(scip, sol, ownerdata->auxvar),
7558  SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue);
7559  )
7560 
7561  /* TODO if expr is root of constraint (consdata->expr == expr),
7562  * then compare auxvalue with constraint sides instead of auxvarvalue, as the former is what actually matters
7563  * that is, if auxvalue is good enough for the constraint to be satisfied, but when looking at evalvalue we see
7564  * the the constraint is violated, then some of the auxvars that nlhdlr uses is not having a good enough value,
7565  * so we should enforce in these auxiliaries first
7566  * if changing this here, we must also adapt analyzeViolation()
7567  */
7568 
7569  auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &auxunderestimate, &auxoverestimate);
7570  assert(auxviol >= 0.0);
7571 
7572  /* if aux-violation is much smaller than orig-violation, then better enforce further down in the expression first */
7573  if( !SCIPisInfinity(scip, auxviol) && auxviol < conshdlrdata->enfoauxviolfactor * origviol )
7574  {
7575  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with " \
7576  "auxviolation %g << origviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr,
7577  SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol, origviol, underestimate, overestimate); )
7578 
7579  /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7580  continue;
7581  }
7582 
7583  /* if aux-violation is small (below feastol) and we look only for strong cuts, then it's unlikely to give a strong cut, so skip it */
7584  if( !allowweakcuts && auxviol < SCIPfeastol(scip) )
7585  {
7586  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " skip enforce using nlhdlr <%s> for expr %p (%s) with tiny " \
7587  "auxviolation %g under:%d over:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)), auxviol,
7588  underestimate, overestimate); )
7589 
7590  /* TODO should we do expr->lastenforced = conshdlrdata->enforound even though we haven't enforced, but only decided not to enforce? */
7591  continue;
7592  }
7593 
7594  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforce using nlhdlr <%s> for expr %p (%s) with auxviolation " \
7595  "%g origviolation %g under:%d over:%d weak:%d\n", SCIPnlhdlrGetName(nlhdlr), (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)),
7596  auxviol, origviol, underestimate, overestimate, allowweakcuts); )
7597 
7598  /* if we want to overestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7599  * wants to be called for separation on this side, then call separation of nlhdlr
7600  */
7601  if( overestimate && auxoverestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPAABOVE) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepaaboveusesactivity) )
7602  {
7603  /* call the separation or estimation callback of the nonlinear handler for overestimation */
7604  hdlrresult = SCIP_DIDNOTFIND;
7605  SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7606  ownerdata->enfos[e]->auxvalue, TRUE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7607 
7608  if( hdlrresult == SCIP_CUTOFF )
7609  {
7610  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7611  *result = SCIP_CUTOFF;
7612  ownerdata->lastenforced = conshdlrdata->enforound;
7613  break;
7614  }
7615 
7616  if( hdlrresult == SCIP_SEPARATED )
7617  {
7618  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7619  *result = SCIP_SEPARATED;
7620  ownerdata->lastenforced = conshdlrdata->enforound;
7621  /* TODO or should we give other nlhdlr another chance? (also #3070) */
7622  break;
7623  }
7624 
7625  if( hdlrresult == SCIP_REDUCEDDOM )
7626  {
7627  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7628  *result = SCIP_REDUCEDDOM;
7629  ownerdata->lastenforced = conshdlrdata->enforound;
7630  /* TODO or should we always just stop here? */
7631  }
7632 
7633  if( hdlrresult == SCIP_BRANCHED )
7634  {
7635  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7636  assert(inenforcement);
7637 
7638  /* separation and domain reduction takes precedence over branching */
7639  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7640  if( *result == SCIP_DIDNOTFIND )
7641  *result = SCIP_BRANCHED;
7642  ownerdata->lastenforced = conshdlrdata->enforound;
7643  }
7644  }
7645 
7646  /* if we want to underestimate and violation w.r.t. auxiliary variables is also present on this side and nlhdlr
7647  * wants to be called for separation on this side, then call separation of nlhdlr
7648  */
7649  if( underestimate && auxunderestimate && (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABELOW) != 0 && (!branchcandonly || ownerdata->enfos[e]->sepabelowusesactivity) )
7650  {
7651  /* call the separation or estimation callback of the nonlinear handler for underestimation */
7652  hdlrresult = SCIP_DIDNOTFIND;
7653  SCIP_CALL( enforceExprNlhdlr(scip, conshdlr, cons, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, sol,
7654  ownerdata->enfos[e]->auxvalue, FALSE, *result == SCIP_SEPARATED, allowweakcuts, inenforcement, branchcandonly, &hdlrresult) );
7655 
7656  if( hdlrresult == SCIP_CUTOFF )
7657  {
7658  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " found a cutoff -> stop separation\n"); )
7659  *result = SCIP_CUTOFF;
7660  ownerdata->lastenforced = conshdlrdata->enforound;
7661  break;
7662  }
7663 
7664  if( hdlrresult == SCIP_SEPARATED )
7665  {
7666  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by cut\n", SCIPnlhdlrGetName(nlhdlr)); )
7667  *result = SCIP_SEPARATED;
7668  ownerdata->lastenforced = conshdlrdata->enforound;
7669  /* TODO or should we give other nlhdlr another chance? (also #3070) */
7670  break;
7671  }
7672 
7673  if( hdlrresult == SCIP_REDUCEDDOM )
7674  {
7675  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> separating the current solution by boundchange\n", SCIPnlhdlrGetName(nlhdlr)); )
7676  *result = SCIP_REDUCEDDOM;
7677  ownerdata->lastenforced = conshdlrdata->enforound;
7678  /* TODO or should we always just stop here? */
7679  }
7680 
7681  if( hdlrresult == SCIP_BRANCHED )
7682  {
7683  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> added branching candidate\n", SCIPnlhdlrGetName(nlhdlr)); )
7684  assert(inenforcement);
7685 
7686  /* separation takes precedence over branching */
7687  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED);
7688  if( *result == SCIP_DIDNOTFIND )
7689  *result = SCIP_BRANCHED;
7690  ownerdata->lastenforced = conshdlrdata->enforound;
7691  }
7692  }
7693  }
7694 
7695  return SCIP_OKAY;
7696 }
7697 
7698 /** helper function to enforce a single constraint */
7699 static
7701  SCIP* scip, /**< SCIP data structure */
7702  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7703  SCIP_CONS* cons, /**< constraint to process */
7704  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7705  SCIP_Longint soltag, /**< tag of solution */
7706  SCIP_EXPRITER* it, /**< expression iterator that we can just use here */
7707  SCIP_Bool allowweakcuts, /**< whether to allow weak cuts in this round */
7708  SCIP_Bool inenforcement, /**< whether to we are in enforcement, and not just separation */
7709  SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7710  SCIP_RESULT* result, /**< pointer to update with result of the enforcing call */
7711  SCIP_Bool* success /**< buffer to store whether some enforcement took place */
7712  )
7713 {
7714  SCIP_CONSDATA* consdata;
7715  SCIP_CONSHDLRDATA* conshdlrdata;
7716  SCIP_EXPR* expr;
7717 
7718  assert(conshdlr != NULL);
7719  assert(cons != NULL);
7720  assert(it != NULL);
7721  assert(result != NULL);
7722  assert(success != NULL);
7723 
7724  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7725  assert(conshdlrdata != NULL);
7726 
7727  consdata = SCIPconsGetData(cons);
7728  assert(consdata != NULL);
7729  assert(SCIPexprGetOwnerData(consdata->expr)->nenfos >= 0);
7730 
7731  *success = FALSE;
7732 
7733  if( inenforcement && !branchcandonly && !consdata->ispropagated )
7734  {
7735  /* If there are boundchanges that haven't been propagated to activities yet, then do this now and update bounds of
7736  * auxiliary variables, since some nlhdlr/exprhdlr may look at auxvar bounds or activities
7737  * (TODO: nlhdlr tells us now whether they do and so we could skip).
7738  * For now, update bounds of auxiliary variables only if called from enforcement, since updating auxvar bounds in
7739  * separation doesn't seem to be right (it would be ok if the boundchange cuts off the current LP solution by a
7740  * nice amount, but if not, we may just add a boundchange that doesn't change the dual bound much and could
7741  * confuse the stalling check for how long to do separation).
7742  */
7743  SCIP_Bool infeasible;
7744  int ntightenings;
7745 
7746  SCIP_CALL( forwardPropExpr(scip, conshdlr, consdata->expr, inenforcement, &infeasible, &ntightenings) );
7747  if( infeasible )
7748  {
7749  *result = SCIP_CUTOFF;
7750  return SCIP_OKAY;
7751  }
7752  /* if we tightened an auxvar bound, we better communicate that */
7753  if( ntightenings > 0 )
7754  *result = SCIP_REDUCEDDOM;
7755  }
7756 
7757  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
7758  {
7759  SCIP_EXPR_OWNERDATA* ownerdata;
7760  SCIP_RESULT resultexpr;
7761 
7762  ownerdata = SCIPexprGetOwnerData(expr);
7763  assert(ownerdata != NULL);
7764 
7765  /* we can only enforce if there is an auxvar to compare with */
7766  if( ownerdata->auxvar == NULL )
7767  continue;
7768 
7769  assert(ownerdata->lastenforced <= conshdlrdata->enforound);
7770  if( ownerdata->lastenforced == conshdlrdata->enforound )
7771  {
7772  ENFOLOG(
7773  SCIPinfoMessage(scip, enfologfile, " skip expr ");
7774  SCIPprintExpr(scip, expr, enfologfile);
7775  SCIPinfoMessage(scip, enfologfile, " as already enforced in this enforound\n");
7776  )
7777  *success = TRUE;
7778  continue;
7779  }
7780 
7781  SCIP_CALL( enforceExpr(scip, conshdlr, cons, expr, sol, soltag, allowweakcuts, inenforcement, branchcandonly, &resultexpr) );
7782 
7783  /* if not enforced, then we must not have found a cutoff, cut, domain reduction, or branchscore */
7784  assert((ownerdata->lastenforced == conshdlrdata->enforound) == (resultexpr != SCIP_DIDNOTFIND));
7785  if( ownerdata->lastenforced == conshdlrdata->enforound )
7786  *success = TRUE;
7787 
7788  if( resultexpr == SCIP_CUTOFF )
7789  {
7790  *result = SCIP_CUTOFF;
7791  break;
7792  }
7793 
7794  if( resultexpr == SCIP_SEPARATED )
7795  *result = SCIP_SEPARATED;
7796 
7797  if( resultexpr == SCIP_REDUCEDDOM && *result != SCIP_SEPARATED )
7798  *result = SCIP_REDUCEDDOM;
7799 
7800  if( resultexpr == SCIP_BRANCHED && *result != SCIP_SEPARATED && *result != SCIP_REDUCEDDOM )
7801  *result = SCIP_BRANCHED;
7802  }
7803 
7804  return SCIP_OKAY;
7805 }
7806 
7807 /** try to separate violated constraints and, if in enforcement, register branching scores
7808  *
7809  * If branchcandonly=TRUE, then do not separate or propagate, but register branching scores only.
7810  *
7811  * Sets result to
7812  * - SCIP_DIDNOTFIND, if nothing of the below has been done
7813  * - SCIP_CUTOFF, if node can be cutoff,
7814  * - SCIP_SEPARATED, if a cut has been added,
7815  * - SCIP_REDUCEDDOM, if a domain reduction has been found or a variable got fixed (in an attempt to branch on it),
7816  * - SCIP_BRANCHED, if branching has been done (if branchcandonly=TRUE, then collected branching candidates only),
7817  * - SCIP_INFEASIBLE, if external branching candidates were registered
7818  */
7819 static
7821  SCIP* scip, /**< SCIP data structure */
7822  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7823  SCIP_CONS** conss, /**< constraints to process */
7824  int nconss, /**< number of constraints */
7825  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7826  SCIP_Longint soltag, /**< tag of solution */
7827  SCIP_Bool inenforcement, /**< whether we are in enforcement, and not just separation */
7828  SCIP_Bool branchcandonly, /**< only collect branching candidates, do not separate or propagate */
7829  SCIP_Real maxrelconsviol, /**< largest scaled violation among all violated expr-constraints, only used if in enforcement */
7830  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7831  )
7832 {
7833  SCIP_CONSHDLRDATA* conshdlrdata;
7834  SCIP_EXPRITER* it;
7835  SCIP_Bool consenforced; /* whether any expression in constraint could be enforced */
7836  int c;
7837 
7838  assert(conshdlr != NULL);
7839  assert(conss != NULL || nconss == 0);
7840  assert(result != NULL);
7841 
7842  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7843  assert(conshdlrdata != NULL);
7844 
7845  /* increase tag to tell whether branching scores in expression belong to this sweep
7846  * and which expressions have already been enforced in this sweep
7847  * (we also want to distinguish sepa rounds, so this need to be here and not in consEnfo)
7848  */
7849  ++(conshdlrdata->enforound);
7850 
7851  *result = SCIP_DIDNOTFIND;
7852 
7853  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
7855 
7856  for( c = 0; c < nconss; ++c )
7857  {
7858  assert(conss != NULL && conss[c] != NULL);
7859 
7860  /* skip constraints that are not enabled or deleted */
7861  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
7862  continue;
7863  assert(SCIPconsIsActive(conss[c]));
7864 
7865  /* skip constraints that have separation disabled if we are only in separation */
7866  if( !inenforcement && !SCIPconsIsSeparationEnabled(conss[c]) )
7867  continue;
7868 
7869  /* skip non-violated constraints */
7870  if( !isConsViolated(scip, conss[c]) )
7871  continue;
7872 
7873  ENFOLOG(
7874  {
7875  SCIP_CONSDATA* consdata;
7876  int i;
7877  consdata = SCIPconsGetData(conss[c]);
7878  assert(consdata != NULL);
7879  SCIPinfoMessage(scip, enfologfile, " constraint ");
7880  SCIP_CALL( SCIPprintCons(scip, conss[c], enfologfile) );
7881  SCIPinfoMessage(scip, enfologfile, "\n with viol %g and point\n", getConsAbsViolation(conss[c]));
7882  for( i = 0; i < consdata->nvarexprs; ++i )
7883  {
7884  SCIP_VAR* var;
7885  var = SCIPgetVarExprVar(consdata->varexprs[i]);
7886  SCIPinfoMessage(scip, enfologfile, " %-10s = %15g bounds: [%15g,%15g]\n", SCIPvarGetName(var),
7887  SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
7888  }
7889  })
7890 
7891  SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, FALSE, inenforcement, branchcandonly, result, &consenforced) );
7892 
7893  if( *result == SCIP_CUTOFF )
7894  break;
7895 
7896  if( !consenforced && inenforcement && !branchcandonly )
7897  {
7898  SCIP_Real viol;
7899 
7900  SCIP_CALL( getConsRelViolation(scip, conss[c], &viol, sol, soltag) );
7901  if( viol > conshdlrdata->weakcutminviolfactor * maxrelconsviol )
7902  {
7903  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " constraint <%s> could not be enforced, try again with weak "\
7904  "cuts allowed\n", SCIPconsGetName(conss[c])); )
7905 
7906  SCIP_CALL( enforceConstraint(scip, conshdlr, conss[c], sol, soltag, it, TRUE, inenforcement, branchcandonly, result, &consenforced) );
7907 
7908  if( consenforced )
7909  ++conshdlrdata->nweaksepa; /* TODO maybe this should not be counted per constraint, but per enforcement round? */
7910 
7911  if( *result == SCIP_CUTOFF )
7912  break;
7913  }
7914  }
7915  }
7916 
7917  SCIPfreeExpriter(&it);
7918 
7919  ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7920 
7921  if( *result == SCIP_BRANCHED && !branchcandonly )
7922  {
7923  /* having result set to branched here means only that we have branching candidates, we still need to do the actual
7924  * branching
7925  */
7926  SCIP_CALL( branching(scip, conshdlr, conss, nconss, maxrelconsviol, sol, soltag, result) );
7927 
7928  /* branching should either have branched: result == SCIP_BRANCHED,
7929  * or fixed a variable: result == SCIP_REDUCEDDOM,
7930  * or have registered external branching candidates: result == SCIP_INFEASIBLE,
7931  * or have not done anything: result == SCIP_DIDNOTFIND
7932  */
7933  assert(*result == SCIP_BRANCHED || *result == SCIP_REDUCEDDOM || *result == SCIP_INFEASIBLE || *result == SCIP_DIDNOTFIND);
7934  }
7935 
7936  ENFOLOG( if( enfologfile != NULL ) fflush( enfologfile); )
7937 
7938  return SCIP_OKAY;
7939 }
7940 
7941 /** decide whether to branch on fractional integer or nonlinear variable
7942  *
7943  * The routine collects spatial branching candidates by a call to enforceConstraints(branchcandonly=TRUE)
7944  * and collectBranchingCandidates(). Then it adds fractional integer variables to the candidate list.
7945  * Variables that are candidate for both spatial branching and fractionality are considered as two separate candidates.
7946  * selectBranchingCandidate() then selects a variable for branching from the joined candidate list.
7947  * If the selected variable is a fractional integer one, then branchintegral=TRUE is returned, otherwise FALSE.
7948  * Some shortcuts exist for cases where there are no candidates of the one kind or the other.
7949  */
7950 static
7952  SCIP* scip, /**< SCIP data structure */
7953  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7954  SCIP_CONS** conss, /**< constraints to process */
7955  int nconss, /**< number of constraints */
7956  SCIP_Longint soltag, /**< tag of LP solution */
7957  SCIP_Real maxrelconsviol, /**< maximal scaled constraint violation */
7958  SCIP_Bool* branchintegral, /**< buffer to store whether to branch on fractional integer variables first */
7959  SCIP_Bool* cutoff /**< buffer to store whether infeasibility has been detected */
7960  )
7961 {
7962  SCIP_RESULT result;
7963  int nlpcands;
7964  SCIP_VAR** lpcands; /* fractional integer variables */
7965  SCIP_Real* lpcandsfrac; /* fractionalities */
7966  BRANCHCAND* cands;
7967  BRANCHCAND* selected;
7968  int ncands;
7969  int c;
7970 
7971  assert(scip != NULL);
7972  assert(conshdlr != NULL);
7973  assert(conss != NULL);
7974  assert(nconss > 0);
7975  assert(branchintegral != NULL);
7976  assert(cutoff != NULL);
7977 
7978  *branchintegral = FALSE;
7979  *cutoff = FALSE;
7980 
7981  if( SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) == 0 || SCIPgetNLPBranchCands(scip) == 0 )
7982  return SCIP_OKAY;
7983 
7984  SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, NULL, (SCIP_Longint)0, TRUE, TRUE, maxrelconsviol, &result) );
7985  switch( result )
7986  {
7987  case SCIP_DIDNOTFIND:
7988  /* no branching candidates found could mean that the LP solution is in a convex region */
7989  *branchintegral = TRUE;
7990  return SCIP_OKAY;
7991 
7992  case SCIP_CUTOFF:
7993  /* probably cannot happen, but easy to handle */
7994  *cutoff = TRUE;
7995  return SCIP_OKAY;
7996 
7997  case SCIP_SEPARATED:
7998  case SCIP_REDUCEDDOM:
7999  /* we asked enforceConstraints() to collect branching candidates only, it shouldn't have separated or propagated */
8000  SCIPerrorMessage("Unexpected separation or propagation from enforceConstraints(branchcandonly = TRUE)\n");
8001  return SCIP_ERROR;
8002 
8003  case SCIP_BRANCHED:
8004  /* actually meaning that branching candidates were registered (the result for which we have gone through all this effort) */
8005  break;
8006 
8007  case SCIP_INFEASIBLE:
8008  /* should not happen (enforceConstraints() returns this if external branching candidates were registered in branching(),
8009  * but this was disabled by branchcandonly = TRUE)
8010  */
8011  default:
8012  SCIPerrorMessage("Unexpected return from enforceConstraints(branchcandonly = TRUE)\n");
8013  return SCIP_ERROR;
8014  } /*lint !e788*/
8015 
8016  /* collect spatial branching candidates and their auxviol-score */
8017  SCIP_CALL( SCIPallocBufferArray(scip, &cands, SCIPgetNVars(scip) + SCIPgetNLPBranchCands(scip)) );
8018  SCIP_CALL( collectBranchingCandidates(scip, conshdlr, conss, nconss, maxrelconsviol, NULL, soltag, cands, &ncands) );
8019 
8020  /* add fractional integer variables to branching candidates */
8021  SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, &nlpcands, NULL, NULL) );
8022 
8023  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding %d fractional integer variables to branching candidates\n", nlpcands); )
8024 
8025  for( c = 0; c < nlpcands; ++c )
8026  {
8027  assert(ncands < SCIPgetNVars(scip) + SCIPgetNLPBranchCands(scip));
8028  assert(SCIPvarGetType(lpcands[c]) <= SCIP_VARTYPE_INTEGER);
8029  cands[ncands].expr = NULL;
8030  cands[ncands].var = lpcands[c];
8031  cands[ncands].auxviol = 0.0;
8032  cands[ncands].fractionality = lpcandsfrac[c];
8033  ++ncands;
8034  }
8035 
8036  /* select a variable for branching
8037  * to keep things separate, do not include fractionality of integer variables into scores of spatial branching candidates
8038  * the same variables appear among the candides for branching on integrality, where its fractionality is considered
8039  */
8040  SCIP_CALL( selectBranchingCandidate(scip, conshdlr, cands, ncands, FALSE, &selected) );
8041  assert(selected != NULL);
8042 
8043  if( selected->expr == NULL )
8044  {
8045  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " fractional variable <%s> selected for branching; fall back to cons_integral\n", SCIPvarGetName(selected->var)); )
8046 
8047  *branchintegral = TRUE;
8048  }
8049 
8050  SCIPfreeBufferArray(scip, &cands);
8051 
8052  return SCIP_OKAY;
8053 }
8054 
8055 /** decide whether to consider spatial branching before integrality has been enforced
8056  *
8057  * This decides whether we are still at a phase where we always want to branch on fractional integer variables if any (return TRUE),
8058  * or whether branchingIntegralOrNonlinear() should be used (return FALSE).
8059  *
8060  * This essentially checks whether the average pseudo cost count exceeds the value of parameter branchmixfractional.
8061  */
8062 static
8064  SCIP* scip, /**< SCIP data structure */
8065  SCIP_CONSHDLR* conshdlr /**< constraint handler */
8066 )
8067 {
8068  SCIP_CONSHDLRDATA* conshdlrdata;
8069 
8070  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8071  assert(conshdlrdata != NULL);
8072 
8073  /* if LP still unbounded, then work on nonlinear constraints first */
8075  return FALSE;
8076 
8077  /* no branching in cons_integral if no fractional integer variables */
8078  if( SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip) == 0 || SCIPgetNLPBranchCands(scip) == 0 )
8079  return FALSE;
8080 
8081  /* branchmixfractional being infinity means that integral should always go first */
8082  if( SCIPisInfinity(scip, conshdlrdata->branchmixfractional) )
8083  return TRUE;
8084 
8085  /* branchmixfractional being 0.0 means we do not wait for any pseudocosts to be available */
8086  if( conshdlrdata->branchmixfractional == 0.0 )
8087  return FALSE;
8088 
8089  /* if not yet enough pseudocosts for down or up direction, then branch on fractionality
8090  * @todo this gives the total pseudocost count divided by the number of discrete variables
8091  * if we updated pseudocost after branching on continuous variables, wouldn't this be incorrect? (#3637)
8092  */
8093  if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_DOWNWARDS) < conshdlrdata->branchmixfractional )
8094  return TRUE;
8095  if( SCIPgetAvgPseudocostCount(scip, SCIP_BRANCHDIR_UPWARDS) < conshdlrdata->branchmixfractional )
8096  return TRUE;
8097 
8098  /* we may have decent pseudocosts, so go for rule that chooses between fractional and spatial branching based on candidates */
8099  return FALSE;
8100 }
8101 
8102 /** collect (and print (if debugging enfo)) information on violation in expressions
8103  *
8104  * assumes that constraint violations have been computed
8105  */
8106 static
8108  SCIP* scip, /**< SCIP data structure */
8109  SCIP_CONS** conss, /**< constraints */
8110  int nconss, /**< number of constraints */
8111  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
8112  SCIP_Longint soltag, /**< tag of solution */
8113  SCIP_Real* maxabsconsviol, /**< buffer to store maximal absolute violation of constraints */
8114  SCIP_Real* maxrelconsviol, /**< buffer to store maximal relative violation of constraints */
8115  SCIP_Real* minauxviol, /**< buffer to store minimal (nonzero) violation of auxiliaries */
8116  SCIP_Real* maxauxviol, /**< buffer to store maximal violation of auxiliaries (violation in "extended formulation") */
8117  SCIP_Real* maxvarboundviol /**< buffer to store maximal violation of variable bounds */
8118  )
8119 {
8120  SCIP_CONSDATA* consdata;
8121  SCIP_EXPRITER* it;
8122  SCIP_EXPR* expr;
8123  SCIP_Real v;
8124  int c;
8125 
8126  assert(conss != NULL || nconss == 0);
8127  assert(maxabsconsviol != NULL);
8128  assert(maxrelconsviol != NULL);
8129  assert(maxauxviol != NULL);
8130  assert(maxvarboundviol != NULL);
8131 
8132  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
8134 
8135  *maxabsconsviol = 0.0;
8136  *maxrelconsviol = 0.0;
8137  *minauxviol = SCIPinfinity(scip);
8138  *maxauxviol = 0.0;
8139  *maxvarboundviol = 0.0;
8140 
8141  for( c = 0; c < nconss; ++c )
8142  {
8143  assert(conss != NULL && conss[c] != NULL);
8144 
8145  consdata = SCIPconsGetData(conss[c]);
8146  assert(consdata != NULL);
8147 
8148  /* skip constraints that are not enabled, deleted, or have separation disabled */
8149  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8150  continue;
8151  assert(SCIPconsIsActive(conss[c]));
8152 
8153  v = getConsAbsViolation(conss[c]);
8154  *maxabsconsviol = MAX(*maxabsconsviol, v);
8155 
8156  /* skip non-violated constraints */
8157  if( !isConsViolated(scip, conss[c]) )
8158  continue;
8159 
8160  SCIP_CALL( getConsRelViolation(scip, conss[c], &v, sol, soltag) );
8161  *maxrelconsviol = MAX(*maxrelconsviol, v);
8162 
8163  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8164  {
8165  SCIP_EXPR_OWNERDATA* ownerdata;
8166  SCIP_Real auxvarvalue;
8167  SCIP_Real auxvarlb;
8168  SCIP_Real auxvarub;
8169  SCIP_Bool violunder;
8170  SCIP_Bool violover;
8171  SCIP_Real origviol;
8172  SCIP_Real auxviol;
8173  int e;
8174 
8175  ownerdata = SCIPexprGetOwnerData(expr);
8176  assert(ownerdata != NULL);
8177 
8178  if( ownerdata->auxvar == NULL )
8179  {
8180  /* check violation of variable bounds of original variable */
8181  if( SCIPisExprVar(scip, expr) )
8182  {
8183  SCIP_VAR* var;
8184  var = SCIPgetVarExprVar(expr);
8185  auxvarvalue = SCIPgetSolVal(scip, sol, var);
8186  auxvarlb = SCIPvarGetLbLocal(var);
8187  auxvarub = SCIPvarGetUbLocal(var);
8188 
8189  origviol = 0.0;
8190  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8191  origviol = auxvarlb - auxvarvalue;
8192  else if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8193  origviol = auxvarvalue - auxvarub;
8194  if( origviol <= 0.0 )
8195  continue;
8196 
8197  *maxvarboundviol = MAX(*maxvarboundviol, origviol);
8198 
8199  ENFOLOG(
8200  SCIPinfoMessage(scip, enfologfile, "var <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(var), auxvarlb, auxvarub, auxvarvalue);
8201  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8202  SCIPinfoMessage(scip, enfologfile, " var >= lb violated by %g", auxvarlb - auxvarvalue);
8203  if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8204  SCIPinfoMessage(scip, enfologfile, " var <= ub violated by %g", auxvarvalue - auxvarub);
8205  SCIPinfoMessage(scip, enfologfile, "\n");
8206  )
8207  }
8208 
8209  continue;
8210  }
8211 
8212  auxvarvalue = SCIPgetSolVal(scip, sol, ownerdata->auxvar);
8213  auxvarlb = SCIPvarGetLbLocal(ownerdata->auxvar);
8214  auxvarub = SCIPvarGetUbLocal(ownerdata->auxvar);
8215 
8216  /* check violation of variable bounds of auxiliary variable */
8217  if( auxvarlb - auxvarvalue > *maxvarboundviol && !SCIPisInfinity(scip, -auxvarlb) )
8218  *maxvarboundviol = auxvarlb - auxvarvalue;
8219  else if( auxvarvalue - auxvarub > *maxvarboundviol && !SCIPisInfinity(scip, auxvarub) )
8220  *maxvarboundviol = auxvarvalue - auxvarub;
8221 
8222  origviol = getExprAbsOrigViolation(scip, expr, sol, &violunder, &violover);
8223 
8224  ENFOLOG(
8225  if( origviol > 0.0 || auxvarlb > auxvarvalue || auxvarub < auxvarvalue )
8226  {
8227  SCIPinfoMessage(scip, enfologfile, "expr ");
8228  SCIP_CALL( SCIPprintExpr(scip, expr, enfologfile) );
8229  SCIPinfoMessage(scip, enfologfile, " (%p)[%.15g,%.15g] = %.15g\n", (void*)expr, SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, SCIPexprGetEvalValue(expr));
8230 
8231  SCIPinfoMessage(scip, enfologfile, " auxvar <%s>[%.15g,%.15g] = %.15g", SCIPvarGetName(ownerdata->auxvar), auxvarlb, auxvarub, auxvarvalue);
8232  if( origviol > 0.0 )
8233  SCIPinfoMessage(scip, enfologfile, " auxvar %s expr violated by %g", violunder ? ">=" : "<=", origviol);
8234  if( auxvarlb > auxvarvalue && !SCIPisInfinity(scip, -auxvarlb) )
8235  SCIPinfoMessage(scip, enfologfile, " auxvar >= auxvar's lb violated by %g", auxvarlb - auxvarvalue);
8236  if( auxvarub < auxvarvalue && !SCIPisInfinity(scip, auxvarub) )
8237  SCIPinfoMessage(scip, enfologfile, " auxvar <= auxvar's ub violated by %g", auxvarvalue - auxvarub);
8238  SCIPinfoMessage(scip, enfologfile, "\n");
8239  }
8240  )
8241 
8242  /* no violation w.r.t. the original variables -> skip expression */
8243  if( origviol == 0.0 )
8244  continue;
8245 
8246  /* compute aux-violation for each nonlinear handlers */
8247  for( e = 0; e < ownerdata->nenfos; ++e )
8248  {
8249  SCIP_NLHDLR* nlhdlr;
8250 
8251  /* eval in auxvars is only defined for nlhdrs that separate; there might not even be auxvars otherwise */
8252  if( (ownerdata->enfos[e]->nlhdlrparticipation & SCIP_NLHDLR_METHOD_SEPABOTH) == 0 )
8253  continue;
8254 
8255  nlhdlr = ownerdata->enfos[e]->nlhdlr;
8256  assert(nlhdlr != NULL);
8257 
8258  /* evaluate the expression w.r.t. the nlhdlrs auxiliary variables */
8259  SCIP_CALL( SCIPnlhdlrEvalaux(scip, nlhdlr, expr, ownerdata->enfos[e]->nlhdlrexprdata, &ownerdata->enfos[e]->auxvalue, sol) );
8260 
8261  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " nlhdlr <%s> = %.15g", SCIPnlhdlrGetName(nlhdlr), ownerdata->enfos[e]->auxvalue); )
8262 
8263  auxviol = getExprAbsAuxViolation(scip, expr, ownerdata->enfos[e]->auxvalue, sol, &violunder, &violover);
8264 
8265  if( auxviol > 0.0 )
8266  {
8267  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxvar %s nlhdlr-expr violated by %g", violover ? "<=" : ">=", auxviol); )
8268  *maxauxviol = MAX(*maxauxviol, auxviol);
8269  *minauxviol = MIN(*minauxviol, auxviol);
8270  }
8271  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "\n"); )
8272  }
8273  }
8274  }
8275 
8276  SCIPfreeExpriter(&it);
8277 
8278  return SCIP_OKAY;
8279 } /*lint !e715*/
8280 
8281 /** enforcement of constraints called by enfolp and enforelax */
8282 static
8284  SCIP* scip, /**< SCIP data structure */
8285  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8286  SCIP_CONS** conss, /**< constraints to process */
8287  int nconss, /**< number of constraints */
8288  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8289  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8290  )
8291 {
8292  SCIP_CONSHDLRDATA* conshdlrdata;
8293  SCIP_Real maxabsconsviol;
8294  SCIP_Real maxrelconsviol;
8295  SCIP_Real minauxviol;
8296  SCIP_Real maxauxviol;
8297  SCIP_Real maxvarboundviol;
8298  SCIP_Longint soltag;
8299  SCIP_Bool branchintegral;
8300  int nnotify;
8301  int c;
8302 
8303  if( sol == NULL && branchingIntegralFirst(scip, conshdlr) )
8304  {
8305  /* let cons_integral handle enforcement */
8306  *result = SCIP_INFEASIBLE;
8307  return SCIP_OKAY;
8308  }
8309 
8310  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8311  assert(conshdlr != NULL);
8312 
8313  soltag = SCIPgetExprNewSoltag(scip);
8314 
8315  *result = SCIP_FEASIBLE;
8316  for( c = 0; c < nconss; ++c )
8317  {
8318  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8319 
8320  if( isConsViolated(scip, conss[c]) )
8321  *result = SCIP_INFEASIBLE;
8322  }
8323 
8324  if( *result == SCIP_FEASIBLE )
8325  {
8326  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: all expr-constraints feasible, skip enforcing\n",
8328  return SCIP_OKAY;
8329  }
8330 
8331  SCIP_CALL( analyzeViolation(scip, conss, nconss, sol, soltag, &maxabsconsviol, &maxrelconsviol,
8332  &minauxviol, &maxauxviol, &maxvarboundviol) );
8333 
8334  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: enforcing constraints with max conssviol=%e (rel=%e), "\
8335  "auxviolations in %g..%g, variable bounds violated by at most %g, LP feastol=%e\n",
8336  SCIPnodeGetNumber(SCIPgetCurrentNode(scip)), maxabsconsviol, maxrelconsviol, minauxviol, maxauxviol,
8337  maxvarboundviol, SCIPgetLPFeastol(scip)); )
8338 
8339  assert(maxvarboundviol <= SCIPgetLPFeastol(scip));
8340 
8341  /* look at fractional and nonlinear branching candidates and decide whether to branch on fractional vars, first */
8342  if( sol == NULL )
8343  {
8344  SCIP_Bool cutoff;
8345 
8346  SCIP_CALL( branchingIntegralOrNonlinear(scip, conshdlr, conss, nconss, soltag, maxrelconsviol, &branchintegral, &cutoff) );
8347  if( cutoff )
8348  {
8349  *result = SCIP_CUTOFF;
8350  return SCIP_OKAY;
8351  }
8352  if( branchintegral )
8353  {
8354  /* let cons_integral handle enforcement */
8355  *result = SCIP_INFEASIBLE;
8356  return SCIP_OKAY;
8357  }
8358  }
8359 
8360  /* try to propagate */
8361  if( conshdlrdata->propinenforce )
8362  {
8363  SCIP_RESULT propresult;
8364  int nchgbds = 0;
8365 
8366  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8367 
8368  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8369  {
8370  *result = propresult;
8371  return SCIP_OKAY;
8372  }
8373  }
8374 
8375  /* tighten the LP tolerance if violation in variables bounds is larger than aux-violation (max |expr - auxvar| over
8376  * all violated expr/auxvar in violated constraints)
8377  */
8378  if( conshdlrdata->tightenlpfeastol && maxvarboundviol > maxauxviol && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) &&
8379  sol == NULL )
8380  {
8381  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8382  ++conshdlrdata->ntightenlp;
8383 
8384  *result = SCIP_SOLVELP;
8385 
8386  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bound violation %g larger than auxiliary violation %g, "\
8387  "reducing LP feastol to %g\n", maxvarboundviol, maxauxviol, SCIPgetLPFeastol(scip)); )
8388 
8389  return SCIP_OKAY;
8390  }
8391 
8392  /* tighten the LP tolerance if violation in auxiliaries is below LP feastol, as we could have problems to find a cut
8393  * with violation above LP tolerance (especially when auxviolation is below 10*eps = ROWPREP_SCALEUP_VIOLNONZERO in misc_rowprep.c)
8394  */
8395  if( conshdlrdata->tightenlpfeastol && maxauxviol < SCIPgetLPFeastol(scip) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8396  {
8397  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), maxauxviol/2.0));
8398  ++conshdlrdata->ntightenlp;
8399 
8400  *result = SCIP_SOLVELP;
8401 
8402  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " auxiliary violation %g below LP feastol, reducing LP feastol to %g\n", maxauxviol, SCIPgetLPFeastol(scip)); )
8403 
8404  return SCIP_OKAY;
8405  }
8406 
8407  SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, TRUE, FALSE, maxrelconsviol, result) );
8408 
8409  if( *result == SCIP_CUTOFF || *result == SCIP_SEPARATED || *result == SCIP_REDUCEDDOM || *result == SCIP_BRANCHED ||
8410  *result == SCIP_INFEASIBLE )
8411  return SCIP_OKAY;
8412 
8413  assert(*result == SCIP_DIDNOTFIND);
8414 
8415  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " could not enforce violation %g in regular ways, LP feastol=%g, "\
8416  "becoming desperate now...\n", maxabsconsviol, SCIPgetLPFeastol(scip)); )
8417 
8418  if( sol == NULL && SCIPgetNLPBranchCands(scip) > 0 )
8419  {
8420  /* if there are still fractional integer variables, then let cons_integral go first */
8421  *result = SCIP_INFEASIBLE;
8422  return SCIP_OKAY;
8423  }
8424 
8425  if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxvarboundviol) && SCIPisPositive(scip, SCIPgetLPFeastol(scip)) && sol == NULL )
8426  {
8427  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxvarboundviol / 2.0, SCIPgetLPFeastol(scip) / 2.0)));
8428  ++conshdlrdata->ntightenlp;
8429 
8430  *result = SCIP_SOLVELP;
8431 
8432  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " variable bounds are violated by more than eps, reduced LP "\
8433  "feasibility tolerance to %g\n", SCIPgetLPFeastol(scip)); )
8434 
8435  return SCIP_OKAY;
8436  }
8437 
8438  if( conshdlrdata->tightenlpfeastol && SCIPisPositive(scip, maxauxviol) && SCIPisPositive(scip,
8439  SCIPgetLPFeastol(scip)) && sol == NULL )
8440  {
8441  /* try whether tighten the LP feasibility tolerance could help
8442  * maybe it is just some cut that hasn't been taken into account sufficiently
8443  * in the next enforcement round, we would then also allow even weaker cuts, as we want a minimal cut violation of LP's feastol
8444  * unfortunately, we do not know the current LP solution primal infeasibility, so sometimes this just repeats without effect
8445  * until the LP feastol reaches epsilon
8446  * (this is similar to the "tighten the LP tolerance if violation in auxiliaries is below LP feastol..." case above, but applies
8447  * when maxauxviol is above LP feastol)
8448  */
8449  SCIPsetLPFeastol(scip, MAX(SCIPepsilon(scip), MIN(maxauxviol / 2.0, SCIPgetLPFeastol(scip) / 10.0)));
8450  ++conshdlrdata->ndesperatetightenlp;
8451 
8452  *result = SCIP_SOLVELP;
8453 
8454  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " reduced LP feasibility tolerance to %g and hope\n", SCIPgetLPFeastol(scip)); )
8455 
8456  return SCIP_OKAY;
8457  }
8458 
8459  /* try to propagate, if not tried above TODO(?) allow to disable this as well */
8460  if( !conshdlrdata->propinenforce )
8461  {
8462  SCIP_RESULT propresult;
8463  int nchgbds = 0;
8464 
8465  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
8466 
8467  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8468  {
8469  *result = propresult;
8470  return SCIP_OKAY;
8471  }
8472  }
8473 
8474  /* could not find branching candidates even when looking at minimal violated (>eps) expressions
8475  * now look if we find any unfixed variable that we could still branch on
8476  */
8477  SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
8478 
8479  if( nnotify > 0 )
8480  {
8481  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " registered %d unfixed variables as branching candidates\n", nnotify); )
8482  ++conshdlrdata->ndesperatebranch;
8483 
8484  *result = SCIP_INFEASIBLE; /* enforceConstraints may have changed it to SCIP_DIDNOTFIND */
8485 
8486  return SCIP_OKAY;
8487  }
8488 
8489  /* if everything is fixed in violated constraints, then let's cut off the node
8490  * - bound tightening with all vars fixed should prove cutoff, but interval arithmetic overestimates and so the
8491  * result may not be conclusive (when constraint violations are small)
8492  * - if tightenlpfeastol=FALSE, then the LP solution that we try to enforce here may just not be within bounds
8493  * sufficiently (see st_e40)
8494  * - but if the LP solution is really within bounds and since variables are fixed, cutting off the node is actually
8495  * not "desperate", but a pretty obvious thing to do
8496  */
8497  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " enforcement with max. violation %g failed; cutting off node\n", maxabsconsviol); )
8498  *result = SCIP_CUTOFF;
8499 
8500  /* it's only "desperate" if the LP solution does not coincide with variable fixings (should we use something tighter than epsilon here?) */
8501  if( !SCIPisZero(scip, maxvarboundviol) )
8502  ++conshdlrdata->ndesperatecutoff;
8503 
8504  return SCIP_OKAY;
8505 }
8506 
8507 /** separation for all violated constraints to be used by SEPA callbacks */
8508 static
8510  SCIP* scip, /**< SCIP data structure */
8511  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8512  SCIP_CONS** conss, /**< constraints to process */
8513  int nconss, /**< number of constraints */
8514  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
8515  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
8516  )
8517 {
8518  SCIP_Longint soltag;
8519  SCIP_Bool haveviol = FALSE;
8520  int c;
8521 
8522  *result = SCIP_DIDNOTFIND;
8523 
8524  soltag = SCIPgetExprNewSoltag(scip);
8525 
8526  /* compute violations */
8527  for( c = 0; c < nconss; ++c )
8528  {
8529  assert(conss[c] != NULL);
8530 
8531  /* skip constraints that are not enabled, deleted, or have separation disabled */
8532  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) || !SCIPconsIsSeparationEnabled(conss[c]) )
8533  continue;
8534  assert(SCIPconsIsActive(conss[c]));
8535 
8536  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
8537 
8538  if( isConsViolated(scip, conss[c]) )
8539  haveviol = TRUE;
8540  }
8541 
8542  /* if none of our constraints are violated, don't attempt separation */
8543  if( !haveviol )
8544  {
8545  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: skip separation of non-violated constraints\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8546  return SCIP_OKAY;
8547  }
8548 
8549  ENFOLOG( SCIPinfoMessage(scip, enfologfile, "node %lld: separation\n", SCIPnodeGetNumber(SCIPgetCurrentNode(scip))); )
8550 
8551  /* call separation */
8552  SCIP_CALL( enforceConstraints(scip, conshdlr, conss, nconss, sol, soltag, FALSE, FALSE, SCIP_INVALID, result) );
8553 
8554  return SCIP_OKAY;
8555 }
8556 
8557 /** hash key retrieval function for bilinear term entries */
8558 static
8559 SCIP_DECL_HASHGETKEY(bilinearTermsGetHashkey)
8560 { /*lint --e{715}*/
8561  SCIP_CONSHDLRDATA* conshdlrdata;
8562  int idx;
8563 
8564  conshdlrdata = (SCIP_CONSHDLRDATA*)userptr;
8565  assert(conshdlrdata != NULL);
8566 
8567  idx = ((int)(size_t)elem) - 1;
8568  assert(idx >= 0 && idx < conshdlrdata->nbilinterms);
8569 
8570  return (void*)&conshdlrdata->bilinterms[idx];
8571 }
8572 
8573 /** returns TRUE iff the bilinear term entries are equal */
8574 static
8575 SCIP_DECL_HASHKEYEQ(bilinearTermsIsHashkeyEq)
8576 { /*lint --e{715}*/
8579 
8580  /* get corresponding entries */
8581  entry1 = (SCIP_CONSNONLINEAR_BILINTERM*)key1;
8582  entry2 = (SCIP_CONSNONLINEAR_BILINTERM*)key2;
8583  assert(entry1->x != NULL && entry1->y != NULL);
8584  assert(entry2->x != NULL && entry2->y != NULL);
8585  assert(SCIPvarCompare(entry1->x, entry1->y) < 1);
8586  assert(SCIPvarCompare(entry2->x, entry2->y) < 1);
8587 
8588  return entry1->x == entry2->x && entry1->y == entry2->y;
8589 }
8590 
8591 /** returns the hash value of the key */
8592 static
8593 SCIP_DECL_HASHKEYVAL(bilinearTermsGetHashkeyVal)
8594 { /*lint --e{715}*/
8596 
8597  entry = (SCIP_CONSNONLINEAR_BILINTERM*)key;
8598  assert(entry->x != NULL && entry->y != NULL);
8599  assert(SCIPvarCompare(entry->x, entry->y) < 1);
8600 
8601  return SCIPhashTwo(SCIPvarGetIndex(entry->x), SCIPvarGetIndex(entry->y));
8602 }
8603 
8604 /** compare two auxiliary expressions
8605  *
8606  * Compares auxiliary variables, followed by coefficients, and then constants.
8607  */
8608 static
8609 SCIP_DECL_SORTPTRCOMP(auxexprComp)
8613  int compvars;
8614  int i;
8615 
8616  /* compare the auxiliary variables */
8617  compvars = SCIPvarCompare(auxexpr1->auxvar, auxexpr2->auxvar); /* TODO can one of these be NULL? */
8618 
8619  if( compvars != 0 )
8620  return compvars;
8621 
8622  /* compare the coefficients and constants */
8623  for( i = 0; i < 3; ++i )
8624  {
8625  if( auxexpr1->coefs[i] != auxexpr2->coefs[i] )
8626  return auxexpr1->coefs[i] < auxexpr2->coefs[i] ? -1 : 1;
8627  }
8628 
8629  return auxexpr1->cst < auxexpr2->cst ? -1 : auxexpr1->cst == auxexpr2->cst ? 0 : 1;
8630 }
8631 
8632 /* add an auxiliary expression to a bilinear term */
8633 static
8635  SCIP* scip, /**< SCIP data structure */
8636  SCIP_CONSHDLRDATA* conshdlrdata, /**< nonlinear constraint handler data */
8637  SCIP_CONSNONLINEAR_BILINTERM* term, /**< bilinear term */
8638  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression to add */
8639  SCIP_Bool* added /**< pointer to store whether auxexpr has been added */
8640  )
8641 {
8642  SCIP_Bool found;
8643  int pos;
8644  int i;
8645 
8646  *added = FALSE;
8647 
8648  /* check if auxexpr has already been added to term */
8649  if( term->nauxexprs == 0 )
8650  {
8651  found = FALSE;
8652  pos = 0;
8653  }
8654  else
8655  {
8656  found = SCIPsortedvecFindPtr((void**)term->aux.exprs, auxexprComp, auxexpr, term->nauxexprs, &pos);
8657  }
8658 
8659  if( !found )
8660  {
8661  if( term->nauxexprs >= conshdlrdata->bilinmaxnauxexprs )
8662  return SCIP_OKAY;
8663 
8664  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &term->aux.exprs, &term->auxexprssize, term->nauxexprs + 1) );
8665  assert(term->auxexprssize >= term->nauxexprs + 1);
8666 
8667  /* insert expression at the correct position */
8668  for( i = term->nauxexprs; i > pos; --i )
8669  {
8670  term->aux.exprs[i] = term->aux.exprs[i-1];
8671  }
8672  term->aux.exprs[pos] = auxexpr;
8673  ++(term->nauxexprs);
8674  *added = TRUE;
8675  }
8676  else
8677  {
8678  term->aux.exprs[pos]->underestimate |= auxexpr->underestimate;
8679  term->aux.exprs[pos]->overestimate |= auxexpr->overestimate;
8680  }
8681 
8682  return SCIP_OKAY;
8683 }
8684 
8685 /** iterates through all expressions of all nonlinear constraints and adds the corresponding bilinear terms to the hash table */
8686 static
8688  SCIP* scip, /**< SCIP data structure */
8689  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
8690  SCIP_CONS** conss, /**< nonlinear constraints */
8691  int nconss /**< total number of nonlinear constraints */
8692  )
8693 {
8694  SCIP_CONSHDLRDATA* conshdlrdata;
8695  SCIP_EXPRITER* it;
8696  int c;
8697 
8698  assert(conss != NULL || nconss == 0);
8699 
8700  if( nconss == 0 )
8701  return SCIP_OKAY;
8702 
8703  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8704  assert(conshdlrdata != NULL);
8705 
8706  /* check whether the bilinear terms have been stored already */
8707  if( conshdlrdata->bilinterms != NULL )
8708  return SCIP_OKAY;
8709 
8710  /* create and initialize iterator */
8711  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
8714 
8715  /* iterate through all constraints */
8716  for( c = 0; c < nconss; ++c )
8717  {
8718  SCIP_CONSDATA* consdata;
8719  SCIP_EXPR* expr;
8720 
8721  assert(conss != NULL && conss[c] != NULL);
8722  consdata = SCIPconsGetData(conss[c]);
8723  assert(consdata != NULL);
8724 
8725  /* iterate through all expressions */
8726  for( expr = SCIPexpriterRestartDFS(it, consdata->expr); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
8727  {
8728  SCIP_EXPR** children = SCIPexprGetChildren(expr);
8729  SCIP_VAR* x = NULL;
8730  SCIP_VAR* y = NULL;
8731 
8732  /* check whether the expression is of the form f(..)^2 */
8733  if( SCIPisExprPower(scip, expr) && SCIPgetExponentExprPow(expr) == 2.0 )
8734  {
8735  x = SCIPgetExprAuxVarNonlinear(children[0]);
8736  y = x;
8737  }
8738  /* check whether the expression is of the form f(..) * g(..) */
8739  else if( SCIPisExprProduct(scip, expr) && SCIPexprGetNChildren(expr) == 2 )
8740  {
8741  x = SCIPgetExprAuxVarNonlinear(children[0]);
8742  y = SCIPgetExprAuxVarNonlinear(children[1]);
8743  }
8744 
8745  /* add variables to the hash table */
8746  if( x != NULL && y != NULL )
8747  {
8750  }
8751  }
8752  }
8753 
8754  /* release iterator */
8755  SCIPfreeExpriter(&it);
8756 
8757  return SCIP_OKAY;
8758 }
8759 
8760 /** store x, y and the locks in a new bilinear term */
8761 static
8763  SCIP* scip, /**< SCIP data structure */
8764  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
8765  SCIP_VAR* x, /**< the first variable */
8766  SCIP_VAR* y, /**< the second variable */
8767  int nlockspos, /**< number of positive locks of the bilinear term */
8768  int nlocksneg, /**< number of negative locks of the bilinear term */
8769  int* idx, /**< pointer to store the position of the term in bilinterms array */
8770  SCIP_Bool existing /**< whether the term exists explicitly in the problem */
8771  )
8772 {
8773  SCIP_CONSHDLRDATA* conshdlrdata;
8775 
8776  assert(conshdlr != NULL);
8777  assert(x != NULL);
8778  assert(y != NULL);
8779  assert(nlockspos >= 0);
8780  assert(nlocksneg >= 0);
8781 
8782  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8783  assert(conshdlrdata != NULL);
8784 
8785  /* ensure that x.index <= y.index */
8786  if( SCIPvarCompare(x, y) == 1 )
8787  {
8788  SCIPswapPointers((void**)&x, (void**)&y);
8789  }
8790  assert(SCIPvarCompare(x, y) < 1);
8791 
8792  *idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
8793 
8794  /* update or create the term */
8795  if( *idx >= 0 )
8796  { /* the term has already been added */
8797  assert(conshdlrdata->bilinterms[*idx].x == x);
8798  assert(conshdlrdata->bilinterms[*idx].y == y);
8799 
8800  /* get term and add locks */
8801  term = &conshdlrdata->bilinterms[*idx];
8802  assert(existing <= term->existing); /* implicit terms are added after existing ones */
8803  term->nlockspos += nlockspos;
8804  term->nlocksneg += nlocksneg;
8805  }
8806  else
8807  { /* this is the first time we encounter this product */
8808  /* ensure size of bilinterms array */
8809  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->bilinterms, &conshdlrdata->bilintermssize, conshdlrdata->nbilinterms + 1) );
8810 
8811  *idx = conshdlrdata->nbilinterms;
8812 
8813  /* get term and set values in the created bilinear term */
8814  term = &conshdlrdata->bilinterms[*idx];
8815  assert(term != NULL);
8816  term->x = x;
8817  term->y = y;
8818  term->nauxexprs = 0;
8819  term->auxexprssize = 0;
8820  term->nlockspos = nlockspos;
8821  term->nlocksneg = nlocksneg;
8822  term->existing = existing;
8823  if( existing )
8824  term->aux.var = NULL;
8825  else
8826  term->aux.exprs = NULL;
8827 
8828  /* increase the total number of bilinear terms */
8829  ++(conshdlrdata->nbilinterms);
8830 
8831  /* save to the hashtable */
8832  if( conshdlrdata->bilinhashtable == NULL )
8833  {
8834  SCIP_CALL( SCIPhashtableCreate(&conshdlrdata->bilinhashtable, SCIPblkmem(scip), conshdlrdata->nbilinterms,
8835  bilinearTermsGetHashkey, bilinearTermsIsHashkeyEq, bilinearTermsGetHashkeyVal,
8836  (void*)conshdlrdata) );
8837  }
8838  assert(conshdlrdata->bilinhashtable != NULL);
8839 
8840  /* insert the index of the bilinear term into the hash table; note that the index of the i-th element is (i+1)
8841  * because zero can not be inserted into hash table
8842  */
8843  SCIP_CALL( SCIPhashtableInsert(conshdlrdata->bilinhashtable, (void*)(size_t)(*idx + 1)) ); /*lint !e571 !e776*/
8844 
8845  /* capture product variables */
8846  SCIP_CALL( SCIPcaptureVar(scip, x) );
8847  SCIP_CALL( SCIPcaptureVar(scip, y) );
8848  }
8849 
8850  return SCIP_OKAY;
8851 }
8852 
8853 /** frees array of bilinear terms and hash table */
8854 static
8856  SCIP* scip, /**< SCIP data structure */
8857  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8858  )
8859 {
8860  int i;
8861  int j;
8862 
8863  assert(conshdlrdata != NULL);
8864 
8865  /* check whether bilinear terms have been stored */
8866  if( conshdlrdata->bilinterms == NULL )
8867  {
8868  assert(conshdlrdata->bilinterms == NULL);
8869  assert(conshdlrdata->nbilinterms == 0);
8870  assert(conshdlrdata->bilintermssize == 0);
8871 
8872  return SCIP_OKAY;
8873  }
8874 
8875  /* release variables */
8876  for( i = 0; i < conshdlrdata->nbilinterms; ++i )
8877  {
8878  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].y) );
8879  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].x) );
8880 
8881  for( j = 0; j < conshdlrdata->bilinterms[i].nauxexprs; ++j )
8882  {
8883  if( conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar != NULL )
8884  {
8885  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.exprs[j]->auxvar) );
8886  }
8887  SCIPfreeBlockMemory(scip, &(conshdlrdata->bilinterms[i].aux.exprs[j]));
8888  }
8889 
8890  if( conshdlrdata->bilinterms[i].nauxexprs > 0 )
8891  {
8892  SCIPfreeBlockMemoryArray(scip, &(conshdlrdata->bilinterms[i].aux.exprs), conshdlrdata->bilinterms[i].auxexprssize);
8893  continue;
8894  }
8895 
8896  /* the rest is for simple terms with a single auxvar */
8897 
8898  /* it might be that there is a bilinear term without a corresponding auxiliary variable */
8899  if( conshdlrdata->bilinterms[i].aux.var != NULL )
8900  {
8901  SCIP_CALL( SCIPreleaseVar(scip, &conshdlrdata->bilinterms[i].aux.var) );
8902  }
8903  }
8904 
8905  /* free hash table */
8906  if( conshdlrdata->bilinhashtable != NULL )
8907  {
8908  SCIPhashtableFree(&conshdlrdata->bilinhashtable);
8909  }
8910 
8911  /* free bilinterms array; reset counters */
8912  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->bilinterms, conshdlrdata->bilintermssize);
8913  conshdlrdata->nbilinterms = 0;
8914  conshdlrdata->bilintermssize = 0;
8915 
8916  return SCIP_OKAY;
8917 }
8918 
8919 /*
8920  * vertex polyhedral separation
8921  */
8922 
8923 /** builds LP used to compute facets of the convex envelope of vertex-polyhedral functions */
8924 static
8926  SCIP* scip, /**< SCIP data structure */
8927  int nvars, /**< number of (unfixed) variables in vertex-polyhedral functions */
8928  SCIP_LPI** lp /**< pointer to store created LP */
8929  )
8930 {
8931  SCIP_Real* obj;
8932  SCIP_Real* lb;
8933  SCIP_Real* ub;
8934  SCIP_Real* val;
8935  int* beg;
8936  int* ind;
8937  unsigned int nnonz;
8938  unsigned int ncols;
8939  unsigned int nrows;
8940  unsigned int i;
8941  unsigned int k;
8942 
8943  assert(scip != NULL);
8944  assert(lp != NULL);
8945  assert(nvars > 0);
8946  assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
8947 
8948  SCIPdebugMsg(scip, "Building LP for computing facets of convex envelope of vertex-polyhedral function\n");
8949 
8950  /* create lpi to store the LP */
8951  SCIP_CALL( SCIPlpiCreate(lp, SCIPgetMessagehdlr(scip), "facet finding LP", SCIP_OBJSEN_MINIMIZE) );
8952 
8953  nrows = (unsigned int)nvars + 1;
8954  ncols = POWEROFTWO((unsigned int)nvars);
8955  nnonz = (ncols * (nrows + 1)) / 2;
8956 
8957  /* allocate necessary memory; set obj, lb, and ub to zero */
8958  SCIP_CALL( SCIPallocClearBufferArray(scip, &obj, ncols) );
8959  SCIP_CALL( SCIPallocClearBufferArray(scip, &lb, ncols) );
8960  SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
8961  SCIP_CALL( SCIPallocBufferArray(scip, &beg, ncols) );
8962  SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
8963  SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
8964 
8965  /* calculate nonzero entries in the LP */
8966  for( i = 0, k = 0; i < ncols; ++i )
8967  {
8968  int row;
8969  unsigned int a;
8970 
8971  /* an upper bound of 1.0 is implied by the last row, but I presume that LP solvers prefer unbounded variables */
8972  ub[i] = SCIPlpiInfinity(*lp);
8973 
8974  SCIPdebugMsg(scip, "col %u starts at position %u\n", i, k);
8975  beg[i] = (int)k;
8976  row = 0;
8977 
8978  /* iterate through the bit representation of i */
8979  a = 1;
8980  while( a <= i )
8981  {
8982  if( (a & i) != 0 )
8983  {
8984  val[k] = 1.0;
8985  ind[k] = row;
8986 
8987  SCIPdebugMsg(scip, " val[%d][%u] = 1 (position %u)\n", row, i, k);
8988 
8989  ++k;
8990  }
8991 
8992  a <<= 1;
8993  ++row;
8994  assert(0 <= row && row <= SCIP_MAXVERTEXPOLYDIM);
8995  assert(POWEROFTWO(row) == a);
8996  }
8997 
8998  /* put 1 as a coefficient for sum_{i} \lambda_i = 1 row (last row) */
8999  val[k] = 1.0;
9000  ind[k] = (int)nrows - 1;
9001  ++k;
9002  SCIPdebugMsg(scip, " val[%u][%u] = 1 (position %u)\n", nrows - 1, i, k);
9003  }
9004  assert(k == nnonz);
9005 
9006  /* load all data into LP interface
9007  * we can assume nrows (=nvars+1) <= ncols (=2^nvars), so we can pass lb as dummy lhs and rhs
9008  */
9009  assert(nrows <= ncols);
9011  (int)ncols, obj, lb, ub, NULL,
9012  (int)nrows, lb, lb, NULL,
9013  (int)nnonz, beg, ind, val) );
9014 
9015  /* for the last row, we can set the rhs to 1.0 already */
9016  ind[0] = (int)nrows - 1;
9017  val[0] = 1.0;
9018  SCIP_CALL( SCIPlpiChgSides(*lp, 1, ind, val, val) );
9019 
9020  /* free allocated memory */
9021  SCIPfreeBufferArray(scip, &ind);
9022  SCIPfreeBufferArray(scip, &val);
9023  SCIPfreeBufferArray(scip, &beg);
9024  SCIPfreeBufferArray(scip, &ub);
9025  SCIPfreeBufferArray(scip, &lb);
9026  SCIPfreeBufferArray(scip, &obj);
9027 
9028  return SCIP_OKAY;
9029 }
9030 
9031 /** the given facet might not be a valid under(over)estimator, because of numerics and bad fixings; we compute \f$
9032  * \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
9033  * set of vertices of the domain
9034  */
9035 static
9037  SCIP* scip, /**< SCIP data structure */
9038  SCIP_Bool overestimate, /**< whether we check for an over or underestimator */
9039  SCIP_Real* funvals, /**< array containing the evaluation of the function at all corners, length: 2^nvars */
9040  SCIP_Real* box, /**< box for which facet was computed, length: 2*nallvars */
9041  int nallvars, /**< number of all variables */
9042  int nvars, /**< number of unfixed variables */
9043  int* nonfixedpos, /**< indices of unfixed variables, length: nvars */
9044  SCIP_Real* facetcoefs, /**< current facet candidate's coefficients, length: nallvars */
9045  SCIP_Real facetconstant /**< current facet candidate's constant, length: nallvars */
9046  )
9047 {
9048  SCIP_Real maxerror;
9049  SCIP_Real facetval;
9050  SCIP_Real funval;
9051  SCIP_Real error;
9052  unsigned int i;
9053  unsigned int ncorners;
9054  unsigned int prev;
9055 
9056  assert(scip != NULL);
9057  assert(funvals != NULL);
9058  assert(box != NULL);
9059  assert(nonfixedpos != NULL);
9060  assert(facetcoefs != NULL);
9061 
9062  ncorners = POWEROFTWO(nvars);
9063  maxerror = 0.0;
9064 
9065  /* check the origin (all variables at lower bound) */
9066  facetval = facetconstant;
9067  for( i = 0; i < (unsigned int) nallvars; ++i )
9068  facetval += facetcoefs[i] * box[2*i];
9069 
9070  /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9071  funval = funvals[0];
9072  if( overestimate )
9073  error = funval - facetval;
9074  else
9075  error = facetval - funval;
9076 
9077  /* update maximum error */
9078  maxerror = MAX(error, maxerror);
9079 
9080  prev = 0;
9081  for( i = 1; i < ncorners; ++i )
9082  {
9083  unsigned int gray;
9084  unsigned int diff;
9085  unsigned int pos;
9086  int origpos;
9087 
9088  gray = i ^ (i >> 1);
9089  diff = gray ^ prev;
9090 
9091  /* compute position of unique 1 of diff */
9092  pos = 0;
9093  while( (diff >>= 1) != 0 )
9094  ++pos;
9095  assert(pos < (unsigned int)nvars);
9096 
9097  origpos = nonfixedpos[pos];
9098 
9099  if( gray > prev )
9100  facetval += facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9101  else
9102  facetval -= facetcoefs[origpos] * (box[2*origpos+1] - box[2*origpos]);
9103 
9104  /* compute largest/smallest possible value of function, depending on whether we are over/under-estimating */
9105  funval = funvals[gray];
9106  if( overestimate )
9107  error = funval - facetval;
9108  else
9109  error = facetval - funval;
9110 
9111  /* update maximum error */
9112  maxerror = MAX(error, maxerror);
9113 
9114  prev = gray;
9115  }
9116 
9117  SCIPdebugMsg(scip, "maximum error of facet: %2.8e\n", maxerror);
9118 
9119  return maxerror;
9120 }
9121 
9122 /** computes a facet of the convex or concave envelope of a vertex polyhedral function by solving an LP */ /*lint -e{715}*/
9123 static
9125  SCIP* scip, /**< SCIP data structure */
9126  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
9127  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9128  SCIP_Real* xstar, /**< point to be separated */
9129  SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
9130  int nallvars, /**< half of the length of box */
9131  int* nonfixedpos, /**< indices of nonfixed variables */
9132  SCIP_Real* funvals, /**< values of function in all corner points (w.r.t. nonfixed variables) */
9133  int nvars, /**< number of nonfixed variables */
9134  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9135  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9136  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an zero'ed array of length at least nallvars */
9137  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9138  )
9139 { /*lint --e{715}*/
9140  SCIP_CONSHDLRDATA* conshdlrdata;
9141  SCIP_LPI* lp;
9142  SCIP_Real* aux; /* used to transform x^* and then to store LP solution */
9143  int* inds;
9144  int ncols;
9145  int nrows;
9146  int i;
9147  SCIP_Real facetvalue;
9148  SCIP_Real mindomwidth;
9149  SCIP_RETCODE lpsolveretcode;
9150 
9151  assert(scip != NULL);
9152  assert(conshdlr != NULL);
9153  assert(xstar != NULL);
9154  assert(box != NULL);
9155  assert(nonfixedpos != NULL);
9156  assert(funvals != NULL);
9157  assert(nvars >= 0);
9158  assert(nvars <= SCIP_MAXVERTEXPOLYDIM);
9159  assert(success != NULL);
9160  assert(facetcoefs != NULL);
9161  assert(facetconstant != NULL);
9162 
9163  *success = FALSE;
9164 
9165  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9166  assert(conshdlrdata != NULL);
9167 
9168  if( conshdlrdata->vp_randnumgen == NULL && conshdlrdata->vp_maxperturb > 0.0 )
9169  {
9170  SCIP_CALL( SCIPcreateRandom(scip, &conshdlrdata->vp_randnumgen, VERTEXPOLY_RANDNUMINITSEED, TRUE) );
9171  }
9172 
9173  /* construct an LP for this size, if not having one already */
9174  if( conshdlrdata->vp_lp[nvars] == NULL )
9175  {
9176  SCIP_CALL( buildVertexPolyhedralSeparationLP(scip, nvars, &conshdlrdata->vp_lp[nvars]) );
9177  }
9178  lp = conshdlrdata->vp_lp[nvars];
9179  assert(lp != NULL);
9180 
9181  /* get number of cols and rows of separation lp */
9182  SCIP_CALL( SCIPlpiGetNCols(lp, &ncols) );
9183  SCIP_CALL( SCIPlpiGetNRows(lp, &nrows) );
9184 
9185  /* number of columns should equal the number of corners = 2^nvars */
9186  assert(ncols == (int)POWEROFTWO(nvars));
9187 
9188  /* allocate necessary memory */
9189  SCIP_CALL( SCIPallocBufferArray(scip, &aux, nrows) );
9190  SCIP_CALL( SCIPallocBufferArray(scip, &inds, ncols) );
9191 
9192  /*
9193  * set up the described LP on the transformed space
9194  */
9195 
9196  for( i = 0; i < ncols; ++i )
9197  inds[i] = i;
9198 
9199  /* compute T^-1(x^*), i.e. T^-1(x^*)_i = (x^*_i - lb_i)/(ub_i - lb_i) */
9200  mindomwidth = 2*SCIPinfinity(scip);
9201  for( i = 0; i < nrows-1; ++i )
9202  {
9203  SCIP_Real solval;
9204  SCIP_Real lb;
9205  SCIP_Real ub;
9206  int varpos;
9207 
9208  assert(i < nvars);
9209 
9210  varpos = nonfixedpos[i];
9211  lb = box[2 * varpos];
9212  ub = box[2 * varpos + 1];
9213  solval = xstar[varpos];
9214 
9215  if( ub - lb < mindomwidth )
9216  mindomwidth = ub - lb;
9217 
9218  /* explicitly handle solution which violate bounds of variables (this can happen because of tolerances) */
9219  if( solval <= lb )
9220  aux[i] = 0.0;
9221  else if( solval >= ub )
9222  aux[i] = 1.0;
9223  else
9224  aux[i] = (solval - lb) / (ub - lb);
9225 
9226  /* perturb point to hopefully obtain a facet of the convex envelope */
9227  if( conshdlrdata->vp_maxperturb > 0.0 )
9228  {
9229  assert(conshdlrdata->vp_randnumgen != NULL);
9230 
9231  if( aux[i] == 1.0 )
9232  aux[i] -= SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9233  else if( aux[i] == 0.0 )
9234  aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, 0.0, conshdlrdata->vp_maxperturb);
9235  else
9236  {
9237  SCIP_Real perturbation;
9238 
9239  perturbation = MIN( aux[i], 1.0 - aux[i] ) / 2.0;
9240  perturbation = MIN( perturbation, conshdlrdata->vp_maxperturb );
9241  aux[i] += SCIPrandomGetReal(conshdlrdata->vp_randnumgen, -perturbation, perturbation);
9242  }
9243  assert(0.0 < aux[i] && aux[i] < 1.0);
9244  }
9245 
9246  SCIPdebugMsg(scip, "LP row %d in [%e, %e]\n", i, aux[i], aux[i]);
9247  }
9248 
9249  /* update LP */
9250  SCIP_CALL( SCIPlpiChgObj(lp, ncols, inds, funvals) );
9251  SCIP_CALL( SCIPlpiChgSides(lp, nrows-1, inds, aux, aux) );
9253 
9254  /* we can stop the LP solve if will not meet the target value anyway, but only if xstar hasn't been perturbed */
9255  if( conshdlrdata->vp_maxperturb == 0.0 && !SCIPisInfinity(scip, REALABS(targetvalue)) )
9256  {
9257  SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_OBJLIM, targetvalue) );
9258  }
9259  /* set an iteration limit so we do not run forever */
9260  SCIP_CALL( SCIPlpiSetIntpar(lp, SCIP_LPPAR_LPITLIM, 100*ncols) );
9261  /* 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 */
9263  /* since we work with the dual of the LP, dual feastol determines validity of the facet
9264  * if some ub-lb is small, we need higher accuracy, since below we divide coefs by ub-lb (we moved and scaled the box)
9265  * thus, we set the dual feastol to be between SCIPepsilon and SCIPfeastol
9266  */
9267  SCIP_CALL( SCIPlpiSetRealpar(lp, SCIP_LPPAR_DUALFEASTOL, MIN(SCIPfeastol(scip), MAX(SCIPepsilon(scip), mindomwidth * SCIPfeastol(scip)))) );
9268 
9269 #ifdef SCIP_DEBUG
9271 #endif
9272 
9273  /*
9274  * solve the LP and store the resulting facet for the transformed space
9275  */
9276  if( conshdlrdata->vp_dualsimplex )
9277  {
9278  lpsolveretcode = SCIPlpiSolveDual(lp);
9279  }
9280  else
9281  {
9282  lpsolveretcode = SCIPlpiSolvePrimal(lp);
9283  }
9284  if( lpsolveretcode == SCIP_LPERROR )
9285  {
9286  SCIPdebugMsg(scip, "LP error, aborting.\n");
9287  goto CLEANUP;
9288  }
9289  SCIP_CALL( lpsolveretcode );
9290 
9291  /* any dual feasible solution should provide a valid estimator (and a dual optimal one a facet) */
9292  if( !SCIPlpiIsDualFeasible(lp) )
9293  {
9294  SCIPdebugMsg(scip, "LP not solved to dual feasibility, aborting.\n");
9295  goto CLEANUP;
9296  }
9297 
9298  /* get dual solution (facet of convex envelope); again, we have to be careful since the LP can have more rows and
9299  * columns than needed, in particular, \bar \beta is the last dual multiplier
9300  */
9301  SCIP_CALL( SCIPlpiGetSol(lp, NULL, NULL, aux, NULL, NULL) );
9302 
9303  for( i = 0; i < nvars; ++i )
9304  facetcoefs[nonfixedpos[i]] = aux[i];
9305  /* last dual multiplier is the constant */
9306  *facetconstant = aux[nrows - 1];
9307 
9308 #ifdef SCIP_DEBUG
9309  SCIPdebugMsg(scip, "facet for the transformed problem: ");
9310  for( i = 0; i < nallvars; ++i )
9311  {
9312  SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[i], i);
9313  }
9314  SCIPdebugMsgPrint(scip, "%3.4e\n", *facetconstant);
9315 #endif
9316 
9317  /*
9318  * transform the facet to original space and compute value at x^*, i.e., alpha x + beta
9319  */
9320 
9321  SCIPdebugMsg(scip, "facet in orig. space: ");
9322 
9323  facetvalue = 0.0;
9324  for( i = 0; i < nvars; ++i )
9325  {
9326  SCIP_Real lb;
9327  SCIP_Real ub;
9328  int varpos;
9329 
9330  varpos = nonfixedpos[i];
9331  lb = box[2 * varpos];
9332  ub = box[2 * varpos + 1];
9333  assert(!SCIPisEQ(scip, lb, ub));
9334 
9335  /* alpha_i := alpha_bar_i / (ub_i - lb_i) */
9336  facetcoefs[varpos] = facetcoefs[varpos] / (ub - lb);
9337 
9338  /* beta = beta_bar - sum_i alpha_i * lb_i */
9339  *facetconstant -= facetcoefs[varpos] * lb;
9340 
9341  /* evaluate */
9342  facetvalue += facetcoefs[varpos] * xstar[varpos];
9343 
9344  SCIPdebugMsgPrint(scip, "%3.4e * x%d + ", facetcoefs[varpos], varpos);
9345  }
9346  SCIPdebugMsgPrint(scip, "%3.4e ", *facetconstant);
9347 
9348  /* add beta to the facetvalue: at this point in the code, facetvalue = g(x^*) */
9349  facetvalue += *facetconstant;
9350 
9351  SCIPdebugMsgPrint(scip, "has value %g, target = %g\n", facetvalue, targetvalue);
9352 
9353  /* if overestimate, then we want facetvalue < targetvalue
9354  * if underestimate, then we want facetvalue > targetvalue
9355  * if none holds, give up
9356  * so maybe here we should check against the minimal violation
9357  */
9358  if( overestimate == (facetvalue > targetvalue) )
9359  {
9360  SCIPdebugMsg(scip, "missed the target, facetvalue %g targetvalue %g, overestimate=%u\n", facetvalue, targetvalue, overestimate);
9361  goto CLEANUP;
9362  }
9363 
9364  /* if we made it until here, then we have a nice facet */
9365  *success = TRUE;
9366 
9367 CLEANUP:
9368  /* free allocated memory */
9369  SCIPfreeBufferArray(scip, &inds);
9370  SCIPfreeBufferArray(scip, &aux);
9371 
9372  return SCIP_OKAY;
9373 }
9374 
9375 /** computes a facet of the convex or concave envelope of a univariate vertex polyhedral function
9376  *
9377  * In other words, compute the line that passes through two given points.
9378  */
9379 static
9381  SCIP* scip, /**< SCIP data structure */
9382  SCIP_Real left, /**< left coordinate */
9383  SCIP_Real right, /**< right coordinate */
9384  SCIP_Real funleft, /**< value of function in left coordinate */
9385  SCIP_Real funright, /**< value of function in right coordinate */
9386  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9387  SCIP_Real* facetcoef, /**< buffer to store coefficient of facet defining inequality */
9388  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9389  )
9390 {
9391  assert(scip != NULL);
9392  assert(SCIPisLE(scip, left, right));
9393  assert(!SCIPisInfinity(scip, -left));
9394  assert(!SCIPisInfinity(scip, right));
9395  assert(SCIPisFinite(funleft) && funleft != SCIP_INVALID);
9396  assert(SCIPisFinite(funright) && funright != SCIP_INVALID);
9397  assert(success != NULL);
9398  assert(facetcoef != NULL);
9399  assert(facetconstant != NULL);
9400 
9401  *facetcoef = (funright - funleft) / (right - left);
9402  *facetconstant = funleft - *facetcoef * left;
9403 
9404  *success = TRUE;
9405 
9406  return SCIP_OKAY;
9407 }
9408 
9409 /** given three points, constructs coefficient of equation for hyperplane generated by these three points
9410  *
9411  * Three points a, b, and c are given.
9412  * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9413  * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9414  */
9415 static
9417  SCIP* scip, /**< SCIP data structure */
9418  SCIP_Real a1, /**< first coordinate of a */
9419  SCIP_Real a2, /**< second coordinate of a */
9420  SCIP_Real a3, /**< third coordinate of a */
9421  SCIP_Real b1, /**< first coordinate of b */
9422  SCIP_Real b2, /**< second coordinate of b */
9423  SCIP_Real b3, /**< third coordinate of b */
9424  SCIP_Real c1, /**< first coordinate of c */
9425  SCIP_Real c2, /**< second coordinate of c */
9426  SCIP_Real c3, /**< third coordinate of c */
9427  SCIP_Real* alpha, /**< coefficient of first coordinate */
9428  SCIP_Real* beta, /**< coefficient of second coordinate */
9429  SCIP_Real* gamma_, /**< coefficient of third coordinate */
9430  SCIP_Real* delta /**< constant right-hand side */
9431  )
9432 {
9433  assert(scip != NULL);
9434  assert(alpha != NULL);
9435  assert(beta != NULL);
9436  assert(gamma_ != NULL);
9437  assert(delta != NULL);
9438 
9439  *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
9440  *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
9441  *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
9442  *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
9443 
9444  /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
9445 
9446  if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
9447  SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
9448  SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
9449  {
9450  SCIPdebugMsg(scip, "activity above SCIP infinity\n");
9451  *delta = 0.0;
9452  *alpha = 0.0;
9453  *beta = 0.0;
9454  *gamma_ = 0.0;
9455  return SCIP_OKAY;
9456  }
9457 
9458  /* check if hyperplane contains all three points (necessary because of numerical troubles) */
9459  if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9460  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9461  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
9462  {
9463  SCIP_Real m[9];
9464  SCIP_Real rhs[3];
9465  SCIP_Real x[3];
9466  SCIP_Bool success;
9467 
9468  /*
9469  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));
9470  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));
9471  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));
9472  */
9473 
9474  /* initialize matrix column-wise */
9475  m[0] = a1;
9476  m[1] = b1;
9477  m[2] = c1;
9478  m[3] = a2;
9479  m[4] = b2;
9480  m[5] = c2;
9481  m[6] = a3;
9482  m[7] = b3;
9483  m[8] = c3;
9484 
9485  rhs[0] = 1.0;
9486  rhs[1] = 1.0;
9487  rhs[2] = 1.0;
9488 
9489  SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
9490 
9491  /* solve the linear problem */
9492  SCIP_CALL( SCIPlapackSolveLinearEquations(SCIPbuffer(scip), 3, m, rhs, x, &success) );
9493 
9494  *delta = rhs[0];
9495  *alpha = x[0];
9496  *beta = x[1];
9497  *gamma_ = x[2];
9498 
9499  /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
9500  * not add a cut to SCIP and that all assertions are trivially fulfilled
9501  */
9502  if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
9503  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
9504  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
9505  {
9506  SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
9507  *delta = 0.0;
9508  *alpha = 0.0;
9509  *beta = 0.0;
9510  *gamma_ = 0.0;
9511  }
9512  }
9513 
9514  if( *gamma_ < 0.0 )
9515  {
9516  *alpha = -*alpha;
9517  *beta = -*beta;
9518  *gamma_ = -*gamma_;
9519  *delta = -*delta;
9520  }
9521 
9522  return SCIP_OKAY;
9523 }
9524 
9525 /** computes a facet of the convex or concave envelope of a bivariate vertex polyhedral function */
9526 static
9528  SCIP* scip, /**< SCIP data structure */
9529  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
9530  SCIP_Real p1[2], /**< first vertex of box */
9531  SCIP_Real p2[2], /**< second vertex of box */
9532  SCIP_Real p3[2], /**< third vertex of box */
9533  SCIP_Real p4[2], /**< forth vertex of box */
9534  SCIP_Real p1val, /**< value in p1 */
9535  SCIP_Real p2val, /**< value in p2 */
9536  SCIP_Real p3val, /**< value in p3 */
9537  SCIP_Real p4val, /**< value in p4 */
9538  SCIP_Real xstar[2], /**< point to be separated */
9539  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
9540  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
9541  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least 2 */
9542  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
9543  )
9544 {
9545  SCIP_Real alpha, beta, gamma_, delta;
9546  SCIP_Real xstarval, candxstarval = 0.0;
9547  int leaveout;
9548 
9549  assert(scip != NULL);
9550  assert(success != NULL);
9551  assert(SCIPisFinite(p1val) && p1val != SCIP_INVALID);
9552  assert(SCIPisFinite(p2val) && p2val != SCIP_INVALID);
9553  assert(SCIPisFinite(p3val) && p3val != SCIP_INVALID);
9554  assert(SCIPisFinite(p4val) && p4val != SCIP_INVALID);
9555  assert(facetcoefs != NULL);
9556  assert(facetconstant != NULL);
9557 
9558  *success = FALSE;
9559 
9560  /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
9561  if( !overestimate )
9562  {
9563  p1val = -p1val;
9564  p2val = -p2val;
9565  p3val = -p3val;
9566  p4val = -p4val;
9567  targetvalue = -targetvalue;
9568  }
9569 
9570  SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
9571  SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
9572  SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
9573  SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
9574 
9575  /* Compute coefficients alpha, beta, gamma (>0), delta such that
9576  * alpha*x + beta*y + gamma*z = delta
9577  * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
9578  * the fourth corner point lies below this hyperplane.
9579  * 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.,
9580  * alpha*x + beta*y - delta <= -gamma * f(x,y),
9581  * or, equivalently,
9582  * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
9583  */
9584  for( leaveout = 1; leaveout <= 4; ++leaveout )
9585  {
9586  switch( leaveout)
9587  {
9588  case 1 :
9589  /* get hyperplane through p2, p3, p4 */
9590  SCIP_CALL( computeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9591  &alpha, &beta, &gamma_, &delta) );
9592  /* if not underestimating in p1, then go to next candidate */
9593  if( alpha * p1[0] + beta * p1[1] + gamma_ * p1val - delta > 0.0 )
9594  continue;
9595  break;
9596 
9597  case 2 :
9598  /* get hyperplane through p1, p3, p4 */
9599  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
9600  &alpha, &beta, &gamma_, &delta) );
9601  /* if not underestimating in p2, then go to next candidate */
9602  if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val - delta > 0.0 )
9603  continue;
9604  break;
9605 
9606  case 3 :
9607  /* get hyperplane through p1, p2, p4 */
9608  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
9609  &alpha, &beta, &gamma_, &delta) );
9610  /* if not underestimating in p3, then go to next candidate */
9611  if( alpha * p3[0] + beta * p3[1] + gamma_ * p3val - delta > 0.0 )
9612  continue;
9613  break;
9614 
9615  case 4 :
9616  /* get hyperplane through p1, p2, p3 */
9617  SCIP_CALL( computeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
9618  &alpha, &beta, &gamma_, &delta) );
9619  /* if not underestimating in p4, then stop */
9620  if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val - delta > 0.0 )
9621  continue;
9622  break;
9623 
9624  default: /* only for lint */
9625  alpha = SCIP_INVALID;
9626  beta = SCIP_INVALID;
9627  gamma_ = SCIP_INVALID;
9628  delta = SCIP_INVALID;
9629  break;
9630  }
9631 
9632  /* check if bad luck: should not happen if numerics are fine */
9633  if( SCIPisZero(scip, gamma_) )
9634  continue;
9635  assert(!SCIPisNegative(scip, gamma_));
9636 
9637  /* if coefficients become tiny because division by gamma makes them < SCIPepsilon(scip), then skip, too */
9638  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
9639  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta/gamma_)) )
9640  continue;
9641 
9642  SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
9643 
9644  /* value of hyperplane candidate in xstar */
9645  xstarval = -alpha/gamma_ * xstar[0] -beta/gamma_ * xstar[1] + delta/gamma_;
9646 
9647  /* if reaching target and first or better than previous candidate, then update */
9648  if( xstarval <= targetvalue && (!*success || xstarval < candxstarval) )
9649  {
9650  /* flip hyperplane */
9651  if( !overestimate )
9652  gamma_ = -gamma_;
9653 
9654  facetcoefs[0] = -alpha/gamma_;
9655  facetcoefs[1] = -beta/gamma_;
9656  *facetconstant = delta/gamma_;
9657 
9658  *success = TRUE;
9659  candxstarval = xstarval;
9660  }
9661  }
9662 
9663  return SCIP_OKAY;
9664 }
9665 
9666 /** ensures that we can store information about open expressions (i.e., not fully encoded in the symmetry detection
9667  * graph yet) in an array
9668  */
9669 static
9671  SCIP* scip, /**< SCIP pointer */
9672  int** openidx, /**< address of openidx array */
9673  int nelems, /**< number of elements that need to be stored */
9674  int* maxnelems /**< pointer to store maximum number that can be stored */
9675  )
9676 {
9677  assert(scip != NULL);
9678  assert(openidx != NULL);
9679  assert(maxnelems != NULL);
9680 
9681  if( nelems > *maxnelems )
9682  {
9683  int newsize;
9684 
9685  newsize = SCIPcalcMemGrowSize(scip, nelems);
9686  assert(newsize >= nelems);
9687 
9688  SCIP_CALL( SCIPreallocBufferArray(scip, openidx, newsize) );
9689 
9690  *maxnelems = newsize;
9691  }
9692 
9693  return SCIP_OKAY;
9694 }
9695 
9696 /** ensures that we can store information about local variables in an array */
9697 static
9699  SCIP* scip, /**< SCIP pointer */
9700  SCIP_VAR*** vars, /**< address of variable array */
9701  SCIP_Real** vals, /**< address of value array */
9702  int nelems, /**< number of elements that need to be stored */
9703  int* maxnelems /**< pointer to store maximum number that can be stored */
9704  )
9705 {
9706  assert(scip != NULL);
9707  assert(vars != NULL);
9708  assert(vals != NULL);
9709  assert(maxnelems != NULL);
9710 
9711  if( nelems > *maxnelems )
9712  {
9713  int newsize;
9714 
9715  newsize = SCIPcalcMemGrowSize(scip, nelems);
9716  assert(newsize > *maxnelems);
9717 
9718  SCIP_CALL( SCIPreallocBufferArray(scip, vars, newsize) );
9719  SCIP_CALL( SCIPreallocBufferArray(scip, vals, newsize) );
9720 
9721  *maxnelems = newsize;
9722  }
9723 
9724  return SCIP_OKAY;
9725 }
9726 
9727 /** tries to add gadget for finding signed permutations of bilinear products
9728  *
9729  * If a product has exactly two children being variables, negating both simultanteoulsy
9730  * is a signed permutation.
9731  */
9732 static
9734  SCIP* scip, /**< SCIP pointer */
9735  SCIP_EXPR* expr, /**< product expression for which gadget is tried to be added */
9736  SCIP_CONS* cons, /**< constraint containing product expression */
9737  SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9738  int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9739  SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9740  SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9741  SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9742  SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9743  int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9744  SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
9745  SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9746  )
9747 {
9748  SYM_EXPRDATA* symdata;
9749  SCIP_EXPR** children;
9750  SCIP_VAR* var1 = NULL;
9751  SCIP_VAR* var2 = NULL;
9752  SCIP_Real val1 = 0.0;
9753  SCIP_Real val2 = 0.0;
9754  SCIP_Real coef;
9755  SCIP_Real prodval;
9756  SCIP_Real constant;
9757  int nlocvars;
9758  int optype;
9759  int nchildren;
9760  int prodidx;
9761  int coefidx1;
9762  int coefidx2;
9763  int childidx;
9764 
9765  assert(scip != NULL);
9766  assert(expr != NULL);
9767  assert(SCIPisExprProduct(scip, expr));
9768  assert(graph != NULL);
9769  assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
9770  assert(consvars != NULL);
9771  assert(consvals != NULL);
9772  assert(maxnconsvars != NULL);
9773  assert(*maxnconsvars > 0);
9774  assert(handledexprs != NULL);
9775  assert(success != NULL);
9776 
9777  *success = FALSE;
9778 
9779  /* we require exactly two children being variables */
9780  nchildren = SCIPexprGetNChildren(expr);
9781  if( nchildren != 2 )
9782  return SCIP_OKAY;
9783 
9784  children = SCIPexprGetChildren(expr);
9785  if( !SCIPisExprVar(scip, children[0]) || !SCIPisExprVar(scip, children[1]) )
9786  return SCIP_OKAY;
9787 
9788  /* check whether each child is not multi-aggregated and is not shifted */
9789  SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, SCIPexprGetNChildren(expr), maxnconsvars) );
9790 
9791  for( childidx = 0; childidx < 2; ++childidx )
9792  {
9793  (*consvars)[0] = SCIPgetVarExprVar(children[childidx]);
9794  (*consvals)[0] = 1.0;
9795  nlocvars = 1;
9796  constant = 0.0;
9797 
9798  SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars,
9799  &constant, SCIPconsIsTransformed(cons)) );
9800 
9801  if( nlocvars != 1 || !SCIPisZero(scip, constant) )
9802  return SCIP_OKAY;
9803 
9804  if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal((*consvars)[0]))
9805  != SCIPisInfinity(scip, -SCIPvarGetLbGlobal((*consvars)[0]))) )
9806  return SCIP_OKAY;
9807 
9808  /* store information about variables */
9809  if( childidx == 0 )
9810  {
9811  var1 = (*consvars)[0];
9812  val1 = (*consvals)[0];
9813  }
9814  else
9815  {
9816  var2 = (*consvars)[0];
9817  val2 = (*consvals)[0];
9818  }
9819  }
9820  assert(var1 != NULL);
9821  assert(var2 != NULL);
9822 
9823  /* store the we handle the children */
9824  SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[0]) );
9825  SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[1]) );
9826 
9827  SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
9828  assert(symdata != NULL);
9829  assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9830 
9831  coef = SCIPgetSymExprdataConstants(symdata)[0];
9832 
9833  SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
9834 
9835  /* add gadget modeling the product
9836  *
9837  * Since the constants are 0, each variable is centered at the origin, which leads to
9838  * a product of the form \f$(\alpha x)\cdot(\gamma y)\f$. Manipulating the formula leads
9839  * to \f$\alpha \gamma (x \cdot y)\f$, which is modeled in a gadget that allows to
9840  * negate both variables simulataneously.
9841  */
9843  SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &prodidx) );
9844  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, prodidx, hasparentcoef, parentcoef) );
9845 
9846  prodval = coef * val1 * val2;
9847 
9848  /* introduce nodes for the product value and its negation; since flipping both variables
9849  * simultaneously is a signed symmetry, assign both nodes the same value
9850  */
9851  SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx1) );
9852  SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, prodval, &coefidx2) );
9853 
9854  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx1, FALSE, 0.0) );
9855  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, prodidx, coefidx2, FALSE, 0.0) );
9856  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1, coefidx2, FALSE, 0.0) );
9857 
9858  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
9859  SCIPgetSymgraphVarnodeidx(scip, graph, var1), FALSE, 0.0) );
9860  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx1,
9861  SCIPgetSymgraphVarnodeidx(scip, graph, var2), FALSE, 0.0) );
9862  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
9863  SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var1), FALSE, 0.0) );
9864  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefidx2,
9865  SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var2), FALSE, 0.0) );
9866 
9867  *success = TRUE;
9868 
9869  return SCIP_OKAY;
9870 }
9871 
9872 /** returns whether an operator is even and, if yes, stores data about operator */
9873 static
9875  SCIP* scip, /**< SCIP pointer */
9876  SCIP_EXPR* expr, /**< expression corresponding to operator */
9877  SCIP_Bool* hasvalue, /**< pointer to store whether even operator has a value
9878  * needed for symmetry computation */
9879  SCIP_Real* value /**< pointer to store value for symmetry computation */
9880  )
9881 {
9882  SYM_EXPRDATA* symdata;
9883 
9884  assert(scip != NULL);
9885  assert(expr != NULL);
9886  assert(hasvalue != NULL);
9887  assert(value != NULL);
9888 
9889  /* check for different operators known to be even */
9890  if( SCIPisExprSignpower(scip, expr) || SCIPisExprCos(scip, expr) )
9891  {
9892  /* get remaining information needed for symmetry detection */
9893  if( SCIPisExprSignpower(scip, expr) )
9894  {
9895  SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
9896  assert(symdata != NULL);
9897  assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9898 
9899  *value = SCIPgetSymExprdataConstants(symdata)[0];
9900  *hasvalue = !SCIPisEQ(scip, *value, 1.0);
9901 
9902  SCIP_CALL_ABORT( SCIPfreeSymDataExpr(scip, &symdata) );
9903  }
9904  else
9905  {
9906  assert(SCIPisExprCos(scip, expr));
9907  *hasvalue = FALSE;
9908  }
9909 
9910  return TRUE;
9911  }
9912  else if( SCIPisExprPower(scip, expr) )
9913  {
9914  SCIP_Real exponent;
9915  int safeexponent;
9916 
9917  /* only consider expressions corresponding to an even power */
9918  SCIP_CALL_ABORT( SCIPgetSymDataExpr(scip, expr, &symdata) );
9919  assert(symdata != NULL);
9920  assert(SCIPgetSymExprdataNConstants(symdata) == 1);
9921 
9922  exponent = SCIPgetSymExprdataConstants(symdata)[0];
9923  SCIP_CALL_ABORT( SCIPfreeSymDataExpr(scip, &symdata) );
9924 
9925  /* check whether the exponent is an even integer */
9926  if( !SCIPisIntegral(scip, exponent) || SCIPisLE(scip, exponent, 0.0) )
9927  return FALSE;
9928 
9929  /* deal with numerics */
9930  safeexponent = (int) (exponent + 0.5);
9931  if( safeexponent % 2 != 0 )
9932  return FALSE;
9933 
9934  *hasvalue = TRUE;
9935  *value = exponent;
9936 
9937  return TRUE;
9938  }
9939  else if( SCIPisExprAbs(scip, expr) )
9940  {
9941  *hasvalue = FALSE;
9942 
9943  return TRUE;
9944  }
9945 
9946  return FALSE;
9947 }
9948 
9949 /** returns whether a variable is centered at 0 */
9950 static
9952  SCIP* scip, /**< SCIP pointer */
9953  SCIP_VAR* var /**< variable to be checked */
9954  )
9955 {
9956  assert(scip != NULL);
9957  assert(var != NULL);
9958 
9959  if( (SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) != SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var))) )
9960  return FALSE;
9961 
9962  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
9963  return TRUE;
9964 
9965  if( SCIPisEQ(scip, SCIPvarGetUbGlobal(var), -SCIPvarGetLbGlobal(var)) )
9966  return TRUE;
9967 
9968  return FALSE;
9969 }
9970 
9971 /** tries to add gadget for finding signed permutation of even univariate operators with variable child */
9972 static
9974  SCIP* scip, /**< SCIP pointer */
9975  SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
9976  SCIP_EXPR* child, /**< child expression of evenopexpr */
9977  SCIP_CONS* cons, /**< constraint containing expression */
9978  SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
9979  int parentidx, /**< index of parent node in symmetry detection graph for gadget */
9980  SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
9981  SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
9982  SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
9983  SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
9984  SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
9985  SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
9986  int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
9987  SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
9988  )
9989 {
9990  SCIP_VAR* var;
9991  SCIP_Real constant;
9992  SCIP_Real edgeweight;
9993  int nlocvars;
9994  int nodeidx;
9995  int optype;
9996  int thisopidx;
9997 
9998  assert(scip != NULL);
9999  assert(evenopexpr != NULL);
10000  assert(child != NULL);
10001  assert(SCIPisExprVar(scip, child));
10002  assert(cons != NULL);
10003  assert(graph != NULL);
10004  assert(parentidx >= 0);
10005  assert(consvars != NULL);
10006  assert(consvals != NULL);
10007  assert(maxnconsvars != NULL);
10008  assert(success != NULL);
10009 
10010  *success = FALSE;
10011 
10012  /* check whether child variable is (multi-)aggregated */
10013  var = SCIPgetVarExprVar(child);
10014  (*consvars)[0] = var;
10015  (*consvals)[0] = 1.0;
10016  constant = 0.0;
10017  nlocvars = 1;
10018 
10019  SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10020  SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10021  SCIPconsIsTransformed(cons)) );
10022 
10023  /* skip multi-aggregated variables or variables with domain not centered at 0 */
10024  if( nlocvars != 1 || !SCIPisZero(scip, constant) )
10025  return SCIP_OKAY;
10026 
10027  if( !varIsCenteredAt0(scip, var) )
10028  return SCIP_OKAY;
10029 
10030  /* store partial information for gadget */
10031  var = (*consvars)[0];
10032  edgeweight = (*consvals)[0];
10033 
10034  /* add gadget to graph for even univariate expression */
10035  *success = TRUE;
10036 
10037  SCIP_CALL( SCIPgetSymOpNodeType(scip, SCIPexprhdlrGetName(SCIPexprGetHdlr(evenopexpr)), &optype) );
10038 
10039  SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10040  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10041 
10042  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10043  TRUE, edgeweight) );
10044  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var),
10045  TRUE, edgeweight) );
10046 
10047  if( hassymval )
10048  {
10049  SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10050  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10051  }
10052 
10053  return SCIP_OKAY;
10054 }
10055 
10056 /** tries to add gadget for finding signed permutation of even univariate operators with sum child */
10057 static
10059  SCIP* scip, /**< SCIP pointer */
10060  SCIP_EXPR* evenopexpr, /**< even operator expression for which gadget is tried to be added */
10061  SCIP_EXPR* child, /**< child expression of evenopexpr */
10062  SCIP_CONS* cons, /**< constraint containing expression */
10063  SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10064  int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10065  SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10066  SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10067  SCIP_Bool hassymval, /**< whether evenopexpr has a value needed for symmetry detection */
10068  SCIP_Real symval, /**< value needed for symmetry detection (if hassymval is TRUE) */
10069  SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10070  SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10071  int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10072  SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10073  SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10074  )
10075 {
10076  SCIP_VAR* var;
10077  SCIP_Real constant;
10078  SCIP_Real weight;
10079  int nlocvars;
10080  int nodeidx;
10081  int optype;
10082  int thisopidx;
10083  int i;
10084 
10085  assert(scip != NULL);
10086  assert(evenopexpr != NULL);
10087  assert(child != NULL);
10088  assert(SCIPisExprSum(scip, child));
10089  assert(cons != NULL);
10090  assert(graph != NULL);
10091  assert(parentidx >= 0);
10092  assert(consvars != NULL);
10093  assert(consvals != NULL);
10094  assert(maxnconsvars != NULL);
10095  assert(handledexprs != NULL);
10096  assert(success != NULL);
10097 
10098  *success = FALSE;
10099 
10100  /* check whether child variable is (multi-)aggregated and whether all children are variables */
10101  nlocvars = SCIPexprGetNChildren(child);
10102 
10103  SCIP_CALL( ensureLocVarsArraySize(scip, consvars, consvals, nlocvars, maxnconsvars) );
10104 
10105  for( i = 0; i < nlocvars; ++i)
10106  {
10107  if( SCIPisExprVar(scip, SCIPexprGetChildren(child)[i]) )
10108  {
10109  (*consvars)[i] = SCIPgetVarExprVar(SCIPexprGetChildren(child)[i]);
10110  (*consvals)[i] = SCIPgetCoefsExprSum(child)[i];
10111  }
10112  else
10113  return SCIP_OKAY;
10114  }
10115  constant = SCIPgetConstantExprSum(child);
10116 
10117  SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals, &nlocvars, &constant,
10118  SCIPconsIsTransformed(cons)) );
10119 
10120  /* we can only handle the case without constant and two variables with domain centered at origin */
10121  if( nlocvars > 2 || !SCIPisZero(scip, constant) )
10122  return SCIP_OKAY;
10123  assert(nlocvars > 0);
10124 
10125  var = (*consvars)[0];
10126  if( !varIsCenteredAt0(scip, var) )
10127  return SCIP_OKAY;
10128 
10129  if( nlocvars == 2 )
10130  {
10131  var = (*consvars)[1];
10132  if( !varIsCenteredAt0(scip, var) )
10133  return SCIP_OKAY;
10134  }
10135 
10136  /* add gadget to graph for even univariate expression that have a sum of at most two variables as child */
10137  *success = TRUE;
10138  for( i = 0; i < SCIPexprGetNChildren(child); ++i )
10139  {
10140  SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) SCIPexprGetChildren(child)[i]) );
10141  }
10142 
10143  SCIP_CALL( SCIPgetSymOpNodeType(scip, SCIPexprhdlrGetName(SCIPexprGetHdlr(evenopexpr)), &optype) );
10144 
10145  SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &thisopidx) );
10146  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisopidx, hasparentcoef, parentcoef) );
10147 
10148  if( hassymval )
10149  {
10150  SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, symval, &nodeidx) );
10151  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, nodeidx, FALSE, 0.0) );
10152  }
10153 
10154  if( nlocvars == 1 )
10155  {
10156  var = (*consvars)[0];
10157  weight = (*consvals)[0];
10158 
10159  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10160  TRUE, weight) );
10161  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, thisopidx, SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var),
10162  TRUE, weight) );
10163  }
10164  else
10165  {
10166  int dummyidx1;
10167  int dummyidx2;
10168 
10169  /* add dummy nodes for gadget */
10170  SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx1) );
10171  SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &dummyidx2) );
10172 
10173  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, thisopidx, FALSE, 0.0) );
10174  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, thisopidx, FALSE, 0.0) );
10175  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, dummyidx2, FALSE, 0.0) );
10176 
10177  /* connect dummy nodes with variables */
10178  for( i = 0; i < 2; ++i)
10179  {
10180  var = (*consvars)[i];
10181  weight = ABS((*consvals)[i]);
10182 
10183  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx1, SCIPgetSymgraphVarnodeidx(scip, graph, var),
10184  TRUE, weight) );
10185  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, dummyidx2, SCIPgetSymgraphNegatedVarnodeidx(scip, graph, var),
10186  TRUE, weight) );
10187  }
10188  }
10189 
10190  return SCIP_OKAY;
10191 }
10192 
10193 /** tries to add gadget for finding signed permutations of even univariate operators
10194  *
10195  * We handle two cases. First, if a univariate operator is even and has a variable
10196  * as child, negating the child is signed permutation. Second, the univariate operator
10197  * is even and has a weighted sum of two variables as child.
10198  */
10199 static
10201  SCIP* scip, /**< SCIP pointer */
10202  SCIP_EXPR* expr, /**< expression for which gadget is tried to be added */
10203  SCIP_CONS* cons, /**< constraint containing expression */
10204  SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10205  int parentidx, /**< index of parent node in symmetry detection graph for gadget */
10206  SCIP_Bool hasparentcoef, /**< whether the parent gives a coefficient to the expression */
10207  SCIP_Real parentcoef, /**< the parent coefficient (if it exists) */
10208  SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10209  SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10210  int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10211  SCIP_HASHSET* handledexprs, /**< hashset to store handled expressions */
10212  SCIP_Bool* success /**< pointer to store whether gadget could be added successfully */
10213  )
10214 {
10215  SCIP_EXPR* child;
10216  SCIP_Real val = 0.0;
10217  SCIP_Bool hasval = FALSE;
10218 
10219  assert(scip != NULL);
10220  assert(expr != NULL);
10221  assert(graph != NULL);
10222  assert(0 <= parentidx && parentidx < SCIPgetSymgraphNNodes(graph));
10223  assert(consvars != NULL);
10224  assert(consvals != NULL);
10225  assert(maxnconsvars != NULL);
10226  assert(*maxnconsvars > 0);
10227  assert(handledexprs != NULL);
10228  assert(success != NULL);
10229 
10230  *success = FALSE;
10231 
10232  /* ignore variable or value expressions */
10233  if( SCIPisExprVar(scip, expr) || SCIPisExprValue(scip, expr) || SCIPisExprVaridx(scip, expr) )
10234  return SCIP_OKAY;
10235  assert(SCIPexprGetNChildren(expr) > 0);
10236 
10237  /* ignore operators with too many children */
10238  if( SCIPexprGetNChildren(expr) > 1 )
10239  return SCIP_OKAY;
10240 
10241  /* check whether operator is even */
10242  if( !isEvenOperator(scip, expr, &hasval, &val) )
10243  return SCIP_OKAY;
10244 
10245  /* we can only treat the operator if its child is a variable or a sum */
10246  child = SCIPexprGetChildren(expr)[0];
10247  if( SCIPisExprVar(scip, child) )
10248  {
10249  SCIP_CALL( tryAddGadgetEvenOperatorVariable(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10250  hasval, val, consvars, consvals, maxnconsvars, success) );
10251  }
10252  else if( SCIPisExprSum(scip, child) )
10253  {
10254  SCIP_CALL( tryAddGadgetEvenOperatorSum(scip, expr, child, cons, graph, parentidx, hasparentcoef, parentcoef,
10255  hasval, val, consvars, consvals, maxnconsvars, handledexprs, success) );
10256  }
10257 
10258  if( *success )
10259  {
10260  SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) child) );
10261  }
10262 
10263  return SCIP_OKAY;
10264 }
10265 
10266 /** compares two variable pointers */
10267 static
10268 SCIP_DECL_SORTINDCOMP(SCIPsortVarPtr)
10269 { /*lint --e{715}*/
10270  SCIP_VAR** vars;
10271  SCIP_VAR* var1;
10272  SCIP_VAR* var2;
10273 
10274  vars = (SCIP_VAR**) dataptr;
10275 
10276  var1 = vars[ind1];
10277  var2 = vars[ind2];
10278  assert(var1 != NULL);
10279  assert(var2 != NULL);
10280 
10281  /* sort variables by their unique index */
10282  if( SCIPvarGetIndex(var1) < SCIPvarGetIndex(var2) )
10283  return -1;
10284  if( SCIPvarGetIndex(var1) > SCIPvarGetIndex(var2) )
10285  return 1;
10286 
10287  return 0;
10288 }
10289 
10290 /** gets domain center of a variable which has not semi-infinite domain */
10291 static
10293  SCIP* scip, /**< SCIP pointer */
10294  SCIP_VAR* var /**< variable */
10295  )
10296 {
10297  SCIP_Real ub;
10298  SCIP_Real lb;
10299 
10300  ub = SCIPvarGetUbGlobal(var);
10301  lb = SCIPvarGetLbGlobal(var);
10302 
10303  assert( SCIPisInfinity(scip, ub) == SCIPisInfinity(scip, -lb) );
10304 
10305  if ( SCIPisInfinity(scip, ub) )
10306  return 0.0;
10307 
10308  return (ub + lb) / 2;
10309 }
10310 
10311 /** tries to add gadget for finding signed permutations for squared differences in a sum expression */
10312 static
10314  SCIP* scip, /**< SCIP pointer */
10315  SCIP_EXPR* sumexpr, /**< sum expression */
10316  SCIP_CONS* cons, /**< constraint containing the sum expression */
10317  SYM_GRAPH* graph, /**< symmetry detection graph to be extended by gadget */
10318  int sumnodeidx, /**< index of sum node in symmetry detection graph for gadget */
10319  SCIP_VAR*** consvars, /**< pointer to allocated array to store temporary variables */
10320  SCIP_Real** consvals, /**< pointer to allocated arrat to store temporary values */
10321  int* maxnconsvars, /**< pointer to maximum number consvars/consvals can hold */
10322  SCIP_HASHSET* handledexprs /**< hashset to store handled expressions */
10323  )
10324 {
10325  SYM_EXPRDATA* symdata;
10326  SCIP_EXPR** children;
10327  SCIP_EXPR** powexprs;
10328  SCIP_EXPR** prodexprs;
10329  SCIP_EXPR* child;
10330  SCIP_VAR** powvars;
10331  SCIP_VAR** prodvars;
10332  SCIP_VAR* actvar;
10333  SCIP_VAR* actvar2;
10334  SCIP_VAR* var;
10335  SCIP_VAR* var2;
10336  SCIP_Real* sumcoefs;
10337  SCIP_Real constant;
10338  SCIP_Real constant2;
10339  SCIP_Real val;
10340  SCIP_Real val2;
10341  SCIP_Bool* powexprused = NULL;
10342  int* powperm = NULL;
10343  int* prodperm = NULL;
10344  int nchildren;
10345  int nlocvars;
10346  int nodeidx;
10347  int coefnodeidx1;
10348  int coefnodeidx2;
10349  int cnt;
10350  int i;
10351  int j;
10352  int nterms;
10353  int npowexprs = 0;
10354  int nprodexprs = 0;
10355  int powcoef = 0;
10356 
10357  assert(scip != NULL);
10358  assert(sumexpr != NULL);
10359  assert(cons != NULL);
10360  assert(SCIPisExprSum(scip, sumexpr));
10361  assert(consvars != NULL);
10362  assert(consvals != NULL);
10363  assert(maxnconsvars != NULL);
10364  assert(*maxnconsvars > 0);
10365  assert(handledexprs != NULL);
10366 
10367  /* iterate over sum expression and extract all power and product expressions */
10368  sumcoefs = SCIPgetCoefsExprSum(sumexpr);
10369  children = SCIPexprGetChildren(sumexpr);
10370  nchildren = SCIPexprGetNChildren(sumexpr);
10371  SCIP_CALL( SCIPallocBufferArray(scip, &powexprs, nchildren) );
10372  SCIP_CALL( SCIPallocBufferArray(scip, &prodexprs, 2 * nchildren) );
10373  SCIP_CALL( SCIPallocBufferArray(scip, &powvars, nchildren) );
10374  SCIP_CALL( SCIPallocBufferArray(scip, &prodvars, 2 * nchildren) );
10375 
10376  /* we scan for norm constraints, i.e., the number of powexpr needs to be twice the prodexpr */
10377  /** @todo make this work in a more general case */
10378  for( i = 0; i < nchildren; ++i )
10379  {
10380  if( SCIPisExprPower(scip, children[i]) )
10381  {
10382  SCIP_Real exponent;
10383 
10384  /* we require a coefficient of +/- 1 from the sum and all power expressions have the same coefficient */
10385  if( powcoef == 0 )
10386  {
10387  if( SCIPisEQ(scip, sumcoefs[i], 1.0) || SCIPisEQ(scip, sumcoefs[i], -1.0) )
10388  powcoef = (int) SCIPround(scip, sumcoefs[i]);
10389  }
10390  else if( !SCIPisEQ(scip, (SCIP_Real) powcoef, sumcoefs[i]) )
10391  continue;
10392 
10393  /* we only store power expressions if their child is a variable */
10394  assert(SCIPexprGetNChildren(children[i]) == 1);
10395  child = SCIPexprGetChildren(children[i])[0];
10396  if( !SCIPisExprVar(scip, child) )
10397  continue;
10398 
10399  /* the power is required to be a 2 */
10400  SCIP_CALL( SCIPgetSymDataExpr(scip, children[i], &symdata) );
10401  assert(symdata != NULL);
10402  assert(SCIPgetSymExprdataNConstants(symdata) == 1);
10403 
10404  exponent = SCIPgetSymExprdataConstants(symdata)[0];
10405  SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10406 
10407  if( !SCIPisEQ(scip, exponent, 2.0) )
10408  continue;
10409 
10410  /* we only store power expressions if the child is not multi-aggregated */
10411  var = SCIPgetVarExprVar(child);
10413  {
10414  powexprs[npowexprs] = children[i];
10415  powvars[npowexprs++] = var;
10416  }
10417  }
10418  else if( SCIPisExprProduct(scip, children[i]) )
10419  {
10420  /* we require a coefficient of +/- 2 from the sum and all product expressions have the same coefficient */
10421  if( powcoef == 0 )
10422  {
10423  if( SCIPisEQ(scip, sumcoefs[i], 2.0) || SCIPisEQ(scip, sumcoefs[i], -2.0) )
10424  powcoef = (int) -SCIPround(scip, sumcoefs[i]);
10425  }
10426  else if( !SCIPisEQ(scip, (SCIP_Real) 2 * powcoef, -sumcoefs[i]) )
10427  continue;
10428 
10429  /* we only store power expressions if they have exactly two children being variables */
10430  if( SCIPexprGetNChildren(children[i]) != 2 )
10431  continue;
10432  if( !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[0])
10433  || !SCIPisExprVar(scip, SCIPexprGetChildren(children[i])[1]) )
10434  continue;
10435 
10436  var = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[0]);
10437  var2 = SCIPgetVarExprVar(SCIPexprGetChildren(children[i])[1]);
10438 
10439  /* we only store product expressions if the children are not multi-aggregated */
10442  {
10443  prodexprs[nprodexprs] = children[i];
10444  prodvars[nprodexprs++] = var;
10445  prodexprs[nprodexprs] = children[i];
10446  prodvars[nprodexprs++] = var2;
10447  }
10448  }
10449  }
10450 
10451  if( npowexprs == 0 || nprodexprs != npowexprs )
10452  goto FREEMEMORY;
10453 
10454  /* check whether the power variables and product variables match */
10455  SCIP_CALL( SCIPallocBufferArray(scip, &powperm, nprodexprs) );
10456  SCIP_CALL( SCIPallocBufferArray(scip, &prodperm, nprodexprs) );
10457 
10458  SCIPsort(powperm, SCIPsortVarPtr, (void*) powvars, npowexprs);
10459  SCIPsort(prodperm, SCIPsortVarPtr, (void*) prodvars, npowexprs);
10460 
10461  for( i = 0; i < npowexprs; ++i )
10462  {
10463  if( SCIPvarGetIndex(prodvars[prodperm[i]]) != SCIPvarGetIndex(powvars[powperm[i]]) )
10464  goto FREEMEMORY;
10465  }
10466 
10467  /* if we reach this line, the variables match: we have found a potential norm constraint */
10468  assert(npowexprs % 2 == 0);
10469  nterms = npowexprs / 2;
10470  SCIP_CALL( SCIPallocClearBufferArray(scip, &powexprused, npowexprs) );
10471 
10472  /* add gadget of each squared difference term */
10473  cnt = 0;
10474  for( i = 0; i < nterms; ++i )
10475  {
10476  SCIP_Bool var1found = FALSE;
10477  SCIP_Bool var2found = FALSE;
10478 
10479  (*consvals)[0] = 1.0;
10480  (*consvars)[0] = prodvars[cnt++];
10481  constant = 0.0;
10482  nlocvars = 1;
10483 
10484  SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals,
10485  &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10486 
10487  if( nlocvars != 1 )
10488  {
10489  ++cnt;
10490  continue;
10491  }
10492  actvar = (*consvars)[0];
10493  val = (*consvals)[0];
10494 
10495  (*consvals)[0] = 1.0;
10496  (*consvars)[0] = prodvars[cnt++];
10497  constant2 = 0.0;
10498  nlocvars = 1;
10499 
10500  SCIP_CALL( SCIPgetSymActiveVariables(scip, SYM_SYMTYPE_SIGNPERM, consvars, consvals,
10501  &nlocvars, &constant2, SCIPconsIsTransformed(cons)) );
10502 
10503  if( nlocvars != 1 )
10504  continue;
10505  actvar2 = (*consvars)[0];
10506  val2 = (*consvals)[0];
10507 
10508  /* we cannot handle the pair of variables if their constant/scalar differs or one variable
10509  * cannot be centered at the origin or they are not centered around the same point
10510  */
10511  if( !SCIPisEQ(scip, constant, constant2) || !SCIPisEQ(scip, val, val2)
10512  || (SCIPisInfinity(scip, SCIPvarGetUbGlobal(actvar)) != SCIPisInfinity(scip, -SCIPvarGetLbGlobal(actvar)))
10513  || (SCIPisInfinity(scip, SCIPvarGetUbGlobal(actvar2)) != SCIPisInfinity(scip, -SCIPvarGetLbGlobal(actvar2)))
10514  || (SCIPisInfinity(scip, SCIPvarGetUbGlobal(actvar)) != SCIPisInfinity(scip, SCIPvarGetLbGlobal(actvar2)))
10515  || !SCIPisEQ(scip, getDomainCenter(scip, actvar), getDomainCenter(scip, actvar2)) )
10516  continue;
10517 
10518  /* add gadget */
10519  SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SQDIFF, &nodeidx) );
10520  SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val, &coefnodeidx1) );
10521  SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, val2, &coefnodeidx2) );
10522 
10523  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, (SCIP_Real) powcoef) );
10524  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx1, TRUE, (SCIP_Real) powcoef) );
10525  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, nodeidx, coefnodeidx2, TRUE, (SCIP_Real) powcoef) );
10526  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10527  SCIPgetSymgraphVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10528  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx1,
10529  SCIPgetSymgraphVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10530  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10531  SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar), FALSE, 0.0) );
10532  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, coefnodeidx2,
10533  SCIPgetSymgraphNegatedVarnodeidx(scip, graph, actvar2), FALSE, 0.0) );
10534 
10535  /* mark product expression as handled */
10536  SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) prodexprs[2*i]) );
10537 
10538  /* find corresponding unused power expressions and mark them as handled */
10539  for( j = 0; j < npowexprs && !(var1found && var2found); ++j )
10540  {
10541  if( powexprused[j] )
10542  continue;
10543  assert(cnt >= 2);
10544 
10545  if( !var1found && powvars[j] == prodvars[cnt - 2] )
10546  {
10547  SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10548  powexprused[j] = TRUE;
10549  var1found = TRUE;
10550  }
10551  else if( !var2found && powvars[j] == prodvars[cnt - 1] )
10552  {
10553  SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) powexprs[j]) );
10554  powexprused[j] = TRUE;
10555  var2found = TRUE;
10556  }
10557  }
10558  }
10559 
10560  FREEMEMORY:
10561  SCIPfreeBufferArrayNull(scip, &powexprused);
10562  SCIPfreeBufferArrayNull(scip, &prodperm);
10563  SCIPfreeBufferArrayNull(scip, &powperm);
10564  SCIPfreeBufferArray(scip, &prodvars);
10565  SCIPfreeBufferArray(scip, &powvars);
10566  SCIPfreeBufferArray(scip, &prodexprs);
10567  SCIPfreeBufferArray(scip, &powexprs);
10568 
10569  return SCIP_OKAY;
10570 }
10571 
10572 /** adds symmetry information of constraint to a symmetry detection graph */
10573 static
10575  SCIP* scip, /**< SCIP pointer */
10576  SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
10577  SCIP_CONS* cons, /**< constraint */
10578  SYM_GRAPH* graph, /**< symmetry detection graph */
10579  SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
10580  )
10581 { /*lint --e{850}*/
10582  SCIP_EXPRITER* it;
10583  SCIP_HASHSET* handledexprs;
10584  SCIP_EXPR* rootexpr;
10585  SCIP_EXPR* expr;
10586  SCIP_VAR** consvars;
10587  SCIP_Real* consvals;
10588  SCIP_Real constant;
10589  SCIP_Real parentcoef = 0.0;
10590  int* openidx;
10591  int maxnopenidx;
10592  int parentidx;
10593  int nconsvars;
10594  int maxnconsvars;
10595  int nlocvars;
10596  int nopenidx = 0;
10597  int consnodeidx;
10598  int nodeidx;
10599  int i;
10600  SCIP_Bool iscolored;
10601  SCIP_Bool hasparentcoef;
10602 
10603  assert(scip != NULL);
10604  assert(cons != NULL);
10605  assert(graph != NULL);
10606  assert(success != NULL);
10607 
10608  /* store lhs/rhs */
10609  SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons,
10610  SCIPgetLhsNonlinear(cons), SCIPgetRhsNonlinear(cons), &consnodeidx) );
10611 
10612  rootexpr = SCIPgetExprNonlinear(cons);
10613  assert(rootexpr != NULL);
10614 
10615  /* allocate arrays to store operators not completely handled yet (due to DFS) and variables in constraint */
10616  expr = SCIPgetExprNonlinear(cons);
10617  assert(expr != NULL);
10618 
10619  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
10622 
10623  /* find potential number of nodes in graph */
10624  maxnopenidx = 0;
10625  for( ; !SCIPexpriterIsEnd(it); (void) SCIPexpriterGetNext(it) )
10626  {
10628  continue;
10629 
10630  ++maxnopenidx;
10631  }
10632 
10633  SCIP_CALL( SCIPallocBufferArray(scip, &openidx, maxnopenidx) );
10634 
10635  maxnconsvars = SCIPgetNVars(scip);
10636  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, maxnconsvars) );
10637  SCIP_CALL( SCIPallocBufferArray(scip, &consvals, maxnconsvars) );
10638 
10639  /* for finding special subexpressions, use hashset to store which expressions have been handled completely */
10640  SCIP_CALL( SCIPhashsetCreate(&handledexprs, SCIPblkmem(scip), maxnopenidx) );
10641 
10642  /* iterate over expression tree and store nodes/edges */
10643  expr = SCIPgetExprNonlinear(cons); /*lint !e838*/
10646 
10647  for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
10648  {
10649  /* if an expression has already been handled by an ancestor, increase iterator until we leave it */
10650  if( !SCIPhashsetIsEmpty(handledexprs) && SCIPhashsetExists(handledexprs, expr) )
10651  {
10652  SCIP_EXPR* baseexpr;
10653 
10654  baseexpr = expr;
10655  while( SCIPexpriterGetStageDFS(it) != SCIP_EXPRITER_LEAVEEXPR || expr != baseexpr )
10656  expr = SCIPexpriterGetNext(it);
10657 
10658  SCIP_CALL( SCIPhashsetRemove(handledexprs, (void*) expr) );
10659 
10660  /* leave the expression */
10661  continue;
10662  }
10663 
10664  /* due to DFS and expression has not been handled by ancestor, remove expression from list of open expressions */
10666  {
10667  --nopenidx;
10668  continue;
10669  }
10671 
10672  /* find parentidx */
10673  if( expr == rootexpr )
10674  parentidx = consnodeidx;
10675  else
10676  {
10677  assert(nopenidx >= 1);
10678  parentidx = openidx[nopenidx - 1];
10679  }
10680 
10681  /* possibly find a coefficient assigned to the expression by the parent */
10682  hasparentcoef = FALSE;
10683  if ( expr != rootexpr )
10684  {
10685  SCIP_CALL( SCIPgetCoefSymData(scip, expr, SCIPexpriterGetParentDFS(it), &parentcoef, &hasparentcoef) );
10686  }
10687 
10688  /* deal with different kinds of expressions and store them in the symmetry data structure */
10689  if( SCIPisExprVar(scip, expr) )
10690  {
10691  /* needed to correctly reset value when leaving expression */
10692  SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10693 
10694  openidx[nopenidx++] = -1;
10695 
10696  assert(maxnconsvars > 0);
10697  assert(parentidx > 0);
10698 
10699  /* if the parent assigns the variable a coefficient, introduce an intermediate node */
10700  if( hasparentcoef )
10701  {
10702  SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_COEF, &nodeidx) ); /*lint !e641*/
10703 
10704  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, TRUE, parentcoef) ); /*lint !e644*/
10705  parentidx = nodeidx;
10706  }
10707 
10708  /* connect (aggregation of) variable expression with its parent */
10709  nconsvars = 1;
10710  consvars[0] = SCIPgetVarExprVar(expr);
10711  consvals[0] = 1.0;
10712  constant = 0.0;
10713 
10714  SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10715  &nconsvars, &constant, SCIPconsIsTransformed(cons)) );
10716 
10717  /* check whether variable is aggregated */
10718  if( nconsvars > 1 || !SCIPisZero(scip, constant) || !SCIPisEQ(scip, consvals[0], 1.0) )
10719  {
10720  int thisidx;
10721 
10722  SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &thisidx) ); /*lint !e641*/
10723  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, thisidx, FALSE, 0.0) );
10724 
10725  parentidx = thisidx;
10726  }
10727  SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, parentidx, consvars, consvals,
10728  nconsvars, constant) );
10729  }
10730  else if( SCIPisExprValue(scip, expr) )
10731  {
10732  assert(parentidx > 0);
10733 
10734  SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetValueExprValue(expr), &nodeidx) );
10735 
10736  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, nodeidx, hasparentcoef, parentcoef) );
10737 
10738  /* needed to correctly reset value when leaving expression */
10739  SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10740 
10741  openidx[nopenidx++] = -1;
10742  }
10743  else
10744  {
10745  SCIP_Bool usedefaultgadget = TRUE;
10746 
10747  assert(expr == rootexpr || parentidx > 0);
10748  assert(SCIPhashsetIsEmpty(handledexprs) || !SCIPhashsetExists(handledexprs, expr));
10749 
10750  if( SCIPisExprSum(scip, expr) )
10751  {
10752  /* deal with sum expressions differently, because we can possibly aggregate linear sums */
10753  SCIP_EXPR** children;
10754  int sumidx;
10755  int optype;
10756  int childidx;
10757 
10758  /* sums are handled by a special gadget */
10759  usedefaultgadget = FALSE;
10760 
10761  /* extract all children being variables and compute the sum of active variables expression */
10762  nlocvars = 0;
10763  children = SCIPexprGetChildren(expr);
10764 
10765  SCIP_CALL( ensureLocVarsArraySize(scip, &consvars, &consvals, SCIPexprGetNChildren(expr), &maxnconsvars) );
10766 
10767  for( childidx = 0; childidx < SCIPexprGetNChildren(expr); ++childidx )
10768  {
10769  if( !SCIPisExprVar(scip, children[childidx]) )
10770  continue;
10771 
10772  consvars[nlocvars] = SCIPgetVarExprVar(children[childidx]);
10773  consvals[nlocvars++] = SCIPgetCoefsExprSum(expr)[childidx];
10774 
10775  /* store that we have already handled this expression */
10776  SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) children[childidx]) );
10777  }
10778 
10779  constant = SCIPgetConstantExprSum(expr);
10780 
10781  SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &consvars, &consvals,
10782  &nlocvars, &constant, SCIPconsIsTransformed(cons)) );
10783 
10785 
10786  SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &sumidx) );
10787  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, sumidx, hasparentcoef, parentcoef) );
10788 
10789  /* add the linear part of the sum */
10790  SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, sumidx, consvars, consvals, nlocvars, constant) );
10791 
10792  SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10793 
10794  /* check whether the sum encodes expressions of type \f$(x - y)^2\f$ */
10795  if( symtype == SYM_SYMTYPE_SIGNPERM )
10796  {
10797  SCIP_CALL( tryAddGadgetSquaredDifference(scip, expr, cons, graph, sumidx,
10798  &consvars, &consvals, &maxnconsvars, handledexprs) );
10799  }
10800 
10801  /* store sumidx for children that have not been treated */
10802  openidx[nopenidx++] = sumidx;
10803  }
10804  else if( symtype == SYM_SYMTYPE_SIGNPERM && SCIPisExprProduct(scip, expr) )
10805  {
10806  SCIP_Bool succ;
10807 
10808  SCIP_CALL( tryAddGadgetBilinearProductSignedPerm(scip, expr, cons, graph, parentidx, hasparentcoef,
10809  parentcoef, &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10810 
10811  if( succ )
10812  {
10813  usedefaultgadget = FALSE;
10814  SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10815  }
10816  }
10817  else if( symtype == SYM_SYMTYPE_SIGNPERM )
10818  {
10819  SCIP_Bool succ;
10820 
10821  /* we can find more signed permutations for even univariate operators */
10822  SCIP_CALL( tryAddGadgetEvenOperator(scip, expr, cons, graph, parentidx, hasparentcoef, parentcoef,
10823  &consvars, &consvals, &maxnconsvars, handledexprs, &succ) );
10824 
10825  if( succ )
10826  {
10827  usedefaultgadget = FALSE;
10828  SCIP_CALL( SCIPhashsetInsert(handledexprs, SCIPblkmem(scip), (void*) expr) );
10829  }
10830  }
10831 
10832  if( usedefaultgadget )
10833  {
10834  int opidx;
10835  int optype;
10836 
10838  SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, optype, &opidx) );
10839  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, parentidx, opidx, hasparentcoef, parentcoef) );
10840 
10841  /* possibly add constants of expression */
10843  {
10844  SYM_EXPRDATA* symdata;
10845 
10846  SCIP_CALL( SCIPgetSymDataExpr(scip, expr, &symdata) );
10847  assert(symdata != NULL);
10848 
10849  /* if expression has multiple constants, assign colors to edges to distinguish them */
10850  iscolored = SCIPgetSymExprdataNConstants(symdata) > 1 ? TRUE : FALSE;
10851  for( i = 0; i < SCIPgetSymExprdataNConstants(symdata); ++i )
10852  {
10853  SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, SCIPgetSymExprdataConstants(symdata)[i], &nodeidx) );
10854  SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opidx, nodeidx, iscolored, (SCIP_Real) i+1) );
10855  }
10856 
10857  SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
10858  }
10859 
10860  SCIP_CALL( ensureOpenArraySizeSymdetect(scip, &openidx, nopenidx + 1, &maxnopenidx) );
10861 
10862  openidx[nopenidx++] = opidx;
10863  }
10864  }
10865  }
10866 
10867  SCIPhashsetFree(&handledexprs, SCIPblkmem(scip));
10868  SCIPfreeBufferArray(scip, &consvals);
10869  SCIPfreeBufferArray(scip, &consvars);
10870  SCIPfreeBufferArray(scip, &openidx);
10871  SCIPfreeExpriter(&it);
10872 
10873  *success = TRUE;
10874 
10875  return SCIP_OKAY;
10876 }
10877 
10878 /*
10879  * Callback methods of constraint handler
10880  */
10881 
10882 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
10883 static
10884 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
10885 { /*lint --e{715}*/
10886  SCIP_CONSHDLR* targetconshdlr;
10887  SCIP_CONSHDLRDATA* sourceconshdlrdata;
10888  int i;
10889 
10890  assert(scip != NULL);
10891  assert(conshdlr != NULL);
10892  assert(valid != NULL);
10893  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
10894 
10895  /* create basic data of constraint handler and include it to scip */
10897 
10898  targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
10899  assert(targetconshdlr != NULL);
10900  assert(targetconshdlr != conshdlr);
10901 
10902  sourceconshdlrdata = SCIPconshdlrGetData(conshdlr);
10903  assert(sourceconshdlrdata != NULL);
10904 
10905  /* copy nonlinear handlers */
10906  for( i = 0; i < sourceconshdlrdata->nnlhdlrs; ++i )
10907  {
10908  SCIP_CALL( SCIPnlhdlrCopyhdlr(scip, targetconshdlr, conshdlr, sourceconshdlrdata->nlhdlrs[i]) );
10909  }
10910 
10911  *valid = TRUE;
10912 
10913  return SCIP_OKAY;
10914 }
10915 
10916 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
10917 static
10918 SCIP_DECL_CONSFREE(consFreeNonlinear)
10919 { /*lint --e{715}*/
10920  SCIP_CONSHDLRDATA* conshdlrdata;
10921  int i;
10922 
10923  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10924  assert(conshdlrdata != NULL);
10925 
10926  /* free nonlinear handlers */
10927  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
10928  {
10929  SCIP_CALL( SCIPnlhdlrFree(scip, &conshdlrdata->nlhdlrs[i]) );
10930  assert(conshdlrdata->nlhdlrs[i] == NULL);
10931  }
10932  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlhdlrs, conshdlrdata->nlhdlrssize);
10933  conshdlrdata->nlhdlrssize = 0;
10934 
10935  /* free upgrade functions */
10936  for( i = 0; i < conshdlrdata->nconsupgrades; ++i )
10937  {
10938  assert(conshdlrdata->consupgrades[i] != NULL);
10939  SCIPfreeBlockMemory(scip, &conshdlrdata->consupgrades[i]);
10940  }
10941  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->consupgrades, conshdlrdata->consupgradessize);
10942 
10943  SCIP_CALL( SCIPfreeClock(scip, &conshdlrdata->canonicalizetime) );
10944 
10945  SCIPqueueFree(&conshdlrdata->reversepropqueue);
10946 
10947  if( conshdlrdata->vp_randnumgen != NULL )
10948  SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
10949 
10950  /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
10951  for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
10952  {
10953  if( conshdlrdata->vp_lp[i] != NULL )
10954  {
10955  SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
10956  }
10957  }
10958 
10959  assert(conshdlrdata->branchrandnumgen == NULL);
10960 
10961  assert(SCIPhashmapGetNElements(conshdlrdata->var2expr) == 0);
10962  SCIPhashmapFree(&conshdlrdata->var2expr);
10963 
10964  SCIPfreeBlockMemory(scip, &conshdlrdata);
10965  SCIPconshdlrSetData(conshdlr, NULL);
10966 
10967  return SCIP_OKAY;
10968 }
10969 
10970 
10971 /** initialization method of constraint handler (called after problem was transformed) */
10972 static
10973 SCIP_DECL_CONSINIT(consInitNonlinear)
10974 { /*lint --e{715}*/
10975  SCIP_CONSHDLRDATA* conshdlrdata;
10976  int i;
10977 
10978  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10979  assert(conshdlrdata != NULL);
10980 
10981  /* make sure current activity tags in expressions are invalid, because we start catching variable events only now */
10982  conshdlrdata->lastboundrelax = ++conshdlrdata->curboundstag;
10983  /* set to 1 so it is larger than initial value of lastenforound in exprs */
10984  conshdlrdata->enforound = 1;
10985  /* reset numbering for auxiliary variables */
10986  conshdlrdata->auxvarid = 0;
10987 
10988  for( i = 0; i < nconss; ++i )
10989  {
10990  SCIP_CALL( storeVarExprs(scip, conshdlr, SCIPconsGetData(conss[i])) );
10991  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, conss[i]) );
10992  }
10993 
10994  /* sort nonlinear handlers by detection priority, in decreasing order */
10995  if( conshdlrdata->nnlhdlrs > 1 )
10996  SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
10997 
10998  /* get heuristics for later use */
10999  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
11000  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
11001 
11002  /* reset statistics in nonlinear handlers (TODO only if misc/resetstat == TRUE) and call nlhdlrInit */
11003  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11004  {
11005  SCIP_CALL( SCIPnlhdlrInit(scip, conshdlrdata->nlhdlrs[i]) );
11006  }
11007 
11008  /* reset statistics in constraint handler */
11009  conshdlrdata->nweaksepa = 0;
11010  conshdlrdata->ntightenlp = 0;
11011  conshdlrdata->ndesperatebranch = 0;
11012  conshdlrdata->ndesperatecutoff = 0;
11013  conshdlrdata->ndesperatetightenlp = 0;
11014  conshdlrdata->nforcelp = 0;
11015  SCIP_CALL( SCIPresetClock(scip, conshdlrdata->canonicalizetime) );
11016  conshdlrdata->ncanonicalizecalls = 0;
11017 
11018 #ifdef ENFOLOGFILE
11019  ENFOLOG( enfologfile = fopen(ENFOLOGFILE, "w"); )
11020 #endif
11021 
11022  return SCIP_OKAY;
11023 }
11024 
11025 
11026 /** deinitialization method of constraint handler (called before transformed problem is freed) */
11027 static
11028 SCIP_DECL_CONSEXIT(consExitNonlinear)
11029 { /*lint --e{715}*/
11030  SCIP_CONSHDLRDATA* conshdlrdata;
11031  SCIP_CONS** consssorted;
11032  int i;
11033 
11034  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11035  assert(conshdlrdata != NULL);
11036 
11037  if( nconss > 0 )
11038  {
11039  /* for better performance of dropVarEvents, we sort by index, descending */
11040  SCIP_CALL( SCIPduplicateBufferArray(scip, &consssorted, conss, nconss) );
11041  SCIPsortDownPtr((void**)consssorted, compIndexConsNonlinear, nconss);
11042 
11043  for( i = 0; i < nconss; ++i )
11044  {
11045  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, consssorted[i]) );
11046  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(consssorted[i])) );
11047  }
11048 
11049  SCIPfreeBufferArray(scip, &consssorted);
11050  }
11051 
11052  conshdlrdata->subnlpheur = NULL;
11053  conshdlrdata->trysolheur = NULL;
11054 
11055  if( conshdlrdata->vp_randnumgen != NULL )
11056  SCIPfreeRandom(scip, &conshdlrdata->vp_randnumgen);
11057 
11058  /* free LPs used to construct facets of envelops of vertex-polyhedral functions */
11059  for( i = 0; i <= SCIP_MAXVERTEXPOLYDIM; ++i )
11060  {
11061  if( conshdlrdata->vp_lp[i] != NULL )
11062  {
11063  SCIP_CALL( SCIPlpiFree(&conshdlrdata->vp_lp[i]) );
11064  }
11065  }
11066 
11067  if( conshdlrdata->branchrandnumgen != NULL )
11068  SCIPfreeRandom(scip, &conshdlrdata->branchrandnumgen);
11069 
11070  /* deinitialize nonlinear handlers */
11071  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11072  {
11073  SCIP_CALL( SCIPnlhdlrExit(scip, conshdlrdata->nlhdlrs[i]) );
11074  }
11075 
11076  ENFOLOG(
11077  if( enfologfile != NULL )
11078  {
11079  fclose(enfologfile);
11080  enfologfile = NULL;
11081  })
11082 
11083  return SCIP_OKAY;
11084 }
11085 
11086 
11087 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
11088 #ifdef SCIP_DISABLED_CODE
11089 static
11091 { /*lint --e{715}*/
11092  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11093  SCIPABORT(); /*lint --e{527}*/
11094 
11095  return SCIP_OKAY;
11096 }
11097 #else
11098 #define consInitpreNonlinear NULL
11099 #endif
11100 
11101 
11102 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
11103 static
11104 SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
11105 { /*lint --e{715}*/
11106  SCIP_Bool infeasible;
11107 
11108  if( nconss == 0 )
11109  return SCIP_OKAY;
11110 
11111  /* skip some extra work if already known to be infeasible */
11112  if( SCIPgetStatus(scip) == SCIP_STATUS_INFEASIBLE )
11113  return SCIP_OKAY;
11114 
11115  /* simplify constraints and replace common subexpressions */
11116  SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, SCIP_PRESOLTIMING_ALWAYS, &infeasible, NULL, NULL, NULL) );
11117 
11118  /* currently SCIP does not offer to communicate this,
11119  * but at the moment this can only become true if canonicalizeConstraints called detectNlhdlrs (which it doesn't do in EXITPRESOLVE stage)
11120  * or if a constraint expression became constant
11121  * the latter happened on tls4 within fiberscip, so I'm disabling this assert for now
11122  */
11123  /* assert(!infeasible); */
11124 
11125  /* tell SCIP that we have something nonlinear */
11126  SCIPenableNLP(scip);
11127 
11128  return SCIP_OKAY;
11129 }
11130 
11131 
11132 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
11133 static
11134 SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
11135 { /*lint --e{715}*/
11136  SCIP_CONSHDLRDATA* conshdlrdata;
11137  int i;
11138 
11139  /* skip remaining initializations if we have solved already
11140  * if infeasibility was found by our boundtightening, then curvature check may also fail as some exprhdlr (e.g., pow)
11141  * assumes nonempty activities in expressions
11142  */
11143  switch( SCIPgetStatus(scip) )
11144  {
11145  case SCIP_STATUS_OPTIMAL:
11147  case SCIP_STATUS_UNBOUNDED:
11148  case SCIP_STATUS_INFORUNBD:
11149  return SCIP_OKAY;
11150  default: ;
11151  } /*lint !e788 */
11152 
11153  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11154  assert(conshdlrdata != NULL);
11155 
11156  /* reset one of the number of detections counter to count only current round */
11157  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
11158  SCIPnlhdlrResetNDetectionslast(conshdlrdata->nlhdlrs[i]);
11159 
11160  SCIP_CALL( initSolve(scip, conshdlr, conss, nconss) );
11161 
11162  /* check that branching/lpgainnormalize is set to a known value if pseudo-costs are used in branching */
11163  if( conshdlrdata->branchpscostweight > 0.0 )
11164  {
11165  SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &(conshdlrdata->branchpscostupdatestrategy)) );
11166  if( strchr("lds", conshdlrdata->branchpscostupdatestrategy) == NULL )
11167  {
11168  SCIPerrorMessage("branching/lpgainnormalize strategy %c unknown\n", conshdlrdata->branchpscostupdatestrategy);
11169  SCIPABORT();
11170  return SCIP_INVALIDDATA;
11171  }
11172  }
11173 
11174  return SCIP_OKAY;
11175 }
11176 
11177 
11178 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
11179 static
11180 SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
11181 { /*lint --e{715}*/
11182  SCIP_CONSHDLRDATA* conshdlrdata;
11183 
11184  SCIP_CALL( deinitSolve(scip, conshdlr, conss, nconss) );
11185 
11186  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11187  assert(conshdlrdata != NULL);
11188 
11189  /* free hash table for bilinear terms */
11190  SCIP_CALL( bilinearTermsFree(scip, conshdlrdata) );
11191 
11192  /* reset flag to allow another call of presolSingleLockedVars() after a restart */
11193  conshdlrdata->checkedvarlocks = FALSE;
11194 
11195  /* drop catching new solution event, if catched before */
11196  if( conshdlrdata->newsoleventfilterpos >= 0 )
11197  {
11198  SCIP_EVENTHDLR* eventhdlr;
11199 
11200  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11201  assert(eventhdlr != NULL);
11202 
11203  SCIP_CALL( SCIPdropEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
11204  conshdlrdata->newsoleventfilterpos = -1;
11205  }
11206 
11207  return SCIP_OKAY;
11208 }
11209 
11210 
11211 /** frees specific constraint data */
11212 static
11213 SCIP_DECL_CONSDELETE(consDeleteNonlinear)
11214 { /*lint --e{715}*/
11215  assert(consdata != NULL);
11216  assert(*consdata != NULL);
11217  assert((*consdata)->expr != NULL);
11218 
11219  /* constraint locks should have been removed */
11220  assert((*consdata)->nlockspos == 0);
11221  assert((*consdata)->nlocksneg == 0);
11222 
11223  /* free variable expressions */
11224  SCIP_CALL( freeVarExprs(scip, *consdata) );
11225 
11226  SCIP_CALL( SCIPreleaseExpr(scip, &(*consdata)->expr) );
11227 
11228  /* free nonlinear row representation */
11229  if( (*consdata)->nlrow != NULL )
11230  {
11231  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
11232  }
11233 
11234  SCIPfreeBlockMemory(scip, consdata);
11235 
11236  return SCIP_OKAY;
11237 }
11238 
11239 
11240 /** transforms constraint data into data belonging to the transformed problem */
11241 static
11242 SCIP_DECL_CONSTRANS(consTransNonlinear)
11243 { /*lint --e{715}*/
11244  SCIP_EXPR* targetexpr;
11245  SCIP_CONSDATA* sourcedata;
11246 
11247  sourcedata = SCIPconsGetData(sourcecons);
11248  assert(sourcedata != NULL);
11249 
11250  /* get a copy of sourceexpr with transformed vars */
11251  SCIP_CALL( SCIPduplicateExpr(scip, sourcedata->expr, &targetexpr, mapexprtransvar, conshdlr, exprownerCreate, (void*)conshdlr) );
11252  assert(targetexpr != NULL); /* SCIPduplicateExpr cannot fail */
11253 
11254  /* create transformed cons (only captures targetexpr, no need to copy again) */
11255  SCIP_CALL( createCons(scip, conshdlr, targetcons, SCIPconsGetName(sourcecons),
11256  targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
11257  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
11258  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
11259  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
11260  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons)) );
11261 
11262  /* release target expr */
11263  SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
11264 
11265  return SCIP_OKAY;
11266 }
11267 
11268 
11269 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
11270 static
11271 SCIP_DECL_CONSINITLP(consInitlpNonlinear)
11272 { /*lint --e{715}*/
11273  SCIP_CONSHDLRDATA* conshdlrdata;
11274 
11275  /* create auxiliary variables and call separation initialization callbacks of the expression handlers
11276  * TODO if we ever want to allow constraints that are separated but not initial, then we need to call initSepa also
11277  * during SEPALP, ENFOLP, etc, whenever a constraint may be separated the first time
11278  * for now, there is an assert in detectNlhdlrs to require initial if separated
11279  */
11280  SCIP_CALL( initSepa(scip, conshdlr, conss, nconss, infeasible) );
11281 
11282  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11283  assert(conshdlrdata != NULL);
11284 
11285  /* catch new solution event */
11286  if( conshdlrdata->linearizeheursol != 'o' && conshdlrdata->newsoleventfilterpos == -1 )
11287  {
11288  SCIP_EVENTHDLR* eventhdlr;
11289 
11290  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME "_newsolution");
11291  assert(eventhdlr != NULL);
11292 
11293  SCIP_CALL( SCIPcatchEvent(scip, conshdlrdata->linearizeheursol == 'i' ? SCIP_EVENTTYPE_BESTSOLFOUND : SCIP_EVENTTYPE_SOLFOUND,
11294  eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
11295  }
11296 
11297  /* collect all bilinear terms for which an auxvar is present
11298  * TODO this will only do something for the first call of initlp after initsol, because it cannot handle
11299  * addition (and removal?) of constraints during solve
11300  * this is typically the majority of constraints, but the method should be made more flexible
11301  */
11302  SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
11303 
11304  return SCIP_OKAY;
11305 }
11306 
11307 
11308 /** separation method of constraint handler for LP solutions */
11309 static
11310 SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
11311 { /*lint --e{715}*/
11312  SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, NULL, result) );
11313 
11314  return SCIP_OKAY;
11315 }
11316 
11317 
11318 /** separation method of constraint handler for arbitrary primal solutions */
11319 static
11320 SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
11321 { /*lint --e{715}*/
11322  SCIP_CALL( consSepa(scip, conshdlr, conss, nconss, sol, result) );
11323 
11324  return SCIP_OKAY;
11325 }
11326 
11327 
11328 /** constraint enforcing method of constraint handler for LP solutions */
11329 static
11330 SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
11331 { /*lint --e{715}*/
11332  SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, NULL, result) );
11333 
11334  return SCIP_OKAY;
11335 }
11336 
11337 
11338 /** constraint enforcing method of constraint handler for relaxation solutions */
11339 static
11340 SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
11341 { /*lint --e{715}*/
11342  SCIP_CALL( consEnfo(scip, conshdlr, conss, nconss, sol, result) );
11343 
11344  return SCIP_OKAY;
11345 }
11346 
11347 
11348 /** constraint enforcing method of constraint handler for pseudo solutions */
11349 static
11350 SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
11351 { /*lint --e{715}*/
11352  SCIP_RESULT propresult;
11353  SCIP_Longint soltag;
11354  int nchgbds;
11355  int nnotify;
11356  int c;
11357 
11358  soltag = SCIPgetExprNewSoltag(scip);
11359 
11360  *result = SCIP_FEASIBLE;
11361  for( c = 0; c < nconss; ++c )
11362  {
11363  SCIP_CALL( computeViolation(scip, conss[c], NULL, soltag) );
11364 
11365  if( isConsViolated(scip, conss[c]) )
11366  *result = SCIP_INFEASIBLE;
11367  }
11368 
11369  if( *result == SCIP_FEASIBLE )
11370  return SCIP_OKAY;
11371 
11372  /* try to propagate
11373  * TODO obey propinenfo parameter, but we need something to recognize cutoff
11374  */
11375  nchgbds = 0;
11376  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, TRUE, &propresult, &nchgbds) );
11377 
11378  if( (propresult == SCIP_CUTOFF) || (propresult == SCIP_REDUCEDDOM) )
11379  {
11380  *result = propresult;
11381  return SCIP_OKAY;
11382  }
11383 
11384  /* register all unfixed variables in all violated constraints as branching candidates */
11385  SCIP_CALL( registerBranchingCandidatesAllUnfixed(scip, conshdlr, conss, nconss, &nnotify) );
11386  if( nnotify > 0 )
11387  {
11388  SCIPdebugMsg(scip, "registered %d external branching candidates\n", nnotify);
11389 
11390  return SCIP_OKAY;
11391  }
11392 
11393  SCIPdebugMsg(scip, "could not find branching candidates, forcing to solve LP\n");
11394  *result = SCIP_SOLVELP;
11395  ++SCIPconshdlrGetData(conshdlr)->nforcelp;
11396 
11397  return SCIP_OKAY;
11398 }
11399 
11400 
11401 /** feasibility check method of constraint handler for integral solutions */
11402 static
11403 SCIP_DECL_CONSCHECK(consCheckNonlinear)
11404 { /*lint --e{715}*/
11405  SCIP_CONSHDLRDATA* conshdlrdata;
11406  SCIP_CONSDATA* consdata;
11407  SCIP_Real maxviol;
11408  SCIP_Bool maypropfeasible;
11409  SCIP_Longint soltag;
11410  int c;
11411 
11412  assert(scip != NULL);
11413  assert(conshdlr != NULL);
11414  assert(conss != NULL || nconss == 0);
11415  assert(result != NULL);
11416 
11417  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11418  assert(conshdlrdata != NULL);
11419 
11420  *result = SCIP_FEASIBLE;
11421  soltag = SCIPgetExprNewSoltag(scip);
11422  maxviol = 0.0;
11423  maypropfeasible = conshdlrdata->trysolheur != NULL && SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED
11424  && SCIPgetStage(scip) <= SCIP_STAGE_SOLVING;
11425 
11426  if( maypropfeasible && (sol == NULL || SCIPsolGetOrigin(sol) == SCIP_SOLORIGIN_LPSOL) && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY )
11427  maypropfeasible = FALSE;
11428 
11429  /* check nonlinear constraints for feasibility */
11430  for( c = 0; c < nconss; ++c )
11431  {
11432  assert(conss != NULL && conss[c] != NULL);
11433  SCIP_CALL( computeViolation(scip, conss[c], sol, soltag) );
11434 
11435  if( isConsViolated(scip, conss[c]) )
11436  {
11437  *result = SCIP_INFEASIBLE;
11438  maxviol = MAX(maxviol, getConsAbsViolation(conss[c]));
11439 
11440  consdata = SCIPconsGetData(conss[c]);
11441  assert(consdata != NULL);
11442 
11443  /* print reason for infeasibility */
11444  if( printreason )
11445  {
11446  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
11447  SCIPinfoMessage(scip, NULL, ";\n");
11448 
11449  if( consdata->lhsviol > SCIPfeastol(scip) )
11450  {
11451  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
11452  }
11453  if( consdata->rhsviol > SCIPfeastol(scip) )
11454  {
11455  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
11456  }
11457  }
11458  else if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
11459  {
11460  /* if we don't want to pass to subnlp heuristic and don't need to print reasons, then can stop checking here */
11461  return SCIP_OKAY;
11462  }
11463 
11464  /* do not try to shift linear variables if violation is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
11465  if( maypropfeasible && SCIPisInfinity(scip, getConsAbsViolation(conss[c])) )
11466  maypropfeasible = FALSE;
11467 
11468  if( maypropfeasible )
11469  {
11470  if( consdata->lhsviol > SCIPfeastol(scip) )
11471  {
11472  /* check if there is a variable which may help to get the left hand side satisfied
11473  * if there is no such variable, then we cannot get feasible
11474  */
11475  if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef > 0.0) &&
11476  !(consdata->linvardecr != NULL && consdata->linvardecrcoef < 0.0) )
11477  maypropfeasible = FALSE;
11478  }
11479  else
11480  {
11481  assert(consdata->rhsviol > SCIPfeastol(scip));
11482  /* check if there is a variable which may help to get the right hand side satisfied
11483  * if there is no such variable, then we cannot get feasible
11484  */
11485  if( !(consdata->linvarincr != NULL && consdata->linvarincrcoef < 0.0) &&
11486  !(consdata->linvardecr != NULL && consdata->linvardecrcoef > 0.0) )
11487  maypropfeasible = FALSE;
11488  }
11489  }
11490  }
11491  }
11492 
11493  if( *result == SCIP_INFEASIBLE && maypropfeasible )
11494  {
11495  SCIP_Bool success;
11496 
11497  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
11498 
11499  /* do not pass solution to NLP heuristic if we made it feasible this way */
11500  if( success )
11501  return SCIP_OKAY;
11502  }
11503 
11504  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
11505  {
11506  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
11507  }
11508 
11509  return SCIP_OKAY;
11510 }
11511 
11512 
11513 /** domain propagation method of constraint handler */
11514 static
11515 SCIP_DECL_CONSPROP(consPropNonlinear)
11516 { /*lint --e{715}*/
11517  int nchgbds = 0;
11518 
11519  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, &nchgbds) );
11520  assert(nchgbds >= 0);
11521 
11522  /* TODO would it make sense to check for redundant constraints? */
11523 
11524  return SCIP_OKAY;
11525 }
11526 
11527 
11528 /** presolving method of constraint handler */
11529 static
11530 SCIP_DECL_CONSPRESOL(consPresolNonlinear)
11531 { /*lint --e{715}*/
11532  SCIP_CONSHDLRDATA* conshdlrdata;
11533  SCIP_Bool infeasible;
11534  int c;
11535 
11536  *result = SCIP_DIDNOTFIND;
11537 
11538  if( nconss == 0 )
11539  {
11540  *result = SCIP_DIDNOTRUN;
11541  return SCIP_OKAY;
11542  }
11543 
11544  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11545  assert(conshdlrdata != NULL);
11546 
11547  /* simplify constraints and replace common subexpressions, reinit nlhdlrs */
11548  SCIP_CALL( canonicalizeConstraints(scip, conshdlr, conss, nconss, presoltiming, &infeasible, ndelconss, naddconss, nchgcoefs) );
11549  if( infeasible )
11550  {
11551  *result = SCIP_CUTOFF;
11552  return SCIP_OKAY;
11553  }
11554 
11555  /* merge constraints with the same root expression */
11556  if( presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE )
11557  {
11558  SCIP_Bool success;
11559 
11560  SCIP_CALL( presolveMergeConss(scip, conss, nconss, &success) );
11561  if( success )
11562  *result = SCIP_SUCCESS;
11563  }
11564 
11565  /* propagate constraints */
11566  SCIP_CALL( propConss(scip, conshdlr, conss, nconss, FALSE, result, nchgbds) );
11567  if( *result == SCIP_CUTOFF )
11568  return SCIP_OKAY;
11569 
11570  /* propagate function domains (TODO integrate with simplify?) */
11571  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) || nrounds == 0 )
11572  {
11573  SCIP_RESULT localresult;
11574  SCIP_CALL( propExprDomains(scip, conshdlr, conss, nconss, &localresult, nchgbds) );
11575  if( localresult == SCIP_CUTOFF )
11576  {
11577  *result = SCIP_CUTOFF;
11578  return SCIP_OKAY;
11579  }
11580  if( localresult == SCIP_REDUCEDDOM )
11581  *result = SCIP_REDUCEDDOM;
11582  }
11583 
11584  /* check for redundant constraints, remove constraints that are a value expression */
11585  SCIP_CALL( presolveRedundantConss(scip, conshdlr, conss, nconss, &infeasible, ndelconss, nchgbds) );
11586  if( infeasible )
11587  {
11588  *result = SCIP_CUTOFF;
11589  return SCIP_OKAY;
11590  }
11591 
11592  /* try to upgrade constraints */
11593  for( c = 0; c < nconss; ++c )
11594  {
11595  SCIP_Bool upgraded;
11596 
11597  /* skip inactive and deleted constraints */
11598  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsActive(conss[c]) )
11599  continue;
11600 
11601  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
11602  }
11603 
11604  /* try to change continuous variables that appear linearly to be implicit integer */
11605  if( presoltiming & SCIP_PRESOLTIMING_MEDIUM )
11606  {
11607  SCIP_CALL( presolveImplint(scip, conshdlr, conss, nconss, nchgvartypes, &infeasible) );
11608 
11609  if( infeasible )
11610  {
11611  SCIPdebugMsg(scip, "presolveImplint() detected infeasibility\n");
11612  *result = SCIP_CUTOFF;
11613  return SCIP_OKAY;
11614  }
11615  }
11616 
11617  /* fix variables that are contained in only one nonlinear constraint to their upper or lower bounds, if possible */
11618  if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) && SCIPisPresolveFinished(scip)
11619  && !conshdlrdata->checkedvarlocks && conshdlrdata->checkvarlocks != 'd' )
11620  {
11621  /* run this presolving technique only once because we don't want to generate identical bound disjunction
11622  * constraints multiple times
11623  */
11624  conshdlrdata->checkedvarlocks = TRUE;
11625 
11626  for( c = 0; c < nconss; ++c )
11627  {
11628  int tmpnchgvartypes = 0;
11629  int tmpnaddconss = 0;
11630 
11631  SCIP_CALL( presolveSingleLockedVars(scip, conshdlr, conss[c], &tmpnchgvartypes, &tmpnaddconss, &infeasible) );
11632  SCIPdebugMsg(scip, "presolSingleLockedVars() for %s: nchgvartypes=%d naddconss=%d infeas=%u\n",
11633  SCIPconsGetName(conss[c]), tmpnchgvartypes, tmpnaddconss, infeasible);
11634 
11635  if( infeasible )
11636  {
11637  SCIPdebugMsg(scip, "presolSingleLockedVars() detected infeasibility\n");
11638  *result = SCIP_CUTOFF;
11639  return SCIP_OKAY;
11640  }
11641 
11642  (*nchgvartypes) += tmpnchgvartypes;
11643  (*naddconss) += tmpnaddconss;
11644  }
11645  }
11646 
11647  if( *ndelconss > 0 || *nchgbds > 0 || *nupgdconss > 0 || *naddconss > 0 || *nchgvartypes > 0 )
11648  *result = SCIP_SUCCESS;
11649  else
11650  *result = SCIP_DIDNOTFIND;
11651 
11652  return SCIP_OKAY;
11653 }
11654 
11655 
11656 /** propagation conflict resolving method of constraint handler */
11657 #ifdef SCIP_DISABLED_CODE
11658 static
11660 { /*lint --e{715}*/
11661  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11662  SCIPABORT(); /*lint --e{527}*/
11663 
11664  return SCIP_OKAY;
11665 }
11666 #else
11667 #define consRespropNonlinear NULL
11668 #endif
11669 
11670 
11671 /** variable rounding lock method of constraint handler */
11672 static
11673 SCIP_DECL_CONSLOCK(consLockNonlinear)
11674 { /*lint --e{715}*/
11675  SCIP_CONSDATA* consdata;
11676  SCIP_EXPR_OWNERDATA* ownerdata;
11677  SCIP_Bool reinitsolve = FALSE;
11678 
11679  assert(conshdlr != NULL);
11680  assert(cons != NULL);
11681 
11682  consdata = SCIPconsGetData(cons);
11683  assert(consdata != NULL);
11684  assert(consdata->expr != NULL);
11685 
11686  ownerdata = SCIPexprGetOwnerData(consdata->expr);
11687 
11688  /* check whether we need to initSolve again because
11689  * - we have enfo initialized (nenfos >= 0)
11690  * - and locks appeared (going from zero to nonzero) or disappeared (going from nonzero to zero) now
11691  */
11692  if( ownerdata->nenfos >= 0 )
11693  {
11694  if( (consdata->nlockspos == 0) != (nlockspos == 0) )
11695  reinitsolve = TRUE;
11696  if( (consdata->nlocksneg == 0) != (nlocksneg == 0) )
11697  reinitsolve = TRUE;
11698  }
11699 
11700  if( reinitsolve )
11701  {
11702  SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11703  }
11704 
11705  /* add locks */
11706  SCIP_CALL( addLocks(scip, cons, nlockspos, nlocksneg) );
11707 
11708  if( reinitsolve )
11709  {
11710  SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11711  }
11712 
11713  return SCIP_OKAY;
11714 }
11715 
11716 
11717 /** constraint activation notification method of constraint handler */
11718 static
11719 SCIP_DECL_CONSACTIVE(consActiveNonlinear)
11720 { /*lint --e{715}*/
11721  SCIP_CONSDATA* consdata;
11722  SCIP_Bool infeasible = FALSE;
11723 
11724  consdata = SCIPconsGetData(cons);
11725  assert(consdata != NULL);
11726 
11727  /* simplify root expression if the constraint has been added after presolving */
11729  {
11730  SCIP_Bool replacedroot;
11731 
11732  if( !consdata->issimplified )
11733  {
11734  SCIP_EXPR* simplified;
11735  SCIP_Bool changed;
11736 
11737  /* simplify constraint */
11738  SCIP_CALL( SCIPsimplifyExpr(scip, consdata->expr, &simplified, &changed, &infeasible, exprownerCreate, (void*)conshdlr) );
11739  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
11740  assert(simplified != NULL);
11741  consdata->expr = simplified;
11742  consdata->issimplified = TRUE;
11743  }
11744 
11745  /* ensure each variable is represented by one variable expression only (need this for storeVarExprs() with simplified=TRUE below) */
11746  SCIP_CALL( SCIPreplaceCommonSubexpressions(scip, &consdata->expr, 1, &replacedroot) );
11747  assert(!replacedroot); /* root expression cannot have been equal to one of its subexpressions */
11748 
11749  /* ensure that varexprs in consdata->expr are the one from var2expr hashmap */
11750  {
11751  SCIP_CONSHDLRDATA* conshdlrdata;
11752  SCIP_EXPRITER* it;
11753  SCIP_EXPR* expr;
11754 
11755  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11756  assert(conshdlrdata != NULL);
11757 
11758  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
11759  SCIP_CALL( SCIPexpriterInit(it, consdata->expr, SCIP_EXPRITER_DFS, FALSE) );
11761  for( expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
11762  {
11763  SCIP_EXPR* child;
11764  SCIP_EXPR* hashmapexpr;
11765 
11766  child = SCIPexpriterGetChildExprDFS(it);
11767  if( !SCIPisExprVar(scip, child) )
11768  continue;
11769 
11770  /* check which expression is stored in the hashmap for the var of child */
11771  hashmapexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, SCIPgetVarExprVar(child));
11772  /* if a varexpr exists already in the hashmap, but it is child, then replace child by the one in the hashmap */
11773  if( hashmapexpr != NULL && hashmapexpr != child )
11774  {
11775  SCIP_CALL( SCIPreplaceExprChild(scip, expr, SCIPexpriterGetChildIdxDFS(it), hashmapexpr) );
11776  }
11777  }
11778  SCIPfreeExpriter(&it);
11779  }
11780  }
11781 
11782  /* store variable expressions */
11783  if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
11784  {
11785  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
11786  }
11787 
11788  /* add manually locks to constraints that are not checked for feasibility */
11789  if( !SCIPconsIsChecked(cons) )
11790  {
11791  assert(consdata->nlockspos == 0);
11792  assert(consdata->nlocksneg == 0);
11793 
11794  SCIP_CALL( addLocks(scip, cons, 1, 0) );
11795  }
11796 
11797  if( SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && !infeasible )
11798  {
11799  SCIP_CALL( initSolve(scip, conshdlr, &cons, 1) );
11800  }
11801 
11802  /* TODO deal with infeasibility */
11803  assert(!infeasible);
11804 
11805  return SCIP_OKAY;
11806 }
11807 
11808 
11809 /** constraint deactivation notification method of constraint handler */
11810 static
11811 SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
11812 { /*lint --e{715}*/
11813  SCIP_CONSHDLRDATA* conshdlrdata;
11814 
11815  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11816  assert(conshdlrdata != NULL);
11817 
11818  if( SCIPgetStage(scip) < SCIP_STAGE_EXITSOLVE )
11819  {
11820  SCIP_CALL( deinitSolve(scip, conshdlr, &cons, 1) );
11821  }
11822 
11823  if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMED )
11824  {
11825  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11826  SCIP_CALL( freeVarExprs(scip, SCIPconsGetData(cons)) );
11827  }
11828 
11829  /* remove locks that have been added in consActiveExpr() */
11830  if( !SCIPconsIsChecked(cons) )
11831  {
11832  SCIP_CALL( addLocks(scip, cons, -1, 0) );
11833 
11834  assert(SCIPconsGetData(cons)->nlockspos == 0);
11835  assert(SCIPconsGetData(cons)->nlocksneg == 0);
11836  }
11837 
11838  return SCIP_OKAY;
11839 }
11840 
11841 
11842 /** constraint enabling notification method of constraint handler */
11843 static
11844 SCIP_DECL_CONSENABLE(consEnableNonlinear)
11845 { /*lint --e{715}*/
11846  SCIP_CONSHDLRDATA* conshdlrdata;
11847 
11848  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11849  assert(conshdlrdata != NULL);
11850 
11851  if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
11852  {
11853  SCIP_CALL( catchVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11854  }
11855 
11856  return SCIP_OKAY;
11857 }
11858 
11859 
11860 /** constraint disabling notification method of constraint handler */
11861 static
11862 SCIP_DECL_CONSDISABLE(consDisableNonlinear)
11863 { /*lint --e{715}*/
11864  SCIP_CONSHDLRDATA* conshdlrdata;
11865 
11866  conshdlrdata = SCIPconshdlrGetData(conshdlr);
11867  assert(conshdlrdata != NULL);
11868 
11869  if( SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED )
11870  {
11871  SCIP_CALL( dropVarEvents(scip, conshdlrdata->eventhdlr, cons) );
11872  }
11873 
11874  return SCIP_OKAY;
11875 }
11876 
11877 /** variable deletion of constraint handler */
11878 #ifdef SCIP_DISABLED_CODE
11879 static
11881 { /*lint --e{715}*/
11882  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
11883  SCIPABORT(); /*lint --e{527}*/
11884 
11885  return SCIP_OKAY;
11886 }
11887 #else
11888 #define consDelvarsNonlinear NULL
11889 #endif
11890 
11891 
11892 /** constraint display method of constraint handler */
11893 static
11894 SCIP_DECL_CONSPRINT(consPrintNonlinear)
11895 { /*lint --e{715}*/
11896  SCIP_CONSDATA* consdata;
11897 
11898  consdata = SCIPconsGetData(cons);
11899  assert(consdata != NULL);
11900  assert(consdata->expr != NULL);
11901 
11902  /* print left hand side for ranged constraints */
11903  if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11904  {
11905  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
11906  }
11907 
11908  /* print expression */
11909  SCIP_CALL( SCIPprintExpr(scip, consdata->expr, file) );
11910 
11911  /* print right hand side */
11912  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
11913  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
11914  else if( !SCIPisInfinity(scip, consdata->rhs) )
11915  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
11916  else if( !SCIPisInfinity(scip, -consdata->lhs) )
11917  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
11918  else
11919  SCIPinfoMessage(scip, file, " [free]");
11920 
11921  return SCIP_OKAY;
11922 }
11923 
11924 
11925 /** constraint copying method of constraint handler */
11926 static
11927 SCIP_DECL_CONSCOPY(consCopyNonlinear)
11928 { /*lint --e{715}*/
11929  SCIP_CONSHDLR* targetconshdlr;
11930  SCIP_EXPR* targetexpr = NULL;
11931  SCIP_CONSDATA* sourcedata;
11932 
11933  assert(cons != NULL);
11934 
11935  sourcedata = SCIPconsGetData(sourcecons);
11936  assert(sourcedata != NULL);
11937 
11938  targetconshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
11939  assert(targetconshdlr != NULL);
11940 
11941  SCIP_CALL( SCIPcopyExpr(sourcescip, scip, sourcedata->expr, &targetexpr, exprownerCreate, (void*)targetconshdlr, varmap, consmap, global, valid) );
11942 
11943  if( targetexpr == NULL )
11944  *valid = FALSE;
11945 
11946  *cons = NULL;
11947  if( *valid )
11948  {
11949  /* create copy (only capture targetexpr, no need to copy again) */
11950  SCIP_CALL( createCons(scip, targetconshdlr, cons, name != NULL ? name : SCIPconsGetName(sourcecons),
11951  targetexpr, sourcedata->lhs, sourcedata->rhs, FALSE,
11952  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
11953  }
11954 
11955  if( targetexpr != NULL )
11956  {
11957  /* release target expr */
11958  SCIP_CALL( SCIPreleaseExpr(scip, &targetexpr) );
11959  }
11960 
11961  return SCIP_OKAY;
11962 }
11963 
11964 
11965 /** constraint parsing method of constraint handler */
11966 static
11967 SCIP_DECL_CONSPARSE(consParseNonlinear)
11968 { /*lint --e{715}*/
11969  SCIP_Real lhs;
11970  SCIP_Real rhs;
11971  char* endptr;
11972  SCIP_EXPR* consexprtree;
11973 
11974  SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n", str);
11975 
11976  assert(scip != NULL);
11977  assert(success != NULL);
11978  assert(str != NULL);
11979  assert(name != NULL);
11980  assert(cons != NULL);
11981 
11982  *success = FALSE;
11983 
11984  /* return if string empty */
11985  if( !*str )
11986  return SCIP_OKAY;
11987 
11988  endptr = (char*)str;
11989 
11990  /* set left and right hand side to their default values */
11991  lhs = -SCIPinfinity(scip);
11992  rhs = SCIPinfinity(scip);
11993 
11994  /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
11995 
11996  /* check for left hand side */
11997  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
11998  {
11999  /* there is a number coming, maybe it is a left-hand-side */
12000  if( !SCIPparseReal(scip, str, &lhs, &endptr) )
12001  {
12002  SCIPerrorMessage("error parsing number from <%s>\n", str);
12003  return SCIP_READERROR;
12004  }
12005 
12006  /* ignore whitespace */
12007  SCIP_CALL( SCIPskipSpace(&endptr) );
12008 
12009  if( endptr[0] != '<' || endptr[1] != '=' )
12010  {
12011  /* no '<=' coming, so it was the beginning of the expression and not a left-hand-side */
12012  lhs = -SCIPinfinity(scip);
12013  }
12014  else
12015  {
12016  /* it was indeed a left-hand-side, so continue parsing after it */
12017  str = endptr + 2;
12018 
12019  /* ignore whitespace */
12020  SCIP_CALL( SCIPskipSpace((char**)&str) );
12021  }
12022  }
12023 
12024  SCIPdebugMsg(scip, "str should start at beginning of expr: %s\n", str);
12025 
12026  /* parse expression: so far we did not allocate memory, so can just return in case of readerror */
12027  SCIP_CALL( SCIPparseExpr(scip, &consexprtree, str, &str, exprownerCreate, (void*)conshdlr) );
12028 
12029  /* check for left or right hand side */
12030  SCIP_CALL( SCIPskipSpace((char**)&str) );
12031 
12032  /* check for free constraint */
12033  if( strncmp(str, "[free]", 6) == 0 )
12034  {
12035  if( !SCIPisInfinity(scip, -lhs) )
12036  {
12037  SCIPerrorMessage("cannot have left hand side and [free] status \n");
12038  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12039  return SCIP_OKAY;
12040  }
12041  *success = TRUE;
12042  }
12043  else
12044  {
12045  switch( *str )
12046  {
12047  case '<':
12048  *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12049  break;
12050  case '=':
12051  if( !SCIPisInfinity(scip, -lhs) )
12052  {
12053  SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
12054  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12055  return SCIP_OKAY;
12056  }
12057  else
12058  {
12059  *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &rhs, &endptr) : FALSE;
12060  lhs = rhs;
12061  }
12062  break;
12063  case '>':
12064  if( !SCIPisInfinity(scip, -lhs) )
12065  {
12066  SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
12067  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12068  return SCIP_OKAY;
12069  }
12070  else
12071  {
12072  *success = *(str+1) == '=' ? SCIPparseReal(scip, str+2, &lhs, &endptr) : FALSE;
12073  break;
12074  }
12075  case '\0':
12076  *success = TRUE;
12077  break;
12078  default:
12079  SCIPerrorMessage("unexpected character %c\n", *str);
12080  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12081  return SCIP_OKAY;
12082  }
12083  }
12084 
12085  /* create constraint */
12086  SCIP_CALL( createCons(scip, conshdlr, cons, name,
12087  consexprtree, lhs, rhs, FALSE,
12088  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12089  assert(*cons != NULL);
12090 
12091  SCIP_CALL( SCIPreleaseExpr(scip, &consexprtree) );
12092 
12093  SCIPdebugMsg(scip, "created nonlinear constraint: <%s>\n", SCIPconsGetName(*cons));
12094 
12095  return SCIP_OKAY;
12096 }
12097 
12098 
12099 /** constraint method of constraint handler which returns the variables (if possible) */
12100 static
12101 SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
12102 { /*lint --e{715}*/
12103  SCIP_CONSDATA* consdata;
12104  int i;
12105 
12106  consdata = SCIPconsGetData(cons);
12107  assert(consdata != NULL);
12108 
12109  /* store variable expressions if not done so far */
12110  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12111 
12112  /* check whether array is too small in order to store all variables */
12113  if( varssize < consdata->nvarexprs )
12114  {
12115  *success = FALSE;
12116  return SCIP_OKAY;
12117  }
12118 
12119  for( i = 0; i < consdata->nvarexprs; ++i )
12120  {
12121  vars[i] = SCIPgetVarExprVar(consdata->varexprs[i]);
12122  assert(vars[i] != NULL);
12123  }
12124 
12125  *success = TRUE;
12126 
12127  return SCIP_OKAY;
12128 }
12129 
12130 /** constraint method of constraint handler which returns the number of variables (if possible) */
12131 static
12132 SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
12133 { /*lint --e{715}*/
12134  SCIP_CONSDATA* consdata;
12135 
12136  consdata = SCIPconsGetData(cons);
12137  assert(consdata != NULL);
12138 
12139  /* store variable expressions if not done so far */
12140  SCIP_CALL( storeVarExprs(scip, conshdlr, consdata) );
12141 
12142  *nvars = consdata->nvarexprs;
12143  *success = TRUE;
12144 
12145  return SCIP_OKAY;
12146 }
12147 
12148 /** constraint handler method to suggest dive bound changes during the generic diving algorithm */
12149 #ifdef SCIP_DISABLED_CODE
12150 static
12152 { /*lint --e{715}*/
12153  SCIPerrorMessage("method of nonlinear constraint handler not implemented yet\n");
12154  SCIPABORT(); /*lint --e{527}*/
12155 
12156  return SCIP_OKAY;
12157 }
12158 #else
12159 #define consGetDiveBdChgsNonlinear NULL
12160 #endif
12161 
12162 /** constraint handler method which returns the permutation symmetry detection graph of a constraint (if possible) */
12163 static
12164 SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphNonlinear)
12165 { /*lint --e{715}*/
12166  SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
12167 
12168  return SCIP_OKAY;
12169 }
12170 
12171 /** constraint handler method which returns the signed permutation symmetry detection graph of a constraint (if possible) */
12172 static
12173 SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphNonlinear)
12174 { /*lint --e{715}*/
12175  SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
12176 
12177  return SCIP_OKAY;
12178 }
12179 
12180 /** output method of statistics table to output file stream 'file' */
12181 static
12182 SCIP_DECL_TABLEOUTPUT(tableOutputNonlinear)
12183 { /*lint --e{715}*/
12184  SCIP_CONSHDLR* conshdlr;
12185  SCIP_CONSHDLRDATA* conshdlrdata;
12186 
12187  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12188  assert(conshdlr != NULL);
12189 
12190  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12191  assert(conshdlrdata != NULL);
12192 
12193  /* print statistics for constraint handler */
12194  SCIPinfoMessage(scip, file, "Nonlinear Conshdlr : %10s %10s %10s %10s %10s %10s %10s\n", "WeakSepa", "TightenLP", "DespTghtLP", "DespBranch", "DespCutoff", "ForceLP", "CanonTime");
12195  SCIPinfoMessage(scip, file, " enforce%-10s:", "");
12196  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nweaksepa);
12197  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ntightenlp);
12198  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatetightenlp);
12199  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatebranch);
12200  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->ndesperatecutoff);
12201  SCIPinfoMessage(scip, file, " %10lld", conshdlrdata->nforcelp);
12202  SCIPinfoMessage(scip, file, "\n");
12203  SCIPinfoMessage(scip, file, " presolve%-9s: %-65s", "", "");
12204  SCIPinfoMessage(scip, file, " %10.2f", SCIPgetClockTime(scip, conshdlrdata->canonicalizetime));
12205  SCIPinfoMessage(scip, file, "\n");
12206 
12207  return SCIP_OKAY;
12208 }
12209 
12210 /** output method of statistics table to output file stream 'file' */
12211 static
12212 SCIP_DECL_TABLEOUTPUT(tableOutputNlhdlr)
12213 { /*lint --e{715}*/
12214  SCIP_CONSHDLR* conshdlr;
12215  SCIP_CONSHDLRDATA* conshdlrdata;
12216 
12217  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12218  assert(conshdlr != NULL);
12219 
12220  /* skip nlhdlr table if there never were active nonlinear constraints */
12221  if( SCIPconshdlrGetMaxNActiveConss(conshdlr) == 0 )
12222  return SCIP_OKAY;
12223 
12224  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12225  assert(conshdlrdata != NULL);
12226 
12227  /* print statistics for nonlinear handlers */
12228  SCIPnlhdlrPrintStatistics(scip, conshdlrdata->nlhdlrs, conshdlrdata->nnlhdlrs, file);
12229 
12230  return SCIP_OKAY;
12231 }
12232 
12233 /** execution method of display nlhdlrs dialog */
12234 static
12235 SCIP_DECL_DIALOGEXEC(dialogExecDisplayNlhdlrs)
12236 { /*lint --e{715}*/
12237  SCIP_CONSHDLR* conshdlr;
12238  SCIP_CONSHDLRDATA* conshdlrdata;
12239  int i;
12240 
12241  /* add dialog to history of dialogs that have been executed */
12242  SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
12243 
12244  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12245  assert(conshdlr != NULL);
12246 
12247  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12248  assert(conshdlrdata != NULL);
12249 
12250  /* display list of nonlinear handler */
12251  SCIPdialogMessage(scip, NULL, "\n");
12252  SCIPdialogMessage(scip, NULL, " nonlinear handler enabled detectprio enforceprio description\n");
12253  SCIPdialogMessage(scip, NULL, " ----------------- ------- ---------- ----------- -----------\n");
12254  for( i = 0; i < conshdlrdata->nnlhdlrs; ++i )
12255  {
12256  SCIP_NLHDLR* nlhdlr = conshdlrdata->nlhdlrs[i];
12257  assert(nlhdlr != NULL);
12258 
12259  SCIPdialogMessage(scip, NULL, " %-17s ", SCIPnlhdlrGetName(nlhdlr));
12260  SCIPdialogMessage(scip, NULL, " %7s ", SCIPnlhdlrIsEnabled(nlhdlr) ? "yes" : "no");
12261  SCIPdialogMessage(scip, NULL, " %10d ", SCIPnlhdlrGetDetectPriority(nlhdlr));
12262  SCIPdialogMessage(scip, NULL, " %11d ", SCIPnlhdlrGetEnfoPriority(nlhdlr));
12263  SCIPdialogMessage(scip, NULL, " %s", SCIPnlhdlrGetDesc(nlhdlr));
12264  SCIPdialogMessage(scip, NULL, "\n");
12265  }
12266  SCIPdialogMessage(scip, NULL, "\n");
12267 
12268  /* next dialog will be root dialog again */
12269  *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
12270 
12271  return SCIP_OKAY;
12272 }
12273 
12274 /*
12275  * constraint handler specific interface methods
12276  */
12277 
12278 /** creates the handler for nonlinear constraints and includes it in SCIP */
12280  SCIP* scip /**< SCIP data structure */
12281  )
12282 {
12283  SCIP_CONSHDLRDATA* conshdlrdata;
12284  SCIP_DIALOG* parentdialog;
12285 
12286  /* create nonlinear constraint handler data */
12287  SCIP_CALL( SCIPallocClearBlockMemory(scip, &conshdlrdata) );
12288  conshdlrdata->intevalvar = intEvalVarBoundTightening;
12289  conshdlrdata->curboundstag = 1;
12290  conshdlrdata->lastboundrelax = 1;
12291  conshdlrdata->curpropboundstag = 1;
12292  conshdlrdata->newsoleventfilterpos = -1;
12293  SCIP_CALL( SCIPcreateClock(scip, &conshdlrdata->canonicalizetime) );
12294  SCIP_CALL( SCIPqueueCreate(&conshdlrdata->reversepropqueue, 100, 2.0) );
12295  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->var2expr, SCIPblkmem(scip), 100) );
12296 
12297  /* include constraint handler */
12303  conshdlrCopyNonlinear,
12304  consFreeNonlinear, consInitNonlinear, consExitNonlinear,
12305  consInitpreNonlinear, consExitpreNonlinear, consInitsolNonlinear, consExitsolNonlinear,
12306  consDeleteNonlinear, consTransNonlinear, consInitlpNonlinear,
12307  consSepalpNonlinear, consSepasolNonlinear, consEnfolpNonlinear, consEnforelaxNonlinear, consEnfopsNonlinear, consCheckNonlinear,
12308  consPropNonlinear, consPresolNonlinear, consRespropNonlinear, consLockNonlinear,
12309  consActiveNonlinear, consDeactiveNonlinear,
12310  consEnableNonlinear, consDisableNonlinear, consDelvarsNonlinear,
12311  consPrintNonlinear, consCopyNonlinear, consParseNonlinear,
12312  consGetVarsNonlinear, consGetNVarsNonlinear, consGetDiveBdChgsNonlinear, consGetPermsymGraphNonlinear,
12313  consGetSignedPermsymGraphNonlinear, conshdlrdata) );
12314 
12315  /* add nonlinear constraint handler parameters */
12316  /* TODO organize into more subcategories */
12317  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
12318  "limit on number of propagation rounds for a set of constraints within one round of SCIP propagation",
12319  &conshdlrdata->maxproprounds, FALSE, 10, 0, INT_MAX, NULL, NULL) );
12320 
12321  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propauxvars",
12322  "whether to check bounds of all auxiliary variable to seed reverse propagation",
12323  &conshdlrdata->propauxvars, TRUE, TRUE, NULL, NULL) );
12324 
12325  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelax",
12326  "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",
12327  &conshdlrdata->varboundrelax, TRUE, 'r', "nabr", NULL, NULL) );
12328 
12329  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/varboundrelaxamount",
12330  "by how much to relax variable bounds during bound tightening if strategy 'a', 'b', or 'r'",
12331  &conshdlrdata->varboundrelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12332 
12333  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/conssiderelaxamount",
12334  "by how much to relax constraint sides during bound tightening",
12335  &conshdlrdata->conssiderelaxamount, TRUE, SCIPepsilon(scip), 0.0, 1.0, NULL, NULL) );
12336 
12337  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpmaxperturb",
12338  "maximal relative perturbation of reference point when computing facet of envelope of vertex-polyhedral function (dim>2)",
12339  &conshdlrdata->vp_maxperturb, TRUE, VERTEXPOLY_MAXPERTURBATION, 0.0, 1.0, NULL, NULL) );
12340 
12341  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/vpadjfacetthresh",
12342  "adjust computed facet of envelope of vertex-polyhedral function up to a violation of this value times LP feasibility tolerance",
12343  &conshdlrdata->vp_adjfacetthreshold, TRUE, VERTEXPOLY_ADJUSTFACETFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
12344 
12345  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/vpdualsimplex",
12346  "whether to use dual simplex instead of primal simplex for LP that computes facet of vertex-polyhedral function",
12347  &conshdlrdata->vp_dualsimplex, TRUE, VERTEXPOLY_USEDUALSIMPLEX, NULL, NULL) );
12348 
12349  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/bilinmaxnauxexprs",
12350  "maximal number of auxiliary expressions per bilinear term",
12351  &conshdlrdata->bilinmaxnauxexprs, FALSE, BILIN_MAXNAUXEXPRS, 0, INT_MAX, NULL, NULL) );
12352 
12353  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprods",
12354  "whether to reformulate products of binary variables during presolving",
12355  &conshdlrdata->reformbinprods, FALSE, TRUE, NULL, NULL) );
12356 
12357  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsand",
12358  "whether to use the AND constraint handler for reformulating binary products",
12359  &conshdlrdata->reformbinprodsand, FALSE, TRUE, NULL, NULL) );
12360 
12361  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/reformbinprodsfac",
12362  "minimum number of terms to reformulate bilinear binary products by factorizing variables (<= 1: disabled)",
12363  &conshdlrdata->reformbinprodsfac, FALSE, 50, 1, INT_MAX, NULL, NULL) );
12364 
12365  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forbidmultaggrnlvar",
12366  "whether to forbid multiaggregation of nonlinear variables",
12367  &conshdlrdata->forbidmultaggrnlvar, TRUE, TRUE, NULL, NULL) );
12368 
12369  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/tightenlpfeastol",
12370  "whether to tighten LP feasibility tolerance during enforcement, if it seems useful",
12371  &conshdlrdata->tightenlpfeastol, TRUE, TRUE, NULL, NULL) );
12372 
12373  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/propinenforce",
12374  "whether to (re)run propagation in enforcement",
12375  &conshdlrdata->propinenforce, TRUE, FALSE, NULL, NULL) );
12376 
12377  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutthreshold",
12378  "threshold for when to regard a cut from an estimator as weak (lower values allow more weak cuts)",
12379  &conshdlrdata->weakcutthreshold, TRUE, 0.2, 0.0, 1.0, NULL, NULL) );
12380 
12381  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/strongcutmaxcoef",
12382  "\"strong\" cuts will be scaled to have their maximal coef in [1/strongcutmaxcoef,strongcutmaxcoef]",
12383  &conshdlrdata->strongcutmaxcoef, TRUE, 1000.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
12384 
12385  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strongcutefficacy",
12386  "consider efficacy requirement when deciding whether a cut is \"strong\"",
12387  &conshdlrdata->strongcutefficacy, TRUE, FALSE, NULL, NULL) );
12388 
12389  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forcestrongcut",
12390  "whether to force \"strong\" cuts in enforcement",
12391  &conshdlrdata->forcestrongcut, TRUE, FALSE, NULL, NULL) );
12392 
12393  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/enfoauxviolfactor",
12394  "an expression will be enforced if the \"auxiliary\" violation is at least this factor times the \"original\" violation",
12395  &conshdlrdata->enfoauxviolfactor, TRUE, 0.01, 0.0, 1.0, NULL, NULL) );
12396 
12397  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/weakcutminviolfactor",
12398  "retry enfo of constraint with weak cuts if violation is least this factor of maximal violated constraints",
12399  &conshdlrdata->weakcutminviolfactor, TRUE, 0.5, 0.0, 2.0, NULL, NULL) );
12400 
12401  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/rownotremovable",
12402  "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",
12403  &conshdlrdata->rownotremovable, TRUE, 'o', "oea", NULL, NULL) );
12404 
12405  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/violscale",
12406  "method how to scale violations to make them comparable (not used for feasibility check): (n)one, (a)ctivity and side, norm of (g)radient",
12407  &conshdlrdata->violscale, TRUE, 'n', "nag", NULL, NULL) );
12408 
12409  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/checkvarlocks",
12410  "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)",
12411  &conshdlrdata->checkvarlocks, TRUE, 't', "bdt", NULL, NULL) );
12412 
12413  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/branching/aux",
12414  "from which depth on in the tree to allow branching on auxiliary variables (variables added for extended formulation)",
12415  &conshdlrdata->branchauxmindepth, FALSE, INT_MAX, 0, INT_MAX, NULL, NULL) );
12416 
12417  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branching/external",
12418  "whether to use external branching candidates and branching rules for branching",
12419  &conshdlrdata->branchexternal, FALSE, FALSE, NULL, NULL) );
12420 
12421  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highviolfactor",
12422  "consider a constraint highly violated if its violation is >= this factor * maximal violation among all constraints",
12423  &conshdlrdata->branchhighviolfactor, FALSE, 0.0, 0.0, 1.0, NULL, NULL) );
12424 
12425  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/highscorefactor",
12426  "consider a variable branching score high if its branching score >= this factor * maximal branching score among all variables",
12427  &conshdlrdata->branchhighscorefactor, FALSE, 0.9, 0.0, 1.0, NULL, NULL) );
12428 
12429  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/violweight",
12430  "weight by how much to consider the violation assigned to a variable for its branching score",
12431  &conshdlrdata->branchviolweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12432 
12433  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/fracweight",
12434  "weight by how much to consider fractionality of integer variables in branching score for spatial branching",
12435  &conshdlrdata->branchfracweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12436 
12437  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/dualweight",
12438  "weight by how much to consider the dual values of rows that contain a variable for its branching score",
12439  &conshdlrdata->branchdualweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12440 
12441  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostweight",
12442  "weight by how much to consider the pseudo cost of a variable for its branching score",
12443  &conshdlrdata->branchpscostweight, FALSE, 1.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12444 
12445  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/domainweight",
12446  "weight by how much to consider the domain width in branching score",
12447  &conshdlrdata->branchdomainweight, FALSE, 0.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12448 
12449  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/vartypeweight",
12450  "weight by how much to consider variable type (continuous: 0, binary: 1, integer: 0.1, impl-integer: 0.01) in branching score",
12451  &conshdlrdata->branchvartypeweight, FALSE, 0.5, 0.0, SCIPinfinity(scip), NULL, NULL) );
12452 
12453  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/scoreagg",
12454  "how to aggregate several branching scores given for the same expression: 'a'verage, 'm'aximum, 's'um",
12455  &conshdlrdata->branchscoreagg, FALSE, 's', "ams", NULL, NULL) );
12456 
12457  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/branching/violsplit",
12458  "method used to split violation in expression onto variables: 'u'niform, 'm'idness of solution, 'd'omain width, 'l'ogarithmic domain width",
12459  &conshdlrdata->branchviolsplit, FALSE, 'm', "umdl", NULL, NULL) );
12460 
12461  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/pscostreliable",
12462  "minimum pseudo-cost update count required to consider pseudo-costs reliable",
12463  &conshdlrdata->branchpscostreliable, FALSE, 2.0, 0.0, SCIPinfinity(scip), NULL, NULL) );
12464 
12465  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/branching/mixfractional",
12466  "minimal average pseudo cost count for discrete variables at which to start considering spatial branching before branching on fractional integer variables",
12467  &conshdlrdata->branchmixfractional, FALSE, SCIPinfinity(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
12468 
12469  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/linearizeheursol",
12470  "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)",
12471  &conshdlrdata->linearizeheursol, FALSE, 'o', "oie", NULL, NULL) );
12472 
12473  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
12474  "whether to assume that any constraint is convex",
12475  &conshdlrdata->assumeconvex, FALSE, FALSE, NULL, NULL) );
12476 
12477  /* include handler for bound change events */
12478  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, CONSHDLR_NAME "_boundchange",
12479  "signals a bound change to a nonlinear constraint", processVarEvent, NULL) );
12480  assert(conshdlrdata->eventhdlr != NULL);
12481 
12482  /* include tables for statistics */
12483  assert(SCIPfindTable(scip, TABLE_NAME_NONLINEAR) == NULL);
12485  NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNonlinear,
12487 
12488  assert(SCIPfindTable(scip, TABLE_NAME_NLHDLR) == NULL);
12490  NULL, NULL, NULL, NULL, NULL, NULL, tableOutputNlhdlr,
12492 
12493  /* create, include, and release display nlhdlrs dialog */
12494  if( SCIPgetRootDialog(scip) != NULL && SCIPdialogFindEntry(SCIPgetRootDialog(scip), "display", &parentdialog) == 1 )
12495  {
12496  SCIP_DIALOG* dialog;
12497 
12498  assert(parentdialog != NULL);
12499  assert(!SCIPdialogHasEntry(parentdialog, DIALOG_NAME));
12500 
12501  SCIP_CALL( SCIPincludeDialog(scip, &dialog,
12502  NULL, dialogExecDisplayNlhdlrs, NULL, NULL,
12504  SCIP_CALL( SCIPaddDialogEntry(scip, parentdialog, dialog) );
12505  SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
12506  }
12507 
12508  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME "_newsolution", "handles the event that a new primal solution has been found",
12509  processNewSolutionEvent, NULL) );
12510 
12511  return SCIP_OKAY;
12512 }
12513 
12514 /** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
12516  SCIP* scip, /**< SCIP data structure */
12517  SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)), /**< method to call for upgrading nonlinear constraint */
12518  int priority, /**< priority of upgrading method */
12519  SCIP_Bool active, /**< should the upgrading method by active by default? */
12520  const char* conshdlrname /**< name of the constraint handler */
12521  )
12522 {
12523  SCIP_CONSHDLR* conshdlr;
12524  SCIP_CONSHDLRDATA* conshdlrdata;
12525  CONSUPGRADE* consupgrade;
12526  char paramname[SCIP_MAXSTRLEN];
12527  char paramdesc[SCIP_MAXSTRLEN];
12528  int i;
12529 
12530  assert(conshdlrname != NULL );
12531  assert(nlconsupgd != NULL);
12532 
12533  /* find the nonlinear constraint handler */
12534  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12535  if( conshdlr == NULL )
12536  {
12537  SCIPerrorMessage("nonlinear constraint handler not found\n");
12538  return SCIP_PLUGINNOTFOUND;
12539  }
12540 
12541  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12542  assert(conshdlrdata != NULL);
12543 
12544  /* check whether upgrade method exists already */
12545  for( i = conshdlrdata->nconsupgrades - 1; i >= 0; --i )
12546  {
12547  if( conshdlrdata->consupgrades[i]->consupgd == nlconsupgd )
12548  {
12549 #ifdef SCIP_DEBUG
12550  SCIPwarningMessage(scip, "Try to add already known upgrade method for constraint handler <%s>.\n", conshdlrname);
12551 #endif
12552  return SCIP_OKAY;
12553  }
12554  }
12555 
12556  /* create a nonlinear constraint upgrade data object */
12557  SCIP_CALL( SCIPallocBlockMemory(scip, &consupgrade) );
12558  consupgrade->consupgd = nlconsupgd;
12559  consupgrade->priority = priority;
12560  consupgrade->active = active;
12561 
12562  /* insert nonlinear constraint upgrade method into constraint handler data */
12563  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->consupgrades, &conshdlrdata->consupgradessize, conshdlrdata->nconsupgrades+1) );
12564  assert(conshdlrdata->nconsupgrades+1 <= conshdlrdata->consupgradessize);
12565 
12566  for( i = conshdlrdata->nconsupgrades; i > 0 && conshdlrdata->consupgrades[i-1]->priority < consupgrade->priority; --i )
12567  conshdlrdata->consupgrades[i] = conshdlrdata->consupgrades[i-1];
12568  assert(0 <= i && i <= conshdlrdata->nconsupgrades);
12569  conshdlrdata->consupgrades[i] = consupgrade;
12570  conshdlrdata->nconsupgrades++;
12571 
12572  /* adds parameter to turn on and off the upgrading step */
12573  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
12574  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
12576  paramname, paramdesc,
12577  &consupgrade->active, FALSE, active, NULL, NULL) );
12578 
12579  return SCIP_OKAY;
12580 }
12581 
12582 /** creates and captures a nonlinear constraint
12583  *
12584  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12585  */
12587  SCIP* scip, /**< SCIP data structure */
12588  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12589  const char* name, /**< name of constraint */
12590  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12591  SCIP_Real lhs, /**< left hand side of constraint */
12592  SCIP_Real rhs, /**< right hand side of constraint */
12593  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12594  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12595  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12596  * Usually set to TRUE. */
12597  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12598  * TRUE for model constraints, FALSE for additional, redundant constraints. */
12599  SCIP_Bool check, /**< should the constraint be checked for feasibility?
12600  * TRUE for model constraints, FALSE for additional, redundant constraints. */
12601  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12602  * Usually set to TRUE. */
12603  SCIP_Bool local, /**< is constraint only valid locally?
12604  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12605  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12606  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12607  * adds coefficients to this constraint. */
12608  SCIP_Bool dynamic, /**< is constraint subject to aging?
12609  * Usually set to FALSE. Set to TRUE for own cuts which
12610  * are separated as constraints. */
12611  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12612  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12613  )
12614 {
12615  /* TODO: (optional) modify the definition of the SCIPcreateConsNonlinear() call, if you don't need all the information */
12616  SCIP_CONSHDLR* conshdlr;
12617 
12618  /* find the nonlinear constraint handler */
12619  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12620  if( conshdlr == NULL )
12621  {
12622  SCIPerrorMessage("nonlinear constraint handler not found\n");
12623  return SCIP_PLUGINNOTFOUND;
12624  }
12625 
12626  /* create constraint */
12627  SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, TRUE,
12628  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12629 
12630  return SCIP_OKAY;
12631 }
12632 
12633 /** creates and captures a nonlinear constraint with all its constraint flags set to their default values
12634  *
12635  * All flags can be set via SCIPconsSetFLAGNAME-methods.
12636  *
12637  * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration.
12638  *
12639  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12640  */
12642  SCIP* scip, /**< SCIP data structure */
12643  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12644  const char* name, /**< name of constraint */
12645  SCIP_EXPR* expr, /**< expression of constraint (must not be NULL) */
12646  SCIP_Real lhs, /**< left hand side of constraint */
12647  SCIP_Real rhs /**< right hand side of constraint */
12648  )
12649 {
12650  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, expr, lhs, rhs,
12651  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
12652 
12653  return SCIP_OKAY;
12654 }
12655 
12656 /** creates and captures a quadratic nonlinear constraint
12657  *
12658  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12659  */
12661  SCIP* scip, /**< SCIP data structure */
12662  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12663  const char* name, /**< name of constraint */
12664  int nlinvars, /**< number of linear terms */
12665  SCIP_VAR** linvars, /**< array with variables in linear part */
12666  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12667  int nquadterms, /**< number of quadratic terms */
12668  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12669  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12670  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12671  SCIP_Real lhs, /**< left hand side of quadratic equation */
12672  SCIP_Real rhs, /**< right hand side of quadratic equation */
12673  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
12674  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
12675  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
12676  * Usually set to TRUE. */
12677  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
12678  * TRUE for model constraints, FALSE for additional, redundant constraints. */
12679  SCIP_Bool check, /**< should the constraint be checked for feasibility?
12680  * TRUE for model constraints, FALSE for additional, redundant constraints. */
12681  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
12682  * Usually set to TRUE. */
12683  SCIP_Bool local, /**< is constraint only valid locally?
12684  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
12685  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
12686  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
12687  * adds coefficients to this constraint. */
12688  SCIP_Bool dynamic, /**< is constraint subject to aging?
12689  * Usually set to FALSE. Set to TRUE for own cuts which
12690  * are separated as constraints. */
12691  SCIP_Bool removable /**< should the relaxation be removed from the LP due to aging or cleanup?
12692  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
12693  )
12694 {
12695  SCIP_CONSHDLR* conshdlr;
12696  SCIP_EXPR* expr;
12697 
12698  assert(nlinvars == 0 || (linvars != NULL && lincoefs != NULL));
12699  assert(nquadterms == 0 || (quadvars1 != NULL && quadvars2 != NULL && quadcoefs != NULL));
12700 
12701  /* get nonlinear constraint handler */
12702  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
12703  if( conshdlr == NULL )
12704  {
12705  SCIPerrorMessage("nonlinear constraint handler not found\n");
12706  return SCIP_PLUGINNOTFOUND;
12707  }
12708 
12709  /* create quadratic expression */
12710  SCIP_CALL( SCIPcreateExprQuadratic(scip, &expr, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, exprownerCreate, (void*)conshdlr) );
12711  assert(expr != NULL);
12712 
12713  /* create nonlinear constraint */
12714  SCIP_CALL( createCons(scip, conshdlr, cons, name, expr, lhs, rhs, FALSE,
12715  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable) );
12716 
12717  /* release quadratic expression (captured by constraint now) */
12718  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12719 
12720  return SCIP_OKAY;
12721 }
12722 
12723 /** creates and captures a quadratic nonlinear constraint with all its constraint flags set to their default values
12724  *
12725  * All flags can be set via SCIPconsSetFLAGNAME-methods.
12726  *
12727  * @see SCIPcreateConsQuadraticNonlinear() for information about the basic constraint flag configuration.
12728  *
12729  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12730  */
12732  SCIP* scip, /**< SCIP data structure */
12733  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12734  const char* name, /**< name of constraint */
12735  int nlinvars, /**< number of linear terms */
12736  SCIP_VAR** linvars, /**< array with variables in linear part */
12737  SCIP_Real* lincoefs, /**< array with coefficients of variables in linear part */
12738  int nquadterms, /**< number of quadratic terms */
12739  SCIP_VAR** quadvars1, /**< array with first variables in quadratic terms */
12740  SCIP_VAR** quadvars2, /**< array with second variables in quadratic terms */
12741  SCIP_Real* quadcoefs, /**< array with coefficients of quadratic terms */
12742  SCIP_Real lhs, /**< left hand side of quadratic equation */
12743  SCIP_Real rhs /**< right hand side of quadratic equation */
12744  )
12745 {
12746  SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nquadterms, quadvars1, quadvars2, quadcoefs, lhs, rhs,
12747  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
12748 
12749  return SCIP_OKAY;
12750 }
12751 
12752 /** creates and captures a nonlinear constraint that is a second-order cone constraint with all its constraint flags set to their default values
12753  *
12754  * \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$
12755  *
12756  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12757  */
12759  SCIP* scip, /**< SCIP data structure */
12760  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12761  const char* name, /**< name of constraint */
12762  int nvars, /**< number of variables on left hand side of constraint (n) */
12763  SCIP_VAR** vars, /**< array with variables on left hand side (x_i) */
12764  SCIP_Real* coefs, /**< array with coefficients of left hand side variables (alpha_i), or NULL if all 1.0 */
12765  SCIP_Real* offsets, /**< array with offsets of variables (beta_i), or NULL if all 0.0 */
12766  SCIP_Real constant, /**< constant on left hand side (gamma) */
12767  SCIP_VAR* rhsvar, /**< variable on right hand side of constraint (x_{n+1}) */
12768  SCIP_Real rhscoeff, /**< coefficient of variable on right hand side (alpha_{n+1}) */
12769  SCIP_Real rhsoffset /**< offset of variable on right hand side (beta_{n+1}) */
12770  )
12771 {
12772  SCIP_EXPR* expr;
12773  SCIP_EXPR* lhssum;
12774  SCIP_EXPR* terms[2];
12775  SCIP_Real termcoefs[2];
12776  int i;
12777 
12778  assert(vars != NULL || nvars == 0);
12779 
12780  SCIP_CALL( SCIPcreateExprSum(scip, &lhssum, 0, NULL, NULL, constant, NULL, NULL) ); /* gamma */
12781  for( i = 0; i < nvars; ++i )
12782  {
12783  SCIP_EXPR* varexpr;
12784  SCIP_EXPR* powexpr;
12785 
12786  SCIP_CALL( SCIPcreateExprVar(scip, &varexpr, vars[i], NULL, NULL) ); /* x_i */
12787  if( offsets != NULL && offsets[i] != 0.0 )
12788  {
12789  SCIP_EXPR* sum;
12790  SCIP_CALL( SCIPcreateExprSum(scip, &sum, 1, &varexpr, NULL, offsets[i], NULL, NULL) ); /* x_i + beta_i */
12791  SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, sum, 2.0, NULL, NULL) ); /* (x_i + beta_i)^2 */
12792  SCIP_CALL( SCIPreleaseExpr(scip, &sum) );
12793  }
12794  else
12795  {
12796  SCIP_CALL( SCIPcreateExprPow(scip, &powexpr, varexpr, 2.0, NULL, NULL) ); /* x_i^2 */
12797  }
12798 
12799  SCIP_CALL( SCIPappendExprSumExpr(scip, lhssum, powexpr, coefs != NULL ? coefs[i]*coefs[i] : 1.0) ); /* + alpha_i^2 (x_i + beta_i)^2 */
12800  SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
12801  SCIP_CALL( SCIPreleaseExpr(scip, &powexpr) );
12802  }
12803 
12804  SCIP_CALL( SCIPcreateExprPow(scip, &terms[0], lhssum, 0.5, NULL, NULL) ); /* sqrt(...) */
12805  SCIP_CALL( SCIPreleaseExpr(scip, &lhssum) );
12806  termcoefs[0] = 1.0;
12807 
12808  SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], rhsvar, NULL, NULL) ); /* x_{n+1} */
12809  termcoefs[1] = -rhscoeff;
12810 
12811  SCIP_CALL( SCIPcreateExprSum(scip, &expr, 2, terms, termcoefs, 0.0, NULL, NULL) ); /* sqrt(...) - alpha_{n+1}x_{n_1} */
12812 
12813  SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
12814  SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
12815 
12816  SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, expr, -SCIPinfinity(scip), rhscoeff * rhsoffset) );
12817 
12818  SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
12819 
12820  return SCIP_OKAY;
12821 }
12822 
12823 /** creates and captures a signpower nonlinear constraint with all its constraint flags set to their default values
12824  *
12825  * \f$\textrm{lhs} \leq \textrm{sign}(x+a) |x+a|^n + c z \leq \textrm{rhs}\f$
12826  *
12827  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
12828  */
12830  SCIP* scip, /**< SCIP data structure */
12831  SCIP_CONS** cons, /**< pointer to hold the created constraint */
12832  const char* name, /**< name of constraint */
12833  SCIP_VAR* x, /**< nonlinear variable x in constraint */
12834  SCIP_VAR* z, /**< linear variable z in constraint */
12835  SCIP_Real exponent, /**< exponent n of |x+offset|^n term in constraint */
12836  SCIP_Real xoffset, /**< offset in |x+offset|^n term in constraint */
12837  SCIP_Real zcoef, /**< coefficient of z in constraint */
12838  SCIP_Real lhs, /**< left hand side of constraint */
12839  SCIP_Real rhs /**< right hand side of constraint */
12840  )
12841 {
12842  SCIP_EXPR* xexpr;
12843  SCIP_EXPR* terms[2];
12844  SCIP_Real coefs[2];
12845  SCIP_EXPR* sumexpr;
12846 
12847  assert(x != NULL);
12848  assert(z != NULL);
12849 
12850  SCIP_CALL( SCIPcreateExprVar(scip, &xexpr, x, NULL, NULL) );
12851  if( xoffset != 0.0 )
12852  {
12853  SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 1, &xexpr, NULL, xoffset, NULL, NULL) ); /* x + xoffset */
12854  SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], sumexpr, exponent, NULL, NULL) ); /* signpow(x + xoffset, exponent) */
12855 
12856  SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
12857  }
12858  else
12859  {
12860  SCIP_CALL( SCIPcreateExprSignpower(scip, &terms[0], xexpr, exponent, NULL, NULL) ); /* signpow(x, exponent) */
12861  }
12862  coefs[0] = 1.0;
12863 
12864  SCIP_CALL( SCIPcreateExprVar(scip, &terms[1], z, NULL, NULL) );
12865  coefs[1] = zcoef;
12866 
12867  SCIP_CALL( SCIPcreateExprSum(scip, &sumexpr, 2, terms, coefs, 0.0, NULL, NULL) ); /* signpowexpr + zcoef * z */
12868 
12869  SCIP_CALL( SCIPcreateConsBasicNonlinear(scip, cons, name, sumexpr, lhs, rhs) );
12870 
12871  SCIP_CALL( SCIPreleaseExpr(scip, &sumexpr) );
12872  SCIP_CALL( SCIPreleaseExpr(scip, &terms[1]) );
12873  SCIP_CALL( SCIPreleaseExpr(scip, &terms[0]) );
12874  SCIP_CALL( SCIPreleaseExpr(scip, &xexpr) );
12875 
12876  return SCIP_OKAY;
12877 }
12878 
12879 /** gets tag indicating current local variable bounds */
12881  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12882  )
12883 {
12884  SCIP_CONSHDLRDATA* conshdlrdata;
12885 
12886  assert(conshdlr != NULL);
12887  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12888 
12889  return conshdlrdata->curboundstag;
12890 }
12891 
12892 /** gets the `curboundstag` from the last time where variable bounds were relaxed */
12894  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12895  )
12896 {
12897  SCIP_CONSHDLRDATA* conshdlrdata;
12898 
12899  assert(conshdlr != NULL);
12900  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12901 
12902  return conshdlrdata->lastboundrelax;
12903 }
12904 
12905 /** increments `curboundstag` and resets `lastboundrelax` in constraint handler data
12906  *
12907  * @attention This method is not intended for normal use.
12908  * These tags are maintained by the event handler for variable bound change events.
12909  * This method is used by some unittests.
12910  */
12912  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
12913  SCIP_Bool boundrelax /**< indicates whether a bound was relaxed, i.e., lastboundrelax should be set too */
12914  )
12915 {
12916  SCIP_CONSHDLRDATA* conshdlrdata;
12917 
12918  conshdlrdata = SCIPconshdlrGetData(conshdlr);
12919  assert(conshdlrdata != NULL);
12920 
12921  ++conshdlrdata->curboundstag;
12922  assert(conshdlrdata->curboundstag > 0);
12923 
12924  if( boundrelax )
12925  conshdlrdata->lastboundrelax = conshdlrdata->curboundstag;
12926 }
12927 
12928 /** returns the hashmap that is internally used to map variables to their corresponding variable expressions */
12930  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
12931  )
12932 {
12933  assert(conshdlr != NULL);
12934 
12935  return SCIPconshdlrGetData(conshdlr)->var2expr;
12936 }
12937 
12938 /** processes a rowprep for cut addition and maybe report branchscores */
12940  SCIP* scip, /**< SCIP data structure */
12941  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler which provided the estimator */
12942  SCIP_CONS* cons, /**< nonlinear constraint */
12943  SCIP_EXPR* expr, /**< expression */
12944  SCIP_ROWPREP* rowprep, /**< cut to be added */
12945  SCIP_Bool overestimate, /**< whether the expression needs to be over- or underestimated */
12946  SCIP_VAR* auxvar, /**< auxiliary variable */
12947  SCIP_Real auxvalue, /**< current value of expression w.r.t. auxiliary variables as obtained from EVALAUX */
12948  SCIP_Bool allowweakcuts, /**< whether we should only look for "strong" cuts, or anything that separates is fine */
12949  SCIP_Bool branchscoresuccess, /**< whether the estimator generation generated branching scores */
12950  SCIP_Bool inenforcement, /**< whether we are in enforcement, or only in separation */
12951  SCIP_SOL* sol, /**< solution to be separated (NULL for the LP solution) */
12952  SCIP_RESULT* result /**< pointer to store the result */
12953  )
12954 {
12955  SCIP_Real cutviol;
12956  SCIP_CONSHDLRDATA* conshdlrdata;
12957  SCIP_Real auxvarvalue = SCIP_INVALID;
12958  SCIP_Bool sepasuccess;
12959  SCIP_Real estimateval = SCIP_INVALID;
12960  SCIP_Real mincutviolation;
12961 
12962  assert(nlhdlr != NULL);
12963  assert(cons != NULL);
12964  assert(expr != NULL);
12965  assert(rowprep != NULL);
12966  assert(auxvar != NULL);
12967  assert(result != NULL);
12968 
12969  /* decide on minimal violation of cut */
12970  if( sol == NULL )
12971  mincutviolation = SCIPgetLPFeastol(scip); /* we enforce an LP solution */
12972  else
12973  mincutviolation = SCIPfeastol(scip);
12974 
12975  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
12976  assert(conshdlrdata != NULL);
12977 
12978  sepasuccess = TRUE;
12979 
12980  cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, NULL);
12981  if( cutviol > 0.0 )
12982  {
12983  auxvarvalue = SCIPgetSolVal(scip, sol, auxvar);
12984 
12985  /* check whether cut is weak (if f(x) not defined, then it's never weak) */
12986  if( !allowweakcuts && auxvalue != SCIP_INVALID )
12987  {
12988  /* let the estimator be c'x-b, the auxvar is z (=auxvarvalue), and the expression is f(x) (=auxvalue)
12989  * then if we are underestimating and since the cut is violated, we should have z <= c'x-b <= f(x)
12990  * cutviol is c'x-b - z, so estimator value is c'x-b = z + cutviol
12991  * if the estimator value (c'x-b) is too close to z (auxvarvalue), when compared to f(x) (auxvalue),
12992  * then let's call this a weak cut that is, it's a weak cut if c'x-b <= z + weakcutthreshold * (f(x)-z)
12993  * <-> c'x-b - z <= weakcutthreshold * (f(x)-z)
12994  *
12995  * if we are overestimating, we have z >= c'x-b >= f(x)
12996  * cutviol is z - (c'x-b), so estimator value is c'x-b = z - cutviol
12997  * it's weak if c'x-b >= f(x) + (1-weakcutthreshold) * (z - f(x))
12998  * <-> c'x-b - z >= weakcutthreshold * (f(x)-z)
12999  *
13000  * when linearizing convex expressions, then we should have c'x-b = f(x), so they would never be weak
13001  */
13002  if( (!overestimate && ( cutviol <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13003  ( overestimate && (-cutviol >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13004  {
13005  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut is too "\
13006  "weak: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13007  SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13008  auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate); )
13009  sepasuccess = FALSE;
13010  }
13011  }
13012 
13013  /* save estimator value for later, see long comment above why this gives the value for c'x-b */
13014  estimateval = auxvarvalue + (!overestimate ? cutviol : -cutviol);
13015  }
13016  else
13017  {
13018  sepasuccess = FALSE;
13019  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded, but cut does not "\
13020  "separate\n", SCIPnlhdlrGetName(nlhdlr)); )
13021  }
13022 
13023  /* clean up estimator */
13024  if( sepasuccess )
13025  {
13026  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " estimate of nlhdlr %s succeeded: auxvarvalue %g "\
13027  "estimateval %g auxvalue %g (over %d)\n ", SCIPnlhdlrGetName(nlhdlr), auxvarvalue,
13028  auxvarvalue + (overestimate ? -cutviol : cutviol), auxvalue, overestimate);
13029  SCIPprintRowprep(scip, rowprep, enfologfile); )
13030 
13031  /* if not allowweakcuts, then do not attempt to get cuts more violated by scaling them up,
13032  * instead, may even scale them down, that is, scale so that max coef is close to 1
13033  */
13034  if( !allowweakcuts )
13035  {
13036  SCIP_CALL( SCIPcleanupRowprep2(scip, rowprep, sol, conshdlrdata->strongcutmaxcoef, &sepasuccess) );
13037 
13038  if( !sepasuccess )
13039  {
13040  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup cut failed due to bad numerics\n"); )
13041  }
13042  else
13043  {
13044  cutviol = SCIPgetRowprepViolation(scip, rowprep, sol, &sepasuccess);
13045  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup succeeded, violation = %g and %sreliable, "\
13046  "min requ viol = %g\n", cutviol, sepasuccess ? "" : "not ", mincutviolation); )
13047  if( sepasuccess )
13048  sepasuccess = cutviol > mincutviolation;
13049  }
13050 
13051  if( sepasuccess && auxvalue != SCIP_INVALID )
13052  {
13053  /* check whether cut is weak now
13054  * auxvar z may now have a coefficient due to scaling (down) in cleanup - take this into account when
13055  * reconstructing estimateval from cutviol (TODO improve or remove?)
13056  */
13057  SCIP_Real auxvarcoef = 0.0;
13058  int i;
13059 
13060  /* get absolute value of coef of auxvar in row - this makes the whole check here more expensive than
13061  * it should be...
13062  */
13063  for( i = 0; i < SCIProwprepGetNVars(rowprep); ++i )
13064  {
13065  if( SCIProwprepGetVars(rowprep)[i] == auxvar )
13066  {
13067  auxvarcoef = REALABS(SCIProwprepGetCoefs(rowprep)[i]);
13068  break;
13069  }
13070  }
13071 
13072  if( auxvarcoef == 0.0 ||
13073  (!overestimate && ( cutviol / auxvarcoef <= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) ||
13074  ( overestimate && (-cutviol / auxvarcoef >= conshdlrdata->weakcutthreshold * (auxvalue - auxvarvalue))) )
13075  {
13076  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut is too weak after cleanup: auxvarvalue %g estimateval %g auxvalue %g (over %d)\n",
13077  auxvarvalue, auxvarvalue + (overestimate ? -cutviol : cutviol) / auxvarcoef, auxvalue, overestimate); )
13078  sepasuccess = FALSE;
13079  }
13080  }
13081  }
13082  else
13083  {
13084  /* TODO if violations are really tiny, then maybe handle special (decrease LP feastol, for example) */
13085 
13086  /* if estimate didn't report branchscores explicitly, then consider branching on those children for
13087  * which the following cleanup changes coefficients (we had/have this in expr_sum this way)
13088  */
13089  if( !branchscoresuccess )
13091 
13092  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, mincutviolation, &cutviol, &sepasuccess) );
13093 
13094  if( !sepasuccess )
13095  {
13096  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cleanup failed, %d coefs modified, cutviol %g\n",
13097  SCIProwprepGetNModifiedVars(rowprep), cutviol); )
13098  }
13099 
13100  /* if cleanup left us with a useless cut, then consider branching on variables for which coef were
13101  * changed
13102  */
13103  if( !sepasuccess && !branchscoresuccess && SCIProwprepGetNModifiedVars(rowprep) > 0 )
13104  {
13105  SCIP_Real violscore;
13106 
13107 #ifdef BRSCORE_ABSVIOL
13108  violscore = getExprAbsAuxViolation(scip, expr, auxvalue, sol, NULL, NULL);
13109 #else
13110  SCIP_CALL( SCIPgetExprRelAuxViolationNonlinear(scip, expr, auxvalue, sol, &violscore, NULL, NULL) );
13111 #endif
13112  SCIP_CALL( addExprViolScoresAuxVars(scip, expr, violscore, SCIProwprepGetModifiedVars(rowprep), SCIProwprepGetNModifiedVars(rowprep), sol, &branchscoresuccess) );
13113 
13114  /* addConsExprExprBranchScoresAuxVars can fail if the only vars for which the coef was changed
13115  * - were fixed,
13116  * - are this expr's auxvar (I don't think it makes sense to branch on that one (would it?)), or
13117  * - if a variable in the rowprep is not in expr (can happen with indicator added by perspective)
13118  * the first case came up again in #3085 and I don't see how to exclude this in the assert,
13119  * so I'm disabling the assert for now
13120  */
13121  /* assert(branchscoresuccess || (rowprep->nmodifiedvars == 1 && rowprep->modifiedvars[0] == auxvar) ||
13122  strcmp(SCIPnlhdlrGetName(nlhdlr), "perspective")==0); */
13123  }
13124  }
13125  }
13126 
13127  /* if cut looks good (numerics ok and cutting off solution), then turn into row and add to sepastore */
13128  if( sepasuccess )
13129  {
13130  SCIP_ROW* row;
13131 
13132  if( conshdlrdata->branchdualweight > 0.0 )
13133  {
13134  /* store remaining gap |f(x)-estimateval| in row name, which could be used in getDualBranchscore
13135  * skip if gap is zero
13136  */
13137  if( auxvalue == SCIP_INVALID )
13138  strcat(SCIProwprepGetName(rowprep), "_estimategap=inf");
13139  else if( !SCIPisEQ(scip, auxvalue, estimateval) )
13140  {
13141  char gap[40];
13142  /* coverity[secure_coding] */
13143  (void) sprintf(gap, "_estimategap=%g", REALABS(auxvalue - estimateval));
13144  strcat(SCIProwprepGetName(rowprep), gap);
13145  }
13146  }
13147 
13148  SCIP_CALL( SCIPgetRowprepRowCons(scip, &row, rowprep, cons) );
13149 
13150  if( !allowweakcuts && conshdlrdata->strongcutefficacy && !SCIPisCutEfficacious(scip, sol, row) )
13151  {
13152  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut efficacy %g is too low (minefficacy=%g)\n",
13153  SCIPgetCutEfficacy(scip, sol, row), SCIPgetSepaMinEfficacy(scip)); )
13154  }
13155  else if( !SCIPisCutApplicable(scip, row) )
13156  {
13157  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " cut not applicable (e.g., cut is boundchange below eps)\n"); )
13158  }
13159  else
13160  {
13161  SCIP_Bool infeasible;
13162 
13163  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " adding cut ");
13164  SCIP_CALL( SCIPprintRow(scip, row, enfologfile) ); )
13165 
13166  /* I take !allowweakcuts as equivalent for having a strong cut (we usually have allowweakcuts=TRUE only
13167  * if we haven't found strong cuts before)
13168  */
13169  SCIP_CALL( SCIPaddRow(scip, row, conshdlrdata->forcestrongcut && !allowweakcuts && inenforcement, &infeasible) );
13170 
13171  /* mark row as not removable from LP for current node (this can prevent some cycling) */
13172  if( conshdlrdata->rownotremovable == 'a' || (conshdlrdata->rownotremovable == 'e' && inenforcement) )
13173  SCIPmarkRowNotRemovableLocal(scip, row);
13174 
13175  if( infeasible )
13176  {
13177  *result = SCIP_CUTOFF;
13179  }
13180  else
13181  {
13182  *result = SCIP_SEPARATED;
13184  }
13185  }
13186 
13187  SCIP_CALL( SCIPreleaseRow(scip, &row) );
13188  }
13189  else if( branchscoresuccess )
13190  {
13191  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed, but "\
13192  "branching candidates added\n", SCIPnlhdlrGetName(nlhdlr)); )
13193 
13194  /* well, not branched, but addConsExprExprViolScoresAuxVars() added scores to (aux)variables and that makes the
13195  * expressions eligible for branching candidate, see enforceConstraints() and branching()
13196  */
13197  *result = SCIP_BRANCHED;
13198  }
13199  else
13200  {
13201  ENFOLOG( SCIPinfoMessage(scip, enfologfile, " separation with estimate of nlhdlr %s failed and no "\
13202  "branching candidates%s\n", SCIPnlhdlrGetName(nlhdlr), (allowweakcuts && inenforcement) ?
13203  " (!)" : ""); )
13204  }
13205 
13206  return SCIP_OKAY;
13207 }
13208 
13209 /** returns whether all nonlinear constraints are assumed to be convex */
13211  SCIP_CONSHDLR* conshdlr
13212  )
13213 {
13214  SCIP_CONSHDLRDATA* conshdlrdata;
13215 
13216  assert(conshdlr != NULL);
13217 
13218  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13219  assert(conshdlrdata != NULL);
13220 
13221  return conshdlrdata->assumeconvex;
13222 }
13223 
13224 /** collects all bilinear terms for a given set of constraints
13225  *
13226  * @attention This method should only be used for unit tests that depend on SCIPgetBilinTermsNonlinear(),
13227  * SCIPgetBilinTermNonlinear() or SCIPgetBilinTermIdxNonlinear().
13228  */
13230  SCIP* scip, /**< SCIP data structure */
13231  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13232  SCIP_CONS** conss, /**< nonlinear constraints */
13233  int nconss /**< total number of nonlinear constraints */
13234  )
13235 {
13236  assert(conshdlr != NULL);
13237  assert(conss != NULL || nconss == 0);
13238 
13239  SCIP_CALL( bilinearTermsInsertAll(scip, conshdlr, conss, nconss) );
13240 
13241  return SCIP_OKAY;
13242 }
13243 
13244 /** returns the total number of bilinear terms that are contained in all nonlinear constraints
13245  *
13246  * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13247  */
13249  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13250  )
13251 {
13252  SCIP_CONSHDLRDATA* conshdlrdata;
13253 
13254  assert(conshdlr != NULL);
13255 
13256  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13257  assert(conshdlrdata != NULL);
13258 
13259  return conshdlrdata->nbilinterms;
13260 }
13261 
13262 /** returns all bilinear terms that are contained in all nonlinear constraints
13263  *
13264  * @note This method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13265  * @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.
13266  */
13268  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
13269  )
13270 {
13271  SCIP_CONSHDLRDATA* conshdlrdata;
13272 
13273  assert(conshdlr != NULL);
13274 
13275  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13276  assert(conshdlrdata != NULL);
13277 
13278  return conshdlrdata->bilinterms;
13279 }
13280 
13281 /** returns the index of the bilinear term representing the product of the two given variables
13282  *
13283  * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13284  * @return The method returns -1 if the variables do not appear bilinearly.
13285  */
13287  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13288  SCIP_VAR* x, /**< first variable */
13289  SCIP_VAR* y /**< second variable */
13290  )
13291 {
13292  SCIP_CONSHDLRDATA* conshdlrdata;
13294  int idx;
13295 
13296  assert(conshdlr != NULL);
13297  assert(x != NULL);
13298  assert(y != NULL);
13299 
13300  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13301  assert(conshdlrdata != NULL);
13302 
13303  if( conshdlrdata->bilinhashtable == NULL )
13304  {
13305  return -1;
13306  }
13307 
13308  /* ensure that x.index <= y.index */
13309  if( SCIPvarCompare(x, y) == 1 )
13310  {
13311  SCIPswapPointers((void**)&x, (void**)&y);
13312  }
13313  assert(SCIPvarCompare(x, y) < 1);
13314 
13315  /* use a new entry to find the image in the bilinear hash table */
13316  entry.x = x;
13317  entry.y = y;
13318  idx = (int)(size_t)SCIPhashtableRetrieve(conshdlrdata->bilinhashtable, (void*)&entry) - 1;
13319  assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13320  assert(idx < 0 || conshdlrdata->bilinterms[idx].x == x);
13321  assert(idx < 0 || conshdlrdata->bilinterms[idx].y == y);
13322 
13323  return idx;
13324 }
13325 
13326 /** returns the bilinear term that represents the product of two given variables
13327  *
13328  * @note The method should only be used after auxiliary variables have been created, i.e., after CONSINITLP.
13329  * @return The method returns NULL if the variables do not appear bilinearly.
13330  */
13332  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13333  SCIP_VAR* x, /**< first variable */
13334  SCIP_VAR* y /**< second variable */
13335  )
13336 {
13337  SCIP_CONSHDLRDATA* conshdlrdata;
13338  int idx;
13339 
13340  assert(conshdlr != NULL);
13341  assert(x != NULL);
13342  assert(y != NULL);
13343 
13344  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13345  assert(conshdlrdata != NULL);
13346 
13347  idx = SCIPgetBilinTermIdxNonlinear(conshdlr, x, y);
13348  assert(idx >= -1 && idx < conshdlrdata->nbilinterms);
13349 
13350  if( idx >= 0 )
13351  {
13352  return &conshdlrdata->bilinterms[idx];
13353  }
13354 
13355  return NULL;
13356 }
13357 
13358 /** evaluates an auxiliary expression for a bilinear term */
13360  SCIP* scip, /**< SCIP data structure */
13361  SCIP_VAR* x, /**< first variable of the bilinear term */
13362  SCIP_VAR* y, /**< second variable of the bilinear term */
13363  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr, /**< auxiliary expression */
13364  SCIP_SOL* sol /**< solution at which to evaluate (can be NULL) */
13365  )
13366 {
13367  assert(scip != NULL);
13368  assert(x != NULL);
13369  assert(y != NULL);
13370  assert(auxexpr != NULL);
13371  assert(auxexpr->auxvar != NULL);
13372 
13373  return auxexpr->cst + auxexpr->coefs[0] * SCIPgetSolVal(scip, sol, auxexpr->auxvar) +
13374  auxexpr->coefs[1] * SCIPgetSolVal(scip, sol, x) + auxexpr->coefs[2] * SCIPgetSolVal(scip, sol, y);
13375 }
13376 
13377 /** stores the variables of a bilinear term in the data of the constraint handler */
13379  SCIP* scip, /**< SCIP data structure */
13380  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13381  SCIP_VAR* x, /**< first variable */
13382  SCIP_VAR* y, /**< second variable */
13383  SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13384  int nlockspos, /**< number of positive expression locks */
13385  int nlocksneg /**< number of negative expression locks */
13386  )
13387 {
13388  SCIP_CONSHDLRDATA* conshdlrdata;
13390  int idx;
13391 
13392  assert(conshdlr != NULL);
13393 
13394  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13395  assert(conshdlrdata != NULL);
13396 
13397  SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, TRUE) );
13398 
13399  term = &conshdlrdata->bilinterms[idx];
13400  assert(term != NULL);
13401  assert(term->nauxexprs == 0); /* existing terms should be added before implicit terms */
13402  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) */
13403 
13404  /* store and capture auxiliary variable */
13405  if( auxvar != NULL )
13406  {
13407  term->aux.var = auxvar;
13408  SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13409  }
13410 
13411  return SCIP_OKAY;
13412 }
13413 
13414 /** stores the variables of a bilinear term in the data of the constraint handler */
13416  SCIP* scip, /**< SCIP data structure */
13417  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
13418  SCIP_VAR* x, /**< first variable */
13419  SCIP_VAR* y, /**< second variable */
13420  SCIP_VAR* auxvar, /**< auxiliary variable (might be NULL) */
13421  SCIP_Real coefx, /**< coefficient of x in the auxiliary expression */
13422  SCIP_Real coefy, /**< coefficient of y in the auxiliary expression */
13423  SCIP_Real coefaux, /**< coefficient of auxvar in the auxiliary expression */
13424  SCIP_Real cst, /**< constant of the auxiliary expression */
13425  SCIP_Bool overestimate /**< whether the auxiliary expression overestimates the bilinear product */
13426  )
13427 {
13428  SCIP_CONSHDLRDATA* conshdlrdata;
13430  SCIP_CONSNONLINEAR_AUXEXPR* auxexpr;
13431  int idx;
13432  int nlockspos;
13433  int nlocksneg;
13434  SCIP_Bool added;
13435 
13436  assert(conshdlr != NULL);
13437 
13438  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13439  assert(conshdlrdata != NULL);
13440 
13441  nlockspos = overestimate ? 1 : 0;
13442  nlocksneg = overestimate ? 0 : 1;
13443 
13444  SCIP_CALL( bilinearTermsInsertEntry(scip, conshdlr, x, y, nlockspos, nlocksneg, &idx, FALSE) );
13445 
13446  term = &conshdlrdata->bilinterms[idx];
13447  assert(term != NULL);
13448  assert(SCIPvarCompare(term->x, term->y) < 1);
13449 
13450  if( term->existing && term->nauxexprs == 0 && term->aux.var != NULL )
13451  {
13452  SCIP_CONSNONLINEAR_AUXEXPR* auxvarexpr;
13453  /* this is the case where we are adding an implicitly defined relation for a product that has already
13454  * been explicitly defined; convert auxvar into an auxexpr */
13455 
13456  /* nothing to do if we aren't allowed to add more than one auxexpr per term */
13457  if( conshdlrdata->bilinmaxnauxexprs <= 1 )
13458  return SCIP_OKAY;
13459 
13460  SCIP_CALL( SCIPallocBlockMemory(scip, &auxvarexpr) );
13461  auxvarexpr->cst = 0.0;
13462  auxvarexpr->coefs[0] = 1.0;
13463  auxvarexpr->coefs[1] = 0.0;
13464  auxvarexpr->coefs[2] = 0.0;
13465  auxvarexpr->auxvar = term->aux.var;
13466  auxvarexpr->underestimate = term->nlocksneg > 0;
13467  auxvarexpr->overestimate = term->nlockspos > 0;
13468 
13469  /* before we were working with term->aux.var; now aux.var has been saved and aux.exprs can be initialised to NULL */
13470  term->aux.exprs = NULL;
13471 
13472  SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxvarexpr, &added) );
13473 
13474  /* since there were no auxexprs before and we've already checked for bilinmaxnauxexprs, auxvarexpr should always be added */
13475  assert(added);
13476  }
13477 
13478  /* create and add auxexpr */
13479  SCIP_CALL( SCIPallocBlockMemory(scip, &auxexpr) );
13480  auxexpr->underestimate = !overestimate;
13481  auxexpr->overestimate = overestimate;
13482  auxexpr->auxvar = auxvar;
13483  auxexpr->coefs[0] = coefaux;
13484  if( term->x == x )
13485  {
13486  assert(term->y == y);
13487  auxexpr->coefs[1] = coefx;
13488  auxexpr->coefs[2] = coefy;
13489  }
13490  else
13491  {
13492  assert(term->x == y);
13493  assert(term->y == x);
13494  auxexpr->coefs[1] = coefy;
13495  auxexpr->coefs[2] = coefx;
13496  }
13497  auxexpr->cst = cst;
13498  SCIP_CALL( bilinTermAddAuxExpr(scip, conshdlrdata, term, auxexpr, &added) );
13499 
13500  if( !added )
13501  {
13502  SCIPfreeBlockMemory(scip, &auxexpr);
13503  }
13504  else if( auxvar != NULL )
13505  { /* capture auxiliary variable */
13506  SCIP_CALL( SCIPcaptureVar(scip, auxvar) );
13507  }
13508 
13509  return SCIP_OKAY;
13510 }
13511 
13512 /* replication of long comment on SCIPcomputeFacetVertexPolyhedralNonlinear() in cons_nonlinear.h omitted here */
13514  SCIP* scip, /**< SCIP data structure */
13515  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
13516  SCIP_Bool overestimate, /**< whether to compute facet of concave (TRUE) or convex (FALSE) envelope */
13517  SCIP_DECL_VERTEXPOLYFUN((*function)), /**< pointer to vertex polyhedral function */
13518  void* fundata, /**< data for function evaluation (can be NULL) */
13519  SCIP_Real* xstar, /**< point to be separated */
13520  SCIP_Real* box, /**< box where to compute facet: should be lb_1, ub_1, lb_2, ub_2... */
13521  int nallvars, /**< half of the length of box */
13522  SCIP_Real targetvalue, /**< target value: no need to compute facet if value in xstar would be worse than this value */
13523  SCIP_Bool* success, /**< buffer to store whether a facet could be computed successfully */
13524  SCIP_Real* facetcoefs, /**< buffer to store coefficients of facet defining inequality; must be an array of length at least nallvars */
13525  SCIP_Real* facetconstant /**< buffer to store constant part of facet defining inequality */
13526  )
13527 {
13528  SCIP_Real* corner;
13529  SCIP_Real* funvals;
13530  int* nonfixedpos;
13531  SCIP_Real maxfaceterror;
13532  int nvars; /* number of nonfixed variables */
13533  unsigned int ncorners;
13534  unsigned int i;
13535  int j;
13536 
13537  assert(scip != NULL);
13538  assert(conshdlr != NULL);
13539  assert(function != NULL);
13540  assert(xstar != NULL);
13541  assert(box != NULL);
13542  assert(success != NULL);
13543  assert(facetcoefs != NULL);
13544  assert(facetconstant != NULL);
13545 
13546  *success = FALSE;
13547 
13548  /* identify fixed variables */
13549  SCIP_CALL( SCIPallocBufferArray(scip, &nonfixedpos, nallvars) );
13550  nvars = 0;
13551  for( j = 0; j < nallvars; ++j )
13552  {
13553  if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13554  continue;
13555  nonfixedpos[nvars] = j;
13556  nvars++;
13557  }
13558 
13559  /* if all variables are fixed, then we could provide something trivial, but that wouldn't be the job of separation
13560  * if too many variables are not fixed, then we do nothing currently
13561  */
13562  if( nvars == 0 || nvars > SCIP_MAXVERTEXPOLYDIM )
13563  {
13564  SCIPwarningMessage(scip, "SCIPcomputeFacetVertexPolyhedralNonlinear() called with %d nonfixed variables. Must be between [1,%d].\n", nvars, SCIP_MAXVERTEXPOLYDIM);
13565  SCIPfreeBufferArray(scip, &nonfixedpos);
13566  return SCIP_OKAY;
13567  }
13568 
13569  /* compute f(v^i) for each corner v^i of [l,u] */
13570  ncorners = POWEROFTWO(nvars);
13571  SCIP_CALL( SCIPallocBufferArray(scip, &funvals, ncorners) );
13572  SCIP_CALL( SCIPallocBufferArray(scip, &corner, nallvars) );
13573  for( j = 0; j < nallvars; ++j )
13574  {
13575  if( SCIPisRelEQ(scip, box[2 * j], box[2 * j + 1]) )
13576  corner[j] = (box[2 * j] + box[2 * j + 1]) / 2.0;
13577  }
13578  for( i = 0; i < ncorners; ++i )
13579  {
13580  SCIPdebugMsg(scip, "corner %u: ", i);
13581  for( j = 0; j < nvars; ++j )
13582  {
13583  int varpos = nonfixedpos[j];
13584  /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
13585  * we check this by shifting i for j positions to the right and checking whether the last bit is set
13586  */
13587  if( (i >> j) & 0x1 )
13588  corner[varpos] = box[2 * varpos + 1]; /* ub of var */
13589  else
13590  corner[varpos] = box[2 * varpos ]; /* lb of var */
13591  SCIPdebugMsgPrint(scip, "%g, ", corner[varpos]);
13592  assert(!SCIPisInfinity(scip, REALABS(corner[varpos])));
13593  }
13594 
13595  funvals[i] = function(corner, nallvars, fundata);
13596 
13597  SCIPdebugMsgPrint(scip, "obj = %e\n", funvals[i]);
13598 
13599  if( funvals[i] == SCIP_INVALID || SCIPisInfinity(scip, REALABS(funvals[i])) )
13600  {
13601  SCIPdebugMsg(scip, "cannot compute underestimator; function value at corner is too large %g\n", funvals[i]);
13602  goto CLEANUP;
13603  }
13604  }
13605 
13606  /* clear coefs array; below we only fill in coefs for nonfixed variables */
13607  BMSclearMemoryArray(facetcoefs, nallvars);
13608 
13609  if( nvars == 1 )
13610  {
13611  SCIP_CALL( computeVertexPolyhedralFacetUnivariate(scip, box[2 * nonfixedpos[0]], box[2 * nonfixedpos[0] + 1], funvals[0], funvals[1], success, &facetcoefs[nonfixedpos[0]], facetconstant) );
13612 
13613  /* check whether target has been missed */
13614  if( *success && overestimate == (*facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]] > targetvalue) )
13615  {
13616  SCIPdebugMsg(scip, "computed secant, but missed target %g (facetvalue=%g, overestimate=%u)\n", targetvalue, *facetconstant + facetcoefs[nonfixedpos[0]] * xstar[nonfixedpos[0]], overestimate);
13617  *success = FALSE;
13618  }
13619  }
13620  else if( nvars == 2 && SCIPlapackIsAvailable() )
13621  {
13622  int idx1 = nonfixedpos[0];
13623  int idx2 = nonfixedpos[1];
13624  SCIP_Real p1[2] = { box[2*idx1], box[2*idx2] }; /* corner 0: 0>>0 & 0x1 = 0, 0>>1 & 0x1 = 0 */
13625  SCIP_Real p2[2] = { box[2*idx1+1], box[2*idx2] }; /* corner 1: 1>>0 & 0x1 = 1, 1>>1 & 0x1 = 0 */
13626  SCIP_Real p3[2] = { box[2*idx1], box[2*idx2+1] }; /* corner 2: 2>>0 & 0x1 = 0, 2>>1 & 0x1 = 1 */
13627  SCIP_Real p4[2] = { box[2*idx1+1], box[2*idx2+1] }; /* corner 3: 3>>0 & 0x1 = 1, 3>>1 & 0x1 = 1 */
13628  SCIP_Real xstar2[2] = { xstar[idx1], xstar[idx2] };
13629  SCIP_Real coefs[2] = { 0.0, 0.0 };
13630 
13631  SCIP_CALL( computeVertexPolyhedralFacetBivariate(scip, overestimate, p1, p2, p3, p4, funvals[0], funvals[1], funvals[2], funvals[3], xstar2, targetvalue, success, coefs, facetconstant) );
13632 
13633  facetcoefs[idx1] = coefs[0];
13634  facetcoefs[idx2] = coefs[1];
13635  }
13636  else
13637  {
13638  SCIP_CALL( computeVertexPolyhedralFacetLP(scip, conshdlr, overestimate, xstar, box, nallvars, nonfixedpos, funvals, nvars, targetvalue, success, facetcoefs, facetconstant) );
13639  }
13640  if( !*success )
13641  {
13642  SCIPdebugMsg(scip, "no success computing facet, %d vars\n", nvars);
13643  goto CLEANUP;
13644  }
13645 
13646  /*
13647  * check and adjust facet with the algorithm of Rikun et al.
13648  */
13649 
13650  maxfaceterror = computeVertexPolyhedralMaxFacetError(scip, overestimate, funvals, box, nallvars, nvars, nonfixedpos, facetcoefs, *facetconstant);
13651 
13652  /* adjust constant part of the facet by maxerror to make it a valid over/underestimator (not facet though) */
13653  if( maxfaceterror > 0.0 )
13654  {
13655  SCIP_CONSHDLRDATA* conshdlrdata;
13656  SCIP_Real midval;
13657  SCIP_Real feastol;
13658 
13659  feastol = SCIPgetStage(scip) == SCIP_STAGE_SOLVING ? SCIPgetLPFeastol(scip) : SCIPfeastol(scip);
13660 
13661  /* evaluate function in middle point to get some idea for a scaling */
13662  for( j = 0; j < nvars; ++j )
13663  corner[nonfixedpos[j]] = (box[2 * nonfixedpos[j]] + box[2 * nonfixedpos[j] + 1]) / 2.0;
13664  midval = function(corner, nallvars, fundata);
13665  if( midval == SCIP_INVALID )
13666  midval = 1.0;
13667 
13668  conshdlrdata = SCIPconshdlrGetData(conshdlr);
13669  assert(conshdlrdata != NULL);
13670 
13671  /* there seem to be numerical problems if the error is too large; in this case we reject the facet */
13672  if( maxfaceterror > conshdlrdata->vp_adjfacetthreshold * feastol * fabs(midval) )
13673  {
13674  SCIPdebugMsg(scip, "ignoring facet due to instability, it cuts off a vertex by %g (midval=%g).\n", maxfaceterror, midval);
13675  *success = FALSE;
13676  goto CLEANUP;
13677  }
13678 
13679  SCIPdebugMsg(scip, "maximum facet error %g (midval=%g), adjust constant to make cut valid!\n", maxfaceterror, midval);
13680 
13681  if( overestimate )
13682  *facetconstant += maxfaceterror;
13683  else
13684  *facetconstant -= maxfaceterror;
13685  }
13686 
13687  /* if we made it until here, then we have a nice facet */
13688  assert(*success);
13689 
13690 CLEANUP:
13691  /* free allocated memory */
13692  SCIPfreeBufferArray(scip, &corner);
13693  SCIPfreeBufferArray(scip, &funvals);
13694  SCIPfreeBufferArray(scip, &nonfixedpos);
13695 
13696  return SCIP_OKAY;
13697 }
13698 
13699 /*
13700  * constraint specific interface methods
13701  */
13702 
13703 /** returns the expression of the given nonlinear constraint */
13705  SCIP_CONS* cons /**< constraint data */
13706  )
13707 {
13708  SCIP_CONSDATA* consdata;
13709 
13710  assert(cons != NULL);
13711  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13712 
13713  consdata = SCIPconsGetData(cons);
13714  assert(consdata != NULL);
13715 
13716  return consdata->expr;
13717 }
13718 
13719 /** gets the left hand side of a nonlinear constraint */
13721  SCIP_CONS* cons /**< constraint data */
13722  )
13723 {
13724  SCIP_CONSDATA* consdata;
13725 
13726  assert(cons != NULL);
13727  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13728 
13729  consdata = SCIPconsGetData(cons);
13730  assert(consdata != NULL);
13731 
13732  return consdata->lhs;
13733 }
13734 
13735 /** gets the right hand side of a nonlinear constraint */
13737  SCIP_CONS* cons /**< constraint data */
13738  )
13739 {
13740  SCIP_CONSDATA* consdata;
13741 
13742  assert(cons != NULL);
13743  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13744 
13745  consdata = SCIPconsGetData(cons);
13746  assert(consdata != NULL);
13747 
13748  return consdata->rhs;
13749 }
13750 
13751 /** gets the nonlinear constraint as a nonlinear row representation. */
13753  SCIP* scip, /**< SCIP data structure */
13754  SCIP_CONS* cons, /**< constraint */
13755  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
13756  )
13757 {
13758  SCIP_CONSDATA* consdata;
13759 
13760  assert(cons != NULL);
13761  assert(nlrow != NULL);
13762  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13763 
13764  consdata = SCIPconsGetData(cons);
13765  assert(consdata != NULL);
13766 
13767  if( consdata->nlrow == NULL )
13768  {
13769  SCIP_CALL( createNlRow(scip, cons) );
13770  }
13771  assert(consdata->nlrow != NULL);
13772  *nlrow = consdata->nlrow;
13773 
13774  return SCIP_OKAY;
13775 }
13776 
13777 /** returns the curvature of the expression of a given nonlinear constraint
13778  *
13779  * @note The curvature information is computed during CONSINITSOL.
13780  */
13782  SCIP_CONS* cons /**< constraint data */
13783  )
13784 {
13785  SCIP_CONSDATA* consdata;
13786 
13787  assert(cons != NULL);
13788  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13789 
13790  consdata = SCIPconsGetData(cons);
13791  assert(consdata != NULL);
13792 
13793  return consdata->curv;
13794 }
13795 
13796 /** checks whether expression of constraint can be represented as quadratic form
13797  *
13798  * Only sets `*isquadratic` to TRUE if the whole expression is quadratic (in the non-extended formulation) and non-linear.
13799  * That is, the expression in each \ref SCIP_QUADEXPR_QUADTERM will be a variable expressions and
13800  * \ref SCIPgetVarExprVar() can be used to retrieve the variable.
13801  */
13803  SCIP* scip, /**< SCIP data structure */
13804  SCIP_CONS* cons, /**< constraint data */
13805  SCIP_Bool* isquadratic /**< buffer to store whether constraint is quadratic */
13806  )
13807 {
13808  SCIP_CONSDATA* consdata;
13809 
13810  assert(scip != NULL);
13811  assert(cons != NULL);
13812  assert(isquadratic != NULL);
13813  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13814 
13815  consdata = SCIPconsGetData(cons);
13816  assert(consdata != NULL);
13817  assert(consdata->expr != NULL);
13818 
13819  /* check whether constraint expression is quadratic in extended formulation */
13820  SCIP_CALL( SCIPcheckExprQuadratic(scip, consdata->expr, isquadratic) );
13821 
13822  /* if not quadratic in non-extended formulation, then do indicate quadratic */
13823  if( *isquadratic )
13824  *isquadratic = SCIPexprAreQuadraticExprsVariables(consdata->expr);
13825 
13826  return SCIP_OKAY;
13827 }
13828 
13829 /** changes left-hand-side of a nonlinear constraint
13830  *
13831  * @attention This method can only be called in the problem stage.
13832  */
13834  SCIP* scip, /**< SCIP data structure */
13835  SCIP_CONS* cons, /**< constraint data */
13836  SCIP_Real lhs /**< new left-hand-side */
13837  )
13838 {
13839  SCIP_CONSDATA* consdata;
13840 
13841  assert(scip != NULL);
13842  assert(cons != NULL);
13843  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13844 
13845  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13846  {
13847  SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13848  return SCIP_INVALIDCALL;
13849  }
13850 
13851  /* we should have an original constraint */
13852  assert(SCIPconsIsOriginal(cons));
13853 
13854  consdata = SCIPconsGetData(cons);
13855  assert(consdata != NULL);
13856 
13857  if( consdata->lhs == lhs )
13858  return SCIP_OKAY;
13859 
13860  consdata->lhs = lhs;
13861 
13862  /* not sure we care about any of these flags for original constraints */
13863  consdata->ispropagated = FALSE;
13864 
13865  return SCIP_OKAY;
13866 }
13867 
13868 /** changes right-hand-side of a nonlinear constraint
13869  *
13870  * @attention This method can only be called in the problem stage.
13871  */
13873  SCIP* scip, /**< SCIP data structure */
13874  SCIP_CONS* cons, /**< constraint data */
13875  SCIP_Real rhs /**< new right-hand-side */
13876  )
13877 {
13878  SCIP_CONSDATA* consdata;
13879 
13880  assert(scip != NULL);
13881  assert(cons != NULL);
13882  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
13883 
13884  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13885  {
13886  SCIPerrorMessage("SCIPchgLhsNonlinear can only be called in problem stage.\n");
13887  return SCIP_INVALIDCALL;
13888  }
13889 
13890  /* we should have an original constraint */
13891  assert(SCIPconsIsOriginal(cons));
13892 
13893  consdata = SCIPconsGetData(cons);
13894  assert(consdata != NULL);
13895 
13896  if( consdata->rhs == rhs )
13897  return SCIP_OKAY;
13898 
13899  consdata->rhs = rhs;
13900 
13901  /* not sure we care about any of these flags for original constraints */
13902  consdata->ispropagated = FALSE;
13903 
13904  return SCIP_OKAY;
13905 }
13906 
13907 /** changes expression of a nonlinear constraint
13908  *
13909  * @attention This method can only be called in the problem stage.
13910  */
13912  SCIP* scip, /**< SCIP data structure */
13913  SCIP_CONS* cons, /**< constraint data */
13914  SCIP_EXPR* expr /**< new expression */
13915  )
13916 {
13917  SCIP_CONSHDLR* conshdlr;
13918  SCIP_CONSDATA* consdata;
13919 
13920  assert(scip != NULL);
13921  assert(cons != NULL);
13922  assert(expr != NULL);
13923 
13924  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13925  {
13926  SCIPerrorMessage("SCIPchgExprNonlinear can only be called in problem stage.\n");
13927  return SCIP_INVALIDCALL;
13928  }
13929 
13930  /* we should have an original constraint */
13931  assert(SCIPconsIsOriginal(cons));
13932 
13933  conshdlr = SCIPconsGetHdlr(cons);
13934  assert(conshdlr != NULL);
13935  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13936 
13937  consdata = SCIPconsGetData(cons);
13938  assert(consdata != NULL);
13939  assert(consdata->expr != NULL);
13940 
13941  /* we should not have collected additional data for the expr
13942  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
13943  */
13944  assert(consdata->nvarexprs == 0);
13945  assert(consdata->varexprs == NULL);
13946  assert(!consdata->catchedevents);
13947 
13948  SCIP_CALL( SCIPreleaseExpr(scip, &consdata->expr) );
13949 
13950  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
13951  SCIP_CALL( SCIPduplicateExpr(scip, expr, &consdata->expr, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
13952 
13953  /* not sure we care about any of these flags for original constraints */
13954  consdata->curv = SCIP_EXPRCURV_UNKNOWN;
13955  consdata->issimplified = FALSE;
13956  consdata->ispropagated = FALSE;
13957 
13958  return SCIP_OKAY;
13959 }
13960 
13961 /** adds coef * var to nonlinear constraint
13962  *
13963  * @attention This method can only be called in the problem stage.
13964  */
13966  SCIP* scip, /**< SCIP data structure */
13967  SCIP_CONS* cons, /**< constraint data */
13968  SCIP_VAR* var, /**< variable */
13969  SCIP_Real coef /**< coefficient */
13970  )
13971 {
13972  SCIP_CONSHDLR* conshdlr;
13973  SCIP_CONSDATA* consdata;
13974  SCIP_EXPR* varexpr;
13975 
13976  assert(scip != NULL);
13977  assert(cons != NULL);
13978 
13979  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
13980  {
13981  SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
13982  return SCIP_INVALIDCALL;
13983  }
13984 
13985  /* we should have an original constraint */
13986  assert(SCIPconsIsOriginal(cons));
13987 
13988  if( coef == 0.0 )
13989  return SCIP_OKAY;
13990 
13991  conshdlr = SCIPconsGetHdlr(cons);
13992  assert(conshdlr != NULL);
13993  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
13994 
13995  consdata = SCIPconsGetData(cons);
13996  assert(consdata != NULL);
13997  assert(consdata->expr != NULL);
13998 
13999  /* we should not have collected additional data for it
14000  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14001  */
14002  assert(consdata->nvarexprs == 0);
14003  assert(consdata->varexprs == NULL);
14004  assert(!consdata->catchedevents);
14005 
14006  SCIP_CALL( createExprVar(scip, conshdlr, &varexpr, var) );
14007 
14008  /* append to sum, if consdata->expr is sum and not used anywhere else */
14009  if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14010  {
14011  SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, varexpr, coef) );
14012  }
14013  else
14014  {
14015  /* create new expression = 1 * consdata->expr + coef * var */
14016  SCIP_EXPR* children[2] = { consdata->expr, varexpr };
14017  SCIP_Real coefs[2] = { 1.0, coef };
14018 
14019  SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14020 
14021  /* release old root expr */
14022  SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14023  }
14024 
14025  SCIP_CALL( SCIPreleaseExpr(scip, &varexpr) );
14026 
14027  /* not sure we care about any of these flags for original constraints */
14028  consdata->issimplified = FALSE;
14029  consdata->ispropagated = FALSE;
14030 
14031  return SCIP_OKAY;
14032 }
14033 
14034 /** adds coef * expr to nonlinear constraint
14035  *
14036  * @attention This method can only be called in the problem stage.
14037  */
14039  SCIP* scip, /**< SCIP data structure */
14040  SCIP_CONS* cons, /**< nonlinear constraint */
14041  SCIP_EXPR* expr, /**< expression */
14042  SCIP_Real coef /**< coefficient */
14043  )
14044 {
14045  SCIP_CONSHDLR* conshdlr;
14046  SCIP_CONSDATA* consdata;
14047  SCIP_EXPR* exprowned;
14048 
14049  assert(scip != NULL);
14050  assert(cons != NULL);
14051 
14052  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
14053  {
14054  SCIPerrorMessage("SCIPaddLinearVarNonlinear can only be called in problem stage.\n");
14055  return SCIP_INVALIDCALL;
14056  }
14057 
14058  /* we should have an original constraint */
14059  assert(SCIPconsIsOriginal(cons));
14060 
14061  if( coef == 0.0 )
14062  return SCIP_OKAY;
14063 
14064  conshdlr = SCIPconsGetHdlr(cons);
14065  assert(conshdlr != NULL);
14066  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
14067 
14068  consdata = SCIPconsGetData(cons);
14069  assert(consdata != NULL);
14070  assert(consdata->expr != NULL);
14071 
14072  /* we should not have collected additional data for it
14073  * if some of these asserts fail, we may have to remove it and add some code to keep information up to date
14074  */
14075  assert(consdata->nvarexprs == 0);
14076  assert(consdata->varexprs == NULL);
14077  assert(!consdata->catchedevents);
14078 
14079  /* copy expression, thereby map variables expressions to already existing variables expressions in var2expr map, or augment var2expr map */
14080  SCIP_CALL( SCIPduplicateExpr(scip, expr, &exprowned, mapexprvar, conshdlr, exprownerCreate, (void*)conshdlr) );
14081 
14082  /* append to sum, if consdata->expr is sum and not used anywhere else */
14083  if( SCIPexprGetNUses(consdata->expr) == 1 && SCIPisExprSum(scip, consdata->expr) )
14084  {
14085  SCIP_CALL( SCIPappendExprSumExpr(scip, consdata->expr, exprowned, coef) );
14086  }
14087  else
14088  {
14089  /* create new expression = 1 * consdata->expr + coef * var */
14090  SCIP_EXPR* children[2] = { consdata->expr, exprowned };
14091  SCIP_Real coefs[2] = { 1.0, coef };
14092 
14093  SCIP_CALL( SCIPcreateExprSum(scip, &consdata->expr, 2, children, coefs, 0.0, exprownerCreate, (void*)conshdlr) );
14094 
14095  /* release old root expr */
14096  SCIP_CALL( SCIPreleaseExpr(scip, &children[0]) );
14097  }
14098 
14099  SCIP_CALL( SCIPreleaseExpr(scip, &exprowned) );
14100 
14101  /* not sure we care about any of these flags for original constraints */
14102  consdata->issimplified = FALSE;
14103  consdata->ispropagated = FALSE;
14104 
14105  return SCIP_OKAY;
14106 }
14107 
14108 /** computes value of constraint expression in a given solution
14109  *
14110  * Stores value of constraint expression in sol in activity.
14111  * In case of a domain error (function cannot be evaluated in sol), activity is set to SCIP_INVALID.
14112  */
14114  SCIP* scip, /**< SCIP data structure */
14115  SCIP_CONS* cons, /**< constraint */
14116  SCIP_SOL* sol, /**< solution */
14117  SCIP_Real* activity /**< buffer to store computed activity */
14118  )
14119 {
14120  SCIP_CONSDATA* consdata;
14121 
14122  assert(cons != NULL);
14123  assert(activity != NULL);
14124 
14125  consdata = SCIPconsGetData(cons);
14126  assert(consdata != NULL);
14127 
14128  SCIP_CALL( SCIPevalExpr(scip, consdata->expr, sol, 0L) );
14129  *activity = SCIPexprGetEvalValue(consdata->expr);
14130 
14131  return SCIP_OKAY;
14132 }
14133 
14134 /** gets absolute violation of nonlinear constraint
14135  *
14136  * This function evaluates the constraints in the given solution.
14137  *
14138  * If this value is at most SCIPfeastol(), the constraint would be considered feasible.
14139  */
14141  SCIP* scip, /**< SCIP data structure */
14142  SCIP_CONS* cons, /**< constraint */
14143  SCIP_SOL* sol, /**< solution to check */
14144  SCIP_Real* viol /**< buffer to store computed violation */
14145  )
14146 {
14147  assert(cons != NULL);
14148  assert(viol != NULL);
14149 
14150  SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14151  *viol = getConsAbsViolation(cons);
14152 
14153  return SCIP_OKAY;
14154 }
14155 
14156 /** gets scaled violation of nonlinear constraint
14157  *
14158  * This function evaluates the constraints in the given solution.
14159  *
14160  * The scaling that is applied to the absolute violation of the constraint
14161  * depends on the setting of parameter constraints/nonlinear/violscale.
14162  */
14164  SCIP* scip, /**< SCIP data structure */
14165  SCIP_CONS* cons, /**< constraint */
14166  SCIP_SOL* sol, /**< solution to check */
14167  SCIP_Real* viol /**< buffer to store computed violation */
14168  )
14169 {
14170  assert(cons != NULL);
14171  assert(viol != NULL);
14172 
14173  SCIP_CALL( computeViolation(scip, cons, sol, 0L) );
14174  SCIP_CALL( getConsRelViolation(scip, cons, viol, sol, 0L) );
14175 
14176  return SCIP_OKAY;
14177 }
14178 
14179 /** returns a variable that appears linearly that may be decreased without making any other constraint infeasible */
14181  SCIP* scip, /**< SCIP data structure */
14182  SCIP_CONS* cons, /**< nonlinear constraint */
14183  SCIP_VAR** var, /**< pointer to store the variable */
14184  SCIP_Real* coef /**< pointer to store the coefficient */
14185  )
14186 {
14187  SCIP_CONSDATA* consdata;
14188 
14189  assert(cons != NULL);
14190  assert(var != NULL);
14191  assert(coef != NULL);
14192 
14193  /* check for a linear variable that can be increased or decreased without harming feasibility */
14194  findUnlockedLinearVar(scip, cons);
14195 
14196  consdata = SCIPconsGetData(cons);
14197  assert(consdata != NULL);
14198 
14199  *var = consdata->linvardecr;
14200  *coef = consdata->linvardecrcoef;
14201 }
14202 
14203 /** returns a variable that appears linearly that may be increased without making any other constraint infeasible */
14205  SCIP* scip, /**< SCIP data structure */
14206  SCIP_CONS* cons, /**< nonlinear constraint */
14207  SCIP_VAR** var, /**< pointer to store the variable */
14208  SCIP_Real* coef /**< pointer to store the coefficient */
14209  )
14210 {
14211  SCIP_CONSDATA* consdata;
14212 
14213  assert(cons != NULL);
14214  assert(var != NULL);
14215  assert(coef != NULL);
14216 
14217  /* check for a linear variable that can be increased or decreased without harming feasibility */
14218  findUnlockedLinearVar(scip, cons);
14219 
14220  consdata = SCIPconsGetData(cons);
14221  assert(consdata != NULL);
14222 
14223  *var = consdata->linvarincr;
14224  *coef = consdata->linvarincrcoef;
14225 }
14226 
14227 
14228 /*
14229  * Methods for Expressions in Nonlinear Constraints
14230  */
14231 
14232 /** returns the number of positive rounding locks of an expression */
14234  SCIP_EXPR* expr /**< expression */
14235  )
14236 {
14237  assert(expr != NULL);
14238  assert(SCIPexprGetOwnerData(expr) != NULL);
14239 
14240  return SCIPexprGetOwnerData(expr)->nlockspos;
14241 }
14242 
14243 /** returns the number of negative rounding locks of an expression */
14245  SCIP_EXPR* expr /**< expression */
14246  )
14247 {
14248  assert(expr != NULL);
14249  assert(SCIPexprGetOwnerData(expr) != NULL);
14250 
14251  return SCIPexprGetOwnerData(expr)->nlocksneg;
14252 }
14253 
14254 /** returns the variable used for linearizing a given expression (return value might be NULL)
14255  *
14256  * @note for variable expression it returns the corresponding variable
14257  */
14259  SCIP_EXPR* expr /**< expression */
14260  )
14261 {
14262  SCIP_EXPR_OWNERDATA* ownerdata;
14263 
14264  assert(expr != NULL);
14265 
14266  ownerdata = SCIPexprGetOwnerData(expr);
14267  assert(ownerdata != NULL);
14268 
14269  return ownerdata->filterpos >= -1 ? SCIPgetVarExprVar(expr) : ownerdata->auxvar;
14270 }
14271 
14272 /** returns the number of enforcements for an expression */
14274  SCIP_EXPR* expr /**< expression */
14275  )
14276 {
14277  assert(expr != NULL);
14278  assert(SCIPexprGetOwnerData(expr) != NULL);
14279 
14280  return SCIPexprGetOwnerData(expr)->nenfos;
14281 }
14282 
14283 /** returns the data for one of the enforcements of an expression */
14285  SCIP_EXPR* expr, /**< expression */
14286  int idx, /**< position of enforcement in enfos array */
14287  SCIP_NLHDLR** nlhdlr, /**< buffer to store nlhldr */
14288  SCIP_NLHDLREXPRDATA** nlhdlrexprdata, /**< buffer to store nlhdlr data for expression, or NULL */
14289  SCIP_NLHDLR_METHOD* nlhdlrparticipation, /**< buffer to store methods where nonlinear handler participates, or NULL */
14290  SCIP_Bool* sepabelowusesactivity, /**< buffer to store whether sepabelow uses activity of some expression, or NULL */
14291  SCIP_Bool* sepaaboveusesactivity, /**< buffer to store whether sepaabove uses activity of some expression, or NULL */
14292  SCIP_Real* auxvalue /**< buffer to store current auxvalue, or NULL */
14293  )
14294 {
14295  SCIP_EXPR_OWNERDATA* ownerdata;
14296 
14297  assert(expr != NULL);
14298 
14299  ownerdata = SCIPexprGetOwnerData(expr);
14300  assert(ownerdata != NULL);
14301  assert(idx >= 0);
14302  assert(idx < ownerdata->nenfos);
14303  assert(ownerdata->enfos[idx] != NULL);
14304  assert(nlhdlr != NULL);
14305 
14306  *nlhdlr = ownerdata->enfos[idx]->nlhdlr;
14307 
14308  if( nlhdlrexprdata != NULL )
14309  *nlhdlrexprdata = ownerdata->enfos[idx]->nlhdlrexprdata;
14310 
14311  if( nlhdlrparticipation != NULL )
14312  *nlhdlrparticipation = ownerdata->enfos[idx]->nlhdlrparticipation;
14313 
14314  if( sepabelowusesactivity != NULL )
14315  *sepabelowusesactivity = ownerdata->enfos[idx]->sepabelowusesactivity;
14316 
14317  if( sepaaboveusesactivity != NULL )
14318  *sepaaboveusesactivity = ownerdata->enfos[idx]->sepaaboveusesactivity;
14319 
14320  if( auxvalue != NULL )
14321  *auxvalue = ownerdata->enfos[idx]->auxvalue;
14322 }
14323 
14324 /** sets the auxiliary value of expression for one of the enforcements of an expression */
14326  SCIP_EXPR* expr, /**< expression */
14327  int idx, /**< position of enforcement in enfos array */
14328  SCIP_Real auxvalue /**< the new value of auxval */
14329  )
14330 {
14331  SCIP_EXPR_OWNERDATA* ownerdata;
14332 
14333  assert(expr != NULL);
14334 
14335  ownerdata = SCIPexprGetOwnerData(expr);
14336  assert(ownerdata != NULL);
14337 
14338  assert(idx >= 0);
14339  assert(idx < ownerdata->nenfos);
14340  assert(ownerdata->enfos[idx] != NULL);
14341 
14342  ownerdata->enfos[idx]->auxvalue = auxvalue;
14343 }
14344 
14345 /** number of nonlinear handlers whose activity computation and propagation methods depend on the activity of the expression
14346  *
14347  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14348  */
14350  SCIP_EXPR* expr /**< expression */
14351  )
14352 {
14353  assert(expr != NULL);
14354  assert(SCIPexprGetOwnerData(expr) != NULL);
14355 
14356  return SCIPexprGetOwnerData(expr)->nactivityusesprop;
14357 }
14358 
14359 /** number of nonlinear handlers whose separation methods (estimate or enforcement) depend on the activity of the expression
14360  *
14361  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14362  */
14364  SCIP_EXPR* expr /**< expression */
14365  )
14366 {
14367  assert(expr != NULL);
14368  assert(SCIPexprGetOwnerData(expr) != NULL);
14369 
14370  return SCIPexprGetOwnerData(expr)->nactivityusessepa;
14371 }
14372 
14373 /** number of nonlinear handlers whose separation methods (estimate or enforcement) use auxiliary variable of the expression
14374  *
14375  * @note This method can only be used after the detection methods of the nonlinear handlers have been called.
14376  */
14377 unsigned int SCIPgetExprNAuxvarUsesNonlinear(
14378  SCIP_EXPR* expr /**< expression */
14379  )
14380 {
14381  assert(expr != NULL);
14382  assert(SCIPexprGetOwnerData(expr) != NULL);
14383 
14384  return SCIPexprGetOwnerData(expr)->nauxvaruses;
14385 }
14386 
14387 /** method to be called by a nlhdlr during NLHDLRDETECT to notify an expression that it will be used
14388  *
14389  * - if `useauxvar` is enabled, then ensures that an auxiliary variable will be created in INITLP
14390  * - if `useactivityforprop` or `useactivityforsepa{below,above}` is enabled, then ensured that activity will be updated for `expr`
14391  * - if `useactivityforprop` is enabled, then increments the count returned by SCIPgetExprNPropUsesActivityNonlinear()
14392  * - if `useactivityforsepa{below,above}` is enabled, then increments the count returned by SCIPgetExprNSepaUsesActivityNonlinear()
14393  * and also increments this count for all variables in the expression.
14394  *
14395  * The distinction into `useactivityforprop` and `useactivityforsepa{below,above}` is to recognize variables which domain influences
14396  * under/overestimators. Domain propagation routines (like OBBT) may invest more work for these variables.
14397  * The distinction into `useactivityforsepabelow` and `useactivityforsepaabove` is to recognize whether a nlhdlr that called this method
14398  * will use activity of `expr` in enfomethod \ref SCIP_NLHDLR_METHOD_SEPABELOW or \ref SCIP_NLHDLR_METHOD_SEPAABOVE.
14399  */
14401  SCIP* scip, /**< SCIP data structure */
14402  SCIP_EXPR* expr, /**< expression */
14403  SCIP_Bool useauxvar, /**< whether an auxiliary variable will be used for estimate or cut generation */
14404  SCIP_Bool useactivityforprop, /**< whether activity of expr will be used by domain propagation or activity calculation (inteval) */
14405  SCIP_Bool useactivityforsepabelow, /**< whether activity of expr will be used by underestimation */
14406  SCIP_Bool useactivityforsepaabove /**< whether activity of expr will be used by overestimation */
14407  )
14408 {
14409  SCIP_EXPR_OWNERDATA* ownerdata;
14410 
14411  assert(expr != NULL);
14412 
14413  ownerdata = SCIPexprGetOwnerData(expr);
14414  assert(ownerdata != NULL);
14415 
14416  /* do not store auxvar request for variable expressions */
14417  if( useauxvar && SCIPisExprVar(scip, expr) )
14418  useauxvar = FALSE;
14419 
14420  if( ownerdata->nenfos >= 0 &&
14421  ( (ownerdata->nactivityusesprop == 0 && ownerdata->nactivityusessepa == 0 && (useactivityforprop || useactivityforsepabelow || useactivityforsepaabove)) ||
14422  (ownerdata->nauxvaruses == 0 && useauxvar)
14423  ) )
14424  {
14425  /* if we already have ran detect of nlhdlrs on expr (nenfos >= 0), then we need to rerun detection if
14426  * we require additional enforcement methods, that is,
14427  * - activity of expr was not used before but will be used now, or
14428  * - auxiliary variable of expr was not required before but will be used now
14429  */
14430  SCIP_CALL( freeEnfoData(scip, expr, FALSE) );
14431  }
14432 
14433  if( useauxvar )
14434  ++ownerdata->nauxvaruses;
14435 
14436  if( useactivityforprop )
14437  ++ownerdata->nactivityusesprop;
14438 
14439  if( useactivityforsepabelow || useactivityforsepaabove )
14440  ++ownerdata->nactivityusessepa;
14441 
14442  /* remember that SCIPregisterExprUsageNonlinear() has been called with useactivityforsepa{below,above}=TRUE; this
14443  * information is used in detectNlhdlr()
14444  */
14445  if( useactivityforsepabelow )
14446  SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepabelow = TRUE;
14447  if( useactivityforsepaabove )
14448  SCIPconshdlrGetData(ownerdata->conshdlr)->registerusesactivitysepaabove = TRUE;
14449 
14450  if( useactivityforprop )
14451  {
14452  /* if activity will be used for propagation, then make sure there is a valid activity
14453  * this way, we can do a reversepropcall after detectNlhdlr
14454  */
14455  SCIP_CALL( SCIPevalExprActivity(scip, expr) );
14456  }
14457 
14458  /* increase the nactivityusedsepa counter for all variables used in the given expression */
14459  if( (useactivityforsepabelow || useactivityforsepaabove) && SCIPexprGetNChildren(expr) > 0 )
14460  {
14461  SCIP_EXPRITER* it;
14462 
14463  /* create and initialize iterator */
14464  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
14466 
14467  for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14468  if( SCIPisExprVar(scip, expr) )
14469  ++SCIPexprGetOwnerData(expr)->nactivityusessepa;
14470 
14471  /* free iterator */
14472  SCIPfreeExpriter(&it);
14473  }
14474 
14475  return SCIP_OKAY;
14476 }
14477 
14478 /** computes absolute violation for auxvar relation in an expression w.r.t. original variables
14479  *
14480  * Assume the expression is f(x), where x are original (i.e., not auxiliary) variables.
14481  * Assume that f(x) is associated with auxiliary variable z.
14482  *
14483  * If there are negative locks, then returns the violation of z &le; f(x) and sets `violover` to TRUE.
14484  * If there are positive locks, then returns the violation of z &ge; f(x) and sets `violunder` to TRUE.
14485  * Of course, if there both negative and positive locks, then return the violation of z = f(x).
14486  *
14487  * If necessary, f is evaluated in the given solution. If that fails (domain error),
14488  * then `viol` is set to SCIPinfinity() and both `violover` and `violunder` are set to TRUE.
14489  */
14491  SCIP* scip, /**< SCIP data structure */
14492  SCIP_EXPR* expr, /**< expression */
14493  SCIP_SOL* sol, /**< solution */
14494  SCIP_Longint soltag, /**< tag of solution */
14495  SCIP_Real* viol, /**< buffer to store computed violation */
14496  SCIP_Bool* violunder, /**< buffer to store whether z >= f(x) is violated, or NULL */
14497  SCIP_Bool* violover /**< buffer to store whether z <= f(x) is violated, or NULL */
14498  )
14499 {
14500  assert(scip != NULL);
14501  assert(expr != NULL);
14502  assert(viol != NULL);
14503 
14504  /* make sure expression has been evaluated */
14505  SCIP_CALL( SCIPevalExpr(scip, expr, sol, soltag) );
14506 
14507  /* get violation from internal method */
14508  *viol = getExprAbsOrigViolation(scip, expr, sol, violunder, violover);
14509 
14510  return SCIP_OKAY;
14511 }
14512 
14513 /** computes absolute violation for auxvar relation in an expression w.r.t. auxiliary variables
14514  *
14515  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14516  * Assume that f(w) is associated with auxiliary variable z.
14517  *
14518  * If there are negative locks, then returns the violation of z &le; f(w) and sets `violover` to TRUE.
14519  * If there are positive locks, then returns the violation of z &ge; f(w) and sets `violunder` to TRUE.
14520  * Of course, if there both negative and positive locks, then return the violation of z = f(w).
14521  *
14522  * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14523  * both `violover` and `violunder` are set to TRUE.
14524  */
14526  SCIP* scip, /**< SCIP data structure */
14527  SCIP_EXPR* expr, /**< expression */
14528  SCIP_Real auxvalue, /**< the value of f(w) */
14529  SCIP_SOL* sol, /**< solution that has been evaluated */
14530  SCIP_Real* viol, /**< buffer to store computed violation */
14531  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14532  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14533  )
14534 {
14535  assert(scip != NULL);
14536  assert(expr != NULL);
14537  assert(viol != NULL);
14538 
14539  /* get violation from internal method */
14540  *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14541 
14542  return SCIP_OKAY;
14543 }
14544 
14545 
14546 /** computes relative violation for auxvar relation in an expression w.r.t. auxiliary variables
14547  *
14548  * Assume the expression is f(w), where w are auxiliary variables that were introduced by some nlhdlr.
14549  * Assume that f(w) is associated with auxiliary variable z.
14550  *
14551  * Taking the absolute violation from SCIPgetExprAbsAuxViolationNonlinear(), this function returns
14552  * the absolute violation divided by max(1,|f(w)|).
14553  *
14554  * If the given value of f(w) is SCIP_INVALID, then `viol` is set to SCIPinfinity() and
14555  * both `violover` and `violunder` are set to TRUE.
14556  */
14558  SCIP* scip, /**< SCIP data structure */
14559  SCIP_EXPR* expr, /**< expression */
14560  SCIP_Real auxvalue, /**< the value of f(w) */
14561  SCIP_SOL* sol, /**< solution that has been evaluated */
14562  SCIP_Real* viol, /**< buffer to store computed violation */
14563  SCIP_Bool* violunder, /**< buffer to store whether z >= f(w) is violated, or NULL */
14564  SCIP_Bool* violover /**< buffer to store whether z <= f(w) is violated, or NULL */
14565  )
14566 {
14567  assert(scip != NULL);
14568  assert(expr != NULL);
14569  assert(viol != NULL);
14570 
14571  /* get violation from internal method */
14572  *viol = getExprAbsAuxViolation(scip, expr, auxvalue, sol, violunder, violover);
14573 
14574  if( !SCIPisInfinity(scip, *viol) )
14575  {
14576  assert(auxvalue != SCIP_INVALID);
14577  /* TODO maybe we should rather use max(eps,|auxvalue|)? */
14578  *viol /= MAX(1.0, REALABS(auxvalue));
14579  }
14580 
14581  return SCIP_OKAY;
14582 }
14583 
14584 /** returns bounds on the expression
14585  *
14586  * This gives an intersection of bounds from
14587  * - activity calculation (SCIPexprGetActivity()), if valid,
14588  * - auxiliary variable, if present,
14589  * - stored by SCIPtightenExprIntervalNonlinear() during domain propagation
14590  *
14591  * @note The returned interval can be empty!
14592  */
14594  SCIP* scip, /**< SCIP data structure */
14595  SCIP_EXPR* expr /**< expression */
14596  )
14597 {
14598  SCIP_EXPR_OWNERDATA* ownerdata;
14599  SCIP_CONSHDLRDATA* conshdlrdata;
14600  SCIP_INTERVAL bounds;
14601 
14602  assert(scip != NULL);
14603  assert(expr != NULL);
14604 
14605  ownerdata = SCIPexprGetOwnerData(expr);
14606  assert(ownerdata != NULL);
14607 
14608  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14609  assert(conshdlrdata != NULL);
14610 
14611  /* SCIPdebugMsg(scip, "get bounds expr %p:", expr); */
14612 
14613  /* start with propbounds if they belong to current propagation */
14614  if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14615  {
14616  bounds = ownerdata->propbounds;
14617  /* SCIPdebugMsgPrint(scip, " propbounds [%.15g,%.15g]", ownerdata->propbounds.inf, ownerdata->propbounds.sup); */
14618  }
14619  else
14621 
14622  if( SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax )
14623  {
14624  /* apply propbounds to expr activity, but ensure it's not-empty if very close disjoint intervals */
14625  /* SCIPdebugMsgPrint(scip, " activity [%.15g,%.15g]", expr->activity.inf, expr->activity.sup); */
14626  SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), bounds);
14627  }
14628 
14629  if( ownerdata->auxvar != NULL )
14630  {
14631  /* apply auxiliary variable bounds to bounds */
14632  SCIP_INTERVAL auxvarbounds;
14633 
14634  auxvarbounds = conshdlrdata->intevalvar(scip, ownerdata->auxvar, conshdlrdata);
14635  /* SCIPdebugMsgPrint(scip, " auxvar [%.15g,%.15g]", auxvarbounds.inf, auxvarbounds.sup); */
14636  SCIPintervalIntersectEps(&bounds, SCIPepsilon(scip), bounds, auxvarbounds);
14637  }
14638 
14639  /* SCIPdebugMsgPrint(scip, " -> [%.15g,%.15g]\n", bounds.inf, bounds.sup); */
14640 
14641  return bounds;
14642 }
14643 
14644 /** informs the expression about new bounds that can be used for reverse-propagation and to tighten bounds of
14645  * corresponding (auxiliary) variable (if any)
14646  *
14647  * @attention this function should only be called during domain propagation in cons_nonlinear
14648  */
14650  SCIP* scip, /**< SCIP data structure */
14651  SCIP_EXPR* expr, /**< expression to be tightened */
14652  SCIP_INTERVAL newbounds, /**< new bounds for the expression */
14653  SCIP_Bool* cutoff, /**< buffer to store whether a cutoff was detected */
14654  int* ntightenings /**< buffer to add the total number of tightenings, or NULL */
14655  )
14656 {
14657  SCIP_EXPR_OWNERDATA* ownerdata;
14658  SCIP_CONSHDLRDATA* conshdlrdata;
14659 
14660  assert(scip != NULL);
14661  assert(expr != NULL);
14662  assert(cutoff != NULL);
14663 
14664  ownerdata = SCIPexprGetOwnerData(expr);
14665  assert(ownerdata != NULL);
14666  assert(ownerdata->conshdlr != NULL);
14667 
14668  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14669  assert(conshdlrdata != NULL);
14670 
14671  /* the code below assumes that current activity is valid
14672  * if it turns out that we cannot ensure that, then we should change code
14673  */
14674  assert(SCIPexprGetActivityTag(expr) >= conshdlrdata->lastboundrelax || SCIPintervalIsEntire(SCIP_INTERVAL_INFINITY, SCIPexprGetActivity(expr)));
14676 
14677  *cutoff = FALSE;
14678 
14679 #ifdef DEBUG_PROP
14680  SCIPdebugMsg(scip, "Trying to tighten bounds of expr ");
14681  SCIP_CALL( SCIPprintExpr(scip, expr, NULL) );
14682  SCIPdebugMsgPrint(scip, " with activity [%.15g,%.15g] to [%.15g,%.15g] (force=%d)\n", SCIPexprGetActivity(expr).inf, SCIPexprGetActivity(expr).sup, newbounds.inf, newbounds.sup, conshdlrdata->forceboundtightening);
14683 #endif
14684 
14685  if( SCIPexprIsIntegral(expr) )
14686  {
14687  /* apply integrality to new bounds
14688  * it should be ok to use normal ceil() and floor(), but for safety, we use SCIPceil and SCIPfloor for now
14689  */
14690  if( newbounds.inf > -SCIP_INTERVAL_INFINITY )
14691  newbounds.inf = SCIPceil(scip, newbounds.inf);
14692  if( newbounds.sup < SCIP_INTERVAL_INFINITY )
14693  newbounds.sup = SCIPfloor(scip, newbounds.sup);
14694 #ifdef DEBUG_PROP
14695  SCIPdebugMsg(scip, " applied integrality: [%.15g,%.15g]\n", newbounds.inf, newbounds.sup);
14696 #endif
14697  }
14698 
14700  {
14701  SCIPdebugMsg(scip, " cut off due to new bounds being empty\n");
14702 
14703  *cutoff = TRUE;
14704  return SCIP_OKAY;
14705  }
14706 
14707  /* treat the new bounds as empty if either the lower/upper bound is above/below +/- SCIPinfinity() */
14708  if( SCIPisInfinity(scip, newbounds.inf) || SCIPisInfinity(scip, -newbounds.sup) )
14709  {
14710  SCIPdebugMsg(scip, " cut off due to new bounds being beyond infinity\n");
14711 
14712  *cutoff = TRUE;
14713  return SCIP_OKAY;
14714  }
14715 
14716  /* tighten newbounds w.r.t. existing expr->propbounds or activity */
14717  if( ownerdata->propboundstag == conshdlrdata->curpropboundstag )
14718  {
14719  /* if already having propbounds in expr, then tighten newbounds by propbounds */
14720  SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), ownerdata->propbounds, newbounds);
14721  }
14722  else
14723  {
14724  /* first time we have propbounds for expr in this propagation rounds:
14725  * intersect with activity (though don't let it become empty if very close intervals)
14726  */
14727  SCIPintervalIntersectEps(&newbounds, SCIPepsilon(scip), SCIPexprGetActivity(expr), newbounds);
14728  }
14729 #ifdef DEBUG_PROP
14730  SCIPdebugMsg(scip, " applied %s: [%.20g,%.20g]\n", ownerdata->propboundstag == conshdlrdata->curpropboundstag ? "previous propbounds" : "activity", newbounds.inf, newbounds.sup);
14731 #endif
14732 
14733  /* check if the new bounds lead to an empty interval */
14735  {
14736  SCIPdebugMsg(scip, " cut off due to empty intersection with previous propbounds or activity\n");
14737 
14738  *cutoff = TRUE;
14739  return SCIP_OKAY;
14740  }
14741 
14742  /* if expr is not constant or variable, then store newbounds in expr->propbounds
14743  * - for constant, the intersection with activity should have been sufficient to determine infeasibilty
14744  * - for variable, the tightenAuxVarBounds call below should be suffient to have to new bounds acknowledged
14745  */
14746  if( SCIPexprGetNChildren(expr) > 0 )
14747  {
14748  ownerdata->propbounds = newbounds;
14749  ownerdata->propboundstag = conshdlrdata->curpropboundstag;
14750  }
14751 
14752  /* if updated propbounds do not allow a sufficient tightening, then do not consider adding to queue for reverse
14753  * propagation or update of auxvar bounds
14754  * TODO? if we first had a considerable tightening and then only get small tightenings under the same
14755  * curpropboundstag, then these will still be considered as isIntervalBetter, since we compare with activity here and
14756  * not with the propbounds as set in the beginning; I'm not sure, though, that comparing always with previous
14757  * propbounds would be better, since a number of small updates to propbounds could eventually lead to a considerable
14758  * one or should we not even update propbounds to newbounds if the update is small?
14759  */
14760  if( !isIntervalBetter(scip, conshdlrdata->forceboundtightening, newbounds, SCIPexprGetActivity(expr)) )
14761  {
14762 #ifdef DEBUG_PROP
14763  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);
14764 #endif
14765  return SCIP_OKAY;
14766  }
14767 
14768  if( SCIPexprGetNChildren(expr) > 0 && !ownerdata->inpropqueue && (ownerdata->nactivityusesprop > 0 || ownerdata->nactivityusessepa > 0 || ownerdata->nenfos < 0) )
14769  {
14770  /* add expression to propagation queue if not there yet and not var or constant and
14771  * if it should have a nlhdlr with a reverseprop callback or nlhdlrs are not initialized yet (nenfos < 0)
14772  */
14773 #ifdef DEBUG_PROP
14774  SCIPdebugMsg(scip, " insert expr <%p> (%s) into reversepropqueue\n", (void*)expr, SCIPexprhdlrGetName(SCIPexprGetHdlr(expr)));
14775 #endif
14776  SCIP_CALL( SCIPqueueInsert(conshdlrdata->reversepropqueue, expr) );
14777  ownerdata->inpropqueue = TRUE;
14778  }
14779 
14780  /* update bounds on variable or auxiliary variable */
14781  SCIP_CALL( tightenAuxVarBounds(scip, ownerdata->conshdlr, expr, newbounds, cutoff, ntightenings) );
14782 
14783  return SCIP_OKAY;
14784 }
14785 
14786 /** mark constraints that include this expression to be propagated again
14787  *
14788  * This can be used by, e.g., nlhdlrs, to trigger a new propagation of constraints without
14789  * a change of variable bounds, e.g., because new information on the expression is available
14790  * that could potentially lead to tighter expression activity values.
14791  *
14792  * Note, that this call marks also constraints for propagation which only share some variable
14793  * with this expression.
14794  */
14796  SCIP* scip, /**< SCIP data structure */
14797  SCIP_EXPR* expr /**< expression to propagate again */
14798  )
14799 {
14800  SCIP_EXPRITER* it;
14801  SCIP_CONSDATA* consdata;
14802  SCIP_EXPR_OWNERDATA* ownerdata;
14803  int c;
14804 
14805  assert(scip != NULL);
14806  assert(expr != NULL);
14807 
14808  ownerdata = SCIPexprGetOwnerData(expr);
14809  assert(ownerdata != NULL);
14810 
14811  SCIPincrementCurBoundsTagNonlinear(ownerdata->conshdlr, FALSE);
14812 
14813  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
14815 
14816  for( ; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )
14817  {
14818  if( !SCIPisExprVar(scip, expr) )
14819  continue;
14820 
14821  ownerdata = SCIPexprGetOwnerData(expr);
14822  assert(ownerdata != NULL);
14823 
14824  for( c = 0; c < ownerdata->nconss; ++c )
14825  {
14826  consdata = SCIPconsGetData(ownerdata->conss[c]);
14827  assert(consdata != NULL);
14828  consdata->ispropagated = FALSE;
14829  }
14830  }
14831 
14832  SCIPfreeExpriter(&it);
14833 
14834  return SCIP_OKAY;
14835 }
14836 
14837 /** adds violation-branching score to an expression
14838  *
14839  * Adds a score to the expression-specific violation-branching score, thereby marking it as branching candidate.
14840  * The expression must either be a variable expression or have an aux-variable.
14841  * In the latter case, branching on auxiliary variables must have been enabled.
14842  * In case of doubt, use SCIPaddExprsViolScoreNonlinear(). Roughly, the difference between these functions is that the current
14843  * function adds `violscore` to the expression directly, while SCIPaddExprsViolScoreNonlinear() will split the
14844  * violation score among all the given expressions according to parameter constraints/nonlinear/branching/violsplit.
14845  *
14846  * @see SCIPaddExprsViolScoreNonlinear()
14847  */
14849  SCIP* scip, /**< SCIP data structure */
14850  SCIP_EXPR* expr, /**< expression where to add branching score */
14851  SCIP_Real violscore /**< violation score to add to expression */
14852  )
14853 {
14854  SCIP_EXPR_OWNERDATA* ownerdata;
14855  SCIP_CONSHDLRDATA* conshdlrdata;
14856 
14857  assert(scip != NULL);
14858  assert(expr != NULL);
14859  assert(violscore >= 0.0);
14860 
14861  ownerdata = SCIPexprGetOwnerData(expr);
14862  assert(ownerdata != NULL);
14863 
14864  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14865  assert(conshdlrdata != NULL);
14866 
14867  /* if not allowing to branch on auxvars, then expr must be a var-expr */
14868  assert(branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr));
14869  /* if allowing to branch on auxvars, then expr must be a var-expr or have an auxvar */
14870  assert(!branchAuxNonlinear(scip, ownerdata->conshdlr) || SCIPisExprVar(scip, expr) || ownerdata->auxvar != NULL);
14871 
14872  /* reset branching score if we are in a different enfo round */
14873  if( ownerdata->violscoretag != conshdlrdata->enforound )
14874  {
14875  ownerdata->violscoresum = violscore;
14876  ownerdata->violscoremax = violscore;
14877  ownerdata->nviolscores = 1;
14878  ownerdata->violscoretag = conshdlrdata->enforound;
14879  return;
14880  }
14881 
14882  ownerdata->violscoresum += violscore;
14883  if( violscore > ownerdata->violscoremax )
14884  ownerdata->violscoremax = violscore;
14885  ++ownerdata->nviolscores;
14886 }
14887 
14888 /** adds violation-branching score to a set of expressions, distributing the score among all the expressions
14889  *
14890  * Each expression must either be a variable expression or have an aux-variable.
14891  * If branching on aux-variables is disabled, then the violation branching score will be distributed among all
14892  * variables present in `exprs`.
14893  */
14895  SCIP* scip, /**< SCIP data structure */
14896  SCIP_EXPR** exprs, /**< expressions where to add branching score */
14897  int nexprs, /**< number of expressions */
14898  SCIP_Real violscore, /**< violation score to add to expression */
14899  SCIP_SOL* sol, /**< current solution */
14900  SCIP_Bool* success /**< buffer to store whether at least one violscore was added */
14901  )
14902 {
14903  SCIP_EXPRITER* it;
14904  SCIP_EXPR** varexprs;
14905  SCIP_EXPR* e;
14906  int nvars;
14907  int varssize;
14908  int i;
14909 
14910  assert(exprs != NULL || nexprs == 0);
14911  assert(success != NULL);
14912 
14913  if( nexprs == 0 )
14914  {
14915  *success = FALSE;
14916  return SCIP_OKAY;
14917  }
14918 
14919  /* if allowing to branch on auxiliary variables, then call internal addConsExprExprsViolScore immediately */
14920  if( branchAuxNonlinear(scip, SCIPexprGetOwnerData(exprs[0])->conshdlr) )
14921  {
14922  addExprsViolScore(scip, exprs, nexprs, violscore, sol, success);
14923  return SCIP_OKAY;
14924  }
14925 
14926  /* if not allowing to branch on aux vars, then create new array containing var expressions that exprs depend on */
14927  nvars = 0;
14928  varssize = 5;
14929  SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, varssize) );
14930 
14931  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
14933 
14934  for( i = 0; i < nexprs; ++i )
14935  {
14936  for( e = SCIPexpriterRestartDFS(it, exprs[i]); !SCIPexpriterIsEnd(it); e = SCIPexpriterGetNext(it) )
14937  {
14938  assert(e != NULL);
14939 
14940  if( SCIPisExprVar(scip, e) )
14941  {
14942  /* add variable expression to vars array */
14943  if( varssize == nvars )
14944  {
14945  varssize = SCIPcalcMemGrowSize(scip, nvars + 1);
14946  SCIP_CALL( SCIPreallocBufferArray(scip, &varexprs, varssize) );
14947  }
14948  assert(varssize > nvars);
14949 
14950  varexprs[nvars++] = e;
14951  }
14952  }
14953  }
14954 
14955  SCIPfreeExpriter(&it);
14956 
14957  addExprsViolScore(scip, varexprs, nvars, violscore, sol, success);
14958 
14959  SCIPfreeBufferArray(scip, &varexprs);
14960 
14961  return SCIP_OKAY;
14962 }
14963 
14964 /** gives violation-branching score stored in expression, or 0.0 if no valid score has been stored */
14966  SCIP_EXPR* expr /**< expression */
14967  )
14968 {
14969  SCIP_EXPR_OWNERDATA* ownerdata;
14970  SCIP_CONSHDLRDATA* conshdlrdata;
14971 
14972  assert(expr != NULL);
14973 
14974  ownerdata = SCIPexprGetOwnerData(expr);
14975  assert(ownerdata != NULL);
14976 
14977  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
14978  assert(conshdlrdata != NULL);
14979 
14980  if( conshdlrdata->enforound != ownerdata->violscoretag )
14981  return 0.0;
14982 
14983  if( ownerdata->nviolscores == 0 )
14984  return 0.0;
14985 
14986  switch( conshdlrdata->branchscoreagg )
14987  {
14988  case 'a' :
14989  /* average */
14990  return ownerdata->violscoresum / ownerdata->nviolscores;
14991 
14992  case 'm' :
14993  /* maximum */
14994  return ownerdata->violscoremax;
14995 
14996  case 's' :
14997  /* sum */
14998  return ownerdata->violscoresum;
14999 
15000  default:
15001  SCIPerrorMessage("Invalid value %c for branchscoreagg parameter\n", conshdlrdata->branchscoreagg);
15002  SCIPABORT();
15003  return SCIP_INVALID;
15004  }
15005 }
15006 
15007 /** returns the partial derivative of an expression w.r.t. a variable (or SCIP_INVALID if there was an evaluation error)
15008  *
15009  * @see SCIPexprGetDerivative()
15010  */
15012  SCIP* scip, /**< SCIP data structure */
15013  SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprGradient() call */
15014  SCIP_VAR* var /**< variable (needs to be in the expression) */
15015  )
15016 {
15017  SCIP_EXPR_OWNERDATA* ownerdata;
15018  SCIP_CONSHDLRDATA* conshdlrdata;
15019  SCIP_EXPR* varexpr;
15020 
15021  assert(scip != NULL);
15022  assert(expr != NULL);
15023  assert(var != NULL);
15024 
15025  /* return 0.0 for value expression */
15026  if( SCIPisExprValue(scip, expr) )
15027  {
15028  assert(SCIPexprGetDerivative(expr) == 0.0);
15029  return 0.0;
15030  }
15031 
15032  /* check if an error occurred during the last SCIPevalExprGradient() call */
15033  if( SCIPexprGetDerivative(expr) == SCIP_INVALID )
15034  return SCIP_INVALID;
15035 
15036  ownerdata = SCIPexprGetOwnerData(expr);
15037  assert(ownerdata != NULL);
15038 
15039  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15040  assert(conshdlrdata != NULL);
15041 
15042  /* use variable to expressions mapping which is stored in the constraint handler data */
15043  assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15044 
15045  varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15046  assert(varexpr != NULL);
15047  assert(SCIPisExprVar(scip, varexpr));
15048 
15049  /* use difftag to decide whether the variable belongs to the expression */
15050  return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetDerivative(varexpr);
15051 }
15052 
15053 /** 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)
15054  *
15055  * @see SCIPexprGetBardot()
15056  */
15058  SCIP* scip, /**< SCIP data structure */
15059  SCIP_EXPR* expr, /**< root expression of constraint used in the last SCIPevalExprHessianDir() call */
15060  SCIP_VAR* var /**< variable (needs to be in the expression) */
15061  )
15062 {
15063  SCIP_EXPR_OWNERDATA* ownerdata;
15064  SCIP_CONSHDLRDATA* conshdlrdata;
15065  SCIP_EXPR* varexpr;
15066 
15067  assert(scip != NULL);
15068  assert(expr != NULL);
15069  assert(var != NULL);
15070 
15071  /* return 0.0 for value expression */
15072  if( SCIPisExprValue(scip, expr) )
15073  return 0.0;
15074 
15075  /* check if an error occurred during the last SCIPevalExprHessianDir() call */
15076  if( SCIPexprGetBardot(expr) == SCIP_INVALID )
15077  return SCIP_INVALID;
15078 
15079  ownerdata = SCIPexprGetOwnerData(expr);
15080  assert(ownerdata != NULL);
15081 
15082  conshdlrdata = SCIPconshdlrGetData(ownerdata->conshdlr);
15083  assert(conshdlrdata != NULL);
15084 
15085  /* use variable to expressions mapping which is stored in the constraint handler data;
15086  * if this fails it means that we are asking for the var's component of H*u for a var
15087  * that doesn't appear in any nonlinear constraint, so maybe we can also just return 0.0
15088  */
15089  assert(SCIPhashmapExists(conshdlrdata->var2expr, var));
15090 
15091  varexpr = (SCIP_EXPR*)SCIPhashmapGetImage(conshdlrdata->var2expr, var);
15092  assert(varexpr != NULL);
15093  assert(SCIPisExprVar(scip, varexpr));
15094 
15095  /* use difftag to decide whether the variable belongs to the expression */
15096  return (SCIPexprGetDiffTag(expr) != SCIPexprGetDiffTag(varexpr)) ? 0.0 : SCIPexprGetBardot(varexpr);
15097 }
15098 
15099 /** evaluates quadratic term in a solution w.r.t. auxiliary variables
15100  *
15101  * \note This requires that for every expr used in the quadratic data, a variable or auxiliary variable is available.
15102  */
15104  SCIP* scip, /**< SCIP data structure */
15105  SCIP_EXPR* expr, /**< quadratic expression */
15106  SCIP_SOL* sol /**< solution to evaluate, or NULL for LP solution */
15107  )
15108 {
15109  SCIP_Real auxvalue;
15110  int nlinexprs;
15111  SCIP_Real* lincoefs;
15112  SCIP_EXPR** linexprs;
15113  int nquadexprs;
15114  int nbilinexprs;
15115  int i;
15116 
15117  assert(scip != NULL);
15118  assert(expr != NULL);
15119 
15120  SCIPexprGetQuadraticData(expr, &auxvalue, &nlinexprs, &linexprs, &lincoefs, &nquadexprs, &nbilinexprs, NULL, NULL);
15121 
15122  /* linear terms */
15123  for( i = 0; i < nlinexprs; ++i )
15124  {
15125  assert(SCIPgetExprAuxVarNonlinear(linexprs[i]) != NULL);
15126  auxvalue += lincoefs[i] * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(linexprs[i]));
15127  }
15128 
15129  /* quadratic terms */
15130  for( i = 0; i < nquadexprs; ++i )
15131  {
15132  SCIP_EXPR* quadexprterm;
15133  SCIP_Real lincoef;
15134  SCIP_Real sqrcoef;
15135  SCIP_Real solval;
15136 
15137  SCIPexprGetQuadraticQuadTerm(expr, i, &quadexprterm, &lincoef, &sqrcoef, NULL, NULL, NULL);
15138 
15139  assert(SCIPgetExprAuxVarNonlinear(quadexprterm) != NULL);
15140 
15141  solval = SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(quadexprterm));
15142  auxvalue += (lincoef + sqrcoef * solval) * solval;
15143  }
15144 
15145  /* bilinear terms */
15146  for( i = 0; i < nbilinexprs; ++i )
15147  {
15148  SCIP_EXPR* expr1;
15149  SCIP_EXPR* expr2;
15150  SCIP_Real coef;
15151 
15152  SCIPexprGetQuadraticBilinTerm(expr, i, &expr1, &expr2, &coef, NULL, NULL);
15153 
15154  assert(SCIPgetExprAuxVarNonlinear(expr1) != NULL);
15155  assert(SCIPgetExprAuxVarNonlinear(expr2) != NULL);
15156  auxvalue += coef * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr1)) * SCIPgetSolVal(scip, sol, SCIPgetExprAuxVarNonlinear(expr2));
15157  }
15158 
15159  return auxvalue;
15160 }
15161 
15162 /**@addtogroup PublicNlhdlrInterfaceMethods
15163  * @{
15164  */
15165 
15166 /** creates a nonlinear handler and includes it into the nonlinear constraint handler */
15168  SCIP* scip, /**< SCIP data structure */
15169  SCIP_NLHDLR** nlhdlr, /**< buffer where to store nonlinear handler */
15170  const char* name, /**< name of nonlinear handler (must not be NULL) */
15171  const char* desc, /**< description of nonlinear handler (can be NULL) */
15172  int detectpriority, /**< detection priority of nonlinear handler */
15173  int enfopriority, /**< enforcement priority of nonlinear handler */
15174  SCIP_DECL_NLHDLRDETECT((*detect)), /**< structure detection callback of nonlinear handler */
15175  SCIP_DECL_NLHDLREVALAUX((*evalaux)), /**< auxiliary evaluation callback of nonlinear handler */
15176  SCIP_NLHDLRDATA* nlhdlrdata /**< data of nonlinear handler (can be NULL) */
15177  )
15178 {
15179  SCIP_CONSHDLR* conshdlr;
15180  SCIP_CONSHDLRDATA* conshdlrdata;
15181 
15182  assert(scip != NULL);
15183  assert(nlhdlr != NULL);
15184  assert(detect != NULL);
15185 
15186  /* find myself */
15187  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15188  if( conshdlr == NULL )
15189  {
15190  SCIPerrorMessage("nonlinear constraint handler not found");
15191  return SCIP_PLUGINNOTFOUND;
15192  }
15193 
15194  /* create nlhdlr */
15195  SCIP_CALL( SCIPnlhdlrCreate(scip, nlhdlr, name, desc, detectpriority, enfopriority, detect, evalaux, nlhdlrdata) );
15196 
15197  /* include into constraint handler */
15198  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15199  assert(conshdlrdata != NULL);
15200 
15201  SCIP_CALL( SCIPensureBlockMemoryArray(scip, &conshdlrdata->nlhdlrs, &conshdlrdata->nlhdlrssize, conshdlrdata->nnlhdlrs+1) );
15202 
15203  conshdlrdata->nlhdlrs[conshdlrdata->nnlhdlrs] = *nlhdlr;
15204  ++conshdlrdata->nnlhdlrs;
15205 
15206  /* sort nonlinear handlers by detection priority, in decreasing order
15207  * will happen in INIT, so only do when called late
15208  */
15209  if( SCIPgetStage(scip) > SCIP_STAGE_INIT && conshdlrdata->nnlhdlrs > 1 )
15210  SCIPsortDownPtr((void**)conshdlrdata->nlhdlrs, SCIPnlhdlrComp, conshdlrdata->nnlhdlrs);
15211 
15212  return SCIP_OKAY;
15213 }
15214 
15215 /** get number of nonlinear handler */
15217  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15218  )
15219 {
15220  SCIP_CONSHDLRDATA* conshdlrdata;
15221 
15222  assert(conshdlr != NULL);
15223 
15224  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15225  assert(conshdlrdata != NULL);
15226 
15227  return conshdlrdata->nnlhdlrs;
15228 }
15229 
15230 /** get nonlinear handlers */
15232  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
15233  )
15234 {
15235  SCIP_CONSHDLRDATA* conshdlrdata;
15236 
15237  assert(conshdlr != NULL);
15238 
15239  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15240  assert(conshdlrdata != NULL);
15241 
15242  return conshdlrdata->nlhdlrs;
15243 }
15244 
15245 /** returns a nonlinear handler of a given name (or NULL if not found) */
15247  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraint handler */
15248  const char* name /**< name of nonlinear handler */
15249  )
15250 {
15251  SCIP_CONSHDLRDATA* conshdlrdata;
15252  int h;
15253 
15254  assert(conshdlr != NULL);
15255  assert(name != NULL);
15256 
15257  conshdlrdata = SCIPconshdlrGetData(conshdlr);
15258  assert(conshdlrdata != NULL);
15259 
15260  for( h = 0; h < conshdlrdata->nnlhdlrs; ++h )
15261  if( strcmp(SCIPnlhdlrGetName(conshdlrdata->nlhdlrs[h]), name) == 0 )
15262  return conshdlrdata->nlhdlrs[h];
15263 
15264  return NULL;
15265 }
15266 
15267 /** gives expression data that a given nonlinear handler stored in an expression
15268  *
15269  * Returns NULL if expr has not been detected by nlhdlr or nlhdlr did not store data.
15270  */
15272  SCIP_NLHDLR* nlhdlr, /**< nonlinear handler */
15273  SCIP_EXPR* expr /**< expression */
15274  )
15275 {
15276  SCIP_EXPR_OWNERDATA* ownerdata;
15277  int e;
15278 
15279  assert(nlhdlr != NULL);
15280  assert(expr != NULL);
15281 
15282  ownerdata = SCIPexprGetOwnerData(expr);
15283  assert(ownerdata != NULL);
15284 
15285  for( e = 0; e < ownerdata->nenfos; ++e )
15286  if( ownerdata->enfos[e]->nlhdlr == nlhdlr )
15287  return ownerdata->enfos[e]->nlhdlrexprdata;
15288 
15289  return NULL;
15290 }
15291 
15292 /** @} */
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
SCIP_RETCODE SCIPgetLPBranchCands(SCIP *scip, SCIP_VAR ***lpcands, SCIP_Real **lpcandssol, SCIP_Real **lpcandsfrac, int *nlpcands, int *npriolpcands, int *nfracimplvars)
Definition: scip_branch.c:395
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
SCIP_Real fractionality
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
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:5202
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
static SCIP_RETCODE branchingIntegralOrNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Longint soltag, SCIP_Real maxrelconsviol, SCIP_Bool *branchintegral, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPaddDialogEntry(SCIP *scip, SCIP_DIALOG *dialog, SCIP_DIALOG *subdialog)
Definition: scip_dialog.c:171
static SCIP_DECL_CONSEXIT(consExitNonlinear)
static SCIP_RETCODE enforceConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Longint soltag, SCIP_Bool inenforcement, SCIP_Bool branchcandonly, SCIP_Real maxrelconsviol, SCIP_RESULT *result)
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
SCIP_RETCODE SCIPgetExprActivityNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *activity)
#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:8813
#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:1438
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:1247
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:8949
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)
static SCIP_RETCODE selectBranchingCandidate(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_Bool considerfracnl, BRANCHCAND **selected)
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:4644
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 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:4316
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:5319
#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:752
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)
#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:4612
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
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:428
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_Real SCIPfeasCeil(SCIP *scip, SCIP_Real val)
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_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
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:8175
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:633
SCIP_NLHDLR ** SCIPgetNlhdlrsNonlinear(SCIP_CONSHDLR *conshdlr)
SCIP_EXPR * expr
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:8714
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:5181
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
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_Bool branchcandonly, SCIP_RESULT *result)
#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
static SCIP_Bool branchingIntegralFirst(SCIP *scip, SCIP_CONSHDLR *conshdlr)
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_VAR * var
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
static void scoreBranchingCandidates(SCIP *scip, SCIP_CONSHDLR *conshdlr, BRANCHCAND *cands, int ncands, SCIP_Bool considerfracnl, SCIP_SOL *sol)
#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
SCIP_Real SCIPgetAvgPseudocostCount(SCIP *scip, SCIP_BRANCHDIR dir)
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
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_Bool branchcandonly, SCIP_RESULT *result, SCIP_Bool *success)
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:1213
#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
#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:453
#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:452
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)
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_Bool branchcandonly, SCIP_RESULT *result)
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:1943
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)