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-2017 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_nonlinear.c
17  * @brief constraint handler for nonlinear constraints \f$\textrm{lhs} \leq \sum_{i=1}^n a_ix_i + \sum_{j=1}^m c_jf_j(x) \leq \textrm{rhs}\f$
18  * @author Stefan Vigerske
19  * @author Ingmar Vierhaus (consparse)
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include <assert.h>
25 #include <math.h>
26 #include <string.h>
27 #include <ctype.h>
28 
29 #include "scip/cons_nonlinear.h"
30 #define SCIP_PRIVATE_ROWPREP
31 #include "scip/cons_quadratic.h" /* for SCIP_ROWPREP */
32 #include "scip/cons_linear.h"
33 #include "scip/heur_trysol.h"
34 #include "scip/heur_subnlp.h"
35 #include "nlpi/exprinterpret.h"
36 #include "nlpi/nlpi_ipopt.h"
37 #include "scip/debug.h"
38 
39 /* constraint handler properties */
40 #define CONSHDLR_NAME "nonlinear"
41 #define CONSHDLR_DESC "constraint handler for nonlinear constraints"
42 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
43 #define CONSHDLR_ENFOPRIORITY -60 /**< priority of the constraint handler for constraint enforcing */
44 #define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
45 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
46 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
47 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
48  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
49 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
50 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
51 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
52 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
53 
54 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
55 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
56 
57 #define INTERVALINFTY 1E+43 /**< value for infinity in interval operations */
58 #define BOUNDTIGHTENING_MINSTRENGTH 0.05/**< minimal required bound tightening strength in expression graph domain tightening for propagating bound change */
59 #define INITLPMAXVARVAL 1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
60 
61 /*
62  * Data structures
63  */
64 
65 /** event data for linear variable bound change events */
66 struct LinVarEventData
67 {
68  SCIP_CONSHDLRDATA* conshdlrdata; /**< the constraint handler data */
69  SCIP_CONS* cons; /**< the constraint */
70  int varidx; /**< the index of the linear variable which bound change is catched */
71  int filterpos; /**< position of eventdata in SCIP's event filter */
72 };
73 typedef struct LinVarEventData LINVAREVENTDATA;
74 
75 /** constraint data for nonlinear constraints */
76 struct SCIP_ConsData
77 {
78  SCIP_Real lhs; /**< left hand side of constraint */
79  SCIP_Real rhs; /**< right hand side of constraint */
80 
81  int nlinvars; /**< number of linear variables */
82  int linvarssize; /**< length of linear variable arrays */
83  SCIP_VAR** linvars; /**< linear variables */
84  SCIP_Real* lincoefs; /**< coefficients of linear variables */
85  LINVAREVENTDATA** lineventdata; /**< eventdata for bound change of linear variable */
86 
87  int nexprtrees; /**< number of expression trees */
88  SCIP_Real* nonlincoefs; /**< coefficients of expression trees */
89  SCIP_EXPRTREE** exprtrees; /**< nonlinear part of constraint */
90  SCIP_EXPRCURV* curvatures; /**< curvature of each expression tree (taking nonlincoefs into account) */
91  SCIP_EXPRGRAPHNODE* exprgraphnode; /**< node in expression graph corresponding to expression tree of this constraint */
92  SCIP_EXPRCURV curvature; /**< curvature of complete nonlinear part, if checked */
93 
94  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
95 
96  unsigned int linvarssorted:1; /**< are the linear variables already sorted? */
97  unsigned int linvarsmerged:1; /**< are equal linear variables already merged? */
98 
99  unsigned int iscurvchecked:1; /**< is nonlinear function checked on convexity or concavity ? */
100  unsigned int isremovedfixingslin:1; /**< did we removed fixed/aggr/multiaggr variables in linear part? */
101  unsigned int ispresolved:1; /**< did we checked for possibilities of upgrading or implicit integer variables? */
102  unsigned int forcebackprop:1; /**< should we force to run the backward propagation on our subgraph in the exprgraph? */
103 
104  SCIP_Real minlinactivity; /**< sum of minimal activities of all linear terms with finite minimal activity */
105  SCIP_Real maxlinactivity; /**< sum of maximal activities of all linear terms with finite maximal activity */
106  int minlinactivityinf; /**< number of linear terms with infinite minimal activity */
107  int maxlinactivityinf; /**< number of linear terms with infinity maximal activity */
108  SCIP_Real activity; /**< activity of constraint function w.r.t. current solution */
109  SCIP_Real lhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
110  SCIP_Real rhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
111 
112  int linvar_maydecrease; /**< index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
113  int linvar_mayincrease; /**< index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
114 
115  SCIP_Real lincoefsmin; /**< maximal absolute value of coefficients in linear part, only available in solving stage */
116  SCIP_Real lincoefsmax; /**< minimal absolute value of coefficients in linear part, only available in solving stage */
117  unsigned int ncuts; /**< number of cuts created for this constraint so far */
118 };
119 
120 /** nonlinear constraint update method */
121 struct SCIP_NlConsUpgrade
122 {
123  SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)); /**< method to call for upgrading nonlinear constraint */
124  SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform));/**< method to call for reformulating an expression graph node */
125  int priority; /**< priority of upgrading method */
126  SCIP_Bool active; /**< is upgrading enabled */
127 };
130 /** constraint handler data */
131 struct SCIP_ConshdlrData
132 {
133  SCIP_EXPRINT* exprinterpreter; /**< expression interpreter to compute gradients */
134 
135  SCIP_Real mincutefficacysepa; /**< minimal efficacy of a cut in order to add it to relaxation during separation */
136  SCIP_Real mincutefficacyenfofac;/**< minimal target efficacy of a cut in order to add it to relaxation during enforcement as factor of feasibility tolerance (may be ignored) */
137  char scaling; /**< scaling method of constraints in feasibility check */
138  SCIP_Real cutmaxrange; /**< maximal range (maximal coef / minimal coef) of a cut in order to be added to LP */
139  SCIP_Bool linfeasshift; /**< whether to make solutions in check feasible if possible */
140  SCIP_Bool checkconvexexpensive;/**< whether to apply expensive curvature checking methods */
141  SCIP_Bool assumeconvex; /**< whether functions in inequalities should be assumed to be convex */
142  int maxproprounds; /**< limit on number of propagation rounds for a single constraint within one round of SCIP propagation */
143  SCIP_Bool reformulate; /**< whether to reformulate expression graph */
144  int maxexpansionexponent;/**< maximal exponent where still expanding non-monomial polynomials in expression simplification */
145  SCIP_Real sepanlpmincont; /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
146  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
147 
148  SCIP_HEUR* subnlpheur; /**< a pointer to the subNLP heuristic, if available */
149  SCIP_HEUR* trysolheur; /**< a pointer to the TRYSOL heuristic, if available */
150  SCIP_EVENTHDLR* linvareventhdlr; /**< our handler for linear variable bound change events */
151  SCIP_EVENTHDLR* nonlinvareventhdlr; /**< our handler for nonlinear variable bound change events */
152  int newsoleventfilterpos;/**< filter position of new solution event handler, if catched */
153 
154  SCIP_NLCONSUPGRADE** nlconsupgrades; /**< nonlinear constraint upgrade methods for specializing nonlinear constraints */
155  int nlconsupgradessize; /**< size of nlconsupgrade array */
156  int nnlconsupgrades; /**< number of nonlinear constraint upgrade methods */
157 
158  SCIP_EXPRGRAPH* exprgraph; /**< expression graph */
159  SCIP* scip; /**< SCIP pointer for use in expression graph callbacks */
160  unsigned int isremovedfixings:1; /**< have fixed variables been removed in the expression graph? */
161  unsigned int ispropagated:1; /**< have current bounds of linear variables in constraints and variables in expression graph been propagated? */
162  unsigned int isreformulated:1; /**< has expression graph been reformulated? */
163  unsigned int sepanlp:1; /**< has a linearization in the NLP relaxation been added? */
164  int naddedreformconss; /**< number of constraints added via reformulation */
165  SCIP_NODE* lastenfonode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
166  int nenforounds; /**< counter on number of enforcement rounds for the current node */
167 };
168 
169 /*
170  * Local methods
171  */
172 
173 /** translate from one value of infinity to another
174  *
175  * if val is >= infty1, then give infty2, else give val
176  */
177 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
179 /* catches variable bound change events on a linear variable in a nonlinear constraint */
180 static
182  SCIP* scip, /**< SCIP data structure */
183  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
184  int linvarpos /**< position of variable in linear variables array */
185  )
186 {
188  SCIP_CONSDATA* consdata;
189  LINVAREVENTDATA* eventdata;
190  SCIP_EVENTTYPE eventtype;
191 
192  assert(scip != NULL);
193  assert(cons != NULL);
194  assert(SCIPconsIsEnabled(cons));
195  assert(SCIPconsIsTransformed(cons));
196 
197  assert(SCIPconsGetHdlr(cons) != NULL);
198  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
199  assert(conshdlrdata != NULL);
200  assert(conshdlrdata->linvareventhdlr != NULL);
201 
202  consdata = SCIPconsGetData(cons);
203  assert(consdata != NULL);
204 
205  assert(linvarpos >= 0);
206  assert(linvarpos < consdata->nlinvars);
207 
208  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
209 
210  eventtype = SCIP_EVENTTYPE_VARFIXED;
211  if( !SCIPisInfinity(scip, consdata->rhs) )
212  {
213  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest */
214  if( consdata->lincoefs[linvarpos] > 0.0 )
215  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
216  else
217  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
218  }
219  if( !SCIPisInfinity(scip, -consdata->lhs) )
220  {
221  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest */
222  if( consdata->lincoefs[linvarpos] > 0.0 )
223  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
224  else
225  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
226  }
227 
228  eventdata->conshdlrdata = conshdlrdata;
229  eventdata->cons = cons;
230  eventdata->varidx = linvarpos;
231  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->linvars[linvarpos], eventtype, conshdlrdata->linvareventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
232 
233  /* ensure lineventdata array is existing */
234  if( consdata->lineventdata == NULL )
235  {
236  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize) );
237  }
238 
239  consdata->lineventdata[linvarpos] = eventdata;
240 
241  /* since bound changes were not catched before, a possibly stored linear activity may have become outdated, so set to invalid */
242  consdata->minlinactivity = SCIP_INVALID;
243  consdata->maxlinactivity = SCIP_INVALID;
244 
245  /* mark constraint for propagation */
246  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
247 
248  return SCIP_OKAY;
249 }
250 
251 /* drops variable bound change events on a linear variable in a nonlinear constraint */
252 static
254  SCIP* scip, /**< SCIP data structure */
255  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
256  int linvarpos /**< position of variable in linear variables array */
257  )
258 {
260  SCIP_CONSDATA* consdata;
261  SCIP_EVENTTYPE eventtype;
262 
263  assert(scip != NULL);
264  assert(cons != NULL);
265  assert(SCIPconsIsTransformed(cons));
266 
267  assert(SCIPconsGetHdlr(cons) != NULL);
269  assert(conshdlrdata != NULL);
270  assert(conshdlrdata->linvareventhdlr != NULL);
271 
272  consdata = SCIPconsGetData(cons);
273  assert(consdata != NULL);
274 
275  assert(linvarpos >= 0);
276  assert(linvarpos < consdata->nlinvars);
277  assert(consdata->lineventdata != NULL);
278  assert(consdata->lineventdata[linvarpos] != NULL);
279  assert(consdata->lineventdata[linvarpos]->cons == cons);
280  assert(consdata->lineventdata[linvarpos]->varidx == linvarpos);
281  assert(consdata->lineventdata[linvarpos]->filterpos >= 0);
282 
283  eventtype = SCIP_EVENTTYPE_VARFIXED;
284  if( !SCIPisInfinity(scip, consdata->rhs) )
285  {
286  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest */
287  if( consdata->lincoefs[linvarpos] > 0.0 )
288  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
289  else
290  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
291  }
292  if( !SCIPisInfinity(scip, -consdata->lhs) )
293  {
294  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest */
295  if( consdata->lincoefs[linvarpos] > 0.0 )
296  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
297  else
298  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
299  }
300 
301  SCIP_CALL( SCIPdropVarEvent(scip, consdata->linvars[linvarpos], eventtype, conshdlrdata->linvareventhdlr, (SCIP_EVENTDATA*)consdata->lineventdata[linvarpos], consdata->lineventdata[linvarpos]->filterpos) );
302 
303  SCIPfreeBlockMemory(scip, &consdata->lineventdata[linvarpos]); /*lint !e866*/
304 
305  return SCIP_OKAY;
306 }
307 
308 /** locks a linear variable in a constraint */
309 static
311  SCIP* scip, /**< SCIP data structure */
312  SCIP_CONS* cons, /**< constraint where to lock a variable */
313  SCIP_VAR* var, /**< variable to lock */
314  SCIP_Real coef /**< coefficient of variable in constraint */
315  )
316 {
317  SCIP_CONSDATA* consdata;
318 
319  assert(scip != NULL);
320  assert(cons != NULL);
321  assert(var != NULL);
322  assert(coef != 0.0);
323 
324  consdata = SCIPconsGetData(cons);
325  assert(consdata != NULL);
326 
327  if( coef > 0.0 )
328  {
329  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
330  }
331  else
332  {
333  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
334  }
335 
336  return SCIP_OKAY;
337 }
338 
339 /** unlocks a linear variable in a constraint */
340 static
342  SCIP* scip, /**< SCIP data structure */
343  SCIP_CONS* cons, /**< constraint where to unlock a variable */
344  SCIP_VAR* var, /**< variable to unlock */
345  SCIP_Real coef /**< coefficient of variable in constraint */
346  )
347 {
348  SCIP_CONSDATA* consdata;
349 
350  assert(scip != NULL);
351  assert(cons != NULL);
352  assert(var != NULL);
353  assert(coef != 0.0);
354 
355  consdata = SCIPconsGetData(cons);
356  assert(consdata != NULL);
357 
358  if( coef > 0.0 )
359  {
360  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
361  }
362  else
363  {
364  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
365  }
366 
367  return SCIP_OKAY;
368 }
369 
370 /** computes the minimal and maximal activity for the linear part in a constraint data
371  * only sums up terms that contribute finite values
372  * gives the number of terms that contribute infinite values
373  * only computes those activities where the corresponding side of the constraint is finite
374  */
375 static
377  SCIP* scip, /**< SCIP data structure */
378  SCIP_CONSDATA* consdata /**< constraint data */
379  )
380 { /*lint --e{666}*/
381  SCIP_ROUNDMODE prevroundmode;
382  int i;
383  SCIP_Real bnd;
384 
385  assert(scip != NULL);
386  assert(consdata != NULL);
387 
388  if( consdata->minlinactivity != SCIP_INVALID && consdata->maxlinactivity != SCIP_INVALID ) /*lint !e777*/
389  {
390  /* activities should be uptodate */
391  assert(consdata->minlinactivityinf >= 0);
392  assert(consdata->maxlinactivityinf >= 0);
393  return;
394  }
395 
396  consdata->minlinactivityinf = 0;
397  consdata->maxlinactivityinf = 0;
398 
399  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
400  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
401  */
402  consdata->minlinactivity = SCIPisInfinity(scip, consdata->rhs) ? -INTERVALINFTY : 0.0;
403  consdata->maxlinactivity = SCIPisInfinity(scip, -consdata->lhs) ? INTERVALINFTY : 0.0;
404 
405  if( consdata->nlinvars == 0 )
406  return;
407 
408  /* if the activities computed here should be still uptodate after boundchanges,
409  * variable events need to be catched */
410  assert(consdata->lineventdata != NULL);
411 
412  prevroundmode = SCIPintervalGetRoundingMode();
413 
414  if( !SCIPisInfinity(scip, consdata->rhs) )
415  {
416  /* compute minimal activity only if there is a finite right hand side */
418 
419  for( i = 0; i < consdata->nlinvars; ++i )
420  {
421  assert(SCIPvarGetLbLocal(consdata->linvars[i]) <= SCIPvarGetUbLocal(consdata->linvars[i]));
422  assert(consdata->lineventdata[i] != NULL);
423  if( consdata->lincoefs[i] >= 0.0 )
424  {
425  bnd = SCIPvarGetLbLocal(consdata->linvars[i]);
426  if( SCIPisInfinity(scip, -bnd) )
427  {
428  ++consdata->minlinactivityinf;
429  continue;
430  }
431  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
432  }
433  else
434  {
435  bnd = SCIPvarGetUbLocal(consdata->linvars[i]);
436  if( SCIPisInfinity(scip, bnd) )
437  {
438  ++consdata->minlinactivityinf;
439  continue;
440  }
441  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
442  }
443  consdata->minlinactivity += consdata->lincoefs[i] * bnd;
444  }
445  }
446 
447  if( !SCIPisInfinity(scip, -consdata->lhs) )
448  {
449  /* compute maximal activity only if there is a finite left hand side */
451 
452  for( i = 0; i < consdata->nlinvars; ++i )
453  {
454  assert(consdata->lineventdata[i] != NULL);
455  assert(SCIPvarGetLbLocal(consdata->linvars[i]) <= SCIPvarGetUbLocal(consdata->linvars[i]));
456  if( consdata->lincoefs[i] >= 0.0 )
457  {
458  bnd = SCIPvarGetUbLocal(consdata->linvars[i]);
459  if( SCIPisInfinity(scip, bnd) )
460  {
461  ++consdata->maxlinactivityinf;
462  continue;
463  }
464  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
465  }
466  else
467  {
468  bnd = SCIPvarGetLbLocal(consdata->linvars[i]);
469  if( SCIPisInfinity(scip, -bnd) )
470  {
471  ++consdata->maxlinactivityinf;
472  continue;
473  }
474  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
475  }
476  consdata->maxlinactivity += consdata->lincoefs[i] * bnd;
477  }
478  }
479  assert(consdata->minlinactivity <= consdata->maxlinactivity || consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0);
480 
481  SCIPintervalSetRoundingMode(prevroundmode);
482 }
483 
484 /** update the linear activities after a change in the lower bound of a variable */
485 static
487  SCIP* scip, /**< SCIP data structure */
488  SCIP_CONSDATA* consdata, /**< constraint data */
489  SCIP_Real coef, /**< coefficient of variable in constraint */
490  SCIP_Real oldbnd, /**< previous lower bound of variable */
491  SCIP_Real newbnd /**< new lower bound of variable */
492  )
493 {
494  SCIP_ROUNDMODE prevroundmode;
495 
496  assert(scip != NULL);
497  assert(consdata != NULL);
498  /* we can't deal with lower bounds at infinity */
499  assert(!SCIPisInfinity(scip, oldbnd));
500  assert(!SCIPisInfinity(scip, newbnd));
501 
502  /* assume lhs <= a*x + y <= rhs, then the following boundchanges can be deduced:
503  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
504  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
505  */
506 
507  if( coef > 0.0 )
508  {
509  /* we should only be called if rhs is finite */
510  assert(!SCIPisInfinity(scip, consdata->rhs));
511 
512  /* we have no min activities computed so far, so cannot update */
513  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777*/
514  return;
515 
516  assert(consdata->minlinactivity > -INTERVALINFTY);
517 
518  prevroundmode = SCIPintervalGetRoundingMode();
520 
521  /* update min activity */
522  if( SCIPisInfinity(scip, -oldbnd) )
523  {
524  --consdata->minlinactivityinf;
525  assert(consdata->minlinactivityinf >= 0);
526  }
527  else
528  {
529  consdata->minlinactivity += SCIPintervalNegateReal(coef) * oldbnd;
530  }
531 
532  if( SCIPisInfinity(scip, -newbnd) )
533  {
534  ++consdata->minlinactivityinf;
535  }
536  else
537  {
538  consdata->minlinactivity += coef * newbnd;
539  }
540 
541  SCIPintervalSetRoundingMode(prevroundmode);
542  }
543  else
544  {
545  /* we should only be called if lhs is finite */
546  assert(!SCIPisInfinity(scip, -consdata->lhs));
547 
548  /* we have no max activities computed so far, so cannot update */
549  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777*/
550  return;
551 
552  assert(consdata->maxlinactivity < INTERVALINFTY);
553 
554  prevroundmode = SCIPintervalGetRoundingMode();
556 
557  /* update max activity */
558  if( SCIPisInfinity(scip, -oldbnd) )
559  {
560  --consdata->maxlinactivityinf;
561  assert(consdata->maxlinactivityinf >= 0);
562  }
563  else
564  {
565  consdata->maxlinactivity += SCIPintervalNegateReal(coef) * oldbnd;
566  }
567 
568  if( SCIPisInfinity(scip, -newbnd) )
569  {
570  ++consdata->maxlinactivityinf;
571  }
572  else
573  {
574  consdata->maxlinactivity += coef * newbnd;
575  }
576 
577  SCIPintervalSetRoundingMode(prevroundmode);
578  }
579 }
580 
581 /** update the linear activities after a change in the upper bound of a variable */
582 static
584  SCIP* scip, /**< SCIP data structure */
585  SCIP_CONSDATA* consdata, /**< constraint data */
586  SCIP_Real coef, /**< coefficient of variable in constraint */
587  SCIP_Real oldbnd, /**< previous lower bound of variable */
588  SCIP_Real newbnd /**< new lower bound of variable */
589  )
590 {
591  SCIP_ROUNDMODE prevroundmode;
592 
593  assert(scip != NULL);
594  assert(consdata != NULL);
595  /* we can't deal with upper bounds at -infinity */
596  assert(!SCIPisInfinity(scip, -oldbnd));
597  assert(!SCIPisInfinity(scip, -newbnd));
598 
599  /* assume lhs <= a*x + y <= rhs, then the following boundchanges can be deduced:
600  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
601  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
602  */
603  if( coef > 0.0 )
604  {
605  /* we should only be called if lhs is finite */
606  assert(!SCIPisInfinity(scip, -consdata->lhs));
607 
608  /* we have no max activities computed so far, so cannot update */
609  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777*/
610  return;
611 
612  assert(consdata->maxlinactivity < INTERVALINFTY);
613 
614  prevroundmode = SCIPintervalGetRoundingMode();
616 
617  /* update max activity */
618  if( SCIPisInfinity(scip, oldbnd) )
619  {
620  --consdata->maxlinactivityinf;
621  assert(consdata->maxlinactivityinf >= 0);
622  }
623  else
624  {
625  consdata->maxlinactivity += SCIPintervalNegateReal(coef) * oldbnd;
626  }
627 
628  if( SCIPisInfinity(scip, newbnd) )
629  {
630  ++consdata->maxlinactivityinf;
631  }
632  else
633  {
634  consdata->maxlinactivity += coef * newbnd;
635  }
636 
637  SCIPintervalSetRoundingMode(prevroundmode);
638  }
639  else
640  {
641  /* we should only be called if rhs is finite */
642  assert(!SCIPisInfinity(scip, consdata->rhs));
643 
644  /* we have no min activities computed so far, so cannot update */
645  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777*/
646  return;
647 
648  assert(consdata->minlinactivity > -INTERVALINFTY);
649 
650  prevroundmode = SCIPintervalGetRoundingMode();
652 
653  /* update min activity */
654  if( SCIPisInfinity(scip, oldbnd) )
655  {
656  --consdata->minlinactivityinf;
657  assert(consdata->minlinactivityinf >= 0);
658  }
659  else
660  {
661  consdata->minlinactivity += SCIPintervalNegateReal(coef) * oldbnd;
662  }
663 
664  if( SCIPisInfinity(scip, newbnd) )
665  {
666  ++consdata->minlinactivityinf;
667  }
668  else
669  {
670  consdata->minlinactivity += coef * newbnd;
671  }
672 
673  SCIPintervalSetRoundingMode(prevroundmode);
674  }
675 }
676 
677 /** processes variable fixing or bound change event */
678 static
679 SCIP_DECL_EVENTEXEC(processLinearVarEvent)
680 {
681  SCIP_CONS* cons;
682  SCIP_CONSDATA* consdata;
683  SCIP_EVENTTYPE eventtype;
684  int varidx;
685 
686  assert(scip != NULL);
687  assert(event != NULL);
688  assert(eventdata != NULL);
689  assert(eventhdlr != NULL);
690 
691  cons = ((LINVAREVENTDATA*)eventdata)->cons;
692  assert(cons != NULL);
693 
694  consdata = SCIPconsGetData(cons);
695  assert(consdata != NULL);
696 
697  varidx = ((LINVAREVENTDATA*)eventdata)->varidx;
698  assert(varidx >= 0);
699  assert(varidx < consdata->nlinvars);
700 
701  eventtype = SCIPeventGetType(event);
702 
703  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
704  {
705  consdata->isremovedfixingslin = FALSE;
706  }
707 
708  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
709  {
710  /* update activity bounds for linear terms */
711  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
712  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
713  else
714  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
715 
716  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
717  {
718  assert(((LINVAREVENTDATA*)eventdata)->conshdlrdata != NULL);
719  ((LINVAREVENTDATA*)eventdata)->conshdlrdata->ispropagated = FALSE;
720 
721  /* mark constraint for propagation */
722  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
723  }
724  }
725 
726  return SCIP_OKAY;
727 }
728 
729 /** processes bound change events for variables in expression graph */
730 static
731 SCIP_DECL_EVENTEXEC(processNonlinearVarEvent)
732 {
734  SCIP_EVENTTYPE eventtype;
735 
736  assert(scip != NULL);
737  assert(event != NULL);
738  assert(eventdata != NULL);
739  assert(eventhdlr != NULL);
740 
741  conshdlrdata = (SCIP_CONSHDLRDATA*)SCIPeventhdlrGetData(eventhdlr);
742  assert(conshdlrdata != NULL);
743  assert(conshdlrdata->exprgraph != NULL);
744 
745  eventtype = SCIPeventGetType(event);
746  assert( eventtype & (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED) );
747 
748  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
749  {
750  SCIP_Real newbd;
751 
752  SCIPdebugMsg(scip, "changed %s bound on expression graph variable <%s> from %g to %g\n",
753  (eventtype & SCIP_EVENTTYPE_LBCHANGED) ? "lower" : "upper",
755 
756  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
757  conshdlrdata->ispropagated = FALSE;
758  /* @todo a global bound tightening may yield in convex/concave curvatures, maybe the iscurvcheck flag should be reset? */
759 
760  /* update variable bound in expression graph, with epsilon added */
761  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
762  {
763  newbd = -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -SCIPeventGetNewbound(event)); /*lint !e666*/
764  /* if newbd in [0,eps], then relax to 0.0, otherwise relax by -epsilon
765  * this is to ensure that an original positive variable does not get negative by this, which may have an adverse effect on convexity recoginition, for example */
766  if( newbd >= 0.0 && newbd <= SCIPepsilon(scip) )
767  newbd = 0.0;
768  else
769  newbd -= SCIPepsilon(scip);
770  SCIPexprgraphSetVarNodeLb(conshdlrdata->exprgraph, (SCIP_EXPRGRAPHNODE*)eventdata, newbd);
771  }
772  else
773  {
774  newbd = +infty2infty(SCIPinfinity(scip), INTERVALINFTY, SCIPeventGetNewbound(event)); /*lint !e666*/
775  /* if newbd in [-eps,0], then relax to 0.0, otherwise relax by +epsilon */
776  if( newbd >= -SCIPepsilon(scip) && newbd <= 0.0 )
777  newbd = 0.0;
778  else
779  newbd += SCIPepsilon(scip);
780  SCIPexprgraphSetVarNodeUb(conshdlrdata->exprgraph, (SCIP_EXPRGRAPHNODE*)eventdata, newbd);
781  }
782  }
783  else
784  {
785  assert(eventtype & SCIP_EVENTTYPE_VARFIXED);
786  conshdlrdata->isremovedfixings = FALSE;
787  }
788 
789  return SCIP_OKAY;
790 }
791 
792 /** callback method for variable addition in expression graph */
793 static
794 SCIP_DECL_EXPRGRAPHVARADDED( exprgraphVarAdded )
795 {
797  SCIP_INTERVAL varbounds;
798  SCIP_VAR* var_;
799 
800  assert(exprgraph != NULL);
801  assert(var != NULL);
802  assert(varnode != NULL);
803 
804  var_ = (SCIP_VAR*)var;
805 
806  conshdlrdata = (SCIP_CONSHDLRDATA*)userdata;
807  assert(conshdlrdata != NULL);
808  assert(conshdlrdata->exprgraph == exprgraph);
809 
810  /* catch variable bound change events */
811  SCIP_CALL( SCIPcatchVarEvent(conshdlrdata->scip, (SCIP_VAR*)var, SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED, conshdlrdata->nonlinvareventhdlr, (SCIP_EVENTDATA*)varnode, NULL) );
812  SCIPdebugMessage("catch boundchange events on new expression graph variable <%s>\n", SCIPvarGetName(var_));
813 
814  /* set current bounds in expression graph */
815  SCIPintervalSetBounds(&varbounds,
816  -infty2infty(SCIPinfinity(conshdlrdata->scip), INTERVALINFTY, -MIN(SCIPvarGetLbLocal(var_), SCIPvarGetUbLocal(var_))), /*lint !e666*/
817  +infty2infty(SCIPinfinity(conshdlrdata->scip), INTERVALINFTY, MAX(SCIPvarGetLbLocal(var_), SCIPvarGetUbLocal(var_))) /*lint !e666*/
818  );
819  SCIPexprgraphSetVarNodeBounds(exprgraph, varnode, varbounds);
820 
821  SCIP_CALL( SCIPaddVarLocks(conshdlrdata->scip, var_, 1, 1) );
822  SCIPdebugMessage("increased up- and downlocks of variable <%s>\n", SCIPvarGetName(var_));
823 
824  SCIP_CALL( SCIPcaptureVar(conshdlrdata->scip, var_) );
825  SCIPdebugMessage("capture variable <%s>\n", SCIPvarGetName(var_));
826 
827  conshdlrdata->isremovedfixings &= SCIPvarIsActive(var_);
828  conshdlrdata->ispropagated = FALSE;
829 
830  return SCIP_OKAY;
831 }
832 
833 /** callback method for variable removal in expression graph */
834 static
835 SCIP_DECL_EXPRGRAPHVARREMOVE( exprgraphVarRemove )
836 {
838  SCIP_VAR* var_;
839 
840  assert(exprgraph != NULL);
841  assert(var != NULL);
842  assert(varnode != NULL);
843 
844  var_ = (SCIP_VAR*)var;
845 
846  conshdlrdata = (SCIP_CONSHDLRDATA*)userdata;
847  assert(conshdlrdata != NULL);
848  assert(conshdlrdata->exprgraph == exprgraph);
849 
850  SCIP_CALL( SCIPdropVarEvent(conshdlrdata->scip, var_, SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED, conshdlrdata->nonlinvareventhdlr, (SCIP_EVENTDATA*)varnode, -1) );
851  SCIPdebugMessage("drop boundchange events on expression graph variable <%s>\n", SCIPvarGetName(var_));
852 
853  SCIP_CALL( SCIPaddVarLocks(conshdlrdata->scip, var_, -1, -1) );
854  SCIPdebugMessage("decreased up- and downlocks of variable <%s>\n", SCIPvarGetName(var_));
855 
856  SCIPdebugMessage("release variable <%s>\n", SCIPvarGetName(var_));
857  SCIP_CALL( SCIPreleaseVar(conshdlrdata->scip, &var_) );
858 
859  return SCIP_OKAY;
860 }
861 
862 /* adds expression trees to constraint */
863 static
865  SCIP* scip, /**< SCIP data structure */
866  SCIP_CONSDATA* consdata, /**< nonlinear constraint data */
867  int nexprtrees, /**< number of expression trees */
868  SCIP_EXPRTREE** exprtrees, /**< expression trees */
869  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
870  SCIP_Bool copytrees /**< whether trees should be copied or ownership should be assumed */
871  )
872 {
873  int i;
874 
875  assert(scip != NULL);
876  assert(consdata != NULL);
877  assert(consdata->exprtrees != NULL || consdata->nexprtrees == 0);
878 
879  if( nexprtrees == 0 )
880  return SCIP_OKAY;
881 
882  /* invalidate activity information */
883  consdata->activity = SCIP_INVALID;
884 
885  /* invalidate nonlinear row */
886  if( consdata->nlrow != NULL )
887  {
888  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
889  }
890 
891  consdata->ispresolved = FALSE;
892  consdata->curvature = SCIP_EXPRCURV_UNKNOWN;
893  consdata->iscurvchecked = FALSE;
894 
895  if( consdata->nexprtrees == 0 )
896  {
897  assert(consdata->exprtrees == NULL);
898  assert(consdata->nonlincoefs == NULL);
899  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->exprtrees, nexprtrees) );
900  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->nonlincoefs, nexprtrees) );
901  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->curvatures, nexprtrees) );
902  }
903  else
904  {
905  assert(consdata->exprtrees != NULL);
906  assert(consdata->nonlincoefs != NULL);
907  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->exprtrees, consdata->nexprtrees, consdata->nexprtrees + nexprtrees) );
908  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->nonlincoefs, consdata->nexprtrees, consdata->nexprtrees + nexprtrees) );
909  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->curvatures, consdata->nexprtrees, consdata->nexprtrees + nexprtrees) );
910  }
911 
912  for( i = 0; i < nexprtrees; ++i )
913  {
914  assert(exprtrees[i] != NULL);
915  /* the expression tree need to have SCIP_VAR*'s stored */
916  assert(SCIPexprtreeGetNVars(exprtrees[i]) == 0 || SCIPexprtreeGetVars(exprtrees[i]) != NULL);
917 
918  if( copytrees )
919  {
920  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &consdata->exprtrees[consdata->nexprtrees + i], exprtrees[i]) );
921  }
922  else
923  {
924  consdata->exprtrees[consdata->nexprtrees + i] = exprtrees[i];
925  }
926 
927  consdata->nonlincoefs[consdata->nexprtrees + i] = (coefs != NULL ? coefs[i] : 1.0);
928  consdata->curvatures[consdata->nexprtrees + i] = SCIP_EXPRCURV_UNKNOWN;
929  }
930  consdata->nexprtrees += nexprtrees;
931 
932  return SCIP_OKAY;
933 }
934 
935 /* sets expression trees of constraints, clears previously ones */
936 static
938  SCIP* scip, /**< SCIP data structure */
939  SCIP_CONSDATA* consdata, /**< nonlinear constraint data */
940  int nexprtrees, /**< number of expression trees */
941  SCIP_EXPRTREE** exprtrees, /**< expression trees */
942  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
943  SCIP_Bool copytrees /**< whether trees should be copied or ownership should be assumed */
944  )
945 {
946  int i;
947 
948  assert(scip != NULL);
949  assert(consdata != NULL);
950  assert(consdata->exprtrees != NULL || consdata->nexprtrees == 0);
951 
952  /* clear existing expression trees */
953  if( consdata->nexprtrees > 0 )
954  {
955  for( i = 0; i < consdata->nexprtrees; ++i )
956  {
957  assert(consdata->exprtrees[i] != NULL);
958  SCIP_CALL( SCIPexprtreeFree(&consdata->exprtrees[i]) );
959  }
960 
961  /* invalidate activity information */
962  consdata->activity = SCIP_INVALID;
963 
964  /* invalidate nonlinear row */
965  if( consdata->nlrow != NULL )
966  {
967  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
968  }
969 
970  consdata->ispresolved = FALSE;
971  consdata->curvature = SCIP_EXPRCURV_LINEAR;
972  consdata->iscurvchecked = TRUE;
973 
974  SCIPfreeBlockMemoryArray(scip, &consdata->exprtrees, consdata->nexprtrees);
975  SCIPfreeBlockMemoryArray(scip, &consdata->nonlincoefs, consdata->nexprtrees);
976  SCIPfreeBlockMemoryArray(scip, &consdata->curvatures, consdata->nexprtrees);
977  consdata->nexprtrees = 0;
978  }
979 
980  SCIP_CALL( consdataAddExprtrees(scip, consdata, nexprtrees, exprtrees, coefs, copytrees) );
981 
982  return SCIP_OKAY;
983 }
984 
985 /** ensures, that linear vars and coefs arrays can store at least num entries */
986 static
988  SCIP* scip, /**< SCIP data structure */
989  SCIP_CONSDATA* consdata, /**< nonlinear constraint data */
990  int num /**< minimum number of entries to store */
991  )
992 {
993  assert(scip != NULL);
994  assert(consdata != NULL);
995  assert(consdata->nlinvars <= consdata->linvarssize);
996 
997  if( num > consdata->linvarssize )
998  {
999  int newsize;
1000 
1001  newsize = SCIPcalcMemGrowSize(scip, num);
1002  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1003  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1004  if( consdata->lineventdata != NULL )
1005  {
1006  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1007  }
1008  consdata->linvarssize = newsize;
1009  }
1010  assert(num <= consdata->linvarssize);
1011 
1012  return SCIP_OKAY;
1013 }
1014 
1015 /** creates constraint data structure */
1016 static
1018  SCIP* scip, /**< SCIP data structure */
1019  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1020  SCIP_Real lhs, /**< left hand side of constraint */
1021  SCIP_Real rhs, /**< right hand side of constraint */
1022  int nlinvars, /**< number of linear variables */
1023  SCIP_VAR** linvars, /**< array of linear variables */
1024  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1025  int nexprtrees, /**< number of expression trees */
1026  SCIP_EXPRTREE** exprtrees, /**< expression trees */
1027  SCIP_Real* nonlincoefs, /**< coefficients of expression trees */
1028  SCIP_Bool capturevars /**< whether we should capture variables */
1029  )
1030 {
1031  int i;
1032 
1033  assert(scip != NULL);
1034  assert(consdata != NULL);
1035 
1036  assert(nlinvars == 0 || linvars != NULL);
1037  assert(nlinvars == 0 || lincoefs != NULL);
1038  assert(nexprtrees == 0 || exprtrees != NULL);
1039  assert(nexprtrees == 0 || nonlincoefs != NULL);
1040 
1041  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1042  BMSclearMemory(*consdata);
1043 
1044  (*consdata)->minlinactivity = SCIP_INVALID;
1045  (*consdata)->maxlinactivity = SCIP_INVALID;
1046  (*consdata)->minlinactivityinf = -1;
1047  (*consdata)->maxlinactivityinf = -1;
1048 
1049  (*consdata)->lhs = lhs;
1050  (*consdata)->rhs = rhs;
1051 
1052  if( nlinvars > 0 )
1053  {
1054  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1055  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1056  (*consdata)->nlinvars = nlinvars;
1057  (*consdata)->linvarssize = nlinvars;
1058 
1059  if( capturevars )
1060  for( i = 0; i < nlinvars; ++i )
1061  {
1062  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1063  }
1064  }
1065  else
1066  {
1067  (*consdata)->linvarssorted = TRUE;
1068  (*consdata)->linvarsmerged = TRUE;
1069  }
1070 
1071  SCIP_CALL( consdataSetExprtrees(scip, *consdata, nexprtrees, exprtrees, nonlincoefs, TRUE) );
1072 
1073  (*consdata)->linvar_maydecrease = -1;
1074  (*consdata)->linvar_mayincrease = -1;
1075 
1076  (*consdata)->activity = SCIP_INVALID;
1077  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1078  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1079 
1080  return SCIP_OKAY;
1081 }
1082 
1083 /** creates empty constraint data structure */
1084 static
1086  SCIP* scip, /**< SCIP data structure */
1087  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1088  )
1089 {
1090  assert(scip != NULL);
1091  assert(consdata != NULL);
1092 
1093  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1094  BMSclearMemory(*consdata);
1095 
1096  (*consdata)->lhs = -SCIPinfinity(scip);
1097  (*consdata)->rhs = SCIPinfinity(scip);
1098 
1099  (*consdata)->linvarssorted = TRUE;
1100  (*consdata)->linvarsmerged = TRUE;
1101 
1102  (*consdata)->isremovedfixingslin = TRUE;
1103 
1104  (*consdata)->linvar_maydecrease = -1;
1105  (*consdata)->linvar_mayincrease = -1;
1106 
1107  (*consdata)->minlinactivity = SCIP_INVALID;
1108  (*consdata)->maxlinactivity = SCIP_INVALID;
1109  (*consdata)->minlinactivityinf = -1;
1110  (*consdata)->maxlinactivityinf = -1;
1111 
1112  (*consdata)->curvature = SCIP_EXPRCURV_LINEAR;
1113  (*consdata)->iscurvchecked = TRUE;
1114 
1115  (*consdata)->ncuts = 0;
1116 
1117  return SCIP_OKAY;
1118 }
1119 
1120 /** frees constraint data structure */
1121 static
1123  SCIP* scip, /**< SCIP data structure */
1124  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1125  )
1126 {
1127  int i;
1128 
1129  assert(scip != NULL);
1130  assert(consdata != NULL);
1131  assert(*consdata != NULL);
1132 
1133  /* release linear variables and free linear part */
1134  if( (*consdata)->linvarssize > 0 )
1135  {
1136  for( i = 0; i < (*consdata)->nlinvars; ++i )
1137  {
1138  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1139  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1140  }
1141  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1142  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1143  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1144  }
1145  assert((*consdata)->linvars == NULL);
1146  assert((*consdata)->lincoefs == NULL);
1147  assert((*consdata)->lineventdata == NULL);
1148 
1149  if( (*consdata)->nexprtrees > 0 )
1150  {
1151  assert((*consdata)->exprtrees != NULL);
1152  assert((*consdata)->nonlincoefs != NULL);
1153  assert((*consdata)->curvatures != NULL);
1154  for( i = 0; i < (*consdata)->nexprtrees; ++i )
1155  {
1156  assert((*consdata)->exprtrees[i] != NULL);
1157  SCIP_CALL( SCIPexprtreeFree(&(*consdata)->exprtrees[i]) );
1158  assert((*consdata)->exprtrees[i] == NULL);
1159  }
1160  SCIPfreeBlockMemoryArray(scip, &(*consdata)->exprtrees, (*consdata)->nexprtrees);
1161  SCIPfreeBlockMemoryArray(scip, &(*consdata)->nonlincoefs, (*consdata)->nexprtrees);
1162  SCIPfreeBlockMemoryArray(scip, &(*consdata)->curvatures, (*consdata)->nexprtrees);
1163  }
1164  assert((*consdata)->exprtrees == NULL);
1165  assert((*consdata)->nonlincoefs == NULL);
1166  assert((*consdata)->curvatures == NULL);
1167 
1168  /* free nonlinear row representation */
1169  if( (*consdata)->nlrow != NULL )
1170  {
1171  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1172  }
1173 
1174  SCIPfreeBlockMemory(scip, consdata);
1175  *consdata = NULL;
1176 
1177  return SCIP_OKAY;
1178 }
1179 
1180 /** sorts linear part of constraint data */
1181 static
1183  SCIP_CONSDATA* consdata /**< nonlinear constraint data */
1184  )
1185 {
1186  assert(consdata != NULL);
1187 
1188  if( consdata->linvarssorted )
1189  return;
1190 
1191  if( consdata->nlinvars <= 1 )
1192  {
1193  consdata->linvarssorted = TRUE;
1194  return;
1195  }
1196 
1197  if( consdata->lineventdata == NULL )
1198  {
1199  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1200  }
1201  else
1202  {
1203  int i;
1204 
1205  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1206 
1207  /* update variable indices in event data */
1208  for( i = 0; i < consdata->nlinvars; ++i )
1209  if( consdata->lineventdata[i] != NULL )
1210  consdata->lineventdata[i]->varidx = i;
1211  }
1212 
1213  consdata->linvarssorted = TRUE;
1214 }
1215 
1216 /* this function is currently not needed, but also to nice to be deleted, so it is only deactivated */
1217 #ifdef SCIP_DISABLED_CODE
1218 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1219 static
1220 int consdataFindLinearVar(
1221  SCIP_CONSDATA* consdata, /**< nonlinear constraint data */
1222  SCIP_VAR* var /**< variable to search for */
1223  )
1224 {
1225  int pos;
1226 
1227  assert(consdata != NULL);
1228  assert(var != NULL);
1229 
1230  if( consdata->nlinvars == 0 )
1231  return -1;
1232 
1233  consdataSortLinearVars(consdata);
1234 
1235  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1236  pos = -1;
1237 
1238  return pos;
1239 }
1240 #endif
1241 
1242 /** moves a linear variable from one position to another */
1243 static
1245  SCIP_CONSDATA* consdata, /**< constraint data */
1246  int oldpos, /**< position of variable that shall be moved */
1247  int newpos /**< new position of variable */
1248  )
1249 {
1250  assert(consdata != NULL);
1251  assert(oldpos >= 0);
1252  assert(oldpos < consdata->nlinvars);
1253  assert(newpos >= 0);
1254  assert(newpos < consdata->linvarssize);
1255 
1256  if( newpos == oldpos )
1257  return;
1258 
1259  consdata->linvars [newpos] = consdata->linvars [oldpos];
1260  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1261 
1262  if( consdata->lineventdata != NULL )
1263  {
1264  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1265 
1266  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1267  consdata->lineventdata[newpos]->varidx = newpos;
1268 
1269  consdata->lineventdata[oldpos] = NULL;
1270  }
1271 
1272  consdata->linvarssorted = FALSE;
1273 }
1274 
1275 /** adds linear coefficient in nonlinear constraint */
1276 static
1278  SCIP* scip, /**< SCIP data structure */
1279  SCIP_CONS* cons, /**< nonlinear constraint */
1280  SCIP_VAR* var, /**< variable of constraint entry */
1281  SCIP_Real coef /**< coefficient of constraint entry */
1282  )
1283 {
1284  SCIP_CONSDATA* consdata;
1285  SCIP_Bool transformed;
1286 
1287  assert(scip != NULL);
1288  assert(cons != NULL);
1289  assert(var != NULL);
1290 
1291  /* ignore coefficient if it is nearly zero */
1292  if( SCIPisZero(scip, coef) )
1293  return SCIP_OKAY;
1294 
1295  consdata = SCIPconsGetData(cons);
1296  assert(consdata != NULL);
1297 
1298  /* are we in the transformed problem? */
1299  transformed = SCIPconsIsTransformed(cons);
1300 
1301  /* always use transformed variables in transformed constraints */
1302  if( transformed )
1303  {
1304  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1305  }
1306  assert(var != NULL);
1307  assert(transformed == SCIPvarIsTransformed(var));
1308 
1309  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1310  consdata->linvars [consdata->nlinvars] = var;
1311  consdata->lincoefs[consdata->nlinvars] = coef;
1312 
1313  ++consdata->nlinvars;
1314 
1315  /* catch variable events */
1316  if( SCIPconsIsEnabled(cons) )
1317  {
1318  /* catch bound change events of variable */
1319  SCIP_CALL( catchLinearVarEvents(scip, cons, consdata->nlinvars-1) );
1320  }
1321 
1322  /* invalidate activity information */
1323  consdata->activity = SCIP_INVALID;
1324  consdata->minlinactivity = SCIP_INVALID;
1325  consdata->maxlinactivity = SCIP_INVALID;
1326  consdata->minlinactivityinf = -1;
1327  consdata->maxlinactivityinf = -1;
1328 
1329  /* invalidate nonlinear row */
1330  if( consdata->nlrow != NULL )
1331  {
1332  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1333  }
1334 
1335  /* install rounding locks for new variable */
1336  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1337 
1338  /* capture new variable */
1339  SCIP_CALL( SCIPcaptureVar(scip, var) );
1340 
1341  consdata->ispresolved = FALSE;
1342  consdata->isremovedfixingslin = consdata->isremovedfixingslin && SCIPvarIsActive(var);
1343  if( consdata->nlinvars == 1 )
1344  consdata->linvarssorted = TRUE;
1345  else
1346  consdata->linvarssorted = consdata->linvarssorted &&
1347  (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1348  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1349  consdata->linvarsmerged = FALSE;
1350 
1351  return SCIP_OKAY;
1352 }
1353 
1354 /** deletes linear coefficient at given position from nonlinear constraint data */
1355 static
1357  SCIP* scip, /**< SCIP data structure */
1358  SCIP_CONS* cons, /**< nonlinear constraint */
1359  int pos /**< position of coefficient to delete */
1360  )
1361 {
1362  SCIP_CONSDATA* consdata;
1363  SCIP_VAR* var;
1364  SCIP_Real coef;
1365 
1366  assert(scip != NULL);
1367  assert(cons != NULL);
1368 
1369  consdata = SCIPconsGetData(cons);
1370  assert(consdata != NULL);
1371  assert(0 <= pos && pos < consdata->nlinvars);
1372 
1373  var = consdata->linvars[pos];
1374  coef = consdata->lincoefs[pos];
1375  assert(var != NULL);
1376 
1377  /* remove rounding locks for deleted variable */
1378  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1379 
1380  /* if constraint is enabled, drop the events on the variable */
1381  if( SCIPconsIsEnabled(cons) )
1382  {
1383  /* drop bound change events of variable */
1384  SCIP_CALL( dropLinearVarEvents(scip, cons, pos) );
1385  }
1386 
1387  /* release variable */
1388  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
1389 
1390  /* move the last variable to the free slot */
1391  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
1392 
1393  --consdata->nlinvars;
1394 
1395  /* invalidate activity */
1396  consdata->activity = SCIP_INVALID;
1397  consdata->minlinactivity = SCIP_INVALID;
1398  consdata->maxlinactivity = SCIP_INVALID;
1399  consdata->minlinactivityinf = -1;
1400  consdata->maxlinactivityinf = -1;
1401 
1402  /* invalidate nonlinear row */
1403  if( consdata->nlrow != NULL )
1404  {
1405  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1406  }
1407 
1408  consdata->ispresolved = FALSE;
1409 
1410  return SCIP_OKAY;
1411 }
1412 
1413 /** changes linear coefficient value at given position of nonlinear constraint */
1414 static
1416  SCIP* scip, /**< SCIP data structure */
1417  SCIP_CONS* cons, /**< nonlinear constraint */
1418  int pos, /**< position of linear coefficient to change */
1419  SCIP_Real newcoef /**< new value of linear coefficient */
1420  )
1421 {
1422  SCIP_CONSDATA* consdata;
1423  SCIP_VAR* var;
1424  SCIP_Real coef;
1425 
1426  assert(scip != NULL);
1427  assert(cons != NULL);
1428  assert(!SCIPisZero(scip, newcoef));
1429 
1430  consdata = SCIPconsGetData(cons);
1431  assert(consdata != NULL);
1432  assert(0 <= pos);
1433  assert(pos < consdata->nlinvars);
1434  assert(!SCIPisZero(scip, newcoef));
1435 
1436  var = consdata->linvars[pos];
1437  coef = consdata->lincoefs[pos];
1438  assert(var != NULL);
1439  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
1440 
1441  /* invalidate activity */
1442  consdata->activity = SCIP_INVALID;
1443  consdata->minlinactivity = SCIP_INVALID;
1444  consdata->maxlinactivity = SCIP_INVALID;
1445  consdata->minlinactivityinf = -1;
1446  consdata->maxlinactivityinf = -1;
1447 
1448  /* invalidate nonlinear row */
1449  if( consdata->nlrow != NULL )
1450  {
1451  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1452  }
1453 
1454  /* if necessary, remove the rounding locks and event catching of the variable */
1455  if( newcoef * coef < 0.0 )
1456  {
1457  if( SCIPconsIsLocked(cons) )
1458  {
1459  assert(SCIPconsIsTransformed(cons));
1460 
1461  /* remove rounding locks for variable with old coefficient */
1462  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1463  }
1464 
1465  if( SCIPconsIsEnabled(cons) )
1466  {
1467  /* drop bound change events of variable */
1468  SCIP_CALL( dropLinearVarEvents(scip, cons, pos) );
1469  }
1470  }
1471 
1472  /* change the coefficient */
1473  consdata->lincoefs[pos] = newcoef;
1474 
1475  /* if necessary, install the rounding locks and event catching of the variable again */
1476  if( newcoef * coef < 0.0 )
1477  {
1478  if( SCIPconsIsLocked(cons) )
1479  {
1480  /* install rounding locks for variable with new coefficient */
1481  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
1482  }
1483 
1484  if( SCIPconsIsEnabled(cons) )
1485  {
1486  /* catch bound change events of variable */
1487  SCIP_CALL( catchLinearVarEvents(scip, cons, pos) );
1488  }
1489  }
1490 
1491  consdata->ispresolved = FALSE;
1492 
1493  return SCIP_OKAY;
1494 }
1495 
1496 
1497 /* merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
1498 static
1500  SCIP* scip, /**< SCIP data structure */
1501  SCIP_CONS* cons /**< nonlinear constraint */
1502  )
1503 {
1504  SCIP_CONSDATA* consdata;
1505  SCIP_Real newcoef;
1506  int i;
1507  int j;
1508 
1509  assert(scip != NULL);
1510  assert(cons != NULL);
1511 
1512  consdata = SCIPconsGetData(cons);
1513 
1514  if( consdata->linvarsmerged )
1515  return SCIP_OKAY;
1516 
1517  if( consdata->nlinvars == 0 )
1518  {
1519  consdata->linvarsmerged = TRUE;
1520  return SCIP_OKAY;
1521  }
1522 
1523  i = 0;
1524  while( i < consdata->nlinvars )
1525  {
1526  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
1527  consdataSortLinearVars(consdata);
1528 
1529  /* sum up coefficients that correspond to variable i */
1530  newcoef = consdata->lincoefs[i];
1531  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
1532  newcoef += consdata->lincoefs[j];
1533  /* delete the additional variables in backward order */
1534  for( j = j-1; j > i; --j )
1535  {
1536  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
1537  }
1538 
1539  /* delete also entry at position i, if it became zero (or was zero before) */
1540  if( SCIPisZero(scip, newcoef) )
1541  {
1542  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
1543  }
1544  else
1545  {
1546  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
1547  ++i;
1548  }
1549  }
1550 
1551  consdata->linvarsmerged = TRUE;
1552 
1553  return SCIP_OKAY;
1554 }
1555 
1556 /** removes fixes (or aggregated) linear variables from a nonlinear constraint */
1557 static
1559  SCIP* scip, /**< SCIP data structure */
1560  SCIP_CONS* cons /**< nonlinearconstraint */
1561  )
1562 {
1563  SCIP_CONSDATA* consdata;
1564  SCIP_Real coef;
1565  SCIP_Real offset;
1566  SCIP_VAR* var;
1567  int i;
1568  int j;
1569 
1570  assert(scip != NULL);
1571  assert(cons != NULL);
1572 
1573  consdata = SCIPconsGetData(cons);
1574 
1575  if( !consdata->isremovedfixingslin )
1576  {
1577  i = 0;
1578  while( i < consdata->nlinvars )
1579  {
1580  var = consdata->linvars[i];
1581 
1582  if( SCIPvarIsActive(var) )
1583  {
1584  ++i;
1585  continue;
1586  }
1587 
1588  coef = consdata->lincoefs[i];
1589  offset = 0.0;
1590 
1591  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
1592 
1593  SCIPdebugMsg(scip, " linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]), coef, SCIPvarGetName(var), offset);
1594 
1595  /* delete previous variable (this will move another variable to position i) */
1596  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
1597 
1598  /* put constant part into bounds */
1599  if( offset != 0.0 )
1600  {
1601  if( !SCIPisInfinity(scip, -consdata->lhs) )
1602  {
1603  consdata->lhs -= offset;
1604  assert(!SCIPisInfinity(scip, REALABS(consdata->lhs)));
1605  }
1606  if( !SCIPisInfinity(scip, consdata->rhs) )
1607  {
1608  consdata->rhs -= offset;
1609  assert(!SCIPisInfinity(scip, REALABS(consdata->rhs)));
1610  }
1611  }
1612 
1613  /* nothing left to do if variable had been fixed */
1614  if( coef == 0.0 )
1615  continue;
1616 
1617  /* if GetProbvar gave a linear variable, just add it
1618  * if it's a multilinear variable, add it's disaggregated variables */
1619  if( SCIPvarIsActive(var) )
1620  {
1621  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
1622  }
1623  else
1624  {
1625  int naggrs;
1626  SCIP_VAR** aggrvars;
1627  SCIP_Real* aggrscalars;
1628  SCIP_Real aggrconstant;
1629 
1630  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
1631 
1632  naggrs = SCIPvarGetMultaggrNVars(var);
1633  aggrvars = SCIPvarGetMultaggrVars(var);
1634  aggrscalars = SCIPvarGetMultaggrScalars(var);
1635  aggrconstant = SCIPvarGetMultaggrConstant(var);
1636 
1637  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
1638 
1639  for( j = 0; j < naggrs; ++j )
1640  {
1641  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
1642  }
1643 
1644  if( aggrconstant != 0.0 )
1645  {
1646  if( !SCIPisInfinity(scip, -consdata->lhs) )
1647  {
1648  consdata->lhs -= coef * aggrconstant;
1649  assert(!SCIPisInfinity(scip, REALABS(consdata->lhs)));
1650  }
1651  if( !SCIPisInfinity(scip, consdata->rhs) )
1652  {
1653  consdata->rhs -= coef * aggrconstant;
1654  assert(!SCIPisInfinity(scip, REALABS(consdata->rhs)));
1655  }
1656  }
1657  }
1658  }
1659 
1660  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
1661 
1662  consdata->isremovedfixingslin = TRUE;
1663  }
1664 
1665  SCIPdebugMsg(scip, "removed fixations of linear variables from <%s>\n -> ", SCIPconsGetName(cons));
1666  SCIPdebugPrintCons(scip, cons, NULL);
1667 
1668 #ifndef NDEBUG
1669  for( i = 0; i < consdata->nlinvars; ++i )
1670  assert(SCIPvarIsActive(consdata->linvars[i]));
1671 #endif
1672 
1673  return SCIP_OKAY;
1674 }
1675 
1676 /** removes fixed variables from expression graph */
1677 static
1679  SCIP* scip, /**< SCIP data structure */
1680  SCIP_CONSHDLR* conshdlr /**< constraint handler */
1681  )
1682 {
1684  SCIP_VAR* var;
1685  SCIP_VAR** vars;
1686  SCIP_Real* coefs;
1687  int nvars;
1688  int varssize;
1689  SCIP_Real constant;
1690  int i;
1691  int requsize;
1692  SCIPdebug( int j );
1693 
1694  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1695  assert(conshdlrdata != NULL);
1696  assert(conshdlrdata->exprgraph != NULL);
1697 
1698  if( conshdlrdata->isremovedfixings )
1699  return SCIP_OKAY;
1700 
1701  varssize = 5;
1702  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
1703  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, varssize) );
1704 
1705  i = 0;
1706  while( i < SCIPexprgraphGetNVars(conshdlrdata->exprgraph) )
1707  {
1708  var = (SCIP_VAR*)SCIPexprgraphGetVars(conshdlrdata->exprgraph)[i];
1709  if( SCIPvarIsActive(var) )
1710  {
1711  ++i;
1712  continue;
1713  }
1714 
1715  do
1716  {
1717  vars[0] = var;
1718  coefs[0] = 1.0;
1719  constant = 0.0;
1720  nvars = 1;
1721  SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, coefs, &nvars, varssize, &constant, &requsize, TRUE) );
1722 
1723  if( requsize > varssize )
1724  {
1725  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requsize) );
1726  SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, requsize) );
1727  varssize = requsize;
1728  continue;
1729  }
1730 
1731  }
1732  while( FALSE );
1733 
1734 #ifdef SCIP_DEBUG
1735  SCIPdebugMsg(scip, "replace fixed variable <%s> by %g", SCIPvarGetName(var), constant);
1736  for( j = 0; j < nvars; ++j )
1737  {
1738  SCIPdebugMsgPrint(scip, " %+g <%s>", coefs[j], SCIPvarGetName(vars[j]));
1739  }
1740  SCIPdebugMsgPrint(scip, "\n");
1741 #endif
1742 
1743  SCIP_CALL( SCIPexprgraphReplaceVarByLinearSum(conshdlrdata->exprgraph, var, nvars, coefs, (void**)vars, constant) );
1744 
1745  i = 0;
1746  }
1747 
1748  SCIPfreeBufferArray(scip, &vars);
1749  SCIPfreeBufferArray(scip, &coefs);
1750 
1751  conshdlrdata->isremovedfixings = TRUE;
1752 
1753  return SCIP_OKAY;
1754 }
1755 
1756 /** moves constant and linear part from expression graph node into constraint sides and linear part
1757  * frees expression graph node if expression is constant or linear */
1758 static
1760  SCIP* scip, /**< SCIP data structure */
1761  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1762  SCIP_CONS* cons, /**< nonlinear constraint */
1763  SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
1764  )
1765 {
1767  SCIP_CONSDATA* consdata;
1768  SCIP_VAR** linvars;
1769  SCIP_Real* lincoefs;
1770  SCIP_Real constant;
1771  int linvarssize;
1772  int nlinvars;
1773  int i;
1774 
1775  assert(scip != NULL);
1776  assert(conshdlr != NULL);
1777  assert(cons != NULL);
1778 
1779  consdata = SCIPconsGetData(cons);
1780  assert(consdata != NULL);
1781 
1782  *infeasible = FALSE;
1783 
1784  if( consdata->exprgraphnode == NULL )
1785  return SCIP_OKAY;
1786 
1787  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1788  assert(conshdlrdata != NULL);
1789  assert(conshdlrdata->exprgraph != NULL);
1790 
1791  /* number of children of expression graph node is a good upper estimate on number of linear variables */
1792  linvarssize = MAX(SCIPexprgraphGetNodeNChildren(consdata->exprgraphnode), 1); /*lint !e666*/
1793  SCIP_CALL( SCIPallocBufferArray(scip, &linvars, linvarssize) );
1794  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, linvarssize) );
1795 
1796  /* get linear and constant part from expression graph node
1797  * releases expression graph node if not uses otherwise */
1798  SCIP_CALL( SCIPexprgraphNodeSplitOffLinear(conshdlrdata->exprgraph, &consdata->exprgraphnode, linvarssize, &nlinvars, (void**)linvars, lincoefs, &constant) );
1799 
1800  if( SCIPisInfinity(scip, constant) )
1801  {
1802  if( !SCIPisInfinity(scip, -consdata->lhs) )
1803  {
1804  /* setting constraint lhs to -infinity; this may change linear variable locks and events */
1805  for( i = 0; i < consdata->nlinvars; ++i )
1806  {
1807  if( SCIPconsIsLocked(cons) )
1808  {
1809  SCIP_CALL( unlockLinearVariable(scip, cons, consdata->linvars[i], consdata->lincoefs[i]) );
1810  }
1811  if( SCIPconsIsEnabled(cons) )
1812  {
1813  SCIP_CALL( dropLinearVarEvents(scip, cons, i) );
1814  }
1815  }
1816 
1817  consdata->lhs = -SCIPinfinity(scip);
1818 
1819  for( i = 0; i < consdata->nlinvars; ++i )
1820  {
1821  if( SCIPconsIsEnabled(cons) )
1822  {
1823  SCIP_CALL( catchLinearVarEvents(scip, cons, i) );
1824  }
1825  if( SCIPconsIsLocked(cons) )
1826  {
1827  SCIP_CALL( lockLinearVariable(scip, cons, consdata->linvars[i], consdata->lincoefs[i]) );
1828  }
1829  }
1830  }
1831 
1832  if( !SCIPisInfinity(scip, consdata->rhs) )
1833  {
1834  *infeasible = TRUE;
1835  goto TERMINATE;
1836  }
1837  }
1838  else if( SCIPisInfinity(scip, -constant) )
1839  {
1840  if( !SCIPisInfinity(scip, consdata->rhs) )
1841  {
1842  /* setting constraint rhs to infinity; this may change linear variable locks and events */
1843  for( i = 0; i < consdata->nlinvars; ++i )
1844  {
1845  if( SCIPconsIsLocked(cons) )
1846  {
1847  SCIP_CALL( unlockLinearVariable(scip, cons, consdata->linvars[i], consdata->lincoefs[i]) );
1848  }
1849  if( SCIPconsIsEnabled(cons) )
1850  {
1851  SCIP_CALL( dropLinearVarEvents(scip, cons, i) );
1852  }
1853  }
1854 
1855  consdata->rhs = SCIPinfinity(scip);
1856 
1857  for( i = 0; i < consdata->nlinvars; ++i )
1858  {
1859  if( SCIPconsIsEnabled(cons) )
1860  {
1861  SCIP_CALL( catchLinearVarEvents(scip, cons, i) );
1862  }
1863  if( SCIPconsIsLocked(cons) )
1864  {
1865  SCIP_CALL( lockLinearVariable(scip, cons, consdata->linvars[i], consdata->lincoefs[i]) );
1866  }
1867  }
1868  }
1869  if( !SCIPisInfinity(scip, -consdata->lhs) )
1870  {
1871  *infeasible = TRUE;
1872  goto TERMINATE;
1873  }
1874  }
1875  else if( constant != 0.0 )
1876  {
1877  if( !SCIPisInfinity(scip, -consdata->lhs) )
1878  {
1879  consdata->lhs -= constant;
1880  assert(!SCIPisInfinity(scip, REALABS(consdata->lhs)));
1881  }
1882  if( !SCIPisInfinity(scip, consdata->rhs) )
1883  {
1884  consdata->rhs -= constant;
1885  assert(!SCIPisInfinity(scip, REALABS(consdata->rhs)));
1886  }
1887  }
1888 
1889 TERMINATE:
1890  for( i = 0; i < nlinvars; ++i )
1891  {
1892  SCIP_CALL( addLinearCoef(scip, cons, linvars[i], lincoefs[i]) );
1893  }
1894 
1895  SCIPfreeBufferArray(scip, &linvars);
1896  SCIPfreeBufferArray(scip, &lincoefs);
1897 
1898  /* @todo linear variables that are also children of exprgraphnode could be moved into the expression graph for certain nonlinear operators (quadratic, polynomial), since that may allow better bound tightening */
1899 
1900  return SCIP_OKAY;
1901 }
1902 
1903 /** create a nonlinear row representation of the constraint and stores them in consdata */
1904 static
1906  SCIP* scip, /**< SCIP data structure */
1907  SCIP_CONS* cons /**< nonlinear constraint */
1908  )
1909 {
1910  SCIP_CONSDATA* consdata;
1911 
1912  assert(scip != NULL);
1913  assert(cons != NULL);
1914 
1915  consdata = SCIPconsGetData(cons);
1916  assert(consdata != NULL);
1917 
1918  if( consdata->nlrow != NULL )
1919  {
1920  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1921  }
1922 
1923  if( consdata->nexprtrees == 0 )
1924  {
1925  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
1926  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
1927  0, NULL, 0, NULL,
1928  NULL, consdata->lhs, consdata->rhs,
1929  consdata->curvature) );
1930  }
1931  else if( consdata->nexprtrees == 1 && consdata->nonlincoefs[0] == 1.0 )
1932  {
1933  assert(consdata->exprtrees[0] != NULL);
1934  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
1935  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
1936  0, NULL, 0, NULL,
1937  consdata->exprtrees[0], consdata->lhs, consdata->rhs,
1938  consdata->curvature) );
1939  }
1940  else
1941  {
1942  /* since expression trees may share variable, we cannot easily sum them up,
1943  * but we can request a single expression tree from the expression graph
1944  */
1946  SCIP_EXPRTREE* exprtree;
1947 
1948  assert(consdata->exprgraphnode != NULL); /* since nexprtrees > 0 */
1949  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
1950  assert(conshdlrdata != NULL);
1951 
1952  SCIP_CALL( SCIPexprgraphGetTree(conshdlrdata->exprgraph, consdata->exprgraphnode, &exprtree) );
1953  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
1954  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
1955  0, NULL, 0, NULL,
1956  exprtree, consdata->lhs, consdata->rhs,
1957  consdata->curvature) );
1958  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
1959  }
1960 
1961  return SCIP_OKAY;
1962 }
1963 
1964 /** tries to automatically convert a nonlinear constraint (or a part of it) into a more specific and more specialized constraint */
1965 static
1967  SCIP* scip, /**< SCIP data structure */
1968  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
1969  SCIP_CONS* cons, /**< source constraint to try to convert */
1970  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
1971  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
1972  int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
1973  )
1974 {
1976  SCIP_CONS** upgdconss;
1977  int upgdconsssize;
1978  int nupgdconss_;
1979  int i;
1980 
1981  assert(scip != NULL);
1982  assert(conshdlr != NULL);
1983  assert(cons != NULL);
1984  assert(!SCIPconsIsModifiable(cons));
1985  assert(upgraded != NULL);
1986  assert(nupgdconss != NULL);
1987  assert(naddconss != NULL);
1988 
1989  *upgraded = FALSE;
1990 
1991  nupgdconss_ = 0;
1992 
1993  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1994  assert(conshdlrdata != NULL);
1995 
1996  /* if there are no upgrade methods, we can stop */
1997  if( conshdlrdata->nnlconsupgrades == 0 )
1998  return SCIP_OKAY;
1999 
2000  /* set debug solution in expression graph and evaluate nodes, so reformulation methods can compute debug solution values for new auxiliary variables */
2001 #ifdef SCIP_DEBUG_SOLUTION
2002  if( SCIPdebugIsMainscip(scip) )
2003  {
2004  SCIP_Real* varvals;
2005 
2006  SCIP_CALL( SCIPallocBufferArray(scip, &varvals, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
2007 
2008  for( i = 0; i < SCIPexprgraphGetNVars(conshdlrdata->exprgraph); ++i )
2009  SCIP_CALL( SCIPdebugGetSolVal(scip, (SCIP_VAR*)SCIPexprgraphGetVars(conshdlrdata->exprgraph)[i], &varvals[i]) );
2010 
2011  SCIP_CALL( SCIPexprgraphEval(conshdlrdata->exprgraph, varvals) );
2012 
2013  SCIPfreeBufferArray(scip, &varvals);
2014  }
2015 #endif
2016 
2017  upgdconsssize = 2;
2018  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
2019 
2020  /* call the upgrading methods */
2021 
2022  SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods):\n",
2023  SCIPconsGetName(cons), conshdlrdata->nnlconsupgrades);
2024  SCIPdebugPrintCons(scip, cons, NULL);
2025 
2026  /* try all upgrading methods in priority order in case the upgrading step is enable */
2027  for( i = 0; i < conshdlrdata->nnlconsupgrades; ++i )
2028  {
2029  if( !conshdlrdata->nlconsupgrades[i]->active )
2030  continue;
2031  if( conshdlrdata->nlconsupgrades[i]->nlconsupgd == NULL )
2032  continue;
2033 
2034  SCIP_CALL( conshdlrdata->nlconsupgrades[i]->nlconsupgd(scip, cons, &nupgdconss_, upgdconss, upgdconsssize) );
2035 
2036  while( nupgdconss_ < 0 )
2037  {
2038  /* upgrade function requires more memory: resize upgdconss and call again */
2039  assert(-nupgdconss_ > upgdconsssize);
2040  upgdconsssize = -nupgdconss_;
2041  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
2042 
2043  SCIP_CALL( conshdlrdata->nlconsupgrades[i]->nlconsupgd(scip, cons, &nupgdconss_, upgdconss, upgdconsssize) );
2044 
2045  assert(nupgdconss_ != 0);
2046  }
2047 
2048  if( nupgdconss_ > 0 )
2049  {
2050  /* got upgrade */
2051  int j;
2052 
2053  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
2054 
2055  /* add the upgraded constraints to the problem and forget them */
2056  for( j = 0; j < nupgdconss_; ++j )
2057  {
2058  SCIPdebugMsgPrint(scip, "\t");
2059  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
2060 
2061  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
2062  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
2063  }
2064 
2065  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
2066  *nupgdconss += 1;
2067  *naddconss += nupgdconss_ - 1;
2068  *upgraded = TRUE;
2069 
2070  /* delete upgraded constraint */
2071  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
2072  SCIP_CALL( SCIPdelCons(scip, cons) );
2073 
2074  break;
2075  }
2076  }
2077 
2078  SCIPfreeBufferArray(scip, &upgdconss);
2079 
2080  return SCIP_OKAY;
2081 }
2082 
2083 /** checks a nonlinear constraint for convexity and/or concavity */
2084 static
2086  SCIP* scip, /**< SCIP data structure */
2087  SCIP_CONS* cons, /**< nonlinear constraint */
2088  SCIP_Bool expensivechecks, /**< whether also expensive checks should be executed */
2089  SCIP_Bool assumeconvex /**< whether to assume convexity in inequalities */
2090  )
2091 {
2092  SCIP_CONSDATA* consdata;
2093  SCIP_INTERVAL* varbounds;
2094  int varboundssize;
2095  SCIP_VAR* var;
2096  int i;
2097  int j;
2098 
2099  assert(scip != NULL);
2100  assert(cons != NULL);
2101 
2102  consdata = SCIPconsGetData(cons);
2103  assert(consdata != NULL);
2104 
2105  if( consdata->iscurvchecked )
2106  return SCIP_OKAY;
2107 
2108  SCIPdebugMsg(scip, "Checking curvature of constraint <%s>\n", SCIPconsGetName(cons));
2109 
2110  consdata->curvature = SCIP_EXPRCURV_LINEAR;
2111  consdata->iscurvchecked = TRUE;
2112 
2113  varbounds = NULL;
2114  varboundssize = 0;
2115 
2116  for( i = 0; i < consdata->nexprtrees; ++i )
2117  {
2118  assert(consdata->exprtrees[i] != NULL);
2119  assert(SCIPexprtreeGetNVars(consdata->exprtrees[i]) > 0 );
2120 
2121  if( assumeconvex )
2122  {
2123  /* for constraints a*f(x) <= rhs, we assume that it is convex */
2124  if( SCIPisInfinity(scip, -consdata->lhs) )
2125  consdata->curvatures[i] = SCIP_EXPRCURV_CONVEX;
2126 
2127  /* for constraints lhs <= a*f(x), we assume that it is concave */
2128  if( SCIPisInfinity(scip, consdata->rhs) )
2129  consdata->curvatures[i] = SCIP_EXPRCURV_CONCAVE;
2130  }
2131  else
2132  {
2133  if( varboundssize == 0 )
2134  {
2135  SCIP_CALL( SCIPallocBufferArray(scip, &varbounds, SCIPexprtreeGetNVars(consdata->exprtrees[i])) );
2136  varboundssize = SCIPexprtreeGetNVars(consdata->exprtrees[i]);
2137  }
2138  else if( varboundssize < SCIPexprtreeGetNVars(consdata->exprtrees[i]) )
2139  {
2140  SCIP_CALL( SCIPreallocBufferArray(scip, &varbounds, SCIPexprtreeGetNVars(consdata->exprtrees[i])) );
2141  varboundssize = SCIPexprtreeGetNVars(consdata->exprtrees[i]);
2142  }
2143  assert(varbounds != NULL);
2144 
2145  for( j = 0; j < SCIPexprtreeGetNVars(consdata->exprtrees[i]); ++j )
2146  {
2147  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[j];
2148  SCIPintervalSetBounds(&varbounds[j],
2149  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -MIN(SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var))), /*lint !e666*/
2150  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, MAX(SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var))) ); /*lint !e666*/
2151  }
2152 
2153  SCIP_CALL( SCIPexprtreeCheckCurvature(consdata->exprtrees[i], INTERVALINFTY, varbounds, &consdata->curvatures[i], NULL) );
2154  consdata->curvatures[i] = SCIPexprcurvMultiply(consdata->nonlincoefs[i], consdata->curvatures[i]);
2155 
2156  if( consdata->curvatures[i] == SCIP_EXPRCURV_UNKNOWN && SCIPconshdlrGetData(SCIPconsGetHdlr(cons))->isreformulated && SCIPexprGetOperator(SCIPexprtreeGetRoot(consdata->exprtrees[i])) != SCIP_EXPR_USER )
2157  {
2158  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "indefinite expression tree in constraint <%s>\n", SCIPconsGetName(cons));
2159  SCIPdebug( SCIP_CALL( SCIPexprtreePrintWithNames(consdata->exprtrees[i], SCIPgetMessagehdlr(scip), NULL) ) );
2160  SCIPdebugMsgPrint(scip, "\n");
2161  }
2162  }
2163 
2164  /* @todo implement some more expensive checks */
2165 
2166  consdata->curvature = SCIPexprcurvAdd(consdata->curvature, consdata->curvatures[i]);
2167 
2168  SCIPdebugMsg(scip, "-> tree %d with coef %g is %s -> nonlinear part is %s\n", i, consdata->nonlincoefs[i], SCIPexprcurvGetName(consdata->curvatures[i]), SCIPexprcurvGetName(consdata->curvature));
2169  }
2170 
2171  SCIPfreeBufferArrayNull(scip, &varbounds);
2172 
2173  return SCIP_OKAY;
2174 } /*lint !e715*/
2175 
2176 /* replaces a node by another node in expression graph
2177  * moves all parents of node to replacement
2178  * replaces all exprgraphnode's in constraints that are node by replacement
2179  * node may be freed, if captured only by given constraints
2180  */
2181 static
2183  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
2184  SCIP_EXPRGRAPHNODE** node, /**< pointer to node to be replaced in expression graph */
2185  SCIP_EXPRGRAPHNODE* replacement, /**< node which takes node's place */
2186  SCIP_CONS** conss, /**< constraints */
2187  int nconss /**< number of constraints */
2188  )
2189 {
2190  SCIP_CONSDATA* consdata;
2191  int c;
2192 
2193  assert(exprgraph != NULL);
2194  assert(node != NULL);
2195  assert(*node != NULL);
2196  assert(replacement != NULL);
2197  assert(conss != NULL || nconss == 0);
2198 
2199  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, node, replacement) );
2200 
2201  /* node was not captured by any constraint */
2202  if( *node == NULL )
2203  return SCIP_OKAY;
2204 
2205  /* if node still exists, then because it is captured by some constraint (it should not have parents anymore)
2206  * thus, look into the given constraints and replace their exprgraphnode by replacement
2207  * @todo may be expensive when this is done more often, esp. when we know that node will not be freed due to an added auxiliary constraint
2208  */
2209  assert(*node == NULL || SCIPexprgraphGetNodeNParents(*node) == 0);
2210  for( c = 0; c < nconss; ++c )
2211  {
2212  assert(conss[c] != NULL); /*lint !e613*/
2213 
2214  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
2215  assert(consdata != NULL);
2216 
2217  if( consdata->exprgraphnode == *node )
2218  {
2219  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &consdata->exprgraphnode) );
2220  consdata->exprgraphnode = replacement;
2221  SCIPexprgraphCaptureNode(replacement);
2222 
2223  /* since we change the node, also the constraint changes, so ensure that it is presolved again */
2224  consdata->ispresolved = FALSE;
2225  }
2226  }
2227  *node = NULL;
2228 
2229  return SCIP_OKAY;
2230 }
2231 
2232 /** creates a new auxiliary variable and a new auxiliary nonlinear constraint connecting the var and a given node
2233  * node is replaced by new new auxiliary variables node in all parents of node in expression graph and in all constraints that use node
2234  */
2235 static
2237  SCIP* scip, /**< SCIP data structure */
2238  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
2239  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
2240  SCIP_CONS** conss, /**< constraints where to update exprgraphnode */
2241  int nconss, /**< number of constraints */
2242  int* naddcons, /**< counter to increase when constraint is added */
2243  SCIP_Bool donotmultaggr /**< whether to mark auxiliary variable as not to multiaggregate */
2244  )
2245 {
2246  char name[SCIP_MAXSTRLEN];
2247  SCIP_VAR* auxvar;
2248  SCIP_CONS* auxcons;
2249  SCIP_EXPRGRAPHNODE* auxvarnode;
2250  SCIP_INTERVAL bounds;
2251  SCIP_Real minusone;
2252  SCIP_Bool cutoff;
2253 
2254  assert(scip != NULL);
2255  assert(exprgraph != NULL);
2256  assert(node != NULL);
2257  assert(naddcons != NULL);
2258  assert(SCIPexprgraphGetNodeDepth(node) >= 1); /* do not turn vars or consts into new vars */
2259 
2260  bounds = SCIPexprgraphGetNodeBounds(node);
2261  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2262 
2263  SCIPdebugMsg(scip, "add auxiliary variable and constraint %s for node %p(%d,%d)\n", name, (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
2264 
2265  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, SCIPintervalGetInf(bounds), SCIPintervalGetSup(bounds), 0.0,
2267  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2268  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, &auxvarnode) );
2269 #ifdef SCIP_DEBUG_SOLUTION
2270  if( SCIPdebugIsMainscip(scip) )
2271  {
2272  /* store debug sol value of node as value for auxvar in debug solution and as value for auxvarnode */
2274  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(node)) );
2275  }
2276 #endif
2277 
2278  if( donotmultaggr )
2279  {
2280  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, auxvar) );
2281  }
2282 
2283  /* set also bounds of auxvarnode to bounds, so it is available for new parent nodes (currently node->parents)
2284  * when updating their curvature information; avoid having to run domain propagation through exprgraph
2285  */
2286  SCIPexprgraphTightenNodeBounds(exprgraph, auxvarnode, bounds, BOUNDTIGHTENING_MINSTRENGTH, INTERVALINFTY, &cutoff);
2287  assert(!cutoff); /* we tightenend bounds from [-inf,+inf] to bounds, this should not be infeasible */
2288 
2289  /* add new constraint auxvar == node */
2290  minusone = -1.0;
2291  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 1, &auxvar, &minusone, node, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
2292  FALSE, FALSE, FALSE, FALSE, FALSE) );
2293  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2294 
2295  /* move parents of node in expression graph to auxvarnode
2296  * replace node by auxvarnode in constraints that use node */
2297  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxvarnode, conss, nconss) );
2298 
2299  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2300  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2301 
2302  ++*naddcons;
2303 
2304  return SCIP_OKAY;
2305 }
2306 
2307 /** ensures that all children of a node have at least a given curvature by adding auxiliary variables */
2308 static
2310  SCIP* scip, /**< SCIP data structure */
2311  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
2312  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
2313  SCIP_EXPRCURV mincurv, /**< minimal desired curvature */
2314  SCIP_CONS** conss, /**< constraints to check whether they use one of the replaced nodes */
2315  int nconss, /**< number of constraints to check */
2316  int* naddcons /**< counter to increase when constraint is added */
2317  )
2318 {
2319  SCIP_EXPRGRAPHNODE* child;
2320  SCIP_Bool needupdate;
2321 
2322  int i;
2323  assert(scip != NULL);
2324  assert(exprgraph != NULL);
2325  assert(node != NULL);
2326  assert(naddcons != NULL);
2327  assert(SCIPexprgraphGetNodeDepth(node) >= 1); /* do not turn vars or consts into new vars */
2328  assert(mincurv != SCIP_EXPRCURV_UNKNOWN); /* this is trivial and makes no sense */
2329 
2330  needupdate = FALSE; /* whether we need to update curvature of node */
2331 
2332  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
2333  {
2334  child = SCIPexprgraphGetNodeChildren(node)[i];
2335  assert(child != NULL);
2336 
2337  if( (SCIPexprgraphGetNodeCurvature(child) & mincurv) != mincurv )
2338  {
2339  SCIPdebugMsg(scip, "add auxiliary variable for child %p(%d,%d) with curvature %s\n",
2341 
2342  SCIP_CALL( reformNode2Var(scip, exprgraph, child, conss, nconss, naddcons, FALSE) );
2343  needupdate = TRUE;
2344 
2345  /* i'th child of node should now be a variable */
2346  assert(SCIPexprgraphGetNodeChildren(node)[i] != child);
2348  }
2349 
2350  assert(SCIPexprgraphGetNodeCurvature(SCIPexprgraphGetNodeChildren(node)[i]) & mincurv);
2351  }
2352 
2353  if( needupdate )
2354  {
2357  }
2358 
2359  return SCIP_OKAY;
2360 }
2361 
2362 /** reformulates a monomial by adding auxiliary variables and constraints for bilinear terms */
2363 static
2365  SCIP* scip, /**< SCIP data structure */
2366  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
2367  int nfactors, /**< number of factors */
2368  SCIP_EXPRGRAPHNODE** factors, /**< factors */
2369  SCIP_Real* exponents, /**< exponents, or NULL if all 1.0 */
2370  SCIP_EXPRGRAPHNODE** resultnode, /**< buffer to store node which represents the reformulated monomial */
2371  SCIP_Bool createauxcons, /**< whether to create auxiliary var/cons */
2372  int mindepth, /**< minimal depth of new nodes in expression graph, or -1 */
2373  int* naddcons /**< buffer to increase by number of added cons */
2374  )
2375 {
2376  char name[SCIP_MAXSTRLEN];
2377  SCIP_VAR* auxvar;
2378  SCIP_CONS* auxcons;
2379  SCIP_Real minusone;
2380 
2381  assert(scip != NULL);
2382  assert(exprgraph != NULL);
2383  assert(nfactors > 0);
2384  assert(factors != NULL);
2385  assert(resultnode != NULL);
2386  assert(naddcons != NULL);
2387 
2388  /* factors are just one node */
2389  if( nfactors == 1 && (exponents == NULL || exponents[0] == 1.0) )
2390  {
2391  *resultnode = factors[0];
2392  return SCIP_OKAY;
2393  }
2394 
2395  /* only one factor, but with exponent < 0.0 and factor has mixed sign, e.g., x^(-3)
2396  * reformulate as auxvar * factor^(-exponent) = 1 and return the node for auxvar in resultnode
2397  */
2398  if( nfactors == 1 && exponents[0] < 0.0 && SCIPexprgraphGetNodeBounds(factors[0]).inf < 0.0 && SCIPexprgraphGetNodeBounds(factors[0]).sup > 0.0 ) /*lint !e613*/
2399  {
2400  SCIP_EXPRGRAPHNODE* auxnode;
2401  SCIP_EXPRGRAPHNODE* reformfactors[2];
2402  SCIP_Real reformexp[2];
2403 
2404  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2405  SCIPdebugMsg(scip, "add auxiliary variable and constraint %s\n", name);
2406 
2407  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2409  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2410  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, resultnode) );
2411 
2412 #ifdef SCIP_DEBUG_SOLUTION
2413  /* store debug sol value of node as value for auxvar in debug solution and as value for resultnode */
2414  if( SCIPdebugIsMainscip(scip) )
2415  {
2416  SCIP_Real debugval;
2417  debugval = pow(SCIPexprgraphGetNodeVal(factors[0]), exponents[0]);
2418  SCIPexprgraphSetVarNodeValue(*resultnode, debugval);
2419  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
2420  }
2421 #endif
2422 
2423  /* increase naddcons before next call to reformMonomial, to avoid duplicate variable names, which is bad for debugging */
2424  ++*naddcons;
2425 
2426  /* add reformulation for resultnode(=auxvar) * factor^(-exponent) = 1.0
2427  * if exponent != -1.0, then factor^(-exponent) should be moved into extra variable
2428  * finally one should get an EXPR_MUL node */
2429  reformfactors[0] = *resultnode;
2430  reformfactors[1] = factors[0];
2431  reformexp[0] = 1.0;
2432  reformexp[1] = -exponents[0]; /*lint !e613*/
2433  SCIP_CALL( reformMonomial(scip, exprgraph, 2, reformfactors, reformexp, &auxnode, FALSE, mindepth, naddcons) );
2434 
2435  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 0, NULL, NULL, auxnode, 1.0, 1.0,
2436  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
2437  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2438 
2439  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2440  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2441 
2442  return SCIP_OKAY;
2443  }
2444 
2445  /* only one factor, but with exponent != 1.0 */
2446  if( nfactors == 1 )
2447  {
2448  /* create some power expression node, if not existing already */
2449  SCIP_EXPRGRAPHNODE* expnode;
2450  SCIP_EXPRGRAPHNODE* parent;
2451  int p;
2452 
2453  assert(exponents != NULL);
2454 
2455  /* check if there is already a node for factors[0]^exponents[0] */
2456  expnode = NULL;
2457  for( p = 0; p < SCIPexprgraphGetNodeNParents(factors[0]); ++p)
2458  {
2459  parent = SCIPexprgraphGetNodeParents(factors[0])[p];
2460  if( SCIPisIntegral(scip, exponents[0]) &&
2462  SCIPexprgraphGetNodeIntPowerExponent(parent) == (int)SCIPround(scip, exponents[0]) )
2463  {
2464  expnode = parent;
2465  break;
2466  }
2468  SCIPisEQ(scip, SCIPexprgraphGetNodeRealPowerExponent(parent), exponents[0]) )
2469  {
2470  expnode = parent;
2471  }
2472  }
2473  if( expnode == NULL )
2474  {
2475  if( SCIPisIntegral(scip, exponents[0]) )
2476  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &expnode, SCIP_EXPR_INTPOWER, (int)SCIPround(scip, exponents[0])) );
2477  else
2478  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &expnode, SCIP_EXPR_REALPOWER, exponents[0]) );
2479 
2480  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, expnode, mindepth, 1, &factors[0]) );
2483  }
2484 
2485  if( createauxcons )
2486  {
2487  /* @todo if there was already a node for factors[0]^exponents[0], then there may have been also been already an auxiliary variable and constraint (-> ex7_3_4) */
2488  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2489  SCIPdebugMsg(scip, "add auxiliary variable and constraint %s\n", name);
2490 
2491  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2493  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2494  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, resultnode) );
2495 
2496 #ifdef SCIP_DEBUG_SOLUTION
2497  if( SCIPdebugIsMainscip(scip) )
2498  {
2500  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(expnode)) );
2501  }
2502 #endif
2503 
2504  /* add new constraint resultnode(=auxvar) = expnode */
2505  minusone = -1.0;
2506  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 1, &auxvar, &minusone, expnode, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
2507  FALSE, FALSE, FALSE, FALSE, FALSE) );
2508  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2509 
2510  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2511  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2512 
2513  ++*naddcons;
2514  }
2515  else
2516  {
2517  *resultnode = expnode;
2518  }
2519 
2520  return SCIP_OKAY;
2521  }
2522 
2523  if( nfactors == 2 && exponents != NULL && exponents[0] != 1.0 && exponents[0] == exponents[1] ) /*lint !e777*/
2524  {
2525  /* factor0^exponent * factor1^exponent with exponent != 1.0, reform as (factor0*factor1)^exponent */
2526  SCIP_EXPRGRAPHNODE* productnode;
2527 
2528  /* create node for factor0*factor1 */
2529  SCIP_CALL( reformMonomial(scip, exprgraph, 2, factors, NULL, &productnode, TRUE, mindepth, naddcons) );
2530 
2531  /* create node for productnode^exponents[0] by just calling this method again */
2532  SCIP_CALL( reformMonomial(scip, exprgraph, 1, &productnode, &exponents[0], resultnode, createauxcons, mindepth, naddcons) );
2533 
2534  return SCIP_OKAY;
2535  }
2536 
2537  if( nfactors == 2 && exponents != NULL && exponents[0] == -exponents[1] ) /*lint !e777*/
2538  {
2539  /* factor0^exponent * factor1^(-exponent), reform as (factor0/factor1)^exponent or (factor1/factor0)^(-exponent) */
2540  SCIP_EXPRGRAPHNODE* auxvarnode;
2541  SCIP_EXPRGRAPHNODE* auxconsnode;
2542  SCIP_EXPRGRAPHNODE* leftright[2];
2543  SCIP_Real absexp;
2544 
2545  /* create variable and constraint for factor0 = auxvar * factor1 (if exponent > 0) or factor1 = auxvar * factor0 (if exponent < 0) */
2546 
2547  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2548  SCIPdebugMsg(scip, "add auxiliary variable and constraint %s\n", name);
2549 
2550  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2552  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2553  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, &auxvarnode) );
2554 
2555 #ifdef SCIP_DEBUG_SOLUTION
2556  /* store debug sol value of node as value for auxvar in debug solution and as value for resultnode */
2557  if( SCIPdebugIsMainscip(scip) )
2558  {
2559  SCIP_Real debugval;
2560  if( exponents[0] > 0.0 )
2561  debugval = SCIPexprgraphGetNodeVal(factors[0]) / SCIPexprgraphGetNodeVal(factors[1]);
2562  else
2563  debugval = SCIPexprgraphGetNodeVal(factors[1]) / SCIPexprgraphGetNodeVal(factors[0]);
2564  SCIPexprgraphSetVarNodeValue(auxvarnode, debugval);
2565  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
2566  }
2567 #endif
2568 
2569  /* add new constraint resultnode(= auxvar) * factor1 - factor0 == 0 (exponent > 0) or auxvar * factor0 - factor1 == 0 (exponent < 0) */
2570  leftright[0] = auxvarnode;
2571  leftright[1] = exponents[0] > 0.0 ? factors[1] : factors[0];
2572 
2574  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, auxconsnode, -1, 2, leftright) );
2575 
2576  leftright[0] = auxconsnode;
2577  leftright[1] = exponents[0] > 0.0 ? factors[0] : factors[1];
2578 
2580  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, auxconsnode, -1, 2, leftright) );
2581 
2582  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 0, NULL, NULL, auxconsnode, 0.0, 0.0,
2583  TRUE, TRUE, TRUE, TRUE, TRUE,
2584  FALSE, FALSE, FALSE, FALSE, FALSE) );
2585  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2586 
2587  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2588  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2589 
2590  ++*naddcons;
2591 
2592  /* create node for auxvarnode^abs(exponents[0]) by just calling this method again */
2593  absexp = fabs(exponents[0]);
2594  SCIP_CALL( reformMonomial(scip, exprgraph, 1, &auxvarnode, &absexp, resultnode, createauxcons, mindepth, naddcons) );
2595 
2596  return SCIP_OKAY;
2597  }
2598 
2599  /* @todo if nfactors > 2, assemble groups of factors with same exponent and replace these by a single variable first */
2600 
2601  {
2602  /* at least two factors */
2603  /* create auxvar for left half (recursively) and auxvar for right half (recursively) and maybe new auxvar for product */
2604  /* @todo it may be enough to replace single factors in a monomial to get it convex or concave, see Westerlund et.al. */
2605 
2606  SCIP_EXPRGRAPHNODE* productnode;
2607  SCIP_EXPRGRAPHNODE* leftright[2]; /* {left, right} */
2608  SCIP_EXPRGRAPHNODE* parent;
2609  int half;
2610  int p;
2611 
2612  half = nfactors / 2;
2613  assert(half > 0);
2614  assert(half < nfactors);
2615 
2616  SCIP_CALL( reformMonomial(scip, exprgraph, half, factors, exponents, &leftright[0], TRUE, mindepth, naddcons) );
2617  SCIP_CALL( reformMonomial(scip, exprgraph, nfactors-half, &factors[half], exponents != NULL ? &exponents[half] : NULL, &leftright[1], TRUE, mindepth, naddcons) ); /*lint !e826*/
2618 
2619  /* check if there is already a node for left * right */
2620  productnode = NULL;
2621  for( p = 0; p < SCIPexprgraphGetNodeNParents(leftright[0]); ++p)
2622  {
2623  parent = SCIPexprgraphGetNodeParents(factors[0])[p];
2625  continue;
2626 
2627  assert(SCIPexprgraphGetNodeNChildren(parent) == 2);
2628  if( (SCIPexprgraphGetNodeChildren(parent)[0] == leftright[0] && SCIPexprgraphGetNodeChildren(parent)[1] == leftright[1]) ||
2629  ( SCIPexprgraphGetNodeChildren(parent)[0] == leftright[1] && SCIPexprgraphGetNodeChildren(parent)[1] == leftright[0]) )
2630  {
2631  productnode = parent;
2632  break;
2633  }
2634  }
2635  if( productnode == NULL )
2636  {
2637  /* create node for left * right */
2638  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &productnode, SCIP_EXPR_MUL, NULL) );
2639  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, productnode, mindepth, 2, leftright) );
2642  }
2643 
2644  if( createauxcons )
2645  {
2646  /* @todo if there was already a node for factors[0]^exponents[0], then there may have been also been already an auxiliary variable and constraint (-> ex7_3_4) */
2647  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2648  SCIPdebugMsg(scip, "add auxiliary variable and constraint %s\n", name);
2649 
2650  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2651  SCIP_VARTYPE_CONTINUOUS, TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
2652  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2653  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, resultnode) );
2654 
2655 #ifdef SCIP_DEBUG_SOLUTION
2656  if( SCIPdebugIsMainscip(scip) )
2657  {
2658  SCIPexprgraphSetVarNodeValue(*resultnode, SCIPexprgraphGetNodeVal(productnode));
2659  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(productnode)) );
2660  }
2661 #endif
2662 
2663  /* add new constraint resultnode(= auxvar) == left * right */
2664  minusone = -1.0;
2665  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 1, &auxvar, &minusone, productnode, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
2666  FALSE, FALSE, FALSE, FALSE, FALSE) );
2667  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2668 
2669  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2670  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2671 
2672  ++*naddcons;
2673  }
2674  else
2675  {
2676  *resultnode = productnode;
2677  }
2678  }
2679 
2680  return SCIP_OKAY;
2681 }
2682 
2683 /** reformulates expression graph into a form so that for each node under- and overestimators could be computed
2684  * similar to factorable reformulation in other global solvers, but sometimes does not split up complex operands (like quadratic)
2685  */
2686 static
2688  SCIP* scip, /**< SCIP data structure */
2689  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2690  SCIP_CONS** conss, /**< constraints */
2691  int nconss, /**< number of constraints */
2692  int* naddcons /**< buffer to increase by the number of added constraints */
2693  )
2694 {
2696  SCIP_CONSDATA* consdata;
2697  SCIP_EXPRGRAPH* exprgraph;
2698  SCIP_EXPRGRAPHNODE* node;
2699  SCIP_EXPRGRAPHNODE** children;
2700  SCIP_EXPRGRAPHNODE* reformnode;
2701  SCIP_Bool havenonlinparent;
2702  SCIP_Bool domainerror;
2703  int nchildren;
2704  int c;
2705  int d;
2706  int i;
2707  int u;
2708 #ifndef NDEBUG
2709  int j;
2710 #endif
2711 
2712  assert(scip != NULL);
2713  assert(conshdlr != NULL);
2714  assert(conss != NULL || nconss == 0);
2715  assert(naddcons != NULL);
2716  assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING);
2717  assert(!SCIPinProbing(scip));
2718 
2719  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2720  assert(conshdlrdata != NULL);
2721 
2722  if( conshdlrdata->isreformulated )
2723  {
2724  SCIPdebugMsg(scip, "skip reformulation, already done\n");
2725  return SCIP_OKAY;
2726  }
2727 
2728  exprgraph = conshdlrdata->exprgraph;
2729 
2730  /* make sure current variable bounds are variable nodes of exprgraph */
2731  SCIP_CALL( SCIPexprgraphPropagateVarBounds(exprgraph, INTERVALINFTY, FALSE, &domainerror) );
2732  assert(!domainerror); /* should have been found by domain propagation */
2733 
2734  /* set debug solution in expression graph and evaluate nodes, so we can compute debug solution values for auxiliary variables */
2735 #ifdef SCIP_DEBUG_SOLUTION
2736  if( SCIPdebugIsMainscip(scip) )
2737  {
2738  SCIP_Real* varvals;
2739 
2740  SCIP_CALL( SCIPallocBufferArray(scip, &varvals, SCIPexprgraphGetNVars(exprgraph)) );
2741 
2742  for( i = 0; i < SCIPexprgraphGetNVars(exprgraph); ++i )
2743  SCIP_CALL( SCIPdebugGetSolVal(scip, (SCIP_VAR*)SCIPexprgraphGetVars(exprgraph)[i], &varvals[i]) );
2744 
2745  SCIP_CALL( SCIPexprgraphEval(exprgraph, varvals) );
2746 
2747  SCIPfreeBufferArray(scip, &varvals);
2748  }
2749 #endif
2750 
2751  for( d = 1; d < SCIPexprgraphGetDepth(exprgraph); ++d )
2752  {
2753  i = 0;
2754  while( i < SCIPexprgraphGetNNodes(exprgraph)[d] )
2755  {
2756  node = SCIPexprgraphGetNodes(exprgraph)[d][i];
2757  assert(node != NULL);
2758 
2759  /* skip disabled nodes, they should be removed soon */
2760  if( !SCIPexprgraphIsNodeEnabled(node) )
2761  {
2762  ++i;
2763  continue;
2764  }
2765 
2766  /* make sure bounds and curvature of node are uptodate */
2769 
2770  /* try external reformulation methods */
2771  for( u = 0; u < conshdlrdata->nnlconsupgrades; ++u )
2772  {
2773  if( conshdlrdata->nlconsupgrades[u]->nodereform != NULL && conshdlrdata->nlconsupgrades[u]->active )
2774  {
2775  SCIP_CALL( conshdlrdata->nlconsupgrades[u]->nodereform(scip, exprgraph, node, naddcons, &reformnode) );
2776  if( reformnode == NULL )
2777  continue;
2778 
2779  SCIPdebugMsg(scip, "external nodereform reformulated node %p(%d,%d), replace by %p\n",
2780  (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node), (void*)reformnode);
2781 
2782  SCIP_CALL( reformReplaceNode(exprgraph, &node, reformnode, conss, nconss) );
2785 
2786  break;
2787  }
2788  }
2789  /* if node has been reformulated, continue with next node without increasing i */
2790  if( u < conshdlrdata->nnlconsupgrades )
2791  continue;
2792 
2793  /* leave nodes that are known to be convex/concave/linear as they are */
2795  {
2796  SCIPdebugMsg(scip, "skip reformulating node %p(%d,%d) = ", (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
2799  ++i;
2800  continue;
2801  }
2802 
2803  /* get flag whether node has a nonlinear parent
2804  * we want to know whether the current node will be at the top of the tree after the next simplification run
2805  * due to the tricky reformulation of polynomials below, this may not be the case yet
2806  */
2807  havenonlinparent = SCIPexprgraphHasNodeNonlinearAncestor(node);
2808 
2809  /* take action */
2811  SCIPdebugMsg(scip, "think about reformulating %s node %p(%d,%d) = ", SCIPexpropGetName(SCIPexprgraphGetNodeOperator(node)), (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
2813  SCIPdebugMsgPrint(scip, "\n");
2814 
2815  children = SCIPexprgraphGetNodeChildren(node);
2816  nchildren = SCIPexprgraphGetNodeNChildren(node);
2817  assert(children != NULL || nchildren == 0);
2818 
2819 #ifndef NDEBUG
2820  /* at this place, all children nodes should have a known curvature, except if they only appear only linearly in constraints
2821  * the latter for cases where constraints with unknown curvature are upgraded to other constraint handler that can handle these (quadratic, signpower,...)
2822  */
2823  for( j = 0; j < nchildren; ++j )
2824  {
2825  assert(children[j] != NULL); /*lint !e613*/
2826  if( havenonlinparent ||
2831  assert(SCIPexprgraphGetNodeCurvature(children[j]) != SCIP_EXPRCURV_UNKNOWN || SCIPexprgraphGetNodeOperator(children[j]) == SCIP_EXPR_USER); /*lint !e613*/
2832  }
2833 #endif
2834 
2835 
2836  switch( SCIPexprgraphGetNodeOperator(node) )
2837  {
2838  case SCIP_EXPR_VARIDX:
2839  case SCIP_EXPR_PARAM:
2840  case SCIP_EXPR_CONST:
2841  SCIPerrorMessage("node with operator %d cannot have unknown curvature\n", SCIPexprgraphGetNodeOperator(node));
2842  SCIPABORT();
2843  break; /*lint !e527*/
2844 
2845  /* linear operands */
2846  case SCIP_EXPR_PLUS:
2847  case SCIP_EXPR_MINUS:
2848  case SCIP_EXPR_SUM:
2849  case SCIP_EXPR_LINEAR:
2850  /* children have conflicting curvature, we can handle such sums in cons_nonlinear
2851  * thus, turn node into variable, if it has nonlinear parents */
2852  if( havenonlinparent )
2853  {
2854  SCIP_CALL( reformNode2Var(scip, exprgraph, node, conss, nconss, naddcons, FALSE) );
2855  assert(node != NULL);
2856  assert(SCIPexprgraphGetNodeNParents(node) == 0); /* node should now be at top of graph */
2857  }
2858  ++i;
2859  break;
2860 
2861  /* quadratic operands */
2862  case SCIP_EXPR_MUL:
2863  case SCIP_EXPR_QUADRATIC:
2864  {
2865  SCIP_EXPRGRAPHNODE* child;
2866  SCIP_Bool needupdate;
2867 
2868  /* ensure all children are linear, so next simplifier run makes sure all children will be variables (by distributing the product)
2869  * however, that will not work for user-expressions, so we should also ensure that they are none (@todo as they are linear, they could actually be replaced by a regular linear expression)
2870  */
2871  SCIPdebugMessage("ensure children are linear\n");
2872  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_LINEAR, conss, nconss, naddcons) );
2873 
2874  needupdate = FALSE; /* whether we need to update curvature of node */
2875  for( c = 0; c < SCIPexprgraphGetNodeNChildren(node); ++c )
2876  {
2877  child = SCIPexprgraphGetNodeChildren(node)[c];
2878  assert(child != NULL);
2879 
2881  {
2882  SCIPdebugMessage("add auxiliary variable for child %p(%d,%d) with curvature %s operator %s\n",
2884 
2885  SCIP_CALL( reformNode2Var(scip, exprgraph, child, conss, nconss, naddcons, FALSE) );
2886  needupdate = TRUE;
2887 
2888  /* c'th child of node should now be a variable */
2889  assert(SCIPexprgraphGetNodeChildren(node)[c] != child);
2891  }
2892  }
2893  if( needupdate )
2894  {
2897  }
2898 
2900  {
2901  /* if curvature is now known then we are done */
2902  ++i;
2903  break;
2904  }
2905 
2906  /* if we have nonlinear parents or a sibling, then add auxiliary variable for this node, so an upgrade to cons_quadratic should take place
2907  * we assume that siblings are non-linear and non-quadratic, which should be the case if simplifier was run, and also if this node was created during reformulating a polynomial
2908  * @todo we could also add auxvars for the sibling nodes, e.g., if there is only one
2909  * @todo if sibling nodes are quadratic (or even linear) due to reformulation, then we do not need to reform here... (-> nvs16)
2910  * maybe this step should not be done here at all if havenonlinparent is FALSE? e.g., move into upgrade from quadratic?
2911  */
2912  if( havenonlinparent || SCIPexprgraphHasNodeSibling(node) )
2913  {
2914  SCIP_CALL( reformNode2Var(scip, exprgraph, node, conss, nconss, naddcons, FALSE) );
2915  assert(node != NULL);
2916  assert(SCIPexprgraphGetNodeNParents(node) == 0); /* node should now be at top of graph, so it can be upgraded by cons_quadratic */
2917  break;
2918  }
2919 
2920  ++i;
2921  break;
2922  }
2923 
2924  case SCIP_EXPR_DIV:
2925  {
2926  /* reformulate as bilinear term
2927  * note that in the reformulation, a zero in the denominator forces the nominator to be zero too, but the auxiliary can be arbitrary
2928  */
2929  SCIP_EXPRGRAPHNODE* auxvarnode;
2930  SCIP_EXPRGRAPHNODE* auxnode;
2931  SCIP_EXPRGRAPHNODE* auxchildren[3];
2932  SCIP_Real lincoefs[3];
2933  SCIP_QUADELEM quadelem;
2934  SCIP_VAR* auxvar;
2935  SCIP_CONS* auxcons;
2936  char name[SCIP_MAXSTRLEN];
2937  SCIP_INTERVAL bounds;
2938 
2939  assert(children != NULL);
2940  assert(nchildren == 2);
2941 
2942  bounds = SCIPexprgraphGetNodeBounds(node);
2943  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2944 
2945  SCIPdebugMsg(scip, "add auxiliary variable %s for division in node %p(%d,%d)\n", name, (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
2946 
2947  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, SCIPintervalGetInf(bounds), SCIPintervalGetSup(bounds), 0.0,
2949  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2950  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, &auxvarnode) );
2951 
2952 #ifdef SCIP_DEBUG_SOLUTION
2953  if( SCIPdebugIsMainscip(scip) )
2954  {
2955  SCIP_Real debugval;
2956  debugval = SCIPexprgraphGetNodeVal(children[0]) / SCIPexprgraphGetNodeVal(children[1]);
2957  SCIPexprgraphSetVarNodeValue(auxvarnode, debugval);
2958  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
2959  }
2960 #endif
2961 
2962  /* add new constraint auxvar * child[1] - child[0] == 0 */
2963  auxchildren[0] = children[0]; /*lint !e613*/
2964  auxchildren[1] = children[1]; /*lint !e613*/
2965  auxchildren[2] = auxvarnode;
2966 
2967  lincoefs[0] = -1.0;
2968  lincoefs[1] = 0.0;
2969  lincoefs[2] = 0.0;
2970 
2971  quadelem.idx1 = 1;
2972  quadelem.idx2 = 2;
2973  quadelem.coef = 1.0;
2974 
2975  SCIP_CALL( SCIPexprgraphCreateNodeQuadratic(SCIPblkmem(scip), &auxnode, 3, lincoefs, 1, &quadelem, 0.0) );
2976  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, auxnode, -1, 3, auxchildren) );
2977 
2978  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 0, NULL, NULL, auxnode, 0.0, 0.0,
2979  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
2980  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2981 
2982  /* replace node by auxvarnode in graph and constraints that use it */
2983  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxvarnode, conss, nconss) );
2984 
2985  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2986  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2987 
2988  ++*naddcons;
2989 
2990  /* do not increase i, since node was removed and not necessarily replaced here */
2991  break;
2992  }
2993 
2994  case SCIP_EXPR_MIN:
2995  {
2996  /* make sure that both children are concave, because min of concave functions is concave */
2997  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_CONCAVE, conss, nconss, naddcons) );
2999  ++i;
3000  break;
3001  }
3002 
3003  case SCIP_EXPR_MAX:
3004  {
3005  /* make sure that both children are convex, because max of convex functions is convex */
3006  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_CONVEX, conss, nconss, naddcons) );
3008  ++i;
3009  break;
3010 
3011  }
3012 
3013  case SCIP_EXPR_INTPOWER:
3014  {
3015  assert(nchildren == 1);
3016 
3017  /* for an intpower with mixed sign in the base and negative exponent, we reformulate similar as for EXPR_DIV */
3018  if( SCIPexprgraphGetNodeIntPowerExponent(node) < 0 && SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(children[0])) < 0.0 && SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(children[0])) > 0.0 ) /*lint !e613*/
3019  {
3020  SCIP_EXPRGRAPHNODE* auxvarnode;
3021  SCIP_Real exponent;
3022 
3023  /* if we have something like x^(-3) with mixed sign for x, then add auxvar and reform as auxvar*x^3 = 1 via reformMonomial */
3025  SCIP_CALL( reformMonomial(scip, exprgraph, 1, children, &exponent, &auxvarnode, TRUE, SCIPexprgraphGetNodeDepth(node), naddcons) );
3026  /* replace node by auxvarnode */
3027  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxvarnode, conss, nconss) );
3028  break;
3029  }
3030 
3031  /* otherwise, we continue as for other univariate operands */
3032  } /*lint -fallthrough*/
3033 
3034  /* univariate operands where the child does not have bounds and curvature from which we can deduce curvature of this node,
3035  * but where we can do more if the child is linear
3036  * thus, turn child into auxiliary variable
3037  */
3038  case SCIP_EXPR_SQUARE:
3039  case SCIP_EXPR_SQRT:
3040  case SCIP_EXPR_EXP:
3041  case SCIP_EXPR_LOG:
3042  case SCIP_EXPR_ABS:
3043  case SCIP_EXPR_REALPOWER:
3044  case SCIP_EXPR_SIGNPOWER:
3045  {
3046  assert(nchildren == 1);
3047 
3048  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_LINEAR, conss, nconss, naddcons) );
3049 
3051  {
3052  /* the only case where f(x) for a linear term x is indefinite here is if f is intpower or signpower and x has mixed sign */
3054  assert(SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(children[0])) < 0.0); /*lint !e613*/
3055  assert(SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(children[0])) > 0.0); /*lint !e613*/
3056  }
3057 
3058  /* update curvature of node */
3061 
3063  {
3064  /* if intpower and signpower with positive exponent and a mixed sign in the child bounds still does not give a curvature,
3065  * we can do more if we make this node the root of a nonlinear constraints expression node, so it can be upgraded by cons_signpower
3066  * of course, this is only required if the node is still intermediate
3067  *
3068  * an intpower with negative exponent should have been handled above
3069  * for signpower, we assume the exponent is > 1.0
3070  */
3074  if( havenonlinparent )
3075  {
3076  SCIP_CALL( reformNode2Var(scip, exprgraph, node, conss, nconss, naddcons, FALSE) );
3077  assert(node != NULL); /* it should be used by some auxiliary constraint now */
3078  assert(SCIPexprgraphGetNodeNParents(node) == 0); /* node should now be at top of graph (and used by new auxiliary constraint) */
3079  }
3080  }
3081  ++i;
3082 
3083  break;
3084  }
3085 
3086  case SCIP_EXPR_SIN:
3087  case SCIP_EXPR_COS:
3088  case SCIP_EXPR_TAN:
3089  case SCIP_EXPR_SIGN:
3090  /* case SCIP_EXPR_ERF : */
3091  /* case SCIP_EXPR_ERFI : */
3092  {
3093  SCIPerrorMessage("no support for trigonometric or sign operands yet\n");
3094  return SCIP_ERROR;
3095  }
3096 
3097  case SCIP_EXPR_PRODUCT:
3098  {
3099  /* ensure all children are linear */
3100  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_LINEAR, conss, nconss, naddcons) );
3102  {
3103  ++i;
3104  break;
3105  }
3106 
3107  /* if curvature is still unknown (quite likely), then turn into a cascade of bilinear terms
3108  * if node has parents, then ensure that it has a known curvature, otherwise we are also fine with a node that is a product of two (aux)variables */
3109  SCIP_CALL( reformMonomial(scip, exprgraph, nchildren, children, NULL, &reformnode, havenonlinparent, SCIPexprgraphGetNodeDepth(node), naddcons) );
3110 
3111  /* replace node by reformnode in graph and in all constraints that use it */
3112  SCIP_CALL( reformReplaceNode(exprgraph, &node, reformnode, conss, nconss) );
3113 
3114  /* do not increase i, since node was removed and not necessarily replaced here */
3115  break;
3116  }
3117 
3118  case SCIP_EXPR_POLYNOMIAL:
3119  {
3120  /* if polynomial has several monomials, replace by a sum of nodes each having a single monomial and one that has all linear and quadratic monomials
3121  * if polynomial has only a single monomial, then reformulate that one
3122  */
3123  SCIP_EXPRDATA_MONOMIAL** monomials;
3124  SCIP_EXPRDATA_MONOMIAL* monomial;
3125  int nmonomials;
3126  SCIP_Real* exponents;
3127  SCIP_Real coef;
3128  int* childidxs;
3129  int nfactors;
3130  int f;
3131  SCIP_INTERVAL childbounds;
3132  SCIP_EXPRCURV childcurv;
3133  SCIP_Bool modified;
3134 
3135  monomials = SCIPexprgraphGetNodePolynomialMonomials(node);
3136  nmonomials = SCIPexprgraphGetNodePolynomialNMonomials(node);
3137  assert(nmonomials >= 1); /* constant polynomials should have been simplified away */
3138 
3139  if( nmonomials > 1 )
3140  {
3141  SCIP_EXPRGRAPHNODE* sumnode;
3142  SCIP_Real constant;
3143  int nquadelems;
3144  SCIP_QUADELEM* quadelems;
3145  SCIP_Real* lincoefs;
3146  int nmonomialnodes;
3147  SCIP_EXPRGRAPHNODE** childrennew;
3148  SCIP_EXPRGRAPHNODE** monomialnodes;
3149  int m;
3150 
3151  /* @todo if a monomial is a factor of another monomial, then we could (and should?) replace it there by the node we create for it here -> ex7_2_1
3152  * @todo factorizing the polynomial could be beneficial
3153  */
3154 
3155  /* constant part of polynomials, to add to first monomialnode, if any, or quadratic or linear part */
3156  constant = SCIPexprgraphGetNodePolynomialConstant(node);
3157 
3158  /* coefficients from linear monomials */
3159  lincoefs = NULL;
3160 
3161  /* quadratic elements */
3162  nquadelems = 0;
3163  quadelems = NULL;
3164 
3165  /* expression graph nodes representing single higher-degree monomials, and single node with linear and/or quadratic monomials */
3166  nmonomialnodes = 0;
3167  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnodes, nmonomials) );
3168 
3169  /* children of new monomial nodes that are setup */
3170  childrennew = NULL;
3171 
3172  for( m = 0; m < nmonomials; ++m )
3173  {
3174  monomial = monomials[m];
3175  assert(monomial != NULL);
3176 
3177  coef = SCIPexprGetMonomialCoef(monomial);
3178  exponents = SCIPexprGetMonomialExponents(monomial);
3179  childidxs = SCIPexprGetMonomialChildIndices(monomial);
3180  nfactors = SCIPexprGetMonomialNFactors(monomial);
3181  assert(nfactors >= 1); /* constant monomials should have been simplified away */
3182  assert(coef != 0.0); /* zero-monomials should have been simplified away */
3183 
3184  if( nfactors == 1 && exponents[0] == 1.0 )
3185  {
3186  /* linear monomial */
3187  if( lincoefs == NULL )
3188  {
3189  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nchildren) );
3190  BMSclearMemoryArray(lincoefs, nchildren);
3191  }
3192  assert(0 <= childidxs[0] && childidxs[0] < nchildren);
3193  assert(lincoefs[childidxs[0]] == 0.0); /* monomials should have been merged */
3194  lincoefs[childidxs[0]] = coef;
3195  }
3196  else if( nfactors == 1 && exponents[0] == 2.0 )
3197  {
3198  /* square monomial */
3199  if( quadelems == NULL )
3200  {
3201  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nmonomials) );
3202  }
3203  quadelems[nquadelems].idx1 = childidxs[0];
3204  quadelems[nquadelems].idx2 = childidxs[0];
3205  quadelems[nquadelems].coef = coef;
3206  ++nquadelems;
3207  }
3208  else if( nfactors == 2 && exponents[0] == 1.0 && exponents[1] == 1.0 )
3209  {
3210  /* bilinear monomial */
3211  if( quadelems == NULL )
3212  {
3213  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nmonomials) );
3214  }
3215  if( childidxs[0] < childidxs[1] )
3216  {
3217  quadelems[nquadelems].idx1 = childidxs[0];
3218  quadelems[nquadelems].idx2 = childidxs[1];
3219  }
3220  else
3221  {
3222  quadelems[nquadelems].idx1 = childidxs[1];
3223  quadelems[nquadelems].idx2 = childidxs[0];
3224  }
3225  quadelems[nquadelems].coef = coef;
3226  ++nquadelems;
3227  }
3228  else
3229  {
3230  /* general monomial -> pass into separate expression graph node */
3231  SCIP_EXPRDATA_MONOMIAL* monomialnew;
3232 
3233  /* create new node for this monomial, children will be those associated with factors */
3234  SCIP_CALL( SCIPexprCreateMonomial(SCIPblkmem(scip), &monomialnew, coef, nfactors, NULL, exponents) );
3235  SCIP_CALL( SCIPexprgraphCreateNodePolynomial(SCIPblkmem(scip), &monomialnodes[nmonomialnodes], 1, &monomialnew, constant, FALSE) );
3236  constant = 0.0;
3237 
3238  if( childrennew == NULL )
3239  {
3240  SCIP_CALL( SCIPallocBufferArray(scip, &childrennew, nchildren) );
3241  }
3242  assert(nfactors <= nchildren);
3243  for( f = 0; f < nfactors; ++f )
3244  childrennew[f] = children[childidxs[f]]; /*lint !e613*/
3245 
3246  /* add new node to same depth as this node, so we will reformulate it during this run
3247  * no need to refresh bounds/curvature here, since that will be done when we reach this node next */
3248  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, monomialnodes[nmonomialnodes], SCIPexprgraphGetNodeDepth(node), nfactors, childrennew) );
3249 
3250  ++nmonomialnodes;
3251  }
3252  }
3253  /* should have had at least one linear, quadratic, or general monomial */
3254  assert(lincoefs != NULL || nquadelems > 0 || nmonomialnodes > 0);
3255 
3256  if( nquadelems > 0 )
3257  {
3258  /* create and add additional node for quadratic and linear part, simplifier should take care of removing unused children later */
3259  SCIP_CALL( SCIPexprgraphCreateNodeQuadratic(SCIPblkmem(scip), &monomialnodes[nmonomialnodes], nchildren, lincoefs, nquadelems, quadelems, constant) );
3260  constant = 0.0;
3261  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, monomialnodes[nmonomialnodes], SCIPexprgraphGetNodeDepth(node), nchildren, children) );
3262  ++nmonomialnodes;
3263  }
3264  else if( lincoefs != NULL )
3265  {
3266  /* create additional node for linear part, simplifier should take care of removing unused children later */
3267  SCIP_CALL( SCIPexprgraphCreateNodeLinear(SCIPblkmem(scip), &monomialnodes[nmonomialnodes], nchildren, lincoefs, constant) );
3268  constant = 0.0;
3269  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, monomialnodes[nmonomialnodes], SCIPexprgraphGetNodeDepth(node), nchildren, children) );
3270  ++nmonomialnodes;
3271  }
3272  assert(constant == 0.0); /* the constant should have been used somewhere */
3273 
3274  SCIPfreeBufferArrayNull(scip, &lincoefs);
3275  SCIPfreeBufferArrayNull(scip, &quadelems);
3276  SCIPfreeBufferArrayNull(scip, &childrennew);
3277 
3278  assert(nmonomialnodes > 0);
3279  if( nmonomialnodes > 1 )
3280  {
3281  /* add node for sum of monomials to expression graph */
3282  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &sumnode, nmonomialnodes == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM) );
3283  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, sumnode, -1, nmonomialnodes, monomialnodes) );
3284  }
3285  else
3286  {
3287  /* if only one monomial, then because polynomial was linear or quadratic... */
3288  assert(SCIPexprgraphGetNodeOperator(monomialnodes[0]) == SCIP_EXPR_LINEAR || SCIPexprgraphGetNodeOperator(monomialnodes[0]) == SCIP_EXPR_QUADRATIC);
3289  sumnode = monomialnodes[0];
3290  }
3291  SCIPfreeBufferArray(scip, &monomialnodes);
3292 
3293  /* replace node by sumnode, and we are done */
3294  SCIP_CALL( reformReplaceNode(exprgraph, &node, sumnode, conss, nconss) );
3295 
3296  SCIPdebugMsg(scip, "splitup polynomial into sum of %d nodes\n", nmonomialnodes);
3297 
3298  break;
3299  }
3300 
3301  /* reformulate a monomial such that it becomes convex or concave, if necessary */
3302 
3303  monomial = monomials[0];
3304  assert(monomial != NULL);
3305 
3306  coef = SCIPexprGetMonomialCoef(monomial);
3307  exponents = SCIPexprGetMonomialExponents(monomial);
3308  childidxs = SCIPexprGetMonomialChildIndices(monomial);
3309  nfactors = SCIPexprGetMonomialNFactors(monomial);
3310  assert(nfactors >= 1); /* constant monomials should have been simplified away */
3311  assert(coef != 0.0); /* zero-monomials should have been simplified away */
3312  assert(children != NULL);
3313 
3314  /* check if we make monomial convex or concave by making a child linear */
3315  modified = FALSE;
3316  if( nfactors == 1 )
3317  {
3318  /* ensure that the child of an univariate monomial is linear if its current (bounds,curvature) yields an unknown curvature for the monomial
3319  * and with linear child it had a known curvature (rules out x^a, a negative, x not linear) */
3320  childcurv = SCIPexprgraphGetNodeCurvature(children[childidxs[0]]); /*lint !e613*/
3321  childbounds = SCIPexprgraphGetNodeBounds(children[childidxs[0]]); /*lint !e613*/
3322  assert(SCIPexprcurvPower(childbounds, childcurv, exponents[0]) == SCIP_EXPRCURV_UNKNOWN); /* this is exactly the curvature of the node, which is unknown */
3323 
3324  /* if monomial were convex or concave if child were linear, then make child linear */
3325  if( SCIPexprcurvPower(childbounds, SCIP_EXPRCURV_LINEAR, exponents[0]) != SCIP_EXPRCURV_UNKNOWN )
3326  {
3327  assert(childcurv != SCIP_EXPRCURV_LINEAR);
3328  SCIPdebugMsg(scip, "reform child %d (univar. monomial) with curv %s into var\n", childidxs[0], SCIPexprcurvGetName(childcurv));
3329  SCIP_CALL( reformNode2Var(scip, exprgraph, children[childidxs[0]], conss, nconss, naddcons, FALSE) ); /*lint !e613*/
3330  modified = TRUE;
3331  }
3332  }
3333  else
3334  {
3335  /* check if the conditions on the exponents allow for a convex or concave monomial, assuming that the children are linear
3336  * if one of these conditions is fulfilled but a children curvature does not fit, then make these children linear
3337  */
3338  int nnegative;
3339  int npositive;
3340  SCIP_Real sum;
3341  SCIP_Bool expcurvpos;
3342  SCIP_Bool expcurvneg;
3343  SCIP_EXPRCURV desiredcurv;
3344 
3345  nnegative = 0; /* number of negative exponents */
3346  npositive = 0; /* number of positive exponents */
3347  sum = 0.0; /* sum of exponents */
3348  expcurvpos = TRUE; /* whether exp_j * f_j''(x) >= 0 for all factors (assuming f_j >= 0) */
3349  expcurvneg = TRUE; /* whether exp_j * f_j''(x) <= 0 for all factors (assuming f_j >= 0) */
3350 
3351  /* ensure that none of the children have unknown curvature */
3352  for( c = 0; c < SCIPexprgraphGetNodeNChildren(node); ++c )
3353  {
3354  childcurv = SCIPexprgraphGetNodeCurvature(children[c]); /*lint !e613*/
3355  if( childcurv == SCIP_EXPRCURV_UNKNOWN )
3356  {
3357  SCIPdebugMessage("reform child %d with unknown curvature into var\n", c);
3358  SCIP_CALL( reformNode2Var(scip, exprgraph, children[c], conss, nconss, naddcons, FALSE) ); /*lint !e613*/
3359  modified = TRUE;
3360  }
3361  }
3362  if( modified )
3363  {
3364  /* refresh curvature information in node, since we changed children */
3367 
3368  modified = FALSE;
3369  }
3370 
3371  for( f = 0; f < nfactors; ++f )
3372  {
3373  childcurv = SCIPexprgraphGetNodeCurvature(children[childidxs[f]]); /*lint !e613*/
3374  assert(childcurv != SCIP_EXPRCURV_UNKNOWN);
3375  childbounds = SCIPexprgraphGetNodeBounds(children[childidxs[f]]); /*lint !e613*/
3376  if( childbounds.inf < 0.0 && childbounds.sup > 0.0 )
3377  break;
3378 
3379  if( exponents[f] < 0.0 )
3380  ++nnegative;
3381  else
3382  ++npositive;
3383  sum += exponents[f];
3384 
3385  /* negate curvature if factor is negative */
3386  if( childbounds.inf < 0.0 )
3387  childcurv = SCIPexprcurvNegate(childcurv);
3388 
3389  /* check if exp_j * checkcurv is convex (>= 0) and/or concave */
3390  childcurv = SCIPexprcurvMultiply(exponents[f], childcurv);
3391  if( !(childcurv & SCIP_EXPRCURV_CONVEX) )
3392  expcurvpos = FALSE;
3393  if( !(childcurv & SCIP_EXPRCURV_CONCAVE) )
3394  expcurvneg = FALSE;
3395  }
3396 
3397  /* if some child can be both positive and negative, then nothing we can do here to get the monomial convex or concave
3398  * otherwise (i.e., f == nfactors), look further */
3399  desiredcurv = SCIP_EXPRCURV_UNKNOWN;
3400  if( f == nfactors )
3401  {
3402  /* if all factors are linear, then a product f_j^exp_j with f_j >= 0 is convex if
3403  * - all exponents are negative, or
3404  * - all except one exponent j* are negative and exp_j* >= 1 - sum_{j!=j*}exp_j, but the latter is equivalent to sum_j exp_j >= 1
3405  * further, the product is concave if
3406  * - all exponents are positive and the sum of exponents is <= 1.0
3407  *
3408  * if factors are nonlinear, then we require additionally, that for convexity
3409  * - each factor is convex if exp_j >= 0, or concave if exp_j <= 0, i.e., exp_j*f_j'' >= 0
3410  * and for concavity, we require that
3411  * - all factors are concave, i.e., exp_j*f_j'' <= 0
3412  */
3413 
3414  if( nnegative == nfactors || (nnegative == nfactors-1 && SCIPisGE(scip, sum, 1.0)) )
3415  {
3416  /* if exponents are such that we can be convex, but children curvature does not fit, make some children linear */
3417  SCIPdebugMsg(scip, "%d-variate monomial is convex (modulo sign), child curv fits = %u\n", nfactors, expcurvpos);
3418  /* since current node curvature is set to unknown, there must be such a child, since otherwise the node curvature had to be convex */
3419  assert(!expcurvpos);
3420  desiredcurv = SCIP_EXPRCURV_CONVEX;
3421  }
3422  else if( npositive == nfactors && SCIPisLE(scip, sum, 1.0) )
3423  {
3424  /* if exponents are such that we can be concave, but children curvature does not fit, make some children linear */
3425  SCIPdebugMsg(scip, "%d-variate monomial is concave (modulo sign), child curv fits = %u\n", nfactors, expcurvneg);
3426  /* since current node curvature is set to unknown, there must be such a child, since otherwise the node curvature had to be concave */
3427  assert(!expcurvneg);
3428  desiredcurv = SCIP_EXPRCURV_CONCAVE;
3429  }
3430  else
3431  {
3432  /* exponents are such that monomial is neither convex nor concave even if children were linear
3433  * thus, reformulate monomial below
3434  */
3435  }
3436  }
3437 
3438  if( desiredcurv != SCIP_EXPRCURV_UNKNOWN )
3439  {
3440  for( f = 0; f < nfactors; ++f )
3441  {
3442  childcurv = SCIPexprgraphGetNodeCurvature(children[childidxs[f]]); /*lint !e613*/
3443  assert(childcurv != SCIP_EXPRCURV_UNKNOWN);
3444  childbounds = SCIPexprgraphGetNodeBounds(children[childidxs[f]]); /*lint !e613*/
3445  assert(childbounds.inf >= 0.0 || childbounds.sup <= 0.0);
3446 
3447  /* negate curvature if factor is negative */
3448  if( childbounds.inf < 0.0 )
3449  childcurv = SCIPexprcurvNegate(childcurv);
3450 
3451  /* check if exp_j * checkcurv is convex (>= 0) and/or concave */
3452  childcurv = SCIPexprcurvMultiply(SCIPexprGetMonomialExponents(monomial)[f], childcurv);
3453  if( (desiredcurv == SCIP_EXPRCURV_CONVEX && !(childcurv & SCIP_EXPRCURV_CONVEX )) ||
3454  (desiredcurv == SCIP_EXPRCURV_CONCAVE && !(childcurv & SCIP_EXPRCURV_CONCAVE)) )
3455  {
3456  SCIPdebugMsg(scip, "reform child %d (factor %d) with curv %s into var\n",
3457  childidxs[f], f, SCIPexprcurvGetName(SCIPexprgraphGetNodeCurvature(children[childidxs[f]]))); /*lint !e613*/
3458  SCIP_CALL( reformNode2Var(scip, exprgraph, children[childidxs[f]], conss, nconss, naddcons, FALSE) ); /*lint !e613*/
3459  modified = TRUE;
3460  }
3461  }
3462  }
3463  }
3464 
3465  if( modified )
3466  {
3467  /* refresh curvature information in node, since we changed children, it should be convex or concave now */
3471 
3472  /* we are done and can proceed with the next node */
3473  ++i;
3474  break;
3475  }
3476 
3477  /* monomial can only have unknown curvature here, if it has several factors
3478  * or is of form x^a with x both negative and positive and a an odd or negative integer (-> INTPOWER expression)
3479  */
3480  assert(nfactors > 1 ||
3481  (SCIPexprgraphGetNodeBounds(children[childidxs[0]]).inf < 0.0 && SCIPexprgraphGetNodeBounds(children[childidxs[0]]).sup > 0.0 &&
3482  SCIPisIntegral(scip, exponents[0]) && (exponents[0] < 0.0 || ((int)SCIPround(scip, exponents[0]) % 2 != 0)))
3483  ); /*lint !e613*/
3484 
3485  /* bilinear monomials should not come up here, since simplifier should have turned them into quadratic expression nodes */
3486  assert(!(nfactors == 2 && exponents[0] == 1.0 && exponents[1] == 1.0));
3487 
3488  /* reform monomial if it is a product, or we need it to be on the top of the graph, or if it of the form x^a with a < 0.0 (and thus x having mixed sign, see assert above)
3489  * thus, in the case x^a with a an odd positive integer we assume that cons_signpower will do something */
3490  if( nfactors > 1 || havenonlinparent || exponents[0] < 0.0 )
3491  {
3492  SCIP_EXPRGRAPHNODE* auxnode;
3493  SCIP_EXPRGRAPHNODE** factors;
3494 
3495  if( nfactors > 1 )
3496  {
3497  SCIP_CALL( SCIPallocBufferArray(scip, &factors, nfactors) );
3498  for( f = 0; f < nfactors; ++f )
3499  factors[f] = children[childidxs[f]]; /*lint !e613*/
3500  }
3501  else
3502  factors = &children[childidxs[0]]; /*lint !e613*/
3503 
3504  SCIPdebugMsg(scip, "reform monomial node, create auxvar = %u\n", havenonlinparent);
3505  /* get new auxnode for monomial
3506  * if node has parents and monomial is of indefinite form x^a, then also create auxvar for it, since otherwise we create a auxnode with unknown curvature
3507  * note, that the case x^a with positive and odd a will still give an indefinite node (without parents), where we assume that signpower will pick it up at some point
3508  */
3509  SCIP_CALL( reformMonomial(scip, exprgraph, nfactors, factors, exponents, &auxnode, havenonlinparent, SCIPexprgraphGetNodeDepth(node), naddcons) );
3510 
3511  if( nfactors > 1 )
3512  {
3513  SCIPfreeBufferArray(scip, &factors);
3514  }
3515 
3516  /* create node for monomialcoef * auxnode + monomialconstant, if not identical to auxnode */
3517  if( SCIPexprgraphGetNodePolynomialConstant(node) != 0.0 || coef != 1.0 )
3518  {
3519  SCIP_EXPRGRAPHNODE* replnode;
3520 
3522  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, replnode, -1, 1, &auxnode) );
3523  auxnode = replnode;
3524  }
3525 
3526  /* replace node by auxnode and refresh its curvature */
3527  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxnode, conss, nconss) );
3530 
3531  break;
3532  }
3533  else
3534  {
3535  SCIPdebugMsg(scip, "no reformulation of monomial node, assume signpower will take care of it\n");
3536  }
3537 
3538  ++i;
3539  break;
3540  }
3541 
3542  case SCIP_EXPR_USER:
3543  {
3544  /* ensure all children are linear */
3545  SCIP_CALL( reformEnsureChildrenMinCurvature( scip, exprgraph, node, SCIP_EXPRCURV_LINEAR, conss, nconss, naddcons ) );
3546 
3547  /* unknown curvature can be handled by user estimator callback or interval gradient */
3548  /*
3549  if( SCIPexprgraphGetNodeCurvature( node ) == SCIP_EXPRCURV_UNKNOWN )
3550  {
3551  SCIPerrorMessage("user expression with unknown curvature not supported\n");
3552  return SCIP_ERROR;
3553  }
3554  */
3555 
3556  ++i;
3557  break;
3558  }
3559 
3560  case SCIP_EXPR_LAST:
3561  SCIPABORT();
3562  break;
3563  }
3564  }
3565  }
3566 
3567  /* for constraints with concave f(g(x)) with linear g:R^n -> R, n>1, reformulate to get a univariate concave function, since this is easier to underestimate
3568  * @todo this does not work yet for sums of functions other than polynomials
3569  */
3570  for( c = 0; c < nconss; ++c )
3571  {
3572  SCIP_EXPRGRAPHNODE* multivarnode;
3573  SCIP_EXPRCURV curv;
3574 
3575  assert(conss[c] != NULL); /*lint !e613*/
3576 
3577  /* skip constraints that are to be deleted */
3578  if( SCIPconsIsDeleted(conss[c]) ) /*lint !e613*/
3579  continue;
3580 
3581  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3582  assert(consdata != NULL);
3583 
3584  if( consdata->exprgraphnode == NULL )
3585  continue;
3586 
3587  /* after reformulation, force a round of backpropagation in expression graph for all constraints,
3588  * since new variables (nlreform*) may now be used in existing constraints and we want domain restrictions
3589  * of operators propagated for these variables
3590  */
3591  consdata->forcebackprop = TRUE;
3592 
3593  if( SCIPexprgraphGetNodeOperator(consdata->exprgraphnode) == SCIP_EXPR_POLYNOMIAL )
3594  {
3595  SCIP_EXPRDATA_MONOMIAL* monomial;
3596  int m;
3597  int f;
3598 
3599  for( m = 0; m < SCIPexprgraphGetNodePolynomialNMonomials(consdata->exprgraphnode); ++m )
3600  {
3601  SCIP_CALL( SCIPexprgraphGetNodePolynomialMonomialCurvature(consdata->exprgraphnode, m, INTERVALINFTY, &curv) );
3602 
3603  monomial = SCIPexprgraphGetNodePolynomialMonomials(consdata->exprgraphnode)[m];
3604  assert(monomial != NULL);
3605 
3606  /* if nothing concave, then continue */
3607  if( (SCIPisInfinity(scip, consdata->rhs) || curv != SCIP_EXPRCURV_CONCAVE) &&
3608  ( SCIPisInfinity(scip, -consdata->lhs) || curv != SCIP_EXPRCURV_CONVEX) )
3609  continue;
3610 
3611  for( f = 0; f < SCIPexprGetMonomialNFactors(monomial); ++f )
3612  {
3613  multivarnode = SCIPexprgraphGetNodeChildren(consdata->exprgraphnode)[SCIPexprGetMonomialChildIndices(monomial)[f]];
3614 
3615  /* search for a descendant of node that has > 1 children
3616  * after simplifier run, there should be no constant expressions left
3617  */
3618  while( SCIPexprgraphGetNodeNChildren(multivarnode) == 1 )
3619  multivarnode = SCIPexprgraphGetNodeChildren(multivarnode)[0];
3620 
3621  /* if node expression is obviously univariate, then continue */
3622  if( SCIPexprgraphGetNodeNChildren(multivarnode) == 0 )
3623  {
3625  continue;
3626  }
3627 
3628  /* if multivarnode is a linear expression, then replace this by an auxiliary variable/node
3629  * mark auxiliary variable as not to multiaggregate, so SCIP cannot undo what we just did
3630  */
3632  {
3633  SCIPdebugMsg(scip, "replace linear multivariate node %p(%d,%d) in expression of cons <%s> by auxvar\n",
3634  (void*)multivarnode, SCIPexprgraphGetNodeDepth(multivarnode), SCIPexprgraphGetNodePosition(multivarnode), SCIPconsGetName(conss[c])); /*lint !e613*/
3635  SCIPdebugPrintCons(scip, conss[c], NULL); /*lint !e613*/
3636  SCIP_CALL( reformNode2Var(scip, exprgraph, multivarnode, conss, nconss, naddcons, TRUE) );
3637  }
3638  }
3639  }
3640  }
3641  else
3642  {
3643  curv = SCIPexprgraphGetNodeCurvature(consdata->exprgraphnode);
3644 
3645  /* if nothing concave, then continue */
3646  if( (SCIPisInfinity(scip, consdata->rhs) || curv != SCIP_EXPRCURV_CONCAVE) &&
3647  ( SCIPisInfinity(scip, -consdata->lhs) || curv != SCIP_EXPRCURV_CONVEX) )
3648  continue;
3649 
3650  /* search for a descendant of node that has > 1 children
3651  * after simplifier run, there should be no constant expressions left
3652  */
3653  multivarnode = consdata->exprgraphnode;
3654  while( SCIPexprgraphGetNodeNChildren(multivarnode) == 1 )
3655  multivarnode = SCIPexprgraphGetNodeChildren(multivarnode)[0];
3656 
3657  /* if node expression is obviously univariate, then continue */
3658  if( SCIPexprgraphGetNodeNChildren(multivarnode) == 0 )
3659  {
3661  continue;
3662  }
3663 
3664  /* if node itself is multivariate, then continue */
3665  if( multivarnode == consdata->exprgraphnode )
3666  continue;
3667 
3668  /* if multivarnode is a linear expression, then replace this by an auxiliary variable/node
3669  * mark auxiliary variable as not to multiaggregate, so SCIP cannot undo what we just did
3670  */
3672  {
3673  SCIPdebugMsg(scip, "replace linear multivariate node %p(%d,%d) in expression of cons <%s> by auxvar\n",
3674  (void*)multivarnode, SCIPexprgraphGetNodeDepth(multivarnode), SCIPexprgraphGetNodePosition(multivarnode), SCIPconsGetName(conss[c])); /*lint !e613*/
3675  SCIPdebugPrintCons(scip, conss[c], NULL); /*lint !e613*/
3676  SCIP_CALL( reformNode2Var(scip, exprgraph, multivarnode, conss, nconss, naddcons, TRUE) );
3677  }
3678  }
3679  }
3680 
3681  conshdlrdata->isreformulated = TRUE;
3682 
3683  return SCIP_OKAY;
3684 }
3685 
3686 /** gets maximal absolute element of gradient of nonlinear function */
3687 static
3689  SCIP* scip, /**< SCIP data structure */
3690  SCIP_EXPRINT* exprint, /**< expressions interpreter */
3691  SCIP_CONS* cons, /**< constraint */
3692  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
3693  SCIP_Bool newsol, /**< have the expression trees been evaluated at sol before? */
3694  SCIP_Real* maxelem /**< buffer to store maximal element */
3695  )
3696 {
3697  SCIP_CONSDATA* consdata;
3698  int i;
3699  int j;
3700 
3701  assert(scip != NULL);
3702  assert(cons != NULL);
3703  assert(maxelem != NULL);
3704 
3705  consdata = SCIPconsGetData(cons);
3706  assert(consdata != NULL);
3707  assert(exprint != NULL);
3708  assert(consdata->nexprtrees != 0 || consdata->exprgraphnode == NULL);
3709 
3710  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
3711  {
3712  *maxelem = 0.0;
3713  for( i = 0; i < consdata->nlinvars; ++i )
3714  if( REALABS(consdata->lincoefs[i]) > *maxelem )
3715  *maxelem = REALABS(consdata->lincoefs[i]);
3716  }
3717  else
3718  {
3719  *maxelem = consdata->lincoefsmax;
3720  }
3721 
3722  for( j = 0; j < consdata->nexprtrees; ++j )
3723  {
3724  int nvars;
3725  SCIP_Real val;
3726 
3727  assert(consdata->exprtrees[j] != NULL);
3728 
3729  nvars = SCIPexprtreeGetNVars(consdata->exprtrees[j]);
3730 
3731  if( newsol )
3732  {
3733  /* compile expression tree, if not done before (can happen, if called from proposeFeasibleSolution) */
3734  if( SCIPexprtreeGetInterpreterData(consdata->exprtrees[j]) == NULL )
3735  {
3736  SCIP_CALL( SCIPexprintCompile(exprint, consdata->exprtrees[j]) );
3737  }
3738 
3739  if( nvars == 1 )
3740  {
3741  /* in the not so unusual case that an expression has only one variable, we do not extra alloc memory */
3742  double varval;
3743  SCIP_Real grad;
3744 
3745  varval = SCIPgetSolVal(scip, sol, SCIPexprtreeGetVars(consdata->exprtrees[j])[0]);
3746  SCIP_CALL( SCIPexprintGrad(exprint, consdata->exprtrees[j], &varval, TRUE, &val, &grad) );
3747  if( REALABS(grad) > *maxelem )
3748  *maxelem = REALABS(grad);
3749  }
3750  else
3751  {
3752  SCIP_Real* x;
3753  SCIP_Real* grad;
3754 
3755  SCIP_CALL( SCIPallocBufferArray(scip, &x, nvars) );
3756  SCIP_CALL( SCIPallocBufferArray(scip, &grad, nvars) );
3757 
3758  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, SCIPexprtreeGetVars(consdata->exprtrees[j]), x) );
3759  SCIP_CALL( SCIPexprintGrad(exprint, consdata->exprtrees[j], x, TRUE, &val, grad) );
3760 
3761  for( i = 0; i < nvars; ++i )
3762  {
3763  grad[i] *= consdata->nonlincoefs[j];
3764  if( REALABS(grad[i]) > *maxelem )
3765  *maxelem = REALABS(grad[i]);
3766  }
3767 
3768  SCIPfreeBufferArray(scip, &x);
3769  SCIPfreeBufferArray(scip, &grad);
3770  }
3771  }
3772  else
3773  {
3774  assert(SCIPexprtreeGetInterpreterData(consdata->exprtrees[j]) != NULL);
3775 
3776  if( nvars == 1 )
3777  {
3778  SCIP_Real grad;
3779 
3780  SCIP_CALL( SCIPexprintGrad(exprint, consdata->exprtrees[j], NULL, FALSE, &val, &grad) );
3781  if( REALABS(grad) > *maxelem )
3782  *maxelem = REALABS(grad);
3783  }
3784  else
3785  {
3786  SCIP_Real* grad;
3787 
3788  SCIP_CALL( SCIPallocBufferArray(scip, &grad, nvars) );
3789 
3790  SCIP_CALL( SCIPexprintGrad(exprint, consdata->exprtrees[j], NULL, FALSE, &val, grad) );
3791 
3792  for( i = 0; i < nvars; ++i )
3793  {
3794  grad[i] *= consdata->nonlincoefs[j];
3795  if( REALABS(grad[i]) > *maxelem )
3796  *maxelem = REALABS(grad[i]);
3797  }
3798 
3799  SCIPfreeBufferArray(scip, &grad);
3800  }
3801  }
3802  }
3803 
3804  return SCIP_OKAY;
3805 }
3806 
3807 /** computes activity and violation of a constraint
3808  *
3809  * During presolving and if the constraint is active, it is assumes that SCIPexprgraphEval has been called for sol before.
3810  *
3811  * If a solution is found to violate the variable bounds, then violation calculation is stopped and solviolbounds is set to TRUE.
3812  */
3813 static
3815  SCIP* scip, /**< SCIP data structure */
3816  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3817  SCIP_CONS* cons, /**< nonlinear constraint */
3818  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
3819  SCIP_Bool* solviolbounds /**< buffer to indicate whether solution is found to violate variable bounds by more than feastol */
3820  )
3821 { /*lint --e{666}*/
3823  SCIP_CONSDATA* consdata;
3824  SCIP_VAR* var;
3825  SCIP_Real varval;
3826  int i;
3827 
3828  assert(scip != NULL);
3829  assert(conshdlr != NULL);
3830  assert(cons != NULL);
3831  assert(solviolbounds != NULL);
3832 
3833  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3834  assert(conshdlrdata != NULL);
3835  assert(conshdlrdata->exprinterpreter != NULL);
3836 
3837  consdata = SCIPconsGetData(cons);
3838  assert(consdata != NULL);
3839 
3840  consdata->activity = 0.0;
3841  consdata->lhsviol = 0.0;
3842  consdata->rhsviol = 0.0;
3843  varval = 0.0;
3844  *solviolbounds = FALSE;
3845 
3846  for( i = 0; i < consdata->nlinvars; ++i )
3847  {
3848  SCIP_Real activity;
3849 
3850  var = consdata->linvars[i];
3851  varval = SCIPgetSolVal(scip, sol, var);
3852 
3853  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
3854  if( sol == NULL )
3855  {
3856  /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case */
3857  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
3858  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
3859  {
3860  *solviolbounds = TRUE;
3861  return SCIP_OKAY;
3862  }
3863  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
3864  }
3865  activity = consdata->lincoefs[i] * varval;
3866 
3867  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
3868  * 0.0 otherwise
3869  */
3870  if( SCIPisInfinity(scip, REALABS(varval)) )
3871  {
3872  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
3873  {
3874  consdata->activity = SCIPinfinity(scip);
3875  consdata->rhsviol = SCIPinfinity(scip);
3876  return SCIP_OKAY;
3877  }
3878 
3879  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
3880  {
3881  consdata->activity = -SCIPinfinity(scip);
3882  consdata->lhsviol = SCIPinfinity(scip);
3883  return SCIP_OKAY;
3884  }
3885  }
3886 
3887  consdata->activity += activity;
3888  }
3889 
3890  for( i = 0; i < consdata->nexprtrees; ++i )
3891  {
3892  SCIP_Real activity;
3893  SCIP_Real val;
3894  int nvars;
3895 
3896  /* compile expression tree, if not done before */
3897  if( SCIPexprtreeGetInterpreterData(consdata->exprtrees[i]) == NULL )
3898  {
3899  SCIP_CALL( SCIPexprintCompile(conshdlrdata->exprinterpreter, consdata->exprtrees[i]) );
3900  }
3901 
3902  nvars = SCIPexprtreeGetNVars(consdata->exprtrees[i]);
3903 
3904  if( nvars == 1 )
3905  {
3906  /* in the not so unusual case that an expression has only one variable, we do not need to extra allocate memory */
3907  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[0];
3908  varval = SCIPgetSolVal(scip, sol, var);
3909 
3910  /* project onto local box, in case the LP solution is slightly outside the bounds (and then cannot be evaluated) */
3911  if( sol == NULL )
3912  {
3913  /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case */
3914  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
3915  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
3916  {
3917  *solviolbounds = TRUE;
3918  return SCIP_OKAY;
3919  }
3920  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
3921  }
3922 
3923  SCIP_CALL( SCIPexprintEval(conshdlrdata->exprinterpreter, consdata->exprtrees[i], &varval, &val) );
3924  }
3925  else
3926  {
3927  SCIP_Real* x;
3928  int j;
3929 
3930  SCIP_CALL( SCIPallocBufferArray(scip, &x, nvars) );
3931 
3932  for( j = 0; j < nvars; ++j )
3933  {
3934  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[j];
3935  varval = SCIPgetSolVal(scip, sol, var);
3936 
3937  /* project onto local box, in case the LP solution is slightly outside the bounds (and then cannot be evaluated) */
3938  if( sol == NULL )
3939  {
3940  /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case */
3941  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
3942  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
3943  {
3944  *solviolbounds = TRUE;
3945  SCIPfreeBufferArray(scip, &x);
3946  return SCIP_OKAY;
3947  }
3948  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
3949  }
3950 
3951  x[j] = varval;
3952  }
3953 
3954  SCIP_CALL( SCIPexprintEval(conshdlrdata->exprinterpreter, consdata->exprtrees[i], x, &val) );
3955 
3956  SCIPfreeBufferArray(scip, &x);
3957  }
3958 
3959  /* set the activity to infinity if a function evaluation was not valid (e.g., sqrt(-1) ) */
3960  if( !SCIPisFinite(val) )
3961  {
3962  consdata->activity = SCIPinfinity(scip);
3963  if( !SCIPisInfinity(scip, -consdata->lhs) )
3964  consdata->lhsviol = SCIPinfinity(scip);
3965  if( !SCIPisInfinity(scip, consdata->rhs) )
3966  consdata->rhsviol = SCIPinfinity(scip);
3967  return SCIP_OKAY;
3968  }
3969 
3970  /* the contribution of an expression with |val| = +inf is +inf when its coefficient is > 0.0, -inf when its coefficient is < 0.0, and
3971  * 0.0 otherwise
3972  */
3973  activity = consdata->nonlincoefs[i] * val;
3974  if( SCIPisInfinity(scip, REALABS(val)) )
3975  {
3976  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
3977  {
3978  consdata->activity = SCIPinfinity(scip);
3979  consdata->rhsviol = SCIPinfinity(scip);
3980  return SCIP_OKAY;
3981  }
3982 
3983  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
3984  {
3985  consdata->activity = -SCIPinfinity(scip);
3986  consdata->lhsviol = SCIPinfinity(scip);
3987  return SCIP_OKAY;
3988  }
3989  }
3990 
3991  consdata->activity += activity;
3992  }
3993 
3994  if( consdata->nexprtrees == 0 && consdata->exprgraphnode != NULL )
3995  {
3996  SCIP_Real val;
3997 
3999 
4000  val = SCIPexprgraphGetNodeVal(consdata->exprgraphnode);
4001  assert(val != SCIP_INVALID); /*lint !e777*/
4002 
4003  /* set the activity to infinity if a function evaluation was not valid (e.g., sqrt(-1) ) */
4004  if( !SCIPisFinite(val) )
4005  {
4006  consdata->activity = SCIPinfinity(scip);
4007  if( !SCIPisInfinity(scip, -consdata->lhs) )
4008  consdata->lhsviol = SCIPinfinity(scip);
4009  if( !SCIPisInfinity(scip, consdata->rhs) )
4010  consdata->rhsviol = SCIPinfinity(scip);
4011  return SCIP_OKAY;
4012  }
4013 
4014  if( SCIPisInfinity(scip, val) && !SCIPisInfinity(scip, consdata->rhs) )
4015  {
4016  consdata->activity = SCIPinfinity(scip);
4017  consdata->rhsviol = SCIPinfinity(scip);
4018  return SCIP_OKAY;
4019  }
4020  else if( SCIPisInfinity(scip, -val) && !SCIPisInfinity(scip, -consdata->lhs) )
4021  {
4022  consdata->activity = -SCIPinfinity(scip);
4023  consdata->lhsviol = SCIPinfinity(scip);
4024  return SCIP_OKAY;
4025  }
4026 
4027  consdata->activity += val;
4028  }
4029 
4030  if( !SCIPisInfinity(scip, -consdata->lhs) && SCIPisGT(scip, consdata->lhs - consdata->activity, SCIPfeastol(scip)) )
4031  consdata->lhsviol = consdata->lhs - consdata->activity;
4032  else
4033  consdata->lhsviol = 0.0;
4034 
4035  if( !SCIPisInfinity(scip, consdata->rhs) && SCIPisGT(scip, consdata->activity - consdata->rhs, SCIPfeastol(scip)) )
4036  consdata->rhsviol = consdata->activity - consdata->rhs;
4037  else
4038  consdata->rhsviol = 0.0;
4039 
4040  switch( conshdlrdata->scaling )
4041  {
4042  case 'o' :
4043  /* no scaling */
4044  break;
4045 
4046  case 'g' :
4047  /* scale by sup-norm of gradient in current point
4048  * do only if we are linear or have expression trees, thus, not during presolve
4049  */
4050  if( (consdata->lhsviol > 0.0 || consdata->rhsviol > 0.0) && (consdata->exprgraphnode == NULL || consdata->nexprtrees > 0) )
4051  {
4052  SCIP_Real norm;
4053 
4054  SCIP_CALL( getGradientMaxElement(scip, conshdlrdata->exprinterpreter, cons, sol, FALSE, &norm) );
4055 
4056  if( norm > 1.0 && !SCIPisInfinity(scip, norm) )
4057  {
4058  consdata->lhsviol /= norm;
4059  consdata->rhsviol /= norm;
4060  }
4061  }
4062  break;
4063 
4064  case 's' :
4065  /* scale by left/right hand side of constraint */
4066  if( consdata->lhsviol > 0.0 )
4067  consdata->lhsviol /= MAX(1.0, REALABS(consdata->lhs));
4068 
4069  if( consdata->rhsviol > 0.0 )
4070  consdata->rhsviol /= MAX(1.0, REALABS(consdata->rhs));
4071 
4072  break;
4073 
4074  default :
4075  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
4076  SCIPABORT();
4077  return SCIP_INVALIDDATA; /*lint !e527*/
4078  }
4079 
4080  return SCIP_OKAY;
4081 }
4082 
4083 /** computes violation of a set of constraints
4084  *
4085  * If the solution is found to violate bounds of some variable in some constraint, then violation computation is stopped and solviolbounds is set to TRUE.
4086  */
4087 static
4089  SCIP* scip, /**< SCIP data structure */
4090  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4091  SCIP_CONS** conss, /**< constraints */
4092  int nconss, /**< number of constraints */
4093  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
4094  SCIP_Bool* solviolbounds, /**< buffer to indicate whether solution violates bounds of some variable by more than feastol */
4095  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
4096  )
4097 {
4098  SCIP_CONSDATA* consdata;
4099  SCIP_Real viol;
4100  SCIP_Real maxviol;
4101  int c;
4102 
4103  assert(scip != NULL);
4104  assert(conshdlr != NULL);
4105  assert(conss != NULL || nconss == 0);
4106  assert(maxviolcon != NULL);
4107  assert(solviolbounds != NULL);
4108 
4110  {
4112  SCIP_Real* varvals;
4113 
4114  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4115  assert(conshdlrdata != NULL);
4116  assert(conshdlrdata->exprgraph != NULL);
4117 
4118  SCIP_CALL( SCIPallocBufferArray(scip, &varvals, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
4119  SCIP_CALL( SCIPgetSolVals(scip, sol, SCIPexprgraphGetNVars(conshdlrdata->exprgraph), (SCIP_VAR**)SCIPexprgraphGetVars(conshdlrdata->exprgraph), varvals) );
4120 
4121  SCIP_CALL( SCIPexprgraphEval(conshdlrdata->exprgraph, varvals) );
4122 
4123  SCIPfreeBufferArray(scip, &varvals);
4124  }
4125 
4126  *maxviolcon = NULL;
4127 
4128  maxviol = 0.0;
4129 
4130  for( c = 0; c < nconss; ++c )
4131  {
4132  assert(conss != NULL);
4133  assert(conss[c] != NULL);
4134 
4135  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol, solviolbounds) );
4136 
4137  /* stop if solution violates bounds */
4138  if( *solviolbounds )
4139  break;
4140 
4141  consdata = SCIPconsGetData(conss[c]);
4142  assert(consdata != NULL);
4143 
4144  viol = MAX(consdata->lhsviol, consdata->rhsviol);
4145  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
4146  {
4147  maxviol = viol;
4148  *maxviolcon = conss[c];
4149  }
4150 
4151  /* SCIPdebugMsg(scip, "constraint <%s> violated by (%g, %g), activity = %g\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->activity); */
4152  }
4153 
4154  return SCIP_OKAY;
4155 }
4156 
4157 /** adds linearization of a constraints expression tree in reference point to a row */
4158 static
4160  SCIP* scip, /**< SCIP data structure */
4161  SCIP_EXPRINT* exprint, /**< expression interpreter */
4162  SCIP_CONS* cons, /**< constraint */
4163  int exprtreeidx, /**< for which tree a linearization should be added */
4164  SCIP_Real* x, /**< value of expression tree variables where to generate cut */
4165  SCIP_Bool newx, /**< whether the last evaluation of the expression with the expression interpreter was not at x */
4166  SCIP_ROWPREP* rowprep, /**< rowprep where to add linearization */
4167  SCIP_Bool* success /**< buffer to store whether a linearization was succefully added to the row */
4168  )
4169 {
4170  SCIP_CONSDATA* consdata;
4171  SCIP_EXPRTREE* exprtree;
4172  SCIP_Real treecoef;
4173  SCIP_Real val;
4174  SCIP_Real* grad;
4175  SCIP_Real constant = 0.0;
4176  SCIP_Bool perturbedx;
4177  int nvars;
4178  int i;
4179 
4180  assert(scip != NULL);
4181  assert(cons != NULL);
4182  assert(x != NULL);
4183  assert(rowprep != NULL);
4184  assert(success != NULL);
4185 
4186  consdata = SCIPconsGetData(cons);
4187  assert(consdata != NULL);
4188  assert(exprtreeidx >= 0);
4189  assert(exprtreeidx < consdata->nexprtrees);
4190  assert(consdata->exprtrees != NULL);
4191 
4192  exprtree = consdata->exprtrees[exprtreeidx];
4193  assert(exprtree != NULL);
4194  assert(newx || SCIPexprtreeGetInterpreterData(exprtree) != NULL);
4195 
4196  treecoef = consdata->nonlincoefs[exprtreeidx];
4197 
4198  *success = FALSE;
4199 
4200  /* compile expression if evaluated the first time; can only happen if newx is FALSE */
4201  if( newx && SCIPexprtreeGetInterpreterData(exprtree) == NULL )
4202  {
4203  SCIP_CALL( SCIPexprintCompile(exprint, exprtree) );
4204  }
4205 
4206  nvars = SCIPexprtreeGetNVars(exprtree);
4207  SCIP_CALL( SCIPallocBufferArray(scip, &grad, nvars) );
4208 
4209  perturbedx = FALSE;
4210  do
4211  {
4212  /* get value and gradient */
4213  SCIP_CALL( SCIPexprintGrad(exprint, exprtree, x, newx, &val, grad) );
4214  if( SCIPisFinite(val) && !SCIPisInfinity(scip, REALABS(val)) )
4215  {
4216  val *= treecoef;
4217  /* check gradient entries and compute constant f(refx) - grad * refx */
4218  constant = val;
4219  for( i = 0; i < nvars; ++i )
4220  {
4221  if( !SCIPisFinite(grad[i]) || SCIPisInfinity(scip, grad[i]) || SCIPisInfinity(scip, -grad[i]) )
4222  break;
4223 
4224  grad[i] *= treecoef;
4225  constant -= grad[i] * x[i];
4226 
4227  /* try to perturb x if the constant is too large */
4228  if( SCIPisInfinity(scip, REALABS(constant)) )
4229  break;
4230 
4231  /* coefficients smaller than epsilon are rounded to 0.0 when added to row, this can be wrong if variable value is very large (bad numerics)
4232  * in this case, set gradient to 0.0 here, but modify constant so that cut is still valid (if possible)
4233  * i.e., estimate grad[i]*x >= grad[i] * bound(x) or grad[i]*x <= grad[i] * bound(x), depending on whether we compute an underestimator (convex) or an overestimator (concave)
4234  * if required bound of x is not finite, then give up
4235  */
4236  if( grad[i] != 0.0 && SCIPisZero(scip, grad[i]) )
4237  {
4238  SCIP_VAR* var;
4239  SCIP_Real xbnd;
4240 
4241  var = SCIPexprtreeGetVars(exprtree)[i];
4242  if( consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONVEX )
4243  {
4244  xbnd = grad[i] > 0.0 ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
4245  }
4246  else
4247  {
4248  assert(consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONCAVE);
4249  xbnd = grad[i] > 0.0 ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
4250  }
4251  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
4252  {
4253  SCIPdebugMsg(scip, "var <%s> [%g,%g] has tiny gradient %g, replace coefficient by constant %g\n",
4254  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), grad[i], grad[i] * xbnd);
4255  constant += grad[i] * xbnd;
4256  grad[i] = 0.0;
4257  }
4258  else
4259  {
4260  *success = FALSE;
4261  SCIPdebugMsg(scip, "skipping linearization, var <%s> [%g,%g] has tiny gradient %g but no finite bound in this direction\n",
4262  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), grad[i]);
4263  SCIPfreeBufferArray(scip, &grad);
4264  return SCIP_OKAY;
4265  }
4266  }
4267  }
4268 
4269  if( i == nvars )
4270  break;
4271  }
4272 
4273  SCIPdebugMsg(scip, "got nonfinite value in evaluation or gradient of <%s>: ", SCIPconsGetName(cons));
4274  if( !perturbedx )
4275  {
4276  SCIP_Real lb;
4277  SCIP_Real ub;
4278 
4279  SCIPdebugMsgPrint(scip, "perturbing reference point and trying again\n");
4280  for( i = 0; i < nvars; ++i )
4281  {
4282  lb = SCIPvarGetLbGlobal(SCIPexprtreeGetVars(exprtree)[i]);
4283  ub = SCIPvarGetUbGlobal(SCIPexprtreeGetVars(exprtree)[i]);
4284  if( SCIPisEQ(scip, x[i], lb) )
4285  x[i] += MIN(0.9*(ub-lb), i*SCIPfeastol(scip)); /*lint !e666*/
4286  else if( SCIPisEQ(scip, x[i], ub) )
4287  x[i] -= MIN(0.9*(ub-lb), i*SCIPfeastol(scip)); /*lint !e666*/
4288  else
4289  x[i] += MIN3(0.9*(ub-x[i]), 0.9*(x[i]-lb), i*SCIPfeastol(scip)) * (i%2 != 0 ? -1.0 : 1.0); /*lint !e666*/
4290  }
4291  newx = TRUE;
4292  perturbedx = TRUE;
4293  }
4294  else
4295  {
4296  SCIPdebugMsgPrint(scip, "skipping linearization\n");
4297  SCIPfreeBufferArray(scip, &grad);
4298  return SCIP_OKAY;
4299  }
4300  }
4301  while( TRUE ); /*lint !e506*/
4302 
4303  /* add linearization to SCIP row */
4304  SCIPaddRowprepConstant(rowprep, constant);
4305  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, nvars, SCIPexprtreeGetVars(exprtree), grad) );
4306 
4307  *success = TRUE;
4308 
4309  SCIPfreeBufferArray(scip, &grad);
4310 
4311  SCIPdebugMsg(scip, "added linearization for tree %d of constraint <%s>\n", exprtreeidx, SCIPconsGetName(cons));
4312  SCIPdebug( SCIPprintRowprep(scip, rowprep, NULL) );
4313 
4314  return SCIP_OKAY;
4315 }
4316 
4317 /** adds secant of a constraints univariate expression tree in reference point to a row */
4318 static
4320  SCIP* scip, /**< SCIP data structure */
4321  SCIP_CONS* cons, /**< constraint */
4322  int exprtreeidx, /**< for which tree a secant should be added */
4323  SCIP_ROWPREP* rowprep, /**< rowprep where to add estimator */
4324  SCIP_Bool* success /**< buffer to store whether a secant was succefully added to the row */
4325  )
4326 {
4327  SCIP_CONSDATA* consdata;
4328  SCIP_EXPRTREE* exprtree;
4329  SCIP_Real treecoef;
4330  SCIP_VAR* var;
4331  SCIP_Real xlb;
4332  SCIP_Real xub;
4333  SCIP_Real vallb;
4334  SCIP_Real valub;
4335  SCIP_Real slope;
4336  SCIP_Real constant;
4337 
4338  assert(scip != NULL);
4339  assert(cons != NULL);
4340  assert(rowprep != NULL);
4341  assert(success != NULL);
4342 
4343  consdata = SCIPconsGetData(cons);
4344  assert(consdata != NULL);
4345  assert(exprtreeidx >= 0);
4346  assert(exprtreeidx < consdata->nexprtrees);
4347  assert(consdata->exprtrees != NULL);
4348 
4349  exprtree = consdata->exprtrees[exprtreeidx];
4350  assert(exprtree != NULL);
4351  assert(SCIPexprtreeGetNVars(exprtree) == 1);
4352 
4353  treecoef = consdata->nonlincoefs[exprtreeidx];
4354 
4355  *success = FALSE;
4356 
4357  var = SCIPexprtreeGetVars(exprtree)[0];
4358  xlb = SCIPvarGetLbLocal(var);
4359  xub = SCIPvarGetUbLocal(var);
4360 
4361  /* if variable is unbounded, then cannot really compute secant */
4362  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
4363  {
4364  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since variable is unbounded\n", exprtreeidx, SCIPconsGetName(cons));
4365  return SCIP_OKAY;
4366  }
4367  assert(SCIPisLE(scip, xlb, xub));
4368 
4369  SCIP_CALL( SCIPexprtreeEval(exprtree, &xlb, &vallb) );
4370  if( !SCIPisFinite(vallb) || SCIPisInfinity(scip, REALABS(vallb)) )
4371  {
4372  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated in lower bound\n", exprtreeidx, SCIPconsGetName(cons));
4373  return SCIP_OKAY;
4374  }
4375  vallb *= treecoef;
4376 
4377  SCIP_CALL( SCIPexprtreeEval(exprtree, &xub, &valub) );
4378  if( !SCIPisFinite(valub) || SCIPisInfinity(scip, REALABS(valub)) )
4379  {
4380  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated in upper bound\n", exprtreeidx, SCIPconsGetName(cons));
4381  return SCIP_OKAY;
4382  }
4383  valub *= treecoef;
4384 
4385  if( SCIPisEQ(scip, xlb, xub) )
4386  {
4387  slope = 0.0;
4388  /* choose most conservative value for the cut */
4389  if( rowprep->sidetype == SCIP_SIDETYPE_LEFT )
4390  constant = MAX(vallb, valub);
4391  else
4392  constant = MIN(vallb, valub);
4393  }
4394  else
4395  {
4396  slope = (valub - vallb) / (xub - xlb);
4397  constant = vallb - slope * xlb;
4398  }
4399 
4400  /* add secant to SCIP row */
4401  SCIPaddRowprepConstant(rowprep, constant);
4402  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, slope) );
4403 
4404  *success = TRUE;
4405 
4406  SCIPdebugMsg(scip, "added secant for tree %d of constraint <%s>, slope = %g\n", exprtreeidx, SCIPconsGetName(cons), slope);
4407  SCIPdebug( SCIPprintRowprep(scip, rowprep, NULL) );
4408 
4409  return SCIP_OKAY;
4410 }
4411 
4412 /** adds estimator of a constraints bivariate expression tree to a row
4413  * a reference point is given to decide which hyperplane to choose
4414  */
4415 static
4417  SCIP* scip, /**< SCIP data structure */
4418  SCIP_CONS* cons, /**< constraint */
4419  int exprtreeidx, /**< for which tree a secant should be added */
4420  SCIP_Real* ref, /**< reference values of expression tree variables where to generate cut */
4421  SCIP_ROWPREP* rowprep, /**< rowprep where to add estimator */
4422  SCIP_Bool* success /**< buffer to store whether a secant was succefully added to the row */
4423  )
4424 {
4425  SCIP_CONSDATA* consdata;
4426  SCIP_EXPRTREE* exprtree;
4427  SCIP_Real treecoef;
4428  SCIP_VAR* x;
4429  SCIP_VAR* y;
4430  SCIP_Real xlb;
4431  SCIP_Real xub;
4432  SCIP_Real ylb;
4433  SCIP_Real yub;
4434 
4435  SCIP_Real coefx;
4436  SCIP_Real coefy;
4437  SCIP_Real constant;
4438 
4439  SCIP_Real p1[2];
4440  SCIP_Real p2[2];
4441  SCIP_Real p3[2];
4442  SCIP_Real p4[2];
4443  SCIP_Real p1val, p2val, p3val, p4val;
4444 
4445  assert(scip != NULL);
4446  assert(cons != NULL);
4447  assert(ref != NULL);
4448  assert(rowprep != NULL);
4449  assert(success != NULL);
4450 
4451  consdata = SCIPconsGetData(cons);
4452  assert(consdata != NULL);
4453  assert(exprtreeidx >= 0);
4454  assert(exprtreeidx < consdata->nexprtrees);
4455  assert(consdata->exprtrees != NULL);
4456 
4457  exprtree = consdata->exprtrees[exprtreeidx];
4458  assert(exprtree != NULL);
4459  assert(SCIPexprtreeGetNVars(exprtree) == 2);
4460 
4461  treecoef = consdata->nonlincoefs[exprtreeidx];
4462 
4463  *success = FALSE;
4464 
4465  x = SCIPexprtreeGetVars(exprtree)[0];
4466  y = SCIPexprtreeGetVars(exprtree)[1];
4467  xlb = SCIPvarGetLbLocal(x);
4468  xub = SCIPvarGetUbLocal(x);
4469  ylb = SCIPvarGetLbLocal(y);
4470  yub = SCIPvarGetUbLocal(y);
4471 
4472  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) || SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub) )
4473  {
4474  SCIPdebugMsg(scip, "skip bivariate secant since <%s> or <%s> is unbounded\n", SCIPvarGetName(x), SCIPvarGetName(y));
4475  return SCIP_OKAY;
4476  }
4477 
4478  /* reference point should not be outside of bounds */
4479  assert(SCIPisFeasLE(scip, xlb, ref[0]));
4480  assert(SCIPisFeasGE(scip, xub, ref[0]));
4481  ref[0] = MIN(xub, MAX(xlb, ref[0]));
4482  assert(SCIPisFeasLE(scip, ylb, ref[1]));
4483  assert(SCIPisFeasGE(scip, yub, ref[1]));
4484  ref[1] = MIN(yub, MAX(ylb, ref[1]));
4485 
4486  /* lower left */
4487  p1[0] = xlb;
4488  p1[1] = ylb;
4489 
4490  /* lower right */
4491  p2[0] = xub;
4492  p2[1] = ylb;
4493 
4494  /* upper right */
4495  p3[0] = xub;
4496  p3[1] = yub;
4497 
4498  /* upper left */
4499  p4[0] = xlb;
4500  p4[1] = yub;
4501 
4502  if( SCIPisEQ(scip, xlb, xub) && SCIPisEQ(scip, ylb, yub) )
4503  {
4504  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4505 
4506  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) )
4507  {
4508  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4509  return SCIP_OKAY;
4510  }
4511 
4512  p1val *= treecoef;
4513 
4514  coefx = 0.0;
4515  coefy = 0.0;
4516  constant = p1val;
4517  }
4518  else if( SCIPisEQ(scip, xlb, xub) )
4519  {
4520  /* secant between p1 and p4: p1val + [(p4val - p1val) / (yub - ylb)] * (y - ylb) */
4521  assert(!SCIPisEQ(scip, ylb, yub));
4522 
4523  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4524  SCIP_CALL( SCIPexprtreeEval(exprtree, p4, &p4val) );
4525  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p4val) || SCIPisInfinity(scip, REALABS(p4val)) )
4526  {
4527  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4528  return SCIP_OKAY;
4529  }
4530  p1val *= treecoef;
4531  p4val *= treecoef;
4532 
4533  coefx = 0.0;
4534  coefy = (p4val - p1val) / (yub - ylb);
4535  constant = p1val - coefy * ylb;
4536  }
4537  else if( SCIPisEQ(scip, ylb, yub) )
4538  {
4539  /* secant between p1 and p2: p1val + [(p2val - p1val) / (xub - xlb)] * (x - xlb) */
4540  assert(!SCIPisEQ(scip, xlb, xub));
4541 
4542  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4543  SCIP_CALL( SCIPexprtreeEval(exprtree, p2, &p2val) );
4544  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p2val) || SCIPisInfinity(scip, REALABS(p2val)) )
4545  {
4546  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4547  return SCIP_OKAY;
4548  }
4549 
4550  p1val *= treecoef;
4551  p2val *= treecoef;
4552 
4553  coefx = (p2val - p1val) / (xub - xlb);
4554  coefy = 0.0;
4555  constant = p1val - coefx * xlb;
4556  }
4557  else
4558  {
4559  SCIP_Real alpha, beta, gamma_, delta;
4560  SCIP_Bool tryother;
4561  SCIP_Bool doover;
4562 
4563  /* if function is convex, then we want an overestimator, otherwise we want an underestimator */
4564  assert(consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONVEX || consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONCAVE);
4565  doover = (consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONVEX); /*lint !e641*/
4566 
4567  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4568  SCIP_CALL( SCIPexprtreeEval(exprtree, p2, &p2val) );
4569  SCIP_CALL( SCIPexprtreeEval(exprtree, p3, &p3val) );
4570  SCIP_CALL( SCIPexprtreeEval(exprtree, p4, &p4val) );
4571  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p2val) || SCIPisInfinity(scip, REALABS(p2val)) ||
4572  ! SCIPisFinite(p3val) || SCIPisInfinity(scip, REALABS(p3val)) || !SCIPisFinite(p4val) || SCIPisInfinity(scip, REALABS(p4val)) )
4573  {
4574  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4575  return SCIP_OKAY;
4576  }
4577  p1val *= treecoef;
4578  p2val *= treecoef;
4579  p3val *= treecoef;
4580  p4val *= treecoef;
4581 
4582  /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
4583  if( !doover )
4584  {
4585  p1val = -p1val;
4586  p2val = -p2val;
4587  p3val = -p3val;
4588  p4val = -p4val;
4589  }
4590 
4591  SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
4592  SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
4593  SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
4594  SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
4595 
4596  /* Compute coefficients alpha, beta, gamma (>0), delta such that
4597  * alpha*x + beta*y + gamma*z = delta
4598  * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
4599  * the fourth corner point lies below this hyperplane.
4600  * Since we assume that f is convex, we then know that all points (x,y,f(x,y)) are below this hyperplane, i.e.,
4601  * alpha*x + beta*y - delta <= -gamma * f(x,y),
4602  * or, equivalently,
4603  * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
4604  */
4605 
4606  tryother = FALSE;
4607  if( ref[1] <= ylb + (yub - ylb)/(xub - xlb) * (ref[0] - xlb) )
4608  {
4609  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
4610  &alpha, &beta, &gamma_, &delta) );
4611 
4612  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4613  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4614  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4615 
4616  /* if hyperplane through p1,p2,p3 does not overestimate f(p4), then it must be the other variant */
4617  if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val > delta )
4618  tryother = TRUE;
4619  else if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4620  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4621  {
4622  /* if numerically bad, take alternative hyperplane */
4623  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1],
4624  p4val, &alpha, &beta, &gamma_, &delta) );
4625 
4626  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4627  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4628  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4629 
4630  /* if hyperplane through p1,p3,p4 does not overestimate f(p2), then it must be the other variant */
4631  if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val > delta )
4632  tryother = TRUE;
4633  }
4634  }
4635  else
4636  {
4637  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
4638  &alpha, &beta, &gamma_, &delta) );
4639 
4640  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4641  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4642  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4643 
4644  /* if hyperplane through p1,p3,p4 does not overestimate f(p2), then it must be the other variant */
4645  if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val > delta )
4646  tryother = TRUE;
4647  else if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4648  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4649  {
4650  /* if numerically bad, take alternative */
4651  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1],
4652  p3val, &alpha, &beta, &gamma_, &delta) );
4653 
4654  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4655  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4656  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4657 
4658  /* if hyperplane through p1,p2,p3 does not overestimate f(p4), then it must be the other variant */
4659  if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val > delta )
4660  tryother = TRUE;
4661  }
4662  }
4663 
4664  if( tryother )
4665  {
4666  if( ref[1] <= yub + (ylb - yub)/(xub - xlb) * (ref[0] - xlb) )
4667  {
4668  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1],
4669  p4val, &alpha, &beta, &gamma_, &delta) );
4670 
4671  /* hyperplane should be above (p3,f(p3)) and other points should lie on hyperplane */
4672  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4673  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4674  assert(SCIPisRelLE(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4675  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4676 
4677  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4678  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4679  {
4680  /* if numerically bad, take alternative */
4681  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1],
4682  p4val, &alpha, &beta, &gamma_, &delta) );
4683 
4684  /* hyperplane should be above (p1,f(p1)) and other points should lie on hyperplane */
4685  assert(SCIPisRelLE(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4686  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4687  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4688  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4689  }
4690  }
4691  else
4692  {
4693  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1],
4694  p4val, &alpha, &beta, &gamma_, &delta) );
4695 
4696  /* hyperplane should be above (p1,f(p1)) and other points should lie on hyperplane */
4697  assert(SCIPisRelLE(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4698  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4699  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4700  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4701 
4702  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4703  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4704  {
4705  /* if numerically bad, take alternative */
4706  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1],
4707  p4val, &alpha, &beta, &gamma_, &delta) );
4708 
4709  /* hyperplane should be above (p3,f(p3)) and other points should lie on hyperplane */
4710  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4711  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4712  assert(SCIPisRelLE(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4713  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4714  }
4715  }
4716  }
4717 
4718  SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
4719 
4720  /* check if bad luck: should not happen if xlb != xub and ylb != yub and numerics are fine */
4721  if( SCIPisZero(scip, gamma_) )
4722  return SCIP_OKAY;
4723  assert(!SCIPisNegative(scip, gamma_));
4724 
4725  /* flip hyperplane */
4726  if( !doover )
4727  gamma_ = -gamma_;
4728 
4729  coefx = -alpha / gamma_;
4730  coefy = -beta / gamma_;
4731  constant = delta / gamma_;
4732 
4733  /* if we loose coefficients because division by gamma makes them < SCIPepsilon(scip), then better not generate a cut here */
4734  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, coefx)) ||
4735  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, coefy)) )
4736  {
4737  SCIPdebugMsg(scip, "skip bivar secant for <%s> tree %d due to bad numerics\n", SCIPconsGetName(cons), exprtreeidx);
4738  return SCIP_OKAY;
4739  }
4740  }
4741 
4742  /* add hyperplane coefs to SCIP row */
4743  SCIPaddRowprepConstant(rowprep, constant);
4744  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, x, coefx) );
4745  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, y, coefy) );
4746 
4747  *success = TRUE;
4748 
4749  SCIPdebugMsg(scip, "added bivariate secant for tree %d of constraint <%s>\n", exprtreeidx, SCIPconsGetName(cons));
4750  SCIPdebug( SCIPprintRowprep(scip, rowprep, NULL) );
4751 
4752  return SCIP_OKAY;
4753 }
4754 
4755 /** adds estimator of a constraints multivariate expression tree to a row
4756  * Given concave function f(x) and reference point ref.
4757  * Let (v_i: i=1,...,n) be corner points of current domain of x.
4758  * Find (coef,constant) such that <coef,v_i> + constant <= f(v_i) (cut validity) and
4759  * such that <coef, ref> + constant is maximized (cut efficacy).
4760  * Then <coef, x> + constant <= f(x) for all x in current domain.
4761  *
4762  * Similar to compute an overestimator for a convex function f(x).
4763  * Find (coef,constant) such that <coef,v_i> + constant >= f(v_i) and
4764  * such that <coef, ref> + constant is minimized.
4765  * Then <coef, x> + constant >= f(x) for all x in current domain.
4766  */
4767 static
4769  SCIP* scip, /**< SCIP data structure */
4770  SCIP_CONS* cons, /**< constraint */
4771  int exprtreeidx, /**< for which tree a secant should be added */
4772  SCIP_Real* ref, /**< reference values of expression tree variables where to generate cut */
4773  SCIP_ROWPREP* rowprep, /**< rowprep where to add estimator */
4774  SCIP_Bool* success /**< buffer to store whether a secant was succefully added to the row */
4775  )
4776 {
4777  SCIP_CONSDATA* consdata;
4778  SCIP_EXPRTREE* exprtree;
4779  SCIP_Real treecoef;
4780  SCIP_LPI* lpi;
4781  SCIP_Bool doupper;
4782  SCIP_Real funcval;
4783  SCIP_Real lpobj;
4784  SCIP_RETCODE lpret;
4785 
4786  SCIP_VAR** vars;
4787  int nvars;
4788 
4789  int ncols;
4790  SCIP_Real* obj;
4791  SCIP_Real* lb;
4792  SCIP_Real* ub;
4793  int nrows;
4794  SCIP_Real* lhs;
4795  SCIP_Real* rhs;
4796  int nnonz;
4797  int* beg;
4798  int* ind;
4799  SCIP_Real* val;
4800 
4801  int i;
4802  int j;
4803 
4804  static SCIP_Bool warned_highdim_concave = FALSE;
4805 
4806  assert(scip != NULL);
4807  assert(cons != NULL);
4808  assert(ref != NULL);
4809  assert(rowprep != NULL);
4810  assert(success != NULL);
4811 
4812  consdata = SCIPconsGetData(cons);
4813  assert(consdata != NULL);
4814  assert(exprtreeidx >= 0);
4815  assert(exprtreeidx < consdata->nexprtrees);
4816  assert(consdata->exprtrees != NULL);
4817 
4818  exprtree = consdata->exprtrees[exprtreeidx];
4819  assert(exprtree != NULL);
4820 
4821  nvars = SCIPexprtreeGetNVars(exprtree);
4822  assert(nvars >= 2);
4823 
4824  *success = FALSE;
4825 
4826  /* size of LP is exponential in number of variables of tree, so do only for small trees */
4827  if( nvars > 10 )
4828  {
4829  if( !warned_highdim_concave )
4830  {
4831  SCIPwarningMessage(scip, "concave function in constraint <%s> too high-dimensional to compute underestimator\n", SCIPconsGetName(cons));
4832  warned_highdim_concave = TRUE;
4833  }
4834  return SCIP_OKAY;
4835  }
4836 
4837  treecoef = consdata->nonlincoefs[exprtreeidx];
4838  vars = SCIPexprtreeGetVars(exprtree);
4839 
4840  /* check whether bounds are finite
4841  * make sure reference point is strictly within bounds
4842  * otherwise we can easily get an unbounded LP below, e.g., with instances like ex6_2_* from GlobalLib
4843  */
4844  for( j = 0; j < nvars; ++j )
4845  {
4846  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(vars[j])) || SCIPisInfinity(scip, SCIPvarGetUbLocal(vars[j])) )
4847  {
4848  SCIPdebugMsg(scip, "cannot compute underestimator for concave because variable <%s> is unbounded\n", SCIPvarGetName(vars[j]));
4849  return SCIP_OKAY;
4850  }
4851  assert(SCIPisFeasLE(scip, SCIPvarGetLbLocal(vars[j]), ref[j]));
4852  assert(SCIPisFeasGE(scip, SCIPvarGetUbLocal(vars[j]), ref[j]));
4853  ref[j] = MIN(SCIPvarGetUbLocal(vars[j]), MAX(SCIPvarGetLbLocal(vars[j]), ref[j])); /*lint !e666*/
4854  }
4855 
4856  /* create empty auxiliary LP and decide its objective sense */
4857  assert(consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONVEX || consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONCAVE);
4858  doupper = (consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONVEX); /*lint !e641*/
4859  SCIP_CALL( SCIPlpiCreate(&lpi, SCIPgetMessagehdlr(scip), "concaveunderest", doupper ? SCIP_OBJSEN_MINIMIZE : SCIP_OBJSEN_MAXIMIZE) );
4860  if( lpi == NULL )
4861  {
4862  SCIPerrorMessage("failed to create auxiliary LP\n");
4863  return SCIP_ERROR;
4864  }
4865 
4866  /* columns are cut coefficients plus constant */
4867  ncols = nvars + 1;
4868  SCIP_CALL( SCIPallocBufferArray(scip, &obj, ncols) );
4869  SCIP_CALL( SCIPallocBufferArray(scip, &lb, ncols) );
4870  SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
4871 
4872  /* one row for each corner of domain, i.e., 2^nvars many */
4873  nrows = (int)(1u << nvars);
4874  SCIP_CALL( SCIPallocBufferArray(scip, &lhs, nrows) );
4875  SCIP_CALL( SCIPallocBufferArray(scip, &rhs, nrows) );
4876 
4877  /* dense coefficients matrix, i.e., ncols * nrows many potential nonzeros */
4878  nnonz = nrows * ncols;
4879  SCIP_CALL( SCIPallocBufferArray(scip, &beg, nrows+1) );
4880  SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
4881  SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
4882 
4883  /* setup LP data */
4884  for( i = 0; i < nrows; ++i )
4885  {
4886  beg[i] = i * ncols;
4887  /* assemble corner point */
4888  SCIPdebugMsg(scip, "f(");
4889  for( j = 0; j < nvars; ++j )
4890  {
4891  /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
4892  * we check this by shifting i for j positions to the right and checking whether the j'th bit is set */
4893  if( ((unsigned int)i >> j) & 0x1 )
4894  val[i * ncols + j] = SCIPvarGetUbLocal(vars[j]);
4895  else
4896  val[i * ncols + j] = SCIPvarGetLbLocal(vars[j]);
4897  SCIPdebugMsgPrint(scip, "%g, ", val[i*ncols+j]);
4898  assert(!SCIPisInfinity(scip, REALABS(val[i*ncols+j])));
4899 
4900  ind[i * ncols + j] = j;
4901  }
4902 
4903  /* evaluate function in current corner */
4904  SCIP_CALL( SCIPexprtreeEval(exprtree, &val[i*ncols], &funcval) );
4905  SCIPdebugMsgPrint(scip, ") = %g\n", funcval);
4906 
4907  if( !SCIPisFinite(funcval) || SCIPisInfinity(scip, REALABS(funcval)) )
4908  {
4909  SCIPdebugMsg(scip, "cannot compute underestimator for concave because constaint <%s> cannot be evaluated\n", SCIPconsGetName(cons));
4910  goto TERMINATE;
4911  }
4912 
4913  funcval *= treecoef;
4914 
4915  if( !doupper )
4916  {
4917  lhs[i] = -SCIPlpiInfinity(lpi);
4918  rhs[i] = funcval;
4919  }
4920  else
4921  {
4922  lhs[i] = funcval;
4923  rhs[i] = SCIPlpiInfinity(lpi);
4924  }
4925 
4926  /* coefficient for constant is 1.0 */
4927  val[i * ncols + nvars] = 1.0;
4928  ind[i * ncols + nvars] = nvars;
4929  }
4930  beg[nrows] = nnonz;
4931 
4932  for( j = 0; j < ncols; ++j )
4933  {
4934  lb[j] = -SCIPlpiInfinity(lpi);
4935  ub[j] = SCIPlpiInfinity(lpi);
4936  }
4937 
4938  /* objective coefficients are reference points, and an additional 1.0 for the constant */
4939  BMScopyMemoryArray(obj, ref, nvars);
4940  obj[nvars] = 1.0;
4941 
4942  /* get function value in reference point, so we can use this as a cutoff */
4943  SCIP_CALL( SCIPexprtreeEval(exprtree, ref, &funcval) );
4944  funcval *= treecoef;
4945 
4946  SCIP_CALL( SCIPlpiAddCols(lpi, ncols, obj, lb, ub, NULL, 0, NULL, NULL, NULL) );
4947  SCIP_CALL( SCIPlpiAddRows(lpi, nrows, lhs, rhs, NULL, nnonz, beg, ind, val) );
4948 
4949  /* make use of this convenient features, since for us nrows >> ncols */
4950  /*SCIP_CALL( SCIPlpiSetRealpar(lpi, SCIP_LPPAR_ROWREPSWITCH, 5.0) ); */
4951  /* get accurate coefficients */
4953  SCIP_CALL( SCIPlpiSetRealpar(lpi, doupper ? SCIP_LPPAR_LOBJLIM : SCIP_LPPAR_UOBJLIM, funcval) );
4954  SCIP_CALL( SCIPlpiSetIntpar(lpi, SCIP_LPPAR_LPITLIM, 10 * nvars) );
4957 
4958  /* SCIPdebug( SCIP_CALL( SCIPlpiSetIntpar(lpi, SCIP_LPPAR_LPINFO, 1) ) ); */
4959 
4960  lpret = SCIPlpiSolveDual(lpi);
4961  if( lpret != SCIP_OKAY )
4962  {
4963  SCIPwarningMessage(scip, "solving auxiliary LP for underestimator of concave function returned %d\n", lpret);
4964  goto TERMINATE;
4965  }
4966 
4967  if( !SCIPlpiIsPrimalFeasible(lpi) )
4968  {
4969  SCIPdebugMsg(scip, "failed to find feasible solution for auxiliary LP for underestimator of concave function, iterlimexc = %u, cutoff = %u, unbounded = %u\n", SCIPlpiIsIterlimExc(lpi), SCIPlpiIsObjlimExc(lpi), SCIPlpiIsPrimalUnbounded(lpi));
4970  goto TERMINATE;
4971  }
4972  /* should be either solved to optimality, or the objective or iteration limit be hit */
4973  assert(SCIPlpiIsOptimal(lpi) || SCIPlpiIsObjlimExc(lpi) || SCIPlpiIsIterlimExc(lpi));
4974 
4975  /* setup row coefficient, reuse obj array to store LP sol values */
4976  SCIP_CALL( SCIPlpiGetSol(lpi, &lpobj, obj, NULL, NULL, NULL) );
4977 
4978  /* check that computed hyperplane is on right side of function in refpoint
4979  * if numerics is very bad (e.g., st_e32), then even this can happen */
4980  if( (!doupper && SCIPisFeasGT(scip, lpobj, funcval)) || (doupper && SCIPisFeasGT(scip, funcval, lpobj)) )
4981  {
4982  SCIPwarningMessage(scip, "computed cut does not underestimate concave function in refpoint\n");
4983  goto TERMINATE;
4984  }
4985  assert( doupper || SCIPisFeasLE(scip, lpobj, funcval) );
4986  assert(!doupper || SCIPisFeasLE(scip, funcval, lpobj) );
4987 
4988  /* add estimator to rowprep */
4989  SCIPaddRowprepConstant(rowprep, obj[nvars]);
4990  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, nvars, vars, obj) );
4991 
4992  *success = TRUE;
4993 
4994  TERMINATE:
4995  SCIPfreeBufferArray(scip, &obj);
4996  SCIPfreeBufferArray(scip, &lb);
4997  SCIPfreeBufferArray(scip, &ub);
4998  SCIPfreeBufferArray(scip, &lhs);
4999  SCIPfreeBufferArray(scip, &rhs);
5000  SCIPfreeBufferArray(scip, &beg);
5001  SCIPfreeBufferArray(scip, &ind);
5002  SCIPfreeBufferArray(scip, &val);
5003 
5004  if( lpi != NULL )
5005  {
5006  SCIP_CALL( SCIPlpiFree(&lpi) );
5007  }
5008 
5009  return SCIP_OKAY;
5010 }
5011 
5012 /** Computes the linear coeffs and the constant in a linear expression
5013  * both scaled by a given scalar value.
5014  * The coeffs of the variables will be stored in the given array at
5015  * their variable index.
5016  * The constant of the given linear expression will be added to the given
5017  * buffer.
5018  */
5019 static
5021  SCIP_EXPR* expr, /**< the linear expression */
5022  SCIP_Real scalar, /**< the scalar value, i.e. the coeff of the given expression */
5023  SCIP_Real* varcoeffs, /**< buffer array to store the computed coefficients */
5024  SCIP_Real* constant /**< buffer to hold the constant value of the given expression */
5025  )
5026 {
5027  switch( SCIPexprGetOperator( expr ) )
5028  {
5029  case SCIP_EXPR_VARIDX: /* set coeff for this variable to current scalar */
5030  {
5031  /* TODO: can a linear expression contain the same variable twice?
5032  * if yes varcoeffs need to be initialized to zero before calling this function
5033  * and coeff must not be overridden but summed up instead. */
5034  varcoeffs[SCIPexprGetOpIndex( expr )] = scalar;
5035  return SCIP_OKAY;
5036  }
5037 
5038  case SCIP_EXPR_CONST:
5039  {
5040  /* constant value increases */
5041  *constant += scalar * SCIPexprGetOpReal( expr );
5042  return SCIP_OKAY;
5043  }
5044 
5045  case SCIP_EXPR_MUL: /* need to find the constant part of the muliplication and then recurse */
5046  {
5047  SCIP_EXPR** children;
5048  children = SCIPexprGetChildren( expr );
5049 
5050  /* first part is constant */
5051  if( SCIPexprGetOperator( children[0] ) == SCIP_EXPR_CONST )
5052  {
5053  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[1], scalar * SCIPexprGetOpReal( children[0] ), varcoeffs, constant ) );
5054  return SCIP_OKAY;
5055  }
5056 
5057  /* second part is constant */
5058  if( SCIPexprGetOperator( children[1] ) == SCIP_EXPR_CONST )
5059  {
5060  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[0], scalar * SCIPexprGetOpReal( children[1] ), varcoeffs, constant ) );
5061  return SCIP_OKAY;
5062  }
5063 
5064  /* nonlinear -> break out to error case */
5065  break;
5066  }
5067 
5068  case SCIP_EXPR_PLUS: /* just recurse */
5069  {
5070  SCIP_EXPR** children;
5071  children = SCIPexprGetChildren( expr );
5072  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[0], scalar, varcoeffs, constant ) );
5073  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[1], scalar, varcoeffs, constant ) );
5074  return SCIP_OKAY;
5075  }
5076 
5077  case SCIP_EXPR_MINUS: /* recursion on second child is called with negated scalar */
5078  {
5079  SCIP_EXPR** children;
5080  children = SCIPexprGetChildren( expr );
5081  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[0], scalar, varcoeffs, constant ) );
5082  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[1], -scalar, varcoeffs, constant ) );
5083  return SCIP_OKAY;
5084  }
5085 
5086  case SCIP_EXPR_SUM: /* just recurse */
5087  {
5088  SCIP_EXPR** children;
5089  int nchildren;
5090  int c;
5091 
5092  children = SCIPexprGetChildren(expr);
5093  nchildren = SCIPexprGetNChildren(expr);
5094 
5095  for( c = 0; c < nchildren; ++c )
5096  {
5097  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[c], scalar, varcoeffs, constant ) );
5098  }
5099 
5100  return SCIP_OKAY;
5101  }
5102 
5103  case SCIP_EXPR_LINEAR: /* add scaled constant and recurse on children with their coeff multiplied into scalar */
5104  {
5105  SCIP_Real* childCoeffs;
5106  SCIP_EXPR** children;
5107  int i;
5108 
5109  *constant += scalar * SCIPexprGetLinearConstant( expr );
5110 
5111  children = SCIPexprGetChildren( expr );
5112  childCoeffs = SCIPexprGetLinearCoefs( expr );
5113 
5114  for( i = 0; i < SCIPexprGetNChildren( expr ); ++i )
5115  {
5116  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[i], scalar * childCoeffs[i], varcoeffs, constant ) );
5117  }
5118 
5119  return SCIP_OKAY;
5120  }
5121 
5122  default:
5123  break;
5124  } /*lint !e788*/
5125 
5126  SCIPerrorMessage( "Cannot extract linear coefficients from expressions with operator %d %s\n", SCIPexprGetOperator( expr ), SCIPexpropGetName(SCIPexprGetOperator( expr )));
5127  SCIPABORT();
5128  return SCIP_ERROR; /*lint !e527*/
5129 }
5130 
5131 /** adds estimator from user callback of a constraints user expression tree to a row
5132  */
5133 static
5135  SCIP* scip, /**< SCIP data structure */
5136  SCIP_CONS* cons, /**< constraint */
5137  int exprtreeidx, /**< for which tree an estimator should be added */
5138  SCIP_Real* x, /**< value of expression tree variables where to generate cut */
5139  SCIP_Bool overestimate, /**< whether to compute an overestimator instead of an underestimator */
5140  SCIP_ROWPREP* rowprep, /**< rowprep where to add estimator */
5141  SCIP_Bool* success /**< buffer to store whether an estimator was succefully added to the rowprep */
5142  )
5143 {
5144  SCIP_CONSDATA* consdata;
5145  SCIP_EXPRTREE* exprtree;
5146  SCIP_EXPR** children;
5147  SCIP_VAR** vars;
5148  SCIP_Real* params;
5149  SCIP_INTERVAL* varbounds;
5150 
5151  SCIP_INTERVAL* childbounds;
5152  SCIP_Real* childvals;
5153  SCIP_Real* childcoeffs;
5154 
5155  SCIP_Real constant;
5156  SCIP_Real treecoef;
5157  int nvars;
5158  int nchildren;
5159  int i;
5160 
5161  consdata = SCIPconsGetData( cons );
5162  assert( consdata != NULL );
5163  assert( exprtreeidx >= 0 );
5164  assert( exprtreeidx < consdata->nexprtrees );
5165  assert( consdata->exprtrees != NULL );
5166  assert( rowprep != NULL );
5167  assert( success != NULL );
5168 
5169  exprtree = consdata->exprtrees[exprtreeidx];
5170  assert( exprtree != NULL );
5171  assert( SCIPexprGetOperator(SCIPexprtreeGetRoot(exprtree)) == SCIP_EXPR_USER );
5172 
5173  /* if user did not implement estimator callback, then we cannot do anything */
5175  {
5176  *success = FALSE;
5177  return SCIP_OKAY;
5178  }
5179 
5180  params = SCIPexprtreeGetParamVals( exprtree );
5181  nvars = SCIPexprtreeGetNVars( exprtree );
5182  vars = SCIPexprtreeGetVars( exprtree );
5183  nchildren = SCIPexprGetNChildren( SCIPexprtreeGetRoot( exprtree ) );
5184  children = SCIPexprGetChildren( SCIPexprtreeGetRoot( exprtree ) );
5185 
5186  /* Get bounds of variables */
5187  SCIP_CALL( SCIPallocBufferArray( scip, &varbounds, nchildren ) );
5188 
5189  for( i = 0; i < nvars; ++i )
5190  {
5191  double lb = SCIPvarGetLbLocal( vars[i] );
5192  double ub = SCIPvarGetUbLocal( vars[i] );
5193  SCIPintervalSetBounds( &varbounds[i],
5194  -infty2infty( SCIPinfinity( scip ), INTERVALINFTY, -MIN( lb, ub ) ),
5195  +infty2infty( SCIPinfinity( scip ), INTERVALINFTY, MAX( lb, ub ) ) );
5196  }
5197 
5198  /* Compute bounds and solution value for the user expressions children */
5199  SCIP_CALL( SCIPallocBufferArray( scip, &childcoeffs, nchildren ) );
5200  SCIP_CALL( SCIPallocBufferArray( scip, &childbounds, nchildren ) );
5201  SCIP_CALL( SCIPallocBufferArray( scip, &childvals, nchildren ) );
5202 
5203  for( i = 0; i < nchildren; ++i )
5204  {
5205  SCIP_CALL( SCIPexprEval( children[i], x, params, &childvals[i] ) );
5206  SCIP_CALL( SCIPexprEvalInt( children[i], INTERVALINFTY, varbounds, params, &childbounds[i] ) );
5207  }
5208 
5209  /* varbounds not needed any longer */
5210  SCIPfreeBufferArray( scip, &varbounds );
5211 
5212  /* call estimator for user expressions to compute coeffs and constant for the user expressions children */
5213  SCIP_CALL( SCIPexprEstimateUser( SCIPexprtreeGetRoot( exprtree ), INTERVALINFTY, childvals, childbounds, overestimate, childcoeffs, &constant, success ) );
5214 
5215  if( *success )
5216  {
5217  SCIP_Real* varcoeffs;
5218  SCIP_CALL( SCIPallocBufferArray( scip, &varcoeffs, nvars ) );
5219 
5220  treecoef = consdata->nonlincoefs[exprtreeidx];
5221  constant *= treecoef;
5222 
5223  for( i = 0; i < nchildren; ++i )
5224  {
5225  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[i], childcoeffs[i]*treecoef, varcoeffs, &constant ) );
5226  }
5227 
5228  SCIPaddRowprepConstant(rowprep, constant);
5229  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, nvars, vars, varcoeffs) );
5230 
5231  SCIPfreeBufferArray( scip, &varcoeffs );
5232  }
5233 
5234  SCIPfreeBufferArray( scip, &childcoeffs );
5235  SCIPfreeBufferArray( scip, &childbounds );
5236  SCIPfreeBufferArray( scip, &childvals );
5237 
5238  return SCIP_OKAY;
5239 }
5240 
5241 /** adds estimator from interval gradient of a constraints univariate expression tree to a row
5242  * a reference point is used to decide in which corner to generate the cut
5243  */
5244 static
5246  SCIP* scip, /**< SCIP data structure */
5247  SCIP_EXPRINT* exprint, /**< expression interpreter */
5248  SCIP_CONS* cons, /**< constraint */
5249  int exprtreeidx, /**< for which tree a secant should be added */
5250  SCIP_Real* x, /**< value of expression tree variables where to generate cut */
5251  SCIP_Bool newx, /**< whether the last evaluation of the expression with the expression interpreter was not at x */
5252  SCIP_Bool overestimate, /**< whether to compute an overestimator instead of an underestimator */
5253  SCIP_ROWPREP* rowprep, /**< rowprep where to add estimator */
5254  SCIP_Bool* success /**< buffer to store whether an estimator was succefully added to the rowprep */
5255  )
5256 {
5257  SCIP_CONSDATA* consdata;
5258  SCIP_EXPRTREE* exprtree;
5259  SCIP_Real treecoef;
5260  SCIP_Real* coefs;
5261  SCIP_Real constant;
5262  SCIP_Real val;
5263  SCIP_Real lb;
5264  SCIP_Real ub;
5265  SCIP_INTERVAL* box;
5266  SCIP_INTERVAL* intgrad;
5267  SCIP_INTERVAL intval;
5268  SCIP_VAR** vars;
5269  int nvars;
5270  int i;
5271 
5272  assert(scip != NULL);
5273  assert(cons != NULL);
5274  assert(x != NULL);
5275  assert(rowprep != NULL);
5276  assert(success != NULL);
5277 
5278  consdata = SCIPconsGetData(cons);
5279  assert(consdata != NULL);
5280  assert(exprtreeidx >= 0);
5281  assert(exprtreeidx < consdata->nexprtrees);
5282  assert(consdata->exprtrees != NULL);
5283 
5284  exprtree = consdata->exprtrees[exprtreeidx];
5285  assert(exprtree != NULL);
5286  assert(newx || SCIPexprtreeGetInterpreterData(exprtree) != NULL);
5287 
5288  *success = FALSE;
5289 
5290  /* skip interval gradient if expression interpreter cannot compute interval gradients */
5292  return SCIP_OKAY;
5293 
5294  nvars = SCIPexprtreeGetNVars(exprtree);
5295  vars = SCIPexprtreeGetVars(exprtree);
5296 
5297  box = NULL;
5298  intgrad = NULL;
5299  coefs = NULL;
5300 
5301  SCIP_CALL( SCIPallocBufferArray(scip, &box, nvars) );
5302 
5303  /* move reference point to bounds, setup box */
5304  for( i = 0; i < nvars; ++i )
5305  {
5306  lb = SCIPvarGetLbLocal(vars[i]);
5307  ub = SCIPvarGetUbLocal(vars[i]);
5308  if( SCIPisInfinity(scip, -lb) )
5309  {
5310  if( SCIPisInfinity(scip, ub) )
5311  {
5312  SCIPdebugMsg(scip, "skip interval gradient estimator for constraint <%s> because variable <%s> is still unbounded.\n", SCIPconsGetName(cons), SCIPvarGetName(vars[i]));
5313  goto INTGRADESTIMATOR_CLEANUP;
5314  }
5315  x[i] = ub;
5316  }
5317  else
5318  {
5319  if( SCIPisInfinity(scip, ub) )
5320  x[i] = lb;
5321  else
5322  x[i] = (2.0*x[i] < lb+ub) ? lb : ub;
5323  }
5324  SCIPintervalSetBounds(&box[i],
5325  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -MIN(lb, ub)),
5326  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, MAX(lb, ub)));
5327  }
5328 
5329  /* compile expression if evaluated the first time; can only happen if newx is FALSE */
5330  if( newx && SCIPexprtreeGetInterpreterData(exprtree) == NULL )
5331  {
5332  SCIP_CALL( SCIPexprintCompile(exprint, exprtree) );
5333  }
5334 
5335  /* evaluate in reference point */
5336  SCIP_CALL( SCIPexprintEval(exprint, exprtree, x, &val) );
5337  if( !SCIPisFinite(val) )
5338  {
5339  SCIPdebugMsg(scip, "Got nonfinite function value from evaluation of constraint %s tree %d. skipping interval gradient estimator.\n", SCIPconsGetName(cons), exprtreeidx);
5340  goto INTGRADESTIMATOR_CLEANUP;
5341  }
5342 
5343  treecoef = consdata->nonlincoefs[exprtreeidx];
5344  val *= treecoef;
5345  constant = val;
5346 
5347  /* compute interval gradient */
5348  SCIP_CALL( SCIPallocBufferArray(scip, &intgrad, nvars) );
5349  SCIP_CALL( SCIPexprintGradInt(exprint, exprtree, INTERVALINFTY, box, TRUE, &intval, intgrad) );
5350  SCIPintervalMulScalar(INTERVALINFTY, &intval, intval, treecoef);
5351 
5352  /* printf("nvars %d side %d xref = %g x = [%g,%g] intval = [%g,%g] intgrad = [%g,%g]\n", nvars, side, x[0],
5353  box[0].inf, box[0].sup, intval.inf, intval.sup, intgrad[0].inf, intgrad[0].sup); */
5354 
5355  /* compute coefficients and constant */
5356  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
5357  for( i = 0; i < nvars; ++i )
5358  {
5359  val = x[i];
5360  lb = SCIPintervalGetInf(box[i]);
5361  ub = SCIPintervalGetSup(box[i]);
5362 
5363  SCIPintervalMulScalar(INTERVALINFTY, &intgrad[i], intgrad[i], treecoef);
5364 
5365  if( SCIPisEQ(scip, lb, ub) )
5366  coefs[i] = 0.0;
5367  else if( (overestimate && val == ub) || /*lint !e777*/
5368  (!overestimate && val == lb) ) /*lint !e777*/
5369  coefs[i] = SCIPintervalGetInf(intgrad[i]);
5370  else
5371  coefs[i] = SCIPintervalGetSup(intgrad[i]);
5372 
5373  if( SCIPisZero(scip, coefs[i]) )
5374  continue;
5375 
5376  if( SCIPisInfinity(scip, -coefs[i]) || SCIPisInfinity(scip, coefs[i]) )
5377  {
5378  SCIPdebugMsg(scip, "skip intgrad estimator because of infinite interval bound\n");
5379  goto INTGRADESTIMATOR_CLEANUP;
5380  }
5381 
5382  constant -= coefs[i] * val;
5383  }
5384 
5385  /* add interval gradient estimator to row */
5386  SCIPaddRowprepConstant(rowprep, constant);
5387  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, nvars, vars, coefs) );
5388 
5389  INTGRADESTIMATOR_CLEANUP:
5390  SCIPfreeBufferArrayNull(scip, &box);
5391  SCIPfreeBufferArrayNull(scip, &intgrad);
5392  SCIPfreeBufferArrayNull(scip, &coefs);
5393 
5394  return SCIP_OKAY;
5395 }
5396 
5397 /** generates a cut based on linearization (if convex), secant (if concave), or intervalgradient (if indefinite)
5398  */
5399 static
5401  SCIP* scip, /**< SCIP data structure */
5402  SCIP_EXPRINT* exprint, /**< expression interpreter */
5403  SCIP_CONS* cons, /**< constraint */
5404  SCIP_Real** ref, /**< reference point for each exprtree, or NULL if sol should be used */
5405  SCIP_SOL* sol, /**< reference solution where cut should be generated, or NULL if LP solution should be used */
5406  SCIP_Bool newsol, /**< whether the last evaluation of the expression with the expression interpreter was not at sol */
5407  SCIP_SIDETYPE side, /**< for which side a cut should be generated */
5408  SCIP_ROW** row, /**< storage for cut */
5409  SCIP_Real minviol, /**< minimal absolute violation we try to achieve */
5410  SCIP_Real maxrange, /**< maximal range allowed */
5411  SCIP_Bool expensivecurvchecks,/**< whether also expensive checks should be executed */
5412  SCIP_Bool assumeconvex /**< whether to assume convexity in inequalities */
5413  )
5414 {
5415  SCIP_ROWPREP* rowprep;
5416  SCIP_CONSDATA* consdata;
5417  SCIP_Bool success;
5418  SCIP_Real* x;
5419  int i;
5420 
5421  assert(scip != NULL);
5422  assert(cons != NULL);
5423  assert(row != NULL);
5424 
5425  SCIPdebugMsg(scip, "constructing cut for %s hand side of constraint <%s>\n", side == SCIP_SIDETYPE_LEFT ? "left" : "right", SCIPconsGetName(cons));
5426 
5427  SCIP_CALL( checkCurvature(scip, cons, expensivecurvchecks, assumeconvex) );
5428 
5429  consdata = SCIPconsGetData(cons);
5430  assert(consdata != NULL);
5431 
5432  if( consdata->nexprtrees == 0 )
5433  {
5434  char rowname[SCIP_MAXSTRLEN];
5435  (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%u", SCIPconsGetName(cons), ++(consdata->ncuts));
5436 
5437  /* if we are actually linear, add the constraint as row to the LP */
5438  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), rowname, consdata->lhs, consdata->rhs, SCIPconsIsLocal(cons), FALSE , TRUE) );
5439  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
5440  return SCIP_OKAY;
5441  }
5442 
5443  SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, side,
5444  !(side == SCIP_SIDETYPE_LEFT && (consdata->curvature & SCIP_EXPRCURV_CONCAVE)) &&
5445  !(side == SCIP_SIDETYPE_RIGHT && (consdata->curvature & SCIP_EXPRCURV_CONVEX ))) );
5446  SCIPaddRowprepSide(rowprep, side == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
5447  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_%u", SCIPconsGetName(cons), ++(consdata->ncuts));
5448 
5449  if( ref == NULL )
5450  {
5451  SCIP_CALL( SCIPallocBufferArray(scip, &x, SCIPexprtreeGetNVars(consdata->exprtrees[0])) );
5452  }
5453 
5454  success = TRUE;
5455  for( i = 0; i < consdata->nexprtrees; ++i )
5456  {
5457  if( ref == NULL )
5458  {
5459  SCIP_CALL( SCIPreallocBufferArray(scip, &x, SCIPexprtreeGetNVars(consdata->exprtrees[i])) ); /*lint !e644*/
5460  SCIP_CALL( SCIPgetSolVals(scip, sol, SCIPexprtreeGetNVars(consdata->exprtrees[i]), SCIPexprtreeGetVars(consdata->exprtrees[i]), x) );
5461  }
5462  else
5463  {
5464  x = ref[i];
5465  }
5466 
5467  if( (side == SCIP_SIDETYPE_LEFT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONCAVE)) ||
5468  (side == SCIP_SIDETYPE_RIGHT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONVEX )) )
5469  {
5470  SCIP_CALL( addLinearization(scip, exprint, cons, i, x, newsol, rowprep, &success) );
5471  }
5472  else if( (side == SCIP_SIDETYPE_LEFT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONVEX)) ||
5473  ( side == SCIP_SIDETYPE_RIGHT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONCAVE)) )
5474  {
5475  switch( SCIPexprtreeGetNVars(consdata->exprtrees[i]) )
5476  {
5477  case 1:
5478  SCIP_CALL( addConcaveEstimatorUnivariate(scip, cons, i, rowprep, &success) );
5479  break;
5480 
5481  case 2:
5482  SCIP_CALL( addConcaveEstimatorBivariate(scip, cons, i, x, rowprep, &success) );
5483  break;
5484 
5485  default:
5486  SCIP_CALL( addConcaveEstimatorMultivariate(scip, cons, i, x, rowprep, &success) );
5487  break;
5488  }
5489  if( !success )
5490  {
5491  SCIPdebugMsg(scip, "failed to generate polyhedral estimator for %d-dim concave function in exprtree %d, fall back to intervalgradient cut\n", SCIPexprtreeGetNVars(consdata->exprtrees[i]), i);
5492  SCIP_CALL( addIntervalGradientEstimator(scip, exprint, cons, i, x, newsol, side == SCIP_SIDETYPE_LEFT, rowprep, &success) );
5493  }
5494  }
5495  else if( SCIPexprGetOperator( SCIPexprtreeGetRoot( consdata->exprtrees[i] ) ) == SCIP_EXPR_USER )
5496  {
5497  SCIP_CALL( addUserEstimator( scip, cons, i, x, side == SCIP_SIDETYPE_LEFT, rowprep, &success ) );
5498  if( !success ) /* the user estimation may not be implemented -> try interval estimator */
5499  {
5500  SCIP_CALL( addIntervalGradientEstimator(scip, exprint, cons, i, x, newsol, side == SCIP_SIDETYPE_LEFT, rowprep, &success) );
5501  }
5502  }
5503  else
5504  {
5505  SCIP_CALL( addIntervalGradientEstimator(scip, exprint, cons, i, x, newsol, side == SCIP_SIDETYPE_LEFT, rowprep, &success) );
5506  }
5507 
5508  if( !success )
5509  break;
5510  }
5511 
5512  if( ref == NULL )
5513  {
5514  SCIPfreeBufferArray(scip, &x);
5515  }
5516 
5517  if( success )
5518  {
5519  SCIP_Real coefrange;
5520 
5521  /* add coefficients for linear variables */
5522  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
5523 
5524  /* merge terms in same variable */
5525  SCIPmergeRowprepTerms(scip, rowprep);
5526 
5527  /* cleanup row */
5528  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, maxrange, minviol, &coefrange, NULL) );
5529 
5530  /* check that coefficient range is ok */
5531  success = coefrange <= maxrange;
5532 
5533  /* check that side is finite */ /*lint --e{514} */
5534  success &= !SCIPisInfinity(scip, REALABS(rowprep->side));
5535 
5536  /* check whether maximal coef is finite, if any */
5537  success &= (rowprep->nvars == 0) || !SCIPisInfinity(scip, REALABS(rowprep->coefs[0]));
5538  }
5539 
5540  if( success )
5541  {
5542  SCIP_CALL( SCIPgetRowprepRowCons(scip, row, rowprep, SCIPconsGetHdlr(cons)) );
5543  }
5544  else
5545  *row = NULL;
5546 
5547  SCIPfreeRowprep(scip, &rowprep);
5548 
5549  return SCIP_OKAY;
5550 }
5551 
5552 /** tries to separate solution or LP solution by a linear cut
5553  *
5554  * assumes that constraint violations have been computed
5555  */
5556 static
5558  SCIP* scip, /**< SCIP data structure */
5559  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
5560  SCIP_CONS** conss, /**< constraints */
5561  int nconss, /**< number of constraints */
5562  int nusefulconss, /**< number of constraints that seem to be useful */
5563  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
5564  SCIP_Bool newsol, /**< have the constraints just been evaluated at this point? */
5565  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
5566  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
5567  SCIP_RESULT* result, /**< result of separation */
5568  SCIP_Real* bestefficacy /**< buffer to store best efficacy of a cut that was added to the LP, if found; or NULL if not of interest */
5569  )
5570 {
5572  SCIP_CONSDATA* consdata;
5573  SCIP_Real efficacy;
5574  SCIP_Real feasibility;
5575  SCIP_Real norm;
5576  SCIP_SIDETYPE violside;
5577  int c;
5578  SCIP_ROW* row;
5579 
5580  assert(scip != NULL);
5581  assert(conshdlr != NULL);
5582  assert(conss != NULL || nconss == 0);
5583  assert(nusefulconss <= nconss);
5584  assert(result != NULL);
5585 
5586  *result = SCIP_FEASIBLE;
5587 
5588  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5589  assert(conshdlrdata != NULL);
5590 
5591  if( bestefficacy != NULL )
5592  *bestefficacy = 0.0;
5593 
5594  for( c = 0, violside = SCIP_SIDETYPE_LEFT; c < nconss; c = (violside == SCIP_SIDETYPE_RIGHT ? c+1 : c), violside = (violside == SCIP_SIDETYPE_LEFT ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT) )
5595  {
5596  assert(conss != NULL);
5597 
5598  /* skip constraints that are not enabled */
5599  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
5600  continue;
5601  assert(SCIPconsIsActive(conss[c]));
5602 
5603  consdata = SCIPconsGetData(conss[c]);
5604  assert(consdata != NULL);
5605 
5606  /* if side violside of cons c not violated, then continue to next side or next cons */
5607  if( !SCIPisGT(scip, violside == SCIP_SIDETYPE_LEFT ? consdata->lhsviol : consdata->rhsviol, SCIPfeastol(scip)) )
5608  continue;
5609 
5610  /* we are not feasible anymore */
5611  if( *result == SCIP_FEASIBLE )
5612  *result = SCIP_DIDNOTFIND;
5613 
5614  /* generate cut
5615  * if function is defined at sol (activity<infinity) and constraint is violated, then expression interpreter should have evaluated at sol to get gradient before
5616  */
5617  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], NULL, sol, newsol || SCIPisInfinity(scip, consdata->activity), violside, &row, minefficacy, conshdlrdata->cutmaxrange, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
5618 
5619  if( row == NULL ) /* failed to generate cut */
5620  continue;
5621 
5622  if( sol == NULL )
5623  feasibility = SCIPgetRowLPFeasibility(scip, row);
5624  else
5625  feasibility = SCIPgetRowSolFeasibility(scip, row, sol);
5626 
5627  switch( conshdlrdata->scaling )
5628  {
5629  case 'o' :
5630  efficacy = -feasibility;
5631  break;
5632 
5633  case 'g' :
5634  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
5635  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too also
5636  * we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
5637  * scaling) */
5638  norm = SCIPgetRowMaxCoef(scip, row);
5639  efficacy = -feasibility / MAX(1.0, norm);
5640  break;
5641 
5642  case 's' :
5643  {
5644  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
5645  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
5646  SCIP_Real minval = MIN(abslhs, absrhs);
5647 
5648  efficacy = -feasibility / MAX(1.0, minval);
5649  break;
5650  }
5651 
5652  default:
5653  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
5654  SCIPABORT();
5655  return SCIP_INVALIDDATA; /*lint !e527*/
5656  }
5657 
5658  if( (SCIPisGT(scip, efficacy, minefficacy) ||
5659  (inenforcement &&
5660  ( (violside == SCIP_SIDETYPE_RIGHT && (consdata->curvature & SCIP_EXPRCURV_CONVEX )) ||
5661  (violside == SCIP_SIDETYPE_LEFT && (consdata->curvature & SCIP_EXPRCURV_CONCAVE)) ) &&
5662  SCIPisGT(scip, efficacy, SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip))
5663  )
5664  ) && SCIPisCutApplicable(scip, row)
5665  )
5666  {
5667  SCIP_Bool infeasible;
5668 
5669  /* cut cuts off solution */
5670  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE /* forcecut */, &infeasible) );
5671  if ( infeasible )
5672  *result = SCIP_CUTOFF;
5673  else
5674  *result = SCIP_SEPARATED;
5675 
5676  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
5677 
5678  SCIPdebugMsg(scip, "add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy, SCIPconsGetName(conss[c]), MAX(consdata->lhsviol, consdata->rhsviol));
5679  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
5680 
5681  if( bestefficacy != NULL && efficacy > *bestefficacy )
5682  *bestefficacy = efficacy;
5683 
5684  /* mark row as not removable from LP for current node, if in enforcement */
5685  if( inenforcement && !conshdlrdata->enfocutsremovable )
5686  SCIPmarkRowNotRemovableLocal(scip, row);
5687  }
5688  else
5689  {
5690  SCIPdebugMsg(scip, "drop cut since efficacy %g is too small (< %g)\n", efficacy, minefficacy);
5691  }
5692 
5693  SCIP_CALL( SCIPreleaseRow (scip, &row) );
5694 
5695  if ( *result == SCIP_CUTOFF )
5696  break;
5697 
5698  /* enforce only useful constraints
5699  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
5700  */
5701  if( c >= nusefulconss && *result == SCIP_SEPARATED )
5702  break;
5703  }
5704 
5705  return SCIP_OKAY;
5706 }
5707 
5708 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
5709  * if separatedlpsol is not NULL, then a cut that separates the LP solution is added to the sepastore and is forced to enter the LP
5710  * if separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only
5711  * if separatedlpsol is NULL, then cut is added to cutpool only
5712  */
5713 static
5715  SCIP* scip, /**< SCIP data structure */
5716  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
5717  SCIP_CONS** conss, /**< constraints */
5718  int nconss, /**< number of constraints */
5719  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
5720  SCIP_Bool* separatedlpsol, /**< buffer to store whether a cut that separates the current LP solution was found and added to LP, or NULL if adding to cutpool only */
5721  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
5722  )
5723 {
5725  SCIP_CONSDATA* consdata;
5726  SCIP_Bool addedtolp;
5727  SCIP_ROW* row;
5728  int c;
5729 
5730  assert(scip != NULL);
5731  assert(conshdlr != NULL);
5732  assert(conss != NULL || nconss == 0);
5733 
5734  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5735  assert(conshdlrdata != NULL);
5736 
5737  if( separatedlpsol != NULL )
5738  *separatedlpsol = FALSE;
5739 
5740  for( c = 0; c < nconss; ++c )
5741  {
5742  assert(conss[c] != NULL); /*lint !e613*/
5743 
5744  if( SCIPconsIsLocal(conss[c]) ) /*lint !e613*/
5745  continue;
5746 
5747  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) ); /*lint !e613*/
5748 
5749  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
5750  assert(consdata != NULL);
5751 
5752  /* if we cannot linearize, then skip constraint */
5753  if( (!(consdata->curvature & SCIP_EXPRCURV_CONVEX) || SCIPisInfinity(scip, consdata->rhs)) &&
5754  ( !(consdata->curvature & SCIP_EXPRCURV_CONCAVE) || SCIPisInfinity(scip, -consdata->lhs)) )
5755  continue;
5756 
5757  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], NULL, ref, TRUE,
5758  (consdata->curvature & SCIP_EXPRCURV_CONVEX) ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT,
5759  &row, minefficacy, conshdlrdata->cutmaxrange, FALSE, FALSE) ); /*lint !e613*/
5760 
5761  if( row == NULL )
5762  continue;
5763 
5764  addedtolp = FALSE;
5765 
5766  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
5767  if( separatedlpsol != NULL )
5768  {
5769  SCIP_Real efficacy;
5770  SCIP_Real norm;
5771 
5772  efficacy = -SCIPgetRowLPFeasibility(scip, row);
5773  switch( conshdlrdata->scaling )
5774  {
5775  case 'o' :
5776  break;
5777 
5778  case 'g' :
5779  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
5780  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too also
5781  * we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
5782  * scaling) */
5783  norm = SCIPgetRowMaxCoef(scip, row);
5784  efficacy /= MAX(1.0, norm);
5785  break;
5786 
5787  case 's' :
5788  {
5789  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
5790  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
5791  SCIP_Real minval = MIN(abslhs, absrhs);
5792 
5793  efficacy /= MAX(1.0, minval);
5794  break;
5795  }
5796  default:
5797  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
5798  SCIPABORT();
5799  return SCIP_INVALIDDATA; /*lint !e527*/
5800  }
5801 
5802  if( efficacy >= minefficacy )
5803  {
5804  SCIP_Bool infeasible;
5805 
5806  *separatedlpsol = TRUE;
5807  addedtolp = TRUE;
5808  SCIP_CALL( SCIPaddCut(scip, NULL, row, TRUE, &infeasible) );
5809  assert( ! infeasible );
5810  }
5811  }
5812 
5813  if( !SCIProwIsLocal(row) && !addedtolp )
5814  {
5815  SCIP_CALL( SCIPaddPoolCut(scip, row) );
5816  }
5817 
5818  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5819  }
5820 
5821  return SCIP_OKAY;
5822 }
5823 
5824 /** processes the event that a new primal solution has been found */
5825 static
5826 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
5829  SCIP_CONSHDLR* conshdlr;
5830  SCIP_CONS** conss;
5831  int nconss;
5832  SCIP_SOL* sol;
5833 
5834  assert(scip != NULL);
5835  assert(event != NULL);
5836  assert(eventdata != NULL);
5837  assert(eventhdlr != NULL);
5838 
5839  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
5840 
5841  conshdlr = (SCIP_CONSHDLR*)eventdata;
5842 
5843  nconss = SCIPconshdlrGetNConss(conshdlr);
5844 
5845  if( nconss == 0 )
5846  return SCIP_OKAY;
5847 
5848  sol = SCIPeventGetSol(event);
5849  assert(sol != NULL);
5850 
5851  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5852  assert(conshdlrdata != NULL);
5853 
5854  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
5855  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
5856  * or are from the tree, but postprocessed via proposeFeasibleSolution
5857  */
5858  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
5859  return SCIP_OKAY;
5860 
5861  conss = SCIPconshdlrGetConss(conshdlr);
5862  assert(conss != NULL);
5863 
5864  SCIPdebugMsg(scip, "catched new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
5865 
5866  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
5867 
5868  return SCIP_OKAY;
5869 }
5870 
5871 /** registers unfixed variables in nonlinear terms of violated constraints as external branching candidates */
5872 static
5874  SCIP* scip, /**< SCIP data structure */
5875  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5876  SCIP_CONS** conss, /**< constraints to check */
5877  int nconss, /**< number of constraints to check */
5878  int* nnotify /**< counter for number of notifications performed */
5879  )
5880 {
5881  SCIP_CONSDATA* consdata;
5882  SCIP_VAR* var;
5883  int c;
5884  int i;
5885  int j;
5886 
5887  assert(scip != NULL);
5888  assert(conshdlr != NULL);
5889  assert(conss != NULL || nconss == 0);
5890 
5891  *nnotify = 0;
5892 
5893  for( c = 0; c < nconss; ++c )
5894  {
5895  assert(conss != NULL);
5896  consdata = SCIPconsGetData(conss[c]);
5897  assert(consdata != NULL);
5898 
5899  if( consdata->nexprtrees == 0 )
5900  continue;
5901 
5902  /* do not branch on violation of convex constraint */
5903  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || (consdata->curvature & SCIP_EXPRCURV_CONCAVE)) &&
5904  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || (consdata->curvature & SCIP_EXPRCURV_CONVEX )) )
5905  continue;
5906  SCIPdebugMsg(scip, "cons <%s> violation: %g %g curvature: %s\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, SCIPexprcurvGetName(consdata->curvature));
5907 
5908  for( i = 0; i < consdata->nexprtrees; ++i )
5909  {
5910  /* skip convex summands */
5911  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || (consdata->curvatures[i] & SCIP_EXPRCURV_CONCAVE)) &&
5912  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || (consdata->curvatures[i] & SCIP_EXPRCURV_CONVEX )) )
5913  continue;
5914 
5915  for( j = 0; j < SCIPexprtreeGetNVars(consdata->exprtrees[i]); ++j )
5916  {
5917  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[j];
5918  assert(var != NULL);
5919 
5920  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
5921  {
5922  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], width %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
5923  continue;
5924  }
5925 
5926  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
5927  ++*nnotify;
5928  }
5929  }
5930  }
5931 
5932  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
5933 
5934  return SCIP_OKAY;
5935 }
5936 
5937 /** registers a nonlinear variable from a violated constraint as branching candidate that has a large absolute value in the relaxation */
5938 static
5940  SCIP* scip, /**< SCIP data structure */
5941  SCIP_CONS** conss, /**< constraints */
5942  int nconss, /**< number of constraints */
5943  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
5944  SCIP_VAR** brvar /**< buffer to store branching variable */
5945  )
5946 {
5947  SCIP_CONSDATA* consdata;
5948  SCIP_VAR* var;
5949  SCIP_Real val;
5950  SCIP_Real brvarval;
5951  int i;
5952  int j;
5953  int c;
5954 
5955  assert(scip != NULL);
5956  assert(conss != NULL || nconss == 0);
5957 
5958  *brvar = NULL;
5959  brvarval = -1.0;
5960 
5961  for( c = 0; c < nconss; ++c )
5962  {
5963  assert(conss != NULL);
5964  consdata = SCIPconsGetData(conss[c]);
5965  assert(consdata != NULL);
5966 
5967  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5968  continue;
5969 
5970  for( j = 0; j < consdata->nexprtrees; ++j )
5971  {
5972  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]); ++i )
5973  {
5974  var = SCIPexprtreeGetVars(consdata->exprtrees[j])[i];
5975  /* do not propose fixed variables */
5976  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
5977  continue;
5978  val = SCIPgetSolVal(scip, sol, var);
5979  if( REALABS(val) > brvarval )
5980  {
5981  brvarval = ABS(val);
5982  *brvar = var;
5983  }
5984  }
5985  }
5986  }
5987 
5988  if( *brvar != NULL )
5989  {
5990  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
5991  }
5992 
5993  return SCIP_OKAY;
5994 }
5995 
5996 /** replaces violated nonlinear constraints where all nonlinear variables are fixed by linear constraints
5997  * only adds constraint if it is violated in current solution
5998  */
5999 static
6001  SCIP* scip, /**< SCIP data structure */
6002  SCIP_CONS** conss, /**< constraints */
6003  int nconss, /**< number of constraints */
6004  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
6005  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
6006  SCIP_Bool* infeasible /**< whether we detected infeasibility */
6007  )
6008 {
6009  SCIP_CONS* cons;
6010  SCIP_CONSDATA* consdata;
6011  SCIP_Real lhs;
6012  SCIP_Real rhs;
6013  SCIP_RESULT checkresult;
6014  int c;
6015  int i;
6016 
6017  assert(scip != NULL);
6018  assert(conss != NULL || nconss == 0);
6019  assert(addedcons != NULL);
6020  assert(reduceddom != NULL);
6021  assert(infeasible != NULL);
6022 
6023  *addedcons = FALSE;
6024  *reduceddom = FALSE;
6025  *infeasible = FALSE;
6026 
6027  for( c = 0; c < nconss; ++c )
6028  {
6029  assert(conss != NULL);
6030  consdata = SCIPconsGetData(conss[c]);
6031  assert(consdata != NULL);
6032 
6033  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6034  continue;
6035 
6036  lhs = consdata->lhs;
6037  rhs = consdata->rhs;
6038 
6039  for( i = 0; i < consdata->nexprtrees; ++i )
6040  {
6041  SCIP_INTERVAL nonlinactivity;
6042 
6043  SCIP_CALL( SCIPevalExprtreeLocalBounds(scip, consdata->exprtrees[i], INTERVALINFTY, &nonlinactivity) );
6044  SCIPintervalMulScalar(INTERVALINFTY, &nonlinactivity, nonlinactivity, consdata->nonlincoefs[i]);
6045 
6046  if( !SCIPisInfinity(scip, -lhs) )
6047  {
6048  if( SCIPintervalGetSup(nonlinactivity) >= INTERVALINFTY )
6049  lhs = -SCIPinfinity(scip);
6050  else if( SCIPintervalGetSup(nonlinactivity) <= -INTERVALINFTY )
6051  {
6052  /* lhs <= [...,-infinity] + ... will never be feasible */
6053  *infeasible = TRUE;
6054  return SCIP_OKAY;
6055  }
6056  else
6057  lhs -= SCIPintervalGetSup(nonlinactivity);
6058  }
6059 
6060  if( !SCIPisInfinity(scip, rhs) )
6061  {
6062  if( SCIPintervalGetInf(nonlinactivity) <= -INTERVALINFTY )
6063  rhs = SCIPinfinity(scip);
6064  else if( SCIPintervalGetInf(nonlinactivity) >= INTERVALINFTY )
6065  {
6066  /* [infinity,...] + ... <= rhs will never be feasible */
6067  *infeasible = TRUE;
6068  return SCIP_OKAY;
6069  }
6070  else
6071  rhs -= SCIPintervalGetInf(nonlinactivity);
6072  }
6073  }
6074 
6075  /* check if we have a bound change */
6076  if ( consdata->nlinvars == 0 )
6077  {
6078  assert(SCIPisFeasLE(scip, lhs, rhs));
6079  }
6080  else if ( consdata->nlinvars == 1 )
6081  {
6082  SCIP_Bool tightened;
6083  SCIP_Real coef;
6084 
6085  coef = *consdata->lincoefs;
6086  SCIPdebugMsg(scip, "Linear constraint with one variable: %g <= %g <%s> <= %g\n", lhs, coef, SCIPvarGetName(*consdata->linvars), rhs);
6087 
6088  /* possibly correct lhs/rhs */
6089  assert( ! SCIPisZero(scip, coef) );
6090  if ( coef >= 0.0 )
6091  {
6092  if ( ! SCIPisInfinity(scip, -lhs) )
6093  lhs /= coef;
6094  if ( ! SCIPisInfinity(scip, rhs) )
6095  rhs /= coef;
6096  }
6097  else
6098  {
6099  SCIP_Real h;
6100  h = rhs;
6101  if ( ! SCIPisInfinity(scip, -lhs) )
6102  rhs = lhs/coef;
6103  else
6104  rhs = SCIPinfinity(scip);
6105 
6106  if ( ! SCIPisInfinity(scip, h) )
6107  lhs = h/coef;
6108  else
6109  lhs = -SCIPinfinity(scip);
6110  }
6111  SCIPdebugMsg(scip, "Linear constraint is a bound: %g <= <%s> <= %g\n", lhs, SCIPvarGetName(*consdata->linvars), rhs);
6112 
6113  /* cut off the node if SCIP needs to tight the lb/ub to +/-inf */
6114  if( SCIPisInfinity(scip, lhs) || SCIPisInfinity(scip, -rhs) )
6115  {
6116  *infeasible = TRUE;
6117  assert(consdata->linvars[0] != NULL);
6118  SCIPwarningMessage(scip, "Activity of nonlinear part is beyond SCIP's value for infinity. To enforce "
6119  "the constraint %s SCIP needs to tight bounds of %s to a value beyond +/- infinity. Please check if "
6120  "finite bounds can be added.\n", SCIPconsGetName(conss[c]), SCIPvarGetName(consdata->linvars[0]));
6121  return SCIP_OKAY;
6122  }
6123 
6124  if ( ! SCIPisInfinity(scip, -lhs) )
6125  {
6126  SCIP_CALL( SCIPtightenVarLb(scip, *consdata->linvars, lhs, TRUE, infeasible, &tightened) );
6127  if ( *infeasible )
6128  {
6129  SCIPdebugMsg(scip, "Lower bound leads to infeasibility.\n");
6130  return SCIP_OKAY;
6131  }
6132  if ( tightened )
6133  {
6134  SCIPdebugMsg(scip, "Lower bound changed.\n");
6135  *reduceddom = TRUE;
6136  return SCIP_OKAY;
6137  }
6138  }
6139 
6140  if ( ! SCIPisInfinity(scip, rhs) )
6141  {
6142  SCIP_CALL( SCIPtightenVarUb(scip, *consdata->linvars, rhs, TRUE, infeasible, &tightened) );
6143  if ( *infeasible )
6144  {
6145  SCIPdebugMsg(scip, "Upper bound leads to infeasibility.\n");
6146  return SCIP_OKAY;
6147  }
6148  if ( tightened )
6149  {
6150  SCIPdebugMsg(scip, "Upper bound changed.\n");
6151  *reduceddom = TRUE;
6152  return SCIP_OKAY;
6153  }
6154  }
6155  }
6156  else
6157  {
6158  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
6159  consdata->nlinvars, consdata->linvars, consdata->lincoefs, lhs, rhs,
6160  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
6161  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
6162  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
6163  SCIPconsIsStickingAtNode(conss[c])) );
6164 
6165  SCIPdebugMsg(scip, "replace violated nonlinear constraint <%s> by linear constraint after all nonlinear vars have been fixed\n", SCIPconsGetName(conss[c]) );
6166  SCIPdebugPrintCons(scip, conss[c], NULL);
6167  SCIPdebugPrintCons(scip, cons, NULL);
6168 
6169  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
6170 
6171  if( checkresult != SCIP_INFEASIBLE && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
6172  {
6173  SCIPdebugMsg(scip, "linear constraint is feasible, thus do not add\n");
6174  }
6175  else
6176  {
6177  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
6178  *addedcons = TRUE;
6179  }
6180  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
6181  }
6182  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
6183  }
6184 
6185  return SCIP_OKAY;
6186 }
6187 
6188 /* tightens a lower bound on a variable and checks the result */
6189 static
6191  SCIP* scip, /**< SCIP data structure */
6192  SCIP_CONS* cons, /**< constraint where we currently propagate, or NULL if tightening is from expression graph */
6193  SCIP_VAR* var, /**< variable which domain we might reduce */
6194  SCIP_Real bnd, /**< new lower bound for variable */
6195  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
6196  int* nchgbds /**< counter to increase if a bound was tightened */
6197  )
6198 {
6199  SCIP_Bool infeas;
6200  SCIP_Bool tightened;
6201 
6202  assert(scip != NULL);
6203  assert(bnd > -INTERVALINFTY);
6204  assert(var != NULL);
6205  assert(result != NULL);
6206  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
6207  assert(nchgbds != NULL);
6208 
6209  if( SCIPisInfinity(scip, bnd) )
6210  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
6211  *result = SCIP_CUTOFF;
6212  if( cons != NULL )
6213  {
6214  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6215  }
6216  return SCIP_OKAY;
6217  }
6218 
6219  /* new lower bound is very low (between -INTERVALINFTY and -SCIPinfinity()) */
6220  if( SCIPisInfinity(scip, -bnd) )
6221  return SCIP_OKAY;
6222 
6223  bnd = SCIPadjustedVarLb(scip, var, bnd);
6224  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
6225  if( infeas )
6226  {
6227  SCIPdebugMsg(scip, "%sfound constraint <%s> infeasible due to tightened lower bound %g for variable <%s>\n", SCIPinProbing(scip) ? "in probing " : "", cons != NULL ? SCIPconsGetName(cons) : "??", bnd, SCIPvarGetName(var)); /*lint !e585*/
6228  *result = SCIP_CUTOFF;
6229  if( cons != NULL )
6230  {
6231  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6232  }
6233  return SCIP_OKAY;
6234  }
6235  if( tightened )
6236  {
6237  SCIPdebugMsg(scip, "%stightened lower bound of variable <%s> in constraint <%s> to %.20g\n", SCIPinProbing(scip) ? "in probing " : "", SCIPvarGetName(var), cons != NULL ? SCIPconsGetName(cons) : "??", bnd); /*lint !e585*/
6238  ++*nchgbds;
6239  *result = SCIP_REDUCEDDOM;
6240  if( cons != NULL )
6241  {
6242  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6243  }
6244  }
6245 
6246  return SCIP_OKAY;
6247 }
6248 
6249 /* tightens an upper bound on a variable and checks the result */
6250 static
6252  SCIP* scip, /**< SCIP data structure */
6253  SCIP_CONS* cons, /**< constraint where we currently propagate, or NULL if tightening is from expression graph */
6254  SCIP_VAR* var, /**< variable which domain we might reduce */
6255  SCIP_Real bnd, /**< new upper bound for variable */
6256  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
6257  int* nchgbds /**< counter to increase if a bound was tightened */
6258  )
6259 {
6260  SCIP_Bool infeas;
6261  SCIP_Bool tightened;
6262 
6263  assert(scip != NULL);
6264  assert(bnd < INTERVALINFTY);
6265  assert(var != NULL);
6266  assert(result != NULL);
6267  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
6268  assert(nchgbds != NULL);
6269 
6270  if( SCIPisInfinity(scip, -bnd) )
6271  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
6272  *result = SCIP_CUTOFF;
6273  if( cons != NULL )
6274  {
6275  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6276  }
6277  return SCIP_OKAY;
6278  }
6279 
6280  /* new upper bound is very high (between SCIPinfinity() and INTERVALINFTY) */
6281  if( SCIPisInfinity(scip, bnd) )
6282  return SCIP_OKAY;
6283 
6284  bnd = SCIPadjustedVarUb(scip, var, bnd);
6285  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
6286  if( infeas )
6287  {
6288  SCIPdebugMsg(scip, "%sfound constraint <%s> infeasible due to tightened upper bound %g for variable <%s>\n", SCIPinProbing(scip) ? "in probing " : "", cons != NULL ? SCIPconsGetName(cons) : "??", bnd, SCIPvarGetName(var)); /*lint !e585*/
6289  *result = SCIP_CUTOFF;
6290  if( cons != NULL )
6291  {
6292  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6293  }
6294  return SCIP_OKAY;
6295  }
6296  if( tightened )
6297  {
6298  SCIPdebugMsg(scip, "%stightened upper bound of variable <%s> in constraint <%s> to %g\n", SCIPinProbing(scip) ? "in probing " : "", SCIPvarGetName(var), cons != NULL ? SCIPconsGetName(cons) : "??", bnd); /*lint !e585*/
6299  ++*nchgbds;
6300  *result = SCIP_REDUCEDDOM;
6301  if( cons != NULL )
6302  {
6303  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6304  }
6305  }
6306 
6307  return SCIP_OKAY;
6308 }
6309 
6310 /** tightens bounds of linear variables in a single nonlinear constraint */
6311 static
6313  SCIP* scip, /**< SCIP data structure */
6314  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6315  SCIP_CONS* cons, /**< constraint to process */
6316  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
6317  int* nchgbds, /**< buffer where to add the the number of changed bounds */
6318  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
6319  )
6320 { /*lint --e{666}*/
6321  SCIP_CONSDATA* consdata;
6322  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
6323  SCIP_INTERVAL consactivity; /* activity of linear plus nonlinear part */
6324  SCIP_VAR* var;
6325  SCIP_INTERVAL rhs; /* right hand side of nonlinear equation */
6326  SCIP_ROUNDMODE roundmode;
6327  SCIP_Real bnd;
6328  int i;
6329  SCIP_INTERVAL nonlinactivity;
6330 
6331  assert(scip != NULL);
6332  assert(conshdlr != NULL);
6333  assert(cons != NULL);
6334  assert(result != NULL);
6335  assert(nchgbds != NULL);
6336 
6337  consdata = SCIPconsGetData(cons);
6338  assert(consdata != NULL);
6339 
6340  *result = SCIP_DIDNOTRUN;
6341  *redundant = FALSE;
6342 
6343  if( !SCIPconsIsMarkedPropagate(cons) )
6344  return SCIP_OKAY;
6345 
6346  *result = SCIP_DIDNOTFIND;
6347 
6348  SCIPdebugMsg(scip, "start linear vars domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
6349 
6350  /* unmark constraint for propagation */
6351  SCIP_CALL( SCIPunmarkConsPropagate(scip, cons) );
6352 
6353  /* make sure we have activity of linear term */
6354  consdataUpdateLinearActivity(scip, consdata);
6355  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777*/
6356  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777*/
6357  assert(consdata->minlinactivityinf >= 0);
6358  assert(consdata->maxlinactivityinf >= 0);
6359  assert(consdata->exprgraphnode != NULL || consdata->nexprtrees == 0);
6360 
6361  /* get activity of nonlinear part, should have been updated in propagateBounds */
6362  if( consdata->exprgraphnode != NULL )
6363  {
6364  nonlinactivity = SCIPexprgraphGetNodeBounds(consdata->exprgraphnode);
6365  }
6366  else
6367  {
6368  SCIPintervalSet(&nonlinactivity, 0.0);
6369  }
6370  assert(!SCIPintervalIsEmpty(INTERVALINFTY, nonlinactivity) );
6371 
6372  /* @todo adding SCIPepsilon may be sufficient? */
6373  SCIPintervalSetBounds(&consbounds,
6374  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -consdata->lhs + SCIPfeastol(scip)),
6375  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, consdata->rhs + SCIPfeastol(scip)));
6376 
6377  /* check redundancy and infeasibility */
6378  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -INTERVALINFTY : consdata->minlinactivity, consdata->maxlinactivityinf > 0 ? INTERVALINFTY : consdata->maxlinactivity);
6379  SCIPintervalAdd(INTERVALINFTY, &consactivity, consactivity, nonlinactivity);
6380  if( SCIPintervalIsSubsetEQ(INTERVALINFTY, consactivity, consbounds) )
6381  {
6382  SCIPdebugMsg(scip, "found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
6383  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
6384  *redundant = TRUE;
6385  return SCIP_OKAY;
6386  }
6387 
6388  if( SCIPintervalAreDisjoint(consbounds, consactivity) )
6389  {
6390  SCIPdebugMsg(scip, "found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %.20g\n",
6391  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
6392  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
6393  *result = SCIP_CUTOFF;
6394  return SCIP_OKAY;
6395  }
6396 
6397  /* propagate linear part in rhs = consbounds - nonlinactivity (use the one from consdata, since that includes infinities) */
6398  SCIPintervalSub(INTERVALINFTY, &rhs, consbounds, nonlinactivity);
6399  if( !SCIPintervalIsEntire(INTERVALINFTY, rhs) )
6400  {
6401  SCIP_Real coef;
6402 
6403  for( i = 0; i < consdata->nlinvars; ++i )
6404  {
6405  coef = consdata->lincoefs[i];
6406  var = consdata->linvars[i];
6407 
6408  /* skip fixed variables
6409  * @todo is that a good or a bad idea?
6410  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
6411  */
6412  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6413  continue;
6414 
6415  if( coef > 0.0 )
6416  {
6417  if( SCIPintervalGetSup(rhs) < INTERVALINFTY )
6418  {
6419  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777*/
6420  /* try to tighten the upper bound on var x */
6421  if( consdata->minlinactivityinf == 0 )
6422  {
6423  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
6424  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
6425  roundmode = SCIPintervalGetRoundingMode();
6427  bnd = SCIPintervalGetSup(rhs);
6428  bnd -= consdata->minlinactivity;
6429  bnd += coef * SCIPvarGetLbLocal(var);
6430  bnd /= coef;
6431  SCIPintervalSetRoundingMode(roundmode);
6432  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
6433  if( *result == SCIP_CUTOFF )
6434  break;
6435  }
6436  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
6437  {
6438  /* x was the variable that made the minimal linear activity equal -infinity, so
6439  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
6440  roundmode = SCIPintervalGetRoundingMode();
6442  bnd = SCIPintervalGetSup(rhs);
6443  bnd -= consdata->minlinactivity;
6444  bnd /= coef;
6445  SCIPintervalSetRoundingMode(roundmode);
6446  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
6447  if( *result == SCIP_CUTOFF )
6448  break;
6449  }
6450  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
6451  }
6452 
6453  if( SCIPintervalGetInf(rhs) > -INTERVALINFTY )
6454  {
6455  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777*/
6456  /* try to tighten the lower bound on var x */
6457  if( consdata->maxlinactivityinf == 0 )
6458  {
6459  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
6460  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
6461  roundmode = SCIPintervalGetRoundingMode();
6463  bnd = SCIPintervalGetInf(rhs);
6464  bnd -= consdata->maxlinactivity;
6465  bnd += coef * SCIPvarGetUbLocal(var);
6466  bnd /= coef;
6467  SCIPintervalSetRoundingMode(roundmode);
6468  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6469  if( *result == SCIP_CUTOFF )
6470  break;
6471  }
6472  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6473  {
6474  /* x was the variable that made the maximal linear activity equal infinity, so
6475  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
6476  roundmode = SCIPintervalGetRoundingMode();
6478  bnd = SCIPintervalGetInf(rhs);
6479  bnd -= consdata->maxlinactivity;
6480  bnd /= coef;
6481  SCIPintervalSetRoundingMode(roundmode);
6482  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6483  if( *result == SCIP_CUTOFF )
6484  break;
6485  }
6486  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
6487  }
6488  }
6489  else
6490  {
6491  assert(coef < 0.0 );
6492  if( SCIPintervalGetInf(rhs) > -INTERVALINFTY )
6493  {
6494  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777*/
6495  /* try to tighten the upper bound on var x */
6496  if( consdata->maxlinactivityinf == 0 )
6497  {
6498  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
6499  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
6500  roundmode = SCIPintervalGetRoundingMode();
6502  bnd = consdata->maxlinactivity;
6503  bnd += (-coef) * SCIPvarGetLbLocal(var);
6504  bnd -= SCIPintervalGetInf(rhs);
6505  bnd /= (-coef);
6506  SCIPintervalSetRoundingMode(roundmode);
6507  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
6508  if( *result == SCIP_CUTOFF )
6509  break;
6510  }
6511  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
6512  {
6513  /* x was the variable that made the maximal linear activity equal infinity, so
6514  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
6515  roundmode = SCIPintervalGetRoundingMode();
6517  bnd = consdata->maxlinactivity;
6518  bnd -= SCIPintervalGetInf(rhs);
6519  bnd /= (-coef);
6520  SCIPintervalSetRoundingMode(roundmode);
6521  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
6522  if( *result == SCIP_CUTOFF )
6523  break;
6524  }
6525  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
6526  }
6527 
6528  if( SCIPintervalGetSup(rhs) < INTERVALINFTY )
6529  {
6530  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777*/
6531  /* try to tighten the lower bound on var x */
6532  if( consdata->minlinactivityinf == 0 )
6533  {
6534  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
6535  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
6536  roundmode = SCIPintervalGetRoundingMode();
6538  bnd = consdata->minlinactivity;
6539  bnd += (-coef) * SCIPvarGetUbLocal(var);
6540  bnd -= SCIPintervalGetSup(rhs);
6541  bnd /= (-coef);
6542  SCIPintervalSetRoundingMode(roundmode);
6543  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6544  if( *result == SCIP_CUTOFF )
6545  break;
6546  }
6547  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6548  {
6549  /* x was the variable that made the maximal linear activity equal -infinity, so
6550  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
6551  roundmode = SCIPintervalGetRoundingMode();
6553  bnd = consdata->minlinactivity;
6554  bnd -= SCIPintervalGetSup(rhs);
6555  bnd /= (-coef);
6556  SCIPintervalSetRoundingMode(roundmode);
6557  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6558  if( *result == SCIP_CUTOFF )
6559  break;
6560  }
6561  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
6562  }
6563  }
6564  }
6565  if( *result == SCIP_CUTOFF )
6566  return SCIP_OKAY;
6567  }
6568 
6569  return SCIP_OKAY;
6570 }
6571 
6572 /** propagate constraints sides minus linear activity into nonlinear variables */
6573 static
6575  SCIP* scip, /**< SCIP data structure */
6576  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6577  SCIP_CONS** conss, /**< constraints to process */
6578  int nconss, /**< number of constraints */
6579  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
6580  int* nchgbds /**< buffer where to add the number of changed bounds */
6581  )
6582 {
6584  SCIP_CONSDATA* consdata;
6585  int nvars;
6586  SCIP_VAR** vars;
6587  SCIP_EXPRGRAPHNODE** varnodes;
6588  SCIP_INTERVAL bounds;
6589  SCIP_Bool cutoff;
6590  SCIP_ROUNDMODE roundmode;
6591  int c;
6592  int i;
6593 
6594  assert(scip != NULL);
6595  assert(conshdlr != NULL);
6596  assert(result != NULL);
6597  assert(nchgbds != NULL);
6598 
6599  *result = SCIP_DIDNOTFIND;
6600 
6601  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6602  assert(conshdlrdata != NULL);
6603  assert(conshdlrdata->exprgraph != NULL);
6604 
6605  SCIPdebugMsg(scip, "start backward propagation in expression graph\n");
6606 
6607 #ifdef SCIP_OUTPUT
6608  {
6609  FILE* file;
6610  file = fopen("exprgraph_propconss1.dot", "w");
6611  if( file != NULL )
6612  {
6614  fclose(file);
6615  }
6616  }
6617 #endif
6618 
6619  /* put constraint sides less linear activity into expression graph nodes
6620  * also add a [-feastol,feastol] range around constraint sides to cope with numerics */
6621  for( c = 0; c < nconss; ++c )
6622  {
6623  consdata = SCIPconsGetData(conss[c]);
6624  assert(consdata != NULL);
6625 
6626  if( consdata->exprgraphnode == NULL )
6627  continue;
6628 
6629  /* skip (just) deleted or disabled constraints */
6630  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsEnabled(conss[c]) )
6631  continue;
6632 
6633  roundmode = SCIPintervalGetRoundingMode();
6635 
6636  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->maxlinactivityinf == 0 )
6637  bounds.inf = consdata->lhs - consdata->maxlinactivity - SCIPfeastol(scip);
6638  else
6639  bounds.inf = -INTERVALINFTY;
6640 
6641  if( !SCIPisInfinity(scip, consdata->rhs) && consdata->minlinactivityinf == 0 )
6642  bounds.sup = SCIPintervalNegateReal(consdata->minlinactivity - consdata->rhs - SCIPfeastol(scip));
6643  else
6644  bounds.sup = INTERVALINFTY;
6645 
6646  SCIPintervalSetRoundingMode(roundmode);
6647 
6648  /* if we want the expression graph to propagate the bounds in any case, we set minstrength to a negative value */
6649  SCIPexprgraphTightenNodeBounds(conshdlrdata->exprgraph, consdata->exprgraphnode, bounds,
6650  consdata->forcebackprop ? -1.0 : BOUNDTIGHTENING_MINSTRENGTH, INTERVALINFTY, &cutoff);
6651  consdata->forcebackprop = FALSE; /* do this only once */
6652 
6653  if( cutoff )
6654  {
6655  SCIPdebugMsg(scip, "found constraint <%s> infeasible%s\n", SCIPconsGetName(conss[c]), SCIPinProbing(scip) ? " in probing" : "");
6656  *result = SCIP_CUTOFF;
6657  return SCIP_OKAY;
6658  }
6659  }
6660 
6661  /* compute bound tightenings for nonlinear variables */
6663 
6664 #ifdef SCIP_OUTPUT
6665  {
6666  FILE* file;
6667  file = fopen("exprgraph_propconss2.dot", "w");
6668  if( file != NULL )
6669  {
6671  fclose(file);
6672  }
6673  }
6674 #endif
6675 
6676  if( cutoff )
6677  {
6678  SCIPdebugMsg(scip, "backward propagation found problem infeasible%s\n", SCIPinProbing(scip) ? " in probing" : "");
6679  *result = SCIP_CUTOFF;
6680  return SCIP_OKAY;
6681  }
6682 
6683  /* put tighter bounds into variables */
6684  nvars = SCIPexprgraphGetNVars(conshdlrdata->exprgraph);
6685  vars = (SCIP_VAR**)SCIPexprgraphGetVars(conshdlrdata->exprgraph);
6686  varnodes = SCIPexprgraphGetVarNodes(conshdlrdata->exprgraph);
6687 
6688  /* put back new bounds into SCIP variables */
6689  for( i = 0; i < nvars && *result != SCIP_CUTOFF; ++i )
6690  {
6691  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(varnodes[i]))) )
6692  {
6693  SCIP_CALL( propagateBoundsTightenVarLb(scip, NULL, vars[i], SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(varnodes[i])), result, nchgbds) );
6694  }
6695  if( *result != SCIP_CUTOFF && !SCIPisInfinity(scip, SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(varnodes[i]))) )
6696  {
6697  SCIP_CALL( propagateBoundsTightenVarUb(scip, NULL, vars[i], SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(varnodes[i])), result, nchgbds) );
6698  }
6699  }
6700 
6701  return SCIP_OKAY;
6702 }
6703 
6704 /** calls domain propagation for a set of constraints */
6705 static
6707  SCIP* scip, /**< SCIP data structure */
6708  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6709  SCIP_CONS** conss, /**< constraints to process */
6710  int nconss, /**< number of constraints */
6711  SCIP_Bool needclear, /**< whether we may need to clear remainings from a previous backward propagation */
6712  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
6713  int* nchgbds, /**< buffer where to add the the number of changed bounds */
6714  int* ndelconss /**< buffer where to increase if a constraint was deleted (locally) due to redundancy */
6715  )
6716 {
6717 #ifndef NDEBUG
6718  SCIP_CONSDATA* consdata;
6719 #endif
6721  SCIP_RESULT propresult;
6722  SCIP_Bool domainerror;
6723  SCIP_Bool redundant;
6724  int roundnr;
6725  SCIP_Bool success;
6726  int c;
6727 
6728  assert(scip != NULL);
6729  assert(conshdlr != NULL);
6730  assert(conss != NULL || nconss == 0);
6731  assert(result != NULL);
6732  assert(nchgbds != NULL);
6733  assert(ndelconss != NULL);
6734 
6735  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6736  assert(conshdlrdata != NULL);
6737  assert(conshdlrdata->exprgraph != NULL);
6738 
6739  if( nconss == 0 || conshdlrdata->ispropagated )
6740  {
6741  *result = SCIP_DIDNOTRUN;
6742  return SCIP_OKAY;
6743  }
6744 
6745  *result = SCIP_DIDNOTFIND;
6746 
6747  roundnr = 0;
6748  do
6749  {
6750  success = FALSE;
6751 
6752  SCIPdebugMsg(scip, "starting domain propagation round %d for %d constraints\n", roundnr, nconss);
6753 
6754  conshdlrdata->ispropagated = TRUE;
6755 
6756  /* propagate variable bounds through expression graph
6757  * roundnr == 0 clears remainings from a previous backward propagation
6758  * @todo could give FALSE if no linear variable in the constraints had been relaxed since last time
6759  */
6760  SCIP_CALL( SCIPexprgraphPropagateVarBounds(conshdlrdata->exprgraph, INTERVALINFTY, (roundnr == 0) && needclear, &domainerror) );
6761 
6762 #ifdef SCIP_OUTPUT
6763  {
6764  FILE* file;
6765  file = fopen("exprgraph_propvars.dot", "w");
6766  if( file != NULL )
6767  {
6769  fclose(file);
6770  }
6771  }
6772 #endif
6773 
6774  if( domainerror )
6775  {
6776  SCIPdebugMsg(scip, "current bounds out of domain for some expression, do cutoff\n");
6777  *result = SCIP_CUTOFF;
6778  break;
6779  }
6780 
6781  /* check for redundancy and infeasibility of constraints, tighten bounds on linear variables */
6782  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
6783  {
6784  assert(conss != NULL);
6785  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
6786  continue;
6787  assert(SCIPconsIsActive(conss[c]));
6788 
6789 #ifndef NDEBUG
6790  consdata = SCIPconsGetData(conss[c]);
6791  assert(consdata != NULL);
6792  assert(consdata->exprgraphnode == NULL || !SCIPintervalIsEmpty(INTERVALINFTY, SCIPexprgraphGetNodeBounds(consdata->exprgraphnode)));
6793 #endif
6794 
6795  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
6796  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
6797  {
6798  *result = propresult;
6799  success = TRUE;
6800  }
6801  if( redundant )
6802  {
6803  SCIPdebugMsg(scip, "delete redundant constraint <%s> locally\n", SCIPconsGetName(conss[c]));
6804  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
6805  ++*ndelconss;
6806  }
6807  }
6808 
6809  /* propagate backward through expression graph */
6810  if( *result != SCIP_CUTOFF )
6811  {
6812  propresult = SCIP_DIDNOTFIND;
6813  SCIP_CALL( propagateConstraintSides(scip, conshdlr, conss, nconss, &propresult, nchgbds) );
6814 
6815  if( propresult != SCIP_DIDNOTFIND )
6816  {
6817  *result = propresult;
6818  success = TRUE;
6819  }
6820  }
6821  }
6822  while( success && *result != SCIP_CUTOFF && ++roundnr < conshdlrdata->maxproprounds );
6823 
6824  return SCIP_OKAY;
6825 }
6826 
6827 /* checks for a linear variable that can be increase or decreased without harming feasibility */
6828 static
6830  SCIP* scip, /**< SCIP data structure */
6831  SCIP_CONSDATA* consdata /**< constraint data */
6832  )
6833 {
6834  int i;
6835  int poslock;
6836  int neglock;
6837 
6838  consdata->linvar_maydecrease = -1;
6839  consdata->linvar_mayincrease = -1;
6840 
6841  /* check for a linear variable that can be increase or decreased without harming feasibility
6842  * setup lincoefsmin, lincoefsmax */
6843  for( i = 0; i < consdata->nlinvars; ++i )
6844  {
6845  /* compute locks of i'th linear variable */
6846  assert(consdata->lincoefs[i] != 0.0);
6847  if( consdata->lincoefs[i] > 0.0 )
6848  {
6849  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
6850  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
6851  }
6852  else
6853  {
6854  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
6855  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
6856  }
6857 
6858  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - neglock == 0 )
6859  {
6860  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
6861  /* if we have already one candidate, then take the one where the loss in the objective function is less */
6862  if( (consdata->linvar_maydecrease < 0) ||
6863  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
6864  consdata->linvar_maydecrease = i;
6865  }
6866 
6867  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - poslock == 0 )
6868  {
6869  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
6870  /* if we have already one candidate, then take the one where the loss in the objective function is less */
6871  if( (consdata->linvar_mayincrease < 0) ||
6872  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
6873  consdata->linvar_mayincrease = i;
6874  }
6875  }
6876 
6877 #ifdef SCIP_DEBUG
6878  if( consdata->linvar_mayincrease >= 0 )
6879  {
6880  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
6881  }
6882  if( consdata->linvar_maydecrease >= 0 )
6883  {
6884  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
6885  }
6886 #endif
6887 }
6888 
6889 /** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
6890  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
6891  * The method assumes that this is always possible and that not all constraints are feasible already.
6892  */
6893 static
6895  SCIP* scip, /**< SCIP data structure */
6896  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6897  SCIP_CONS** conss, /**< constraints to process */
6898  int nconss, /**< number of constraints */
6899  SCIP_SOL* sol, /**< solution to process */
6900  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
6901  )
6902 {
6904  SCIP_CONSDATA* consdata;
6905  SCIP_SOL* newsol;
6906  SCIP_VAR* var;
6907  int c;
6908  SCIP_Real viol;
6909  SCIP_Real delta;
6910  SCIP_Real gap;
6911  SCIP_Bool solviolbounds;
6912 
6913  assert(scip != NULL);
6914  assert(conshdlr != NULL);
6915  assert(conss != NULL || nconss == 0);
6916  assert(success != NULL);
6917 
6918  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6919  assert(conshdlrdata != NULL);
6920  assert(conshdlrdata->trysolheur != NULL);
6921 
6922  *success = FALSE;
6923 
6924  /* don't propose new solutions if not in presolve or solving */
6926  return SCIP_OKAY;
6927 
6928  if( sol != NULL )
6929  {
6930  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
6931  }
6932  else
6933  {
6934  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
6935  }
6936  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
6937 
6938  for( c = 0; c < nconss; ++c )
6939  {
6940  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6941  assert(consdata != NULL);
6942 
6943  /* recompute violation of solution in case solution has changed
6944  * get absolution violation and sign */
6945  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
6946  {
6947  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
6948  assert(!solviolbounds);
6949  viol = consdata->lhs - consdata->activity;
6950  }
6951  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6952  {
6953  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
6954  assert(!solviolbounds);
6955  viol = consdata->rhs - consdata->activity;
6956  }
6957  else
6958  continue; /* constraint is satisfied */
6959 
6960  assert(viol != 0.0);
6961  if( consdata->linvar_mayincrease >= 0 &&
6962  (( viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) ||
6963  (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
6964  {
6965  /* have variable where increasing makes the constraint less violated */
6966  var = consdata->linvars[consdata->linvar_mayincrease];
6967  /* compute how much we would like to increase var */
6968  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
6969  assert(delta > 0.0);
6970  /* if var has an upper bound, may need to reduce delta */
6971  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
6972  {
6973  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
6974  delta = MIN(MAX(0.0, gap), delta);
6975  }
6976  if( SCIPisPositive(scip, delta) )
6977  {
6978  /* if variable is integral, round delta up so that it will still have an integer value */
6979  if( SCIPvarIsIntegral(var) )
6980  delta = SCIPceil(scip, delta);
6981 
6982  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
6983  SCIPdebugMsg(scip, "increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
6984 
6985  /* adjust constraint violation, if satisfied go on to next constraint */
6986  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
6987  if( SCIPisZero(scip, viol) )
6988  continue;
6989  }
6990  }
6991 
6992  assert(viol != 0.0);
6993  if( consdata->linvar_maydecrease >= 0 &&
6994  (( viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) ||
6995  (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
6996  {
6997  /* have variable where decreasing makes constraint less violated */
6998  var = consdata->linvars[consdata->linvar_maydecrease];
6999  /* compute how much we would like to decrease var */
7000  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
7001  assert(delta < 0.0);
7002  /* if var has a lower bound, may need to reduce delta */
7003  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
7004  {
7005  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
7006  delta = MAX(MIN(0.0, gap), delta);
7007  }
7008  if( SCIPisNegative(scip, delta) )
7009  {
7010  /* if variable is integral, round delta down so that it will still have an integer value */
7011  if( SCIPvarIsIntegral(var) )
7012  delta = SCIPfloor(scip, delta);
7013  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
7014  SCIPdebugMsg(scip, "increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
7015 
7016  /* adjust constraint violation, if satisfied go on to next constraint */
7017  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
7018  if( SCIPisZero(scip, viol) )
7019  continue;
7020  }
7021  }
7022 
7023  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
7024  break;
7025  }
7026 
7027  /* if we have a solution that should satisfy all nonlinear constraints and has a better objective than the current upper bound,
7028  * then pass it to the trysol heuristic */
7029  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
7030  {
7031  SCIPdebugMsg(scip, "pass solution with objective value %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
7032 
7033  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
7034  *success = TRUE;
7035  }
7036 
7037  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
7038 
7039  return SCIP_OKAY;
7040 }
7041 
7042 /** helper function to enforce constraints */
7043 static
7045  SCIP* scip, /**< SCIP data structure */
7046  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
7047  SCIP_CONS** conss, /**< constraints to process */
7048  int nconss, /**< number of constraints */
7049  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
7050  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7051  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
7052  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7053  )
7054 {
7056  SCIP_CONSDATA* consdata;
7057  SCIP_CONS* maxviolcons;
7058  SCIP_Real maxviol;
7059  SCIP_RESULT propresult;
7060  SCIP_RESULT separateresult;
7061  int dummy;
7062  int nnotify;
7063  SCIP_Real sepaefficacy;
7064  SCIP_Real minefficacy;
7065  SCIP_Real leastpossibleefficacy;
7066  SCIP_Bool solviolbounds;
7067 
7068  assert(scip != NULL);
7069  assert(conshdlr != NULL);
7070  assert(conss != NULL || nconss == 0);
7071 
7072  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7073  assert(conshdlrdata != NULL);
7074 
7075  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &solviolbounds, &maxviolcons) );
7076 
7077  if( maxviolcons == NULL )
7078  {
7079  *result = SCIP_FEASIBLE;
7080  return SCIP_OKAY;
7081  }
7082 
7083  *result = SCIP_INFEASIBLE;
7084 
7085  if( solviolbounds )
7086  {
7087  /* if LP solution violates variable bounds, then this should be because a row was added that
7088  * introduced this variable newly to the LP, in which case it gets value 0.0; the row should
7089  * have been added to resolve an infeasibility, so solinfeasible should be TRUE
7090  * see also issue #627
7091  */
7092  assert(solinfeasible);
7093  /* however, if solinfeasible is actually not TRUE, then better cut off the node to avoid that SCIP
7094  * stops because infeasible cannot be resolved */ /*lint --e{774} */
7095  if( !solinfeasible )
7096  *result = SCIP_CUTOFF;
7097  return SCIP_OKAY;
7098  }
7099 
7100  consdata = SCIPconsGetData(maxviolcons);
7101  assert(consdata != NULL);
7102 
7103  maxviol = consdata->lhsviol + consdata->rhsviol;
7104  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
7105 
7106  SCIPdebugMsg(scip, "enforcement with max violation %g in cons <%s> for %s solution\n", maxviol, SCIPconsGetName(maxviolcons),
7107  sol == NULL ? "LP" : "relaxation");
7108 
7109  /* we propagate and separate constraints only if they are active and enforcing by branching only does not seem much effective */
7110  assert(SCIPconsIsActive(maxviolcons));
7111 
7112  /* if we are above the 100'th enforcement round for this node, something is strange
7113  * (maybe the LP does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
7114  * in this case, check if some limit is hit or SCIP should stop for some other reason and terminate enforcement by creating a dummy node
7115  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
7116  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
7117  * we only increment nenfolprounds until 101 to avoid an overflow
7118  */
7119  if( conshdlrdata->lastenfonode == SCIPgetCurrentNode(scip) )
7120  {
7121  if( conshdlrdata->nenforounds > 100 )
7122  {
7123  if( SCIPisStopped(scip) )
7124  {
7125  SCIP_NODE* child;
7126 
7127  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
7128  *result = SCIP_BRANCHED;
7129 
7130  return SCIP_OKAY;
7131  }
7132  }
7133  else
7134  ++conshdlrdata->nenforounds;
7135  }
7136  else
7137  {
7138  conshdlrdata->lastenfonode = SCIPgetCurrentNode(scip);
7139  conshdlrdata->nenforounds = 0;
7140  }
7141 
7142  /* run domain propagation */
7143  dummy = 0;
7144  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, TRUE, &propresult, &dummy, &dummy) );
7145  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
7146  {
7147  *result = propresult;
7148  return SCIP_OKAY;
7149  }
7150 
7151  /* we would like a cut that is efficient enough that it is not redundant in the LP (>feastol)
7152  * however, if the maximal violation is very small, also the best cut efficacy cannot be large
7153  * thus, in the latter case, we are also happy if the efficacy is at least, say, 75% of the maximal violation
7154  * but in any case we need an efficacy that is at least feastol
7155  */
7156  minefficacy = MIN(0.75*maxviol, conshdlrdata->mincutefficacyenfofac * SCIPfeastol(scip)); /*lint !e666*/
7157  minefficacy = MAX(minefficacy, SCIPfeastol(scip)); /*lint !e666*/
7158  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, TRUE /* because computeviolation projects point onto box */, minefficacy, TRUE, &separateresult, &sepaefficacy) );
7159  if( separateresult == SCIP_CUTOFF )
7160  {
7161  SCIPdebugMsg(scip, "separation found cutoff\n");
7162  *result = SCIP_CUTOFF;
7163  return SCIP_OKAY;
7164  }
7165  if( separateresult == SCIP_SEPARATED )
7166  {
7167  SCIPdebugMsg(scip, "separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, minefficacy);
7168  *result = SCIP_SEPARATED;
7169  return SCIP_OKAY;
7170  }
7171 
7172  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
7173  * -> collect variables for branching
7174  */
7175 
7176  SCIPdebugMsg(scip, "separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, minefficacy, maxviol);
7177 
7178  /* find branching candidates */
7179  SCIP_CALL( registerBranchingVariables(scip, conshdlr, conss, nconss, &nnotify) );
7180 
7181  /* if sepastore can decrease feasibility tolerance, we can add cuts with efficacy in [eps, feastol] */
7182  leastpossibleefficacy = SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip);
7183  if( nnotify == 0 && !solinfeasible && minefficacy > leastpossibleefficacy )
7184  {
7185  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
7186  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, FALSE, leastpossibleefficacy, TRUE, &separateresult, &sepaefficacy) );
7187  if( separateresult == SCIP_SEPARATED || separateresult == SCIP_CUTOFF )
7188  {
7189  *result = separateresult;
7190  return SCIP_OKAY;
7191  }
7192  }
7193 
7194  if( nnotify == 0 && !solinfeasible )
7195  {
7196  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
7197  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
7198  */
7199  SCIP_VAR* brvar = NULL;
7200  SCIP_CALL( registerLargeRelaxValueVariableForBranching(scip, conss, nconss, sol, &brvar) );
7201  if( brvar == NULL )
7202  {
7203  /* fallback 3: all nonlinear variables in all violated constraints seem to be fixed -> replace by linear constraints */
7204  SCIP_Bool addedcons;
7205  SCIP_Bool reduceddom;
7206  SCIP_Bool infeasible;
7207 
7208  SCIPdebugMsg(scip, "All nonlinear variables seem to be fixed. Replace remaining violated nonlinear constraints by linear constraints.\n");
7209  SCIP_CALL( replaceViolatedByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
7210  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
7211  * when it enforces the new constraints again and nothing resolves the infeasiblity that we declare here thus,
7212  * we only add them if considered violated, and otherwise claim the solution is feasible (but print a
7213  * warning) */
7214  if ( infeasible )
7215  *result = SCIP_CUTOFF;
7216  else if ( addedcons )
7217  *result = SCIP_CONSADDED;
7218  else if ( reduceddom )
7219  *result = SCIP_REDUCEDDOM;
7220  else
7221  {
7222  *result = SCIP_FEASIBLE;
7223  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
7224  assert(!SCIPisInfinity(scip, maxviol));
7225  }
7226  return SCIP_OKAY;
7227  }
7228  else
7229  {
7230  SCIPdebugMsg(scip, "Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
7231  SCIPvarGetName(brvar), SCIPgetSolVal(scip, sol, brvar));
7232  nnotify = 1;
7233  }
7234  }
7235 
7236  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
7237  return SCIP_OKAY;
7238 }
7239 
7240 /*
7241  * Callback methods of constraint handler
7242  */
7243 
7244 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
7245 static
7246 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
7248  assert(scip != NULL);
7249  assert(conshdlr != NULL);
7250  /* assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); */
7251 
7252  /* call inclusion method of constraint handler */
7254 
7255  *valid = TRUE;
7256 
7257  return SCIP_OKAY;
7258 }
7259 
7260 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
7261 static
7262 SCIP_DECL_CONSFREE(consFreeNonlinear)
7265  int i;
7266 
7267  assert(scip != NULL);
7268  assert(conshdlr != NULL);
7269 
7270  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7271  assert(conshdlrdata != NULL);
7272  assert(conshdlrdata->exprinterpreter != NULL);
7273  assert(conshdlrdata->exprgraph != NULL);
7274  assert(SCIPexprgraphGetNVars(conshdlrdata->exprgraph) == 0);
7275 
7276  /* free expression graph */
7277  SCIP_CALL( SCIPexprgraphFree(&conshdlrdata->exprgraph) );
7278 
7279  /* free upgrade functions */
7280  for( i = 0; i < conshdlrdata->nnlconsupgrades; ++i )
7281  {
7282  assert(conshdlrdata->nlconsupgrades[i] != NULL);
7283  SCIPfreeBlockMemory(scip, &conshdlrdata->nlconsupgrades[i]); /*lint !e866*/
7284  }
7285  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlconsupgrades, conshdlrdata->nlconsupgradessize);
7286 
7287  /* free expressions interpreter */
7288  SCIP_CALL( SCIPexprintFree(&conshdlrdata->exprinterpreter) );
7289 
7290  SCIPfreeBlockMemory(scip, &conshdlrdata);
7291 
7292  return SCIP_OKAY;
7293 }
7294 
7295 /** initialization method of constraint handler (called after problem was transformed) */
7296 static
7297 SCIP_DECL_CONSINIT(consInitNonlinear)
7300 
7301  assert(scip != NULL);
7302  assert(conshdlr != NULL);
7303 
7304  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7305  assert(conshdlrdata != NULL);
7306 
7307  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
7308  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
7309 
7310  /* reset counter, since we have a new problem */
7311  conshdlrdata->naddedreformconss = 0;
7312 
7313 #ifdef SCIP_OUTPUT
7314  {
7315  FILE* file;
7316  file = fopen("exprgraph_init.dot", "w");
7317  if( file != NULL )
7318  {
7319  SCIP_CALL( SCIPexprgraphPrintDot(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), file, NULL) );
7320  fclose(file);
7321  }
7322  }
7323 #endif
7324 
7325  return SCIP_OKAY;
7326 } /*lint !e715*/
7327 
7328 /** deinitialization method of constraint handler (called before transformed problem is freed) */
7329 static
7330 SCIP_DECL_CONSEXIT(consExitNonlinear)
7333 
7334  assert(scip != NULL);
7335  assert(conshdlr != NULL);
7336 
7337  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7338  assert(conshdlrdata != NULL);
7339 
7340  conshdlrdata->subnlpheur = NULL;
7341  conshdlrdata->trysolheur = NULL;
7342 
7343  return SCIP_OKAY;
7344 } /*lint !e715*/
7345 
7346 
7347 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
7348 static
7349 SCIP_DECL_CONSINITPRE(consInitpreNonlinear)
7350 { /*lint --e{715}*/
7351  SCIP_CONSDATA* consdata;
7352  int c;
7353 
7354  assert(scip != NULL);
7355  assert(conshdlr != NULL);
7356  assert(conss != NULL || nconss == 0);
7357 
7358  for( c = 0; c < nconss; ++c )
7359  {
7360  /* skip not yet active constraints */
7361  if( !SCIPconsIsActive(conss[c]) ) /*lint !e613*/
7362  continue;
7363 
7364  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
7365  assert(consdata != NULL);
7366 
7367  /* forget expression trees */
7368  assert(consdata->nexprtrees == 0 || consdata->exprgraphnode != NULL);
7369  SCIP_CALL( consdataSetExprtrees(scip, consdata, 0, NULL, NULL, FALSE) );
7370 
7371  /* mark constraint for propagation */
7372  SCIP_CALL( SCIPmarkConsPropagate(scip, conss[c]) ); /*lint !e613*/
7373  }
7374 
7375  return SCIP_OKAY;
7376 }
7377 
7378 
7379 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
7380 static
7381 SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
7382 { /*lint --e{715}*/
7384  SCIP_CONSDATA* consdata;
7385  SCIP_Bool havegraphchange;
7386  SCIP_Bool havechange;
7387  SCIP_Bool domainerror;
7388 #ifndef NDEBUG
7389  int i;
7390  int j;
7391 #endif
7392  int c;
7393 
7394  assert(scip != NULL);
7395  assert(conshdlr != NULL);
7396  assert(conss != NULL || nconss == 0);
7397 
7398  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7399  assert(conshdlrdata != NULL);
7400 
7401  havegraphchange = FALSE;
7402 
7403  if( !conshdlrdata->isremovedfixings )
7404  {
7405  SCIP_CALL( removeFixedNonlinearVariables(scip, conshdlr) );
7406  assert(conshdlrdata->isremovedfixings);
7407 
7408  havegraphchange = TRUE;
7409  }
7410 
7411  /* if undefined expressions in exprgraph (very unlikely), we will hopefully recognize this during domain propagation later (if it involved an active constraint) */
7412  SCIP_CALL( SCIPexprgraphSimplify(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), SCIPepsilon(scip), conshdlrdata->maxexpansionexponent, &havechange, &domainerror) );
7413  SCIPdebugMsg(scip, "expression graph simplifier found %schange, domain error = %u\n", havechange ? "" : "no ", domainerror);
7414  havegraphchange |= havechange;
7415 
7416  /* some of the methods below will not work if there was a domain error (#1148, point 3) */
7417  if( domainerror )
7418  return SCIP_OKAY;
7419 
7420  for( c = 0; c < nconss; ++c )
7421  {
7422  assert(conss != NULL);
7423 
7424  /* skip inactive constraints */
7425  if( !SCIPconsIsActive(conss[c]) )
7426  continue;
7427  assert(SCIPconsIsAdded(conss[c]));
7428 
7429  consdata = SCIPconsGetData(conss[c]);
7430  assert(consdata != NULL);
7431 
7432  if( !consdata->isremovedfixingslin )
7433  {
7434  SCIP_CALL( removeFixedLinearVariables(scip, conss[c]) );
7435  }
7436 
7437  if( !consdata->ispresolved || havegraphchange )
7438  {
7439  SCIP_Bool infeasible;
7440  SCIP_CALL( splitOffLinearPart(scip, conshdlr, conss[c], &infeasible) );
7441 
7442  /* the infeasibility should have been detected during presolve */
7443  assert(!infeasible);
7444  }
7445 
7446  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
7447 
7448  assert(consdata->isremovedfixingslin);
7449  assert(consdata->linvarsmerged);
7450 #ifndef NDEBUG
7451  for( i = 0; i < consdata->nlinvars; ++i )
7452  assert(SCIPvarIsActive(consdata->linvars[i]));
7453 #endif
7454 
7455  if( consdata->exprgraphnode != NULL )
7456  {
7457  /* get expression trees from expression graph */
7458  SCIP_EXPRTREE** exprtrees;
7459  SCIP_Real* coefs;
7460  int nexprtrees;
7461  int exprtreessize;
7462 
7463  exprtreessize = SCIPexprgraphGetSumTreesNSummands(consdata->exprgraphnode);
7464 
7465  SCIP_CALL( SCIPallocBufferArray(scip, &exprtrees, exprtreessize) );
7466  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, exprtreessize) );
7467 
7468  SCIP_CALL( SCIPexprgraphGetSumTrees(conshdlrdata->exprgraph, consdata->exprgraphnode,
7469  exprtreessize, &nexprtrees, exprtrees, coefs) );
7470  assert(nexprtrees > 0);
7471 
7472  SCIP_CALL( consdataSetExprtrees(scip, consdata, nexprtrees, exprtrees, coefs, FALSE) );
7473 
7474  SCIPfreeBufferArray(scip, &exprtrees);
7475  SCIPfreeBufferArray(scip, &coefs);
7476 
7477  assert(consdata->nexprtrees > 0 );
7478 #ifndef NDEBUG
7479  for( j = 0; j < consdata->nexprtrees; ++j )
7480  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]); ++i )
7481  assert(SCIPvarIsActive(SCIPexprtreeGetVars(consdata->exprtrees[j])[i]));
7482 #endif
7483 
7484  /* tell SCIP that we have something nonlinear */
7485  SCIPenableNLP(scip);
7486  }
7487  }
7488 
7489  return SCIP_OKAY;
7490 }
7491 
7492 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
7493 static
7494 SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
7497  SCIP_CONSDATA* consdata;
7498  int c;
7499  int i;
7500 
7501  assert(scip != NULL);
7502  assert(conshdlr != NULL);
7503  assert(conss != NULL || nconss == 0);
7504 
7505  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7506  assert(conshdlrdata != NULL);
7507 
7508  for( c = 0; c < nconss; ++c )
7509  {
7510  assert(conss != NULL);
7511  consdata = SCIPconsGetData(conss[c]);
7512  assert(consdata != NULL);
7513 
7514  /* check for a linear variable that can be increase or decreased without harming feasibility */
7515  consdataFindUnlockedLinearVar(scip, consdata);
7516 
7517  /* setup lincoefsmin, lincoefsmax */
7518  consdata->lincoefsmin = SCIPinfinity(scip);
7519  consdata->lincoefsmax = 0.0;
7520  for( i = 0; i < consdata->nlinvars; ++i )
7521  {
7522  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666*/
7523  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666*/
7524  }
7525 
7526  /* add nlrow respresentation to NLP, if NLP had been constructed */
7527  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
7528  {
7529  if( consdata->nlrow == NULL )
7530  {
7531  /* compute curvature for the nonlinear constraint if not done yet */
7532  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
7533 
7534  SCIP_CALL( createNlRow(scip, conss[c]) );
7535  assert(consdata->nlrow != NULL);
7536  }
7537  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
7538  }
7539  }
7540 
7541  conshdlrdata->newsoleventfilterpos = -1;
7542  if( nconss != 0 )
7543  {
7544  SCIP_EVENTHDLR* eventhdlr;
7545 
7546  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
7547  assert(eventhdlr != NULL);
7548 
7549  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
7550  }
7551 
7552  /* reset flags and counters */
7553  conshdlrdata->sepanlp = FALSE;
7554  conshdlrdata->lastenfonode = NULL;
7555  conshdlrdata->nenforounds = 0;
7556 
7557  return SCIP_OKAY;
7558 }
7559 
7560 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
7561 static
7562 SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
7565  SCIP_CONSDATA* consdata;
7566  int c;
7567 
7568  assert(scip != NULL);
7569  assert(conshdlr != NULL);
7570  assert(conss != NULL || nconss == 0);
7571 
7572  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7573  assert(conshdlrdata != NULL);
7574 
7575  if( conshdlrdata->newsoleventfilterpos >= 0 )
7576  {
7577  SCIP_EVENTHDLR* eventhdlr;
7578 
7579  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
7580  assert(eventhdlr != NULL);
7581 
7582  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
7583  conshdlrdata->newsoleventfilterpos = -1;
7584  }
7585 
7586  for( c = 0; c < nconss; ++c )
7587  {
7588  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
7589  assert(consdata != NULL);
7590 
7591  /* free nonlinear row representation */
7592  if( consdata->nlrow != NULL )
7593  {
7594  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
7595  }
7596  }
7597 
7598  return SCIP_OKAY;
7599 } /*lint !e715*/
7600 
7601 
7602 /** frees specific constraint data */
7603 static
7604 SCIP_DECL_CONSDELETE(consDeleteNonlinear)
7606  assert(scip != NULL);
7607  assert(conshdlr != NULL);
7608  assert(cons != NULL);
7609  assert(!SCIPconsIsActive(cons));
7610  assert(consdata != NULL);
7611  assert(SCIPconsGetData(cons) == *consdata);
7612 
7613  SCIPdebugMsg(scip, "consDelete for cons <%s>\n", SCIPconsGetName(cons));
7614 
7615  /* expression should have been removed from expression graph when constraint was deactivated */
7616  assert((*consdata)->exprgraphnode == NULL);
7617 
7618  SCIP_CALL( consdataFree(scip, consdata) );
7619 
7620  assert(*consdata == NULL);
7621 
7622  return SCIP_OKAY;
7623 }
7624 
7625 /** transforms constraint data into data belonging to the transformed problem */
7626 static
7627 SCIP_DECL_CONSTRANS(consTransNonlinear)
7629  SCIP_CONSDATA* sourcedata;
7630  SCIP_CONSDATA* targetdata;
7631  int i;
7632 
7633  sourcedata = SCIPconsGetData(sourcecons);
7634  assert(sourcedata != NULL);
7635 
7636  SCIP_CALL( consdataCreate(scip, &targetdata,
7637  sourcedata->lhs, sourcedata->rhs,
7638  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
7639  sourcedata->nexprtrees, sourcedata->exprtrees, sourcedata->nonlincoefs,
7640  FALSE) );
7641 
7642  /* copy information on curvature, if known in original constraint */
7643  if( sourcedata->iscurvchecked && sourcedata->nexprtrees > 0 )
7644  {
7645  BMScopyMemoryArray(targetdata->curvatures, sourcedata->curvatures, sourcedata->nexprtrees);
7646  targetdata->curvature = sourcedata->curvature;
7647  targetdata->iscurvchecked = TRUE;
7648  }
7649 
7650  for( i = 0; i < targetdata->nlinvars; ++i )
7651  {
7652  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
7653  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
7654  }
7655 
7656  for( i = 0; i < targetdata->nexprtrees; ++i )
7657  {
7658  SCIP_CALL( SCIPgetExprtreeTransformedVars(scip, targetdata->exprtrees[i]) );
7659  }
7660 
7661  /* create target constraint */
7662  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
7663  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
7664  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
7665  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
7666  SCIPconsIsStickingAtNode(sourcecons)) );
7667 
7668  SCIPdebugMsg(scip, "created transformed nonlinear constraint ");
7669  SCIPdebugPrintCons(scip, *targetcons, NULL);
7670 
7671  return SCIP_OKAY;
7672 }
7673 
7674 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
7675 static
7676 SCIP_DECL_CONSINITLP(consInitlpNonlinear)
7679  SCIP_CONSDATA* consdata;
7680  SCIP_ROW* row;
7681  int c;
7682  SCIP_Real** x;
7683  int nvars;
7684  int i;
7685  int j;
7686  SCIP_VAR* var;
7687  SCIP_Bool haveunboundedvar;
7688 
7689  assert(scip != NULL);
7690  assert(conshdlr != NULL);
7691  assert(conss != NULL || nconss == 0);
7692 
7693  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7694  assert(conshdlrdata != NULL);
7695 
7696  *infeasible = FALSE;
7697 
7698  for( c = 0; c < nconss && !(*infeasible); ++c )
7699  {
7700  assert(conss[c] != NULL); /*lint !e613*/
7701 
7702  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) ); /*lint !e613*/
7703 
7704  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
7705  assert(consdata != NULL);
7706 
7707  row = NULL;
7708 
7709  if( consdata->nexprtrees == 0 )
7710  {
7711  assert(consdata->exprgraphnode == NULL);
7712  /* if we are actually linear, add the constraint as row to the LP */
7713  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
7714  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613*/
7715  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
7716  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, infeasible) );
7717  SCIP_CALL( SCIPreleaseRow (scip, &row) );
7718  continue;
7719  }
7720 
7721  /* setup reference points for each exprtree */
7722  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nexprtrees) );
7723  haveunboundedvar = FALSE;
7724  for( j = 0; j < consdata->nexprtrees; ++j )
7725  {
7726  nvars = SCIPexprtreeGetNVars(consdata->exprtrees[j]);
7727 
7728  SCIP_CALL( SCIPallocBufferArray(scip, &x[j], nvars) ); /*lint !e866*/
7729  for( i = 0; i < nvars; ++i )
7730  {
7731  var = SCIPexprtreeGetVars(consdata->exprtrees[j])[i];
7732  assert(var != NULL);
7733  /* use midpoint as reference value, if both bounds are finite
7734  * otherwise use 0.0, projected on bounds
7735  */
7736  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
7737  {
7738  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
7739  {
7740  x[j][i] = 0.0;
7741  haveunboundedvar = TRUE;
7742  }
7743  else
7744  x[j][i] = MIN(0.0, SCIPvarGetUbGlobal(var)); /*lint !e666*/
7745  }
7746  else
7747  {
7748  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
7749  x[j][i] = MAX(0.0, SCIPvarGetLbGlobal(var)); /*lint !e666*/
7750  else
7751  {
7752  x[j][i] = (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
7753  /* shift refpoint into [-INITLPMAXVARVAL, INITLPMAXVARVAL], if bounds allow */
7754  if( x[j][i] < -INITLPMAXVARVAL && SCIPvarGetUbGlobal(var) >= -INITLPMAXVARVAL )
7755  x[j][i] = -INITLPMAXVARVAL;
7756  else if( x[j][i] > INITLPMAXVARVAL && SCIPvarGetLbGlobal(var) <= INITLPMAXVARVAL )
7757  x[j][i] = INITLPMAXVARVAL;
7758  }
7759  }
7760  }
7761  }
7762 
7763  /* for inequalities that are convex or that have bounded variables, try to generate a cut */
7764  if( !SCIPisInfinity(scip, consdata->rhs) && ((consdata->curvature & SCIP_EXPRCURV_CONVEX) || !haveunboundedvar) )
7765  {
7766  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], x, NULL, TRUE, SCIP_SIDETYPE_RIGHT, &row,
7767  -SCIPinfinity(scip), conshdlrdata->cutmaxrange, FALSE, FALSE) ); /*lint !e613*/
7768 
7769  if( row != NULL )
7770  {
7771  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE /* forcecut */, infeasible) );
7772  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
7773  SCIP_CALL( SCIPreleaseRow(scip, &row) );
7774  }
7775  }
7776 
7777  if( !(*infeasible) && !SCIPisInfinity(scip, -consdata->lhs) &&
7778  ((consdata->curvature & SCIP_EXPRCURV_CONCAVE) || !haveunboundedvar) )
7779  {
7780  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], x, NULL, TRUE, SCIP_SIDETYPE_LEFT, &row,
7781  -SCIPinfinity(scip), conshdlrdata->cutmaxrange, FALSE, FALSE) ); /*lint !e613*/
7782 
7783  if( row != NULL )
7784  {
7785  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE /* forcecut */, infeasible) );
7786  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
7787  SCIP_CALL( SCIPreleaseRow(scip, &row) );
7788  }
7789  }
7790 
7791  /* @todo could add more linearizations for convex or multivariate concave inequ. */
7792 
7793  for( j = 0; j < consdata->nexprtrees; ++j )
7794  {
7795  SCIPfreeBufferArray(scip, &x[j]);
7796  }
7797  SCIPfreeBufferArray(scip, &x);
7798  }
7799 
7800  return SCIP_OKAY;
7801 }
7802 
7803 /** separation method of constraint handler for LP solutions */
7804 static
7805 SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
7808  SCIP_CONS* maxviolcon;
7809  SCIP_Bool solviolbounds;
7810 
7811  assert(scip != NULL);
7812  assert(conshdlr != NULL);
7813  assert(conss != NULL || nconss == 0);
7814  assert(result != NULL);
7815 
7816  *result = SCIP_DIDNOTFIND;
7817 
7818  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7819  assert(conshdlrdata != NULL);
7820 
7821  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
7822 
7823  /* it can happen here that the solution violates some bound - we then just don't separate, see also discussion in issue #627 */
7824  if( solviolbounds )
7825  return SCIP_OKAY;
7826 
7827  /* nothing violated -> nothing to separate */
7828  if( maxviolcon == NULL )
7829  return SCIP_OKAY;
7830 
7831  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
7832  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
7833  */
7834  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
7835  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) || (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
7836  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
7837  {
7838  SCIP_CONSDATA* consdata;
7839  SCIP_NLPSOLSTAT solstat;
7840  SCIP_Bool solvednlp; /* whether we invoked an NLP solve here */
7841  int c;
7842 
7843  solstat = SCIPgetNLPSolstat(scip);
7844  solvednlp = FALSE;
7845  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
7846  {
7847  /* NLP is not solved yet, so we might want to do this
7848  * but first check whether there is a violated constraint side which corresponds to a convex function
7849  * @todo put this check into initsol and update via consenable/consdisable
7850  */
7851  for( c = 0; c < nconss; ++c )
7852  {
7853  assert(conss[c] != NULL); /*lint !e613*/
7854 
7855  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
7856  assert(consdata != NULL);
7857 
7858  /* skip feasible constraints */
7859  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7860  continue;
7861 
7862  /* make sure curvature has been checked */
7863  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) ); /*lint !e613*/
7864 
7865  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && (consdata->curvature & SCIP_EXPRCURV_CONVEX )) ||
7866  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && (consdata->curvature & SCIP_EXPRCURV_CONCAVE)) )
7867  break;
7868  }
7869 
7870  if( c < nconss )
7871  {
7872  /* try to solve NLP and update solstat */
7873 
7874  /* ensure linear conss are in NLP */
7875  if( conshdlrdata->subnlpheur != NULL )
7876  {
7877  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
7878  }
7879 
7880  /* set LP solution as starting values, if available */
7882  {
7884  }
7885 
7886  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
7887  SCIP_CALL( SCIPsolveNLP(scip) );
7888 
7889  solstat = SCIPgetNLPSolstat(scip);
7890  SCIPdebugMsg(scip, "solved NLP relax, solution status: %d\n", solstat);
7891 
7892  solvednlp = TRUE;
7893  }
7894  }
7895 
7896  conshdlrdata->sepanlp = TRUE;
7897 
7898  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
7899  {
7900  SCIPdebugMsg(scip, "NLP relaxation is globally infeasible, thus can cutoff node\n");
7901  *result = SCIP_CUTOFF;
7902  return SCIP_OKAY;
7903  }
7904 
7905  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
7906  {
7907  /* if we have feasible NLP solution, generate linearization cuts there */
7908  SCIP_Bool lpsolseparated;
7909  SCIP_SOL* nlpsol;
7910 
7911  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
7912  assert(nlpsol != NULL);
7913 
7914  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
7915  if( solvednlp && conshdlrdata->trysolheur != NULL )
7916  {
7917  int nfracvars;
7918 
7919  nfracvars = 0;
7920  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
7921  {
7922  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
7923  }
7924 
7925  if( nfracvars == 0 )
7926  {
7927  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
7928  }
7929  }
7930 
7931  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, conshdlrdata->mincutefficacysepa) );
7932 
7933  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
7934 
7935  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
7936  if( lpsolseparated )
7937  {
7938  SCIPdebugMsg(scip, "linearization cuts separate LP solution\n");
7939 
7940  *result = SCIP_SEPARATED;
7941 
7942  return SCIP_OKAY;
7943  }
7944  }
7945  }
7946  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
7947  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
7948  */
7949 
7950  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, TRUE, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
7951 
7952  return SCIP_OKAY;
7953 }
7954 
7955 /** separation method of constraint handler for arbitrary primal solutions */
7956 static
7957 SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
7960  SCIP_CONS* maxviolcon;
7961  SCIP_Bool solviolbounds;
7962 
7963  assert(scip != NULL);
7964  assert(conshdlr != NULL);
7965  assert(conss != NULL || nconss == 0);
7966  assert(sol != NULL);
7967  assert(result != NULL);
7968 
7969  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7970  assert(conshdlrdata != NULL);
7971 
7972  *result = SCIP_DIDNOTFIND;
7973 
7974  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &solviolbounds, &maxviolcon) );
7975 
7976  /* odd, if this happens for non-LP solutions, but luckily we can just give up here */
7977  if( solviolbounds )
7978  return SCIP_OKAY;
7979 
7980  /* nothing violated -> nothing to separate */
7981  if( maxviolcon == NULL )
7982  return SCIP_OKAY;
7983 
7984  /* computeViolations already evaluated all constraints, so can pass newsol = FALSE here
7985  * in contrast to Sepalp, a sol != NULL is not projected onto the box in computeViolation
7986  */
7987  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, FALSE, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
7988 
7989  return SCIP_OKAY;
7990 }
7991 
7992 /** constraint enforcing method of constraint handler for LP solutions */
7993 static
7994 SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
7995 { /*lint --e{715}*/
7996  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
7997 
7998  return SCIP_OKAY;
7999 }
8000 
8001 /** constraint enforcing method of constraint handler for relaxation solutions */
8002 static
8003 SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
8004 { /*lint --e{715}*/
8005  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
8006 
8007  return SCIP_OKAY;
8008 }
8009 
8010 /** constraint enforcing method of constraint handler for pseudo solutions */
8011 static
8012 SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
8014  SCIP_CONS* maxviolcons;
8015  SCIP_CONSDATA* consdata;
8016  SCIP_RESULT propresult;
8017  SCIP_VAR* var;
8018  int dummy;
8019  int nnotify;
8020  int c;
8021  int i;
8022  int j;
8023  SCIP_Bool solviolbounds;
8024 
8025  assert(scip != NULL);
8026  assert(conss != NULL || nconss == 0);
8027 
8028  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &solviolbounds, &maxviolcons) );
8029 
8030  /* we enforce a pseudo-solution, which should be within (read: at) bounds by definition */
8031  assert(!solviolbounds);
8032 
8033  if( maxviolcons == NULL )
8034  {
8035  *result = SCIP_FEASIBLE;
8036  return SCIP_OKAY;
8037  }
8038 
8039  *result = SCIP_INFEASIBLE;
8040 
8041  SCIPdebugMsg(scip, "enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcons));
8042 
8043  /* we propagate constraints only if they are active and enforcing by branching only does not seem much effective */
8044  assert(SCIPconsIsActive(maxviolcons));
8045 
8046  /* run domain propagation */
8047  dummy = 0;
8048  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, TRUE, &propresult, &dummy, &dummy) );
8049  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
8050  {
8051  *result = propresult;
8052  return SCIP_OKAY;
8053  }
8054 
8055  /* We are not feasible and we cannot prove that the whole node is infeasible -> collect all variables in violated
8056  * constraints for branching. */
8057  nnotify = 0;
8058  for( c = 0; c < nconss; ++c )
8059  {
8060  assert(conss != NULL);
8061  consdata = SCIPconsGetData(conss[c]);
8062  assert(consdata != NULL);
8063 
8064  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
8065  continue;
8066 
8067  for( i = 0; i < consdata->nlinvars; ++i )
8068  {
8069  var = consdata->linvars[i];
8070  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
8071  {
8072  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
8073  ++nnotify;
8074  }
8075  }
8076 
8077  for( j = 0; j < consdata->nexprtrees; ++j )
8078  {
8079  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]); ++i )
8080  {
8081  var = SCIPexprtreeGetVars(consdata->exprtrees[j])[i];
8082  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
8083  {
8084  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
8085  ++nnotify;
8086  }
8087  }
8088  }
8089  }
8090 
8091  if( nnotify == 0 )
8092  {
8093  SCIPdebugMsg(scip, "All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
8094  *result = SCIP_SOLVELP;
8095  }
8096 
8097  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
8098  return SCIP_OKAY;
8099 } /*lint !e715*/
8100 
8101 
8102 /** feasibility check method of constraint handler for integral solutions */
8103 static
8104 SCIP_DECL_CONSCHECK(consCheckNonlinear)
8107  SCIP_CONSDATA* consdata;
8108  SCIP_Real maxviol;
8109  int c;
8110  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
8111  SCIP_Bool solviolbounds;
8112 
8113  assert(scip != NULL);
8114  assert(conss != NULL || nconss == 0);
8115  assert(result != NULL);
8116 
8117  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8118  assert(conshdlrdata != NULL);
8119 
8120  *result = SCIP_FEASIBLE;
8121 
8122  /* during presolve, we do not have exprtrees in the constraints, but we can get values from the expression graph, if we have evaluated it */
8124  {
8125  SCIP_Real* varvals;
8126 
8127  assert(conshdlrdata->exprgraph != NULL);
8128 
8129  SCIP_CALL( SCIPallocBufferArray(scip, &varvals, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
8130  SCIP_CALL( SCIPgetSolVals(scip, sol, SCIPexprgraphGetNVars(conshdlrdata->exprgraph), (SCIP_VAR**)SCIPexprgraphGetVars(conshdlrdata->exprgraph), varvals) );
8131 
8132  SCIP_CALL( SCIPexprgraphEval(conshdlrdata->exprgraph, varvals) );
8133 
8134  SCIPfreeBufferArray(scip, &varvals);
8135  }
8136 
8137  /* @todo adapt proposeFeasibleSolution to function also during presolving */
8138  maxviol = 0.0;
8139  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
8143 
8144  for( c = 0; c < nconss; ++c )
8145  {
8146  assert(conss != NULL);
8147  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol, &solviolbounds) );
8148  assert(!solviolbounds); /* see also issue #627 */
8149 
8150  consdata = SCIPconsGetData(conss[c]);
8151  assert(consdata != NULL);
8152 
8153  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
8154  {
8155  *result = SCIP_INFEASIBLE;
8156  if( printreason )
8157  {
8158  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
8159  SCIPinfoMessage(scip, NULL, ";\n");
8160  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
8161  {
8162  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g (scaled: %.15g)\n", consdata->lhs - consdata->activity, consdata->lhsviol);
8163  }
8164  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
8165  {
8166  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g (scaled: %.15g)\n", consdata->activity - consdata->rhs, consdata->rhsviol);
8167  }
8168  }
8169 
8170  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
8171  return SCIP_OKAY;
8172 
8173  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
8174  maxviol = MAX(consdata->lhsviol, consdata->rhsviol);
8175 
8176  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
8177  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
8178  maypropfeasible = FALSE;
8179 
8180  if( maypropfeasible )
8181  {
8182  /* update information on linear variables that may be in- or decreased */
8183  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
8184  consdataFindUnlockedLinearVar(scip, consdata);
8185 
8186  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
8187  {
8188  /* check if there is a variable which may help to get the left hand side satisfied
8189  * if there is no such var, then we cannot get feasible */
8190  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
8191  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
8192  maypropfeasible = FALSE;
8193  }
8194  else
8195  {
8196  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
8197  /* check if there is a variable which may help to get the right hand side satisfied
8198  * if there is no such var, then we cannot get feasible */
8199  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
8200  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
8201  maypropfeasible = FALSE;
8202  }
8203  }
8204  }
8205  else
8206  {
8207  /* SCIPdebugMsg(scip, "constraint <%s> is feasible (%g, %g) in check, activity = %g, sides = [%g, %g]\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->activity, consdata->lhs, consdata->rhs); */
8208  }
8209  }
8210 
8211  if( *result == SCIP_INFEASIBLE && maypropfeasible )
8212  {
8213  SCIP_Bool success;
8214 
8215  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
8216 
8217  /* do not pass solution to NLP heuristic if we made it feasible this way */
8218  if( success )
8219  return SCIP_OKAY;
8220  }
8221 
8222  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
8223  {
8224  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
8225  }
8226 
8227  return SCIP_OKAY;
8228 } /*lint !e715*/
8229 
8230 
8231 /** domain propagation method of constraint handler */
8232 static
8233 SCIP_DECL_CONSPROP(consPropNonlinear)
8235  int dummy;
8236 
8237  assert(scip != NULL);
8238  assert(conshdlr != NULL);
8239  assert(conss != NULL || nconss == 0);
8240  assert(result != NULL);
8241 
8242  dummy = 0;
8243  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nmarkedconss, TRUE, result, &dummy, &dummy) );
8244 
8245  return SCIP_OKAY;
8246 } /*lint !e715*/
8247 
8248 /** presolving method of constraint handler */
8249 static
8250 SCIP_DECL_CONSPRESOL(consPresolNonlinear)
8253  SCIP_CONSDATA* consdata;
8254  SCIP_RESULT propresult;
8255  SCIP_Bool havechange;
8256  SCIP_Bool domainerror;
8257  SCIP_Bool havegraphchange;
8258  SCIP_Bool tryupgrades;
8259  int c;
8260 
8261  assert(scip != NULL);
8262  assert(conshdlr != NULL);
8263  assert(conss != NULL || nconss == 0);
8264  assert(result != NULL);
8265 
8266  *result = SCIP_DIDNOTFIND;
8267 
8268  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8269  assert(conshdlrdata != NULL);
8270  assert(conshdlrdata->exprgraph != NULL);
8271 
8272  havegraphchange = FALSE;
8273 
8274  if( !conshdlrdata->isremovedfixings )
8275  {
8276  SCIP_CALL( removeFixedNonlinearVariables(scip, conshdlr) );
8277  assert(conshdlrdata->isremovedfixings);
8278 
8279  havegraphchange = TRUE;
8280  }
8281 
8282  SCIP_CALL( SCIPexprgraphSimplify(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), SCIPepsilon(scip), conshdlrdata->maxexpansionexponent, &havechange, &domainerror) );
8283  SCIPdebugMsg(scip, "expression graph simplifier found %schange, domain error = %u\n", havechange ? "" : "no ", domainerror);
8284 
8285  /* if simplifier found some undefined expression, then declare problem as infeasible
8286  * usually, this should be discovered during domain propagation already, but since that is using interval arithmetics,
8287  * it may overestimate in a way that actually undefined expressions still get a value assigned (e.g., 0^(-1) = [-inf,inf])
8288  */
8289  if( domainerror )
8290  *result = SCIP_CUTOFF;
8291 
8292  havegraphchange |= havechange;
8293 
8294  /* if graph has changed, then we will try upgrades, otherwise we only do for changing or not-yet-presolved constraints */
8295  tryupgrades = havegraphchange;
8296 
8297  /* remove fix vars, do some algebraic manipulation, etc; this loop need to finish, even if a cutoff is found because data
8298  * might be unconsistent otherwise (i.e. some asserts might pop later, e.g. exitpresol, etc)
8299  */
8300  for( c = 0; c < nconss; ++c )
8301  {
8302  assert(conss != NULL);
8303 
8304  consdata = SCIPconsGetData(conss[c]);
8305  assert(consdata != NULL);
8306 
8307  SCIPdebugMsg(scip, "process constraint <%s>\n", SCIPconsGetName(conss[c]));
8308  SCIPdebugPrintCons(scip, conss[c], NULL);
8309 
8310  havechange = FALSE;
8311 
8312  if( !consdata->isremovedfixingslin )
8313  {
8314  SCIP_CALL( removeFixedLinearVariables(scip, conss[c]) );
8315  assert(consdata->isremovedfixingslin);
8316  havechange = TRUE;
8317  }
8318 
8319  /* the reductions below require the constraint nonlinear function to be in the expression graph, which is only the
8320  * case for active constraints
8321  */
8322  if( !SCIPconsIsActive(conss[c]) )
8323  continue;
8324 
8325  if( !consdata->ispresolved || havegraphchange )
8326  {
8327  SCIP_Bool infeasible;
8328 
8329  SCIP_CALL( splitOffLinearPart(scip, conshdlr, conss[c], &infeasible) );
8330 
8331  if( infeasible )
8332  {
8333  *result = SCIP_CUTOFF;
8334  continue;
8335  }
8336  }
8337 
8338  if( consdata->nlinvars == 0 && consdata->exprgraphnode == NULL )
8339  {
8340  /* all variables fixed or removed, constraint function is 0.0 now */
8341  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
8342  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
8343  {
8344  /* left hand side positive or right hand side negative */
8345  SCIPdebugMsg(scip, "constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
8346  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
8347  *result = SCIP_CUTOFF;
8348  }
8349  else
8350  {
8351  /* left and right hand side are consistent */
8352  SCIPdebugMsg(scip, "constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
8353  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
8354  ++*ndelconss;
8355 
8356  if( *result != SCIP_CUTOFF )
8357  *result = SCIP_SUCCESS;
8358  continue;
8359  }
8360  }
8361 
8362  /* remember that we want to call upgrade methods for the current constraint */
8363  if( havechange )
8364  consdata->ispresolved = FALSE;
8365 
8366  /* if a constraint is not finished presolving yet, then we will try upgrade methods */
8367  if( !consdata->ispresolved )
8368  tryupgrades = TRUE;
8369  }
8370 
8371  /* if a cutoff was found, return; data is consistent at this point */
8372  if( *result == SCIP_CUTOFF )
8373  return SCIP_OKAY;
8374 
8375  if( tryupgrades )
8376  {
8377  /* upgrade methods may look at expression graph bounds, which are not present in the first presolving round yet and may be invalid in later rounds (e.g., due to probing) */
8378  SCIP_CALL( SCIPexprgraphPropagateVarBounds(conshdlrdata->exprgraph, INTERVALINFTY, TRUE, &domainerror) );
8379 
8380  if( domainerror )
8381  {
8382  SCIPdebugMsg(scip, "propagating variable bounds through expression graph found that some expressions cannot be evaluated w.r.t. current bounds, thus cutoff\n");
8383  *result = SCIP_CUTOFF;
8384  return SCIP_OKAY;
8385  }
8386 
8387  for( c = 0; c < nconss; ++c )
8388  {
8389  consdata = SCIPconsGetData(conss[c]); /*lint !e794*/
8390  assert(consdata != NULL);
8391 
8392  /* call upgrade methods if constraint was not presolved, has been changed, or the expression graph has changed */
8393  if( !consdata->ispresolved || havegraphchange )
8394  {
8395  SCIP_Bool upgraded;
8396 
8397  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) ); /*lint !e794*/
8398  if( upgraded )
8399  {
8400  *result = SCIP_SUCCESS;
8401  continue;
8402  }
8403  }
8404 
8405  consdata->ispresolved = TRUE;
8406  }
8407  }
8408 
8409  /* run domain propagation (if updated bounds in graph above, then can skip cleanup) */
8410  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
8411  {
8412  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, !tryupgrades, &propresult, nchgbds, ndelconss) );
8413  switch( propresult )
8414  {
8415  case SCIP_REDUCEDDOM:
8416  *result = SCIP_SUCCESS;
8417  break;
8418  case SCIP_CUTOFF:
8419  SCIPdebugMsg(scip, "propagation says problem is infeasible in presolve\n");
8420  *result = SCIP_CUTOFF;
8421  return SCIP_OKAY;
8422  default:
8423  assert(propresult == SCIP_DIDNOTFIND || propresult == SCIP_DIDNOTRUN);
8424  } /*lint !e788*/
8425  }
8426 
8427  if( conshdlrdata->reformulate && !conshdlrdata->assumeconvex )
8428  {
8429  /* if other presolvers did not find enough changes for another presolving round,
8430  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
8431  * otherwise, we wait with these
8432  */
8433  if( SCIPisPresolveFinished(scip) || (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
8434  {
8435  int naddconssbefore;
8436 
8437  SCIPdebugMsg(scip, "reformulating expression graph\n");
8438 
8439  naddconssbefore = conshdlrdata->naddedreformconss;
8440  SCIP_CALL( reformulate(scip, conshdlr, conss, nconss, &conshdlrdata->naddedreformconss) );
8441 
8442  if( conshdlrdata->naddedreformconss > naddconssbefore )
8443  {
8444  *result = SCIP_SUCCESS;
8445  *naddconss += conshdlrdata->naddedreformconss - naddconssbefore;
8446 
8447  /* if expression graph changed, ensure that we apply all presolving techniques (esp. upgrades) in next round again */
8448  for( c = 0; c < nconss; ++c )
8449  {
8450  assert(conss[c] != NULL); /*lint !e794*/
8451 
8452  consdata = SCIPconsGetData(conss[c]); /*lint !e794*/
8453  assert(consdata != NULL);
8454 
8455  consdata->ispresolved = FALSE;
8456  }
8457  }
8458  }
8459  }
8460 
8461  return SCIP_OKAY;
8462 } /*lint !e715*/
8463 
8464 
8465 /** variable rounding lock method of constraint handler */
8466 static
8467 SCIP_DECL_CONSLOCK(consLockNonlinear)
8469  SCIP_CONSDATA* consdata;
8470  SCIP_Bool havelhs;
8471  SCIP_Bool haverhs;
8472  int i;
8473 
8474  assert(scip != NULL);
8475  assert(cons != NULL);
8476 
8477  /* variable locking for nonlinear part is done w.r.t. variables in the expression graph
8478  * since only active constraints have their nonlinear part in the expression graph, we can lock only active constraints
8479  */
8480  assert(SCIPconsIsActive(cons) || SCIPconsIsDeleted(cons));
8481 
8482  consdata = SCIPconsGetData(cons);
8483  assert(consdata != NULL);
8484 
8485  havelhs = !SCIPisInfinity(scip, -consdata->lhs);
8486  haverhs = !SCIPisInfinity(scip, consdata->rhs);
8487 
8488  for( i = 0; i < consdata->nlinvars; ++i )
8489  {
8490  if( consdata->lincoefs[i] > 0 )
8491  {
8492  if( havelhs )
8493  {
8494  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
8495  }
8496  if( haverhs )
8497  {
8498  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
8499  }
8500  }
8501  else
8502  {
8503  if( havelhs )
8504  {
8505  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
8506  }
8507  if( haverhs )
8508  {
8509  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
8510  }
8511  }
8512  }
8513 
8514  return SCIP_OKAY;
8515 } /*lint !e715*/
8516 
8517 /** constraint activation notification method of constraint handler */
8518 static
8519 SCIP_DECL_CONSACTIVE(consActiveNonlinear)
8520 { /*lint --e{715}*/
8522  SCIP_CONSDATA* consdata;
8523 
8524  assert(scip != NULL);
8525  assert(conshdlr != NULL);
8526  assert(cons != NULL);
8527  assert(SCIPconsIsTransformed(cons));
8528 
8529  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8530  assert(conshdlrdata != NULL);
8531  assert(conshdlrdata->exprgraph != NULL);
8532 
8533  consdata = SCIPconsGetData(cons);
8534  assert(consdata != NULL);
8535 
8536  SCIPdebugMsg(scip, "activate cons <%s>\n", SCIPconsGetName(cons));
8537 
8538  if( consdata->nexprtrees > 0 )
8539  {
8540  SCIP_Bool exprtreeisnew;
8541 
8542  assert(consdata->exprgraphnode == NULL);
8543 
8544  /* add exprtrees to expression graph */
8545  SCIP_CALL( SCIPexprgraphAddExprtreeSum(conshdlrdata->exprgraph, consdata->nexprtrees, consdata->exprtrees, consdata->nonlincoefs, &consdata->exprgraphnode, &exprtreeisnew) );
8546  assert(consdata->exprgraphnode != NULL);
8547  /* @todo do something with exprtreeisnew? */
8548 
8549  /* if during presolving, then forget expression trees */
8551  {
8552  SCIP_CALL( consdataSetExprtrees(scip, consdata, 0, NULL, NULL, FALSE) );
8553  }
8554 
8555  /* remember that we should run reformulation again */
8556  conshdlrdata->isreformulated = FALSE;
8557 
8558  /* remember that we should force backward propagation on our subgraph propagating the next time,
8559  * so possible domain restrictions are propagated into variable bounds
8560  */
8561  consdata->forcebackprop = TRUE;
8562  }
8563  else if( consdata->exprgraphnode != NULL )
8564  {
8565  /* if constraint already comes with node in expression graph, then also remember that we should run reformulation again */
8566  conshdlrdata->isreformulated = FALSE;
8567 
8568  /* remember that we should force backward propagation on our subgraph propagating the next time,
8569  * so possible domain restrictions are propagated into variable bounds
8570  */
8571  consdata->forcebackprop = TRUE;
8572  }
8573 
8574  return SCIP_OKAY;
8575 }
8576 
8577 /** constraint deactivation notification method of constraint handler */
8578 static
8579 SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
8580 { /*lint --e{715}*/
8582  SCIP_CONSDATA* consdata;
8583 
8584  assert(scip != NULL);
8585  assert(conshdlr != NULL);
8586  assert(cons != NULL);
8587  assert(SCIPconsIsTransformed(cons));
8588 
8589  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8590  assert(conshdlrdata != NULL);
8591  assert(conshdlrdata->exprgraph != NULL);
8592 
8593  consdata = SCIPconsGetData(cons);
8594  assert(consdata != NULL);
8595  assert(consdata->exprgraphnode != NULL || consdata->nexprtrees == 0);
8596 
8597  SCIPdebugMsg(scip, "deactivate cons <%s>\n", SCIPconsGetName(cons));
8598 
8599  if( consdata->exprgraphnode != NULL )
8600  {
8601  if( consdata->nexprtrees == 0 )
8602  {
8603  /* during presolving, the exprtrees in the constraint are removed, so put them back before releasing the exprgraphnode */
8604  SCIP_EXPRTREE* exprtree;
8605 
8606  /* if only presolve is run and problem is found infeasible there, then constraints may not be deactivated there, but in a later call to freeTransform */
8607  /* @todo if infeasible in presolve, will constraints be deactivated still in presolving stage, or in exitpre? */
8609 
8610  SCIP_CALL( SCIPexprgraphGetTree(conshdlrdata->exprgraph, consdata->exprgraphnode, &exprtree) );
8611  SCIP_CALL( consdataSetExprtrees(scip, consdata, 1, &exprtree, NULL, FALSE) );
8612  }
8613 
8614  SCIP_CALL( SCIPexprgraphReleaseNode(conshdlrdata->exprgraph, &consdata->exprgraphnode) );
8615  }
8616 
8617  return SCIP_OKAY;
8618 }
8619 
8620 /** constraint enabling notification method of constraint handler */
8621 static
8622 SCIP_DECL_CONSENABLE(consEnableNonlinear)
8623 { /*lint --e{715}*/
8625  SCIP_CONSDATA* consdata;
8626  int i;
8627 
8628  assert(scip != NULL);
8629  assert(conshdlr != NULL);
8630  assert(cons != NULL);
8631  assert(SCIPconsIsTransformed(cons));
8632  assert(SCIPconsIsActive(cons));
8633 
8634  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8635  assert(conshdlrdata != NULL);
8636  assert(conshdlrdata->exprgraph != NULL);
8637 
8638  consdata = SCIPconsGetData(cons);
8639  assert(consdata != NULL);
8640 
8641  SCIPdebugMsg(scip, "enable cons <%s>\n", SCIPconsGetName(cons));
8642 
8643  if( consdata->exprgraphnode != NULL )
8644  {
8645  /* enable node of expression in expression graph */
8646  SCIPexprgraphEnableNode(conshdlrdata->exprgraph, consdata->exprgraphnode);
8647  }
8648 
8649  /* enable event catching for linear variables */
8650  consdata->isremovedfixingslin = TRUE;
8651  for( i = 0; i < consdata->nlinvars; ++i )
8652  {
8653  SCIP_CALL( catchLinearVarEvents(scip, cons, i) );
8654 
8655  consdata->isremovedfixingslin = consdata->isremovedfixingslin && SCIPvarIsActive(consdata->linvars[i]);
8656  }
8657 
8658  return SCIP_OKAY;
8659 }
8660 
8661 /** constraint disabling notification method of constraint handler */
8662 static
8663 SCIP_DECL_CONSDISABLE(consDisableNonlinear)
8664 { /*lint --e{715}*/
8666  SCIP_CONSDATA* consdata;
8667  int i;
8668 
8669  assert(scip != NULL);
8670  assert(conshdlr != NULL);
8671  assert(cons != NULL);
8672  assert(SCIPconsIsTransformed(cons));
8673 
8674  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8675  assert(conshdlrdata != NULL);
8676  assert(conshdlrdata->exprgraph != NULL);
8677 
8678  consdata = SCIPconsGetData(cons);
8679  assert(consdata != NULL);
8680  assert(consdata->lineventdata != NULL || consdata->nlinvars == 0);
8681 
8682  SCIPdebugMsg(scip, "disable cons <%s>\n", SCIPconsGetName(cons));
8683 
8684  /* disable node of expression in expression graph */
8685  if( consdata->exprgraphnode != NULL )
8686  {
8687  SCIPexprgraphDisableNode(conshdlrdata->exprgraph, consdata->exprgraphnode);
8688  }
8689 
8690  for( i = 0; i < consdata->nlinvars; ++i )
8691  {
8692  SCIP_CALL( dropLinearVarEvents(scip, cons, i) );
8693  }
8694 
8695  return SCIP_OKAY;
8696 }
8697 
8698 
8699 /** constraint display method of constraint handler */
8700 static
8701 SCIP_DECL_CONSPRINT(consPrintNonlinear)
8703  SCIP_CONSDATA* consdata;
8704  int j;
8705 
8706  assert(scip != NULL);
8707  assert(cons != NULL);
8708 
8709  consdata = SCIPconsGetData(cons);
8710  assert(consdata != NULL);
8711 
8712  /* print left hand side for ranged rows */
8713  if( !SCIPisInfinity(scip, -consdata->lhs)
8714  && !SCIPisInfinity(scip, consdata->rhs)
8715  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
8716  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
8717 
8718  /* print coefficients and variables */
8719  if( consdata->nlinvars == 0 && consdata->nexprtrees == 0 && consdata->exprgraphnode == 0 )
8720  {
8721  SCIPinfoMessage(scip, file, "0 ");
8722  }
8723  else
8724  {
8725  if( consdata->nexprtrees > 0 )
8726  {
8727  for( j = 0; j < consdata->nexprtrees; ++j )
8728  {
8729  if( j > 0 || consdata->nonlincoefs[j] != 1.0 )
8730  SCIPinfoMessage(scip, file, " %+.20g ", consdata->nonlincoefs[j]);
8731  SCIP_CALL( SCIPexprtreePrintWithNames(consdata->exprtrees[j], SCIPgetMessagehdlr(scip), file) );
8732  }
8733  }
8734  else if( consdata->exprgraphnode != NULL )
8735  {
8737  SCIP_EXPRTREE* tree;
8738 
8739  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8740  assert(conshdlrdata != NULL);
8741  SCIP_CALL( SCIPexprgraphGetTree(conshdlrdata->exprgraph, consdata->exprgraphnode, &tree) );
8742 
8744 
8745  SCIP_CALL( SCIPexprtreeFree(&tree) );
8746  }
8747 
8748  for( j = 0; j < consdata->nlinvars; ++j )
8749  {
8750  SCIPinfoMessage(scip, file, "%+.15g<%s>[%c] ", consdata->lincoefs[j], SCIPvarGetName(consdata->linvars[j]),
8751  SCIPvarGetType(consdata->linvars[j]) == SCIP_VARTYPE_BINARY ? 'B' :
8752  SCIPvarGetType(consdata->linvars[j]) == SCIP_VARTYPE_INTEGER ? 'I' :
8753  SCIPvarGetType(consdata->linvars[j]) == SCIP_VARTYPE_IMPLINT ? 'I' : 'C');
8754  }
8755  }
8756 
8757  /* print right hand side */
8758  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
8759  {
8760  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
8761  }
8762  else if( !SCIPisInfinity(scip, consdata->rhs) )
8763  {
8764  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
8765  }
8766  else if( !SCIPisInfinity(scip, -consdata->lhs) )
8767  {
8768  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
8769  }
8770  else
8771  {
8772  SCIPinfoMessage(scip, file, " [free]");
8773  }
8774 
8775  return SCIP_OKAY;
8776 }
8777 
8778 /** constraint copying method of constraint handler */
8779 static
8780 SCIP_DECL_CONSCOPY(consCopyNonlinear)
8782  SCIP_CONSDATA* consdata;
8783  SCIP_CONSDATA* targetconsdata;
8784  SCIP_VAR** linvars;
8785  SCIP_Real* nonlincoefs;
8786  SCIP_EXPRTREE** exprtrees;
8787  int nexprtrees;
8788  int i;
8789  int j;
8790 
8791  assert(scip != NULL);
8792  assert(cons != NULL);
8793  assert(sourcescip != NULL);
8794  assert(sourceconshdlr != NULL);
8795  assert(sourcecons != NULL);
8796  assert(varmap != NULL);
8797  assert(valid != NULL);
8798 
8799  consdata = SCIPconsGetData(sourcecons);
8800  assert(consdata != NULL);
8801 
8802  linvars = NULL;
8803  exprtrees = NULL;
8804 
8805  *valid = TRUE;
8806 
8807  if( consdata->nlinvars != 0 )
8808  {
8809  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
8810  for( i = 0; i < consdata->nlinvars && *valid; ++i )
8811  {
8812  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
8813  assert(!*valid || linvars[i] != NULL);
8814  }
8815  }
8816 
8817  nexprtrees = 0;
8818  nonlincoefs = NULL;
8819 
8820  if( *valid && consdata->nexprtrees > 0 )
8821  {
8822  SCIP_VAR** nonlinvars;
8823 
8824  nonlincoefs = consdata->nonlincoefs;
8825  nexprtrees = consdata->nexprtrees;
8826 
8827  SCIP_CALL( SCIPallocBufferArray(sourcescip, &exprtrees, nexprtrees) );
8828  BMSclearMemoryArray(exprtrees, nexprtrees);
8829  SCIP_CALL( SCIPallocBufferArray(sourcescip, &nonlinvars, SCIPexprtreeGetNVars(consdata->exprtrees[0])) );
8830 
8831  for( j = 0; j < consdata->nexprtrees; ++j )
8832  {
8833  SCIP_CALL( SCIPreallocBufferArray(sourcescip, &nonlinvars, SCIPexprtreeGetNVars(consdata->exprtrees[j])) );
8834  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]) && *valid; ++i )
8835  {
8836  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, SCIPexprtreeGetVars(consdata->exprtrees[j])[i], &nonlinvars[i], varmap, consmap, global, valid) );
8837  assert(!*valid || nonlinvars[i] != NULL);
8838  }
8839 
8840  if( *valid )
8841  {
8842  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &exprtrees[j], consdata->exprtrees[j]) );
8843  SCIP_CALL( SCIPexprtreeSetVars(exprtrees[j], SCIPexprtreeGetNVars(consdata->exprtrees[j]), nonlinvars) );
8844  }
8845  else
8846  break;
8847  }
8848 
8849  SCIPfreeBufferArray(sourcescip, &nonlinvars);
8850  }
8851 
8852  if( *valid && consdata->nexprtrees == 0 && consdata->exprgraphnode != NULL )
8853  {
8855  SCIP_VAR** nonlinvars;
8856 
8857  conshdlrdata = SCIPconshdlrGetData(sourceconshdlr);
8858 
8859  nexprtrees = 1;
8860  SCIP_CALL( SCIPallocBufferArray(sourcescip, &exprtrees, 1) );
8861 
8862  SCIP_CALL( SCIPexprgraphGetTree(conshdlrdata->exprgraph, consdata->exprgraphnode, &exprtrees[0]) );
8863 
8864  nonlinvars = SCIPexprtreeGetVars(exprtrees[0]);
8865  for( i = 0; i < SCIPexprtreeGetNVars(exprtrees[0]); ++i )
8866  {
8867  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, nonlinvars[i], &nonlinvars[i], varmap, consmap, global, valid) );
8868  assert(!*valid || nonlinvars[i] != NULL);
8869  }
8870  }
8871 
8872  if( *valid )
8873  {
8874  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name ? name : SCIPconsGetName(sourcecons),
8875  consdata->nlinvars, linvars, consdata->lincoefs,
8876  nexprtrees, exprtrees, nonlincoefs,
8877  consdata->lhs, consdata->rhs,
8878  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
8879 
8880  /* copy information on curvature */
8881  targetconsdata = SCIPconsGetData(*cons);
8882  targetconsdata->curvature = consdata->curvature;
8883  targetconsdata->iscurvchecked = consdata->iscurvchecked && global; /* if the copy is local, then curvature may change (get stronger) */
8884  }
8885 
8886  SCIPfreeBufferArrayNull(sourcescip, &linvars);
8887  if( exprtrees != NULL )
8888  {
8889  for( j = 0; j < nexprtrees; ++j )
8890  {
8891  if( exprtrees[j] != NULL )
8892  {
8893  SCIP_CALL( SCIPexprtreeFree(&exprtrees[j]) );
8894  }
8895  }
8896  SCIPfreeBufferArray(sourcescip, &exprtrees);
8897  }
8898 
8899  return SCIP_OKAY;
8900 }
8901 
8902 /** constraint method of constraint handler which returns the variables (if possible) */
8903 static
8904 SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
8905 { /*lint --e{715}*/
8906  SCIP_CONSDATA* consdata;
8907  int cnt;
8908 
8909  assert(cons != NULL);
8910 
8911  consdata = SCIPconsGetData(cons);
8912  assert(consdata != NULL);
8913 
8914  *success = TRUE;
8915 
8916  if( varssize < consdata->nlinvars )
8917  {
8918  *success = FALSE;
8919  return SCIP_OKAY;
8920  }
8921 
8922  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
8923  cnt = consdata->nlinvars;
8924 
8925  if( consdata->exprgraphnode != NULL )
8926  {
8928  int* varsusage;
8929  int i;
8930 
8931  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8932  assert(conshdlrdata != NULL);
8933 
8934  SCIP_CALL( SCIPallocBufferArray(scip, &varsusage, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
8935 
8936  SCIPexprgraphGetSubtreeVarsUsage(conshdlrdata->exprgraph, consdata->exprgraphnode, varsusage);
8937 
8938  for( i = 0; i < SCIPexprgraphGetNVars(conshdlrdata->exprgraph); ++i )
8939  {
8940  if( varsusage[i] == 0 )
8941  continue;
8942 
8943  if( cnt >= varssize )
8944  {
8945  *success = FALSE;
8946  break;
8947  }
8948 
8949  vars[cnt] = (SCIP_VAR*)(SCIPexprgraphGetVars(conshdlrdata->exprgraph)[i]);
8950  ++cnt;
8951  }
8952 
8953  SCIPfreeBufferArray(scip, &varsusage);
8954  }
8955  else
8956  {
8957  SCIP_VAR** exprvars;
8958  int nexprvars;
8959  int e;
8960 
8961  for( e = 0; e < consdata->nexprtrees; ++e )
8962  {
8963  exprvars = SCIPexprtreeGetVars(consdata->exprtrees[e]);
8964  nexprvars = SCIPexprtreeGetNVars(consdata->exprtrees[e]);
8965  assert(exprvars != NULL || nexprvars == 0);
8966 
8967  if( cnt + nexprvars > varssize )
8968  {
8969  *success = FALSE;
8970  break;
8971  }
8972 
8973  BMScopyMemoryArray(&vars[cnt], exprvars, nexprvars); /*lint !e866*/
8974  cnt += nexprvars;
8975  }
8976  }
8977 
8978  return SCIP_OKAY;
8979 }
8980 
8981 /** constraint method of constraint handler which returns the number of variables (if possible) */
8982 static
8983 SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
8984 { /*lint --e{715}*/
8985  SCIP_CONSDATA* consdata;
8986 
8987  consdata = SCIPconsGetData(cons);
8988  assert(consdata != NULL);
8989 
8990  *nvars = consdata->nlinvars;
8991 
8992  if( consdata->exprgraphnode != NULL )
8993  {
8995  int* varsusage;
8996  int i;
8997 
8998  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8999  assert(conshdlrdata != NULL);
9000 
9001  SCIP_CALL( SCIPallocBufferArray(scip, &varsusage, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
9002 
9003  SCIPexprgraphGetSubtreeVarsUsage(conshdlrdata->exprgraph, consdata->exprgraphnode, varsusage);
9004 
9005  for( i = 0; i < SCIPexprgraphGetNVars(conshdlrdata->exprgraph); ++i )
9006  if( varsusage[i] > 0 )
9007  ++*nvars;
9008 
9009  SCIPfreeBufferArray(scip, &varsusage);
9010  }
9011  else
9012  {
9013  int e;
9014 
9015  for( e = 0; e < consdata->nexprtrees; ++e )
9016  *nvars += SCIPexprtreeGetNVars(consdata->exprtrees[e]);
9017  }
9018 
9019  *success = TRUE;
9020 
9021  return SCIP_OKAY;
9022 }
9023 
9024 /** constraint parsing method of constraint handler */
9025 static
9026 SCIP_DECL_CONSPARSE(consParseNonlinear)
9027 { /*lint --e{715}*/
9028  SCIP_EXPRTREE* exprtree;
9029  SCIP_EXPR* expr;
9030  SCIP_VAR** exprvars;
9031  SCIP_RETCODE retcode;
9032  int nvars;
9033  SCIP_Real lhs;
9034  SCIP_Real rhs;
9035  const char* endptr;
9036  char* nonconstendptr;
9037  const char* exprstart;
9038  const char* exprlastchar;
9039  int* varnames;
9040  int* curvarname;
9041  int i;
9042 
9043  SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n",str);
9044 
9045  assert(scip != NULL);
9046  assert(success != NULL);
9047  assert(str != NULL);
9048  assert(name != NULL);
9049  assert(cons != NULL);
9050 
9051  /* return if string empty */
9052  if( !*str )
9053  return SCIP_OKAY;
9054 
9055  endptr = str;
9056 
9057  expr = NULL;
9058  nvars = 0;
9059 
9060  /* set left and right hand side to their default values */
9061  lhs = -SCIPinfinity(scip);
9062  rhs = SCIPinfinity(scip);
9063 
9064  /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
9065 
9066  /* check for left hand side */
9067  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
9068  {
9069  /* there is a number coming, maybe it is a left-hand-side */
9070  if( !SCIPstrToRealValue(str, &lhs, &nonconstendptr) )
9071  {
9072  SCIPerrorMessage("error parsing number from <%s>\n", str);
9073  return SCIP_READERROR;
9074  }
9075  endptr = nonconstendptr;
9076 
9077  /* ignore whitespace */
9078  while( isspace((unsigned char)*endptr) )
9079  ++endptr;
9080 
9081  if( endptr[0] != '<' || endptr[1] != '=' )
9082  {
9083  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
9084  lhs = -SCIPinfinity(scip);
9085  }
9086  else
9087  {
9088  /* it was indeed a left-hand-side, so continue parsing after it */
9089  str = endptr + 2;
9090 
9091  /* ignore whitespace */
9092  while( isspace((unsigned char)*str) )
9093  ++str;
9094  }
9095  }
9096 
9097  /* Move endptr forward until we find end of expression */
9098  while( !(strncmp(endptr, "[free]", 6) == 0) &&
9099  !(endptr[0] == '<' && endptr[1] == '=') &&
9100  !(endptr[0] == '=' && endptr[1] == '=') &&
9101  !(endptr[0] == '>' && endptr[1] == '=') &&
9102  !(endptr[0] == '\0') )
9103  ++endptr;
9104 
9105  exprstart = str;
9106  exprlastchar = endptr - 1;
9107 
9108  *success = FALSE;
9109  str = endptr;
9110 
9111  /* check for left or right hand side */
9112  while( isspace((unsigned char)*str) )
9113  ++str;
9114 
9115  /* check for free constraint */
9116  if( strncmp(str, "[free]", 6) == 0 )
9117  {
9118  if( !SCIPisInfinity(scip, -lhs) )
9119  {
9120  SCIPerrorMessage("cannot have left hand side and [free] status \n");
9121  return SCIP_OKAY;
9122  }
9123  (*success) = TRUE;
9124  }
9125  else
9126  {
9127  switch( *str )
9128  {
9129  case '<':
9130  *success = SCIPstrToRealValue(str+2, &rhs, &nonconstendptr);
9131  break;
9132  case '=':
9133  if( !SCIPisInfinity(scip, -lhs) )
9134  {
9135  SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
9136  return SCIP_OKAY;
9137  }
9138  else
9139  {
9140  *success = SCIPstrToRealValue(str+2, &rhs, &nonconstendptr);
9141  lhs = rhs;
9142  }
9143  break;
9144  case '>':
9145  if( !SCIPisInfinity(scip, -lhs) )
9146  {
9147  SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
9148  return SCIP_OKAY;
9149  }
9150  else
9151  {
9152  *success = SCIPstrToRealValue(str+2, &lhs, &nonconstendptr);
9153  break;
9154  }
9155  case '\0':
9156  *success = TRUE;
9157  break;
9158  default:
9159  SCIPerrorMessage("unexpected character %c\n", *str);
9160  return SCIP_OKAY;
9161  }
9162  }
9163 
9164  /* alloc some space for variable names incl. indices; shouldn't be longer than expression string, and we even give it sizeof(int) times this length (plus 5) */
9165  SCIP_CALL( SCIPallocBufferArray(scip, &varnames, (int) (exprlastchar - exprstart) + 5) );
9166 
9167  /* parse expression */
9168  retcode = SCIPexprParse(SCIPblkmem(scip), SCIPgetMessagehdlr(scip), &expr, exprstart, exprlastchar, &nvars, varnames);
9169 
9170  if( retcode != SCIP_OKAY )
9171  {
9172  SCIPfreeBufferArray(scip, &varnames);
9173  return retcode;
9174  }
9175 
9176  /* get SCIP variables corresponding to variable names stored in varnames buffer */
9177  SCIP_CALL( SCIPallocBufferArray(scip, &exprvars, nvars) );
9178 
9179  assert( retcode == SCIP_OKAY );
9180  curvarname = varnames;
9181  for( i = 0; i < nvars; ++i )
9182  {
9183  assert(*curvarname == i);
9184  ++curvarname;
9185 
9186  exprvars[i] = SCIPfindVar(scip, (char*)curvarname);
9187  if( exprvars[i] == NULL )
9188  {
9189  SCIPerrorMessage("Unknown SCIP variable <%s> encountered in expression.\n", (char*)curvarname);
9190  retcode = SCIP_READERROR;
9191  goto TERMINATE;
9192  }
9193 
9194  curvarname += (strlen((char*)curvarname) + 1)/sizeof(int) + 1;
9195  }
9196 
9197  /* create expression tree */
9198  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtree, expr, nvars, 0, NULL) );
9199  SCIP_CALL( SCIPexprtreeSetVars(exprtree, nvars, exprvars) );
9200 
9201  /* create constraint */
9202  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name,
9203  0, NULL, NULL,
9204  1, &exprtree, NULL,
9205  lhs, rhs,
9206  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9207 
9208  SCIPdebugMsg(scip, "created nonlinear constraint:\n");
9209  SCIPdebugPrintCons(scip, *cons, NULL);
9210 
9211  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
9212 
9213  TERMINATE:
9214  SCIPfreeBufferArray(scip, &exprvars);
9215  SCIPfreeBufferArray(scip, &varnames);
9216 
9217  return retcode;
9218 }
9219 
9220 /*
9221  * constraint specific interface methods
9222  */
9223 
9224 /** creates the handler for nonlinear constraints and includes it in SCIP */
9226  SCIP* scip /**< SCIP data structure */
9227  )
9228 {
9230  SCIP_CONSHDLR* conshdlr;
9231 
9232  /* create nonlinear constraint handler data */
9235 
9236  /* include constraint handler */
9239  consEnfolpNonlinear, consEnfopsNonlinear, consCheckNonlinear, consLockNonlinear,
9240  conshdlrdata) );
9241  assert(conshdlr != NULL);
9242 
9243  /* set non-fundamental callbacks via specific setter functions */
9244  SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveNonlinear) );
9245  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyNonlinear, consCopyNonlinear) );
9246  SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveNonlinear) );
9247  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteNonlinear) );
9248  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableNonlinear) );
9249  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableNonlinear) );
9250  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitNonlinear) );
9251  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreNonlinear) );
9252  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolNonlinear) );
9253  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeNonlinear) );
9254  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsNonlinear) );
9255  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsNonlinear) );
9256  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitNonlinear) );
9257  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreNonlinear) );
9258  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolNonlinear) );
9259  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpNonlinear) );
9260  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolNonlinear, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
9261  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintNonlinear) );
9262  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropNonlinear, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
9264  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpNonlinear, consSepasolNonlinear, CONSHDLR_SEPAFREQ,
9266  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransNonlinear) );
9267  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseNonlinear) );
9268  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxNonlinear) );
9269 
9270  /* add nonlinear constraint handler parameters */
9271  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacysepa",
9272  "minimal efficacy for a cut to be added to the LP during separation; overwrites separating/efficacy",
9273  &conshdlrdata->mincutefficacysepa, TRUE, 0.0001, 0.0, SCIPinfinity(scip), NULL, NULL) );
9274 
9275  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacyenfofac",
9276  "minimal target efficacy of a cut in order to add it to relaxation during enforcement as a factor of the feasibility tolerance (may be ignored)",
9277  &conshdlrdata->mincutefficacyenfofac, TRUE, 2.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
9278 
9279  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/scaling",
9280  "whether scaling of infeasibility is 'o'ff, by sup-norm of function 'g'radient, or by left/right hand 's'ide",
9281  &conshdlrdata->scaling, TRUE, 'o', "ogs", NULL, NULL) );
9282 
9283  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
9284  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
9285  &conshdlrdata->cutmaxrange, FALSE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
9286 
9287  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
9288  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
9289  &conshdlrdata->linfeasshift, FALSE, TRUE, NULL, NULL) );
9290 
9291 #if 0 /* don't have any expensive checks yet, so we disable this parameter for now */
9292  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkconvexexpensive",
9293  "whether to apply expensive curvature checking methods",
9294  &conshdlrdata->checkconvexexpensive, FALSE, TRUE, NULL, NULL) );
9295 #endif
9296 
9297  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
9298  "whether to assume that nonlinear functions in inequalities (<=) are convex (disables reformulation)",
9299  &conshdlrdata->assumeconvex, TRUE, FALSE, NULL, NULL) );
9300 
9301  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
9302  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation",
9303  &conshdlrdata->maxproprounds, FALSE, 1, 0, INT_MAX, NULL, NULL) );
9304 
9305  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformulate",
9306  "whether to reformulate expression graph",
9307  &conshdlrdata->reformulate, FALSE, TRUE, NULL, NULL) );
9308 
9309  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxexpansionexponent",
9310  "maximal exponent where still expanding non-monomial polynomials in expression simplification",
9311  &conshdlrdata->maxexpansionexponent, TRUE, 2, 1, INT_MAX, NULL, NULL) );
9312 
9313  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/sepanlpmincont",
9314  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
9315  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
9316 
9317  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
9318  "are cuts added during enforcement removable from the LP in the same node?",
9319  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
9320 
9321  conshdlrdata->linvareventhdlr = NULL;
9322  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->linvareventhdlr), CONSHDLR_NAME"_boundchange", "signals a bound change to a nonlinear constraint",
9323  processLinearVarEvent, NULL) );
9324  assert(conshdlrdata->linvareventhdlr != NULL);
9325 
9326  conshdlrdata->nonlinvareventhdlr = NULL;
9327  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->nonlinvareventhdlr), CONSHDLR_NAME"_boundchange2", "signals a bound change to a nonlinear constraint handler",
9328  processNonlinearVarEvent, (SCIP_EVENTHDLRDATA*)conshdlrdata) );
9329  assert(conshdlrdata->nonlinvareventhdlr != NULL);
9330 
9331  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
9332  processNewSolutionEvent, NULL) );
9333 
9334  /* create expression interpreter */
9335  SCIP_CALL( SCIPexprintCreate(SCIPblkmem(scip), &conshdlrdata->exprinterpreter) );
9336 
9337  /* create expression graph */
9338  SCIP_CALL( SCIPexprgraphCreate(SCIPblkmem(scip), &conshdlrdata->exprgraph, -1, -1,
9339  exprgraphVarAdded, exprgraphVarRemove, NULL, (void*)conshdlrdata) );
9340  conshdlrdata->isremovedfixings = TRUE;
9341  conshdlrdata->ispropagated = TRUE;
9342 
9343  conshdlrdata->scip = scip;
9344 
9345  return SCIP_OKAY;
9346 }
9347 
9348 /** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
9350  SCIP* scip, /**< SCIP data structure */
9351  SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)),/**< method to call for upgrading nonlinear constraint, or NULL */
9352  SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)),/**< method to call for reformulating expression graph node, or NULL */
9353  int priority, /**< priority of upgrading method */
9354  SCIP_Bool active, /**< should the upgrading method by active by default? */
9355  const char* conshdlrname /**< name of the constraint handler */
9356  )
9357 {
9358  SCIP_CONSHDLR* conshdlr;
9360  SCIP_NLCONSUPGRADE* nlconsupgrade;
9361  char paramname[SCIP_MAXSTRLEN];
9362  char paramdesc[SCIP_MAXSTRLEN];
9363  int i;
9364 
9365  assert(conshdlrname != NULL );
9366 
9367  /* ignore empty upgrade functions */
9368  if( nonlinconsupgd == NULL && nodereform == NULL )
9369  return SCIP_OKAY;
9370 
9371  /* find the nonlinear constraint handler */
9372  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9373  if( conshdlr == NULL )
9374  {
9375  SCIPerrorMessage("nonlinear constraint handler not found\n");
9376  return SCIP_PLUGINNOTFOUND;
9377  }
9378 
9379  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9380  assert(conshdlrdata != NULL);
9381 
9382  /* check whether upgrade method exists already */
9383  for( i = conshdlrdata->nnlconsupgrades - 1; i >= 0; --i )
9384  {
9385  if( conshdlrdata->nlconsupgrades[i]->nlconsupgd == nonlinconsupgd && conshdlrdata->nlconsupgrades[i]->nodereform == nodereform)
9386  {
9387 #ifdef SCIP_DEBUG
9388  SCIPwarningMessage(scip, "Try to add already known upgrade method pair (%p,%p) for constraint handler <%s>.\n", nonlinconsupgd, nodereform, conshdlrname); /*lint !e611*/
9389 #endif
9390  return SCIP_OKAY;
9391  }
9392  }
9393 
9394  /* create a nonlinear constraint upgrade data object */
9395  SCIP_CALL( SCIPallocBlockMemory(scip, &nlconsupgrade) );
9396  nlconsupgrade->nlconsupgd = nonlinconsupgd;
9397  nlconsupgrade->nodereform = nodereform;
9398  nlconsupgrade->priority = priority;
9399  nlconsupgrade->active = active;
9400 
9401  /* insert nonlinear constraint upgrade method into constraint handler data */
9402  assert(conshdlrdata->nnlconsupgrades <= conshdlrdata->nlconsupgradessize);
9403  if( conshdlrdata->nnlconsupgrades+1 > conshdlrdata->nlconsupgradessize )
9404  {
9405  int newsize;
9406 
9407  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nnlconsupgrades+1);
9408  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->nlconsupgrades, conshdlrdata->nnlconsupgrades, newsize) );
9409  conshdlrdata->nlconsupgradessize = newsize;
9410  }
9411  assert(conshdlrdata->nnlconsupgrades+1 <= conshdlrdata->nlconsupgradessize);
9412 
9413  for( i = conshdlrdata->nnlconsupgrades; i > 0 && conshdlrdata->nlconsupgrades[i-1]->priority < nlconsupgrade->priority; --i )
9414  conshdlrdata->nlconsupgrades[i] = conshdlrdata->nlconsupgrades[i-1];
9415  assert(0 <= i && i <= conshdlrdata->nnlconsupgrades);
9416  conshdlrdata->nlconsupgrades[i] = nlconsupgrade;
9417  conshdlrdata->nnlconsupgrades++;
9418 
9419  /* adds parameter to turn on and off the upgrading step */
9420  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
9421  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
9423  paramname, paramdesc,
9424  &nlconsupgrade->active, FALSE, active, NULL, NULL) );
9425 
9426  return SCIP_OKAY;
9427 }
9428 
9429 /** creates and captures a nonlinear constraint
9430  * this variant takes expression trees as input
9431  *
9432  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9433  */
9435  SCIP* scip, /**< SCIP data structure */
9436  SCIP_CONS** cons, /**< pointer to hold the created constraint */
9437  const char* name, /**< name of constraint */
9438  int nlinvars, /**< number of linear variables in the constraint */
9439  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
9440  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
9441  int nexprtrees, /**< number of expression trees for nonlinear part of constraint */
9442  SCIP_EXPRTREE** exprtrees, /**< expression trees for nonlinear part of constraint */
9443  SCIP_Real* nonlincoefs, /**< coefficients for expression trees for nonlinear part, or NULL if all 1.0 */
9444  SCIP_Real lhs, /**< left hand side of constraint */
9445  SCIP_Real rhs, /**< right hand side of constraint */
9446  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9447  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9448  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9449  * Usually set to TRUE. */
9450  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9451  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9452  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9453  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9454  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9455  * Usually set to TRUE. */
9456  SCIP_Bool local, /**< is constraint only valid locally?
9457  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9458  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9459  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9460  * adds coefficients to this constraint. */
9461  SCIP_Bool dynamic, /**< is constraint subject to aging?
9462  * Usually set to FALSE. Set to TRUE for own cuts which
9463  * are seperated as constraints. */
9464  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9465  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9466  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9467  * if it may be moved to a more global node?
9468  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9469  )
9470 {
9471  SCIP_CONSHDLR* conshdlr;
9472  SCIP_CONSDATA* consdata;
9473  int i;
9474 
9475  assert(linvars != NULL || nlinvars == 0);
9476  assert(lincoefs != NULL || nlinvars == 0);
9477  assert(exprtrees != NULL || nexprtrees == 0);
9478  assert(modifiable == FALSE); /* we do not support column generation */
9479 
9480  /* find the nonlinear constraint handler */
9481  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9482  if( conshdlr == NULL )
9483  {
9484  SCIPerrorMessage("nonlinear constraint handler not found\n");
9485  return SCIP_PLUGINNOTFOUND;
9486  }
9487 
9488  /* create constraint data */
9489  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
9490 
9491  consdata->lhs = lhs;
9492  consdata->rhs = rhs;
9493 
9494  /* create constraint */
9495  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
9496  local, modifiable, dynamic, removable, stickingatnode) );
9497 
9498  /* add linear variables */
9499  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
9500  for( i = 0; i < nlinvars; ++i )
9501  {
9502  if( SCIPisZero(scip, lincoefs[i]) ) /*lint !e613*/
9503  continue;
9504 
9505  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) ); /*lint !e613*/
9506  }
9507 
9508  /* set expression trees */
9509  SCIP_CALL( consdataSetExprtrees(scip, consdata, nexprtrees, exprtrees, nonlincoefs, TRUE) );
9510 
9511  SCIPdebugMsg(scip, "created nonlinear constraint ");
9512  SCIPdebugPrintCons(scip, *cons, NULL);
9513 
9514  return SCIP_OKAY;
9515 }
9516 
9517 /** creates and captures a nonlinear constraint
9518  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
9519  * method SCIPcreateConsNonlinear(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
9520  *
9521  * this variant takes expression trees as input
9522  *
9523  * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration
9524  *
9525  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9526  */
9528  SCIP* scip, /**< SCIP data structure */
9529  SCIP_CONS** cons, /**< pointer to hold the created constraint */
9530  const char* name, /**< name of constraint */
9531  int nlinvars, /**< number of linear variables in the constraint */
9532  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
9533  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
9534  int nexprtrees, /**< number of expression trees for nonlinear part of constraint */
9535  SCIP_EXPRTREE** exprtrees, /**< expression trees for nonlinear part of constraint */
9536  SCIP_Real* nonlincoefs, /**< coefficients for expression trees for nonlinear part, or NULL if all 1.0 */
9537  SCIP_Real lhs, /**< left hand side of constraint */
9538  SCIP_Real rhs /**< right hand side of constraint */
9539  )
9540 {
9541  assert(scip != NULL);
9542 
9543  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nexprtrees, exprtrees,
9544  nonlincoefs, lhs, rhs,
9545  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9546 
9547  return SCIP_OKAY;
9548 }
9549 
9550 /** creates and captures a nonlinear constraint
9551  * this variant takes a node of the expression graph as input and can only be used during presolving
9552  * it is assumed that the nonlinear constraint will be added to the transformed problem short after creation
9553  * the given exprgraphnode is captured in this method
9554  *
9555  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9556  */
9558  SCIP* scip, /**< SCIP data structure */
9559  SCIP_CONS** cons, /**< pointer to hold the created constraint */
9560  const char* name, /**< name of constraint */
9561  int nlinvars, /**< number of linear variables in the constraint */
9562  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
9563  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
9564  SCIP_EXPRGRAPHNODE* exprgraphnode, /**< expression graph node associated to nonlinear expression */
9565  SCIP_Real lhs, /**< left hand side of constraint */
9566  SCIP_Real rhs, /**< right hand side of constraint */
9567  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9568  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9569  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9570  * Usually set to TRUE. */
9571  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9572  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9573  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9574  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9575  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9576  * Usually set to TRUE. */
9577  SCIP_Bool local, /**< is constraint only valid locally?
9578  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9579  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9580  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9581  * adds coefficients to this constraint. */
9582  SCIP_Bool dynamic, /**< is constraint subject to aging?
9583  * Usually set to FALSE. Set to TRUE for own cuts which
9584  * are seperated as constraints. */
9585  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9586  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9587  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9588  * if it may be moved to a more global node?
9589  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9590  )
9591 {
9592  SCIP_CONSHDLR* conshdlr;
9593  SCIP_CONSDATA* consdata;
9594  int i;
9595 
9596  assert(modifiable == FALSE); /* we do not support column generation */
9597  assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING);
9598 
9599  /* find the nonlinear constraint handler */
9600  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9601  if( conshdlr == NULL )
9602  {
9603  SCIPerrorMessage("nonlinear constraint handler not found\n");
9604  return SCIP_PLUGINNOTFOUND;
9605  }
9606 
9607  /* create constraint data */
9608  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
9609 
9610  consdata->lhs = lhs;
9611  consdata->rhs = rhs;
9612 
9613  /* create constraint */
9614  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
9615  local, modifiable, dynamic, removable, stickingatnode) );
9616 
9617  /* add linear variables */
9618  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
9619  for( i = 0; i < nlinvars; ++i )
9620  {
9621  if( SCIPisZero(scip, lincoefs[i]) )
9622  continue;
9623 
9624  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) );
9625  }
9626 
9627  /* set expression graph node */
9628  if( exprgraphnode != NULL )
9629  {
9630  consdata->exprgraphnode = exprgraphnode;
9631  consdata->curvature = SCIP_EXPRCURV_UNKNOWN;
9632  consdata->iscurvchecked = FALSE;
9633  consdata->activity = SCIP_INVALID;
9634  SCIPexprgraphCaptureNode(exprgraphnode);
9635  }
9636 
9637  SCIPdebugMsg(scip, "created nonlinear constraint ");
9638  SCIPdebugPrintCons(scip, *cons, NULL);
9639 
9640  return SCIP_OKAY;
9641 }
9642 
9643 /** creates and captures a nonlinear constraint
9644  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
9645  * method SCIPcreateConsNonlinear(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
9646  *
9647  * this variant takes a node of the expression graph as input and can only be used during presolving
9648  * it is assumed that the nonlinear constraint will be added to the transformed problem short after creation
9649  * the given exprgraphnode is captured in this method
9650  *
9651  * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration
9652  *
9653  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9654  */
9656  SCIP* scip, /**< SCIP data structure */
9657  SCIP_CONS** cons, /**< pointer to hold the created constraint */
9658  const char* name, /**< name of constraint */
9659  int nlinvars, /**< number of linear variables in the constraint */
9660  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
9661  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
9662  SCIP_EXPRGRAPHNODE* exprgraphnode, /**< expression graph node associated to nonlinear expression */
9663  SCIP_Real lhs, /**< left hand side of constraint */
9664  SCIP_Real rhs /**< right hand side of constraint */
9665  )
9666 {
9667  assert(scip != NULL);
9668 
9669  SCIP_CALL( SCIPcreateConsNonlinear2(scip, cons, name, nlinvars, linvars, lincoefs, exprgraphnode, lhs, rhs,
9670  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9671 
9672  return SCIP_OKAY;
9673 }
9674 
9675 /** adds a linear variable with coefficient to a nonlinear constraint */
9677  SCIP* scip, /**< SCIP data structure */
9678  SCIP_CONS* cons, /**< constraint */
9679  SCIP_VAR* var, /**< variable */
9680  SCIP_Real coef /**< coefficient of variable */
9681  )
9682 {
9683  assert(scip != NULL);
9684  assert(cons != NULL);
9685  assert(var != NULL);
9686  assert(!SCIPisInfinity(scip, REALABS(coef)));
9687 
9688  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
9689 
9690  return SCIP_OKAY;
9691 }
9692 
9693 /** sets the expression trees in a nonlinear constraint
9694  * constraint must not be active yet
9695  */
9697  SCIP* scip, /**< SCIP data structure */
9698  SCIP_CONS* cons, /**< constraint */
9699  int nexprtrees, /**< number of expression trees */
9700  SCIP_EXPRTREE** exprtrees, /**< new expression trees, or NULL if nexprtrees is 0 */
9701  SCIP_Real* coefs /**< coefficients of expression trees, or NULL if all 1.0 */
9702  )
9703 {
9704  assert(scip != NULL);
9705  assert(cons != NULL);
9706  assert(!SCIPconsIsActive(cons));
9707  assert(SCIPconsGetData(cons) != NULL);
9708  assert(exprtrees != NULL || nexprtrees == 0);
9709 
9710  SCIP_CALL( consdataSetExprtrees(scip, SCIPconsGetData(cons), nexprtrees, exprtrees, coefs, TRUE) );
9711 
9712  return SCIP_OKAY;
9713 }
9714 
9715 /** adds expression trees to a nonlinear constraint
9716  * constraint must not be active yet
9717  */
9719  SCIP* scip, /**< SCIP data structure */
9720  SCIP_CONS* cons, /**< constraint */
9721  int nexprtrees, /**< number of expression trees */
9722  SCIP_EXPRTREE** exprtrees, /**< new expression trees, or NULL if nexprtrees is 0 */
9723  SCIP_Real* coefs /**< coefficients of expression trees, or NULL if all 1.0 */
9724  )
9725 {
9726  assert(scip != NULL);
9727  assert(cons != NULL);
9728  assert(!SCIPconsIsActive(cons));
9729  assert(SCIPconsGetData(cons) != NULL);
9730  assert(exprtrees != NULL || nexprtrees == 0);
9731 
9732  SCIP_CALL( consdataAddExprtrees(scip, SCIPconsGetData(cons), nexprtrees, exprtrees, coefs, TRUE) );
9733 
9734  return SCIP_OKAY;
9735 }
9736 
9737 /** gets the nonlinear constraint as a nonlinear row representation */
9739  SCIP* scip, /**< SCIP data structure */
9740  SCIP_CONS* cons, /**< constraint */
9741  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
9742  )
9743 {
9744  SCIP_CONSDATA* consdata;
9745 
9746  assert(cons != NULL);
9747  assert(nlrow != NULL);
9748 
9749  consdata = SCIPconsGetData(cons);
9750  assert(consdata != NULL);
9751 
9752  if( consdata->nlrow == NULL )
9753  {
9754  SCIP_CALL( createNlRow(scip, cons) );
9755  }
9756  assert(consdata->nlrow != NULL);
9757  *nlrow = consdata->nlrow;
9758 
9759  return SCIP_OKAY;
9760 }
9761 
9762 /** gets the number of variables in the linear term of a nonlinear constraint */
9764  SCIP* scip, /**< SCIP data structure */
9765  SCIP_CONS* cons /**< constraint */
9766  )
9767 {
9768  assert(cons != NULL);
9769  assert(SCIPconsGetData(cons) != NULL);
9770 
9771  return SCIPconsGetData(cons)->nlinvars;
9772 }
9773 
9774 /** gets the variables in the linear part of a nonlinear constraint */
9776  SCIP* scip, /**< SCIP data structure */
9777  SCIP_CONS* cons /**< constraint */
9778  )
9779 {
9780  assert(cons != NULL);
9781  assert(SCIPconsGetData(cons) != NULL);
9782 
9783  return SCIPconsGetData(cons)->linvars;
9784 }
9785 
9786 /** gets the coefficients in the linear part of a nonlinear constraint */
9788  SCIP* scip, /**< SCIP data structure */
9789  SCIP_CONS* cons /**< constraint */
9790  )
9791 {
9792  assert(cons != NULL);
9793  assert(SCIPconsGetData(cons) != NULL);
9794 
9795  return SCIPconsGetData(cons)->lincoefs;
9796 }
9797 
9798 /** gets the number of expression trees of a nonlinear constraint */
9800  SCIP* scip, /**< SCIP data structure */
9801  SCIP_CONS* cons /**< constraint */
9802  )
9803 {
9804  assert(cons != NULL);
9805  assert(SCIPconsGetData(cons) != NULL);
9807 
9808  return SCIPconsGetData(cons)->nexprtrees;
9809 }
9810 
9811 /** gets the expression trees of a nonlinear constraint */
9813  SCIP* scip, /**< SCIP data structure */
9814  SCIP_CONS* cons /**< constraint */
9815  )
9816 {
9817  assert(cons != NULL);
9818  assert(SCIPconsGetData(cons) != NULL);
9820 
9821  return SCIPconsGetData(cons)->exprtrees;
9822 }
9823 
9824 /** gets the coefficients of the expression trees of a nonlinear constraint */
9826  SCIP* scip, /**< SCIP data structure */
9827  SCIP_CONS* cons /**< constraint */
9828  )
9829 {
9830  assert(cons != NULL);
9831  assert(SCIPconsGetData(cons) != NULL);
9833 
9834  return SCIPconsGetData(cons)->nonlincoefs;
9835 }
9836 
9837 /** gets the expression graph node of a nonlinear constraint */
9839  SCIP* scip, /**< SCIP data structure */
9840  SCIP_CONS* cons /**< constraint */
9841  )
9842 {
9843  assert(cons != NULL);
9844  assert(SCIPconsGetData(cons) != NULL);
9845 
9846  return SCIPconsGetData(cons)->exprgraphnode;
9847 }
9848 
9849 /** gets the left hand side of a nonlinear constraint */
9851  SCIP* scip, /**< SCIP data structure */
9852  SCIP_CONS* cons /**< constraint */
9853  )
9854 {
9855  assert(cons != NULL);
9856  assert(SCIPconsGetData(cons) != NULL);
9857 
9858  return SCIPconsGetData(cons)->lhs;
9859 }
9860 
9861 /** gets the right hand side of a nonlinear constraint */
9863  SCIP* scip, /**< SCIP data structure */
9864  SCIP_CONS* cons /**< constraint */
9865  )
9866 {
9867  assert(cons != NULL);
9868  assert(SCIPconsGetData(cons) != NULL);
9869 
9870  return SCIPconsGetData(cons)->rhs;
9871 }
9872 
9873 /** check the function of a nonlinear constraint for convexity/concavity, if not done yet */
9875  SCIP* scip, /**< SCIP data structure */
9876  SCIP_CONS* cons /**< constraint */
9877  )
9878 {
9879  SCIP_CONSHDLR* conshdlr;
9881 
9882  assert(scip != NULL);
9883  assert(cons != NULL);
9884 
9885  conshdlr = SCIPconsGetHdlr(cons);
9886  assert(conshdlr != NULL);
9887  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9888  assert(conshdlrdata != NULL);
9889 
9890  SCIP_CALL( checkCurvature(scip, cons, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
9891 
9892  return SCIP_OKAY;
9893 }
9894 
9895 /** gets the curvature of the nonlinear function of a nonlinear constraint */
9897  SCIP* scip, /**< SCIP data structure */
9898  SCIP_CONS* cons, /**< constraint */
9899  SCIP_Bool checkcurv, /**< whether to check constraint curvature, if not checked before */
9900  SCIP_EXPRCURV* curvature /**< pointer to store curvature of constraint */
9901  )
9902 {
9903  SCIP_CONSHDLR* conshdlr;
9905  SCIP_CONSDATA* consdata;
9906 
9907  assert(scip != NULL);
9908  assert(cons != NULL);
9909  assert(curvature != NULL);
9910 
9911  consdata = SCIPconsGetData(cons);
9912  assert(consdata != NULL);
9913 
9914  conshdlr = SCIPconsGetHdlr(cons);
9915  assert(conshdlr != NULL);
9916  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9917  assert(conshdlrdata != NULL);
9918 
9919  if( checkcurv && !consdata->iscurvchecked )
9920  {
9921  SCIP_CALL( checkCurvature(scip, cons, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
9922  }
9923 
9924  *curvature = consdata->curvature;
9925 
9926  return SCIP_OKAY;
9927 }
9928 
9929 /** gets the curvature of the expression trees (multiplied by their coefficient) of a nonlinear constraint */
9931  SCIP* scip, /**< SCIP data structure */
9932  SCIP_CONS* cons, /**< constraint */
9933  SCIP_Bool checkcurv, /**< whether to check constraint curvature, if not checked before */
9934  SCIP_EXPRCURV** curvatures /**< buffer to store curvatures of exprtrees */
9935  )
9936 {
9937  SCIP_CONSHDLR* conshdlr;
9939  SCIP_CONSDATA* consdata;
9940 
9941  assert(scip != NULL);
9942  assert(cons != NULL);
9943  assert(curvatures != NULL);
9945 
9946  consdata = SCIPconsGetData(cons);
9947  assert(consdata != NULL);
9948 
9949  conshdlr = SCIPconsGetHdlr(cons);
9950  assert(conshdlr != NULL);
9951  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9952  assert(conshdlrdata != NULL);
9953 
9954  assert(SCIPconsGetData(cons) != NULL);
9955 
9956  if( checkcurv && !consdata->iscurvchecked )
9957  {
9958  SCIP_CALL( checkCurvature(scip, cons, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
9959  }
9960 
9961  *curvatures = consdata->curvatures;
9962 
9963  return SCIP_OKAY;
9964 }
9965 
9966 /** computes the violation of a nonlinear constraint by a solution */
9968  SCIP* scip, /**< SCIP data structure */
9969  SCIP_CONS* cons, /**< constraint */
9970  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
9971  SCIP_Real* violation /**< pointer to store violation of constraint */
9972  )
9973 {
9974  SCIP_CONSHDLR* conshdlr;
9975  SCIP_CONSDATA* consdata;
9976  SCIP_Bool solviolbounds;
9977 
9978  assert(scip != NULL);
9979  assert(cons != NULL);
9980  assert(violation != NULL);
9981 
9983  {
9984  /* @todo make available */
9985  SCIPwarningMessage(scip, "SCIPgetViolationNonlinear is not available for active constraints during presolve.\n");
9986  *violation = SCIP_INVALID;
9987  return SCIP_OKAY;
9988  }
9989 
9990  conshdlr = SCIPconsGetHdlr(cons);
9991  assert(conshdlr != NULL);
9992 
9993  SCIP_CALL( computeViolation(scip, conshdlr, cons, sol, &solviolbounds) );
9994 
9995  if( solviolbounds )
9996  {
9997  SCIPerrorMessage("Solution passed to SCIPgetViolationNonlinear() does not satisfy variable bounds.\n");
9998  return SCIP_ERROR;
9999  }
10000 
10001  consdata = SCIPconsGetData(cons);
10002  assert(consdata != NULL);
10003 
10004  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
10005 
10006  return SCIP_OKAY;
10007 }
10008 
10009 /** get index of a linear variable of a nonlinear constraint that may be decreased without making any other constraint infeasible, or -1 if none */
10011  SCIP* scip, /**< SCIP data structure */
10012  SCIP_CONS* cons /**< constraint */
10013  )
10014 {
10015  SCIP_CONSDATA* consdata;
10016 
10017  assert(scip != NULL);
10018  assert(cons != NULL);
10019 
10020  consdata = SCIPconsGetData(cons);
10021  assert(consdata != NULL);
10022 
10023  if( consdata->linvar_mayincrease == -1 && consdata->linvar_maydecrease == -1 )
10024  consdataFindUnlockedLinearVar(scip, consdata);
10025 
10026  return consdata->linvar_maydecrease;
10027 }
10028 
10029 /** get index of a linear variable of a nonlinear constraint that may be increased without making any other constraint infeasible, or -1 if none */
10031  SCIP* scip, /**< SCIP data structure */
10032  SCIP_CONS* cons /**< constraint */
10033  )
10034 {
10035  SCIP_CONSDATA* consdata;
10036 
10037  assert(scip != NULL);
10038  assert(cons != NULL);
10039 
10040  consdata = SCIPconsGetData(cons);
10041  assert(consdata != NULL);
10042 
10043  if( consdata->linvar_mayincrease == -1 && consdata->linvar_maydecrease == -1 )
10044  consdataFindUnlockedLinearVar(scip, consdata);
10045 
10046  return consdata->linvar_mayincrease;
10047 }
10048 
10049 /** gets expression graph of nonlinear constraint handler */
10051  SCIP* scip, /**< SCIP data structure */
10052  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
10053  )
10054 {
10056 
10057  assert(scip != NULL);
10058  assert(conshdlr != NULL);
10059 
10060  conshdlrdata = SCIPconshdlrGetData(conshdlr);
10061  assert(conshdlrdata != NULL);
10062  assert(conshdlrdata->exprgraph != NULL);
10063 
10064  return conshdlrdata->exprgraph;
10065 }
10066 
10067 /** given three points, constructs coefficient of equation for hyperplane generated by these three points
10068  * Three points a, b, and c are given.
10069  * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
10070  * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
10071  */
10073  SCIP* scip, /**< SCIP data structure */
10074  SCIP_Real a1, /**< first coordinate of a */
10075  SCIP_Real a2, /**< second coordinate of a */
10076  SCIP_Real a3, /**< third coordinate of a */
10077  SCIP_Real b1, /**< first coordinate of b */
10078  SCIP_Real b2, /**< second coordinate of b */
10079  SCIP_Real b3, /**< third coordinate of b */
10080  SCIP_Real c1, /**< first coordinate of c */
10081  SCIP_Real c2, /**< second coordinate of c */
10082  SCIP_Real c3, /**< third coordinate of c */
10083  SCIP_Real* alpha, /**< coefficient of first coordinate */
10084  SCIP_Real* beta, /**< coefficient of second coordinate */
10085  SCIP_Real* gamma_, /**< coefficient of third coordinate */
10086  SCIP_Real* delta /**< constant right-hand side */
10087  )
10088 {
10089  assert(scip != NULL);
10090  assert(alpha != NULL);
10091  assert(beta != NULL);
10092  assert(gamma_ != NULL);
10093  assert(delta != NULL);
10094 
10095  *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
10096  *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
10097  *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
10098  *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
10099 
10100  /* check if hyperplane contains all three points (necessary because of numerical troubles) */
10101  if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 + *gamma_ * a3, *delta) ||
10102  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 + *gamma_ * b3, *delta) ||
10103  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 + *gamma_ * c3, *delta) )
10104  {
10105  SCIP_Real m[9];
10106  SCIP_Real rhs[3];
10107  SCIP_Real x[3];
10108  SCIP_Bool success;
10109 
10110  /* initialize matrix column-wise */
10111  m[0] = a1;
10112  m[1] = b1;
10113  m[2] = c1;
10114  m[3] = a2;
10115  m[4] = b2;
10116  m[5] = c2;
10117  m[6] = a3;
10118  m[7] = b3;
10119  m[8] = c3;
10120 
10121  rhs[0] = 1.0;
10122  rhs[1] = 1.0;
10123  rhs[2] = 1.0;
10124 
10125  SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
10126 
10127  /* solve the linear problem */
10128  SCIP_CALL( SCIPsolveLinearProb(3, m, rhs, x, &success) );
10129 
10130  *delta = rhs[0];
10131  *alpha = x[0];
10132  *beta = x[1];
10133  *gamma_ = x[2];
10134 
10135  /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
10136  * not add a cut to SCIP and that all assertions are trivially fulfilled
10137  */
10138  if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 + *gamma_ * a3, *delta) ||
10139  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 + *gamma_ * b3, *delta) ||
10140  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 + *gamma_ * c3, *delta) )
10141  {
10142  SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
10143  *delta = 0.0;
10144  *alpha = 0.0;
10145  *beta = 0.0;
10146  *gamma_ = 0.0;
10147  }
10148  }
10149 
10150  if( *gamma_ < 0.0 )
10151  {
10152  *alpha = -*alpha;
10153  *beta = -*beta;
10154  *gamma_ = -*gamma_;
10155  *delta = -*delta;
10156  }
10157 
10158  return SCIP_OKAY;
10159 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
static SCIP_DECL_CONSENABLE(consEnableNonlinear)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21975
static SCIP_DECL_EXPRGRAPHVARREMOVE(exprgraphVarRemove)
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13252
int SCIPgetNIntVars(SCIP *scip)
Definition: scip.c:11770
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss)
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15756
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:21964
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:6263
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15437
static void consdataUpdateLinearActivityUbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
SCIP_EXPRGRAPH * SCIPgetExprgraphNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
SCIP_RETCODE SCIPincludeNonlinconsUpgrade(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)), SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)), int priority, SCIP_Bool active, const char *conshdlrname)
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:45508
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14893
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:7978
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprgraphAddNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int mindepth, int nchildren, SCIP_EXPRGRAPHNODE **children)
Definition: expr.c:15093
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:21958
primal heuristic that tries a given solution
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip.c:30965
static SCIP_RETCODE getGradientMaxElement(SCIP *scip, SCIP_EXPRINT *exprint, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool newsol, SCIP_Real *maxelem)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22212
SCIP_RETCODE SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16685
SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1726
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip.c:40680
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:15177
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:814
static void consdataFindUnlockedLinearVar(SCIP *scip, SCIP_CONSDATA *consdata)
methods to interpret (evaluate) an expression tree "fast"
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:58
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8140
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:16961
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip.c:38139
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:6286
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5897
static SCIP_RETCODE getCoeffsAndConstantFromLinearExpr(SCIP_EXPR *expr, SCIP_Real scalar, SCIP_Real *varcoeffs, SCIP_Real *constant)
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:14683
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46696
static SCIP_RETCODE addLinearizationCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *ref, SCIP_Bool *separatedlpsol, SCIP_Real minefficacy)
static SCIP_DECL_CONSEXIT(consExitNonlinear)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:40502
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:6576
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12890
SCIP_CONS * cons
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
static SCIP_DECL_CONSDISABLE(consDisableNonlinear)
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5670
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17169
static SCIP_RETCODE unlockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14863
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:6516
static SCIP_RETCODE addUserEstimator(SCIP *scip, SCIP_CONS *cons, int exprtreeidx, SCIP_Real *x, SCIP_Bool overestimate, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPgetExprtreeCurvaturesNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkcurv, SCIP_EXPRCURV **curvatures)
#define SCIP_MAXSTRLEN
Definition: def.h:225
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPaddRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep, int nvars, SCIP_VAR **vars, SCIP_Real *coefs)
static SCIP_RETCODE consdataAddExprtrees(SCIP *scip, SCIP_CONSDATA *consdata, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_Bool copytrees)
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip.c:6008
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28056
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
static SCIP_DECL_EXPRGRAPHVARADDED(exprgraphVarAdded)
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12530
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:45835
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:16949
SCIP_RETCODE SCIPexprintGradInt(SCIP_EXPRINT *exprint, SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Bool new_varvals, SCIP_INTERVAL *val, SCIP_INTERVAL *gradient)
int SCIPexprgraphGetDepth(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14833
SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefrange, SCIP_Real minviol, SCIP_Real *coefrange, SCIP_Real *viol)
SCIP_RETCODE SCIPsetExprtreesNonlinear(SCIP *scip, SCIP_CONS *cons, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs)
const char * SCIPexpropGetName(SCIP_EXPROP op)
Definition: expr.c:3263
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:46110
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17225
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46037
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDEACTIVE((*consdeactive)))
Definition: scip.c:6378
SCIP_Bool SCIPlpiIsPrimalUnbounded(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2381
static SCIP_RETCODE checkCurvature(SCIP *scip, SCIP_CONS *cons, SCIP_Bool expensivechecks, SCIP_Bool assumeconvex)
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:8250
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:8561
SCIP_Real * SCIPexprtreeGetParamVals(SCIP_EXPRTREE *tree)
Definition: expr.c:8579
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip.c:31348
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
SCIP_RETCODE SCIPexprCreateMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial, SCIP_Real coef, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:7010
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:14937
static SCIP_RETCODE reformEnsureChildrenMinCurvature(SCIP *scip, SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRCURV mincurv, SCIP_CONS **conss, int nconss, int *naddcons)
void SCIPexprgraphCaptureNode(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12868
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip.c:18652
static SCIP_RETCODE splitOffLinearPart(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:18461
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:138
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip.c:6177
#define SCIP_EXPRINTCAPABILITY_INTGRADIENT
SCIP_RETCODE SCIPexprgraphCreateNodeQuadratic(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nchildren, SCIP_Real *lincoefs, int nquadelems, SCIP_QUADELEM *quadelems, SCIP_Real constant)
Definition: expr.c:13381
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:46409
static SCIP_RETCODE consdataCreateEmpty(SCIP *scip, SCIP_CONSDATA **consdata)
int SCIPexprGetOpIndex(SCIP_EXPR *expr)
Definition: expr.c:5700
SCIP_RETCODE SCIPlpiAddCols(SCIP_LPI *lpi, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
Definition: lpi_clp.cpp:649
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46372
SCIP_Real SCIPgetRelaxFeastolFactor(SCIP *scip)
Definition: scip.c:34579
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
SCIP_SIDETYPE sidetype
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4485
void SCIPexprgraphPropagateNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:15810
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16391
#define FALSE
Definition: def.h:64
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip.c:21674
static SCIP_DECL_CONSINITPRE(consInitpreNonlinear)
static SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14883
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip.c:5866
SCIP_Real * SCIPgetLinearCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:46050
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:9340
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:46122
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13019
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_RETCODE SCIPgetNlRowNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28286
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
Definition: lpi_clp.cpp:549
SCIP_RETCODE SCIPsolveNLP(SCIP *scip)
Definition: scip.c:31325
static SCIP_RETCODE addLinearization(SCIP *scip, SCIP_EXPRINT *exprint, SCIP_CONS *cons, int exprtreeidx, SCIP_Real *x, SCIP_Bool newx, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:21349
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8160
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
static SCIP_RETCODE consdataSetExprtrees(SCIP *scip, SCIP_CONSDATA *consdata, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_Bool copytrees)
SCIP_RETCODE SCIPexprtreeCopy(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **targettree, SCIP_EXPRTREE *sourcetree)
Definition: expr.c:8759
SCIP_RETCODE SCIPexprintCompile(SCIP_EXPRINT *exprint, SCIP_EXPRTREE *tree)
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12910
SCIP_INTERVAL SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13242
static SCIP_RETCODE addConcaveEstimatorUnivariate(SCIP *scip, SCIP_CONS *cons, int exprtreeidx, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPgetCurvatureNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkcurv, SCIP_EXPRCURV *curvature)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15735
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
int * SCIPexprgraphGetNNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14843
SCIP_Real SCIPgetRhsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8190
SCIP_RETCODE SCIPexprEvalInt(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7902
static GRAPHNODE ** active
SCIP_RETCODE SCIPexprtreeSetVars(SCIP_EXPRTREE *tree, int nvars, SCIP_VAR **vars)
Definition: nlp.c:111
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22328
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:21973
#define CONSHDLR_SEPAFREQ
static SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip.c:5920
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip.c:8691
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip.c:1228
int SCIPgetLinvarMayDecreaseNonlinear(SCIP *scip, SCIP_CONS *cons)
static void consdataUpdateLinearActivityLbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15297
SCIP_EXPRTREE ** SCIPgetExprtreesNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:45985
static SCIP_DECL_CONSACTIVE(consActiveNonlinear)
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:37220
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8718
static SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:22003
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip.c:21642
SCIP_RETCODE SCIPcreateConsBasicNonlinear2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPRGRAPHNODE *exprgraphnode, SCIP_Real lhs, SCIP_Real rhs)
static SCIP_RETCODE reformReplaceNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, SCIP_EXPRGRAPHNODE *replacement, SCIP_CONS **conss, int nconss)
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:21956
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
#define CONSHDLR_NAME
SCIP_RETCODE SCIPaddExprtreesNonlinear(SCIP *scip, SCIP_CONS *cons, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs)
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8150
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:108
SCIP_Bool SCIPlpiIsObjlimExc(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2577
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:6309
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1260
#define SCIPdebugMsgPrint
Definition: scip.h:452
#define SCIPdebugMsg
Definition: scip.h:451
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.c:4237
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:6493
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:15044
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:7942
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1336
int SCIPgetNContVars(SCIP *scip)
Definition: scip.c:11860
SCIP_VAR ** SCIPexprtreeGetVars(SCIP_EXPRTREE *tree)
Definition: nlp.c:101
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.c:27240
#define SCIP_DECL_EXPRGRAPHNODEREFORM(x)
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:45480
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13113
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
static SCIP_RETCODE removeFixedNonlinearVariables(SCIP *scip, SCIP_CONSHDLR *conshdlr)
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30621
int SCIPgetNExprtreesNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:14317
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:104
SCIP_EXPRCURV SCIPexprcurvMultiply(SCIP_Real factor, SCIP_EXPRCURV curvature)
Definition: expr.c:240
int SCIPexprGetMonomialNFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5887
SCIP_RETCODE SCIPexprtreePrintWithNames(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: nlp.c:172
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:236
SCIP_RETCODE SCIPexprtreeCheckCurvature(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:8950
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12950
SCIP_VAR * SCIPfindVar(SCIP *scip, const char *name)
Definition: scip.c:12374
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13101
SCIP_RETCODE SCIPexprgraphCreate(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPH **exprgraph, int varssizeinit, int depthinit, SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), void *userdata)
Definition: expr.c:15005
static SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
int SCIPgetLinvarMayIncreaseNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17179
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip.c:6129
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:21970
SCIP_Real coef
Definition: type_expr.h:102
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:127
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
SCIP_Real inf
Definition: intervalarith.h:39
const char * SCIPexprcurvGetName(SCIP_EXPRCURV curv)
Definition: expr.c:474
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1162
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip.c:37468
static SCIP_DECL_CONSCHECK(consCheckNonlinear)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip.c:1047
static SCIP_RETCODE addConcaveEstimatorMultivariate(SCIP *scip, SCIP_CONS *cons, int exprtreeidx, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_Bool SCIPconsIsLocked(SCIP_CONS *cons)
Definition: cons.c:8220
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13125
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30585
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:6032
static SCIP_RETCODE registerBranchingVariables(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
SCIP_RETCODE SCIPaddLinearConsToNlpHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_Bool addcombconss, SCIP_Bool addcontconss)
Definition: heur_subnlp.c:2389
SCIP_Bool SCIPexprgraphHasNodeNonlinearAncestor(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14568
SCIP_Bool SCIPlpiIsPrimalFeasible(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2414
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13262
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1181
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprEval(SCIP_EXPR *expr, SCIP_Real *varvals, SCIP_Real *param, SCIP_Real *val)
Definition: expr.c:7841
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip.c:8175
static SCIP_DECL_EVENTEXEC(processLinearVarEvent)
#define SCIPerrorMessage
Definition: pub_message.h:45
SCIP_RETCODE SCIPexprintEval(SCIP_EXPRINT *exprint, SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
static SCIP_RETCODE consdataEnsureLinearVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
#define CONSHDLR_ENFOPRIORITY
static SCIP_DECL_CONSINITLP(consInitlpNonlinear)
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12459
static SCIP_RETCODE propagateBoundsTightenVarLb(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *solviolbounds)
SCIP_RETCODE SCIPexprintCreate(BMS_BLKMEM *blkmem, SCIP_EXPRINT **exprint)
SCIP_RETCODE SCIPaddConsLocal(SCIP *scip, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip.c:13079
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip.c:31216
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:69
SCIP_EXPRGRAPHNODE *** SCIPexprgraphGetNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14853
#define SCIP_DECL_NONLINCONSUPGD(x)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:13160
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16649
#define CONSHDLR_PROP_TIMING
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:38219
static SCIP_RETCODE lockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:16500
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip.c:32031
SCIP_RETCODE SCIPgetViolationNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *violation)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:19006
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:22004
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:45753
SCIP_RETCODE SCIPcheckCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_RESULT *result)
Definition: scip.c:28346
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21477
static SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
static SCIP_RETCODE mergeAndCleanLinearVars(SCIP *scip, SCIP_CONS *cons)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7881
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:25588
SCIP_EXPRCURV SCIPexprcurvPower(SCIP_INTERVAL basebounds, SCIP_EXPRCURV basecurv, SCIP_Real exponent)
Definition: expr.c:253
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8100
void SCIPaddRowprepSide(SCIP_ROWPREP *rowprep, SCIP_Real side)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16555
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:6057
SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:3715
constraint handler for quadratic constraints
#define BOUNDTIGHTENING_MINSTRENGTH
static SCIP_RETCODE propagateBoundsTightenVarUb(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
static SCIP_RETCODE propagateBounds(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool needclear, SCIP_RESULT *result, int *nchgbds, int *ndelconss)
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4133
SCIP_Real * SCIPgetExprtreeCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateRowprep(SCIP *scip, SCIP_ROWPREP **rowprep, SCIP_SIDETYPE sidetype, SCIP_Bool local)
SCIP_RETCODE SCIPgetExprtreeTransformedVars(SCIP *scip, SCIP_EXPRTREE *tree)
Definition: scip.c:32804
#define NULL
Definition: lpi_spx1.cpp:137
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28258
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2382
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:38317
int SCIPgetNNlpis(SCIP *scip)
Definition: scip.c:9479
#define REALABS(x)
Definition: def.h:169
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:8559
SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:31293
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip.c:36877
SCIP_RETCODE SCIPexprgraphCreateNodeLinear(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int ncoefs, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:13355
static SCIP_RETCODE reformNode2Var(SCIP *scip, SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_CONS **conss, int nconss, int *naddcons, SCIP_Bool donotmultaggr)
#define SCIP_CALL(x)
Definition: def.h:316
SCIP_Bool SCIPlpiIsOptimal(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2521
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12880
static SCIP_RETCODE chgLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_Real newcoef)
SCIP_RETCODE SCIPexprParse(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR **expr, const char *str, const char *lastchar, int *nvars, int *varnames)
Definition: expr.c:8488
#define INITLPMAXVARVAL
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46359
static SCIP_RETCODE addConcaveEstimatorBivariate(SCIP *scip, SCIP_CONS *cons, int exprtreeidx, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize, SCIP_Bool mergemultiples)
Definition: scip.c:18950
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:16973
SCIP_Real sup
Definition: intervalarith.h:40
SCIP_EXPRINTCAPABILITY SCIPexprintGetCapability(void)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46346
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16401
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1353
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8120
void SCIPexprgraphTightenNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_INTERVAL nodebounds, SCIP_Real minstrength, SCIP_Real infinity, SCIP_Bool *cutoff)
Definition: expr.c:14621
SCIP_RETCODE SCIPexprEstimateUser(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_Real *argvals, SCIP_INTERVAL *argbounds, SCIP_Bool overestimate, SCIP_Real *coeffs, SCIP_Real *constant, SCIP_Bool *success)
Definition: expr.c:8058
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:265
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:33999
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:106
SCIP_EXPR * SCIPexprtreeGetRoot(SCIP_EXPRTREE *tree)
Definition: expr.c:8549
SCIP_Bool SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14533
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:13140
#define SCIP_EVENTTYPE_UBCHANGED
Definition: type_event.h:105
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4515
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:2671
SCIP_RETCODE SCIPaddLinearVarNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE delLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
static SCIP_RETCODE dropLinearVarEvents(SCIP *scip, SCIP_CONS *cons, int linvarpos)
static void consdataSortLinearVars(SCIP_CONSDATA *consdata)
static SCIP_RETCODE reformMonomial(SCIP *scip, SCIP_EXPRGRAPH *exprgraph, int nfactors, SCIP_EXPRGRAPHNODE **factors, SCIP_Real *exponents, SCIP_EXPRGRAPHNODE **resultnode, SCIP_Bool createauxcons, int mindepth, int *naddcons)
Ipopt NLP interface.
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:21991
#define CONSHDLR_CHECKPRIORITY
static SCIP_RETCODE catchLinearVarEvents(SCIP *scip, SCIP_CONS *cons, int linvarpos)
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:5690
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:982
SCIP_Real side
#define SCIP_Bool
Definition: def.h:61
#define infty2infty(infty1, infty2, val)
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:40434
static SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:28948
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:959
static SCIP_RETCODE reformulate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *naddcons)
SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI *lpi, SCIP_LPPARAM type, int ival)
Definition: lpi_clp.cpp:3510
static SCIP_RETCODE propagateConstraintSides(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_RESULT *result, int *nchgbds)
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:14957
static const char * paramname[]
Definition: lpi_msk.c:4271
static void consdataUpdateLinearActivity(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:30152
SCIP_Real SCIPgetLhsNonlinear(SCIP *scip, SCIP_CONS *cons)
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:42321
SCIP_RETCODE SCIPlpiSetRealpar(SCIP_LPI *lpi, SCIP_LPPARAM type, SCIP_Real dval)
Definition: lpi_clp.cpp:3658
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8604
constraint handler for nonlinear constraints
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:28746
void SCIPmergeRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
SCIP_Bool SCIPexprHasUserEstimator(SCIP_EXPR *expr)
Definition: expr.c:5928
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:9411
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:34094
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7901
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:5680
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11249
methods for debugging
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:16633
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:14977
#define CONSHDLR_PROPFREQ
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8010
#define CONSHDLR_NEEDSCONS
SCIP_RETCODE SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
Definition: scip.c:6424
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:40468
SCIP_RETCODE SCIPexprgraphNodeSplitOffLinear(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, int linvarssize, int *nlinvars, void **linvars, SCIP_Real *lincoefs, SCIP_Real *constant)
Definition: expr.c:13505
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:37806
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8080
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8050
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17017
SCIP_RETCODE SCIPexprtreeFree(SCIP_EXPRTREE **tree)
Definition: expr.c:8799
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.c:40548
#define CONSHDLR_DELAYSEPA
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip.c:17314
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:36572
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE registerLargeRelaxValueVariableForBranching(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_VAR **brvar)
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14495
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
SCIP_Bool SCIPintervalAreDisjoint(SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:93
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21403
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:6470
Constraint handler for linear constraints in their most general form, .
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip.c:33981
SCIP_RETCODE SCIPlpiAddRows(SCIP_LPI *lpi, 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:793
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:16937
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:46061
static SCIP_DECL_CONSPROP(consPropNonlinear)
#define BMSclearMemory(ptr)
Definition: memory.h:88
SCIP_Real SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5877
SCIP_RETCODE SCIPexprintGrad(SCIP_EXPRINT *exprint, SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Bool new_varvals, SCIP_Real *val, SCIP_Real *gradient)
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONSHDLR *conshdlr)
char name[SCIP_MAXSTRLEN]
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip.c:6401
int SCIPgetNBinVars(SCIP *scip)
Definition: scip.c:11725
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:35163
#define INTERVALINFTY
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:11680
#define CONSHDLR_SEPAPRIORITY
int SCIPexprgraphGetNodeIntPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13008
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7202
static SCIP_DECL_CONSDELETE(consDeleteNonlinear)
void SCIPenableNLP(SCIP *scip)
Definition: scip.c:30950
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12920
static SCIP_RETCODE addLinearCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_DECL_CONSTRANS(consTransNonlinear)
static SCIP_RETCODE removeFixedLinearVariables(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, 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, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:6201
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:93
#define CONSHDLR_PRESOLTIMING
SCIP_RETCODE SCIPsolveLinearProb(int N, SCIP_Real *A, SCIP_Real *b, SCIP_Real *x, SCIP_Bool *success)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:30290
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:37248
SCIP_Bool SCIPlpiIsIterlimExc(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2607
static SCIP_RETCODE generateCut(SCIP *scip, SCIP_EXPRINT *exprint, SCIP_CONS *cons, SCIP_Real **ref, SCIP_SOL *sol, SCIP_Bool newsol, SCIP_SIDETYPE side, SCIP_ROW **row, SCIP_Real minviol, SCIP_Real maxrange, SCIP_Bool expensivecurvchecks, SCIP_Bool assumeconvex)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3162
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46024
static SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
SCIP_RETCODE SCIPcheckCurvatureNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
Definition: scip.c:46134
SCIP_Real * SCIPexprGetLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5766
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.c:4321
int SCIPgetNLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip.c:1912
#define CONSHDLR_DELAYPROP
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:11360
SCIP_Real SCIPexprGetOpReal(SCIP_EXPR *expr)
Definition: expr.c:5711
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7911
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip.c:6081
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12940
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip.c:6105
SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
Definition: lpi_clp.cpp:480
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:135
static SCIP_RETCODE propagateBoundsCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_RESULT *result, int *nchgbds, SCIP_Bool *redundant)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:27417
void SCIPintervalSetRoundingModeUpwards(void)
SCIP_RETCODE SCIPexprgraphCreateNodePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:13407
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:6225
SCIP_CONSHDLRDATA * conshdlrdata
static SCIP_RETCODE computeViolations(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *solviolbounds, SCIP_CONS **maxviolcon)
SCIP_RETCODE SCIPexprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op,...)
Definition: expr.c:13272
NLP local search primal heuristic using sub-SCIPs.
SCIP_RETCODE SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14349
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30709
static SCIP_RETCODE separatePoint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool newsol, SCIP_Real minefficacy, SCIP_Bool inenforcement, SCIP_RESULT *result, SCIP_Real *bestefficacy)
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1138
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:46397
SCIP_RETCODE SCIPcreateConsNonlinear2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPRGRAPHNODE *exprgraphnode, 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, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPgetNLPFracVars(SCIP *scip, SCIP_VAR ***fracvars, SCIP_Real **fracvarssol, SCIP_Real **fracvarsfrac, int *nfracvars, int *npriofracvars)
Definition: scip.c:31468
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16674
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:16146
SCIP_RETCODE SCIPincludeConshdlrNonlinear(SCIP *scip)
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:18427
#define SCIP_Real
Definition: def.h:145
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8130
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:30444
#define CONSHDLR_EAGERFREQ
SCIP_VAR ** SCIPgetLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSFREE(consFreeNonlinear)
static void consdataMoveLinearVar(SCIP_CONSDATA *consdata, int oldpos, int newpos)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1138
#define MIN(x, y)
Definition: memory.c:75
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:6539
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_RETCODE SCIPcreateConsNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *nonlincoefs, 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, SCIP_Bool stickingatnode)
static SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8070
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12900
#define SCIP_INVALID
Definition: def.h:165
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8060
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:30892
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5907
void SCIPexprgraphPrintNode(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: expr.c:14605
static SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip.c:30866
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:38011
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:264
static SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
#define SCIPisFinite(x)
Definition: pub_misc.h:1607
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16720
SCIP_RETCODE SCIPexprgraphSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange, SCIP_Bool *domainerror)
Definition: expr.c:15885
#define CONSHDLR_MAXPREROUNDS
static SCIP_DECL_CONSPRINT(consPrintNonlinear)
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
static SCIP_DECL_CONSINIT(consInitNonlinear)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:46098
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46011
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
SCIP_RETCODE SCIPcomputeHyperplaneThreePoints(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_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17235
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:21976
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16697
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2423
SCIP_Bool SCIPconsIsMarkedPropagate(SCIP_CONS *cons)
Definition: cons.c:8090
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12997
SCIP_Real * coefs
SCIP_Real SCIPgetUpperbound(SCIP *scip)
Definition: scip.c:42699
SCIP_RETCODE SCIPexprintFree(SCIP_EXPRINT **exprint)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:89
static SCIP_RETCODE addIntervalGradientEstimator(SCIP *scip, SCIP_EXPRINT *exprint, SCIP_CONS *cons, int exprtreeidx, SCIP_Real *x, SCIP_Bool newx, SCIP_Bool overestimate, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46232
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSACTIVE((*consactive)))
Definition: scip.c:6355
#define CONSHDLR_DESC
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_VAR **quadvars, int nquadelems, SCIP_QUADELEM *quadelems, SCIP_EXPRTREE *expression, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip.c:31923
SCIP_EXPRGRAPHNODE * SCIPgetExprgraphNodeNonlinear(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSLOCK(consLockNonlinear)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
Definition: scip.c:46183
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14873
SCIP_EVENTHDLRDATA * SCIPeventhdlrGetData(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:288
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
static SCIP_DECL_CONSPRESOL(consPresolNonlinear)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:6153
#define SCIPABORT()
Definition: def.h:288
static SCIP_DECL_CONSPARSE(consParseNonlinear)
SCIP_Real SCIPexprGetLinearConstant(SCIP_EXPR *expr)
Definition: expr.c:5779
SCIP_RETCODE SCIPcreateConsBasicNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *nonlincoefs, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
Definition: scip.c:46195
SCIP_EXPRCURV SCIPexprcurvAdd(SCIP_EXPRCURV curv1, SCIP_EXPRCURV curv2)
Definition: expr.c:205
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16746
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:38182
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_Real lhs, SCIP_Real rhs, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *nonlincoefs, SCIP_Bool capturevars)
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1223
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15686
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.c:4293
SCIP_Bool SCIPisRelLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46722
void SCIPintervalSetRoundingModeDownwards(void)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:46171
SCIP_RETCODE SCIPevalExprtreeLocalBounds(SCIP *scip, SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *val)
Definition: scip.c:32963
int SCIPexprgraphGetNodeDepth(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12930
static SCIP_DECL_CONSCOPY(consCopyNonlinear)
SCIP_EXPRCURV SCIPexprcurvNegate(SCIP_EXPRCURV curvature)
Definition: expr.c:214
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPexprtreeEval(SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
Definition: expr.c:8670
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.c:4211
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16842
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:21995
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:134
void SCIPaddRowprepConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
static SCIP_RETCODE replaceViolatedByLinearConstraints(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *addedcons, SCIP_Bool *reduceddom, SCIP_Bool *infeasible)
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5966
static SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
void SCIPexprgraphEnableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14468
enum SCIP_SideType SCIP_SIDETYPE
Definition: type_lp.h:58