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