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