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