Scippy

SCIP

Solving Constraint Integer Programs

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