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