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