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 */
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 };
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 */
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 };
128 
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))
177 
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 #if 0
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  /* if node still exists, then because it is captured by some constraint (it should not have parents anymore)
2097  * thus, look into the given constraints and replace their exprgraphnode by replacement
2098  * @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
2099  */
2100  assert(*node == NULL || SCIPexprgraphGetNodeNParents(*node) == 0);
2101  for( c = 0; c < nconss; ++c )
2102  {
2103  assert(conss[c] != NULL); /*lint !e613*/
2104 
2105  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
2106  assert(consdata != NULL);
2107 
2108  if( consdata->exprgraphnode == *node )
2109  {
2110  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &consdata->exprgraphnode) );
2111  consdata->exprgraphnode = replacement;
2112  SCIPexprgraphCaptureNode(replacement);
2113 
2114  /* since we change the node, also the constraint changes, so ensure that it is presolved again */
2115  consdata->ispresolved = FALSE;
2116  }
2117  }
2118  *node = NULL;
2119 
2120  return SCIP_OKAY;
2121 }
2122 
2123 /** creates a new auxiliary variable and a new auxiliary nonlinear constraint connecting the var and a given node
2124  * node is replaced by new new auxiliary variables node in all parents of node in expression graph and in all constraints that use node
2125  */
2126 static
2128  SCIP* scip, /**< SCIP data structure */
2129  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
2130  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
2131  SCIP_CONS** conss, /**< constraints where to update exprgraphnode */
2132  int nconss, /**< number of constraints */
2133  int* naddcons, /**< counter to increase when constraint is added */
2134  SCIP_Bool donotmultaggr /**< whether to mark auxiliary variable as not to multiaggregate */
2135  )
2136 {
2137  char name[SCIP_MAXSTRLEN];
2138  SCIP_VAR* auxvar;
2139  SCIP_CONS* auxcons;
2140  SCIP_EXPRGRAPHNODE* auxvarnode;
2141  SCIP_INTERVAL bounds;
2142  SCIP_Real minusone;
2143  SCIP_Bool cutoff;
2144 
2145  assert(scip != NULL);
2146  assert(exprgraph != NULL);
2147  assert(node != NULL);
2148  assert(naddcons != NULL);
2149  assert(SCIPexprgraphGetNodeDepth(node) >= 1); /* do not turn vars or consts into new vars */
2150 
2151  bounds = SCIPexprgraphGetNodeBounds(node);
2152  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2153 
2154  SCIPdebugMessage("add auxiliary variable and constraint %s for node %p(%d,%d)\n", name, (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
2155 
2156  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, SCIPintervalGetInf(bounds), SCIPintervalGetSup(bounds), 0.0,
2158  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2159  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, &auxvarnode) );
2160 #ifdef SCIP_DEBUG_SOLUTION
2161  if( SCIPdebugIsMainscip(scip) )
2162  {
2163  /* store debug sol value of node as value for auxvar in debug solution and as value for auxvarnode */
2165  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(node)) );
2166  }
2167 #endif
2168 
2169  if( donotmultaggr )
2170  {
2171  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, auxvar) );
2172  }
2173 
2174  /* set also bounds of auxvarnode to bounds, so it is available for new parent nodes (currently node->parents)
2175  * when updating their curvature information; avoid having to run domain propagation through exprgraph
2176  */
2177  SCIPexprgraphTightenNodeBounds(exprgraph, auxvarnode, bounds, BOUNDTIGHTENING_MINSTRENGTH, &cutoff);
2178  assert(!cutoff); /* we tightenend bounds from [-inf,+inf] to bounds, this should not be infeasible */
2179 
2180  /* add new constraint auxvar == node */
2181  minusone = -1.0;
2182  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 1, &auxvar, &minusone, node, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
2183  FALSE, FALSE, FALSE, FALSE, FALSE) );
2184  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2185 
2186  /* move parents of node in expression graph to auxvarnode
2187  * replace node by auxvarnode in constraints that use node */
2188  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxvarnode, conss, nconss) );
2189 
2190  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2191  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2192 
2193  ++*naddcons;
2194 
2195  return SCIP_OKAY;
2196 }
2197 
2198 /** ensures that all children of a node have at least a given curvature by adding auxiliary variables */
2199 static
2201  SCIP* scip, /**< SCIP data structure */
2202  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
2203  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
2204  SCIP_EXPRCURV mincurv, /**< minimal desired curvature */
2205  SCIP_CONS** conss, /**< constraints to check whether they use one of the replaced nodes */
2206  int nconss, /**< number of constraints to check */
2207  int* naddcons /**< counter to increase when constraint is added */
2208  )
2209 {
2210  SCIP_EXPRGRAPHNODE* child;
2211  SCIP_Bool needupdate;
2212 
2213  int i;
2214  assert(scip != NULL);
2215  assert(exprgraph != NULL);
2216  assert(node != NULL);
2217  assert(naddcons != NULL);
2218  assert(SCIPexprgraphGetNodeDepth(node) >= 1); /* do not turn vars or consts into new vars */
2219  assert(mincurv != SCIP_EXPRCURV_UNKNOWN); /* this is trivial and makes no sense */
2220 
2221  needupdate = FALSE; /* whether we need to update curvature of node */
2222 
2223  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
2224  {
2225  child = SCIPexprgraphGetNodeChildren(node)[i];
2226  assert(child != NULL);
2227 
2228  if( (SCIPexprgraphGetNodeCurvature(child) & mincurv) != mincurv )
2229  {
2230  SCIPdebugMessage("add auxiliary variable for child %p(%d,%d) with curvature %s\n",
2232 
2233  SCIP_CALL( reformNode2Var(scip, exprgraph, child, conss, nconss, naddcons, FALSE) );
2234  needupdate = TRUE;
2235 
2236  /* i'th child of node should now be a variable */
2237  assert(SCIPexprgraphGetNodeChildren(node)[i] != child);
2239  }
2240 
2241  assert(SCIPexprgraphGetNodeCurvature(SCIPexprgraphGetNodeChildren(node)[i]) & mincurv);
2242  }
2243 
2244  if( needupdate )
2245  {
2248  }
2249 
2250  return SCIP_OKAY;
2251 }
2252 
2253 /** reformulates a monomial by adding auxiliary variables and constraints for bilinear terms */
2254 static
2256  SCIP* scip, /**< SCIP data structure */
2257  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
2258  int nfactors, /**< number of factors */
2259  SCIP_EXPRGRAPHNODE** factors, /**< factors */
2260  SCIP_Real* exponents, /**< exponents, or NULL if all 1.0 */
2261  SCIP_EXPRGRAPHNODE** resultnode, /**< buffer to store node which represents the reformulated monomial */
2262  SCIP_Bool createauxcons, /**< whether to create auxiliary var/cons */
2263  int* naddcons /**< buffer to increase by number of added cons */
2264  )
2265 {
2266  char name[SCIP_MAXSTRLEN];
2267  SCIP_VAR* auxvar;
2268  SCIP_CONS* auxcons;
2269  SCIP_Real minusone;
2270 
2271  assert(scip != NULL);
2272  assert(exprgraph != NULL);
2273  assert(nfactors > 0);
2274  assert(factors != NULL);
2275  assert(resultnode != NULL);
2276  assert(naddcons != NULL);
2277 
2278  /* factors are just one node */
2279  if( nfactors == 1 && (exponents == NULL || exponents[0] == 1.0) )
2280  {
2281  *resultnode = factors[0];
2282  return SCIP_OKAY;
2283  }
2284 
2285  /* only one factor, but with exponent < 0.0 and factor has mixed sign, e.g., x^(-3)
2286  * reformulate as auxvar * factor^(-exponent) = 1 and return the node for auxvar in resultnode
2287  */
2288  if( nfactors == 1 && exponents[0] < 0.0 && SCIPexprgraphGetNodeBounds(factors[0]).inf < 0.0 && SCIPexprgraphGetNodeBounds(factors[0]).sup > 0.0 ) /*lint !e613*/
2289  {
2290  SCIP_EXPRGRAPHNODE* auxnode;
2291  SCIP_EXPRGRAPHNODE* reformfactors[2];
2292  SCIP_Real reformexp[2];
2293 
2294  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2295  SCIPdebugMessage("add auxiliary variable and constraint %s\n", name);
2296 
2297  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2299  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2300  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, resultnode) );
2301 
2302 #ifdef SCIP_DEBUG_SOLUTION
2303  /* store debug sol value of node as value for auxvar in debug solution and as value for resultnode */
2304  if( SCIPdebugIsMainscip(scip) )
2305  {
2306  SCIP_Real debugval;
2307  debugval = pow(SCIPexprgraphGetNodeVal(factors[0]), exponents[0]);
2308  SCIPexprgraphSetVarNodeValue(*resultnode, debugval);
2309  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
2310  }
2311 #endif
2312 
2313  /* increase naddcons before next call to reformMonomial, to avoid duplicate variable names, which is bad for debugging */
2314  ++*naddcons;
2315 
2316  /* add reformulation for resultnode(=auxvar) * factor^(-exponent) = 1.0
2317  * if exponent != -1.0, then factor^(-exponent) should be moved into extra variable
2318  * finally one should get an EXPR_MUL node */
2319  reformfactors[0] = *resultnode;
2320  reformfactors[1] = factors[0];
2321  reformexp[0] = 1.0;
2322  reformexp[1] = -exponents[0]; /*lint !e613*/
2323  SCIP_CALL( reformMonomial(scip, exprgraph, 2, reformfactors, reformexp, &auxnode, FALSE, naddcons) );
2324 
2325  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 0, NULL, NULL, auxnode, 1.0, 1.0,
2326  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
2327  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2328 
2329  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2330  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2331 
2332  return SCIP_OKAY;
2333  }
2334 
2335  /* only one factor, but with exponent != 1.0 */
2336  if( nfactors == 1 )
2337  {
2338  /* create some power expression node, if not existing already */
2339  SCIP_EXPRGRAPHNODE* expnode;
2340  SCIP_EXPRGRAPHNODE* parent;
2341  int p;
2342 
2343  assert(exponents != NULL);
2344 
2345  /* check if there is already a node for factors[0]^exponents[0] */
2346  expnode = NULL;
2347  for( p = 0; p < SCIPexprgraphGetNodeNParents(factors[0]); ++p)
2348  {
2349  parent = SCIPexprgraphGetNodeParents(factors[0])[p];
2350  if( SCIPisIntegral(scip, exponents[0]) &&
2352  SCIPexprgraphGetNodeIntPowerExponent(parent) == (int)SCIPround(scip, exponents[0]) )
2353  {
2354  expnode = parent;
2355  break;
2356  }
2358  SCIPisEQ(scip, SCIPexprgraphGetNodeRealPowerExponent(parent), exponents[0]) )
2359  {
2360  expnode = parent;
2361  }
2362  }
2363  if( expnode == NULL )
2364  {
2365  if( SCIPisIntegral(scip, exponents[0]) )
2366  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &expnode, SCIP_EXPR_INTPOWER, (int)SCIPround(scip, exponents[0])) );
2367  else
2368  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &expnode, SCIP_EXPR_REALPOWER, exponents[0]) );
2369 
2370  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, expnode, -1, 1, &factors[0]) );
2373  }
2374 
2375  if( createauxcons )
2376  {
2377  /* @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) */
2378  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2379  SCIPdebugMessage("add auxiliary variable and constraint %s\n", name);
2380 
2381  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2383  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2384  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, resultnode) );
2385 
2386 #ifdef SCIP_DEBUG_SOLUTION
2387  if( SCIPdebugIsMainscip(scip) )
2388  {
2390  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(expnode)) );
2391  }
2392 #endif
2393 
2394  /* add new constraint resultnode(=auxvar) = expnode */
2395  minusone = -1.0;
2396  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 1, &auxvar, &minusone, expnode, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
2397  FALSE, FALSE, FALSE, FALSE, FALSE) );
2398  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2399 
2400  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2401  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2402 
2403  ++*naddcons;
2404  }
2405  else
2406  {
2407  *resultnode = expnode;
2408  }
2409 
2410  return SCIP_OKAY;
2411  }
2412 
2413  if( nfactors == 2 && exponents != NULL && exponents[0] != 1.0 && exponents[0] == exponents[1] ) /*lint !e777*/
2414  {
2415  /* factor0^exponent * factor1^exponent with exponent != 1.0, reform as (factor0*factor1)^exponent */
2416  SCIP_EXPRGRAPHNODE* productnode;
2417 
2418  /* create node for factor0*factor1 */
2419  SCIP_CALL( reformMonomial(scip, exprgraph, 2, factors, NULL, &productnode, TRUE, naddcons) );
2420 
2421  /* create node for productnode^exponents[0] by just calling this method again */
2422  SCIP_CALL( reformMonomial(scip, exprgraph, 1, &productnode, &exponents[0], resultnode, createauxcons, naddcons) );
2423 
2424  return SCIP_OKAY;
2425  }
2426 
2427  if( nfactors == 2 && exponents != NULL && exponents[0] == -exponents[1] ) /*lint !e777*/
2428  {
2429  /* factor0^exponent * factor1^(-exponent), reform as (factor0/factor1)^exponent or (factor1/factor0)^(-exponent) */
2430  SCIP_EXPRGRAPHNODE* auxvarnode;
2431  SCIP_EXPRGRAPHNODE* auxconsnode;
2432  SCIP_EXPRGRAPHNODE* leftright[2];
2433  SCIP_Real absexp;
2434 
2435  /* create variable and constraint for factor0 = auxvar * factor1 (if exponent > 0) or factor1 = auxvar * factor0 (if exponent < 0) */
2436 
2437  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2438  SCIPdebugMessage("add auxiliary variable and constraint %s\n", name);
2439 
2440  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2442  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2443  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, &auxvarnode) );
2444 
2445 #ifdef SCIP_DEBUG_SOLUTION
2446  /* store debug sol value of node as value for auxvar in debug solution and as value for resultnode */
2447  if( SCIPdebugIsMainscip(scip) )
2448  {
2449  SCIP_Real debugval;
2450  if( exponents[0] > 0.0 )
2451  debugval = SCIPexprgraphGetNodeVal(factors[0]) / SCIPexprgraphGetNodeVal(factors[1]);
2452  else
2453  debugval = SCIPexprgraphGetNodeVal(factors[1]) / SCIPexprgraphGetNodeVal(factors[0]);
2454  SCIPexprgraphSetVarNodeValue(auxvarnode, debugval);
2455  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
2456  }
2457 #endif
2458 
2459  /* add new constraint resultnode(= auxvar) * factor1 - factor0 == 0 (exponent > 0) or auxvar * factor0 - factor1 == 0 (exponent < 0) */
2460  leftright[0] = auxvarnode;
2461  leftright[1] = exponents[0] > 0.0 ? factors[1] : factors[0];
2462 
2464  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, auxconsnode, -1, 2, leftright) );
2465 
2466  leftright[0] = auxconsnode;
2467  leftright[1] = exponents[0] > 0.0 ? factors[0] : factors[1];
2468 
2470  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, auxconsnode, -1, 2, leftright) );
2471 
2472  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 0, NULL, NULL, auxconsnode, 0.0, 0.0,
2473  TRUE, TRUE, TRUE, TRUE, TRUE,
2474  FALSE, FALSE, FALSE, FALSE, FALSE) );
2475  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2476 
2477  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2478  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2479 
2480  ++*naddcons;
2481 
2482  /* create node for auxvarnode^abs(exponents[0]) by just calling this method again */
2483  absexp = fabs(exponents[0]);
2484  SCIP_CALL( reformMonomial(scip, exprgraph, 1, &auxvarnode, &absexp, resultnode, createauxcons, naddcons) );
2485 
2486  return SCIP_OKAY;
2487  }
2488 
2489  /* @todo if nfactors > 2, assemble groups of factors with same exponent and replace these by a single variable first */
2490 
2491  {
2492  /* at least two factors */
2493  /* create auxvar for left half (recursively) and auxvar for right half (recursively) and maybe new auxvar for product */
2494  /* @todo it may be enough to replace single factors in a monomial to get it convex or concave, see Westerlund et.al. */
2495 
2496  SCIP_EXPRGRAPHNODE* productnode;
2497  SCIP_EXPRGRAPHNODE* leftright[2]; /* {left, right} */
2498  SCIP_EXPRGRAPHNODE* parent;
2499  int half;
2500  int p;
2501 
2502  half = nfactors / 2;
2503  assert(half > 0);
2504  assert(half < nfactors);
2505 
2506  SCIP_CALL( reformMonomial(scip, exprgraph, half, factors, exponents, &leftright[0], TRUE, naddcons) );
2507  SCIP_CALL( reformMonomial(scip, exprgraph, nfactors-half, &factors[half], exponents != NULL ? &exponents[half] : NULL, &leftright[1], TRUE, naddcons) ); /*lint !e826*/
2508 
2509  /* check if there is already a node for left * right */
2510  productnode = NULL;
2511  for( p = 0; p < SCIPexprgraphGetNodeNParents(leftright[0]); ++p)
2512  {
2513  parent = SCIPexprgraphGetNodeParents(factors[0])[p];
2515  continue;
2516 
2517  assert(SCIPexprgraphGetNodeNChildren(parent) == 2);
2518  if( (SCIPexprgraphGetNodeChildren(parent)[0] == leftright[0] && SCIPexprgraphGetNodeChildren(parent)[1] == leftright[1]) ||
2519  ( SCIPexprgraphGetNodeChildren(parent)[0] == leftright[1] && SCIPexprgraphGetNodeChildren(parent)[1] == leftright[0]) )
2520  {
2521  productnode = parent;
2522  break;
2523  }
2524  }
2525  if( productnode == NULL )
2526  {
2527  /* create node for left * right */
2528  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &productnode, SCIP_EXPR_MUL, NULL) );
2529  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, productnode, -1, 2, leftright) );
2531  assert(!SCIPintervalIsEmpty(SCIPexprgraphGetNodeBounds(productnode)));
2532  }
2533 
2534  if( createauxcons )
2535  {
2536  /* @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) */
2537  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2538  SCIPdebugMessage("add auxiliary variable and constraint %s\n", name);
2539 
2540  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2541  SCIP_VARTYPE_CONTINUOUS, TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
2542  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2543  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, resultnode) );
2544 
2545 #ifdef SCIP_DEBUG_SOLUTION
2546  if( SCIPdebugIsMainscip(scip) )
2547  {
2548  SCIPexprgraphSetVarNodeValue(*resultnode, SCIPexprgraphGetNodeVal(productnode));
2549  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(productnode)) );
2550  }
2551 #endif
2552 
2553  /* add new constraint resultnode(= auxvar) == left * right */
2554  minusone = -1.0;
2555  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 1, &auxvar, &minusone, productnode, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
2556  FALSE, FALSE, FALSE, FALSE, FALSE) );
2557  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2558 
2559  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2560  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2561 
2562  ++*naddcons;
2563  }
2564  else
2565  {
2566  *resultnode = productnode;
2567  }
2568  }
2569 
2570  return SCIP_OKAY;
2571 }
2572 
2573 /** reformulates expression graph into a form so that for each node under- and overestimators could be computed
2574  * similar to factorable reformulation in other global solvers, but sometimes does not split up complex operands (like quadratic)
2575  */
2576 static
2578  SCIP* scip, /**< SCIP data structure */
2579  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2580  SCIP_CONS** conss, /**< constraints */
2581  int nconss, /**< number of constraints */
2582  int* naddcons /**< buffer to increase by the number of added constraints */
2583  )
2584 {
2585  SCIP_CONSHDLRDATA* conshdlrdata;
2586  SCIP_CONSDATA* consdata;
2587  SCIP_EXPRGRAPH* exprgraph;
2588  SCIP_EXPRGRAPHNODE* node;
2589  SCIP_EXPRGRAPHNODE** children;
2590  SCIP_EXPRGRAPHNODE* reformnode;
2591  SCIP_Bool havenonlinparent;
2592  SCIP_Bool domainerror;
2593  int nchildren;
2594  int c;
2595  int d;
2596  int i;
2597  int u;
2598 #ifndef NDEBUG
2599  int j;
2600 #endif
2601 
2602  assert(scip != NULL);
2603  assert(conshdlr != NULL);
2604  assert(conss != NULL || nconss == 0);
2605  assert(naddcons != NULL);
2606  assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING);
2607  assert(!SCIPinProbing(scip));
2608 
2609  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2610  assert(conshdlrdata != NULL);
2611 
2612  if( conshdlrdata->isreformulated )
2613  {
2614  SCIPdebugMessage("skip reformulation, already done\n");
2615  return SCIP_OKAY;
2616  }
2617 
2618  exprgraph = conshdlrdata->exprgraph;
2619 
2620  /* make sure current variable bounds are variable nodes of exprgraph */
2621  SCIP_CALL( SCIPexprgraphPropagateVarBounds(exprgraph, INTERVALINFTY, FALSE, &domainerror) );
2622  assert(!domainerror); /* should have been found by domain propagation */
2623 
2624  /* set debug solution in expression graph and evaluate nodes, so we can compute debug solution values for auxiliary variables */
2625 #ifdef SCIP_DEBUG_SOLUTION
2626  if( SCIPdebugIsMainscip(scip) )
2627  {
2628  SCIP_Real* varvals;
2629 
2630  SCIP_CALL( SCIPallocBufferArray(scip, &varvals, SCIPexprgraphGetNVars(exprgraph)) );
2631 
2632  for( i = 0; i < SCIPexprgraphGetNVars(exprgraph); ++i )
2633  SCIP_CALL( SCIPdebugGetSolVal(scip, (SCIP_VAR*)SCIPexprgraphGetVars(exprgraph)[i], &varvals[i]) );
2634 
2635  SCIP_CALL( SCIPexprgraphEval(exprgraph, varvals) );
2636 
2637  SCIPfreeBufferArray(scip, &varvals);
2638  }
2639 #endif
2640 
2641  for( d = 1; d < SCIPexprgraphGetDepth(exprgraph); ++d )
2642  {
2643  i = 0;
2644  while( i < SCIPexprgraphGetNNodes(exprgraph)[d] )
2645  {
2646  node = SCIPexprgraphGetNodes(exprgraph)[d][i];
2647  assert(node != NULL);
2648 
2649  /* skip disabled nodes, they should be removed soon */
2650  if( !SCIPexprgraphIsNodeEnabled(node) )
2651  {
2652  ++i;
2653  continue;
2654  }
2655 
2656  /* make sure bounds and curvature of node are uptodate */
2659 
2660  /* try external reformulation methods */
2661  for( u = 0; u < conshdlrdata->nnlconsupgrades; ++u )
2662  {
2663  if( conshdlrdata->nlconsupgrades[u]->nodereform != NULL && conshdlrdata->nlconsupgrades[u]->active )
2664  {
2665  SCIP_CALL( conshdlrdata->nlconsupgrades[u]->nodereform(scip, exprgraph, node, naddcons, &reformnode) );
2666  if( reformnode == NULL )
2667  continue;
2668 
2669  SCIPdebugMessage("external nodereform reformulated node %p(%d,%d), replace by %p\n",
2670  (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node), (void*)reformnode);
2671 
2672  SCIP_CALL( reformReplaceNode(exprgraph, &node, reformnode, conss, nconss) );
2674  assert(!SCIPintervalIsEmpty(SCIPexprgraphGetNodeBounds(reformnode)));
2675 
2676  break;
2677  }
2678  }
2679  /* if node has been reformulated, continue with next node without increasing i */
2680  if( u < conshdlrdata->nnlconsupgrades )
2681  continue;
2682 
2683  /* leave nodes that are known to be convex/concave/linear as they are */
2685  {
2686  SCIPdebugMessage("skip reformulating node %p(%d,%d) = ", (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
2689  ++i;
2690  continue;
2691  }
2692 
2693  /* get flag whether node has a nonlinear parent
2694  * we want to know whether the current node will be at the top of the tree after the next simplification run
2695  * due to the tricky reformulation of polynomials below, this may not be the case yet
2696  */
2697  havenonlinparent = SCIPexprgraphHasNodeNonlinearAncestor(node);
2698 
2699  /* take action */
2701  SCIPdebugMessage("think about reformulating %s node %p(%d,%d) = ", SCIPexpropGetName(SCIPexprgraphGetNodeOperator(node)), (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
2703  SCIPdebugPrintf("\n");
2704 
2705  children = SCIPexprgraphGetNodeChildren(node);
2706  nchildren = SCIPexprgraphGetNodeNChildren(node);
2707  assert(children != NULL || nchildren == 0);
2708 
2709 #ifndef NDEBUG
2710  /* at this place, all children nodes should have a known curvature, except if they only appear only linearly in constraints
2711  * the latter for cases where constraints with unknown curvature are upgraded to other constraint handler that can handle these (quadratic, signpower,...)
2712  */
2713  for( j = 0; j < nchildren; ++j )
2714  {
2715  assert(children[j] != NULL); /*lint !e613*/
2716  if( havenonlinparent ||
2721  assert(SCIPexprgraphGetNodeCurvature(children[j]) != SCIP_EXPRCURV_UNKNOWN); /*lint !e613*/
2722  }
2723 #endif
2724 
2725  switch( SCIPexprgraphGetNodeOperator(node) )
2726  {
2727  case SCIP_EXPR_VARIDX:
2728  case SCIP_EXPR_PARAM:
2729  case SCIP_EXPR_CONST:
2730  SCIPerrorMessage("node with operator %d cannot have unknown curvature\n", SCIPexprgraphGetNodeOperator(node));
2731  SCIPABORT();
2732  break; /*lint !e527*/
2733 
2734  /* linear operands */
2735  case SCIP_EXPR_PLUS:
2736  case SCIP_EXPR_MINUS:
2737  case SCIP_EXPR_SUM:
2738  case SCIP_EXPR_LINEAR:
2739  /* children have conflicting curvature, we can handle such sums in cons_nonlinear
2740  * thus, turn node into variable, if it has nonlinear parents */
2741  if( havenonlinparent )
2742  {
2743  SCIP_CALL( reformNode2Var(scip, exprgraph, node, conss, nconss, naddcons, FALSE) );
2744  assert(node != NULL);
2745  assert(SCIPexprgraphGetNodeNParents(node) == 0); /* node should now be at top of graph */
2746  }
2747  ++i;
2748  break;
2749 
2750  /* quadratic operands */
2751  case SCIP_EXPR_MUL:
2752  case SCIP_EXPR_QUADRATIC:
2753  {
2754  /* ensure all children are linear, so next simplifier run makes sure all children will be variables */
2755  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_LINEAR, conss, nconss, naddcons) );
2757  {
2758  /* if curvature is now known then we are done */
2759  ++i;
2760  break;
2761  }
2762 
2763  /* 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
2764  * 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
2765  * @todo we could also add auxvars for the sibling nodes, e.g., if there is only one
2766  * @todo if sibling nodes are quadratic (or even linear) due to reformulation, then we do not need to reform here... (-> nvs16)
2767  * maybe this step should not be done here at all if havenonlinparent is FALSE? e.g., move into upgrade from quadratic?
2768  */
2769  if( havenonlinparent || SCIPexprgraphHasNodeSibling(node) )
2770  {
2771  SCIP_CALL( reformNode2Var(scip, exprgraph, node, conss, nconss, naddcons, FALSE) );
2772  assert(node != NULL);
2773  assert(SCIPexprgraphGetNodeNParents(node) == 0); /* node should now be at top of graph, so it can be upgraded by cons_quadratic */
2774  break;
2775  }
2776 
2777  ++i;
2778  break;
2779  }
2780 
2781  case SCIP_EXPR_DIV:
2782  {
2783  /* reformulate as bilinear term
2784  * note that in the reformulation, a zero in the denominator forces the nominator to be zero too, but the auxiliary can be arbitrary
2785  */
2786  SCIP_EXPRGRAPHNODE* auxvarnode;
2787  SCIP_EXPRGRAPHNODE* auxnode;
2788  SCIP_EXPRGRAPHNODE* auxchildren[3];
2789  SCIP_Real lincoefs[3];
2790  SCIP_QUADELEM quadelem;
2791  SCIP_VAR* auxvar;
2792  SCIP_CONS* auxcons;
2793  char name[SCIP_MAXSTRLEN];
2794  SCIP_INTERVAL bounds;
2795 
2796  bounds = SCIPexprgraphGetNodeBounds(node);
2797  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2798 
2799  SCIPdebugMessage("add auxiliary variable %s for division in node %p(%d,%d)\n", name, (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
2800 
2801  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, SCIPintervalGetInf(bounds), SCIPintervalGetSup(bounds), 0.0,
2803  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2804  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, &auxvarnode) );
2805 
2806 #ifdef SCIP_DEBUG_SOLUTION
2807  if( SCIPdebugIsMainscip(scip) )
2808  {
2809  SCIP_Real debugval;
2810  debugval = SCIPexprgraphGetNodeVal(children[0]) / SCIPexprgraphGetNodeVal(children[1]);
2811  SCIPexprgraphSetVarNodeValue(auxvarnode, debugval);
2812  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
2813  }
2814 #endif
2815 
2816  /* add new constraint auxvar * child[1] - child[0] == 0 */
2817  auxchildren[0] = children[0]; /*lint !e613*/
2818  auxchildren[1] = children[1]; /*lint !e613*/
2819  auxchildren[2] = auxvarnode;
2820 
2821  lincoefs[0] = -1.0;
2822  lincoefs[1] = 0.0;
2823  lincoefs[2] = 0.0;
2824 
2825  quadelem.idx1 = 1;
2826  quadelem.idx2 = 2;
2827  quadelem.coef = 1.0;
2828 
2829  SCIP_CALL( SCIPexprgraphCreateNodeQuadratic(SCIPblkmem(scip), &auxnode, 3, lincoefs, 1, &quadelem, 0.0) );
2830  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, auxnode, -1, 3, auxchildren) );
2831 
2832  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 0, NULL, NULL, auxnode, 0.0, 0.0,
2833  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
2834  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2835 
2836  /* replace node by auxvarnode in graph and constraints that use it */
2837  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxvarnode, conss, nconss) );
2838 
2839  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2840  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2841 
2842  ++*naddcons;
2843 
2844  /* do not increase i, since node was removed and not necessarily replaced here */
2845  break;
2846  }
2847 
2848  case SCIP_EXPR_MIN:
2849  {
2850  /* make sure that both children are concave, because min of concave functions is concave */
2851  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_CONCAVE, conss, nconss, naddcons) );
2853  ++i;
2854  break;
2855  }
2856 
2857  case SCIP_EXPR_MAX:
2858  {
2859  /* make sure that both children are convex, because max of convex functions is convex */
2860  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_CONVEX, conss, nconss, naddcons) );
2862  ++i;
2863  break;
2864 
2865  }
2866 
2867  case SCIP_EXPR_INTPOWER:
2868  {
2869  assert(nchildren == 1);
2870 
2871  /* for an intpower with mixed sign in the base and negative exponent, we reformulate similar as for EXPR_DIV */
2872  if( SCIPexprgraphGetNodeIntPowerExponent(node) < 0 && SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(children[0])) < 0.0 && SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(children[0])) > 0.0 ) /*lint !e613*/
2873  {
2874  SCIP_EXPRGRAPHNODE* auxvarnode;
2875  SCIP_Real exponent;
2876 
2877  /* if we have something like x^(-3) with mixed sign for x, then add auxvar and reform as auxvar*x^3 = 1 via reformMonomial */
2879  SCIP_CALL( reformMonomial(scip, exprgraph, 1, children, &exponent, &auxvarnode, TRUE, naddcons) );
2880  /* replace node by auxvarnode */
2881  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxvarnode, conss, nconss) );
2882  break;
2883  }
2884 
2885  /* otherwise, we continue as for other univariate operands */
2886  } /*lint -fallthrough*/
2887 
2888  /* univariate operands where the child does not have bounds and curvature from which we can deduce curvature of this node,
2889  * but where we can do more if the child is linear
2890  * thus, turn child into auxiliary variable
2891  */
2892  case SCIP_EXPR_SQUARE:
2893  case SCIP_EXPR_SQRT:
2894  case SCIP_EXPR_EXP:
2895  case SCIP_EXPR_LOG:
2896  case SCIP_EXPR_ABS:
2897  case SCIP_EXPR_REALPOWER:
2898  case SCIP_EXPR_SIGNPOWER:
2899  {
2900  assert(nchildren == 1);
2901 
2902  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_LINEAR, conss, nconss, naddcons) );
2903 
2905  {
2906  /* 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 */
2908  assert(SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(children[0])) < 0.0); /*lint !e613*/
2909  assert(SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(children[0])) > 0.0); /*lint !e613*/
2910  }
2911 
2912  /* update curvature of node */
2915 
2917  {
2918  /* if intpower and signpower with positive exponent and a mixed sign in the child bounds still does not give a curvature,
2919  * 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
2920  * of course, this is only required if the node is still intermediate
2921  *
2922  * an intpower with negative exponent should have been handled above
2923  * for signpower, we assume the exponent is > 1.0
2924  */
2928  if( havenonlinparent )
2929  {
2930  SCIP_CALL( reformNode2Var(scip, exprgraph, node, conss, nconss, naddcons, FALSE) );
2931  assert(node != NULL); /* it should be used by some auxiliary constraint now */
2932  assert(SCIPexprgraphGetNodeNParents(node) == 0); /* node should now be at top of graph (and used by new auxiliary constraint) */
2933  }
2934  }
2935  ++i;
2936 
2937  break;
2938  }
2939 
2940  case SCIP_EXPR_SIN:
2941  case SCIP_EXPR_COS:
2942  case SCIP_EXPR_TAN:
2943  case SCIP_EXPR_SIGN:
2944  /* case SCIP_EXPR_ERF : */
2945  /* case SCIP_EXPR_ERFI : */
2946  {
2947  SCIPerrorMessage("no support for trigonometric or sign operands yet\n");
2948  return SCIP_ERROR;
2949  }
2950 
2951  case SCIP_EXPR_PRODUCT:
2952  {
2953  /* ensure all children are linear */
2954  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_LINEAR, conss, nconss, naddcons) );
2956  {
2957  ++i;
2958  break;
2959  }
2960 
2961  /* if curvature is still unknown (quite likely), then turn into a cascade of bilinear terms
2962  * 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 */
2963  SCIP_CALL( reformMonomial(scip, exprgraph, nchildren, children, NULL, &reformnode, havenonlinparent, naddcons) );
2964 
2965  /* replace node by reformnode in graph and in all constraints that use it */
2966  SCIP_CALL( reformReplaceNode(exprgraph, &node, reformnode, conss, nconss) );
2967 
2968  /* do not increase i, since node was removed and not necessarily replaced here */
2969  break;
2970  }
2971  case SCIP_EXPR_POLYNOMIAL:
2972  {
2973  /* 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
2974  * if polynomial has only a single monomial, then reformulate that one
2975  */
2976  SCIP_EXPRDATA_MONOMIAL** monomials;
2977  SCIP_EXPRDATA_MONOMIAL* monomial;
2978  int nmonomials;
2979  SCIP_Real* exponents;
2980  SCIP_Real coef;
2981  int* childidxs;
2982  int nfactors;
2983  int f;
2984  SCIP_INTERVAL childbounds;
2985  SCIP_EXPRCURV childcurv;
2986  SCIP_Bool modified;
2987 
2988  monomials = SCIPexprgraphGetNodePolynomialMonomials(node);
2989  nmonomials = SCIPexprgraphGetNodePolynomialNMonomials(node);
2990  assert(nmonomials >= 1); /* constant polynomials should have been simplified away */
2991 
2992  if( nmonomials > 1 )
2993  {
2994  SCIP_EXPRGRAPHNODE* sumnode;
2995  SCIP_Real constant;
2996  int nquadelems;
2997  SCIP_QUADELEM* quadelems;
2998  SCIP_Real* lincoefs;
2999  int nmonomialnodes;
3000  SCIP_EXPRGRAPHNODE** childrennew;
3001  SCIP_EXPRGRAPHNODE** monomialnodes;
3002  int m;
3003 
3004  /* @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
3005  * @todo factorizing the polynomial could be beneficial
3006  */
3007 
3008  /* constant part of polynomials, to add to first monomialnode, if any, or quadratic or linear part */
3009  constant = SCIPexprgraphGetNodePolynomialConstant(node);
3010 
3011  /* coefficients from linear monomials */
3012  lincoefs = NULL;
3013 
3014  /* quadratic elements */
3015  nquadelems = 0;
3016  quadelems = NULL;
3017 
3018  /* expression graph nodes representing single higher-degree monomials, and single node with linear and/or quadratic monomials */
3019  nmonomialnodes = 0;
3020  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnodes, nmonomials) );
3021 
3022  /* children of new monomial nodes that are setup */
3023  childrennew = NULL;
3024 
3025  for( m = 0; m < nmonomials; ++m )
3026  {
3027  monomial = monomials[m];
3028  assert(monomial != NULL);
3029 
3030  coef = SCIPexprGetMonomialCoef(monomial);
3031  exponents = SCIPexprGetMonomialExponents(monomial);
3032  childidxs = SCIPexprGetMonomialChildIndices(monomial);
3033  nfactors = SCIPexprGetMonomialNFactors(monomial);
3034  assert(nfactors >= 1); /* constant monomials should have been simplified away */
3035  assert(coef != 0.0); /* zero-monomials should have been simplified away */
3036 
3037  if( nfactors == 1 && exponents[0] == 1.0 )
3038  {
3039  /* linear monomial */
3040  if( lincoefs == NULL )
3041  {
3042  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nchildren) );
3043  BMSclearMemoryArray(lincoefs, nchildren);
3044  }
3045  assert(0 <= childidxs[0] && childidxs[0] < nchildren);
3046  assert(lincoefs[childidxs[0]] == 0.0); /* monomials should have been merged */
3047  lincoefs[childidxs[0]] = coef;
3048  }
3049  else if( nfactors == 1 && exponents[0] == 2.0 )
3050  {
3051  /* square monomial */
3052  if( quadelems == NULL )
3053  {
3054  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nmonomials) );
3055  }
3056  quadelems[nquadelems].idx1 = childidxs[0];
3057  quadelems[nquadelems].idx2 = childidxs[0];
3058  quadelems[nquadelems].coef = coef;
3059  ++nquadelems;
3060  }
3061  else if( nfactors == 2 && exponents[0] == 1.0 && exponents[1] == 1.0 )
3062  {
3063  /* bilinear monomial */
3064  if( quadelems == NULL )
3065  {
3066  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nmonomials) );
3067  }
3068  if( childidxs[0] < childidxs[1] )
3069  {
3070  quadelems[nquadelems].idx1 = childidxs[0];
3071  quadelems[nquadelems].idx2 = childidxs[1];
3072  }
3073  else
3074  {
3075  quadelems[nquadelems].idx1 = childidxs[1];
3076  quadelems[nquadelems].idx2 = childidxs[0];
3077  }
3078  quadelems[nquadelems].coef = coef;
3079  ++nquadelems;
3080  }
3081  else
3082  {
3083  /* general monomial -> pass into separate expression graph node */
3084  SCIP_EXPRDATA_MONOMIAL* monomialnew;
3085 
3086  /* create new node for this monomial, children will be those associated with factors */
3087  SCIP_CALL( SCIPexprCreateMonomial(SCIPblkmem(scip), &monomialnew, coef, nfactors, NULL, exponents) );
3088  SCIP_CALL( SCIPexprgraphCreateNodePolynomial(SCIPblkmem(scip), &monomialnodes[nmonomialnodes], 1, &monomialnew, constant, FALSE) );
3089  constant = 0.0;
3090 
3091  if( childrennew == NULL )
3092  {
3093  SCIP_CALL( SCIPallocBufferArray(scip, &childrennew, nchildren) );
3094  }
3095  assert(nfactors <= nchildren);
3096  for( f = 0; f < nfactors; ++f )
3097  childrennew[f] = children[childidxs[f]]; /*lint !e613*/
3098 
3099  /* add new node to same depth as this node, so we will reformulate it during this run
3100  * no need to refresh bounds/curvature here, since that will be done when we reach this node next */
3101  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, monomialnodes[nmonomialnodes], SCIPexprgraphGetNodeDepth(node), nfactors, childrennew) );
3102 
3103  ++nmonomialnodes;
3104  }
3105  }
3106  /* should have had at least one linear, quadratic, or general monomial */
3107  assert(lincoefs != NULL || nquadelems > 0 || nmonomialnodes > 0);
3108 
3109  if( nquadelems > 0 )
3110  {
3111  /* create and add additional node for quadratic and linear part, simplifier should take care of removing unused children later */
3112  SCIP_CALL( SCIPexprgraphCreateNodeQuadratic(SCIPblkmem(scip), &monomialnodes[nmonomialnodes], nchildren, lincoefs, nquadelems, quadelems, constant) );
3113  constant = 0.0;
3114  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, monomialnodes[nmonomialnodes], SCIPexprgraphGetNodeDepth(node), nchildren, children) );
3115  ++nmonomialnodes;
3116  }
3117  else if( lincoefs != NULL )
3118  {
3119  /* create additional node for linear part, simplifier should take care of removing unused children later */
3120  SCIP_CALL( SCIPexprgraphCreateNodeLinear(SCIPblkmem(scip), &monomialnodes[nmonomialnodes], nchildren, lincoefs, constant) );
3121  constant = 0.0;
3122  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, monomialnodes[nmonomialnodes], SCIPexprgraphGetNodeDepth(node), nchildren, children) );
3123  ++nmonomialnodes;
3124  }
3125  assert(constant == 0.0); /* the constant should have been used somewhere */
3126 
3127  SCIPfreeBufferArrayNull(scip, &lincoefs);
3128  SCIPfreeBufferArrayNull(scip, &quadelems);
3129  SCIPfreeBufferArrayNull(scip, &childrennew);
3130 
3131  assert(nmonomialnodes > 0);
3132  if( nmonomialnodes > 1 )
3133  {
3134  /* add node for sum of monomials to expression graph */
3135  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &sumnode, nmonomialnodes == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM) );
3136  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, sumnode, -1, nmonomialnodes, monomialnodes) );
3137  }
3138  else
3139  {
3140  /* if only one monomial, then because polynomial was linear or quadratic... */
3141  assert(SCIPexprgraphGetNodeOperator(monomialnodes[0]) == SCIP_EXPR_LINEAR || SCIPexprgraphGetNodeOperator(monomialnodes[0]) == SCIP_EXPR_QUADRATIC);
3142  sumnode = monomialnodes[0];
3143  }
3144  SCIPfreeBufferArray(scip, &monomialnodes);
3145 
3146  /* replace node by sumnode, and we are done */
3147  SCIP_CALL( reformReplaceNode(exprgraph, &node, sumnode, conss, nconss) );
3148 
3149  SCIPdebugMessage("splitup polynomial into sum of %d nodes\n", nmonomialnodes);
3150 
3151  break;
3152  }
3153 
3154  /* reformulate a monomial such that it becomes convex or concave, if necessary */
3155 
3156  monomial = monomials[0];
3157  assert(monomial != NULL);
3158 
3159  coef = SCIPexprGetMonomialCoef(monomial);
3160  exponents = SCIPexprGetMonomialExponents(monomial);
3161  childidxs = SCIPexprGetMonomialChildIndices(monomial);
3162  nfactors = SCIPexprGetMonomialNFactors(monomial);
3163  assert(nfactors >= 1); /* constant monomials should have been simplified away */
3164  assert(coef != 0.0); /* zero-monomials should have been simplified away */
3165 
3166  /* check if we make monomial convex or concave by making a child linear */
3167  modified = FALSE;
3168  if( nfactors == 1 )
3169  {
3170  /* ensure that the child of an univariate monomial is linear if its current (bounds,curvature) yields an unknown curvature for the monomial
3171  * and with linear child it had a known curvature (rules out x^a, a negative, x not linear) */
3172  childcurv = SCIPexprgraphGetNodeCurvature(children[childidxs[0]]); /*lint !e613*/
3173  childbounds = SCIPexprgraphGetNodeBounds(children[childidxs[0]]); /*lint !e613*/
3174  assert(SCIPexprcurvPower(childbounds, childcurv, exponents[0]) == SCIP_EXPRCURV_UNKNOWN); /* this is exactly the curvature of the node, which is unknown */
3175 
3176  /* if monomial were convex or concave if child were linear, then make child linear */
3177  if( SCIPexprcurvPower(childbounds, SCIP_EXPRCURV_LINEAR, exponents[0]) != SCIP_EXPRCURV_UNKNOWN )
3178  {
3179  assert(childcurv != SCIP_EXPRCURV_LINEAR);
3180  SCIPdebugMessage("reform child %d (univar. monomial) with curv %s into var\n", childidxs[0], SCIPexprcurvGetName(childcurv));
3181  SCIP_CALL( reformNode2Var(scip, exprgraph, children[childidxs[0]], conss, nconss, naddcons, FALSE) ); /*lint !e613*/
3182  modified = TRUE;
3183  }
3184  }
3185  else
3186  {
3187  /* check if the conditions on the exponents allow for a convex or concave monomial, assuming that the children are linear
3188  * if one of these conditions is fulfilled but a children curvature does not fit, then make these children linear
3189  */
3190  int nnegative;
3191  int npositive;
3192  SCIP_Real sum;
3193  SCIP_Bool expcurvpos;
3194  SCIP_Bool expcurvneg;
3195  SCIP_EXPRCURV desiredcurv;
3196 
3197  nnegative = 0; /* number of negative exponents */
3198  npositive = 0; /* number of positive exponents */
3199  sum = 0.0; /* sum of exponents */
3200  expcurvpos = TRUE; /* whether exp_j * f_j''(x) >= 0 for all factors (assuming f_j >= 0) */
3201  expcurvneg = TRUE; /* whether exp_j * f_j''(x) <= 0 for all factors (assuming f_j >= 0) */
3202 
3203  for( f = 0; f < nfactors; ++f )
3204  {
3205  childcurv = SCIPexprgraphGetNodeCurvature(children[childidxs[f]]); /*lint !e613*/
3206  assert(childcurv != SCIP_EXPRCURV_UNKNOWN);
3207  childbounds = SCIPexprgraphGetNodeBounds(children[childidxs[f]]); /*lint !e613*/
3208  if( childbounds.inf < 0.0 && childbounds.sup > 0.0 )
3209  break;
3210 
3211  if( exponents[f] < 0.0 )
3212  ++nnegative;
3213  else
3214  ++npositive;
3215  sum += exponents[f];
3216 
3217  /* negate curvature if factor is negative */
3218  if( childbounds.inf < 0.0 )
3219  childcurv = SCIPexprcurvNegate(childcurv);
3220 
3221  /* check if exp_j * checkcurv is convex (>= 0) and/or concave */
3222  childcurv = SCIPexprcurvMultiply(exponents[f], childcurv);
3223  if( !(childcurv & SCIP_EXPRCURV_CONVEX) )
3224  expcurvpos = FALSE;
3225  if( !(childcurv & SCIP_EXPRCURV_CONCAVE) )
3226  expcurvneg = FALSE;
3227  }
3228 
3229  /* if some child can be both positive and negative, then nothing we can do here to get the monomial convex or concave
3230  * otherwise (i.e., f == nfactors), look further */
3231  desiredcurv = SCIP_EXPRCURV_UNKNOWN;
3232  if( f == nfactors )
3233  {
3234  /* if all factors are linear, then a product f_j^exp_j with f_j >= 0 is convex if
3235  * - all exponents are negative, or
3236  * - 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
3237  * further, the product is concave if
3238  * - all exponents are positive and the sum of exponents is <= 1.0
3239  *
3240  * if factors are nonlinear, then we require additionally, that for convexity
3241  * - each factor is convex if exp_j >= 0, or concave if exp_j <= 0, i.e., exp_j*f_j'' >= 0
3242  * and for concavity, we require that
3243  * - all factors are concave, i.e., exp_j*f_j'' <= 0
3244  */
3245 
3246  if( nnegative == nfactors || (nnegative == nfactors-1 && SCIPisGE(scip, sum, 1.0)) )
3247  {
3248  /* if exponents are such that we can be convex, but children curvature does not fit, make some children linear */
3249  SCIPdebugMessage("%d-variate monomial is convex (modulo sign), child curv fits = %u\n", nfactors, expcurvpos);
3250  /* since current node curvature is set to unknown, there must be such a child, since otherwise the node curvature had to be convex */
3251  assert(!expcurvpos);
3252  desiredcurv = SCIP_EXPRCURV_CONVEX;
3253  }
3254  else if( npositive == nfactors && SCIPisLE(scip, sum, 1.0) )
3255  {
3256  /* if exponents are such that we can be concave, but children curvature does not fit, make some children linear */
3257  SCIPdebugMessage("%d-variate monomial is concave (modulo sign), child curv fits = %u\n", nfactors, expcurvneg);
3258  /* since current node curvature is set to unknown, there must be such a child, since otherwise the node curvature had to be concave */
3259  assert(!expcurvneg);
3260  desiredcurv = SCIP_EXPRCURV_CONCAVE;
3261  }
3262  else
3263  {
3264  /* exponents are such that monomial is neither convex nor concave even if children were linear
3265  * thus, reformulate monomial below
3266  */
3267  }
3268  }
3269 
3270  if( desiredcurv != SCIP_EXPRCURV_UNKNOWN )
3271  {
3272  for( f = 0; f < nfactors; ++f )
3273  {
3274  childcurv = SCIPexprgraphGetNodeCurvature(children[childidxs[f]]); /*lint !e613*/
3275  assert(childcurv != SCIP_EXPRCURV_UNKNOWN);
3276  childbounds = SCIPexprgraphGetNodeBounds(children[childidxs[f]]); /*lint !e613*/
3277  assert(childbounds.inf >= 0.0 || childbounds.sup <= 0.0);
3278 
3279  /* negate curvature if factor is negative */
3280  if( childbounds.inf < 0.0 )
3281  childcurv = SCIPexprcurvNegate(childcurv);
3282 
3283  /* check if exp_j * checkcurv is convex (>= 0) and/or concave */
3284  childcurv = SCIPexprcurvMultiply(SCIPexprGetMonomialExponents(monomial)[f], childcurv);
3285  if( (desiredcurv == SCIP_EXPRCURV_CONVEX && !(childcurv & SCIP_EXPRCURV_CONVEX )) ||
3286  (desiredcurv == SCIP_EXPRCURV_CONCAVE && !(childcurv & SCIP_EXPRCURV_CONCAVE)) )
3287  {
3288  SCIPdebugMessage("reform child %d (factor %d) with curv %s into var\n",
3289  childidxs[f], f, SCIPexprcurvGetName(SCIPexprgraphGetNodeCurvature(children[childidxs[f]]))); /*lint !e613*/
3290  SCIP_CALL( reformNode2Var(scip, exprgraph, children[childidxs[f]], conss, nconss, naddcons, FALSE) ); /*lint !e613*/
3291  modified = TRUE;
3292  }
3293  }
3294  }
3295  }
3296 
3297  if( modified )
3298  {
3299  /* refresh curvature information in node, since we changed children, it should be convex or concave now */
3303 
3304  /* we are done and can proceed with the next node */
3305  ++i;
3306  break;
3307  }
3308 
3309  /* monomial can only have unknown curvature here, if it has several factors
3310  * or is of form x^a with x both negative and positive and a an odd or negative integer (-> INTPOWER expression)
3311  */
3312  assert(nfactors > 1 ||
3313  (SCIPexprgraphGetNodeBounds(children[childidxs[0]]).inf < 0.0 && SCIPexprgraphGetNodeBounds(children[childidxs[0]]).sup > 0.0 &&
3314  SCIPisIntegral(scip, exponents[0]) && (exponents[0] < 0.0 || ((int)SCIPround(scip, exponents[0]) % 2 != 0)))
3315  ); /*lint !e613*/
3316 
3317  /* bilinear monomials should not come up here, since simplifier should have turned them into quadratic expression nodes */
3318  assert(!(nfactors == 2 && exponents[0] == 1.0 && exponents[1] == 1.0));
3319 
3320  /* 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)
3321  * thus, in the case x^a with a an odd positive integer we assume that cons_signpower will do something */
3322  if( nfactors > 1 || havenonlinparent || exponents[0] < 0.0 )
3323  {
3324  SCIP_EXPRGRAPHNODE* auxnode;
3325  SCIP_EXPRGRAPHNODE** factors;
3326 
3327  if( nfactors > 1 )
3328  {
3329  SCIP_CALL( SCIPallocBufferArray(scip, &factors, nfactors) );
3330  for( f = 0; f < nfactors; ++f )
3331  factors[f] = children[childidxs[f]]; /*lint !e613*/
3332  }
3333  else
3334  factors = &children[childidxs[0]]; /*lint !e613*/
3335 
3336  SCIPdebugMessage("reform monomial node, create auxvar = %u\n", havenonlinparent);
3337  /* get new auxnode for monomial
3338  * 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
3339  * 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
3340  */
3341  SCIP_CALL( reformMonomial(scip, exprgraph, nfactors, factors, exponents, &auxnode, havenonlinparent, naddcons) );
3342 
3343  if( nfactors > 1 )
3344  {
3345  SCIPfreeBufferArray(scip, &factors);
3346  }
3347 
3348  /* create node for monomialcoef * auxnode + monomialconstant, if not identical to auxnode */
3349  if( SCIPexprgraphGetNodePolynomialConstant(node) != 0.0 || coef != 1.0 )
3350  {
3351  SCIP_EXPRGRAPHNODE* replnode;
3352 
3354  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, replnode, -1, 1, &auxnode) );
3355  auxnode = replnode;
3356  }
3357 
3358  /* replace node by auxnode and refresh its curvature */
3359  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxnode, conss, nconss) );
3362 
3363  break;
3364  }
3365  else
3366  {
3367  SCIPdebugMessage("no reformulation of monomial node, assume signpower will take care of it\n");
3368  }
3369 
3370  ++i;
3371  break;
3372  }
3373 
3374  case SCIP_EXPR_LAST:
3375  default:
3376  SCIPerrorMessage("got expression with invalid operand\n");
3377  }
3378  }
3379  }
3380 
3381  /* 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
3382  * @todo this does not work yet for sums of functions, e.g., polynomials with more than one monomial
3383  */
3384  for( c = 0; c < nconss; ++c )
3385  {
3386  SCIP_EXPRGRAPHNODE* multivarnode;
3387  SCIP_EXPRCURV curv;
3388 
3389  assert(conss[c] != NULL); /*lint !e613*/
3390 
3391  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3392  assert(consdata != NULL);
3393 
3394  if( consdata->exprgraphnode == NULL )
3395  continue;
3396 
3397  /* after reformulation, force a round of backpropagation in expression graph for all constraints,
3398  * since new variables (nlreform*) may now be used in existing constraints and we want domain restrictions
3399  * of operators propagated for these variables
3400  */
3401  consdata->forcebackprop = TRUE;
3402 
3403  curv = SCIPexprgraphGetNodeCurvature(consdata->exprgraphnode);
3404 
3405  /* if nothing concave, then continue */
3406  if( (SCIPisInfinity(scip, consdata->rhs) || curv != SCIP_EXPRCURV_CONCAVE) &&
3407  ( SCIPisInfinity(scip, -consdata->lhs) || curv != SCIP_EXPRCURV_CONVEX) )
3408  continue;
3409 
3410  /* search for a descendant of node that has > 1 children
3411  * after simiplifier run, there should be no constant expressions left */
3412  multivarnode = consdata->exprgraphnode;
3413  while( SCIPexprgraphGetNodeNChildren(multivarnode) == 1 )
3414  multivarnode = SCIPexprgraphGetNodeChildren(multivarnode)[0];
3415 
3416  /* if node expression is obviously univariate, then continue */
3417  if( SCIPexprgraphGetNodeNChildren(multivarnode) == 0 )
3418  {
3420  continue;
3421  }
3422 
3423  /* if node itself is multivariate, then continue */
3424  if( multivarnode == consdata->exprgraphnode )
3425  continue;
3426 
3427  /* if multivarnode is a linear expression, then replace this by an auxiliary variable/node
3428  * mark auxiliary variable as not to multiaggregate, so SCIP cannot undo what we just did */
3430  {
3431  SCIPdebugMessage("replace linear multivariate node %p(%d,%d) in expression of cons <%s> by auxvar\n",
3432  (void*)multivarnode, SCIPexprgraphGetNodeDepth(multivarnode), SCIPexprgraphGetNodePosition(multivarnode), SCIPconsGetName(conss[c])); /*lint !e613*/
3433  SCIPdebugPrintCons(scip, conss[c], NULL); /*lint !e613*/
3434  SCIP_CALL( reformNode2Var(scip, exprgraph, multivarnode, conss, nconss, naddcons, TRUE) );
3435  }
3436  }
3437 
3438  conshdlrdata->isreformulated = TRUE;
3439 
3440  return SCIP_OKAY;
3441 }
3442 
3443 /** gets maximal absolute element of gradient of nonlinear function */
3444 static
3446  SCIP* scip, /**< SCIP data structure */
3447  SCIP_EXPRINT* exprint, /**< expressions interpreter */
3448  SCIP_CONS* cons, /**< constraint */
3449  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
3450  SCIP_Bool newsol, /**< have the expression trees been evaluated at sol before? */
3451  SCIP_Real* maxelem /**< buffer to store maximal element */
3452  )
3453 {
3454  SCIP_CONSDATA* consdata;
3455  int i;
3456  int j;
3457 
3458  assert(scip != NULL);
3459  assert(cons != NULL);
3460  assert(maxelem != NULL);
3461 
3462  consdata = SCIPconsGetData(cons);
3463  assert(consdata != NULL);
3464  assert(exprint != NULL);
3465  assert(consdata->nexprtrees != 0 || consdata->exprgraphnode == NULL);
3466 
3467  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
3468  {
3469  *maxelem = 0.0;
3470  for( i = 0; i < consdata->nlinvars; ++i )
3471  if( REALABS(consdata->lincoefs[i]) > *maxelem )
3472  *maxelem = REALABS(consdata->lincoefs[i]);
3473  }
3474  else
3475  {
3476  *maxelem = consdata->lincoefsmax;
3477  }
3478 
3479  for( j = 0; j < consdata->nexprtrees; ++j )
3480  {
3481  int nvars;
3482  SCIP_Real val;
3483 
3484  assert(consdata->exprtrees[j] != NULL);
3485 
3486  nvars = SCIPexprtreeGetNVars(consdata->exprtrees[j]);
3487 
3488  if( newsol )
3489  {
3490  /* compile expression tree, if not done before (can happen, if called from proposeFeasibleSolution) */
3491  if( SCIPexprtreeGetInterpreterData(consdata->exprtrees[j]) == NULL )
3492  {
3493  SCIP_CALL( SCIPexprintCompile(exprint, consdata->exprtrees[j]) );
3494  }
3495 
3496  if( nvars == 1 )
3497  {
3498  /* in the not so unusual case that an expression has only one variable, we do not extra alloc memory */
3499  double varval;
3500  SCIP_Real grad;
3501 
3502  varval = SCIPgetSolVal(scip, sol, SCIPexprtreeGetVars(consdata->exprtrees[j])[0]);
3503  SCIP_CALL( SCIPexprintGrad(exprint, consdata->exprtrees[j], &varval, TRUE, &val, &grad) );
3504  if( REALABS(grad) > *maxelem )
3505  *maxelem = REALABS(grad);
3506  }
3507  else
3508  {
3509  SCIP_Real* x;
3510  SCIP_Real* grad;
3511 
3512  SCIP_CALL( SCIPallocBufferArray(scip, &x, nvars) );
3513  SCIP_CALL( SCIPallocBufferArray(scip, &grad, nvars) );
3514 
3515  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, SCIPexprtreeGetVars(consdata->exprtrees[j]), x) );
3516  SCIP_CALL( SCIPexprintGrad(exprint, consdata->exprtrees[j], x, TRUE, &val, grad) );
3517 
3518  for( i = 0; i < nvars; ++i )
3519  {
3520  grad[i] *= consdata->nonlincoefs[j];
3521  if( REALABS(grad[i]) > *maxelem )
3522  *maxelem = REALABS(grad[i]);
3523  }
3524 
3525  SCIPfreeBufferArray(scip, &x);
3526  SCIPfreeBufferArray(scip, &grad);
3527  }
3528  }
3529  else
3530  {
3531  assert(SCIPexprtreeGetInterpreterData(consdata->exprtrees[j]) != NULL);
3532 
3533  if( nvars == 1 )
3534  {
3535  SCIP_Real grad;
3536 
3537  SCIP_CALL( SCIPexprintGrad(exprint, consdata->exprtrees[j], NULL, FALSE, &val, &grad) );
3538  if( REALABS(grad) > *maxelem )
3539  *maxelem = REALABS(grad);
3540  }
3541  else
3542  {
3543  SCIP_Real* grad;
3544 
3545  SCIP_CALL( SCIPallocBufferArray(scip, &grad, nvars) );
3546 
3547  SCIP_CALL( SCIPexprintGrad(exprint, consdata->exprtrees[j], NULL, FALSE, &val, grad) );
3548 
3549  for( i = 0; i < nvars; ++i )
3550  {
3551  grad[i] *= consdata->nonlincoefs[j];
3552  if( REALABS(grad[i]) > *maxelem )
3553  *maxelem = REALABS(grad[i]);
3554  }
3555 
3556  SCIPfreeBufferArray(scip, &grad);
3557  }
3558  }
3559  }
3560 
3561  return SCIP_OKAY;
3562 }
3563 
3564 /** computes activity and violation of a constraint
3565  * during presolving and if the constraint is active, it is assumes that SCIPexprgraphEval has been called for sol before
3566  */
3567 static
3569  SCIP* scip, /**< SCIP data structure */
3570  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3571  SCIP_CONS* cons, /**< nonlinear constraint */
3572  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
3573  )
3574 { /*lint --e{666}*/
3575  SCIP_CONSHDLRDATA* conshdlrdata;
3576  SCIP_CONSDATA* consdata;
3577  SCIP_VAR* var;
3578  SCIP_Real varval;
3579  int i;
3580 
3581  assert(scip != NULL);
3582  assert(conshdlr != NULL);
3583  assert(cons != NULL);
3584 
3585  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3586  assert(conshdlrdata != NULL);
3587  assert(conshdlrdata->exprinterpreter != NULL);
3588 
3589  consdata = SCIPconsGetData(cons);
3590  assert(consdata != NULL);
3591 
3592  consdata->activity = 0.0;
3593  varval = 0.0;
3594 
3595  for( i = 0; i < consdata->nlinvars; ++i )
3596  {
3597  var = consdata->linvars[i];
3598  varval = SCIPgetSolVal(scip, sol, var);
3599  if( SCIPisInfinity(scip, REALABS(varval)) )
3600  {
3601  consdata->activity = SCIPinfinity(scip);
3602  if( !SCIPisInfinity(scip, -consdata->lhs) )
3603  consdata->lhsviol = SCIPinfinity(scip);
3604  if( !SCIPisInfinity(scip, consdata->rhs) )
3605  consdata->rhsviol = SCIPinfinity(scip);
3606  return SCIP_OKAY;
3607  }
3608 
3609  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
3610  if( sol == NULL )
3611  {
3612 #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 */
3613  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
3614  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
3615 #endif
3616  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
3617  }
3618 
3619  consdata->activity += consdata->lincoefs[i] * varval;
3620  }
3621 
3622  for( i = 0; i < consdata->nexprtrees; ++i )
3623  {
3624  SCIP_Real val;
3625  int nvars;
3626 
3627  /* compile expression tree, if not done before */
3628  if( SCIPexprtreeGetInterpreterData(consdata->exprtrees[i]) == NULL )
3629  {
3630  SCIP_CALL( SCIPexprintCompile(conshdlrdata->exprinterpreter, consdata->exprtrees[i]) );
3631  }
3632 
3633  nvars = SCIPexprtreeGetNVars(consdata->exprtrees[i]);
3634 
3635  if( nvars == 1 )
3636  {
3637  /* in the not so unusual case that an expression has only one variable, we do not need to extra allocate memory */
3638  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[0];
3639  varval = SCIPgetSolVal(scip, sol, var);
3640 
3641  /* project onto local box, in case the LP solution is slightly outside the bounds (and then cannot be evaluated) */
3642  if( sol == NULL )
3643  {
3644 #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 */
3645  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
3646  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
3647 #endif
3648  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
3649  }
3650 
3651  SCIP_CALL( SCIPexprintEval(conshdlrdata->exprinterpreter, consdata->exprtrees[i], &varval, &val) );
3652  }
3653  else
3654  {
3655  SCIP_Real* x;
3656  int j;
3657 
3658  SCIP_CALL( SCIPallocBufferArray(scip, &x, nvars) );
3659 
3660  for( j = 0; j < nvars; ++j )
3661  {
3662  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[j];
3663  varval = SCIPgetSolVal(scip, sol, var);
3664 
3665  /* project onto local box, in case the LP solution is slightly outside the bounds (and then cannot be evaluated) */
3666  if( sol == NULL )
3667  {
3668 #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 */
3669  assert(SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var)));
3670  assert(SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var)));
3671 #endif
3672  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
3673  }
3674 
3675  x[j] = varval;
3676  }
3677 
3678  SCIP_CALL( SCIPexprintEval(conshdlrdata->exprinterpreter, consdata->exprtrees[i], x, &val) );
3679 
3680  SCIPfreeBufferArray(scip, &x);
3681  }
3682 
3683  if( SCIPisInfinity(scip, REALABS(val)) || !SCIPisFinite(val) )
3684  {
3685  consdata->activity = SCIPinfinity(scip);
3686  if( !SCIPisInfinity(scip, -consdata->lhs) )
3687  consdata->lhsviol = SCIPinfinity(scip);
3688  if( !SCIPisInfinity(scip, consdata->rhs) )
3689  consdata->rhsviol = SCIPinfinity(scip);
3690  return SCIP_OKAY;
3691  }
3692  consdata->activity += consdata->nonlincoefs[i] * val;
3693  }
3694 
3695  if( consdata->nexprtrees == 0 && consdata->exprgraphnode != NULL )
3696  {
3697  SCIP_Real val;
3698 
3700 
3701  val = SCIPexprgraphGetNodeVal(consdata->exprgraphnode);
3702  assert(val != SCIP_INVALID); /*lint !e777*/
3703 
3704  if( !SCIPisFinite(val) || SCIPisInfinity(scip, REALABS(val)) )
3705  {
3706  consdata->activity = SCIPinfinity(scip);
3707  if( !SCIPisInfinity(scip, -consdata->lhs) )
3708  consdata->lhsviol = SCIPinfinity(scip);
3709  if( !SCIPisInfinity(scip, consdata->rhs) )
3710  consdata->rhsviol = SCIPinfinity(scip);
3711  return SCIP_OKAY;
3712  }
3713  consdata->activity += val;
3714  }
3715 
3716  if( !SCIPisInfinity(scip, -consdata->lhs) && SCIPisGT(scip, consdata->lhs - consdata->activity, SCIPfeastol(scip)) )
3717  consdata->lhsviol = consdata->lhs - consdata->activity;
3718  else
3719  consdata->lhsviol = 0.0;
3720 
3721  if( !SCIPisInfinity(scip, consdata->rhs) && SCIPisGT(scip, consdata->activity - consdata->rhs, SCIPfeastol(scip)) )
3722  consdata->rhsviol = consdata->activity - consdata->rhs;
3723  else
3724  consdata->rhsviol = 0.0;
3725 
3726  switch( conshdlrdata->scaling )
3727  {
3728  case 'o' :
3729  /* no scaling */
3730  break;
3731 
3732  case 'g' :
3733  /* scale by sup-norm of gradient in current point
3734  * do only if we are linear or have expression trees, thus, not during presolve
3735  */
3736  if( (consdata->lhsviol > 0.0 || consdata->rhsviol > 0.0) && (consdata->exprgraphnode == NULL || consdata->nexprtrees > 0) )
3737  {
3738  SCIP_Real norm;
3739 
3740  SCIP_CALL( getGradientMaxElement(scip, conshdlrdata->exprinterpreter, cons, sol, FALSE, &norm) );
3741 
3742  if( norm > 1.0 && !SCIPisInfinity(scip, norm) )
3743  {
3744  consdata->lhsviol /= norm;
3745  consdata->rhsviol /= norm;
3746  }
3747  }
3748  break;
3749 
3750  case 's' :
3751  /* scale by left/right hand side of constraint */
3752  if( consdata->lhsviol > 0.0 )
3753  consdata->lhsviol /= MAX(1.0, REALABS(consdata->lhs));
3754 
3755  if( consdata->rhsviol > 0.0 )
3756  consdata->rhsviol /= MAX(1.0, REALABS(consdata->rhs));
3757 
3758  break;
3759 
3760  default :
3761  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
3762  SCIPABORT();
3763  return SCIP_INVALIDDATA; /*lint !e527*/
3764  }
3765 
3766  return SCIP_OKAY;
3767 }
3768 
3769 /** computes violation of a set of constraints */
3770 static
3772  SCIP* scip, /**< SCIP data structure */
3773  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3774  SCIP_CONS** conss, /**< constraints */
3775  int nconss, /**< number of constraints */
3776  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
3777  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
3778  )
3779 {
3780  SCIP_CONSDATA* consdata;
3781  SCIP_Real viol;
3782  SCIP_Real maxviol;
3783  int c;
3784 
3785  assert(scip != NULL);
3786  assert(conshdlr != NULL);
3787  assert(conss != NULL || nconss == 0);
3788  assert(maxviolcon != NULL);
3789 
3791  {
3792  SCIP_CONSHDLRDATA* conshdlrdata;
3793  SCIP_Real* varvals;
3794 
3795  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3796  assert(conshdlrdata != NULL);
3797  assert(conshdlrdata->exprgraph != NULL);
3798 
3799  SCIP_CALL( SCIPallocBufferArray(scip, &varvals, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
3800  SCIP_CALL( SCIPgetSolVals(scip, sol, SCIPexprgraphGetNVars(conshdlrdata->exprgraph), (SCIP_VAR**)SCIPexprgraphGetVars(conshdlrdata->exprgraph), varvals) );
3801 
3802  SCIP_CALL( SCIPexprgraphEval(conshdlrdata->exprgraph, varvals) );
3803 
3804  SCIPfreeBufferArray(scip, &varvals);
3805  }
3806 
3807  *maxviolcon = NULL;
3808 
3809  maxviol = 0.0;
3810 
3811  for( c = 0; c < nconss; ++c )
3812  {
3813  assert(conss != NULL);
3814  assert(conss[c] != NULL);
3815 
3816  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
3817 
3818  consdata = SCIPconsGetData(conss[c]);
3819  assert(consdata != NULL);
3820 
3821  viol = MAX(consdata->lhsviol, consdata->rhsviol);
3822  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
3823  {
3824  maxviol = viol;
3825  *maxviolcon = conss[c];
3826  }
3827 
3828  /* SCIPdebugMessage("constraint <%s> violated by (%g, %g), activity = %g\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->activity); */
3829  }
3830 
3831  return SCIP_OKAY;
3832 }
3833 
3834 /** adds linearization of a constraints expression tree in reference point to a row */
3835 static
3837  SCIP* scip, /**< SCIP data structure */
3838  SCIP_EXPRINT* exprint, /**< expression interpreter */
3839  SCIP_CONS* cons, /**< constraint */
3840  int exprtreeidx, /**< for which tree a linearization should be added */
3841  SCIP_Real* x, /**< value of expression tree variables where to generate cut */
3842  SCIP_Bool newx, /**< whether the last evaluation of the expression with the expression interpreter was not at x */
3843  SCIP_ROW* row, /**< row where to add linearization */
3844  SCIP_Bool* success /**< buffer to store whether a linearization was succefully added to the row */
3845  )
3846 {
3847  SCIP_CONSDATA* consdata;
3848  SCIP_EXPRTREE* exprtree;
3849  SCIP_Real treecoef;
3850  SCIP_Real val;
3851  SCIP_Real* grad;
3852  SCIP_Real constant;
3853  SCIP_Bool perturbedx;
3854  int nvars;
3855  int i;
3856 
3857  assert(scip != NULL);
3858  assert(cons != NULL);
3859  assert(x != NULL);
3860  assert(row != NULL);
3861  assert(success != NULL);
3862 
3863  consdata = SCIPconsGetData(cons);
3864  assert(consdata != NULL);
3865  assert(exprtreeidx >= 0);
3866  assert(exprtreeidx < consdata->nexprtrees);
3867  assert(consdata->exprtrees != NULL);
3868 
3869  exprtree = consdata->exprtrees[exprtreeidx];
3870  assert(exprtree != NULL);
3871  assert(newx || SCIPexprtreeGetInterpreterData(exprtree) != NULL);
3872 
3873  treecoef = consdata->nonlincoefs[exprtreeidx];
3874 
3875  *success = FALSE;
3876 
3877  /* compile expression if evaluated the first time; can only happen if newx is FALSE */
3878  if( newx && SCIPexprtreeGetInterpreterData(exprtree) == NULL )
3879  {
3880  SCIP_CALL( SCIPexprintCompile(exprint, exprtree) );
3881  }
3882 
3883  nvars = SCIPexprtreeGetNVars(exprtree);
3884  SCIP_CALL( SCIPallocBufferArray(scip, &grad, nvars) );
3885 
3886  perturbedx = FALSE;
3887  do
3888  {
3889  /* get value and gradient */
3890  SCIP_CALL( SCIPexprintGrad(exprint, exprtree, x, newx, &val, grad) );
3891  if( SCIPisFinite(val) && !SCIPisInfinity(scip, REALABS(val)) )
3892  {
3893  val *= treecoef;
3894  /* check gradient entries and compute constant f(refx) - grad * refx */
3895  constant = val;
3896  for( i = 0; i < nvars; ++i )
3897  {
3898  if( !SCIPisFinite(grad[i]) || SCIPisInfinity(scip, grad[i]) || SCIPisInfinity(scip, -grad[i]) )
3899  break;
3900 
3901  grad[i] *= treecoef;
3902  constant -= grad[i] * x[i];
3903 
3904  /* 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)
3905  * in this case, set gradient to 0.0 here, but modify constant so that cut is still valid (if possible)
3906  * 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)
3907  * if required bound of x is not finite, then give up
3908  */
3909  if( grad[i] != 0.0 && SCIPisZero(scip, grad[i]) )
3910  {
3911  SCIP_VAR* var;
3912  SCIP_Real xbnd;
3913 
3914  var = SCIPexprtreeGetVars(exprtree)[i];
3915  if( consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONVEX )
3916  {
3917  xbnd = grad[i] > 0.0 ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
3918  }
3919  else
3920  {
3921  assert(consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONCAVE);
3922  xbnd = grad[i] > 0.0 ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
3923  }
3924  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
3925  {
3926  SCIPdebugMessage("var <%s> [%g,%g] has tiny gradient %g, replace coefficient by constant %g\n",
3927  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), grad[i], grad[i] * xbnd);
3928  constant += grad[i] * xbnd;
3929  grad[i] = 0.0;
3930  }
3931  else
3932  {
3933  *success = FALSE;
3934  SCIPdebugMessage("skipping linearization, var <%s> [%g,%g] has tiny gradient %g but no finite bound in this direction\n",
3935  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), grad[i]);
3936  SCIPfreeBufferArray(scip, &grad);
3937  return SCIP_OKAY;
3938  }
3939  }
3940  }
3941 
3942  if( i == nvars )
3943  break;
3944  }
3945 
3946  SCIPdebugMessage("got nonfinite value in evaluation or gradient of <%s>: ", SCIPconsGetName(cons));
3947  if( !perturbedx )
3948  {
3949  SCIP_Real lb;
3950  SCIP_Real ub;
3951 
3952  SCIPdebugPrintf("perturbing reference point and trying again\n");
3953  for( i = 0; i < nvars; ++i )
3954  {
3955  lb = SCIPvarGetLbGlobal(SCIPexprtreeGetVars(exprtree)[i]);
3956  ub = SCIPvarGetUbGlobal(SCIPexprtreeGetVars(exprtree)[i]);
3957  if( SCIPisEQ(scip, x[i], lb) )
3958  x[i] += MIN(0.9*(ub-lb), i*SCIPfeastol(scip)); /*lint !e666*/
3959  else if( SCIPisEQ(scip, x[i], ub) )
3960  x[i] -= MIN(0.9*(ub-lb), i*SCIPfeastol(scip)); /*lint !e666*/
3961  else
3962  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*/
3963  }
3964  newx = TRUE;
3965  perturbedx = TRUE;
3966  }
3967  else
3968  {
3969  SCIPdebugPrintf("skipping linearization\n");
3970  SCIPfreeBufferArray(scip, &grad);
3971  return SCIP_OKAY;
3972  }
3973  }
3974  while( TRUE ); /*lint !e506*/
3975 
3976  /* add linearization to SCIP row */
3977  if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) )
3978  {
3979  SCIP_CALL( SCIPchgRowLhs(scip, row, SCIProwGetLhs(row) - constant) ); /*lint !e644*/
3980  }
3981  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) )
3982  {
3983  SCIP_CALL( SCIPchgRowRhs(scip, row, SCIProwGetRhs(row) - constant) );
3984  }
3985  SCIP_CALL( SCIPaddVarsToRow(scip, row, nvars, SCIPexprtreeGetVars(exprtree), grad) );
3986 
3987  *success = TRUE;
3988 
3989  SCIPfreeBufferArray(scip, &grad);
3990 
3991  SCIPdebugMessage("added linearization for tree %d of constraint <%s>\n", exprtreeidx, SCIPconsGetName(cons));
3992  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
3993 
3994  return SCIP_OKAY;
3995 }
3996 
3997 /** adds secant of a constraints univariate expression tree in reference point to a row */
3998 static
4000  SCIP* scip, /**< SCIP data structure */
4001  SCIP_CONS* cons, /**< constraint */
4002  int exprtreeidx, /**< for which tree a secant should be added */
4003  SCIP_ROW* row, /**< row where to add secant */
4004  SCIP_Bool* success /**< buffer to store whether a secant was succefully added to the row */
4005  )
4006 {
4007  SCIP_CONSDATA* consdata;
4008  SCIP_EXPRTREE* exprtree;
4009  SCIP_Real treecoef;
4010  SCIP_VAR* var;
4011  SCIP_Real xlb;
4012  SCIP_Real xub;
4013  SCIP_Real vallb;
4014  SCIP_Real valub;
4015  SCIP_Real slope;
4016  SCIP_Real constant;
4017 
4018  assert(scip != NULL);
4019  assert(cons != NULL);
4020  assert(row != NULL);
4021  assert(success != NULL);
4022 
4023  consdata = SCIPconsGetData(cons);
4024  assert(consdata != NULL);
4025  assert(exprtreeidx >= 0);
4026  assert(exprtreeidx < consdata->nexprtrees);
4027  assert(consdata->exprtrees != NULL);
4028 
4029  exprtree = consdata->exprtrees[exprtreeidx];
4030  assert(exprtree != NULL);
4031  assert(SCIPexprtreeGetNVars(exprtree) == 1);
4032 
4033  treecoef = consdata->nonlincoefs[exprtreeidx];
4034 
4035  *success = FALSE;
4036 
4037  var = SCIPexprtreeGetVars(exprtree)[0];
4038  xlb = SCIPvarGetLbLocal(var);
4039  xub = SCIPvarGetUbLocal(var);
4040 
4041  /* if variable is unbounded, then cannot really compute secant */
4042  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
4043  {
4044  SCIPdebugMessage("skip secant for tree %d of constraint <%s> since variable is unbounded\n", exprtreeidx, SCIPconsGetName(cons));
4045  return SCIP_OKAY;
4046  }
4047  assert(SCIPisLE(scip, xlb, xub));
4048 
4049  SCIP_CALL( SCIPexprtreeEval(exprtree, &xlb, &vallb) );
4050  if( !SCIPisFinite(vallb) || SCIPisInfinity(scip, REALABS(vallb)) )
4051  {
4052  SCIPdebugMessage("skip secant for tree %d of constraint <%s> since function cannot be evaluated in lower bound\n", exprtreeidx, SCIPconsGetName(cons));
4053  return SCIP_OKAY;
4054  }
4055  vallb *= treecoef;
4056 
4057  SCIP_CALL( SCIPexprtreeEval(exprtree, &xub, &valub) );
4058  if( !SCIPisFinite(valub) || SCIPisInfinity(scip, REALABS(valub)) )
4059  {
4060  SCIPdebugMessage("skip secant for tree %d of constraint <%s> since function cannot be evaluated in upper bound\n", exprtreeidx, SCIPconsGetName(cons));
4061  return SCIP_OKAY;
4062  }
4063  valub *= treecoef;
4064 
4065  if( SCIPisEQ(scip, xlb, xub) )
4066  {
4067  assert(SCIPisFeasEQ(scip, vallb, valub));
4068  slope = 0.0;
4069  constant = 0.5 * (vallb+valub);
4070  }
4071  else
4072  {
4073  slope = (valub - vallb) / (xub - xlb);
4074  constant = vallb - slope * xlb;
4075  }
4076 
4077  /* add secant to SCIP row */
4078  if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) )
4079  {
4080  SCIP_CALL( SCIPchgRowLhs(scip, row, SCIProwGetLhs(row) - constant) );
4081  }
4082  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) )
4083  {
4084  SCIP_CALL( SCIPchgRowRhs(scip, row, SCIProwGetRhs(row) - constant) );
4085  }
4086  if( slope != 0.0 )
4087  {
4088  SCIP_CALL( SCIPaddVarsToRow(scip, row, 1, &var, &slope) );
4089  }
4090 
4091  *success = TRUE;
4092 
4093  SCIPdebugMessage("added secant for tree %d of constraint <%s>, slope = %g\n", exprtreeidx, SCIPconsGetName(cons), slope);
4094  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
4095 
4096  return SCIP_OKAY;
4097 }
4098 
4099 /** given three points, constructs coefficient of equation for hyperplane generated by these three points
4100  * Three points a, b, and c are given.
4101  * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
4102  * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
4103  */
4104 static
4106  SCIP_Real a1, /* first coordinate of a */
4107  SCIP_Real a2, /* second coordinate of a */
4108  SCIP_Real a3, /* third coordinate of a */
4109  SCIP_Real b1, /* first coordinate of b */
4110  SCIP_Real b2, /* second coordinate of b */
4111  SCIP_Real b3, /* third coordinate of b */
4112  SCIP_Real c1, /* first coordinate of c */
4113  SCIP_Real c2, /* second coordinate of c */
4114  SCIP_Real c3, /* third coordinate of c */
4115  SCIP_Real* alpha, /* coefficient of first coordinate */
4116  SCIP_Real* beta, /* coefficient of second coordinate */
4117  SCIP_Real* gamma_, /* coefficient of third coordinate */
4118  SCIP_Real* delta /* constant right-hand side */
4119  )
4120 {
4121  assert(alpha != NULL);
4122  assert(beta != NULL);
4123  assert(gamma_ != NULL);
4124  assert(delta != NULL);
4125 
4126  *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
4127  *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
4128  *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
4129  *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
4130 
4131  if( *gamma_ < 0.0 )
4132  {
4133  *alpha = -*alpha;
4134  *beta = -*beta;
4135  *gamma_ = -*gamma_;
4136  *delta = -*delta;
4137  }
4138 }
4139 
4140 /** adds estimator of a constraints bivariate expression tree to a row
4141  * a reference point is given to decide which hyperplane to choose
4142  */
4143 static
4145  SCIP* scip, /**< SCIP data structure */
4146  SCIP_CONS* cons, /**< constraint */
4147  int exprtreeidx, /**< for which tree a secant should be added */
4148  SCIP_Real* ref, /**< reference values of expression tree variables where to generate cut */
4149  SCIP_ROW* row, /**< row where to add secant */
4150  SCIP_Bool* success /**< buffer to store whether a secant was succefully added to the row */
4151  )
4152 {
4153  SCIP_CONSDATA* consdata;
4154  SCIP_EXPRTREE* exprtree;
4155  SCIP_Real treecoef;
4156  SCIP_VAR* x;
4157  SCIP_VAR* y;
4158  SCIP_Real xlb;
4159  SCIP_Real xub;
4160  SCIP_Real ylb;
4161  SCIP_Real yub;
4162 
4163  SCIP_Real coefx;
4164  SCIP_Real coefy;
4165  SCIP_Real constant;
4166 
4167  SCIP_Real p1[2];
4168  SCIP_Real p2[2];
4169  SCIP_Real p3[2];
4170  SCIP_Real p4[2];
4171  SCIP_Real p1val, p2val, p3val, p4val;
4172 
4173  assert(scip != NULL);
4174  assert(cons != NULL);
4175  assert(ref != NULL);
4176  assert(row != NULL);
4177  assert(success != NULL);
4178 
4179  consdata = SCIPconsGetData(cons);
4180  assert(consdata != NULL);
4181  assert(exprtreeidx >= 0);
4182  assert(exprtreeidx < consdata->nexprtrees);
4183  assert(consdata->exprtrees != NULL);
4184 
4185  exprtree = consdata->exprtrees[exprtreeidx];
4186  assert(exprtree != NULL);
4187  assert(SCIPexprtreeGetNVars(exprtree) == 2);
4188 
4189  treecoef = consdata->nonlincoefs[exprtreeidx];
4190 
4191  *success = FALSE;
4192 
4193  x = SCIPexprtreeGetVars(exprtree)[0];
4194  y = SCIPexprtreeGetVars(exprtree)[1];
4195  xlb = SCIPvarGetLbLocal(x);
4196  xub = SCIPvarGetUbLocal(x);
4197  ylb = SCIPvarGetLbLocal(y);
4198  yub = SCIPvarGetUbLocal(y);
4199 
4200  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) || SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub) )
4201  {
4202  SCIPdebugMessage("skip bivariate secant since <%s> or <%s> is unbounded\n", SCIPvarGetName(x), SCIPvarGetName(y));
4203  return SCIP_OKAY;
4204  }
4205 
4206  /* reference point should not be outside of bounds */
4207  assert(SCIPisFeasLE(scip, xlb, ref[0]));
4208  assert(SCIPisFeasGE(scip, xub, ref[0]));
4209  ref[0] = MIN(xub, MAX(xlb, ref[0]));
4210  assert(SCIPisFeasLE(scip, ylb, ref[1]));
4211  assert(SCIPisFeasGE(scip, yub, ref[1]));
4212  ref[1] = MIN(yub, MAX(ylb, ref[1]));
4213 
4214  /* lower left */
4215  p1[0] = xlb;
4216  p1[1] = ylb;
4217 
4218  /* lower right */
4219  p2[0] = xub;
4220  p2[1] = ylb;
4221 
4222  /* upper right */
4223  p3[0] = xub;
4224  p3[1] = yub;
4225 
4226  /* upper left */
4227  p4[0] = xlb;
4228  p4[1] = yub;
4229 
4230  if( SCIPisEQ(scip, xlb, xub) && SCIPisEQ(scip, ylb, yub) )
4231  {
4232  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4233 
4234  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) )
4235  {
4236  SCIPdebugMessage("skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4237  return SCIP_OKAY;
4238  }
4239 
4240  p1val *= treecoef;
4241 
4242  coefx = 0.0;
4243  coefy = 0.0;
4244  constant = p1val;
4245  }
4246  else if( SCIPisEQ(scip, xlb, xub) )
4247  {
4248  /* secant between p1 and p4: p1val + [(p4val - p1val) / (yub - ylb)] * (y - ylb) */
4249  assert(!SCIPisEQ(scip, ylb, yub));
4250 
4251  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4252  SCIP_CALL( SCIPexprtreeEval(exprtree, p4, &p4val) );
4253  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p4val) || SCIPisInfinity(scip, REALABS(p4val)) )
4254  {
4255  SCIPdebugMessage("skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4256  return SCIP_OKAY;
4257  }
4258  p1val *= treecoef;
4259  p4val *= treecoef;
4260 
4261  coefx = 0.0;
4262  coefy = (p4val - p1val) / (yub - ylb);
4263  constant = p1val - coefy * ylb;
4264  }
4265  else if( SCIPisEQ(scip, ylb, yub) )
4266  {
4267  /* secant between p1 and p2: p1val + [(p2val - p1val) / (xub - xlb)] * (x - xlb) */
4268  assert(!SCIPisEQ(scip, xlb, xub));
4269 
4270  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4271  SCIP_CALL( SCIPexprtreeEval(exprtree, p2, &p2val) );
4272  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p2val) || SCIPisInfinity(scip, REALABS(p2val)) )
4273  {
4274  SCIPdebugMessage("skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4275  return SCIP_OKAY;
4276  }
4277 
4278  p1val *= treecoef;
4279  p2val *= treecoef;
4280 
4281  coefx = (p2val - p1val) / (xub - xlb);
4282  coefy = 0.0;
4283  constant = p1val - coefx * xlb;
4284  }
4285  else
4286  {
4287  SCIP_Real alpha, beta, gamma_, delta;
4288  SCIP_Bool tryother;
4289  SCIP_Bool doover;
4290 
4291  /* if function is convex, then we want an overestimator, otherwise we want an underestimator */
4292  assert(consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONVEX || consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONCAVE);
4293  doover = (consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONVEX); /*lint !e641*/
4294 
4295  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4296  SCIP_CALL( SCIPexprtreeEval(exprtree, p2, &p2val) );
4297  SCIP_CALL( SCIPexprtreeEval(exprtree, p3, &p3val) );
4298  SCIP_CALL( SCIPexprtreeEval(exprtree, p4, &p4val) );
4299  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p2val) || SCIPisInfinity(scip, REALABS(p2val)) ||
4300  ! SCIPisFinite(p3val) || SCIPisInfinity(scip, REALABS(p3val)) || !SCIPisFinite(p4val) || SCIPisInfinity(scip, REALABS(p4val)) )
4301  {
4302  SCIPdebugMessage("skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4303  return SCIP_OKAY;
4304  }
4305  p1val *= treecoef;
4306  p2val *= treecoef;
4307  p3val *= treecoef;
4308  p4val *= treecoef;
4309 
4310  /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
4311  if( !doover )
4312  {
4313  p1val = -p1val;
4314  p2val = -p2val;
4315  p3val = -p3val;
4316  p4val = -p4val;
4317  }
4318 
4319  SCIPdebugMessage("p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
4320  SCIPdebugMessage("p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
4321  SCIPdebugMessage("p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
4322  SCIPdebugMessage("p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
4323 
4324  /* Compute coefficients alpha, beta, gamma (>0), delta such that
4325  * alpha*x + beta*y + gamma*z = delta
4326  * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
4327  * the fourth corner point lies below this hyperplane.
4328  * Since we assume that f is convex, we then know that all points (x,y,f(x,y)) are below this hyperplane, i.e.,
4329  * alpha*x + beta*y - delta <= -gamma * f(x,y),
4330  * or, equivalently,
4331  * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
4332  */
4333 
4334  tryother = FALSE;
4335  if( ref[1] <= ylb + (yub - ylb)/(xub - xlb) * (ref[0] - xlb) )
4336  {
4337  getAlphaBetaGammaDelta(p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val, &alpha, &beta, &gamma_, &delta);
4338  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4339  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4340  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4341 
4342  /* if hyperplane through p1,p2,p3 does not overestimate f(p4), then it must be the other variant */
4343  if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val > delta )
4344  tryother = TRUE;
4345  else if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4346  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4347  {
4348  /* if numerically bad, take alternative hyperplane */
4349  getAlphaBetaGammaDelta(p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val, &alpha, &beta, &gamma_, &delta);
4350  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4351  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4352  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4353 
4354  /* if hyperplane through p1,p3,p4 does not overestimate f(p2), then it must be the other variant */
4355  if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val > delta )
4356  tryother = TRUE;
4357  }
4358  }
4359  else
4360  {
4361  getAlphaBetaGammaDelta(p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val, &alpha, &beta, &gamma_, &delta);
4362  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4363  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4364  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4365 
4366  /* if hyperplane through p1,p3,p4 does not overestimate f(p2), then it must be the other variant */
4367  if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val > delta )
4368  tryother = TRUE;
4369  else if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4370  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4371  {
4372  /* if numerically bad, take alternative */
4373  getAlphaBetaGammaDelta(p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val, &alpha, &beta, &gamma_, &delta);
4374  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4375  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4376  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4377 
4378  /* if hyperplane through p1,p2,p3 does not overestimate f(p4), then it must be the other variant */
4379  if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val > delta )
4380  tryother = TRUE;
4381  }
4382  }
4383 
4384  if( tryother )
4385  {
4386  if( ref[1] <= yub + (ylb - yub)/(xub - xlb) * (ref[0] - xlb) )
4387  {
4388  getAlphaBetaGammaDelta(p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val, &alpha, &beta, &gamma_, &delta);
4389 
4390  /* hyperplane should be above (p3,f(p3)) and other points should lie on hyperplane */
4391  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4392  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4393  assert(SCIPisRelLE(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4394  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4395 
4396  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4397  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4398  {
4399  /* if numerically bad, take alternative */
4400  getAlphaBetaGammaDelta(p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val, &alpha, &beta, &gamma_, &delta);
4401 
4402  /* hyperplane should be above (p1,f(p1)) and other points should lie on hyperplane */
4403  assert(SCIPisRelLE(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4404  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4405  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4406  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4407  }
4408  }
4409  else
4410  {
4411  getAlphaBetaGammaDelta(p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val, &alpha, &beta, &gamma_, &delta);
4412 
4413  /* hyperplane should be above (p1,f(p1)) and other points should lie on hyperplane */
4414  assert(SCIPisRelLE(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4415  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4416  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4417  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4418 
4419  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4420  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4421  {
4422  /* if numerically bad, take alternative */
4423  getAlphaBetaGammaDelta(p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val, &alpha, &beta, &gamma_, &delta);
4424 
4425  /* hyperplane should be above (p3,f(p3)) and other points should lie on hyperplane */
4426  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
4427  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
4428  assert(SCIPisRelLE(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
4429  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
4430  }
4431  }
4432  }
4433 
4434  SCIPdebugMessage("alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
4435 
4436  /* check if bad luck: should not happen if xlb != xub and ylb != yub and numerics are fine */
4437  if( SCIPisZero(scip, gamma_) )
4438  return SCIP_OKAY;
4439  assert(!SCIPisNegative(scip, gamma_));
4440 
4441  /* flip hyperplane */
4442  if( !doover )
4443  gamma_ = -gamma_;
4444 
4445  coefx = -alpha / gamma_;
4446  coefy = -beta / gamma_;
4447  constant = delta / gamma_;
4448 
4449  /* if we loose coefficients because division by gamma makes them < SCIPepsilon(scip), then better not generate a cut here */
4450  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, coefx)) ||
4451  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, coefy)) )
4452  {
4453  SCIPdebugMessage("skip bivar secant for <%s> tree %d due to bad numerics\n", SCIPconsGetName(cons), exprtreeidx);
4454  return SCIP_OKAY;
4455  }
4456  }
4457 
4458  /* add hyperplane coefs to SCIP row */
4459  if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) )
4460  {
4461  SCIP_CALL( SCIPchgRowLhs(scip, row, SCIProwGetLhs(row) - constant) );
4462  }
4463  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) )
4464  {
4465  SCIP_CALL( SCIPchgRowRhs(scip, row, SCIProwGetRhs(row) - constant) );
4466  }
4467  SCIP_CALL( SCIPaddVarsToRow(scip, row, 1, &x, &coefx) );
4468  SCIP_CALL( SCIPaddVarsToRow(scip, row, 1, &y, &coefy) );
4469 
4470  *success = TRUE;
4471 
4472  SCIPdebugMessage("added bivariate secant for tree %d of constraint <%s>\n", exprtreeidx, SCIPconsGetName(cons));
4473  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
4474 
4475  return SCIP_OKAY;
4476 }
4477 
4478 /** adds estimator of a constraints multivariate expression tree to a row
4479  * Given concave function f(x) and reference point ref.
4480  * Let (v_i: i=1,...,n) be corner points of current domain of x.
4481  * Find (coef,constant) such that <coef,v_i> + constant <= f(v_i) (cut validity) and
4482  * such that <coef, ref> + constant is maximized (cut efficacy).
4483  * Then <coef, x> + constant <= f(x) for all x in current domain.
4484  *
4485  * Similar to compute an overestimator for a convex function f(x).
4486  * Find (coef,constant) such that <coef,v_i> + constant >= f(v_i) and
4487  * such that <coef, ref> + constant is minimized.
4488  * Then <coef, x> + constant >= f(x) for all x in current domain.
4489  */
4490 static
4492  SCIP* scip, /**< SCIP data structure */
4493  SCIP_CONS* cons, /**< constraint */
4494  int exprtreeidx, /**< for which tree a secant should be added */
4495  SCIP_Real* ref, /**< reference values of expression tree variables where to generate cut */
4496  SCIP_ROW* row, /**< row where to add secant */
4497  SCIP_Bool* success /**< buffer to store whether a secant was succefully added to the row */
4498  )
4499 {
4500  SCIP_CONSDATA* consdata;
4501  SCIP_EXPRTREE* exprtree;
4502  SCIP_Real treecoef;
4503  SCIP_LPI* lpi;
4504  SCIP_Bool doupper;
4505  SCIP_Real funcval;
4506  SCIP_Real lpobj;
4507  SCIP_RETCODE lpret;
4508 
4509  SCIP_VAR** vars;
4510  int nvars;
4511 
4512  int ncols;
4513  SCIP_Real* obj;
4514  SCIP_Real* lb;
4515  SCIP_Real* ub;
4516  int nrows;
4517  SCIP_Real* lhs;
4518  SCIP_Real* rhs;
4519  int nnonz;
4520  int* beg;
4521  int* ind;
4522  SCIP_Real* val;
4523 
4524  int i;
4525  int j;
4526 
4527  assert(scip != NULL);
4528  assert(cons != NULL);
4529  assert(ref != NULL);
4530  assert(row != NULL);
4531  assert(success != NULL);
4532 
4533  consdata = SCIPconsGetData(cons);
4534  assert(consdata != NULL);
4535  assert(exprtreeidx >= 0);
4536  assert(exprtreeidx < consdata->nexprtrees);
4537  assert(consdata->exprtrees != NULL);
4538 
4539  exprtree = consdata->exprtrees[exprtreeidx];
4540  assert(exprtree != NULL);
4541 
4542  nvars = SCIPexprtreeGetNVars(exprtree);
4543  assert(nvars >= 2);
4544 
4545  *success = FALSE;
4546 
4547  /* size of LP is exponential in number of variables of tree, so do only for small trees */
4548  if( nvars > 10 )
4549  {
4550  SCIPwarningMessage(scip, "concave function in constraint <%s> too high-dimensional to compute underestimator\n", SCIPconsGetName(cons));
4551  return SCIP_OKAY;
4552  }
4553 
4554  treecoef = consdata->nonlincoefs[exprtreeidx];
4555  vars = SCIPexprtreeGetVars(exprtree);
4556 
4557  /* check whether bounds are finite
4558  * make sure reference point is strictly within bounds
4559  * otherwise we can easily get an unbounded LP below, e.g., with instances like ex6_2_* from GlobalLib
4560  */
4561  for( j = 0; j < nvars; ++j )
4562  {
4563  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(vars[j])) || SCIPisInfinity(scip, SCIPvarGetUbLocal(vars[j])) )
4564  {
4565  SCIPdebugMessage("cannot compute underestimator for concave because variable <%s> is unbounded\n", SCIPvarGetName(vars[j]));
4566  return SCIP_OKAY;
4567  }
4568  assert(SCIPisFeasLE(scip, SCIPvarGetLbLocal(vars[j]), ref[j]));
4569  assert(SCIPisFeasGE(scip, SCIPvarGetUbLocal(vars[j]), ref[j]));
4570  ref[j] = MIN(SCIPvarGetUbLocal(vars[j]), MAX(SCIPvarGetLbLocal(vars[j]), ref[j])); /*lint !e666*/
4571  }
4572 
4573  assert(consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONVEX || consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONCAVE);
4574  doupper = (consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONVEX); /*lint !e641*/
4575 
4576  lpi = NULL;
4577 
4578  /* columns are cut coefficients plus constant */
4579  ncols = nvars + 1;
4580  SCIP_CALL( SCIPallocBufferArray(scip, &obj, ncols) );
4581  SCIP_CALL( SCIPallocBufferArray(scip, &lb, ncols) );
4582  SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
4583 
4584  /* one row for each corner of domain, i.e., 2^nvars many */
4585  nrows = (int)(1u << nvars);
4586  SCIP_CALL( SCIPallocBufferArray(scip, &lhs, nrows) );
4587  SCIP_CALL( SCIPallocBufferArray(scip, &rhs, nrows) );
4588 
4589  /* dense coefficients matrix, i.e., ncols * nrows many potential nonzeros */
4590  nnonz = nrows * ncols;
4591  SCIP_CALL( SCIPallocBufferArray(scip, &beg, nrows+1) );
4592  SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
4593  SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
4594 
4595  /* setup LP data */
4596  for( i = 0; i < nrows; ++i )
4597  {
4598  beg[i] = i * ncols;
4599  /* assemble corner point */
4600  SCIPdebugMessage("f(");
4601  for( j = 0; j < nvars; ++j )
4602  {
4603  /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
4604  * we check this by shifting i for j positions to the right and checking whether the j'th bit is set */
4605  if( ((unsigned int)i >> j) & 0x1 )
4606  val[i * ncols + j] = SCIPvarGetUbLocal(vars[j]);
4607  else
4608  val[i * ncols + j] = SCIPvarGetLbLocal(vars[j]);
4609  SCIPdebugPrintf("%g, ", val[i*ncols+j]);
4610  assert(!SCIPisInfinity(scip, REALABS(val[i*ncols+j])));
4611 
4612  ind[i * ncols + j] = j;
4613  }
4614 
4615  /* evaluate function in current corner */
4616  SCIP_CALL( SCIPexprtreeEval(exprtree, &val[i*ncols], &funcval) );
4617  SCIPdebugPrintf(") = %g\n", funcval);
4618 
4619  if( !SCIPisFinite(funcval) || SCIPisInfinity(scip, REALABS(funcval)) )
4620  {
4621  SCIPdebugMessage("cannot compute underestimator for concave because constaint <%s> cannot be evaluated\n", SCIPconsGetName(cons));
4622  goto TERMINATE;
4623  }
4624 
4625  funcval *= treecoef;
4626 
4627  if( !doupper )
4628  {
4629  lhs[i] = -SCIPlpiInfinity(lpi);
4630  rhs[i] = funcval;
4631  }
4632  else
4633  {
4634  lhs[i] = funcval;
4635  rhs[i] = SCIPlpiInfinity(lpi);
4636  }
4637 
4638  /* coefficient for constant is 1.0 */
4639  val[i * ncols + nvars] = 1.0;
4640  ind[i * ncols + nvars] = nvars;
4641  }
4642  beg[nrows] = nnonz;
4643 
4644  for( j = 0; j < ncols; ++j )
4645  {
4646  lb[j] = -SCIPlpiInfinity(lpi);
4647  ub[j] = SCIPlpiInfinity(lpi);
4648  }
4649 
4650  /* objective coefficients are reference points, and an additional 1.0 for the constant */
4651  BMScopyMemoryArray(obj, ref, nvars);
4652  obj[nvars] = 1.0;
4653 
4654  /* get function value in reference point, so we can use this as a cutoff */
4655  SCIP_CALL( SCIPexprtreeEval(exprtree, ref, &funcval) );
4656  funcval *= treecoef;
4657 
4658  SCIP_CALL( SCIPlpiCreate(&lpi, SCIPgetMessagehdlr(scip), "concaveunderest", doupper ? SCIP_OBJSEN_MINIMIZE : SCIP_OBJSEN_MAXIMIZE) );
4659  SCIP_CALL( SCIPlpiAddCols(lpi, ncols, obj, lb, ub, NULL, 0, NULL, NULL, NULL) );
4660  SCIP_CALL( SCIPlpiAddRows(lpi, nrows, lhs, rhs, NULL, nnonz, beg, ind, val) );
4661 
4662  /* make use of this convenient features, since for us nrows >> ncols */
4663  /*SCIP_CALL( SCIPlpiSetRealpar(lpi, SCIP_LPPAR_ROWREPSWITCH, 5.0) ); */
4664  /* get accurate coefficients */
4666  SCIP_CALL( SCIPlpiSetRealpar(lpi, doupper ? SCIP_LPPAR_LOBJLIM : SCIP_LPPAR_UOBJLIM, funcval) );
4667  SCIP_CALL( SCIPlpiSetIntpar(lpi, SCIP_LPPAR_LPITLIM, 10 * nvars) );
4670 
4671  /* SCIPdebug( SCIP_CALL( SCIPlpiSetIntpar(lpi, SCIP_LPPAR_LPINFO, 1) ) ); */
4672 
4673  lpret = SCIPlpiSolveDual(lpi);
4674  if( lpret != SCIP_OKAY )
4675  {
4676  SCIPwarningMessage(scip, "solving auxiliary LP for underestimator of concave function returned %d\n", lpret);
4677  goto TERMINATE;
4678  }
4679 
4680  if( !SCIPlpiIsPrimalFeasible(lpi) )
4681  {
4682  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));
4683  goto TERMINATE;
4684  }
4685  /* should be either solved to optimality, or the objective or iteration limit be hit */
4686  assert(SCIPlpiIsOptimal(lpi) || SCIPlpiIsObjlimExc(lpi) || SCIPlpiIsIterlimExc(lpi));
4687 
4688  /* setup row coefficient, reuse obj array to store LP sol values */
4689  SCIP_CALL( SCIPlpiGetSol(lpi, &lpobj, obj, NULL, NULL, NULL) );
4690  SCIP_CALL( SCIPaddVarsToRow(scip, row, nvars, vars, obj) );
4691 
4692  /* check that computed hyperplane is on right side of function in refpoint
4693  * if numerics is very bad (e.g., st_e32), then even this can happen */
4694  if( (!doupper && SCIPisFeasGT(scip, lpobj, funcval)) || (doupper && SCIPisFeasGT(scip, funcval, lpobj)) )
4695  {
4696  SCIPwarningMessage(scip, "computed cut does not underestimate concave function in refpoint\n");
4697  goto TERMINATE;
4698  }
4699  assert( doupper || SCIPisFeasLE(scip, lpobj, funcval) );
4700  assert(!doupper || SCIPisFeasLE(scip, funcval, lpobj) );
4701 
4702  /* substract constant from lhs or rhs */
4703  if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) )
4704  {
4705  SCIP_CALL( SCIPchgRowLhs(scip, row, SCIProwGetLhs(row) - obj[nvars]) );
4706  }
4707  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) )
4708  {
4709  SCIP_CALL( SCIPchgRowRhs(scip, row, SCIProwGetRhs(row) - obj[nvars]) );
4710  }
4711 
4712  *success = TRUE;
4713 
4714  TERMINATE:
4715  SCIPfreeBufferArray(scip, &obj);
4716  SCIPfreeBufferArray(scip, &lb);
4717  SCIPfreeBufferArray(scip, &ub);
4718  SCIPfreeBufferArray(scip, &lhs);
4719  SCIPfreeBufferArray(scip, &rhs);
4720  SCIPfreeBufferArray(scip, &beg);
4721  SCIPfreeBufferArray(scip, &ind);
4722  SCIPfreeBufferArray(scip, &val);
4723 
4724  if( lpi != NULL )
4725  {
4726  SCIP_CALL( SCIPlpiFree(&lpi) );
4727  }
4728 
4729  return SCIP_OKAY;
4730 }
4731 
4732 /** adds estimator from interval gradient of a constraints univariate expression tree to a row
4733  * a reference point is used to decide in which corner to generate the cut
4734  */
4735 static
4737  SCIP* scip, /**< SCIP data structure */
4738  SCIP_EXPRINT* exprint, /**< expression interpreter */
4739  SCIP_CONS* cons, /**< constraint */
4740  int exprtreeidx, /**< for which tree a secant should be added */
4741  SCIP_Real* x, /**< value of expression tree variables where to generate cut */
4742  SCIP_Bool newx, /**< whether the last evaluation of the expression with the expression interpreter was not at x */
4743  SCIP_Bool overestimate, /**< whether to compute an overestimator instead of an underestimator */
4744  SCIP_ROW* row, /**< row where to add secant */
4745  SCIP_Bool* success /**< buffer to store whether a secant was succefully added to the row */
4746  )
4747 {
4748  SCIP_CONSDATA* consdata;
4749  SCIP_EXPRTREE* exprtree;
4750  SCIP_Real treecoef;
4751  SCIP_Real* coefs;
4752  SCIP_Real constant;
4753  SCIP_Real val;
4754  SCIP_Real lb;
4755  SCIP_Real ub;
4756  SCIP_INTERVAL* box;
4757  SCIP_INTERVAL* intgrad;
4758  SCIP_INTERVAL intval;
4759  SCIP_VAR** vars;
4760  int nvars;
4761  int i;
4762 
4763  assert(scip != NULL);
4764  assert(cons != NULL);
4765  assert(x != NULL);
4766  assert(row != NULL);
4767  assert(success != NULL);
4768 
4769  consdata = SCIPconsGetData(cons);
4770  assert(consdata != NULL);
4771  assert(exprtreeidx >= 0);
4772  assert(exprtreeidx < consdata->nexprtrees);
4773  assert(consdata->exprtrees != NULL);
4774 
4775  exprtree = consdata->exprtrees[exprtreeidx];
4776  assert(exprtree != NULL);
4777  assert(newx || SCIPexprtreeGetInterpreterData(exprtree) != NULL);
4778 
4779  *success = FALSE;
4780 
4781  /* skip interval gradient if expression interpreter cannot compute interval gradients */
4783  return SCIP_OKAY;
4784 
4785  nvars = SCIPexprtreeGetNVars(exprtree);
4786  vars = SCIPexprtreeGetVars(exprtree);
4787 
4788  box = NULL;
4789  intgrad = NULL;
4790  coefs = NULL;
4791 
4792  SCIP_CALL( SCIPallocBufferArray(scip, &box, nvars) );
4793 
4794  /* move reference point to bounds, setup box */
4795  for( i = 0; i < nvars; ++i )
4796  {
4797  lb = SCIPvarGetLbLocal(vars[i]);
4798  ub = SCIPvarGetUbLocal(vars[i]);
4799  if( SCIPisInfinity(scip, -lb) )
4800  {
4801  if( SCIPisInfinity(scip, ub) )
4802  {
4803  SCIPdebugMessage("skip interval gradient estimator for constraint <%s> because variable <%s> is still unbounded.\n", SCIPconsGetName(cons), SCIPvarGetName(vars[i]));
4804  goto INTGRADESTIMATOR_CLEANUP;
4805  }
4806  x[i] = ub;
4807  }
4808  else
4809  {
4810  if( SCIPisInfinity(scip, ub) )
4811  x[i] = lb;
4812  else
4813  x[i] = (2.0*x[i] < lb+ub) ? lb : ub;
4814  }
4815  SCIPintervalSetBounds(&box[i],
4816  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -MIN(lb, ub)),
4817  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, MAX(lb, ub)));
4818  }
4819 
4820  /* compile expression if evaluated the first time; can only happen if newx is FALSE */
4821  if( newx && SCIPexprtreeGetInterpreterData(exprtree) == NULL )
4822  {
4823  SCIP_CALL( SCIPexprintCompile(exprint, exprtree) );
4824  }
4825 
4826  /* evaluate in reference point */
4827  SCIP_CALL( SCIPexprintEval(exprint, exprtree, x, &val) );
4828  if( !SCIPisFinite(val) )
4829  {
4830  SCIPdebugMessage("Got nonfinite function value from evaluation of constraint %s tree %d. skipping interval gradient estimator.\n", SCIPconsGetName(cons), exprtreeidx);
4831  goto INTGRADESTIMATOR_CLEANUP;
4832  }
4833 
4834  treecoef = consdata->nonlincoefs[exprtreeidx];
4835  val *= treecoef;
4836  constant = val;
4837 
4838  /* compute interval gradient */
4839  SCIP_CALL( SCIPallocBufferArray(scip, &intgrad, nvars) );
4840  SCIP_CALL( SCIPexprintGradInt(exprint, exprtree, INTERVALINFTY, box, TRUE, &intval, intgrad) );
4841  SCIPintervalMulScalar(INTERVALINFTY, &intval, intval, treecoef);
4842 
4843  /* printf("nvars %d side %d xref = %g x = [%g,%g] intval = [%g,%g] intgrad = [%g,%g]\n", nvars, side, x[0],
4844  box[0].inf, box[0].sup, intval.inf, intval.sup, intgrad[0].inf, intgrad[0].sup); */
4845 
4846  /* compute coefficients and constant */
4847  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
4848  for( i = 0; i < nvars; ++i )
4849  {
4850  val = x[i];
4851  lb = SCIPintervalGetInf(box[i]);
4852  ub = SCIPintervalGetSup(box[i]);
4853 
4854  SCIPintervalMulScalar(INTERVALINFTY, &intgrad[i], intgrad[i], treecoef);
4855 
4856  if( SCIPisEQ(scip, lb, ub) )
4857  coefs[i] = 0.0;
4858  else if( (overestimate && val == ub) || /*lint !e777*/
4859  (!overestimate && val == lb) ) /*lint !e777*/
4860  coefs[i] = SCIPintervalGetInf(intgrad[i]);
4861  else
4862  coefs[i] = SCIPintervalGetSup(intgrad[i]);
4863 
4864  if( SCIPisZero(scip, coefs[i]) )
4865  continue;
4866 
4867  if( SCIPisInfinity(scip, -coefs[i]) || SCIPisInfinity(scip, coefs[i]) )
4868  {
4869  SCIPdebugMessage("skip intgrad estimator because of infinite interval bound\n");
4870  goto INTGRADESTIMATOR_CLEANUP;
4871  }
4872 
4873  constant -= coefs[i] * val;
4874  }
4875 
4876  /* add interval gradient estimator to row */
4877  if( !SCIPisInfinity(scip, -SCIProwGetLhs(row)) )
4878  {
4879  SCIP_CALL( SCIPchgRowLhs(scip, row, SCIProwGetLhs(row) - constant) );
4880  }
4881  if( !SCIPisInfinity(scip, SCIProwGetRhs(row)) )
4882  {
4883  SCIP_CALL( SCIPchgRowRhs(scip, row, SCIProwGetRhs(row) - constant) );
4884  }
4885  SCIP_CALL( SCIPaddVarsToRow(scip, row, nvars, vars, coefs) );
4886 
4887  INTGRADESTIMATOR_CLEANUP:
4888  SCIPfreeBufferArrayNull(scip, &box);
4889  SCIPfreeBufferArrayNull(scip, &intgrad);
4890  SCIPfreeBufferArrayNull(scip, &coefs);
4891 
4892  return SCIP_OKAY;
4893 }
4894 
4895 /** generates a cut based on linearization (if convex), secant (if concave), or intervalgradient (if indefinite)
4896  */
4897 static
4899  SCIP* scip, /**< SCIP data structure */
4900  SCIP_EXPRINT* exprint, /**< expression interpreter */
4901  SCIP_CONS* cons, /**< constraint */
4902  SCIP_Real** ref, /**< reference point for each exprtree, or NULL if sol should be used */
4903  SCIP_SOL* sol, /**< reference solution where cut should be generated, or NULL if LP solution should be used */
4904  SCIP_Bool newsol, /**< whether the last evaluation of the expression with the expression interpreter was not at sol */
4905  SCIP_SIDETYPE side, /**< for which side a cut should be generated */
4906  SCIP_ROW** row, /**< storage for cut */
4907  SCIP_Real maxrange, /**< maximal range allowed */
4908  SCIP_Bool expensivecurvchecks,/**< whether also expensive checks should be executed */
4909  SCIP_Bool assumeconvex /**< whether to assume convexity in inequalities */
4910  )
4911 {
4912  char rowname[SCIP_MAXSTRLEN];
4913  SCIP_CONSDATA* consdata;
4914  SCIP_Bool success;
4915  SCIP_Real* x;
4916  int i;
4917 
4918  assert(scip != NULL);
4919  assert(cons != NULL);
4920  assert(row != NULL);
4921 
4922  SCIPdebugMessage("constructing cut for %s hand side of constraint <%s>\n", side == SCIP_SIDETYPE_LEFT ? "left" : "right", SCIPconsGetName(cons));
4923 
4924  SCIP_CALL( checkCurvature(scip, cons, expensivecurvchecks, assumeconvex) );
4925 
4926  consdata = SCIPconsGetData(cons);
4927  assert(consdata != NULL);
4928 
4929  if( consdata->nexprtrees == 0 )
4930  {
4931  (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%u", SCIPconsGetName(cons), ++(consdata->ncuts));
4932 
4933  /* if we are actually linear, add the constraint as row to the LP */
4934  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), rowname, consdata->lhs, consdata->rhs, SCIPconsIsLocal(cons), FALSE , TRUE) );
4935  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
4936  return SCIP_OKAY;
4937  }
4938 
4939  (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%u", SCIPconsGetName(cons), ++(consdata->ncuts));
4940  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), rowname,
4941  side == SCIP_SIDETYPE_LEFT ? consdata->lhs : -SCIPinfinity(scip),
4942  side == SCIP_SIDETYPE_RIGHT ? consdata->rhs : SCIPinfinity(scip),
4943  !(side == SCIP_SIDETYPE_LEFT && (consdata->curvature & SCIP_EXPRCURV_CONCAVE)) &&
4944  !(side == SCIP_SIDETYPE_RIGHT && (consdata->curvature & SCIP_EXPRCURV_CONVEX )),
4945  FALSE, TRUE) );
4946 
4947  if( ref == NULL )
4948  {
4949  SCIP_CALL( SCIPallocBufferArray(scip, &x, SCIPexprtreeGetNVars(consdata->exprtrees[0])) );
4950  }
4951 
4952  success = TRUE;
4953  for( i = 0; i < consdata->nexprtrees; ++i )
4954  {
4955  if( ref == NULL )
4956  {
4957  SCIP_CALL( SCIPreallocBufferArray(scip, &x, SCIPexprtreeGetNVars(consdata->exprtrees[i])) );
4958  SCIP_CALL( SCIPgetSolVals(scip, sol, SCIPexprtreeGetNVars(consdata->exprtrees[i]), SCIPexprtreeGetVars(consdata->exprtrees[i]), x) );
4959  }
4960  else
4961  {
4962  x = ref[i];
4963  }
4964 
4965  if( (side == SCIP_SIDETYPE_LEFT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONCAVE)) ||
4966  (side == SCIP_SIDETYPE_RIGHT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONVEX )) )
4967  {
4968  SCIP_CALL( addLinearization(scip, exprint, cons, i, x, newsol, *row, &success) );
4969  }
4970  else if( (side == SCIP_SIDETYPE_LEFT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONVEX)) ||
4971  ( side == SCIP_SIDETYPE_RIGHT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONCAVE)) )
4972  {
4973  switch( SCIPexprtreeGetNVars(consdata->exprtrees[i]) )
4974  {
4975  case 1:
4976  SCIP_CALL( addConcaveEstimatorUnivariate(scip, cons, i, *row, &success) );
4977  break;
4978 
4979  case 2:
4980  SCIP_CALL( addConcaveEstimatorBivariate(scip, cons, i, x, *row, &success) );
4981  break;
4982 
4983  default:
4984  SCIP_CALL( addConcaveEstimatorMultivariate(scip, cons, i, x, *row, &success) );
4985  break;
4986  }
4987  if( !success )
4988  {
4989  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);
4990  SCIP_CALL( addIntervalGradientEstimator(scip, exprint, cons, i, x, newsol, side == SCIP_SIDETYPE_LEFT, *row, &success) );
4991  }
4992  }
4993  else
4994  {
4995  SCIP_CALL( addIntervalGradientEstimator(scip, exprint, cons, i, x, newsol, side == SCIP_SIDETYPE_LEFT, *row, &success) );
4996  }
4997 
4998  if( !success )
4999  break;
5000  }
5001 
5002  if( ref == NULL )
5003  {
5004  SCIPfreeBufferArray(scip, &x);
5005  }
5006 
5007  /* check numerics */
5008  if( success )
5009  {
5010  SCIP_Real mincoef;
5011  SCIP_Real maxcoef;
5012 
5013  mincoef = SCIPgetRowMinCoef(scip, *row);
5014  maxcoef = SCIPgetRowMaxCoef(scip, *row);
5015 
5016  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
5017  mincoef = MIN(mincoef, consdata->lincoefsmin);
5018  maxcoef = MAX(maxcoef, consdata->lincoefsmax);
5019 
5020  while( maxcoef / mincoef > maxrange )
5021  {
5022  SCIP_VAR* var;
5023  SCIP_Real coef;
5024  SCIP_Real constant;
5025  int j;
5026 
5027  /* if range of coefficients is bad, find very small coefficients (from nonlinear vars) and make them zero */
5028  SCIPdebugMessage("cut coefficients for constraint <%s> have very large range: mincoef = %g maxcoef = %g\n", SCIPconsGetName(cons), mincoef, maxcoef);
5029 
5030  /* if minimal coefficient is given by linear var, then give up (probably the maximal coefficient is the problem) */
5031  if( mincoef == consdata->lincoefsmin ) /*lint !e777*/
5032  {
5033  SCIPdebugMessage("could not eliminate small coefficient, since it comes from linear part\n");
5034  break;
5035  }
5036 
5037  constant = 0.0;
5038  for( j = 0; j < SCIProwGetNNonz(*row); ++j )
5039  {
5040  coef = SCIProwGetVals(*row)[j];
5041  if( !SCIPisEQ(scip, REALABS(coef), mincoef) )
5042  continue;
5043 
5044  var = SCIPcolGetVar(SCIProwGetCols(*row)[j]);
5045  assert(var != NULL);
5046 
5047  /* try to eliminate coefficient with minimal absolute value by weakening cut and try again */
5048  if( ((coef > 0.0 && side == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && side == SCIP_SIDETYPE_LEFT)) &&
5049  !SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
5050  {
5051  SCIPdebugMessage("eliminate coefficient %g for <%s> = %g [%g, %g]\n", coef, SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
5052 
5053  constant += coef * (SCIProwIsLocal(*row) ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var));
5054  SCIP_CALL( SCIPaddVarToRow(scip, *row, var, -coef) );
5055  continue;
5056  }
5057 
5058  if( ((coef < 0.0 && side == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && side == SCIP_SIDETYPE_LEFT)) &&
5059  !SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
5060  {
5061  SCIPdebugMessage("eliminate coefficient %g for <%s> = %g [%g, %g]\n", coef, SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
5062 
5063  constant += coef * (SCIProwIsLocal(*row) ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var));
5064  SCIP_CALL( SCIPaddVarToRow(scip, *row, var, -coef) );
5065  continue;
5066  }
5067 
5068  break;
5069  }
5070 
5071  if( j < SCIProwGetNNonz(*row) )
5072  {
5073  SCIPdebugMessage("could not eliminate small coefficient\n");
5074  success = FALSE;
5075  break;
5076  }
5077 
5078  if( side == SCIP_SIDETYPE_LEFT )
5079  {
5080  SCIP_CALL( SCIPchgRowLhs(scip, *row, SCIProwGetLhs(*row) - constant) );
5081  }
5082  else
5083  {
5084  SCIP_CALL( SCIPchgRowRhs(scip, *row, SCIProwGetRhs(*row) - constant) );
5085  }
5086 
5087  /* update min/max coefficient */
5088  mincoef = SCIPgetRowMinCoef(scip, *row);
5089  maxcoef = SCIPgetRowMaxCoef(scip, *row);
5090 
5091  mincoef = MIN(mincoef, consdata->lincoefsmin);
5092  maxcoef = MAX(maxcoef, consdata->lincoefsmax);
5093  };
5094 
5095  /* avoid numerically very bad cuts */
5096  if( maxcoef / mincoef > maxrange )
5097  {
5098  SCIPdebugMessage("drop row for constraint <%s> because range of coefficients is too large: mincoef = %g, maxcoef = %g -> range = %g\n",
5099  SCIPconsGetName(cons), mincoef, maxcoef, maxcoef / mincoef);
5100  success = FALSE;
5101  }
5102  }
5103 
5104  if( success &&
5105  (( side == SCIP_SIDETYPE_LEFT && SCIPisInfinity(scip, -SCIProwGetLhs(*row))) ||
5106  (side == SCIP_SIDETYPE_RIGHT && SCIPisInfinity(scip, SCIProwGetRhs(*row)))) )
5107  {
5108  SCIPdebugMessage("drop row for constraint <%s> because of very large side: %g\n", SCIPconsGetName(cons), side == SCIP_SIDETYPE_LEFT ? -SCIProwGetLhs(*row) : SCIProwGetRhs(*row));
5109  success = FALSE;
5110  }
5111 
5112  if( !success )
5113  {
5114  SCIP_CALL( SCIPreleaseRow(scip, row) );
5115  return SCIP_OKAY;
5116  }
5117 
5118  /* add coefficients for linear variables */
5119  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
5120 
5121  return SCIP_OKAY;
5122 }
5123 
5124 /** tries to separate solution or LP solution by a linear cut
5125  *
5126  * assumes that constraint violations have been computed
5127  */
5128 static
5130  SCIP* scip, /**< SCIP data structure */
5131  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
5132  SCIP_CONS** conss, /**< constraints */
5133  int nconss, /**< number of constraints */
5134  int nusefulconss, /**< number of constraints that seem to be useful */
5135  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
5136  SCIP_Bool newsol, /**< have the constraints just been evaluated at this point? */
5137  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
5138  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
5139  SCIP_RESULT* result, /**< result of separation */
5140  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 */
5141  )
5142 {
5143  SCIP_CONSHDLRDATA* conshdlrdata;
5144  SCIP_CONSDATA* consdata;
5145  SCIP_Real efficacy;
5146  SCIP_Real feasibility;
5147  SCIP_Real norm;
5148  SCIP_SIDETYPE violside;
5149  int c;
5150  SCIP_ROW* row;
5151 
5152  assert(scip != NULL);
5153  assert(conshdlr != NULL);
5154  assert(conss != NULL || nconss == 0);
5155  assert(nusefulconss <= nconss);
5156  assert(result != NULL);
5157 
5158  *result = SCIP_FEASIBLE;
5159 
5160  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5161  assert(conshdlrdata != NULL);
5162 
5163  if( bestefficacy != NULL )
5164  *bestefficacy = 0.0;
5165 
5166  for( c = 0; c < nconss; ++c )
5167  {
5168  assert(conss != NULL);
5169 
5170  /* skip constraints that are not enabled */
5171  if( !SCIPconsIsEnabled(conss[c]) )
5172  continue;
5173  assert(SCIPconsIsActive(conss[c]));
5174 
5175  consdata = SCIPconsGetData(conss[c]);
5176  assert(consdata != NULL);
5177 
5178  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5179  {
5180  /* we are not feasible anymore */
5181  if( *result == SCIP_FEASIBLE )
5182  *result = SCIP_DIDNOTFIND;
5183 
5184  violside = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT;
5185 
5186  /* generate cut
5187  * if function is defined at sol (activity<infinity) and constraint is violated, then expression interpreter should have evaluated at sol to get gradient before
5188  */
5189  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], NULL, sol, newsol || SCIPisInfinity(scip, consdata->activity), violside, &row, conshdlrdata->cutmaxrange, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
5190 
5191  if( row == NULL ) /* failed to generate cut */
5192  continue;
5193 
5194  if( sol == NULL )
5195  feasibility = SCIPgetRowLPFeasibility(scip, row);
5196  else
5197  feasibility = SCIPgetRowSolFeasibility(scip, row, sol);
5198 
5199  switch( conshdlrdata->scaling )
5200  {
5201  case 'o' :
5202  efficacy = -feasibility;
5203  break;
5204 
5205  case 'g' :
5206  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
5207  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too also
5208  * we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
5209  * scaling) */
5210  norm = SCIPgetRowMaxCoef(scip, row);
5211  efficacy = -feasibility / MAX(1.0, norm);
5212  break;
5213 
5214  case 's' :
5215  {
5216  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
5217  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
5218  SCIP_Real minval = MIN(abslhs, absrhs);
5219 
5220  efficacy = -feasibility / MAX(1.0, minval);
5221  break;
5222  }
5223 
5224  default:
5225  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
5226  SCIPABORT();
5227  return SCIP_INVALIDDATA; /*lint !e527*/
5228  }
5229 
5230  if( (SCIPisGT(scip, efficacy, minefficacy) ||
5231  (inenforcement &&
5232  ( (violside == SCIP_SIDETYPE_RIGHT && (consdata->curvature & SCIP_EXPRCURV_CONVEX )) ||
5233  (violside == SCIP_SIDETYPE_LEFT && (consdata->curvature & SCIP_EXPRCURV_CONCAVE)) ) &&
5234  SCIPisGT(scip, efficacy, SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip))
5235  )
5236  ) && SCIPisCutApplicable(scip, row)
5237  )
5238  {
5239  SCIP_Bool infeasible;
5240 
5241  /* cut cuts off solution */
5242  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE /* forcecut */, &infeasible) );
5243  if ( infeasible )
5244  *result = SCIP_CUTOFF;
5245  else
5246  *result = SCIP_SEPARATED;
5247 
5248  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
5249 
5250  SCIPdebugMessage("add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy, SCIPconsGetName(conss[c]), MAX(consdata->lhsviol, consdata->rhsviol));
5251  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
5252 
5253  if( bestefficacy != NULL && efficacy > *bestefficacy )
5254  *bestefficacy = efficacy;
5255 
5256  /* mark row as not removable from LP for current node, if in enforcement */
5257  if( inenforcement && !conshdlrdata->enfocutsremovable )
5258  SCIPmarkRowNotRemovableLocal(scip, row);
5259  }
5260  else
5261  {
5262  SCIPdebugMessage("drop cut since efficacy %g is too small (< %g)\n", efficacy, minefficacy);
5263  }
5264 
5265  SCIP_CALL( SCIPreleaseRow (scip, &row) );
5266  }
5267 
5268  if ( *result == SCIP_CUTOFF )
5269  break;
5270 
5271  /* enforce only useful constraints
5272  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
5273  */
5274  if( c >= nusefulconss && *result == SCIP_SEPARATED )
5275  break;
5276  }
5277 
5278  return SCIP_OKAY;
5279 }
5280 
5281 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
5282  * 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
5283  * if separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only
5284  * if separatedlpsol is NULL, then cut is added to cutpool only
5285  */
5286 static
5288  SCIP* scip, /**< SCIP data structure */
5289  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
5290  SCIP_CONS** conss, /**< constraints */
5291  int nconss, /**< number of constraints */
5292  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
5293  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 */
5294  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
5295  )
5296 {
5297  SCIP_CONSHDLRDATA* conshdlrdata;
5298  SCIP_CONSDATA* consdata;
5299  SCIP_Bool addedtolp;
5300  SCIP_ROW* row;
5301  int c;
5302 
5303  assert(scip != NULL);
5304  assert(conshdlr != NULL);
5305  assert(conss != NULL || nconss == 0);
5306 
5307  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5308  assert(conshdlrdata != NULL);
5309 
5310  if( separatedlpsol != NULL )
5311  *separatedlpsol = FALSE;
5312 
5313  for( c = 0; c < nconss; ++c )
5314  {
5315  assert(conss[c] != NULL); /*lint !e613*/
5316 
5317  if( SCIPconsIsLocal(conss[c]) ) /*lint !e613*/
5318  continue;
5319 
5320  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) ); /*lint !e613*/
5321 
5322  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
5323  assert(consdata != NULL);
5324 
5325  /* if we cannot linearize, then skip constraint */
5326  if( (!(consdata->curvature & SCIP_EXPRCURV_CONVEX) || SCIPisInfinity(scip, consdata->rhs)) &&
5327  ( !(consdata->curvature & SCIP_EXPRCURV_CONCAVE) || SCIPisInfinity(scip, -consdata->lhs)) )
5328  continue;
5329 
5330  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], NULL, ref, TRUE,
5332  &row, conshdlrdata->cutmaxrange, FALSE, FALSE) ); /*lint !e613*/
5333 
5334  if( row == NULL )
5335  continue;
5336 
5337  addedtolp = FALSE;
5338 
5339  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
5340  if( separatedlpsol != NULL )
5341  {
5342  SCIP_Real efficacy;
5343  SCIP_Real norm;
5344 
5345  efficacy = -SCIPgetRowLPFeasibility(scip, row);
5346  switch( conshdlrdata->scaling )
5347  {
5348  case 'o' :
5349  break;
5350 
5351  case 'g' :
5352  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
5353  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too also
5354  * we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
5355  * scaling) */
5356  norm = SCIPgetRowMaxCoef(scip, row);
5357  efficacy /= MAX(1.0, norm);
5358  break;
5359 
5360  case 's' :
5361  {
5362  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
5363  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
5364  SCIP_Real minval = MIN(abslhs, absrhs);
5365 
5366  efficacy /= MAX(1.0, minval);
5367  break;
5368  }
5369  default:
5370  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
5371  SCIPABORT();
5372  return SCIP_INVALIDDATA; /*lint !e527*/
5373  }
5374 
5375  if( efficacy >= minefficacy )
5376  {
5377  SCIP_Bool infeasible;
5378 
5379  *separatedlpsol = TRUE;
5380  addedtolp = TRUE;
5381  SCIP_CALL( SCIPaddCut(scip, NULL, row, TRUE, &infeasible) );
5382  assert( ! infeasible );
5383  }
5384  }
5385 
5386  if( !SCIProwIsLocal(row) && !addedtolp )
5387  {
5388  SCIP_CALL( SCIPaddPoolCut(scip, row) );
5389  }
5390 
5391  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5392  }
5393 
5394  return SCIP_OKAY;
5395 }
5396 
5397 /** processes the event that a new primal solution has been found */
5398 static
5399 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
5400 {
5401  SCIP_CONSHDLRDATA* conshdlrdata;
5402  SCIP_CONSHDLR* conshdlr;
5403  SCIP_CONS** conss;
5404  int nconss;
5405  SCIP_SOL* sol;
5406 
5407  assert(scip != NULL);
5408  assert(event != NULL);
5409  assert(eventdata != NULL);
5410  assert(eventhdlr != NULL);
5411 
5412  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
5413 
5414  conshdlr = (SCIP_CONSHDLR*)eventdata;
5415 
5416  nconss = SCIPconshdlrGetNConss(conshdlr);
5417 
5418  if( nconss == 0 )
5419  return SCIP_OKAY;
5420 
5421  sol = SCIPeventGetSol(event);
5422  assert(sol != NULL);
5423 
5424  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5425  assert(conshdlrdata != NULL);
5426 
5427  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
5428  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
5429  * or are from the tree, but postprocessed via proposeFeasibleSolution
5430  */
5431  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
5432  return SCIP_OKAY;
5433 
5434  conss = SCIPconshdlrGetConss(conshdlr);
5435  assert(conss != NULL);
5436 
5437  SCIPdebugMessage("catched new sol event %x from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
5438 
5439  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
5440 
5441  return SCIP_OKAY;
5442 }
5443 
5444 /** registers unfixed variables in nonlinear terms of violated constraints as external branching candidates */
5445 static
5447  SCIP* scip, /**< SCIP data structure */
5448  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5449  SCIP_CONS** conss, /**< constraints to check */
5450  int nconss, /**< number of constraints to check */
5451  int* nnotify /**< counter for number of notifications performed */
5452  )
5453 {
5454  SCIP_CONSDATA* consdata;
5455  SCIP_VAR* var;
5456  int c;
5457  int i;
5458  int j;
5459 
5460  assert(scip != NULL);
5461  assert(conshdlr != NULL);
5462  assert(conss != NULL || nconss == 0);
5463 
5464  *nnotify = 0;
5465 
5466  for( c = 0; c < nconss; ++c )
5467  {
5468  assert(conss != NULL);
5469  consdata = SCIPconsGetData(conss[c]);
5470  assert(consdata != NULL);
5471 
5472  if( consdata->nexprtrees == 0 )
5473  continue;
5474 
5475  /* do not branch on violation of convex constraint */
5476  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || (consdata->curvature & SCIP_EXPRCURV_CONCAVE)) &&
5477  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || (consdata->curvature & SCIP_EXPRCURV_CONVEX )) )
5478  continue;
5479  SCIPdebugMessage("cons <%s> violation: %g %g curvature: %s\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, SCIPexprcurvGetName(consdata->curvature));
5480 
5481  for( i = 0; i < consdata->nexprtrees; ++i )
5482  {
5483  /* skip convex summands */
5484  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || (consdata->curvatures[i] & SCIP_EXPRCURV_CONCAVE)) &&
5485  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || (consdata->curvatures[i] & SCIP_EXPRCURV_CONVEX )) )
5486  continue;
5487 
5488  for( j = 0; j < SCIPexprtreeGetNVars(consdata->exprtrees[i]); ++j )
5489  {
5490  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[j];
5491  assert(var != NULL);
5492 
5493  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
5494  {
5495  SCIPdebugMessage("ignore fixed variable <%s>[%g, %g], width %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
5496  continue;
5497  }
5498 
5499  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
5500  ++*nnotify;
5501  }
5502  }
5503  }
5504 
5505  SCIPdebugMessage("registered %d branching candidates\n", *nnotify);
5506 
5507  return SCIP_OKAY;
5508 }
5509 
5510 /** registers a nonlinear variable from a violated constraint as branching candidate that has a large absolute value in the LP relaxation */
5511 static
5513  SCIP* scip, /**< SCIP data structure */
5514  SCIP_CONS** conss, /**< constraints */
5515  int nconss, /**< number of constraints */
5516  SCIP_VAR** brvar /**< buffer to store branching variable */
5517  )
5518 {
5519  SCIP_CONSDATA* consdata;
5520  SCIP_VAR* var;
5521  SCIP_Real val;
5522  SCIP_Real brvarval;
5523  int i;
5524  int j;
5525  int c;
5526 
5527  assert(scip != NULL);
5528  assert(conss != NULL || nconss == 0);
5529 
5530  *brvar = NULL;
5531  brvarval = -1.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( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5540  continue;
5541 
5542  for( j = 0; j < consdata->nexprtrees; ++j )
5543  {
5544  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]); ++i )
5545  {
5546  var = SCIPexprtreeGetVars(consdata->exprtrees[j])[i];
5547  /* do not propose fixed variables */
5548  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
5549  continue;
5550  val = SCIPgetSolVal(scip, NULL, var);
5551  if( REALABS(val) > brvarval )
5552  {
5553  brvarval = ABS(val);
5554  *brvar = var;
5555  }
5556  }
5557  }
5558  }
5559 
5560  if( *brvar != NULL )
5561  {
5562  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
5563  }
5564 
5565  return SCIP_OKAY;
5566 }
5567 
5568 /** replaces violated nonlinear constraints where all nonlinear variables are fixed by linear constraints
5569  * only adds constraint if it is violated in current solution
5570  */
5571 static
5573  SCIP* scip, /**< SCIP data structure */
5574  SCIP_CONS** conss, /**< constraints */
5575  int nconss, /**< number of constraints */
5576  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
5577  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
5578  SCIP_Bool* infeasible /**< whether we detected infeasibility */
5579  )
5580 {
5581  SCIP_CONS* cons;
5582  SCIP_CONSDATA* consdata;
5583  SCIP_Real lhs;
5584  SCIP_Real rhs;
5585  SCIP_RESULT checkresult;
5586  int c;
5587  int i;
5588 
5589  assert(scip != NULL);
5590  assert(conss != NULL || nconss == 0);
5591  assert(addedcons != NULL);
5592  assert(reduceddom != NULL);
5593  assert(infeasible != NULL);
5594 
5595  *addedcons = FALSE;
5596  *reduceddom = FALSE;
5597  *infeasible = FALSE;
5598 
5599  for( c = 0; c < nconss; ++c )
5600  {
5601  assert(conss != NULL);
5602  consdata = SCIPconsGetData(conss[c]);
5603  assert(consdata != NULL);
5604 
5605  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5606  continue;
5607 
5608  lhs = consdata->lhs;
5609  rhs = consdata->rhs;
5610 
5611  for( i = 0; i < consdata->nexprtrees; ++i )
5612  {
5613  SCIP_INTERVAL nonlinactivity;
5614 
5615  SCIP_CALL( SCIPevalExprtreeLocalBounds(scip, consdata->exprtrees[i], INTERVALINFTY, &nonlinactivity) );
5616  assert(SCIPintervalGetInf(nonlinactivity) > -INTERVALINFTY);
5617  assert(SCIPintervalGetSup(nonlinactivity) < INTERVALINFTY);
5618  SCIPintervalMulScalar(INTERVALINFTY, &nonlinactivity, nonlinactivity, consdata->nonlincoefs[i]);
5619 
5620  if( !SCIPisInfinity(scip, -lhs) )
5621  lhs -= SCIPintervalGetSup(nonlinactivity);
5622 
5623  if( !SCIPisInfinity(scip, rhs) )
5624  rhs -= SCIPintervalGetInf(nonlinactivity);
5625  }
5626 
5627  /* check if we have a bound change */
5628  if ( consdata->nlinvars == 0 )
5629  {
5630  assert(SCIPisFeasLE(scip, lhs, rhs));
5631  }
5632  else if ( consdata->nlinvars == 1 )
5633  {
5634  SCIP_Bool tightened;
5635  SCIP_Real coef;
5636 
5637  coef = *consdata->lincoefs;
5638  SCIPdebugMessage("Linear constraint with one variable: %g <= %g <%s> <= %g\n", lhs, coef, SCIPvarGetName(*consdata->linvars), rhs);
5639 
5640  /* possibly correct lhs/rhs */
5641  assert( ! SCIPisZero(scip, coef) );
5642  if ( coef >= 0.0 )
5643  {
5644  if ( ! SCIPisInfinity(scip, -lhs) )
5645  lhs /= coef;
5646  if ( ! SCIPisInfinity(scip, rhs) )
5647  rhs /= coef;
5648  }
5649  else
5650  {
5651  SCIP_Real h;
5652  h = rhs;
5653  if ( ! SCIPisInfinity(scip, -lhs) )
5654  rhs = lhs/coef;
5655  else
5656  rhs = SCIPinfinity(scip);
5657 
5658  if ( ! SCIPisInfinity(scip, h) )
5659  lhs = h/coef;
5660  else
5661  lhs = -SCIPinfinity(scip);
5662  }
5663  SCIPdebugMessage("Linear constraint is a bound: %g <= <%s> <= %g\n", lhs, SCIPvarGetName(*consdata->linvars), rhs);
5664 
5665  if ( ! SCIPisInfinity(scip, -lhs) )
5666  {
5667  SCIP_CALL( SCIPtightenVarLb(scip, *consdata->linvars, lhs, TRUE, infeasible, &tightened) );
5668  if ( *infeasible )
5669  {
5670  SCIPdebugMessage("Lower bound leads to infeasibility.\n");
5671  return SCIP_OKAY;
5672  }
5673  if ( tightened )
5674  {
5675  SCIPdebugMessage("Lower bound changed.\n");
5676  *reduceddom = TRUE;
5677  return SCIP_OKAY;
5678  }
5679  }
5680 
5681  if ( ! SCIPisInfinity(scip, rhs) )
5682  {
5683  SCIP_CALL( SCIPtightenVarUb(scip, *consdata->linvars, rhs, TRUE, infeasible, &tightened) );
5684  if ( *infeasible )
5685  {
5686  SCIPdebugMessage("Upper bound leads to infeasibility.\n");
5687  return SCIP_OKAY;
5688  }
5689  if ( tightened )
5690  {
5691  SCIPdebugMessage("Upper bound changed.\n");
5692  *reduceddom = TRUE;
5693  return SCIP_OKAY;
5694  }
5695  }
5696  }
5697  else
5698  {
5699  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
5700  consdata->nlinvars, consdata->linvars, consdata->lincoefs, lhs, rhs,
5701  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
5702  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
5703  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
5704  SCIPconsIsStickingAtNode(conss[c])) );
5705 
5706  SCIPdebugMessage("replace violated nonlinear constraint <%s> by linear constraint after all nonlinear vars have been fixed\n", SCIPconsGetName(conss[c]) );
5707  SCIPdebugPrintCons(scip, conss[c], NULL);
5708  SCIPdebugPrintCons(scip, cons, NULL);
5709 
5710  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
5711 
5712  if( checkresult != SCIP_INFEASIBLE )
5713  {
5714  SCIPdebugMessage("linear constraint is feasible, thus do not add\n");
5715  }
5716  else
5717  {
5718  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
5719  *addedcons = TRUE;
5720  }
5721  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
5722  }
5723  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
5724  }
5725 
5726  return SCIP_OKAY;
5727 }
5728 
5729 /* tightens a lower bound on a variable and checks the result */
5730 static
5732  SCIP* scip, /**< SCIP data structure */
5733  SCIP_CONS* cons, /**< constraint where we currently propagate, or NULL if tightening is from expression graph */
5734  SCIP_VAR* var, /**< variable which domain we might reduce */
5735  SCIP_Real bnd, /**< new lower bound for variable */
5736  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
5737  int* nchgbds /**< counter to increase if a bound was tightened */
5738  )
5739 {
5740  SCIP_Bool infeas;
5741  SCIP_Bool tightened;
5742 
5743  assert(scip != NULL);
5744  assert(bnd > -INTERVALINFTY);
5745  assert(var != NULL);
5746  assert(result != NULL);
5747  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
5748  assert(nchgbds != NULL);
5749 
5750  if( SCIPisInfinity(scip, bnd) )
5751  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
5752  *result = SCIP_CUTOFF;
5753  if( cons != NULL )
5754  {
5755  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5756  }
5757  return SCIP_OKAY;
5758  }
5759 
5760  /* new lower bound is very low (between -INTERVALINFTY and -SCIPinfinity()) */
5761  if( SCIPisInfinity(scip, -bnd) )
5762  return SCIP_OKAY;
5763 
5764  bnd = SCIPadjustedVarLb(scip, var, bnd);
5765  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
5766  if( infeas )
5767  {
5768  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*/
5769  *result = SCIP_CUTOFF;
5770  if( cons != NULL )
5771  {
5772  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5773  }
5774  return SCIP_OKAY;
5775  }
5776  if( tightened )
5777  {
5778  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*/
5779  ++*nchgbds;
5780  *result = SCIP_REDUCEDDOM;
5781  if( cons != NULL )
5782  {
5783  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5784  }
5785  }
5786 
5787  return SCIP_OKAY;
5788 }
5789 
5790 /* tightens an upper bound on a variable and checks the result */
5791 static
5793  SCIP* scip, /**< SCIP data structure */
5794  SCIP_CONS* cons, /**< constraint where we currently propagate, or NULL if tightening is from expression graph */
5795  SCIP_VAR* var, /**< variable which domain we might reduce */
5796  SCIP_Real bnd, /**< new upper bound for variable */
5797  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
5798  int* nchgbds /**< counter to increase if a bound was tightened */
5799  )
5800 {
5801  SCIP_Bool infeas;
5802  SCIP_Bool tightened;
5803 
5804  assert(scip != NULL);
5805  assert(bnd < INTERVALINFTY);
5806  assert(var != NULL);
5807  assert(result != NULL);
5808  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
5809  assert(nchgbds != NULL);
5810 
5811  if( SCIPisInfinity(scip, -bnd) )
5812  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
5813  *result = SCIP_CUTOFF;
5814  if( cons != NULL )
5815  {
5816  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5817  }
5818  return SCIP_OKAY;
5819  }
5820 
5821  /* new upper bound is very high (between SCIPinfinity() and INTERVALINFTY) */
5822  if( SCIPisInfinity(scip, bnd) )
5823  return SCIP_OKAY;
5824 
5825  bnd = SCIPadjustedVarUb(scip, var, bnd);
5826  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
5827  if( infeas )
5828  {
5829  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*/
5830  *result = SCIP_CUTOFF;
5831  if( cons != NULL )
5832  {
5833  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5834  }
5835  return SCIP_OKAY;
5836  }
5837  if( tightened )
5838  {
5839  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*/
5840  ++*nchgbds;
5841  *result = SCIP_REDUCEDDOM;
5842  if( cons != NULL )
5843  {
5844  SCIP_CALL( SCIPresetConsAge(scip, cons) );
5845  }
5846  }
5847 
5848  return SCIP_OKAY;
5849 }
5850 
5851 /** tightens bounds of linear variables in a single nonlinear constraint */
5852 static
5854  SCIP* scip, /**< SCIP data structure */
5855  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5856  SCIP_CONS* cons, /**< constraint to process */
5857  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
5858  int* nchgbds, /**< buffer where to add the the number of changed bounds */
5859  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
5860  )
5861 { /*lint --e{666}*/
5862  SCIP_CONSDATA* consdata;
5863  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
5864  SCIP_INTERVAL consactivity; /* activity of linear plus nonlinear part */
5865  SCIP_VAR* var;
5866  SCIP_INTERVAL rhs; /* right hand side of nonlinear equation */
5867  SCIP_ROUNDMODE roundmode;
5868  SCIP_Real bnd;
5869  int i;
5870  SCIP_INTERVAL nonlinactivity;
5871 
5872  assert(scip != NULL);
5873  assert(conshdlr != NULL);
5874  assert(cons != NULL);
5875  assert(result != NULL);
5876  assert(nchgbds != NULL);
5877 
5878  consdata = SCIPconsGetData(cons);
5879  assert(consdata != NULL);
5880 
5881  *result = SCIP_DIDNOTRUN;
5882  *redundant = FALSE;
5883 
5884  if( consdata->ispropagated )
5885  return SCIP_OKAY;
5886 
5887  *result = SCIP_DIDNOTFIND;
5888 
5889  SCIPdebugMessage("start linear vars domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
5890 
5891  consdata->ispropagated = TRUE;
5892 
5893  /* make sure we have activity of linear term */
5894  consdataUpdateLinearActivity(scip, consdata);
5895  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777*/
5896  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777*/
5897  assert(consdata->minlinactivityinf >= 0);
5898  assert(consdata->maxlinactivityinf >= 0);
5899  assert(consdata->exprgraphnode != NULL || consdata->nexprtrees == 0);
5900 
5901  /* get activity of nonlinear part, should have been updated in propagateBounds */
5902  if( consdata->exprgraphnode != NULL )
5903  {
5904  nonlinactivity = SCIPexprgraphGetNodeBounds(consdata->exprgraphnode);
5905  }
5906  else
5907  {
5908  SCIPintervalSet(&nonlinactivity, 0.0);
5909  }
5910  assert(!SCIPintervalIsEmpty(nonlinactivity) );
5911 
5912  /* @todo adding SCIPepsilon may be sufficient? */
5913  SCIPintervalSetBounds(&consbounds,
5914  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -consdata->lhs + SCIPfeastol(scip)),
5915  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, consdata->rhs + SCIPfeastol(scip)));
5916 
5917  /* check redundancy and infeasibility */
5918  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -INTERVALINFTY : consdata->minlinactivity, consdata->maxlinactivityinf > 0 ? INTERVALINFTY : consdata->maxlinactivity);
5919  SCIPintervalAdd(INTERVALINFTY, &consactivity, consactivity, nonlinactivity);
5920  if( SCIPintervalIsSubsetEQ(INTERVALINFTY, consactivity, consbounds) )
5921  {
5922  SCIPdebugMessage("found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
5923  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
5924  *redundant = TRUE;
5925  return SCIP_OKAY;
5926  }
5927 
5928  if( SCIPintervalAreDisjoint(consbounds, consactivity) )
5929  {
5930  SCIPdebugMessage("found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %.20g\n",
5931  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
5932  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
5933  *result = SCIP_CUTOFF;
5934  return SCIP_OKAY;
5935  }
5936 
5937  /* propagate linear part in rhs = consbounds - nonlinactivity (use the one from consdata, since that includes infinities) */
5938  SCIPintervalSub(INTERVALINFTY, &rhs, consbounds, nonlinactivity);
5939  if( !SCIPintervalIsEntire(INTERVALINFTY, rhs) )
5940  {
5941  SCIP_Real coef;
5942 
5943  for( i = 0; i < consdata->nlinvars; ++i )
5944  {
5945  coef = consdata->lincoefs[i];
5946  var = consdata->linvars[i];
5947 
5948  /* skip fixed variables
5949  * @todo is that a good or a bad idea?
5950  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
5951  */
5952  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
5953  continue;
5954 
5955  if( coef > 0.0 )
5956  {
5957  if( SCIPintervalGetSup(rhs) < INTERVALINFTY )
5958  {
5959  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777*/
5960  /* try to tighten the upper bound on var x */
5961  if( consdata->minlinactivityinf == 0 )
5962  {
5963  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
5964  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
5965  roundmode = SCIPintervalGetRoundingMode();
5967  bnd = SCIPintervalGetSup(rhs);
5968  bnd -= consdata->minlinactivity;
5969  bnd += coef * SCIPvarGetLbLocal(var);
5970  bnd /= coef;
5971  SCIPintervalSetRoundingMode(roundmode);
5972  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
5973  if( *result == SCIP_CUTOFF )
5974  break;
5975  }
5976  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
5977  {
5978  /* x was the variable that made the minimal linear activity equal -infinity, so
5979  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
5980  roundmode = SCIPintervalGetRoundingMode();
5982  bnd = SCIPintervalGetSup(rhs);
5983  bnd -= consdata->minlinactivity;
5984  bnd /= coef;
5985  SCIPintervalSetRoundingMode(roundmode);
5986  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
5987  if( *result == SCIP_CUTOFF )
5988  break;
5989  }
5990  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
5991  }
5992 
5993  if( SCIPintervalGetInf(rhs) > -INTERVALINFTY )
5994  {
5995  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777*/
5996  /* try to tighten the lower bound on var x */
5997  if( consdata->maxlinactivityinf == 0 )
5998  {
5999  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
6000  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
6001  roundmode = SCIPintervalGetRoundingMode();
6003  bnd = SCIPintervalGetInf(rhs);
6004  bnd -= consdata->maxlinactivity;
6005  bnd += coef * SCIPvarGetUbLocal(var);
6006  bnd /= coef;
6007  SCIPintervalSetRoundingMode(roundmode);
6008  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6009  if( *result == SCIP_CUTOFF )
6010  break;
6011  }
6012  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6013  {
6014  /* x was the variable that made the maximal linear activity equal infinity, so
6015  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
6016  roundmode = SCIPintervalGetRoundingMode();
6018  bnd = SCIPintervalGetInf(rhs);
6019  bnd -= consdata->maxlinactivity;
6020  bnd /= coef;
6021  SCIPintervalSetRoundingMode(roundmode);
6022  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6023  if( *result == SCIP_CUTOFF )
6024  break;
6025  }
6026  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
6027  }
6028  }
6029  else
6030  {
6031  assert(coef < 0.0 );
6032  if( SCIPintervalGetInf(rhs) > -INTERVALINFTY )
6033  {
6034  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777*/
6035  /* try to tighten the upper bound on var x */
6036  if( consdata->maxlinactivityinf == 0 )
6037  {
6038  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
6039  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
6040  roundmode = SCIPintervalGetRoundingMode();
6042  bnd = consdata->maxlinactivity;
6043  bnd += (-coef) * SCIPvarGetLbLocal(var);
6044  bnd -= SCIPintervalGetInf(rhs);
6045  bnd /= (-coef);
6046  SCIPintervalSetRoundingMode(roundmode);
6047  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
6048  if( *result == SCIP_CUTOFF )
6049  break;
6050  }
6051  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
6052  {
6053  /* x was the variable that made the maximal linear activity equal infinity, so
6054  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
6055  roundmode = SCIPintervalGetRoundingMode();
6057  bnd = consdata->maxlinactivity;
6058  bnd -= SCIPintervalGetInf(rhs);
6059  bnd /= (-coef);
6060  SCIPintervalSetRoundingMode(roundmode);
6061  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
6062  if( *result == SCIP_CUTOFF )
6063  break;
6064  }
6065  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
6066  }
6067 
6068  if( SCIPintervalGetSup(rhs) < INTERVALINFTY )
6069  {
6070  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777*/
6071  /* try to tighten the lower bound on var x */
6072  if( consdata->minlinactivityinf == 0 )
6073  {
6074  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
6075  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
6076  roundmode = SCIPintervalGetRoundingMode();
6078  bnd = consdata->minlinactivity;
6079  bnd += (-coef) * SCIPvarGetUbLocal(var);
6080  bnd -= SCIPintervalGetSup(rhs);
6081  bnd /= (-coef);
6082  SCIPintervalSetRoundingMode(roundmode);
6083  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6084  if( *result == SCIP_CUTOFF )
6085  break;
6086  }
6087  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6088  {
6089  /* x was the variable that made the maximal linear activity equal -infinity, so
6090  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
6091  roundmode = SCIPintervalGetRoundingMode();
6093  bnd = consdata->minlinactivity;
6094  bnd -= SCIPintervalGetSup(rhs);
6095  bnd /= (-coef);
6096  SCIPintervalSetRoundingMode(roundmode);
6097  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6098  if( *result == SCIP_CUTOFF )
6099  break;
6100  }
6101  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
6102  }
6103  }
6104  }
6105  if( *result == SCIP_CUTOFF )
6106  return SCIP_OKAY;
6107  }
6108 
6109  return SCIP_OKAY;
6110 }
6111 
6112 /** propagate constraints sides minus linear activity into nonlinear variables */
6113 static
6115  SCIP* scip, /**< SCIP data structure */
6116  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6117  SCIP_CONS** conss, /**< constraints to process */
6118  int nconss, /**< number of constraints */
6119  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
6120  int* nchgbds /**< buffer where to add the number of changed bounds */
6121  )
6122 {
6123  SCIP_CONSHDLRDATA* conshdlrdata;
6124  SCIP_CONSDATA* consdata;
6125  int nvars;
6126  SCIP_VAR** vars;
6127  SCIP_EXPRGRAPHNODE** varnodes;
6128  SCIP_INTERVAL bounds;
6129  SCIP_Bool cutoff;
6130  SCIP_ROUNDMODE roundmode;
6131  int c;
6132  int i;
6133 
6134  assert(scip != NULL);
6135  assert(conshdlr != NULL);
6136  assert(result != NULL);
6137  assert(nchgbds != NULL);
6138 
6139  *result = SCIP_DIDNOTFIND;
6140 
6141  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6142  assert(conshdlrdata != NULL);
6143  assert(conshdlrdata->exprgraph != NULL);
6144 
6145  SCIPdebugMessage("start backward propagation in expression graph\n");
6146 
6147 #ifdef SCIP_OUTPUT
6148  {
6149  FILE* file;
6150  file = fopen("exprgraph_propconss1.dot", "w");
6151  if( file != NULL )
6152  {
6153  SCIP_CALL( SCIPexprgraphPrintDot(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), file, NULL) );
6154  fclose(file);
6155  }
6156  }
6157 #endif
6158 
6159  /* put constraint sides less linear activity into expression graph nodes
6160  * also add a [-feastol,feastol] range around constraint sides to cope with numerics */
6161  for( c = 0; c < nconss; ++c )
6162  {
6163  consdata = SCIPconsGetData(conss[c]);
6164  assert(consdata != NULL);
6165 
6166  if( consdata->exprgraphnode == NULL )
6167  continue;
6168 
6169  /* skip (just) deleted or disabled constraints */
6170  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsEnabled(conss[c]) )
6171  continue;
6172 
6173  roundmode = SCIPintervalGetRoundingMode();
6175 
6176  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->maxlinactivityinf == 0 )
6177  bounds.inf = consdata->lhs - consdata->maxlinactivity - SCIPfeastol(scip);
6178  else
6179  bounds.inf = -INTERVALINFTY;
6180 
6181  if( !SCIPisInfinity(scip, consdata->rhs) && consdata->minlinactivityinf == 0 )
6182  bounds.sup = SCIPintervalNegateReal(consdata->minlinactivity - consdata->rhs - SCIPfeastol(scip));
6183  else
6184  bounds.sup = INTERVALINFTY;
6185 
6186  SCIPintervalSetRoundingMode(roundmode);
6187 
6188  /* if we want the expression graph to propagate the bounds in any case, we set minstrength to a negative value */
6189  SCIPexprgraphTightenNodeBounds(conshdlrdata->exprgraph, consdata->exprgraphnode, bounds,
6190  consdata->forcebackprop ? -1.0 : BOUNDTIGHTENING_MINSTRENGTH, &cutoff);
6191  consdata->forcebackprop = FALSE; /* do this only once */
6192 
6193  if( cutoff )
6194  {
6195  SCIPdebugMessage("found constraint <%s> infeasible%s\n", SCIPconsGetName(conss[c]), SCIPinProbing(scip) ? " in probing" : "");
6196  *result = SCIP_CUTOFF;
6197  return SCIP_OKAY;
6198  }
6199  }
6200 
6201  /* compute bound tightenings for nonlinear variables */
6203 
6204 #ifdef SCIP_OUTPUT
6205  {
6206  FILE* file;
6207  file = fopen("exprgraph_propconss2.dot", "w");
6208  if( file != NULL )
6209  {
6210  SCIP_CALL( SCIPexprgraphPrintDot(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), file, NULL) );
6211  fclose(file);
6212  }
6213  }
6214 #endif
6215 
6216  if( cutoff )
6217  {
6218  SCIPdebugMessage("backward propagation found problem infeasible%s\n", SCIPinProbing(scip) ? " in probing" : "");
6219  *result = SCIP_CUTOFF;
6220  return SCIP_OKAY;
6221  }
6222 
6223  /* put tighter bounds into variables */
6224  nvars = SCIPexprgraphGetNVars(conshdlrdata->exprgraph);
6225  vars = (SCIP_VAR**)SCIPexprgraphGetVars(conshdlrdata->exprgraph);
6226  varnodes = SCIPexprgraphGetVarNodes(conshdlrdata->exprgraph);
6227 
6228  /* put back new bounds into SCIP variables */
6229  for( i = 0; i < nvars && *result != SCIP_CUTOFF; ++i )
6230  {
6231  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(varnodes[i]))) )
6232  {
6233  SCIP_CALL( propagateBoundsTightenVarLb(scip, NULL, vars[i], SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(varnodes[i])), result, nchgbds) );
6234  }
6235  if( *result != SCIP_CUTOFF && !SCIPisInfinity(scip, SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(varnodes[i]))) )
6236  {
6237  SCIP_CALL( propagateBoundsTightenVarUb(scip, NULL, vars[i], SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(varnodes[i])), result, nchgbds) );
6238  }
6239  }
6240 
6241  return SCIP_OKAY;
6242 }
6243 
6244 /** calls domain propagation for a set of constraints */
6245 static
6247  SCIP* scip, /**< SCIP data structure */
6248  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6249  SCIP_CONS** conss, /**< constraints to process */
6250  int nconss, /**< number of constraints */
6251  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
6252  int* nchgbds, /**< buffer where to add the the number of changed bounds */
6253  int* ndelconss /**< buffer where to increase if a constraint was deleted (locally) due to redundancy */
6254  )
6255 {
6256 #ifndef NDEBUG
6257  SCIP_CONSDATA* consdata;
6258 #endif
6259  SCIP_CONSHDLRDATA* conshdlrdata;
6260  SCIP_RESULT propresult;
6261  SCIP_Bool domainerror;
6262  SCIP_Bool redundant;
6263  int roundnr;
6264  SCIP_Bool success;
6265  int c;
6266 
6267  assert(scip != NULL);
6268  assert(conshdlr != NULL);
6269  assert(conss != NULL || nconss == 0);
6270  assert(result != NULL);
6271  assert(nchgbds != NULL);
6272  assert(ndelconss != NULL);
6273 
6274  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6275  assert(conshdlrdata != NULL);
6276  assert(conshdlrdata->exprgraph != NULL);
6277 
6278  if( nconss == 0 || conshdlrdata->ispropagated )
6279  {
6280  *result = SCIP_DIDNOTRUN;
6281  return SCIP_OKAY;
6282  }
6283 
6284  *result = SCIP_DIDNOTFIND;
6285 
6286  roundnr = 0;
6287  do
6288  {
6289  success = FALSE;
6290 
6291  SCIPdebugMessage("starting domain propagation round %d for %d constraints\n", roundnr, nconss);
6292 
6293  conshdlrdata->ispropagated = TRUE;
6294 
6295  /* propagate variable bounds through expression graph
6296  * roundnr == 0 clears remainings from a previous backward propagation
6297  * @todo could give FALSE if no linear variable in the constraints had been relaxed since last time
6298  */
6299  SCIP_CALL( SCIPexprgraphPropagateVarBounds(conshdlrdata->exprgraph, INTERVALINFTY, roundnr == 0, &domainerror) );
6300 
6301 #ifdef SCIP_OUTPUT
6302  {
6303  FILE* file;
6304  file = fopen("exprgraph_propvars.dot", "w");
6305  if( file != NULL )
6306  {
6307  SCIP_CALL( SCIPexprgraphPrintDot(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), file, NULL) );
6308  fclose(file);
6309  }
6310  }
6311 #endif
6312 
6313  if( domainerror )
6314  {
6315  SCIPdebugMessage("current bounds out of domain for some expression, do cutoff\n");
6316  *result = SCIP_CUTOFF;
6317  break;
6318  }
6319 
6320  /* check for redundancy and infeasibility of constraints, tighten bounds on linear variables */
6321  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
6322  {
6323  assert(conss != NULL);
6324  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
6325  continue;
6326  assert(SCIPconsIsActive(conss[c]));
6327 
6328 #ifndef NDEBUG
6329  consdata = SCIPconsGetData(conss[c]);
6330  assert(consdata != NULL);
6331  assert(consdata->exprgraphnode == NULL || !SCIPintervalIsEmpty(SCIPexprgraphGetNodeBounds(consdata->exprgraphnode)));
6332 #endif
6333 
6334  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
6335  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
6336  {
6337  *result = propresult;
6338  success = TRUE;
6339  }
6340  if( redundant )
6341  {
6342  SCIPdebugMessage("delete redundant constraint <%s> locally\n", SCIPconsGetName(conss[c]));
6343  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
6344  ++*ndelconss;
6345  }
6346  }
6347 
6348  /* propagate backward through expression graph */
6349  if( *result != SCIP_CUTOFF )
6350  {
6351  propresult = SCIP_DIDNOTFIND;
6352  SCIP_CALL( propagateConstraintSides(scip, conshdlr, conss, nconss, &propresult, nchgbds) );
6353 
6354  if( propresult != SCIP_DIDNOTFIND )
6355  {
6356  *result = propresult;
6357  success = TRUE;
6358  }
6359  }
6360  }
6361  while( success && *result != SCIP_CUTOFF && ++roundnr < conshdlrdata->maxproprounds );
6362 
6363  return SCIP_OKAY;
6364 }
6365 
6366 /* checks for a linear variable that can be increase or decreased without harming feasibility */
6367 static
6369  SCIP* scip, /**< SCIP data structure */
6370  SCIP_CONSDATA* consdata /**< constraint data */
6371  )
6372 {
6373  int i;
6374  int poslock;
6375  int neglock;
6376 
6377  consdata->linvar_maydecrease = -1;
6378  consdata->linvar_mayincrease = -1;
6379 
6380  /* check for a linear variable that can be increase or decreased without harming feasibility
6381  * setup lincoefsmin, lincoefsmax */
6382  for( i = 0; i < consdata->nlinvars; ++i )
6383  {
6384  /* compute locks of i'th linear variable */
6385  assert(consdata->lincoefs[i] != 0.0);
6386  if( consdata->lincoefs[i] > 0.0 )
6387  {
6388  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
6389  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
6390  }
6391  else
6392  {
6393  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
6394  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
6395  }
6396 
6397  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - neglock == 0 )
6398  {
6399  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
6400  /* if we have already one candidate, then take the one where the loss in the objective function is less */
6401  if( (consdata->linvar_maydecrease < 0) ||
6402  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
6403  consdata->linvar_maydecrease = i;
6404  }
6405 
6406  if( SCIPvarGetNLocksDown(consdata->linvars[i]) - poslock == 0 )
6407  {
6408  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
6409  /* if we have already one candidate, then take the one where the loss in the objective function is less */
6410  if( (consdata->linvar_mayincrease < 0) ||
6411  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
6412  consdata->linvar_mayincrease = i;
6413  }
6414  }
6415 
6416 #ifdef SCIP_DEBUG
6417  if( consdata->linvar_mayincrease >= 0 )
6418  {
6419  SCIPdebugMessage("may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
6420  }
6421  if( consdata->linvar_maydecrease >= 0 )
6422  {
6423  SCIPdebugMessage("may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
6424  }
6425 #endif
6426 }
6427 
6428 /** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
6429  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
6430  * The method assumes that this is always possible and that not all constraints are feasible already.
6431  */
6432 static
6434  SCIP* scip, /**< SCIP data structure */
6435  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6436  SCIP_CONS** conss, /**< constraints to process */
6437  int nconss, /**< number of constraints */
6438  SCIP_SOL* sol, /**< solution to process */
6439  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
6440  )
6441 {
6442  SCIP_CONSHDLRDATA* conshdlrdata;
6443  SCIP_CONSDATA* consdata;
6444  SCIP_SOL* newsol;
6445  SCIP_VAR* var;
6446  int c;
6447  SCIP_Real viol;
6448  SCIP_Real delta;
6449  SCIP_Real gap;
6450 
6451  assert(scip != NULL);
6452  assert(conshdlr != NULL);
6453  assert(conss != NULL || nconss == 0);
6454  assert(success != NULL);
6455 
6456  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6457  assert(conshdlrdata != NULL);
6458  assert(conshdlrdata->trysolheur != NULL);
6459 
6460  *success = FALSE;
6461 
6462  if( sol != NULL )
6463  {
6464  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
6465  }
6466  else
6467  {
6468  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
6469  }
6470  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
6471 
6472  for( c = 0; c < nconss; ++c )
6473  {
6474  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6475  assert(consdata != NULL);
6476 
6477  /* recompute violation of solution in case solution has changed
6478  * get absolution violation and sign */
6479  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
6480  {
6481  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
6482  viol = consdata->lhs - consdata->activity;
6483  }
6484  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6485  {
6486  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
6487  viol = consdata->rhs - consdata->activity;
6488  }
6489  else
6490  continue; /* constraint is satisfied */
6491 
6492  assert(viol != 0.0);
6493  if( consdata->linvar_mayincrease >= 0 &&
6494  (( viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) ||
6495  (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
6496  {
6497  /* have variable where increasing makes the constraint less violated */
6498  var = consdata->linvars[consdata->linvar_mayincrease];
6499  /* compute how much we would like to increase var */
6500  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
6501  assert(delta > 0.0);
6502  /* if var has an upper bound, may need to reduce delta */
6503  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
6504  {
6505  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
6506  delta = MIN(MAX(0.0, gap), delta);
6507  }
6508  if( SCIPisPositive(scip, delta) )
6509  {
6510  /* if variable is integral, round delta up so that it will still have an integer value */
6511  if( SCIPvarIsIntegral(var) )
6512  delta = SCIPceil(scip, delta);
6513 
6514  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
6515  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
6516 
6517  /* adjust constraint violation, if satisfied go on to next constraint */
6518  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
6519  if( SCIPisZero(scip, viol) )
6520  continue;
6521  }
6522  }
6523 
6524  assert(viol != 0.0);
6525  if( consdata->linvar_maydecrease >= 0 &&
6526  (( viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) ||
6527  (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
6528  {
6529  /* have variable where decreasing makes constraint less violated */
6530  var = consdata->linvars[consdata->linvar_maydecrease];
6531  /* compute how much we would like to decrease var */
6532  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
6533  assert(delta < 0.0);
6534  /* if var has a lower bound, may need to reduce delta */
6535  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
6536  {
6537  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
6538  delta = MAX(MIN(0.0, gap), delta);
6539  }
6540  if( SCIPisNegative(scip, delta) )
6541  {
6542  /* if variable is integral, round delta down so that it will still have an integer value */
6543  if( SCIPvarIsIntegral(var) )
6544  delta = SCIPfloor(scip, delta);
6545  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
6546  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
6547 
6548  /* adjust constraint violation, if satisfied go on to next constraint */
6549  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
6550  if( SCIPisZero(scip, viol) )
6551  continue;
6552  }
6553  }
6554 
6555  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
6556  break;
6557  }
6558 
6559  /* if we have a solution that should satisfy all nonlinear constraints and has a better objective than the current upper bound,
6560  * then pass it to the trysol heuristic */
6561  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
6562  {
6563  SCIPdebugMessage("pass solution with objective value %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
6564 
6565  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
6566  *success = TRUE;
6567  }
6568 
6569  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
6570 
6571  return SCIP_OKAY;
6572 }
6573 
6574 /*
6575  * Callback methods of constraint handler
6576  */
6577 
6578 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
6579 static
6580 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
6581 {
6582  assert(scip != NULL);
6583  assert(conshdlr != NULL);
6584  /* assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); */
6585 
6586  /* call inclusion method of constraint handler */
6588 
6589  *valid = TRUE;
6590 
6591  return SCIP_OKAY;
6592 }
6593 
6594 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
6595 static
6596 SCIP_DECL_CONSFREE(consFreeNonlinear)
6597 {
6598  SCIP_CONSHDLRDATA* conshdlrdata;
6599  int i;
6600 
6601  assert(scip != NULL);
6602  assert(conshdlr != NULL);
6603 
6604  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6605  assert(conshdlrdata != NULL);
6606  assert(conshdlrdata->exprinterpreter != NULL);
6607  assert(conshdlrdata->exprgraph != NULL);
6608  assert(SCIPexprgraphGetNVars(conshdlrdata->exprgraph) == 0);
6609 
6610  /* free expression graph */
6611  SCIP_CALL( SCIPexprgraphFree(&conshdlrdata->exprgraph) );
6612 
6613  /* free upgrade functions */
6614  for( i = 0; i < conshdlrdata->nnlconsupgrades; ++i )
6615  {
6616  assert(conshdlrdata->nlconsupgrades[i] != NULL);
6617  SCIPfreeMemory(scip, &conshdlrdata->nlconsupgrades[i]);
6618  }
6619  SCIPfreeMemoryArrayNull(scip, &conshdlrdata->nlconsupgrades);
6620 
6621  /* free expressions interpreter */
6622  SCIP_CALL( SCIPexprintFree(&conshdlrdata->exprinterpreter) );
6623 
6624  SCIPfreeMemory(scip, &conshdlrdata);
6625 
6626  return SCIP_OKAY;
6627 }
6628 
6629 /** initialization method of constraint handler (called after problem was transformed) */
6630 static
6631 SCIP_DECL_CONSINIT(consInitNonlinear)
6632 {
6633  SCIP_CONSHDLRDATA* conshdlrdata;
6634 
6635  assert(scip != NULL);
6636  assert(conshdlr != NULL);
6637 
6638  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6639  assert(conshdlrdata != NULL);
6640 
6641  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
6642  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
6643 
6644  /* reset counter, since we have a new problem */
6645  conshdlrdata->naddedreformconss = 0;
6646 
6647 #ifdef SCIP_OUTPUT
6648  {
6649  FILE* file;
6650  file = fopen("exprgraph_init.dot", "w");
6651  if( file != NULL )
6652  {
6653  SCIP_CALL( SCIPexprgraphPrintDot(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), file, NULL) );
6654  fclose(file);
6655  }
6656  }
6657 #endif
6658 
6659  return SCIP_OKAY;
6660 } /*lint !e715*/
6661 
6662 /** deinitialization method of constraint handler (called before transformed problem is freed) */
6663 static
6664 SCIP_DECL_CONSEXIT(consExitNonlinear)
6665 {
6666  SCIP_CONSHDLRDATA* conshdlrdata;
6667 
6668  assert(scip != NULL);
6669  assert(conshdlr != NULL);
6670 
6671  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6672  assert(conshdlrdata != NULL);
6673 
6674  conshdlrdata->subnlpheur = NULL;
6675  conshdlrdata->trysolheur = NULL;
6676 
6677  return SCIP_OKAY;
6678 } /*lint !e715*/
6679 
6680 
6681 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
6682 static
6683 SCIP_DECL_CONSINITPRE(consInitpreNonlinear)
6684 { /*lint --e{715}*/
6685  SCIP_CONSDATA* consdata;
6686  int c;
6687 
6688  assert(scip != NULL);
6689  assert(conshdlr != NULL);
6690  assert(conss != NULL || nconss == 0);
6691 
6692  for( c = 0; c < nconss; ++c )
6693  {
6694  /* skip not yet active constraints */
6695  if( !SCIPconsIsActive(conss[c]) ) /*lint !e613*/
6696  continue;
6697 
6698  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6699  assert(consdata != NULL);
6700 
6701  /* forget expression trees */
6702  assert(consdata->nexprtrees == 0 || consdata->exprgraphnode != NULL);
6703  SCIP_CALL( consdataSetExprtrees(scip, consdata, 0, NULL, NULL, FALSE) );
6704  }
6705 
6706  return SCIP_OKAY;
6707 }
6708 
6709 
6710 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
6711 static
6712 SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
6713 { /*lint --e{715}*/
6714  SCIP_CONSHDLRDATA* conshdlrdata;
6715  SCIP_CONSDATA* consdata;
6716  SCIP_Bool havegraphchange;
6717  SCIP_Bool havechange;
6718  SCIP_Bool domainerror;
6719 #ifndef NDEBUG
6720  int i;
6721  int j;
6722 #endif
6723  int c;
6724 
6725  assert(scip != NULL);
6726  assert(conshdlr != NULL);
6727  assert(conss != NULL || nconss == 0);
6728 
6729  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6730  assert(conshdlrdata != NULL);
6731 
6732  havegraphchange = FALSE;
6733 
6734  if( !conshdlrdata->isremovedfixings )
6735  {
6736  SCIP_CALL( removeFixedNonlinearVariables(scip, conshdlr) );
6737  assert(conshdlrdata->isremovedfixings);
6738 
6739  havegraphchange = TRUE;
6740  }
6741 
6742  /* if undefined expressions in exprgraph (very unlikely), we will hopefully recognize this during domain propagation later (if it involved an active constraint) */
6743  SCIP_CALL( SCIPexprgraphSimplify(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), SCIPepsilon(scip), conshdlrdata->maxexpansionexponent, &havechange, &domainerror) );
6744  SCIPdebugMessage("expression graph simplifier found %schange, domain error = %u\n", havechange ? "" : "no ", domainerror);
6745  havegraphchange |= havechange;
6746 
6747  for( c = 0; c < nconss; ++c )
6748  {
6749  assert(conss != NULL);
6750 
6751  /* skip inactive constraints */
6752  if( !SCIPconsIsActive(conss[c]) )
6753  continue;
6754  assert(SCIPconsIsAdded(conss[c]));
6755 
6756  consdata = SCIPconsGetData(conss[c]);
6757  assert(consdata != NULL);
6758 
6759  if( !consdata->isremovedfixingslin )
6760  {
6761  SCIP_CALL( removeFixedLinearVariables(scip, conss[c]) );
6762  }
6763 
6764  if( !consdata->ispresolved || havegraphchange )
6765  {
6766  SCIP_CALL( splitOffLinearPart(scip, conshdlr, conss[c]) );
6767  }
6768 
6769  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
6770 
6771  assert(consdata->isremovedfixingslin);
6772  assert(consdata->linvarsmerged);
6773 #ifndef NDEBUG
6774  for( i = 0; i < consdata->nlinvars; ++i )
6775  assert(SCIPvarIsActive(consdata->linvars[i]));
6776 #endif
6777 
6778  if( consdata->exprgraphnode != NULL )
6779  {
6780  /* get expression trees from expression graph */
6781  SCIP_EXPRTREE** exprtrees;
6782  SCIP_Real* coefs;
6783  int nexprtrees;
6784  int exprtreessize;
6785 
6786  exprtreessize = SCIPexprgraphGetSumTreesNSummands(consdata->exprgraphnode);
6787 
6788  SCIP_CALL( SCIPallocBufferArray(scip, &exprtrees, exprtreessize) );
6789  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, exprtreessize) );
6790 
6791  SCIP_CALL( SCIPexprgraphGetSumTrees(conshdlrdata->exprgraph, consdata->exprgraphnode,
6792  exprtreessize, &nexprtrees, exprtrees, coefs) );
6793  assert(nexprtrees > 0);
6794 
6795  SCIP_CALL( consdataSetExprtrees(scip, consdata, nexprtrees, exprtrees, coefs, FALSE) );
6796 
6797  SCIPfreeBufferArray(scip, &exprtrees);
6798  SCIPfreeBufferArray(scip, &coefs);
6799 
6800  assert(consdata->nexprtrees > 0 );
6801 #ifndef NDEBUG
6802  for( j = 0; j < consdata->nexprtrees; ++j )
6803  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]); ++i )
6804  assert(SCIPvarIsActive(SCIPexprtreeGetVars(consdata->exprtrees[j])[i]));
6805 #endif
6806 
6807  /* tell SCIP that we have something nonlinear */
6808  SCIPenableNLP(scip);
6809  }
6810  }
6811 
6812  return SCIP_OKAY;
6813 }
6814 
6815 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
6816 static
6817 SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
6818 {
6819  SCIP_CONSHDLRDATA* conshdlrdata;
6820  SCIP_CONSDATA* consdata;
6821  int c;
6822  int i;
6823 
6824  assert(scip != NULL);
6825  assert(conshdlr != NULL);
6826  assert(conss != NULL || nconss == 0);
6827 
6828  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6829  assert(conshdlrdata != NULL);
6830 
6831  for( c = 0; c < nconss; ++c )
6832  {
6833  assert(conss != NULL);
6834  consdata = SCIPconsGetData(conss[c]);
6835  assert(consdata != NULL);
6836 
6837  /* check for a linear variable that can be increase or decreased without harming feasibility */
6838  consdataFindUnlockedLinearVar(scip, consdata);
6839 
6840  /* setup lincoefsmin, lincoefsmax */
6841  consdata->lincoefsmin = SCIPinfinity(scip);
6842  consdata->lincoefsmax = 0.0;
6843  for( i = 0; i < consdata->nlinvars; ++i )
6844  {
6845  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666*/
6846  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666*/
6847  }
6848 
6849  /* add nlrow respresentation to NLP, if NLP had been constructed */
6850  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
6851  {
6852  if( consdata->nlrow == NULL )
6853  {
6854  SCIP_CALL( createNlRow(scip, conss[c]) );
6855  assert(consdata->nlrow != NULL);
6856  }
6857  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
6858  }
6859  }
6860 
6861  conshdlrdata->newsoleventfilterpos = -1;
6862  if( nconss != 0 )
6863  {
6864  SCIP_EVENTHDLR* eventhdlr;
6865 
6866  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
6867  assert(eventhdlr != NULL);
6868 
6869  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
6870  }
6871 
6872  /* reset flags and counters */
6873  conshdlrdata->sepanlp = FALSE;
6874  conshdlrdata->lastenfolpnode = NULL;
6875  conshdlrdata->nenfolprounds = 0;
6876 
6877  return SCIP_OKAY;
6878 }
6879 
6880 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
6881 static
6882 SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
6883 {
6884  SCIP_CONSHDLRDATA* conshdlrdata;
6885  SCIP_CONSDATA* consdata;
6886  int c;
6887 
6888  assert(scip != NULL);
6889  assert(conshdlr != NULL);
6890  assert(conss != NULL || nconss == 0);
6891 
6892  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6893  assert(conshdlrdata != NULL);
6894 
6895  if( conshdlrdata->newsoleventfilterpos >= 0 )
6896  {
6897  SCIP_EVENTHDLR* eventhdlr;
6898 
6899  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
6900  assert(eventhdlr != NULL);
6901 
6902  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
6903  conshdlrdata->newsoleventfilterpos = -1;
6904  }
6905 
6906  for( c = 0; c < nconss; ++c )
6907  {
6908  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6909  assert(consdata != NULL);
6910 
6911  /* free nonlinear row representation */
6912  if( consdata->nlrow != NULL )
6913  {
6914  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
6915  }
6916  }
6917 
6918  return SCIP_OKAY;
6919 } /*lint !e715*/
6920 
6921 
6922 /** frees specific constraint data */
6923 static
6924 SCIP_DECL_CONSDELETE(consDeleteNonlinear)
6925 {
6926  assert(scip != NULL);
6927  assert(conshdlr != NULL);
6928  assert(cons != NULL);
6929  assert(!SCIPconsIsActive(cons));
6930  assert(consdata != NULL);
6931  assert(SCIPconsGetData(cons) == *consdata);
6932 
6933  SCIPdebugMessage("consDelete for cons <%s>\n", SCIPconsGetName(cons));
6934 
6935  /* expression should have been removed from expression graph when constraint was deactivated */
6936  assert((*consdata)->exprgraphnode == NULL);
6937 
6938  SCIP_CALL( consdataFree(scip, consdata) );
6939 
6940  assert(*consdata == NULL);
6941 
6942  return SCIP_OKAY;
6943 }
6944 
6945 /** transforms constraint data into data belonging to the transformed problem */
6946 static
6947 SCIP_DECL_CONSTRANS(consTransNonlinear)
6948 {
6949  SCIP_CONSDATA* sourcedata;
6950  SCIP_CONSDATA* targetdata;
6951  int i;
6952 
6953  sourcedata = SCIPconsGetData(sourcecons);
6954  assert(sourcedata != NULL);
6955 
6956  SCIP_CALL( consdataCreate(scip, &targetdata,
6957  sourcedata->lhs, sourcedata->rhs,
6958  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
6959  sourcedata->nexprtrees, sourcedata->exprtrees, sourcedata->nonlincoefs,
6960  FALSE) );
6961 
6962  /* copy information on curvature, if known in original constraint */
6963  if( sourcedata->iscurvchecked && sourcedata->nexprtrees > 0 )
6964  {
6965  BMScopyMemoryArray(targetdata->curvatures, sourcedata->curvatures, sourcedata->nexprtrees);
6966  targetdata->curvature = sourcedata->curvature;
6967  targetdata->iscurvchecked = TRUE;
6968  }
6969 
6970  for( i = 0; i < targetdata->nlinvars; ++i )
6971  {
6972  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
6973  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
6974  }
6975 
6976  for( i = 0; i < targetdata->nexprtrees; ++i )
6977  {
6978  SCIP_CALL( SCIPgetExprtreeTransformedVars(scip, targetdata->exprtrees[i]) );
6979  }
6980 
6981  /* create target constraint */
6982  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
6983  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
6984  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
6985  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
6986  SCIPconsIsStickingAtNode(sourcecons)) );
6987 
6988  SCIPdebugMessage("created transformed nonlinear constraint ");
6989  SCIPdebugPrintCons(scip, *targetcons, NULL);
6990 
6991  return SCIP_OKAY;
6992 }
6993 
6994 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
6995 static
6996 SCIP_DECL_CONSINITLP(consInitlpNonlinear)
6997 {
6998  SCIP_CONSHDLRDATA* conshdlrdata;
6999  SCIP_CONSDATA* consdata;
7000  SCIP_ROW* row;
7001  int c;
7002  SCIP_Real** x;
7003  int nvars;
7004  int i;
7005  int j;
7006  SCIP_VAR* var;
7007  SCIP_Bool haveunboundedvar;
7008 
7009  assert(scip != NULL);
7010  assert(conshdlr != NULL);
7011  assert(conss != NULL || nconss == 0);
7012 
7013  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7014  assert(conshdlrdata != NULL);
7015 
7016  for( c = 0; c < nconss; ++c )
7017  {
7018  assert(conss[c] != NULL); /*lint !e613*/
7019 
7020  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) ); /*lint !e613*/
7021 
7022  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
7023  assert(consdata != NULL);
7024 
7025  row = NULL;
7026 
7027  if( consdata->nexprtrees == 0 )
7028  {
7029  SCIP_Bool infeasible;
7030 
7031  assert(consdata->exprgraphnode == NULL);
7032  /* if we are actually linear, add the constraint as row to the LP */
7033  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
7034  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613*/
7035  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
7036  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
7037  SCIP_CALL( SCIPreleaseRow (scip, &row) );
7038  continue;
7039  }
7040 
7041  /* setup reference points for each exprtree */
7042  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nexprtrees) );
7043  haveunboundedvar = FALSE;
7044  for( j = 0; j < consdata->nexprtrees; ++j )
7045  {
7046  nvars = SCIPexprtreeGetNVars(consdata->exprtrees[j]);
7047 
7048  SCIP_CALL( SCIPallocBufferArray(scip, &x[j], nvars) ); /*lint !e866*/
7049  for( i = 0; i < nvars; ++i )
7050  {
7051  var = SCIPexprtreeGetVars(consdata->exprtrees[j])[i];
7052  assert(var != NULL);
7053  /* use midpoint as reference value, if both bounds are finite
7054  * otherwise use 0.0, projected on bounds
7055  */
7056  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
7057  {
7058  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
7059  {
7060  x[j][i] = 0.0;
7061  haveunboundedvar = TRUE;
7062  }
7063  else
7064  x[j][i] = MIN(0.0, SCIPvarGetUbGlobal(var)); /*lint !e666*/
7065  }
7066  else
7067  {
7068  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
7069  x[j][i] = MAX(0.0, SCIPvarGetLbGlobal(var)); /*lint !e666*/
7070  else
7071  {
7072  x[j][i] = (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
7073  /* shift refpoint into [-INITLPMAXVARVAL, INITLPMAXVARVAL], if bounds allow */
7074  if( x[j][i] < -INITLPMAXVARVAL && SCIPvarGetUbGlobal(var) >= -INITLPMAXVARVAL )
7075  x[j][i] = -INITLPMAXVARVAL;
7076  else if( x[j][i] > INITLPMAXVARVAL && SCIPvarGetLbGlobal(var) <= INITLPMAXVARVAL )
7077  x[j][i] = INITLPMAXVARVAL;
7078  }
7079  }
7080  }
7081  }
7082 
7083  /* for inequalities that are convex or that have bounded variables, try to generate a cut */
7084  if( !SCIPisInfinity(scip, consdata->rhs) && ((consdata->curvature & SCIP_EXPRCURV_CONVEX) || !haveunboundedvar) )
7085  {
7086  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], x, NULL, TRUE, SCIP_SIDETYPE_RIGHT, &row, conshdlrdata->cutmaxrange, FALSE, FALSE) ); /*lint !e613*/
7087 
7088  if( row != NULL )
7089  {
7090  SCIP_Bool infeasible;
7091 
7092  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE /* forcecut */, &infeasible) );
7093  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
7094  SCIP_CALL( SCIPreleaseRow(scip, &row) );
7095  }
7096  }
7097 
7098  if( !SCIPisInfinity(scip, -consdata->lhs) && ((consdata->curvature & SCIP_EXPRCURV_CONCAVE) || !haveunboundedvar) )
7099  {
7100  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], x, NULL, TRUE, SCIP_SIDETYPE_LEFT, &row, conshdlrdata->cutmaxrange, FALSE, FALSE) ); /*lint !e613*/
7101 
7102  if( row != NULL )
7103  {
7104  SCIP_Bool infeasible;
7105 
7106  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE /* forcecut */, &infeasible) );
7107  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
7108  SCIP_CALL( SCIPreleaseRow(scip, &row) );
7109  }
7110  }
7111 
7112  /* @todo could add more linearizations for convex or multivariate concave inequ. */
7113 
7114  for( j = 0; j < consdata->nexprtrees; ++j )
7115  {
7116  SCIPfreeBufferArray(scip, &x[j]);
7117  }
7118  SCIPfreeBufferArray(scip, &x);
7119  }
7120 
7121  return SCIP_OKAY;
7122 }
7123 
7124 /** separation method of constraint handler for LP solutions */
7125 static
7126 SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
7127 {
7128  SCIP_CONSHDLRDATA* conshdlrdata;
7129  SCIP_CONS* maxviolcon;
7130  SCIP_Bool newsol;
7131 
7132  assert(scip != NULL);
7133  assert(conshdlr != NULL);
7134  assert(conss != NULL || nconss == 0);
7135  assert(result != NULL);
7136 
7137  *result = SCIP_DIDNOTFIND;
7138 
7139  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7140  assert(conshdlrdata != NULL);
7141 
7142  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
7143  if( maxviolcon == NULL )
7144  return SCIP_OKAY;
7145 
7146  newsol = FALSE;
7147 
7148  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
7149  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
7150  */
7151  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
7152  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) || (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
7153  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
7154  {
7155  SCIP_CONSDATA* consdata;
7156  SCIP_NLPSOLSTAT solstat;
7157  SCIP_Bool solvednlp; /* whether we invoked an NLP solve here */
7158  int c;
7159 
7160  solstat = SCIPgetNLPSolstat(scip);
7161  solvednlp = FALSE;
7162  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
7163  {
7164  /* NLP is not solved yet, so we might want to do this
7165  * but first check whether there is a violated constraint side which corresponds to a convex function
7166  * @todo put this check into initsol and update via consenable/consdisable
7167  */
7168  for( c = 0; c < nconss; ++c )
7169  {
7170  assert(conss[c] != NULL); /*lint !e613*/
7171 
7172  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
7173  assert(consdata != NULL);
7174 
7175  /* skip feasible constraints */
7176  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7177  continue;
7178 
7179  /* make sure curvature has been checked */
7180  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) ); /*lint !e613*/
7181 
7182  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && (consdata->curvature & SCIP_EXPRCURV_CONVEX )) ||
7183  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && (consdata->curvature & SCIP_EXPRCURV_CONCAVE)) )
7184  break;
7185  }
7186 
7187  if( c < nconss )
7188  {
7189  /* try to solve NLP and update solstat */
7190 
7191  /* ensure linear conss are in NLP */
7192  if( conshdlrdata->subnlpheur != NULL )
7193  {
7194  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
7195  }
7196 
7197  /* set LP solution as starting values, if available */
7199  {
7201  }
7202 
7203  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
7204  SCIP_CALL( SCIPsolveNLP(scip) );
7205 
7206  solstat = SCIPgetNLPSolstat(scip);
7207  SCIPdebugMessage("solved NLP relax, solution status: %d\n", solstat);
7208 
7209  solvednlp = TRUE;
7210  }
7211  }
7212 
7213  conshdlrdata->sepanlp = TRUE;
7214 
7215  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
7216  {
7217  SCIPdebugMessage("NLP relaxation is globally infeasible, thus can cutoff node\n");
7218  *result = SCIP_CUTOFF;
7219  return SCIP_OKAY;
7220  }
7221 
7222  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
7223  {
7224  /* if we have feasible NLP solution, generate linearization cuts there */
7225  SCIP_Bool lpsolseparated;
7226  SCIP_SOL* nlpsol;
7227 
7228  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
7229  assert(nlpsol != NULL);
7230 
7231  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
7232  if( solvednlp && conshdlrdata->trysolheur != NULL )
7233  {
7234  int nfracvars;
7235 
7236  nfracvars = 0;
7237  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
7238  {
7239  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
7240  }
7241 
7242  if( nfracvars == 0 )
7243  {
7244  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
7245  }
7246  }
7247 
7248  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, conshdlrdata->mincutefficacysepa) );
7249  newsol = TRUE;
7250 
7251  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
7252 
7253  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
7254  if( lpsolseparated )
7255  {
7256  SCIPdebugMessage("linearization cuts separate LP solution\n");
7257 
7258  *result = SCIP_SEPARATED;
7259 
7260  return SCIP_OKAY;
7261  }
7262  }
7263  }
7264  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
7265  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
7266  */
7267 
7268  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, newsol, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
7269 
7270  return SCIP_OKAY;
7271 }
7272 
7273 /** separation method of constraint handler for arbitrary primal solutions */
7274 static
7275 SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
7276 {
7277  SCIP_CONSHDLRDATA* conshdlrdata;
7278  SCIP_CONS* maxviolcon;
7279 
7280  assert(scip != NULL);
7281  assert(conshdlr != NULL);
7282  assert(conss != NULL || nconss == 0);
7283  assert(sol != NULL);
7284  assert(result != NULL);
7285 
7286  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7287  assert(conshdlrdata != NULL);
7288 
7289  *result = SCIP_DIDNOTFIND;
7290 
7291  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &maxviolcon) );
7292  if( maxviolcon == NULL )
7293  return SCIP_OKAY;
7294 
7295  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, FALSE, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
7296 
7297  return SCIP_OKAY;
7298 }
7299 
7300 /** constraint enforcing method of constraint handler for LP solutions */
7301 static
7302 SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
7303 { /*lint --e{715}*/
7304  SCIP_CONSHDLRDATA* conshdlrdata;
7305  SCIP_CONSDATA* consdata;
7306  SCIP_CONS* maxviolcons;
7307  SCIP_Real maxviol;
7308  SCIP_RESULT propresult;
7309  SCIP_RESULT separateresult;
7310  int dummy;
7311  int nnotify;
7312  SCIP_Real sepaefficacy;
7313  SCIP_Real minefficacy;
7314  SCIP_Real leastpossibleefficacy;
7315 
7316  assert(scip != NULL);
7317  assert(conshdlr != NULL);
7318  assert(conss != NULL || nconss == 0);
7319 
7320  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7321  assert(conshdlrdata != NULL);
7322 
7323  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcons) );
7324  if( maxviolcons == NULL )
7325  {
7326  *result = SCIP_FEASIBLE;
7327  return SCIP_OKAY;
7328  }
7329 
7330  *result = SCIP_INFEASIBLE;
7331 
7332  consdata = SCIPconsGetData(maxviolcons);
7333  assert(consdata != NULL);
7334 
7335  maxviol = consdata->lhsviol + consdata->rhsviol;
7336  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
7337 
7338  SCIPdebugMessage("enfolp with max violation %g in cons <%s>\n", maxviol, SCIPconsGetName(maxviolcons));
7339 
7340  /* we propagate and separate constraints only if they are active and enforcing by branching only does not seem much effective */
7341  assert(SCIPconsIsActive(maxviolcons));
7342 
7343  /* if we are above the 100'th enforcement round for this node, something is strange
7344  * (maybe the LP does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
7345  * 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
7346  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
7347  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
7348  * we only increment nenfolprounds until 101 to avoid an overflow
7349  */
7350  if( conshdlrdata->lastenfolpnode == SCIPgetCurrentNode(scip) )
7351  {
7352  if( conshdlrdata->nenfolprounds > 100 )
7353  {
7354  if( SCIPisStopped(scip) )
7355  {
7356  SCIP_NODE* child;
7357 
7358  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
7359  *result = SCIP_BRANCHED;
7360 
7361  return SCIP_OKAY;
7362  }
7363  }
7364  else
7365  ++conshdlrdata->nenfolprounds;
7366  }
7367  else
7368  {
7369  conshdlrdata->lastenfolpnode = SCIPgetCurrentNode(scip);
7370  conshdlrdata->nenfolprounds = 0;
7371  }
7372 
7373  /* run domain propagation */
7374  dummy = 0;
7375  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &dummy, &dummy) );
7376  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
7377  {
7378  *result = propresult;
7379  return SCIP_OKAY;
7380  }
7381 
7382  /* we would like a cut that is efficient enough that it is not redundant in the LP (>feastol)
7383  * however, if the maximal violation is very small, also the best cut efficacy cannot be large
7384  * thus, in the latter case, we are also happy if the efficacy is at least, say, 75% of the maximal violation
7385  * but in any case we need an efficacy that is at least feastol
7386  */
7387  minefficacy = MIN(0.75*maxviol, conshdlrdata->mincutefficacyenfofac * SCIPfeastol(scip)); /*lint !e666*/
7388  minefficacy = MAX(minefficacy, SCIPfeastol(scip)); /*lint !e666*/
7389  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, FALSE, minefficacy, TRUE, &separateresult, &sepaefficacy) );
7390  if( separateresult == SCIP_CUTOFF )
7391  {
7392  SCIPdebugMessage("separation found cutoff\n");
7393  *result = SCIP_CUTOFF;
7394  return SCIP_OKAY;
7395  }
7396  if( separateresult == SCIP_SEPARATED )
7397  {
7398  SCIPdebugMessage("separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, minefficacy);
7399  *result = SCIP_SEPARATED;
7400  return SCIP_OKAY;
7401  }
7402 
7403  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
7404  * -> collect variables for branching
7405  */
7406 
7407  SCIPdebugMessage("separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, minefficacy, maxviol);
7408 
7409  /* find branching candidates */
7410  SCIP_CALL( registerBranchingVariables(scip, conshdlr, conss, nconss, &nnotify) );
7411 
7412  /* if sepastore can decrease LP feasibility tolerance, we can add cuts with efficacy in [eps, feastol] */
7413  leastpossibleefficacy = SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip);
7414  if( nnotify == 0 && !solinfeasible && minefficacy > leastpossibleefficacy )
7415  {
7416  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
7417  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, FALSE, leastpossibleefficacy, TRUE, &separateresult, &sepaefficacy) );
7418  if( separateresult == SCIP_SEPARATED || separateresult == SCIP_CUTOFF )
7419  {
7420  *result = separateresult;
7421  return SCIP_OKAY;
7422  }
7423  }
7424 
7425  if( nnotify == 0 && !solinfeasible )
7426  {
7427  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
7428  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
7429  */
7430  SCIP_VAR* brvar = NULL;
7431  SCIP_CALL( registerLargeLPValueVariableForBranching(scip, conss, nconss, &brvar) );
7432  if( brvar == NULL )
7433  {
7434  /* fallback 3: all nonlinear variables in all violated constraints seem to be fixed -> replace by linear constraints */
7435  SCIP_Bool addedcons;
7436  SCIP_Bool reduceddom;
7437  SCIP_Bool infeasible;
7438 
7439  SCIPdebugMessage("All nonlinear variables seem to be fixed. Replace remaining violated nonlinear constraints by linear constraints.\n");
7440  SCIP_CALL( replaceViolatedByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
7441  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
7442  * when it enforces the new constraints again and nothing resolves the infeasiblity that we declare here thus,
7443  * we only add them if considered violated, and otherwise claim the solution is feasible (but print a
7444  * warning) */
7445  if ( infeasible )
7446  *result = SCIP_CUTOFF;
7447  else if ( addedcons )
7448  *result = SCIP_CONSADDED;
7449  else if ( reduceddom )
7450  *result = SCIP_REDUCEDDOM;
7451  else
7452  {
7453  *result = SCIP_FEASIBLE;
7454  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
7455  assert(!SCIPisInfinity(scip, maxviol));
7456  }
7457  return SCIP_OKAY;
7458  }
7459  else
7460  {
7461  SCIPdebugMessage("Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
7462  SCIPvarGetName(brvar), SCIPgetSolVal(scip, NULL, brvar));
7463  nnotify = 1;
7464  }
7465  }
7466 
7467  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
7468  return SCIP_OKAY;
7469 }
7470 
7471 
7472 /** constraint enforcing method of constraint handler for pseudo solutions */
7473 static
7474 SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
7475 {
7476  SCIP_CONS* maxviolcons;
7477  SCIP_CONSDATA* consdata;
7478  SCIP_RESULT propresult;
7479  SCIP_VAR* var;
7480  int dummy;
7481  int nnotify;
7482  int c;
7483  int i;
7484  int j;
7485 
7486  assert(scip != NULL);
7487  assert(conss != NULL || nconss == 0);
7488 
7489  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcons) );
7490  if( maxviolcons == NULL )
7491  {
7492  *result = SCIP_FEASIBLE;
7493  return SCIP_OKAY;
7494  }
7495 
7496  *result = SCIP_INFEASIBLE;
7497 
7498  SCIPdebugMessage("enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcons));
7499 
7500  /* we propagate constraints only if they are active and enforcing by branching only does not seem much effective */
7501  assert(SCIPconsIsActive(maxviolcons));
7502 
7503  /* run domain propagation */
7504  dummy = 0;
7505  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &dummy, &dummy) );
7506  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
7507  {
7508  *result = propresult;
7509  return SCIP_OKAY;
7510  }
7511 
7512  /* we are not feasible and we cannot proof that the whole node is infeasible
7513  * -> collect all variables in violated constraints for branching
7514  */
7515 
7516  nnotify = 0;
7517  for( c = 0; c < nconss; ++c )
7518  {
7519  assert(conss != NULL);
7520  consdata = SCIPconsGetData(conss[c]);
7521  assert(consdata != NULL);
7522 
7523  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7524  continue;
7525 
7526  for( i = 0; i < consdata->nlinvars; ++i )
7527  {
7528  var = consdata->linvars[i];
7529  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
7530  {
7531  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
7532  ++nnotify;
7533  }
7534  }
7535 
7536  for( j = 0; j < consdata->nexprtrees; ++j )
7537  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]); ++i )
7538  {
7539  var = SCIPexprtreeGetVars(consdata->exprtrees[j])[i];
7540  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
7541  {
7542  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
7543  ++nnotify;
7544  }
7545  }
7546  }
7547 
7548  if( nnotify == 0 )
7549  {
7550  SCIPdebugMessage("All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
7551  *result = SCIP_SOLVELP;
7552  }
7553 
7554  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
7555  return SCIP_OKAY;
7556 } /*lint !e715*/
7557 
7558 
7559 /** feasibility check method of constraint handler for integral solutions */
7560 static
7561 SCIP_DECL_CONSCHECK(consCheckNonlinear)
7562 {
7563  SCIP_CONSHDLRDATA* conshdlrdata;
7564  SCIP_CONSDATA* consdata;
7565  SCIP_Real maxviol;
7566  int c;
7567  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
7568 
7569  assert(scip != NULL);
7570  assert(conss != NULL || nconss == 0);
7571  assert(result != NULL);
7572 
7573  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7574  assert(conshdlrdata != NULL);
7575 
7576  *result = SCIP_FEASIBLE;
7577 
7578  /* during presolve, we do not have exprtrees in the constraints, but we can get values from the expression graph, if we have evaluated it */
7580  {
7581  SCIP_Real* varvals;
7582 
7583  assert(conshdlrdata->exprgraph != NULL);
7584 
7585  SCIP_CALL( SCIPallocBufferArray(scip, &varvals, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
7586  SCIP_CALL( SCIPgetSolVals(scip, sol, SCIPexprgraphGetNVars(conshdlrdata->exprgraph), (SCIP_VAR**)SCIPexprgraphGetVars(conshdlrdata->exprgraph), varvals) );
7587 
7588  SCIP_CALL( SCIPexprgraphEval(conshdlrdata->exprgraph, varvals) );
7589 
7590  SCIPfreeBufferArray(scip, &varvals);
7591  }
7592 
7593  /* @todo adapt proposeFeasibleSolution to function also during presolving */
7594  maxviol = 0.0;
7595  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
7599 
7600  for( c = 0; c < nconss; ++c )
7601  {
7602  assert(conss != NULL);
7603  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
7604 
7605  consdata = SCIPconsGetData(conss[c]);
7606  assert(consdata != NULL);
7607 
7608  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7609  {
7610  *result = SCIP_INFEASIBLE;
7611  if( printreason )
7612  {
7613  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
7614  SCIPinfoMessage(scip, NULL, ";\n");
7615  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
7616  {
7617  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g (scaled: %.15g)\n", consdata->lhs - consdata->activity, consdata->lhsviol);
7618  }
7619  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7620  {
7621  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g (scaled: %.15g)\n", consdata->activity - consdata->rhs, consdata->rhsviol);
7622  }
7623  }
7624 
7625  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible )
7626  return SCIP_OKAY;
7627 
7628  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
7629  maxviol = MAX(consdata->lhsviol, consdata->rhsviol);
7630 
7631  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
7632  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
7633  maypropfeasible = FALSE;
7634 
7635  if( maypropfeasible )
7636  {
7637  /* update information on linear variables that may be in- or decreased */
7638  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
7639  consdataFindUnlockedLinearVar(scip, consdata);
7640 
7641  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
7642  {
7643  /* check if there is a variable which may help to get the left hand side satisfied
7644  * if there is no such var, then we cannot get feasible */
7645  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
7646  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
7647  maypropfeasible = FALSE;
7648  }
7649  else
7650  {
7651  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
7652  /* check if there is a variable which may help to get the right hand side satisfied
7653  * if there is no such var, then we cannot get feasible */
7654  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
7655  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
7656  maypropfeasible = FALSE;
7657  }
7658  }
7659  }
7660  else
7661  {
7662  /* 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); */
7663  }
7664  }
7665 
7666  if( *result == SCIP_INFEASIBLE && maypropfeasible )
7667  {
7668  SCIP_Bool success;
7669 
7670  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
7671 
7672  /* do not pass solution to NLP heuristic if we made it feasible this way */
7673  if( success )
7674  return SCIP_OKAY;
7675  }
7676 
7677  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL )
7678  {
7679  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
7680  }
7681 
7682  return SCIP_OKAY;
7683 } /*lint !e715*/
7684 
7685 
7686 /** domain propagation method of constraint handler */
7687 static
7688 SCIP_DECL_CONSPROP(consPropNonlinear)
7689 {
7690  int dummy;
7691 
7692  assert(scip != NULL);
7693  assert(conshdlr != NULL);
7694  assert(conss != NULL || nconss == 0);
7695  assert(result != NULL);
7696 
7697  dummy = 0;
7698  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, result, &dummy, &dummy) );
7699 
7700  return SCIP_OKAY;
7701 } /*lint !e715*/
7702 
7703 /** presolving method of constraint handler */
7704 static
7705 SCIP_DECL_CONSPRESOL(consPresolNonlinear)
7706 {
7707  SCIP_CONSHDLRDATA* conshdlrdata;
7708  SCIP_CONSDATA* consdata;
7709  SCIP_RESULT propresult;
7710  SCIP_Bool havechange;
7711  SCIP_Bool domainerror;
7712  SCIP_Bool havegraphchange;
7713  int c;
7714 
7715  assert(scip != NULL);
7716  assert(conshdlr != NULL);
7717  assert(conss != NULL || nconss == 0);
7718  assert(result != NULL);
7719 
7720  *result = SCIP_DIDNOTFIND;
7721 
7722  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7723  assert(conshdlrdata != NULL);
7724  assert(conshdlrdata->exprgraph != NULL);
7725 
7726  havegraphchange = FALSE;
7727 
7728  if( !conshdlrdata->isremovedfixings )
7729  {
7730  SCIP_CALL( removeFixedNonlinearVariables(scip, conshdlr) );
7731  assert(conshdlrdata->isremovedfixings);
7732 
7733  havegraphchange = TRUE;
7734  }
7735 
7736  SCIP_CALL( SCIPexprgraphSimplify(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), SCIPepsilon(scip), conshdlrdata->maxexpansionexponent, &havechange, &domainerror) );
7737  SCIPdebugMessage("expression graph simplifier found %schange, domain error = %u\n", havechange ? "" : "no ", domainerror);
7738  havegraphchange |= havechange;
7739 
7740  /* if simplifier found some undefined expression, then declare problem as infeasible
7741  * usually, this should be discovered during domain propagation already, but since that is using interval arithmetics,
7742  * it may overestimate in a way that actually undefined expressions still get a value assigned (e.g., 0^(-1) = [-inf,inf]) */
7743  if( domainerror )
7744  {
7745  *result = SCIP_CUTOFF;
7746  return SCIP_OKAY;
7747  }
7748 
7749  if( nrounds == 0 )
7750  {
7751  /* upgrade methods may look at expression graph bounds, which are not present in the first presolving round yet */
7752  SCIP_CALL( SCIPexprgraphPropagateVarBounds(conshdlrdata->exprgraph, INTERVALINFTY, TRUE, &domainerror) );
7753 
7754  if( domainerror )
7755  {
7756  SCIPdebugMessage("propagating variable bounds through expression graph found that some expressions cannot be evaluated w.r.t. current bounds, thus cutoff\n");
7757  *result = SCIP_CUTOFF;
7758  return SCIP_OKAY;
7759  }
7760  }
7761 
7762  for( c = 0; c < nconss; ++c )
7763  {
7764  assert(conss != NULL);
7765 
7766  consdata = SCIPconsGetData(conss[c]);
7767  assert(consdata != NULL);
7768 
7769  SCIPdebugMessage("process constraint <%s>\n", SCIPconsGetName(conss[c]));
7770  SCIPdebugPrintCons(scip, conss[c], NULL);
7771 
7772  havechange = FALSE;
7773 
7774  if( !consdata->isremovedfixingslin )
7775  {
7776  SCIP_CALL( removeFixedLinearVariables(scip, conss[c]) );
7777  assert(consdata->isremovedfixingslin);
7778  havechange = TRUE;
7779  }
7780 
7781  /* the reductions below require the constraint nonlinear function to be in the expression graph, which is only the case for active constraints */
7782  if( !SCIPconsIsActive(conss[c]) )
7783  continue;
7784 
7785  if( !consdata->ispresolved || havegraphchange )
7786  {
7787  SCIP_CALL( splitOffLinearPart(scip, conshdlr, conss[c]) );
7788  }
7789 
7790  if( consdata->nlinvars == 0 && consdata->exprgraphnode == NULL )
7791  {
7792  /* all variables fixed or removed, constraint function is 0.0 now */
7793  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
7794  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
7795  {
7796  /* left hand side positive or right hand side negative */
7797  SCIPdebugMessage("constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
7798  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
7799  *result = SCIP_CUTOFF;
7800  return SCIP_OKAY;
7801  }
7802  else
7803  {
7804  /* left and right hand side are consistent */
7805  SCIPdebugMessage("constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
7806  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
7807  ++*ndelconss;
7808  *result = SCIP_SUCCESS;
7809  continue;
7810  }
7811  }
7812 
7813  /* call upgrade methods if constraint was not presolved, has been changed, or the expression graph has changed */
7814  if( !consdata->ispresolved || havechange || havegraphchange )
7815  {
7816  SCIP_Bool upgraded;
7817 
7818  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) );
7819  if( upgraded )
7820  {
7821  *result = SCIP_SUCCESS;
7822  continue;
7823  }
7824  }
7825 
7826  consdata->ispresolved = TRUE;
7827  }
7828 
7829  /* run domain propagation */
7830  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, nchgbds, ndelconss) );
7831  switch( propresult )
7832  {
7833  case SCIP_REDUCEDDOM:
7834  *result = SCIP_SUCCESS;
7835  break;
7836  case SCIP_CUTOFF:
7837  SCIPdebugMessage("propagation says problem is infeasible in presolve\n");
7838  *result = SCIP_CUTOFF;
7839  return SCIP_OKAY;
7840  default:
7841  assert(propresult == SCIP_DIDNOTFIND || propresult == SCIP_DIDNOTRUN);
7842  } /*lint !e788*/
7843 
7844  if( conshdlrdata->reformulate && !conshdlrdata->assumeconvex )
7845  {
7846  /* if other presolvers did not find enough changes for another presolving round,
7847  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
7848  * otherwise, we wait with these
7849  */
7850  if( SCIPisPresolveFinished(scip) )
7851  {
7852  int naddconssbefore;
7853 
7854  SCIPdebugMessage("reformulating expression graph\n");
7855 
7856  naddconssbefore = conshdlrdata->naddedreformconss;
7857  SCIP_CALL( reformulate(scip, conshdlr, conss, nconss, &conshdlrdata->naddedreformconss) );
7858 
7859  if( conshdlrdata->naddedreformconss > naddconssbefore )
7860  {
7861  *result = SCIP_SUCCESS;
7862  *naddconss += conshdlrdata->naddedreformconss - naddconssbefore;
7863 
7864  /* if expression graph changed, ensure that we apply all presolving techniques (esp. upgrades) in next round again */
7865  for( c = 0; c < nconss; ++c )
7866  {
7867  assert(conss[c] != NULL); /*lint !e794*/
7868 
7869  consdata = SCIPconsGetData(conss[c]); /*lint !e794*/
7870  assert(consdata != NULL);
7871 
7872  consdata->ispresolved = FALSE;
7873  }
7874  }
7875  }
7876  else
7877  {
7878  SCIPdebugMessage("presolving will wait with reformulation\n");
7879 
7880  /* if we did not try reformulations, ensure that presolving is called again even if there were only a few changes (< abortfac) */
7881  *result = SCIP_DELAYED;
7882  }
7883  }
7884 
7885  return SCIP_OKAY;
7886 } /*lint !e715*/
7887 
7888 
7889 /** variable rounding lock method of constraint handler */
7890 static
7891 SCIP_DECL_CONSLOCK(consLockNonlinear)
7892 {
7893  SCIP_CONSDATA* consdata;
7894  SCIP_Bool havelhs;
7895  SCIP_Bool haverhs;
7896  int i;
7897 
7898  assert(scip != NULL);
7899  assert(cons != NULL);
7900 
7901  /* variable locking for nonlinear part is done w.r.t. variables in the expression graph
7902  * since only active constraints have their nonlinear part in the expression graph, we can lock only active constraints
7903  */
7904  assert(SCIPconsIsActive(cons) || SCIPconsIsDeleted(cons));
7905 
7906  consdata = SCIPconsGetData(cons);
7907  assert(consdata != NULL);
7908 
7909  havelhs = !SCIPisInfinity(scip, -consdata->lhs);
7910  haverhs = !SCIPisInfinity(scip, consdata->rhs);
7911 
7912  for( i = 0; i < consdata->nlinvars; ++i )
7913  {
7914  if( consdata->lincoefs[i] > 0 )
7915  {
7916  if( havelhs )
7917  {
7918  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
7919  }
7920  if( haverhs )
7921  {
7922  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
7923  }
7924  }
7925  else
7926  {
7927  if( havelhs )
7928  {
7929  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlocksneg, nlockspos) );
7930  }
7931  if( haverhs )
7932  {
7933  SCIP_CALL( SCIPaddVarLocks(scip, consdata->linvars[i], nlockspos, nlocksneg) );
7934  }
7935  }
7936  }
7937 
7938  return SCIP_OKAY;
7939 } /*lint !e715*/
7940 
7941 /** constraint activation notification method of constraint handler */
7942 static
7943 SCIP_DECL_CONSACTIVE(consActiveNonlinear)
7944 { /*lint --e{715}*/
7945  SCIP_CONSHDLRDATA* conshdlrdata;
7946  SCIP_CONSDATA* consdata;
7947 
7948  assert(scip != NULL);
7949  assert(conshdlr != NULL);
7950  assert(cons != NULL);
7951  assert(SCIPconsIsTransformed(cons));
7952 
7953  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7954  assert(conshdlrdata != NULL);
7955  assert(conshdlrdata->exprgraph != NULL);
7956 
7957  consdata = SCIPconsGetData(cons);
7958  assert(consdata != NULL);
7959 
7960  SCIPdebugMessage("activate cons <%s>\n", SCIPconsGetName(cons));
7961 
7962  if( consdata->nexprtrees > 0 )
7963  {
7964  SCIP_Bool exprtreeisnew;
7965 
7966  assert(consdata->exprgraphnode == NULL);
7967 
7968  /* add exprtrees to expression graph */
7969  SCIP_CALL( SCIPexprgraphAddExprtreeSum(conshdlrdata->exprgraph, consdata->nexprtrees, consdata->exprtrees, consdata->nonlincoefs, &consdata->exprgraphnode, &exprtreeisnew) );
7970  assert(consdata->exprgraphnode != NULL);
7971  /* @todo do something with exprtreeisnew? */
7972 
7973  /* if during presolving, then forget expression trees */
7975  {
7976  SCIP_CALL( consdataSetExprtrees(scip, consdata, 0, NULL, NULL, FALSE) );
7977  }
7978 
7979  /* remember that we should run reformulation again */
7980  conshdlrdata->isreformulated = FALSE;
7981 
7982  /* remember that we should force backward propagation on our subgraph propagating the next time,
7983  * so possible domain restrictions are propagated into variable bounds
7984  */
7985  consdata->forcebackprop = TRUE;
7986  }
7987  else if( consdata->exprgraphnode != NULL )
7988  {
7989  /* if constraint already comes with node in expression graph, then also remember that we should run reformulation again */
7990  conshdlrdata->isreformulated = FALSE;
7991 
7992  /* remember that we should force backward propagation on our subgraph propagating the next time,
7993  * so possible domain restrictions are propagated into variable bounds
7994  */
7995  consdata->forcebackprop = TRUE;
7996  }
7997 
7998  return SCIP_OKAY;
7999 }
8000 
8001 /** constraint deactivation notification method of constraint handler */
8002 static
8003 SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
8004 { /*lint --e{715}*/
8005  SCIP_CONSHDLRDATA* conshdlrdata;
8006  SCIP_CONSDATA* consdata;
8007 
8008  assert(scip != NULL);
8009  assert(conshdlr != NULL);
8010  assert(cons != NULL);
8011  assert(SCIPconsIsTransformed(cons));
8012 
8013  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8014  assert(conshdlrdata != NULL);
8015  assert(conshdlrdata->exprgraph != NULL);
8016 
8017  consdata = SCIPconsGetData(cons);
8018  assert(consdata != NULL);
8019  assert(consdata->exprgraphnode != NULL || consdata->nexprtrees == 0);
8020 
8021  SCIPdebugMessage("deactivate cons <%s>\n", SCIPconsGetName(cons));
8022 
8023  if( consdata->exprgraphnode != NULL )
8024  {
8025  if( consdata->nexprtrees == 0 )
8026  {
8027  /* during presolving, the exprtrees in the constraint are removed, so put them back before releasing the exprgraphnode */
8028  SCIP_EXPRTREE* exprtree;
8029 
8030  /* 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 */
8031  /* @todo if infeasible in presolve, will constraints be deactivated still in presolving stage, or in exitpre? */
8033 
8034  SCIP_CALL( SCIPexprgraphGetTree(conshdlrdata->exprgraph, consdata->exprgraphnode, &exprtree) );
8035  SCIP_CALL( consdataSetExprtrees(scip, consdata, 1, &exprtree, NULL, FALSE) );
8036  }
8037 
8038  SCIP_CALL( SCIPexprgraphReleaseNode(conshdlrdata->exprgraph, &consdata->exprgraphnode) );
8039  }
8040 
8041  return SCIP_OKAY;
8042 }
8043 
8044 /** constraint enabling notification method of constraint handler */
8045 static
8046 SCIP_DECL_CONSENABLE(consEnableNonlinear)
8047 { /*lint --e{715}*/
8048  SCIP_CONSHDLRDATA* conshdlrdata;
8049  SCIP_CONSDATA* consdata;
8050  int i;
8051 
8052  assert(scip != NULL);
8053  assert(conshdlr != NULL);
8054  assert(cons != NULL);
8055  assert(SCIPconsIsTransformed(cons));
8056  assert(SCIPconsIsActive(cons));
8057 
8058  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8059  assert(conshdlrdata != NULL);
8060  assert(conshdlrdata->exprgraph != NULL);
8061 
8062  consdata = SCIPconsGetData(cons);
8063  assert(consdata != NULL);
8064 
8065  SCIPdebugMessage("enable cons <%s>\n", SCIPconsGetName(cons));
8066 
8067  if( consdata->exprgraphnode != NULL )
8068  {
8069  /* enable node of expression in expression graph */
8070  SCIPexprgraphEnableNode(conshdlrdata->exprgraph, consdata->exprgraphnode);
8071  }
8072 
8073  /* enable event catching for linear variables */
8074  consdata->isremovedfixingslin = TRUE;
8075  for( i = 0; i < consdata->nlinvars; ++i )
8076  {
8077  SCIP_CALL( catchLinearVarEvents(scip, cons, i) );
8078 
8079  consdata->isremovedfixingslin = consdata->isremovedfixingslin && SCIPvarIsActive(consdata->linvars[i]);
8080  }
8081 
8082  return SCIP_OKAY;
8083 }
8084 
8085 /** constraint disabling notification method of constraint handler */
8086 static
8087 SCIP_DECL_CONSDISABLE(consDisableNonlinear)
8088 { /*lint --e{715}*/
8089  SCIP_CONSHDLRDATA* conshdlrdata;
8090  SCIP_CONSDATA* consdata;
8091  int i;
8092 
8093  assert(scip != NULL);
8094  assert(conshdlr != NULL);
8095  assert(cons != NULL);
8096  assert(SCIPconsIsTransformed(cons));
8097 
8098  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8099  assert(conshdlrdata != NULL);
8100  assert(conshdlrdata->exprgraph != NULL);
8101 
8102  consdata = SCIPconsGetData(cons);
8103  assert(consdata != NULL);
8104  assert(consdata->lineventdata != NULL || consdata->nlinvars == 0);
8105 
8106  SCIPdebugMessage("disable cons <%s>\n", SCIPconsGetName(cons));
8107 
8108  /* disable node of expression in expression graph */
8109  if( consdata->exprgraphnode != NULL )
8110  {
8111  SCIPexprgraphDisableNode(conshdlrdata->exprgraph, consdata->exprgraphnode);
8112  }
8113 
8114  for( i = 0; i < consdata->nlinvars; ++i )
8115  {
8116  SCIP_CALL( dropLinearVarEvents(scip, cons, i) );
8117  }
8118 
8119  return SCIP_OKAY;
8120 }
8121 
8122 
8123 /** constraint display method of constraint handler */
8124 static
8125 SCIP_DECL_CONSPRINT(consPrintNonlinear)
8126 {
8127  SCIP_CONSDATA* consdata;
8128  int j;
8129 
8130  assert(scip != NULL);
8131  assert(cons != NULL);
8132 
8133  consdata = SCIPconsGetData(cons);
8134  assert(consdata != NULL);
8135 
8136  /* print left hand side for ranged rows */
8137  if( !SCIPisInfinity(scip, -consdata->lhs)
8138  && !SCIPisInfinity(scip, consdata->rhs)
8139  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
8140  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
8141 
8142  /* print coefficients and variables */
8143  if( consdata->nlinvars == 0 && consdata->nexprtrees == 0 && consdata->exprgraphnode == 0 )
8144  {
8145  SCIPinfoMessage(scip, file, "0 ");
8146  }
8147  else
8148  {
8149  if( consdata->nexprtrees > 0 )
8150  {
8151  for( j = 0; j < consdata->nexprtrees; ++j )
8152  {
8153  if( j > 0 || consdata->nonlincoefs[j] != 1.0 )
8154  SCIPinfoMessage(scip, file, " %+.20g ", consdata->nonlincoefs[j]);
8155  SCIP_CALL( SCIPexprtreePrintWithNames(consdata->exprtrees[j], SCIPgetMessagehdlr(scip), file) );
8156  }
8157  }
8158  else if( consdata->exprgraphnode != NULL )
8159  {
8160  SCIP_CONSHDLRDATA* conshdlrdata;
8161  SCIP_EXPRTREE* tree;
8162 
8163  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8164  assert(conshdlrdata != NULL);
8165  SCIP_CALL( SCIPexprgraphGetTree(conshdlrdata->exprgraph, consdata->exprgraphnode, &tree) );
8166 
8168 
8169  SCIP_CALL( SCIPexprtreeFree(&tree) );
8170  }
8171 
8172  for( j = 0; j < consdata->nlinvars; ++j )
8173  {
8174  SCIPinfoMessage(scip, file, "%+.15g<%s>[%c] ", consdata->lincoefs[j], SCIPvarGetName(consdata->linvars[j]),
8175  SCIPvarGetType(consdata->linvars[j]) == SCIP_VARTYPE_BINARY ? 'B' :
8176  SCIPvarGetType(consdata->linvars[j]) == SCIP_VARTYPE_INTEGER ? 'I' :
8177  SCIPvarGetType(consdata->linvars[j]) == SCIP_VARTYPE_IMPLINT ? 'I' : 'C');
8178  }
8179  }
8180 
8181  /* print right hand side */
8182  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
8183  {
8184  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
8185  }
8186  else if( !SCIPisInfinity(scip, consdata->rhs) )
8187  {
8188  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
8189  }
8190  else if( !SCIPisInfinity(scip, -consdata->lhs) )
8191  {
8192  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
8193  }
8194  else
8195  {
8196  SCIPinfoMessage(scip, file, " [free]");
8197  }
8198 
8199  return SCIP_OKAY;
8200 }
8201 
8202 /** constraint copying method of constraint handler */
8203 static
8204 SCIP_DECL_CONSCOPY(consCopyNonlinear)
8205 {
8206  SCIP_CONSDATA* consdata;
8207  SCIP_CONSDATA* targetconsdata;
8208  SCIP_VAR** linvars;
8209  SCIP_Real* nonlincoefs;
8210  SCIP_EXPRTREE** exprtrees;
8211  int nexprtrees;
8212  int i;
8213  int j;
8214 
8215  assert(scip != NULL);
8216  assert(cons != NULL);
8217  assert(sourcescip != NULL);
8218  assert(sourceconshdlr != NULL);
8219  assert(sourcecons != NULL);
8220  assert(varmap != NULL);
8221  assert(valid != NULL);
8222 
8223  consdata = SCIPconsGetData(sourcecons);
8224  assert(consdata != NULL);
8225 
8226  linvars = NULL;
8227  exprtrees = NULL;
8228 
8229  *valid = TRUE;
8230 
8231  if( consdata->nlinvars != 0 )
8232  {
8233  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
8234  for( i = 0; i < consdata->nlinvars && *valid; ++i )
8235  {
8236  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
8237  assert(!*valid || linvars[i] != NULL);
8238  }
8239  }
8240 
8241  nexprtrees = 0;
8242  nonlincoefs = NULL;
8243 
8244  if( *valid && consdata->nexprtrees > 0 )
8245  {
8246  SCIP_VAR** nonlinvars;
8247 
8248  nonlincoefs = consdata->nonlincoefs;
8249  nexprtrees = consdata->nexprtrees;
8250 
8251  SCIP_CALL( SCIPallocBufferArray(sourcescip, &exprtrees, nexprtrees) );
8252  BMSclearMemoryArray(exprtrees, nexprtrees);
8253  SCIP_CALL( SCIPallocBufferArray(sourcescip, &nonlinvars, SCIPexprtreeGetNVars(consdata->exprtrees[0])) );
8254 
8255  for( j = 0; j < consdata->nexprtrees; ++j )
8256  {
8257  SCIP_CALL( SCIPreallocBufferArray(sourcescip, &nonlinvars, SCIPexprtreeGetNVars(consdata->exprtrees[j])) );
8258  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]) && *valid; ++i )
8259  {
8260  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, SCIPexprtreeGetVars(consdata->exprtrees[j])[i], &nonlinvars[i], varmap, consmap, global, valid) );
8261  assert(!*valid || nonlinvars[i] != NULL);
8262  }
8263 
8264  if( *valid )
8265  {
8266  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &exprtrees[j], consdata->exprtrees[j]) );
8267  SCIP_CALL( SCIPexprtreeSetVars(exprtrees[j], SCIPexprtreeGetNVars(consdata->exprtrees[j]), nonlinvars) );
8268  }
8269  else
8270  break;
8271  }
8272 
8273  SCIPfreeBufferArray(sourcescip, &nonlinvars);
8274  }
8275 
8276  if( *valid && consdata->nexprtrees == 0 && consdata->exprgraphnode != NULL )
8277  {
8278  SCIP_CONSHDLRDATA* conshdlrdata;
8279  SCIP_VAR** nonlinvars;
8280 
8281  conshdlrdata = SCIPconshdlrGetData(sourceconshdlr);
8282 
8283  nexprtrees = 1;
8284  SCIP_CALL( SCIPallocBufferArray(sourcescip, &exprtrees, 1) );
8285 
8286  SCIP_CALL( SCIPexprgraphGetTree(conshdlrdata->exprgraph, consdata->exprgraphnode, &exprtrees[0]) );
8287 
8288  nonlinvars = SCIPexprtreeGetVars(exprtrees[0]);
8289  for( i = 0; i < SCIPexprtreeGetNVars(exprtrees[0]); ++i )
8290  {
8291  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, nonlinvars[i], &nonlinvars[i], varmap, consmap, global, valid) );
8292  assert(!*valid || nonlinvars[i] != NULL);
8293  }
8294  }
8295 
8296  if( *valid )
8297  {
8298  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name ? name : SCIPconsGetName(sourcecons),
8299  consdata->nlinvars, linvars, consdata->lincoefs,
8300  nexprtrees, exprtrees, nonlincoefs,
8301  consdata->lhs, consdata->rhs,
8302  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
8303 
8304  /* copy information on curvature */
8305  targetconsdata = SCIPconsGetData(*cons);
8306  targetconsdata->curvature = consdata->curvature;
8307  targetconsdata->iscurvchecked = consdata->iscurvchecked && global; /* if the copy is local, then curvature may change (get stronger) */
8308  }
8309 
8310  SCIPfreeBufferArrayNull(sourcescip, &linvars);
8311  if( exprtrees != NULL )
8312  {
8313  for( j = 0; j < nexprtrees; ++j )
8314  {
8315  if( exprtrees[j] != NULL )
8316  {
8317  SCIP_CALL( SCIPexprtreeFree(&exprtrees[j]) );
8318  }
8319  }
8320  SCIPfreeBufferArray(sourcescip, &exprtrees);
8321  }
8322 
8323  return SCIP_OKAY;
8324 }
8325 
8326 /** constraint method of constraint handler which returns the variables (if possible) */
8327 static
8328 SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
8329 { /*lint --e{715}*/
8330  SCIP_CONSDATA* consdata;
8331  int cnt;
8332 
8333  assert(cons != NULL);
8334 
8335  consdata = SCIPconsGetData(cons);
8336  assert(consdata != NULL);
8337 
8338  *success = TRUE;
8339 
8340  if( varssize < consdata->nlinvars )
8341  {
8342  *success = FALSE;
8343  return SCIP_OKAY;
8344  }
8345 
8346  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
8347  cnt = consdata->nlinvars;
8348 
8349  if( consdata->exprgraphnode != NULL )
8350  {
8351  SCIP_CONSHDLRDATA* conshdlrdata;
8352  int* varsusage;
8353  int i;
8354 
8355  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8356  assert(conshdlrdata != NULL);
8357 
8358  SCIP_CALL( SCIPallocBufferArray(scip, &varsusage, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
8359 
8360  SCIPexprgraphGetSubtreeVarsUsage(conshdlrdata->exprgraph, consdata->exprgraphnode, varsusage);
8361 
8362  for( i = 0; i < SCIPexprgraphGetNVars(conshdlrdata->exprgraph); ++i )
8363  {
8364  if( varsusage[i] == 0 )
8365  continue;
8366 
8367  if( cnt >= varssize )
8368  {
8369  *success = FALSE;
8370  break;
8371  }
8372 
8373  vars[cnt] = (SCIP_VAR*)(SCIPexprgraphGetVars(conshdlrdata->exprgraph)[i]);
8374  ++cnt;
8375  }
8376 
8377  SCIPfreeBufferArray(scip, &varsusage);
8378  }
8379  else
8380  {
8381  SCIP_VAR** exprvars;
8382  int nexprvars;
8383  int e;
8384 
8385  for( e = 0; e < consdata->nexprtrees; ++e )
8386  {
8387  exprvars = SCIPexprtreeGetVars(consdata->exprtrees[e]);
8388  nexprvars = SCIPexprtreeGetNVars(consdata->exprtrees[e]);
8389  assert(exprvars != NULL || nexprvars == 0);
8390 
8391  if( cnt + nexprvars > varssize )
8392  {
8393  *success = FALSE;
8394  break;
8395  }
8396 
8397  BMScopyMemoryArray(&vars[cnt], exprvars, nexprvars); /*lint !e866*/
8398  cnt += nexprvars;
8399  }
8400  }
8401 
8402  return SCIP_OKAY;
8403 }
8404 
8405 /** constraint method of constraint handler which returns the number of variables (if possible) */
8406 static
8407 SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
8408 { /*lint --e{715}*/
8409  SCIP_CONSDATA* consdata;
8410 
8411  consdata = SCIPconsGetData(cons);
8412  assert(consdata != NULL);
8413 
8414  *nvars = consdata->nlinvars;
8415 
8416  if( consdata->exprgraphnode != NULL )
8417  {
8418  SCIP_CONSHDLRDATA* conshdlrdata;
8419  int* varsusage;
8420  int i;
8421 
8422  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8423  assert(conshdlrdata != NULL);
8424 
8425  SCIP_CALL( SCIPallocBufferArray(scip, &varsusage, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
8426 
8427  SCIPexprgraphGetSubtreeVarsUsage(conshdlrdata->exprgraph, consdata->exprgraphnode, varsusage);
8428 
8429  for( i = 0; i < SCIPexprgraphGetNVars(conshdlrdata->exprgraph); ++i )
8430  if( varsusage[i] > 0 )
8431  ++*nvars;
8432 
8433  SCIPfreeBufferArray(scip, &varsusage);
8434  }
8435  else
8436  {
8437  int e;
8438 
8439  for( e = 0; e < consdata->nexprtrees; ++e )
8440  *nvars += SCIPexprtreeGetNVars(consdata->exprtrees[e]);
8441  }
8442 
8443  *success = TRUE;
8444 
8445  return SCIP_OKAY;
8446 }
8447 
8448 /** constraint parsing method of constraint handler */
8449 static
8450 SCIP_DECL_CONSPARSE(consParseNonlinear)
8451 { /*lint --e{715}*/
8452  SCIP_EXPRTREE* exprtree;
8453  SCIP_EXPR* expr;
8454  SCIP_VAR** exprvars;
8455  int nvars;
8456  SCIP_Real lhs;
8457  SCIP_Real rhs;
8458  const char* endptr;
8459  char* nonconstendptr;
8460  const char* exprstart;
8461  const char* exprlastchar;
8462  int* varnames;
8463  int* curvarname;
8464  int i;
8465 
8466  SCIPdebugMessage("cons_nonlinear::consparse parsing %s\n",str);
8467 
8468  assert(scip != NULL);
8469  assert(success != NULL);
8470  assert(str != NULL);
8471  assert(name != NULL);
8472  assert(cons != NULL);
8473 
8474  /* return if string empty */
8475  if( !*str )
8476  return SCIP_OKAY;
8477 
8478  endptr = str;
8479 
8480  expr = NULL;
8481  nvars = 0;
8482 
8483  /* set left and right hand side to their default values */
8484  lhs = -SCIPinfinity(scip);
8485  rhs = SCIPinfinity(scip);
8486 
8487  /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
8488 
8489  /* check for left hand side */
8490  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
8491  {
8492  /* there is a number coming, maybe it is a left-hand-side */
8493  if( !SCIPstrToRealValue(str, &lhs, &nonconstendptr) )
8494  {
8495  SCIPerrorMessage("error parsing number from <%s>\n", str);
8496  return SCIP_READERROR;
8497  }
8498  endptr = nonconstendptr;
8499 
8500  /* ignore whitespace */
8501  while( isspace((unsigned char)*endptr) )
8502  ++endptr;
8503 
8504  if( endptr[0] != '<' || endptr[1] != '=' )
8505  {
8506  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
8507  lhs = -SCIPinfinity(scip);
8508  }
8509  else
8510  {
8511  /* it was indeed a left-hand-side, so continue parsing after it */
8512  str = endptr + 2;
8513 
8514  /* ignore whitespace */
8515  while( isspace((unsigned char)*str) )
8516  ++str;
8517  }
8518  }
8519 
8520  /* Move endptr forward until we find end of expression */
8521  while( !(strncmp(endptr, "[free]", 6) == 0) &&
8522  !(endptr[0] == '<' && endptr[1] == '=') &&
8523  !(endptr[0] == '=' && endptr[1] == '=') &&
8524  !(endptr[0] == '>' && endptr[1] == '=') &&
8525  !(endptr[0] == '\0') )
8526  ++endptr;
8527 
8528  exprstart = str;
8529  exprlastchar = endptr - 1;
8530 
8531  *success = FALSE;
8532  str = endptr;
8533 
8534  /* check for left or right hand side */
8535  while( isspace((unsigned char)*str) )
8536  ++str;
8537 
8538  /* check for free constraint */
8539  if( strncmp(str, "[free]", 6) == 0 )
8540  {
8541  if( !SCIPisInfinity(scip, -lhs) )
8542  {
8543  SCIPerrorMessage("cannot have left hand side and [free] status \n");
8544  return SCIP_OKAY;
8545  }
8546  (*success) = TRUE;
8547  }
8548  else
8549  {
8550  switch( *str )
8551  {
8552  case '<':
8553  *success = SCIPstrToRealValue(str+2, &rhs, &nonconstendptr);
8554  break;
8555  case '=':
8556  if( !SCIPisInfinity(scip, -lhs) )
8557  {
8558  SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
8559  return SCIP_OKAY;
8560  }
8561  else
8562  {
8563  *success = SCIPstrToRealValue(str+2, &rhs, &nonconstendptr);
8564  lhs = rhs;
8565  }
8566  break;
8567  case '>':
8568  if( !SCIPisInfinity(scip, -lhs) )
8569  {
8570  SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
8571  return SCIP_OKAY;
8572  }
8573  else
8574  {
8575  *success = SCIPstrToRealValue(str+2, &lhs, &nonconstendptr);
8576  break;
8577  }
8578  case '\0':
8579  *success = TRUE;
8580  break;
8581  default:
8582  SCIPerrorMessage("unexpected character %c\n", *str);
8583  return SCIP_OKAY;
8584  }
8585  }
8586 
8587  /* 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) */
8588  SCIP_CALL( SCIPallocBufferArray(scip, &varnames, (int) (exprlastchar - exprstart) + 5) );
8589 
8590  /* parse expression */
8591  SCIP_CALL( SCIPexprParse(SCIPblkmem(scip), SCIPgetMessagehdlr(scip), &expr, exprstart, exprlastchar, &nvars, varnames) );
8592 
8593  /* get SCIP variables corresponding to variable names stored in varnames buffer */
8594  SCIP_CALL( SCIPallocBufferArray(scip, &exprvars, nvars) );
8595 
8596  curvarname = varnames;
8597  for( i = 0; i < nvars; ++i )
8598  {
8599  assert(*curvarname == i);
8600  ++curvarname;
8601 
8602  exprvars[i] = SCIPfindVar(scip, (char*)curvarname);
8603  if( exprvars[i] == NULL )
8604  {
8605  SCIPerrorMessage("Unknown SCIP variable <%s> encountered in expression.\n", (char*)curvarname);
8606  return SCIP_READERROR;
8607  }
8608 
8609  curvarname += (strlen((char*)curvarname) + 1)/sizeof(int) + 1;
8610  }
8611 
8612  /* create expression tree */
8613  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtree, expr, nvars, 0, NULL) );
8614  SCIP_CALL( SCIPexprtreeSetVars(exprtree, nvars, exprvars) );
8615 
8616  /* create constraint */
8617  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name,
8618  0, NULL, NULL,
8619  1, &exprtree, NULL,
8620  lhs, rhs,
8621  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
8622 
8623  SCIPdebugMessage("created nonlinear constraint:\n");
8624  SCIPdebugPrintCons(scip, *cons, NULL);
8625 
8626  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
8627 
8628  SCIPfreeBufferArray(scip, &exprvars);
8629  SCIPfreeBufferArray(scip, &varnames);
8630 
8631  return SCIP_OKAY;
8632 }
8633 
8634 /*
8635  * constraint specific interface methods
8636  */
8637 
8638 /** creates the handler for nonlinear constraints and includes it in SCIP */
8640  SCIP* scip /**< SCIP data structure */
8641  )
8642 {
8643  SCIP_CONSHDLRDATA* conshdlrdata;
8644  SCIP_CONSHDLR* conshdlr;
8645 
8646  /* create nonlinear constraint handler data */
8647  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
8648  BMSclearMemory(conshdlrdata);
8649 
8650  /* include constraint handler */
8653  consEnfolpNonlinear, consEnfopsNonlinear, consCheckNonlinear, consLockNonlinear,
8654  conshdlrdata) );
8655  assert(conshdlr != NULL);
8656 
8657  /* set non-fundamental callbacks via specific setter functions */
8658  SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveNonlinear) );
8659  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyNonlinear, consCopyNonlinear) );
8660  SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveNonlinear) );
8661  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteNonlinear) );
8662  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableNonlinear) );
8663  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableNonlinear) );
8664  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitNonlinear) );
8665  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreNonlinear) );
8666  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolNonlinear) );
8667  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeNonlinear) );
8668  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsNonlinear) );
8669  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsNonlinear) );
8670  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitNonlinear) );
8671  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreNonlinear) );
8672  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolNonlinear) );
8673  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpNonlinear) );
8674  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolNonlinear, CONSHDLR_MAXPREROUNDS, CONSHDLR_DELAYPRESOL) );
8675  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintNonlinear) );
8676  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropNonlinear, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
8678  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpNonlinear, consSepasolNonlinear, CONSHDLR_SEPAFREQ,
8680  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransNonlinear) );
8681  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseNonlinear) );
8682 
8683  /* add nonlinear constraint handler parameters */
8684  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/minefficacysepa",
8685  "minimal efficacy for a cut to be added to the LP during separation; overwrites separating/efficacy",
8686  &conshdlrdata->mincutefficacysepa, TRUE, 0.0001, 0.0, SCIPinfinity(scip), NULL, NULL) );
8687 
8688  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/minefficacyenfofac",
8689  "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)",
8690  &conshdlrdata->mincutefficacyenfofac, TRUE, 2.0, 1.0, SCIPinfinity(scip), NULL, NULL) );
8691 
8692  SCIP_CALL( SCIPaddCharParam(scip, "constraints/"CONSHDLR_NAME"/scaling",
8693  "whether scaling of infeasibility is 'o'ff, by sup-norm of function 'g'radient, or by left/right hand 's'ide",
8694  &conshdlrdata->scaling, TRUE, 'o', "ogs", NULL, NULL) );
8695 
8696  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/cutmaxrange",
8697  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
8698  &conshdlrdata->cutmaxrange, FALSE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
8699 
8700  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/linfeasshift",
8701  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
8702  &conshdlrdata->linfeasshift, FALSE, TRUE, NULL, NULL) );
8703 
8704 #if 0 /* don't have any expensive checks yet, so we disable this parameter for now */
8705  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/checkconvexexpensive",
8706  "whether to apply expensive curvature checking methods",
8707  &conshdlrdata->checkconvexexpensive, FALSE, TRUE, NULL, NULL) );
8708 #endif
8709 
8710  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/assumeconvex",
8711  "whether to assume that nonlinear functions in inequalities (<=) are convex (disables reformulation)",
8712  &conshdlrdata->assumeconvex, TRUE, FALSE, NULL, NULL) );
8713 
8714  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/maxproprounds",
8715  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation",
8716  &conshdlrdata->maxproprounds, FALSE, 1, 0, INT_MAX, NULL, NULL) );
8717 
8718  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/reformulate",
8719  "whether to reformulate expression graph",
8720  &conshdlrdata->reformulate, FALSE, TRUE, NULL, NULL) );
8721 
8722  SCIP_CALL( SCIPaddIntParam(scip, "constraints/"CONSHDLR_NAME"/maxexpansionexponent",
8723  "maximal exponent where still expanding non-monomial polynomials in expression simplification",
8724  &conshdlrdata->maxexpansionexponent, TRUE, 2, 1, INT_MAX, NULL, NULL) );
8725 
8726  SCIP_CALL( SCIPaddRealParam(scip, "constraints/"CONSHDLR_NAME"/sepanlpmincont",
8727  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
8728  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
8729 
8730  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/"CONSHDLR_NAME"/enfocutsremovable",
8731  "are cuts added during enforcement removable from the LP in the same node?",
8732  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
8733 
8734  conshdlrdata->linvareventhdlr = NULL;
8735  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->linvareventhdlr), CONSHDLR_NAME"_boundchange", "signals a bound change to a nonlinear constraint",
8736  processLinearVarEvent, NULL) );
8737  assert(conshdlrdata->linvareventhdlr != NULL);
8738 
8739  conshdlrdata->nonlinvareventhdlr = NULL;
8740  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->nonlinvareventhdlr), CONSHDLR_NAME"_boundchange2", "signals a bound change to a nonlinear constraint handler",
8741  processNonlinearVarEvent, (SCIP_EVENTHDLRDATA*)conshdlrdata) );
8742  assert(conshdlrdata->nonlinvareventhdlr != NULL);
8743 
8744  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
8745  processNewSolutionEvent, NULL) );
8746 
8747  /* create expression interpreter */
8748  SCIP_CALL( SCIPexprintCreate(SCIPblkmem(scip), &conshdlrdata->exprinterpreter) );
8749 
8750  /* create expression graph */
8751  SCIP_CALL( SCIPexprgraphCreate(SCIPblkmem(scip), &conshdlrdata->exprgraph, -1, -1,
8752  exprgraphVarAdded, exprgraphVarRemove, NULL, (void*)conshdlrdata) );
8753  conshdlrdata->isremovedfixings = TRUE;
8754  conshdlrdata->ispropagated = TRUE;
8755 
8756  conshdlrdata->scip = scip;
8757 
8758  return SCIP_OKAY;
8759 }
8760 
8761 /** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
8763  SCIP* scip, /**< SCIP data structure */
8764  SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)),/**< method to call for upgrading nonlinear constraint, or NULL */
8765  SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)),/**< method to call for reformulating expression graph node, or NULL */
8766  int priority, /**< priority of upgrading method */
8767  SCIP_Bool active, /**< should the upgrading method by active by default? */
8768  const char* conshdlrname /**< name of the constraint handler */
8769  )
8770 {
8771  SCIP_CONSHDLR* conshdlr;
8772  SCIP_CONSHDLRDATA* conshdlrdata;
8773  SCIP_NLCONSUPGRADE* nlconsupgrade;
8774  char paramname[SCIP_MAXSTRLEN];
8775  char paramdesc[SCIP_MAXSTRLEN];
8776  int i;
8777 
8778  assert(conshdlrname != NULL );
8779 
8780  /* ignore empty upgrade functions */
8781  if( nonlinconsupgd == NULL && nodereform == NULL )
8782  return SCIP_OKAY;
8783 
8784  /* find the nonlinear constraint handler */
8785  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
8786  if( conshdlr == NULL )
8787  {
8788  SCIPerrorMessage("nonlinear constraint handler not found\n");
8789  return SCIP_PLUGINNOTFOUND;
8790  }
8791 
8792  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8793  assert(conshdlrdata != NULL);
8794 
8795  /* check whether upgrade method exists already */
8796  for( i = conshdlrdata->nnlconsupgrades - 1; i >= 0; --i )
8797  {
8798  if( conshdlrdata->nlconsupgrades[i]->nlconsupgd == nonlinconsupgd && conshdlrdata->nlconsupgrades[i]->nodereform == nodereform)
8799  {
8800 #ifdef SCIP_DEBUG
8801  SCIPwarningMessage(scip, "Try to add already known upgrade method pair (%p,%p) for constraint handler <%s>.\n", nonlinconsupgd, nodereform, conshdlrname); /*lint !e611*/
8802 #endif
8803  return SCIP_OKAY;
8804  }
8805  }
8806 
8807  /* create a nonlinear constraint upgrade data object */
8808  SCIP_CALL( SCIPallocMemory(scip, &nlconsupgrade) );
8809  nlconsupgrade->nlconsupgd = nonlinconsupgd;
8810  nlconsupgrade->nodereform = nodereform;
8811  nlconsupgrade->priority = priority;
8812  nlconsupgrade->active = active;
8813 
8814  /* insert nonlinear constraint upgrade method into constraint handler data */
8815  assert(conshdlrdata->nnlconsupgrades <= conshdlrdata->nlconsupgradessize);
8816  if( conshdlrdata->nnlconsupgrades+1 > conshdlrdata->nlconsupgradessize )
8817  {
8818  int newsize;
8819 
8820  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nnlconsupgrades+1);
8821  SCIP_CALL( SCIPreallocMemoryArray(scip, &conshdlrdata->nlconsupgrades, newsize) );
8822  conshdlrdata->nlconsupgradessize = newsize;
8823  }
8824  assert(conshdlrdata->nnlconsupgrades+1 <= conshdlrdata->nlconsupgradessize);
8825 
8826  for( i = conshdlrdata->nnlconsupgrades; i > 0 && conshdlrdata->nlconsupgrades[i-1]->priority < nlconsupgrade->priority; --i )
8827  conshdlrdata->nlconsupgrades[i] = conshdlrdata->nlconsupgrades[i-1];
8828  assert(0 <= i && i <= conshdlrdata->nnlconsupgrades);
8829  conshdlrdata->nlconsupgrades[i] = nlconsupgrade;
8830  conshdlrdata->nnlconsupgrades++;
8831 
8832  /* adds parameter to turn on and off the upgrading step */
8833  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/"CONSHDLR_NAME"/upgrade/%s", conshdlrname);
8834  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
8836  paramname, paramdesc,
8837  &nlconsupgrade->active, FALSE, active, NULL, NULL) );
8838 
8839  return SCIP_OKAY;
8840 }
8841 
8842 /** creates and captures a nonlinear constraint
8843  * this variant takes expression trees as input
8844  *
8845  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8846  */
8848  SCIP* scip, /**< SCIP data structure */
8849  SCIP_CONS** cons, /**< pointer to hold the created constraint */
8850  const char* name, /**< name of constraint */
8851  int nlinvars, /**< number of linear variables in the constraint */
8852  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
8853  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
8854  int nexprtrees, /**< number of expression trees for nonlinear part of constraint */
8855  SCIP_EXPRTREE** exprtrees, /**< expression trees for nonlinear part of constraint */
8856  SCIP_Real* nonlincoefs, /**< coefficients for expression trees for nonlinear part, or NULL if all 1.0 */
8857  SCIP_Real lhs, /**< left hand side of constraint */
8858  SCIP_Real rhs, /**< right hand side of constraint */
8859  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
8860  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
8861  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
8862  * Usually set to TRUE. */
8863  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
8864  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8865  SCIP_Bool check, /**< should the constraint be checked for feasibility?
8866  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8867  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
8868  * Usually set to TRUE. */
8869  SCIP_Bool local, /**< is constraint only valid locally?
8870  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
8871  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
8872  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
8873  * adds coefficients to this constraint. */
8874  SCIP_Bool dynamic, /**< is constraint subject to aging?
8875  * Usually set to FALSE. Set to TRUE for own cuts which
8876  * are seperated as constraints. */
8877  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
8878  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
8879  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
8880  * if it may be moved to a more global node?
8881  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
8882  )
8883 {
8884  SCIP_CONSHDLR* conshdlr;
8885  SCIP_CONSDATA* consdata;
8886  int i;
8887 
8888  assert(linvars != NULL || nlinvars == 0);
8889  assert(lincoefs != NULL || nlinvars == 0);
8890  assert(exprtrees != NULL || nexprtrees == 0);
8891  assert(modifiable == FALSE); /* we do not support column generation */
8892 
8893  /* find the nonlinear constraint handler */
8894  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
8895  if( conshdlr == NULL )
8896  {
8897  SCIPerrorMessage("nonlinear constraint handler not found\n");
8898  return SCIP_PLUGINNOTFOUND;
8899  }
8900 
8901  /* create constraint data */
8902  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
8903 
8904  consdata->lhs = lhs;
8905  consdata->rhs = rhs;
8906 
8907  /* create constraint */
8908  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
8909  local, modifiable, dynamic, removable, stickingatnode) );
8910 
8911  /* add linear variables */
8912  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
8913  for( i = 0; i < nlinvars; ++i )
8914  {
8915  if( SCIPisZero(scip, lincoefs[i]) ) /*lint !e613*/
8916  continue;
8917 
8918  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) ); /*lint !e613*/
8919  }
8920 
8921  /* set expression trees */
8922  SCIP_CALL( consdataSetExprtrees(scip, consdata, nexprtrees, exprtrees, nonlincoefs, TRUE) );
8923 
8924  SCIPdebugMessage("created nonlinear constraint ");
8925  SCIPdebugPrintCons(scip, *cons, NULL);
8926 
8927  return SCIP_OKAY;
8928 }
8929 
8930 /** creates and captures a nonlinear constraint
8931  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
8932  * method SCIPcreateConsNonlinear(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
8933  *
8934  * this variant takes expression trees as input
8935  *
8936  * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration
8937  *
8938  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8939  */
8941  SCIP* scip, /**< SCIP data structure */
8942  SCIP_CONS** cons, /**< pointer to hold the created constraint */
8943  const char* name, /**< name of constraint */
8944  int nlinvars, /**< number of linear variables in the constraint */
8945  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
8946  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
8947  int nexprtrees, /**< number of expression trees for nonlinear part of constraint */
8948  SCIP_EXPRTREE** exprtrees, /**< expression trees for nonlinear part of constraint */
8949  SCIP_Real* nonlincoefs, /**< coefficients for expression trees for nonlinear part, or NULL if all 1.0 */
8950  SCIP_Real lhs, /**< left hand side of constraint */
8951  SCIP_Real rhs /**< right hand side of constraint */
8952  )
8953 {
8954  assert(scip != NULL);
8955 
8956  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nexprtrees, exprtrees,
8957  nonlincoefs, lhs, rhs,
8958  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
8959 
8960  return SCIP_OKAY;
8961 }
8962 
8963 /** creates and captures a nonlinear constraint
8964  * this variant takes a node of the expression graph as input and can only be used during presolving
8965  * it is assumed that the nonlinear constraint will be added to the transformed problem short after creation
8966  * the given exprgraphnode is captured in this method
8967  *
8968  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8969  */
8971  SCIP* scip, /**< SCIP data structure */
8972  SCIP_CONS** cons, /**< pointer to hold the created constraint */
8973  const char* name, /**< name of constraint */
8974  int nlinvars, /**< number of linear variables in the constraint */
8975  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
8976  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
8977  SCIP_EXPRGRAPHNODE* exprgraphnode, /**< expression graph node associated to nonlinear expression */
8978  SCIP_Real lhs, /**< left hand side of constraint */
8979  SCIP_Real rhs, /**< right hand side of constraint */
8980  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
8981  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
8982  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
8983  * Usually set to TRUE. */
8984  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
8985  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8986  SCIP_Bool check, /**< should the constraint be checked for feasibility?
8987  * TRUE for model constraints, FALSE for additional, redundant constraints. */
8988  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
8989  * Usually set to TRUE. */
8990  SCIP_Bool local, /**< is constraint only valid locally?
8991  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
8992  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
8993  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
8994  * adds coefficients to this constraint. */
8995  SCIP_Bool dynamic, /**< is constraint subject to aging?
8996  * Usually set to FALSE. Set to TRUE for own cuts which
8997  * are seperated as constraints. */
8998  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
8999  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9000  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9001  * if it may be moved to a more global node?
9002  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9003  )
9004 {
9005  SCIP_CONSHDLR* conshdlr;
9006  SCIP_CONSDATA* consdata;
9007  int i;
9008 
9009  assert(modifiable == FALSE); /* we do not support column generation */
9010  assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING);
9011 
9012  /* find the nonlinear constraint handler */
9013  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9014  if( conshdlr == NULL )
9015  {
9016  SCIPerrorMessage("nonlinear constraint handler not found\n");
9017  return SCIP_PLUGINNOTFOUND;
9018  }
9019 
9020  /* create constraint data */
9021  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
9022 
9023  consdata->lhs = lhs;
9024  consdata->rhs = rhs;
9025 
9026  /* create constraint */
9027  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
9028  local, modifiable, dynamic, removable, stickingatnode) );
9029 
9030  /* add linear variables */
9031  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
9032  for( i = 0; i < nlinvars; ++i )
9033  {
9034  if( SCIPisZero(scip, lincoefs[i]) )
9035  continue;
9036 
9037  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) );
9038  }
9039 
9040  /* set expression graph node */
9041  if( exprgraphnode != NULL )
9042  {
9043  consdata->exprgraphnode = exprgraphnode;
9044  consdata->curvature = SCIP_EXPRCURV_UNKNOWN;
9045  consdata->iscurvchecked = FALSE;
9046  consdata->activity = SCIP_INVALID;
9047  SCIPexprgraphCaptureNode(exprgraphnode);
9048  }
9049 
9050  SCIPdebugMessage("created nonlinear constraint ");
9051  SCIPdebugPrintCons(scip, *cons, NULL);
9052 
9053  return SCIP_OKAY;
9054 }
9055 
9056 /** creates and captures a nonlinear constraint
9057  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
9058  * method SCIPcreateConsNonlinear(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
9059  *
9060  * this variant takes a node of the expression graph as input and can only be used during presolving
9061  * it is assumed that the nonlinear constraint will be added to the transformed problem short after creation
9062  * the given exprgraphnode is captured in this method
9063  *
9064  * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration
9065  *
9066  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9067  */
9069  SCIP* scip, /**< SCIP data structure */
9070  SCIP_CONS** cons, /**< pointer to hold the created constraint */
9071  const char* name, /**< name of constraint */
9072  int nlinvars, /**< number of linear variables in the constraint */
9073  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
9074  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
9075  SCIP_EXPRGRAPHNODE* exprgraphnode, /**< expression graph node associated to nonlinear expression */
9076  SCIP_Real lhs, /**< left hand side of constraint */
9077  SCIP_Real rhs /**< right hand side of constraint */
9078  )
9079 {
9080  assert(scip != NULL);
9081 
9082  SCIP_CALL( SCIPcreateConsNonlinear2(scip, cons, name, nlinvars, linvars, lincoefs, exprgraphnode, lhs, rhs,
9083  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9084 
9085  return SCIP_OKAY;
9086 }
9087 
9088 /** adds a linear variable with coefficient to a nonlinear constraint */
9090  SCIP* scip, /**< SCIP data structure */
9091  SCIP_CONS* cons, /**< constraint */
9092  SCIP_VAR* var, /**< variable */
9093  SCIP_Real coef /**< coefficient of variable */
9094  )
9095 {
9096  assert(scip != NULL);
9097  assert(cons != NULL);
9098  assert(var != NULL);
9099  assert(!SCIPisInfinity(scip, REALABS(coef)));
9100 
9101  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
9102 
9103  return SCIP_OKAY;
9104 }
9105 
9106 /** sets the expression trees in a nonlinear constraint
9107  * constraint must not be active yet
9108  */
9110  SCIP* scip, /**< SCIP data structure */
9111  SCIP_CONS* cons, /**< constraint */
9112  int nexprtrees, /**< number of expression trees */
9113  SCIP_EXPRTREE** exprtrees, /**< new expression trees, or NULL if nexprtrees is 0 */
9114  SCIP_Real* coefs /**< coefficients of expression trees, or NULL if all 1.0 */
9115  )
9116 {
9117  assert(scip != NULL);
9118  assert(cons != NULL);
9119  assert(!SCIPconsIsActive(cons));
9120  assert(SCIPconsGetData(cons) != NULL);
9121  assert(exprtrees != NULL || nexprtrees == 0);
9122 
9123  SCIP_CALL( consdataSetExprtrees(scip, SCIPconsGetData(cons), nexprtrees, exprtrees, coefs, TRUE) );
9124 
9125  return SCIP_OKAY;
9126 }
9127 
9128 /** adds expression trees to a nonlinear constraint
9129  * constraint must not be active yet
9130  */
9132  SCIP* scip, /**< SCIP data structure */
9133  SCIP_CONS* cons, /**< constraint */
9134  int nexprtrees, /**< number of expression trees */
9135  SCIP_EXPRTREE** exprtrees, /**< new expression trees, or NULL if nexprtrees is 0 */
9136  SCIP_Real* coefs /**< coefficients of expression trees, or NULL if all 1.0 */
9137  )
9138 {
9139  assert(scip != NULL);
9140  assert(cons != NULL);
9141  assert(!SCIPconsIsActive(cons));
9142  assert(SCIPconsGetData(cons) != NULL);
9143  assert(exprtrees != NULL || nexprtrees == 0);
9144 
9145  SCIP_CALL( consdataAddExprtrees(scip, SCIPconsGetData(cons), nexprtrees, exprtrees, coefs, TRUE) );
9146 
9147  return SCIP_OKAY;
9148 }
9149 
9150 /** gets the nonlinear constraint as a nonlinear row representation */
9152  SCIP* scip, /**< SCIP data structure */
9153  SCIP_CONS* cons, /**< constraint */
9154  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
9155  )
9156 {
9157  SCIP_CONSDATA* consdata;
9158 
9159  assert(cons != NULL);
9160  assert(nlrow != NULL);
9161 
9162  consdata = SCIPconsGetData(cons);
9163  assert(consdata != NULL);
9164 
9165  if( consdata->nlrow == NULL )
9166  {
9167  SCIP_CALL( createNlRow(scip, cons) );
9168  }
9169  assert(consdata->nlrow != NULL);
9170  *nlrow = consdata->nlrow;
9171 
9172  return SCIP_OKAY;
9173 }
9174 
9175 /** gets the number of variables in the linear term of a nonlinear constraint */
9177  SCIP* scip, /**< SCIP data structure */
9178  SCIP_CONS* cons /**< constraint */
9179  )
9180 {
9181  assert(cons != NULL);
9182  assert(SCIPconsGetData(cons) != NULL);
9183 
9184  return SCIPconsGetData(cons)->nlinvars;
9185 }
9186 
9187 /** gets the variables in the linear part of a nonlinear constraint */
9189  SCIP* scip, /**< SCIP data structure */
9190  SCIP_CONS* cons /**< constraint */
9191  )
9192 {
9193  assert(cons != NULL);
9194  assert(SCIPconsGetData(cons) != NULL);
9195 
9196  return SCIPconsGetData(cons)->linvars;
9197 }
9198 
9199 /** gets the coefficients in the linear part of a nonlinear constraint */
9201  SCIP* scip, /**< SCIP data structure */
9202  SCIP_CONS* cons /**< constraint */
9203  )
9204 {
9205  assert(cons != NULL);
9206  assert(SCIPconsGetData(cons) != NULL);
9207 
9208  return SCIPconsGetData(cons)->lincoefs;
9209 }
9210 
9211 /** gets the number of expression trees of a nonlinear constraint */
9213  SCIP* scip, /**< SCIP data structure */
9214  SCIP_CONS* cons /**< constraint */
9215  )
9216 {
9217  assert(cons != NULL);
9218  assert(SCIPconsGetData(cons) != NULL);
9220 
9221  return SCIPconsGetData(cons)->nexprtrees;
9222 }
9223 
9224 /** gets the expression trees of a nonlinear constraint */
9226  SCIP* scip, /**< SCIP data structure */
9227  SCIP_CONS* cons /**< constraint */
9228  )
9229 {
9230  assert(cons != NULL);
9231  assert(SCIPconsGetData(cons) != NULL);
9233 
9234  return SCIPconsGetData(cons)->exprtrees;
9235 }
9236 
9237 /** gets the coefficients of the expression trees of a nonlinear constraint */
9239  SCIP* scip, /**< SCIP data structure */
9240  SCIP_CONS* cons /**< constraint */
9241  )
9242 {
9243  assert(cons != NULL);
9244  assert(SCIPconsGetData(cons) != NULL);
9246 
9247  return SCIPconsGetData(cons)->nonlincoefs;
9248 }
9249 
9250 /** gets the expression graph node of a nonlinear constraint */
9252  SCIP* scip, /**< SCIP data structure */
9253  SCIP_CONS* cons /**< constraint */
9254  )
9255 {
9256  assert(cons != NULL);
9257  assert(SCIPconsGetData(cons) != NULL);
9258 
9259  return SCIPconsGetData(cons)->exprgraphnode;
9260 }
9261 
9262 /** gets the left hand side of a nonlinear constraint */
9264  SCIP* scip, /**< SCIP data structure */
9265  SCIP_CONS* cons /**< constraint */
9266  )
9267 {
9268  assert(cons != NULL);
9269  assert(SCIPconsGetData(cons) != NULL);
9270 
9271  return SCIPconsGetData(cons)->lhs;
9272 }
9273 
9274 /** gets the right hand side of a nonlinear constraint */
9276  SCIP* scip, /**< SCIP data structure */
9277  SCIP_CONS* cons /**< constraint */
9278  )
9279 {
9280  assert(cons != NULL);
9281  assert(SCIPconsGetData(cons) != NULL);
9282 
9283  return SCIPconsGetData(cons)->rhs;
9284 }
9285 
9286 /** check the function of a nonlinear constraint for convexity/concavity, if not done yet */
9288  SCIP* scip, /**< SCIP data structure */
9289  SCIP_CONS* cons /**< constraint */
9290  )
9291 {
9292  SCIP_CONSHDLR* conshdlr;
9293  SCIP_CONSHDLRDATA* conshdlrdata;
9294 
9295  assert(scip != NULL);
9296  assert(cons != NULL);
9297 
9298  conshdlr = SCIPconsGetHdlr(cons);
9299  assert(conshdlr != NULL);
9300  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9301  assert(conshdlrdata != NULL);
9302 
9303  SCIP_CALL( checkCurvature(scip, cons, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
9304 
9305  return SCIP_OKAY;
9306 }
9307 
9308 /** gets the curvature of the nonlinear function of a nonlinear constraint */
9310  SCIP* scip, /**< SCIP data structure */
9311  SCIP_CONS* cons, /**< constraint */
9312  SCIP_Bool checkcurv, /**< whether to check constraint curvature, if not checked before */
9313  SCIP_EXPRCURV* curvature /**< pointer to store curvature of constraint */
9314  )
9315 {
9316  SCIP_CONSHDLR* conshdlr;
9317  SCIP_CONSHDLRDATA* conshdlrdata;
9318  SCIP_CONSDATA* consdata;
9319 
9320  assert(scip != NULL);
9321  assert(cons != NULL);
9322  assert(curvature != NULL);
9323 
9324  consdata = SCIPconsGetData(cons);
9325  assert(consdata != NULL);
9326 
9327  conshdlr = SCIPconsGetHdlr(cons);
9328  assert(conshdlr != NULL);
9329  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9330  assert(conshdlrdata != NULL);
9331 
9332  if( checkcurv && !consdata->iscurvchecked )
9333  {
9334  SCIP_CALL( checkCurvature(scip, cons, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
9335  }
9336 
9337  *curvature = consdata->curvature;
9338 
9339  return SCIP_OKAY;
9340 }
9341 
9342 /** gets the curvature of the expression trees (multiplied by their coefficient) of a nonlinear constraint */
9344  SCIP* scip, /**< SCIP data structure */
9345  SCIP_CONS* cons, /**< constraint */
9346  SCIP_Bool checkcurv, /**< whether to check constraint curvature, if not checked before */
9347  SCIP_EXPRCURV** curvatures /**< buffer to store curvatures of exprtrees */
9348  )
9349 {
9350  SCIP_CONSHDLR* conshdlr;
9351  SCIP_CONSHDLRDATA* conshdlrdata;
9352  SCIP_CONSDATA* consdata;
9353 
9354  assert(scip != NULL);
9355  assert(cons != NULL);
9356  assert(curvatures != NULL);
9358 
9359  consdata = SCIPconsGetData(cons);
9360  assert(consdata != NULL);
9361 
9362  conshdlr = SCIPconsGetHdlr(cons);
9363  assert(conshdlr != NULL);
9364  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9365  assert(conshdlrdata != NULL);
9366 
9367  assert(SCIPconsGetData(cons) != NULL);
9368 
9369  if( checkcurv && !consdata->iscurvchecked )
9370  {
9371  SCIP_CALL( checkCurvature(scip, cons, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
9372  }
9373 
9374  *curvatures = consdata->curvatures;
9375 
9376  return SCIP_OKAY;
9377 }
9378 
9379 /** computes the violation of a nonlinear constraint by a solution */
9381  SCIP* scip, /**< SCIP data structure */
9382  SCIP_CONS* cons, /**< constraint */
9383  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
9384  SCIP_Real* violation /**< pointer to store violation of constraint */
9385  )
9386 {
9387  SCIP_CONSHDLR* conshdlr;
9388  SCIP_CONSDATA* consdata;
9389 
9390  assert(scip != NULL);
9391  assert(cons != NULL);
9392  assert(violation != NULL);
9393 
9395  {
9396  /* @todo make available */
9397  SCIPwarningMessage(scip, "SCIPgetViolationNonlinear is not available for active constraints during presolve.\n");
9398  *violation = SCIP_INVALID;
9399  return SCIP_OKAY;
9400  }
9401 
9402  conshdlr = SCIPconsGetHdlr(cons);
9403  assert(conshdlr != NULL);
9404 
9405  SCIP_CALL( computeViolation(scip, conshdlr, cons, sol) );
9406 
9407  consdata = SCIPconsGetData(cons);
9408  assert(consdata != NULL);
9409 
9410  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
9411 
9412  return SCIP_OKAY;
9413 }
9414 
9415 /** gets expression graph of nonlinear constraint handler */
9417  SCIP* scip, /**< SCIP data structure */
9418  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
9419  )
9420 {
9421  SCIP_CONSHDLRDATA* conshdlrdata;
9422 
9423  assert(scip != NULL);
9424  assert(conshdlr != NULL);
9425 
9426  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9427  assert(conshdlrdata != NULL);
9428  assert(conshdlrdata->exprgraph != NULL);
9429 
9430  return conshdlrdata->exprgraph;
9431 }
9432