Scippy

SCIP

Solving Constraint Integer Programs

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