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