Scippy

SCIP

Solving Constraint Integer Programs

cons_bivariate.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2018 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_bivariate.c
17  * @brief constraint handler for bivariate nonlinear constraints \f$\textrm{lhs} \leq f(x,y) + c z \leq \textrm{rhs}\f$
18  * @author Martin Ballerstein
19  * @author Dennis Michaels
20  * @author Stefan Vigerske
21  */
22 
23 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24 
25 #include <assert.h>
26 #include <math.h>
27 
28 #include "scip/cons_bivariate.h"
29 #include "scip/cons_linear.h"
30 #include "scip/cons_quadratic.h"
31 #include "scip/cons_nonlinear.h"
32 #include "scip/heur_subnlp.h"
33 #include "scip/heur_trysol.h"
34 #include "scip/debug.h"
35 #include "nlpi/nlpi.h"
36 #include "nlpi/exprinterpret.h"
37 
38 /* constraint handler properties */
39 #define CONSHDLR_NAME "bivariate"
40 #define CONSHDLR_DESC "constraint handler for constraints of the form lhs <= f(x,y) + c*z <= rhs where f(x,y) is a bivariate function"
41 #define CONSHDLR_SEPAPRIORITY 5 /**< priority of the constraint handler for separation */
42 #define CONSHDLR_ENFOPRIORITY -55 /**< priority of the constraint handler for constraint enforcing */
43 #define CONSHDLR_CHECKPRIORITY -3600000 /**< priority of the constraint handler for checking feasibility */
44 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
45 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
46 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
47  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
48 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
49 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
50 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
51 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
52 
53 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_FAST
54 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
55 
56 #define INTERVALINFTY 1E+43 /**< value for infinity in interval operations */
57 #define NEWTONMAXITER 1000 /**< maximal number of iterations in newton method */
58 #define INITLPMAXVARVAL 1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
59 
60 #define QUADCONSUPGD_PRIORITY 5000 /**< priority of the constraint handler for upgrading of quadratic constraints */
61 #define NONLINCONSUPGD_PRIORITY 10000 /**< priority of the constraint handler for upgrading of nonlinear constraints */
62 
63 /* activate the following define to get output on number of bivariate constraints for each convexity-type during INITSOL */
64 /* #define TYPESTATISTICS */
65 
66 /*
67  * Data structures
68  */
69 
70 /** data structure to cache data used for separation of convex-concave constraints */
71 struct SepaData_ConvexConcave
72 {
73  SCIP_Bool linearinx; /**< whether the function is linear in x */
74  SCIP_Bool lineariny; /**< whether the function is linear in y */
75  SCIP_EXPRTREE* f_yfixed; /**< expression tree for f(x,yfixed) */
76  SCIP_EXPRTREE* f_neg_swapped; /**< expression tree for -f(y,x) */
77  SCIP_EXPRTREE* f_neg_swapped_yfixed;/**< expression tree for -f(y,xfixed) */
78  SCIP_EXPRTREE* vred; /**< expression tree for vred to underestimate f(x,y) */
79  SCIP_EXPRTREE* vred_neg_swapped; /**< expression tree for vred to underestimate -f(y,x) */
80 };
81 /** data structure to cache data used for separation of convex-concave constraints */
82 typedef struct SepaData_ConvexConcave SEPADATA_CONVEXCONCAVE;
83 
84 /** constraint data for bivariate constraints */
85 struct SCIP_ConsData
86 {
87  SCIP_EXPRTREE* f; /**< expression tree of bivariate function f(x,y) */
88  SCIP_BIVAR_CONVEXITY convextype; /**< kind of convexity of f(x,y) */
89  SCIP_VAR* z; /**< linear variable */
90  SCIP_Real zcoef; /**< coefficient of linear variable */
91  SCIP_Real lhs; /**< left hand side */
92  SCIP_Real rhs; /**< right hand side */
93 
94  SCIP_Real activity; /**< activity of bivariate function w.r.t. current solution */
95  SCIP_Real lhsviol; /**< violation of left hand side in current solution */
96  SCIP_Real rhsviol; /**< violation of left hand side in current solution */
97 
98  unsigned int mayincreasez:1; /**< whether z can be increased without harming other constraints */
99  unsigned int maydecreasez:1; /**< whether z can be decreased without harming other constraints */
100  int eventfilterpos; /**< position of z var events in SCIP event filter */
101 
102  SCIP_EXPRGRAPHNODE* exprgraphnode; /**< node in expression graph corresponding to bivariate function */
103 
104  SEPADATA_CONVEXCONCAVE sepaconvexconcave; /**< separation data for convex-concave constraints */
105 };
106 
107 /** constraint handler data */
108 struct SCIP_ConshdlrData
109 {
110  SCIP_EXPRINT* exprinterpreter; /**< expression interpreter (computer gradients and hessians) */
111 
112  SCIP_Real cutmaxrange; /**< maximal range (maximal coef / minimal coef) of a cut in order to be added to LP */
113  SCIP_Bool linfeasshift; /**< whether to make solutions in check feasible if possible */
114  int maxproprounds; /**< limit on number of propagation rounds for a single constraint within one round of SCIP propagation */
115  int ninitlprefpoints; /**< number of reference points in each direction where to compute linear support for envelope in LP initialization */
116  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
117 
118  SCIP_EVENTHDLR* linvareventhdlr; /**< handler for linear variable bound change events */
119  SCIP_EVENTHDLR* nonlinvareventhdlr; /**< handler for nonlinear variable bound change events */
120  SCIP_HEUR* subnlpheur; /**< a pointer to the subNLP heuristic */
121  SCIP_HEUR* trysolheur; /**< a pointer to the TRYSOL heuristic, if available */
122  int newsoleventfilterpos;/**< filter position of new solution event handler, if catched */
123 
124  SCIP_EXPRGRAPH* exprgraph; /**< expression graph */
125  SCIP_Bool isremovedfixings; /**< whether variable fixations have been removed from the expression graph */
126  SCIP_Bool ispropagated; /**< whether the bounds on the variables in the expression graph have been propagated */
127  SCIP* scip; /**< SCIP data structure, needed in expression graph callbacks */
128 
129  SCIP_NODE* lastenfonode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
130  int nenforounds; /**< counter on number of enforcement rounds for the current node */
131 };
132 
133 
134 /*
135  * Local methods
136  */
137 
138 /** translate from one value of infinity to another
139  *
140  * if val is >= infty1, then give infty2, else give val
141  */
142 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
144 /** processes bound tightening event */
145 static
146 SCIP_DECL_EVENTEXEC(processLinearVarEvent)
147 {
148  SCIP_CONS* cons;
149 
150  assert(scip != NULL);
151  assert(event != NULL);
152  assert(eventdata != NULL);
153  assert(eventhdlr != NULL);
155 
156  cons = (SCIP_CONS*) eventdata;
157  assert(cons != NULL);
158 
160 
161  return SCIP_OKAY;
162 }
163 
164 /** catches variable bound change events on the linear variable in a bivariate constraint */
165 static
167  SCIP* scip, /**< SCIP data structure */
168  SCIP_CONS* cons /**< constraint for which to catch bound change events */
169  )
170 {
171  SCIP_CONSHDLRDATA* conshdlrdata;
172  SCIP_CONSDATA* consdata;
173  SCIP_EVENTTYPE eventtype;
174 
175  assert(scip != NULL);
176  assert(cons != NULL);
177  assert(SCIPconsIsEnabled(cons));
178  assert(SCIPconsIsTransformed(cons));
179 
180  assert(SCIPconsGetHdlr(cons) != NULL);
181  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
182  assert(conshdlrdata != NULL);
183  assert(conshdlrdata->linvareventhdlr != NULL);
184 
185  consdata = SCIPconsGetData(cons);
186  assert(consdata != NULL);
187 
188  if( consdata->z == NULL )
189  return SCIP_OKAY;
190  assert(consdata->eventfilterpos == -1);
191 
192  eventtype = SCIP_EVENTTYPE_DISABLED;
193  if( !SCIPisInfinity(scip, consdata->rhs) )
194  {
195  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest */
196  if( consdata->zcoef > 0.0 )
197  eventtype |= SCIP_EVENTTYPE_LBTIGHTENED;
198  else
199  eventtype |= SCIP_EVENTTYPE_UBTIGHTENED;
200  }
201  if( !SCIPisInfinity(scip, -consdata->lhs) )
202  {
203  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest */
204  if( consdata->zcoef > 0.0 )
205  eventtype |= SCIP_EVENTTYPE_UBTIGHTENED;
206  else
207  eventtype |= SCIP_EVENTTYPE_LBTIGHTENED;
208  }
209 
210  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->z, eventtype, conshdlrdata->linvareventhdlr, (SCIP_EVENTDATA*)cons, &consdata->eventfilterpos) );
211 
212  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
213 
214  return SCIP_OKAY;
215 }
216 
217 /** drops variable bound change events on the linear variable in a bivariate constraint */
218 static
220  SCIP* scip, /**< SCIP data structure */
221  SCIP_CONS* cons /**< constraint for which to catch bound change events */
222  )
223 {
224  SCIP_CONSHDLRDATA* conshdlrdata;
225  SCIP_CONSDATA* consdata;
226  SCIP_EVENTTYPE eventtype;
227 
228  assert(scip != NULL);
229  assert(cons != NULL);
230  assert(SCIPconsIsTransformed(cons));
231 
232  assert(SCIPconsGetHdlr(cons) != NULL);
233  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
234  assert(conshdlrdata != NULL);
235  assert(conshdlrdata->linvareventhdlr != NULL);
236 
237  consdata = SCIPconsGetData(cons);
238  assert(consdata != NULL);
239 
240  if( consdata->z == NULL )
241  return SCIP_OKAY;
242  assert(consdata->eventfilterpos >= 0);
243 
244  eventtype = SCIP_EVENTTYPE_DISABLED;
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->zcoef > 0.0 )
249  eventtype |= SCIP_EVENTTYPE_LBTIGHTENED;
250  else
251  eventtype |= SCIP_EVENTTYPE_UBTIGHTENED;
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->zcoef > 0.0 )
257  eventtype |= SCIP_EVENTTYPE_UBTIGHTENED;
258  else
259  eventtype |= SCIP_EVENTTYPE_LBTIGHTENED;
260  }
261 
262  SCIP_CALL( SCIPdropVarEvent(scip, consdata->z, eventtype, conshdlrdata->linvareventhdlr, (SCIP_EVENTDATA*)cons, consdata->eventfilterpos) );
263  consdata->eventfilterpos = -1;
264 
265  return SCIP_OKAY;
266 }
267 
268 
269 /** processes bound change events for variables in expression graph */
270 static
271 SCIP_DECL_EVENTEXEC(processNonlinearVarEvent)
272 {
273  SCIP_CONSHDLRDATA* conshdlrdata;
274  SCIP_EVENTTYPE eventtype;
275 
276  assert(scip != NULL);
277  assert(event != NULL);
278  assert(eventdata != NULL);
279  assert(eventhdlr != NULL);
280 
281  conshdlrdata = (SCIP_CONSHDLRDATA*)SCIPeventhdlrGetData(eventhdlr);
282  assert(conshdlrdata != NULL);
283  assert(conshdlrdata->exprgraph != NULL);
284 
285  eventtype = SCIPeventGetType(event);
286  assert( eventtype & (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED) );
287 
288  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
289  {
290  SCIPdebugMsg(scip, "changed %s bound on expression graph variable <%s> from %g to %g\n",
291  (eventtype & SCIP_EVENTTYPE_LBCHANGED) ? "lower" : "upper",
293 
294  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
295  conshdlrdata->ispropagated = FALSE;
296 
297  /* update variable bound in expression graph
298  * @todo should we add epsilon to variable range?
299  */
300  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
301  SCIPexprgraphSetVarNodeLb(conshdlrdata->exprgraph, (SCIP_EXPRGRAPHNODE*)eventdata,
302  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -SCIPeventGetNewbound(event))); /*lint !e666*/
303  else
304  SCIPexprgraphSetVarNodeUb(conshdlrdata->exprgraph, (SCIP_EXPRGRAPHNODE*)eventdata,
305  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, SCIPeventGetNewbound(event))); /*lint !e666*/
306  }
307  else
308  {
309  assert(eventtype & SCIP_EVENTTYPE_VARFIXED);
310  conshdlrdata->isremovedfixings = FALSE;
311  }
312 
313  return SCIP_OKAY;
314 }
315 
316 /** callback method for variable addition in expression graph */
317 static
318 SCIP_DECL_EXPRGRAPHVARADDED( exprgraphVarAdded )
319 {
320  SCIP_CONSHDLRDATA* conshdlrdata;
321  SCIP_INTERVAL varbounds;
322  SCIP_VAR* var_;
323 
324  assert(exprgraph != NULL);
325  assert(var != NULL);
326  assert(varnode != NULL);
327 
328  var_ = (SCIP_VAR*)var;
329 
330  conshdlrdata = (SCIP_CONSHDLRDATA*)userdata;
331  assert(conshdlrdata != NULL);
332  assert(conshdlrdata->exprgraph == exprgraph);
333 
334  /* catch variable bound change events */
335  SCIP_CALL( SCIPcatchVarEvent(conshdlrdata->scip, (SCIP_VAR*)var, SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED, conshdlrdata->nonlinvareventhdlr, (SCIP_EVENTDATA*)varnode, NULL) );
336  SCIPdebugMessage("catch boundchange events on new expression graph variable <%s>\n", SCIPvarGetName(var_));
337 
338  /* set current bounds in expression graph */
339  SCIPintervalSetBounds(&varbounds,
340  -infty2infty(SCIPinfinity(conshdlrdata->scip), INTERVALINFTY, -MIN(SCIPvarGetLbLocal(var_), SCIPvarGetUbLocal(var_))), /*lint !e666*/
341  +infty2infty(SCIPinfinity(conshdlrdata->scip), INTERVALINFTY, MAX(SCIPvarGetLbLocal(var_), SCIPvarGetUbLocal(var_))) /*lint !e666*/
342  );
343  SCIPexprgraphSetVarNodeBounds(exprgraph, varnode, varbounds);
344 
345  SCIP_CALL( SCIPaddVarLocks(conshdlrdata->scip, var_, 1, 1) );
346  SCIPdebugMessage("increased up- and downlocks of variable <%s>\n", SCIPvarGetName(var_));
347 
348  conshdlrdata->isremovedfixings &= SCIPvarIsActive(var_);
349  conshdlrdata->ispropagated = FALSE;
350 
351  return SCIP_OKAY;
352 }
353 
354 /** callback method for variable removal in expression graph */
355 static
356 SCIP_DECL_EXPRGRAPHVARREMOVE( exprgraphVarRemove )
357 {
358  SCIP_CONSHDLRDATA* conshdlrdata;
359  SCIP_VAR* var_;
360 
361  assert(exprgraph != NULL);
362  assert(var != NULL);
363  assert(varnode != NULL);
364 
365  var_ = (SCIP_VAR*)var;
366 
367  conshdlrdata = (SCIP_CONSHDLRDATA*)userdata;
368  assert(conshdlrdata != NULL);
369  assert(conshdlrdata->exprgraph == exprgraph);
370 
371  SCIP_CALL( SCIPdropVarEvent(conshdlrdata->scip, var_, SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED, conshdlrdata->nonlinvareventhdlr, (SCIP_EVENTDATA*)varnode, -1) );
372  SCIPdebugMessage("drop boundchange events on expression graph variable <%s>\n", SCIPvarGetName(var_));
373 
374  SCIP_CALL( SCIPaddVarLocks(conshdlrdata->scip, var_, -1, -1) );
375  SCIPdebugMessage("decreased up- and downlocks of variable <%s>\n", SCIPvarGetName(var_));
376 
377  return SCIP_OKAY;
378 }
379 
380 /** locks linear variable in a constraint */
381 static
383  SCIP* scip, /**< SCIP data structure */
384  SCIP_CONS* cons, /**< constraint where to lock a variable */
385  SCIP_VAR* var, /**< variable to lock */
386  SCIP_Real coef /**< coefficient of variable in constraint */
387  )
388 {
389  SCIP_CONSDATA* consdata;
390 
391  assert(scip != NULL);
392  assert(cons != NULL);
393  assert(var != NULL);
394  assert(coef != 0.0);
395 
396  consdata = SCIPconsGetData(cons);
397  assert(consdata != NULL);
398 
399  if( coef > 0.0 )
400  {
401  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
402  }
403  else
404  {
405  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
406  }
407 
408  return SCIP_OKAY;
409 }
410 
411 /** unlocks linear variable in a constraint */
412 static
414  SCIP* scip, /**< SCIP data structure */
415  SCIP_CONS* cons, /**< constraint where to unlock a variable */
416  SCIP_VAR* var, /**< variable to unlock */
417  SCIP_Real coef /**< coefficient of variable in constraint */
418  )
419 {
420  SCIP_CONSDATA* consdata;
421 
422  assert(scip != NULL);
423  assert(cons != NULL);
424  assert(var != NULL);
425  assert(coef != 0.0);
426 
427  consdata = SCIPconsGetData(cons);
428  assert(consdata != NULL);
429 
430  if( coef > 0.0 )
431  {
432  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
433  }
434  else
435  {
436  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
437  }
438 
439  return SCIP_OKAY;
440 }
441 
442 /** resolves variable fixations and aggregations in a constraint */
443 static
445  SCIP* scip, /**< SCIP data structure */
446  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
447  SCIP_CONS* cons, /**< constraint where to remove fixed variables */
448  SCIP_Bool* ischanged, /**< buffer to store whether something was changed in the constraint */
449  SCIP_Bool* isupgraded /**< buffer to store whether the constraint has been upgraded (and deleted) */
450  )
451 {
452 #ifndef NDEBUG
453  SCIP_CONSHDLRDATA* conshdlrdata;
454 #endif
455  SCIP_CONSDATA* consdata;
456  SCIP_EXPR* substexpr[2];
457  SCIP_VAR* var;
458  SCIP_VAR* vars[2];
459  SCIP_Real coef;
460  SCIP_Real constant;
461  int i;
462 
463  assert(conshdlr != NULL);
464  assert(scip != NULL);
465  assert(cons != NULL);
466  assert(ischanged != NULL);
467  assert(isupgraded != NULL);
468 
469 #ifndef NDEBUG
470  conshdlrdata = SCIPconshdlrGetData(conshdlr);
471  assert(conshdlrdata != NULL);
472 #endif
473 
474  consdata = SCIPconsGetData(cons);
475  assert(consdata != NULL);
476  assert(consdata->f != NULL);
477 
478  *ischanged = FALSE;
479  *isupgraded = FALSE;
480 
481  if( consdata->z != NULL && !SCIPvarIsActive(consdata->z) && SCIPvarGetStatus(consdata->z) != SCIP_VARSTATUS_MULTAGGR )
482  {
483  /* replace z by active or multaggr. variable */
484 
485  /* drop events on z, unlock and release variable */
486  SCIP_CALL( dropLinearVarEvents(scip, cons) );
487  SCIP_CALL( unlockLinearVariable(scip, cons, consdata->z, consdata->zcoef) );
488 
489  /* replace by new variable, or NULL */
490  constant = 0.0;
491  SCIP_CALL( SCIPgetProbvarSum(scip, &consdata->z, &consdata->zcoef, &constant) );
492  if( consdata->zcoef == 0.0 )
493  consdata->z = NULL;
494  if( constant != 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
495  consdata->lhs -= constant;
496  if( constant != 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
497  consdata->rhs -= constant;
498 
499  if( consdata->z != NULL )
500  {
501  /* catch events on new z, lock and capture variable, mark as not to multaggr */
502  SCIP_CALL( catchLinearVarEvents(scip, cons) );
503  SCIP_CALL( lockLinearVariable(scip, cons, consdata->z, consdata->zcoef) );
504  if( SCIPvarIsActive(consdata->z) )
505  {
506  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->z) );
507  }
508  }
509 
510  *ischanged = TRUE;
511  }
512 
513  assert(SCIPexprtreeGetNVars(consdata->f) == 2);
514  vars[0] = SCIPexprtreeGetVars(consdata->f)[0];
515  vars[1] = SCIPexprtreeGetVars(consdata->f)[1];
516 
517  if( vars[0] == NULL || vars[1] == NULL )
518  return SCIP_INVALIDDATA;
519 
522  SCIPvarGetProbvar(vars[0]) == SCIPvarGetProbvar(vars[1]) )
523  {
524  /* if number of variable reduces, then upgrade to nonlinear constraint
525  * except if we are in the exit-presolving stage, where upgrading is not allowed
526  * in the latter case, we just do nothing, which may not be most efficient, but should still work
527  */
528  SCIP_EXPRTREE* tree;
529  SCIP_CONS* nlcons;
530 
532  return SCIP_OKAY;
533 
534  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &tree, consdata->f) );
535 
536  for( i = 0; i < 2; ++i )
537  {
538  substexpr[i] = NULL;
539 
540  var = vars[i];
542  continue;
543 
544  coef = 1.0;
545  constant = 0.0;
546  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &constant) );
547 
548  if( coef == 0.0 )
549  {
550  /* replace var_i by constant in expression tree */
551  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &substexpr[i], SCIP_EXPR_CONST, constant) );
552  vars[i] = NULL;
553  }
554  else if( coef == 1.0 && constant == 0.0 )
555  {
556  /* do not need to change expression tree, just store new variable in tree */
557  substexpr[i] = NULL;
558  vars[i] = var;
559  }
560  else
561  {
562  /* replace var_i by coef * var_i + constant in expression tree */
563  SCIP_EXPR* child;
564 
565  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &child, SCIP_EXPR_VARIDX, i) );
566  SCIP_CALL( SCIPexprCreateLinear(SCIPblkmem(scip), &substexpr[i], 1, &child, &coef, constant) );
567  vars[i] = var;
568  }
569  }
570 
571  assert(substexpr[0] != NULL || substexpr[1] != NULL);
572 
573  SCIP_CALL( SCIPexprtreeSubstituteVars(tree, substexpr) );
574  if( substexpr[0] != NULL )
575  SCIPexprFreeDeep(SCIPblkmem(scip), &substexpr[0]);
576  if( substexpr[1] != NULL )
577  SCIPexprFreeDeep(SCIPblkmem(scip), &substexpr[1]);
578 
579  /* if variable 0 has been remove or is the same as variable 1, reindex 1 to 0 */
580  if( (vars[0] == NULL || vars[0] == vars[1]) && vars[1] != NULL )
581  {
582  int reindex[2];
583 
584  reindex[0] = 0;
585  reindex[1] = 0;
587  vars[0] = vars[1];
588  vars[1] = NULL;
589  }
590 
591  /* update variables array in tree */
592  assert(vars[1] == NULL || vars[0] != NULL);
593  SCIP_CALL( SCIPexprtreeSetVars(tree, vars[0] == NULL ? 0 : (vars[1] == NULL ? 1 : 2), vars) );
594 
595  SCIP_CALL( SCIPcreateConsNonlinear(scip, &nlcons, SCIPconsGetName(cons),
596  consdata->z != NULL ? 1 : 0, consdata->z != NULL ? &consdata->z : NULL, &consdata->zcoef,
597  1, &tree, NULL, consdata->lhs, consdata->rhs,
601  SCIPconsIsStickingAtNode(cons)) ); /*lint !e826*/
602  SCIP_CALL( SCIPaddCons(scip, nlcons) );
603  SCIPdebugMsg(scip, "upgraded to"); SCIPdebugPrintCons(scip, nlcons, NULL);
604  SCIP_CALL( SCIPreleaseCons(scip, &nlcons) );
605 
606  *isupgraded = TRUE;
607 
608  SCIP_CALL( SCIPexprtreeFree(&tree) );
609 
610  return SCIP_OKAY;
611  }
612 
613  for( i = 0; i < 2; ++i )
614  {
615  substexpr[i] = NULL;
616 
617  var = vars[i];
619  continue;
620 
621  coef = 1.0;
622  constant = 0.0;
623  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &constant) );
624  assert(coef != 0.0); /* fixed vars should have been handled above */
625 
626  if( coef == 1.0 && constant == 0.0 )
627  {
628  /* do not need to change expression tree, just store new variable in tree */
629  substexpr[i] = NULL;
630  vars[i] = var;
631  }
632  else
633  {
634  /* replace var_i by coef * var_i + constant in expression tree */
635  SCIP_EXPR* child;
636 
637  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &child, SCIP_EXPR_VARIDX, i) );
638  SCIP_CALL( SCIPexprCreateLinear(SCIPblkmem(scip), &substexpr[i], 1, &child, &coef, constant) );
639  vars[i] = var;
640  }
641 
642  /* update variables array in tree for next operation */
643  SCIP_CALL( SCIPexprtreeSetVars(consdata->f, 2, vars) );
644 
645  /* mark that variables in constraint should not be multiaggregated (bad for bound tightening and branching) */
646  if( SCIPvarIsActive(vars[0]) )
647  {
648  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, vars[0]) );
649  }
650  if( SCIPvarIsActive(vars[1]) )
651  {
652  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, vars[1]) );
653  }
654 
655  *ischanged = TRUE;
656  }
657 
658  /* update expression tree, if necessary */
659  if( substexpr[0] != NULL || substexpr[1] != NULL )
660  {
661  SCIP_CALL( SCIPexprtreeSubstituteVars(consdata->f, substexpr) );
662  if( substexpr[0] != NULL )
663  SCIPexprFreeDeep(SCIPblkmem(scip), &substexpr[0]);
664  if( substexpr[1] != NULL )
665  SCIPexprFreeDeep(SCIPblkmem(scip), &substexpr[1]);
666  }
667 
668  return SCIP_OKAY;
669 }
670 
671 /** removes fixed variables from expression graph */
672 static
674  SCIP* scip, /**< SCIP data structure */
675  SCIP_CONSHDLR* conshdlr /**< constraint handler */
676  )
677 {
678  SCIP_CONSHDLRDATA* conshdlrdata;
679  SCIP_VAR* var;
680  SCIP_VAR** vars;
681  SCIP_Real* coefs;
682  int nvars;
683  int varssize;
684  SCIP_Real constant;
685  int i;
686  int requsize;
687  SCIPdebug( int j );
688 
689  conshdlrdata = SCIPconshdlrGetData(conshdlr);
690  assert(conshdlrdata != NULL);
691  assert(conshdlrdata->exprgraph != NULL);
692 
693  if( conshdlrdata->isremovedfixings )
694  return SCIP_OKAY;
695 
696  varssize = 5;
697  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
698  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, varssize) );
699 
700  i = 0;
701  while( i < SCIPexprgraphGetNVars(conshdlrdata->exprgraph) )
702  {
703  var = (SCIP_VAR*) SCIPexprgraphGetVars(conshdlrdata->exprgraph)[i];
704  if( SCIPvarIsActive(var) )
705  {
706  ++i;
707  continue;
708  }
709 
710  vars[0] = var;
711  coefs[0] = 1.0;
712  constant = 0.0;
713  nvars = 1;
714  SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, coefs, &nvars, varssize, &constant, &requsize, TRUE) );
715 
716  if( requsize > varssize )
717  {
718  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requsize) );
719  SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, requsize) );
720  varssize = requsize;
721  SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, coefs, &nvars, varssize, &constant, &requsize, TRUE) );
722  assert(requsize <= varssize);
723  }
724 
725 #ifdef SCIP_DEBUG
726  SCIPdebugMsg(scip, "replace fixed variable <%s> by %g", SCIPvarGetName(var), constant);
727  for( j = 0; j < nvars; ++j )
728  {
729  SCIPdebugMsgPrint(scip, " %+g <%s>", coefs[j], SCIPvarGetName(vars[j]));
730  }
731  SCIPdebugMsgPrint(scip, "\n");
732 #endif
733 
734  SCIP_CALL( SCIPexprgraphReplaceVarByLinearSum(conshdlrdata->exprgraph, var, nvars, coefs, (void**)vars, constant) );
735 
736  i = 0;
737  }
738 
739  SCIPfreeBufferArray(scip, &vars);
740  SCIPfreeBufferArray(scip, &coefs);
741 
742  conshdlrdata->isremovedfixings = TRUE;
743 
744  return SCIP_OKAY;
745 }
746 
747 /** computes violation of a constraint */
748 static
750  SCIP* scip, /**< SCIP data structure */
751  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
752  SCIP_CONS* cons, /**< constraint */
753  SCIP_SOL* sol /**< solution or NULL if LP solution should be used */
754  )
755 { /*lint --e{666}*/
756  SCIP_CONSHDLRDATA* conshdlrdata;
757  SCIP_CONSDATA* consdata;
758  SCIP_Real xyvals[2];
759  SCIP_Real zval = 0.0;
760  SCIP_Real xlb;
761  SCIP_Real xub;
762  SCIP_Real ylb;
763  SCIP_Real yub;
764  SCIP_Real absviol;
765  SCIP_Real relviol;
766  SCIP_VAR* x;
767  SCIP_VAR* y;
768 
769  assert(scip != NULL);
770  assert(conshdlr != NULL);
771  assert(cons != NULL);
772 
773  conshdlrdata = SCIPconshdlrGetData(conshdlr);
774  assert(conshdlrdata != NULL);
775  assert(conshdlrdata->exprinterpreter != NULL);
776 
777  consdata = SCIPconsGetData(cons);
778  assert(consdata != NULL);
779 
780  if( SCIPexprtreeGetInterpreterData(consdata->f) == NULL )
781  {
782  SCIP_CALL( SCIPexprintCompile(conshdlrdata->exprinterpreter, consdata->f) );
783  }
784 
785  x = SCIPexprtreeGetVars(consdata->f)[0];
786  y = SCIPexprtreeGetVars(consdata->f)[1];
787 
788  xyvals[0] = SCIPgetSolVal(scip, sol, x);
789  xyvals[1] = SCIPgetSolVal(scip, sol, y);
790  if( consdata->z != NULL )
791  zval = SCIPgetSolVal(scip, sol, consdata->z);
792 
793  /* @todo proper handling of variables at infinity
794  * for now, just say infeasible and keep fingers crossed
795  */
796  if( SCIPisInfinity(scip, REALABS(xyvals[0])) )
797  {
798  consdata->lhsviol = consdata->rhsviol = SCIPinfinity(scip);
799  return SCIP_OKAY;
800  }
801 
802  if( SCIPisInfinity(scip, REALABS(xyvals[1])) )
803  {
804  consdata->lhsviol = consdata->rhsviol = SCIPinfinity(scip);
805  return SCIP_OKAY;
806  }
807 
808  /* project point onto box if from LP or very close to bounds to avoid eval error when function is not defined slightly outside bounds */
809  xlb = SCIPvarGetLbGlobal(x);
810  xub = SCIPvarGetUbGlobal(x);
811  ylb = SCIPvarGetLbGlobal(y);
812  yub = SCIPvarGetUbGlobal(y);
813  /* @todo handle case where variables are outside of bounds as in other constraint handlers, see also #627 */
814  if( sol == NULL )
815  {
816  assert(SCIPisFeasGE(scip, xyvals[0], xlb));
817  assert(SCIPisFeasLE(scip, xyvals[0], xub));
818  xyvals[0] = MAX(xlb, MIN(xub, xyvals[0]));
819 
820  assert(SCIPisFeasGE(scip, xyvals[1], ylb));
821  assert(SCIPisFeasLE(scip, xyvals[1], yub));
822  xyvals[1] = MAX(ylb, MIN(yub, xyvals[1]));
823 
824  if( consdata->z != NULL )
825  {
826  assert(SCIPisFeasGE(scip, zval, SCIPvarGetLbLocal(consdata->z)));
827  assert(SCIPisFeasLE(scip, zval, SCIPvarGetUbLocal(consdata->z)));
828  zval = MAX(SCIPvarGetLbLocal(consdata->z), MIN(SCIPvarGetUbLocal(consdata->z), zval));
829  }
830  }
831  else
832  {
833  if( SCIPisEQ(scip, xyvals[0], xlb) || SCIPisEQ(scip, xyvals[0], xub) )
834  xyvals[0] = MAX(xlb, MIN(xub, xyvals[0]));
835  if( SCIPisEQ(scip, xyvals[1], ylb) || SCIPisEQ(scip, xyvals[1], yub) )
836  xyvals[1] = MAX(ylb, MIN(yub, xyvals[1]));
837  }
838 
839  /* compute activity of constraint */
840  SCIP_CALL( SCIPexprintEval(conshdlrdata->exprinterpreter, consdata->f, xyvals, &consdata->activity) );
841 
842  /* point is outside the domain of f */
843  if( !SCIPisFinite(consdata->activity) )
844  {
845  consdata->lhsviol = consdata->rhsviol = SCIPinfinity(scip);
846  return SCIP_OKAY;
847  }
848 
849  if( consdata->z != NULL )
850  consdata->activity += consdata->zcoef * zval;
851 
852  /* compute violation of constraint sides */
853  absviol = 0.0;
854  relviol = 0.0;
855  if( consdata->activity < consdata->lhs && !SCIPisInfinity(scip, -consdata->lhs) )
856  {
857  consdata->lhsviol = consdata->lhs - consdata->activity;
858  absviol = consdata->lhsviol;
859  relviol = SCIPrelDiff(consdata->lhs, consdata->activity);
860  }
861  else
862  consdata->lhsviol = 0.0;
863 
864  if( consdata->activity > consdata->rhs && !SCIPisInfinity(scip, consdata->rhs) )
865  {
866  consdata->rhsviol = consdata->activity - consdata->rhs;
867  absviol = consdata->rhsviol;
868  relviol = SCIPrelDiff(consdata->activity, consdata->rhs);
869  }
870  else
871  consdata->rhsviol = 0.0;
872 
873  if( sol != NULL )
874  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
875 
876  return SCIP_OKAY;
877 }
878 
879 /** computes violation of a set of constraints */
880 static
882  SCIP* scip, /**< SCIP data structure */
883  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
884  SCIP_CONS** conss, /**< constraints */
885  int nconss, /**< number of constraints */
886  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
887  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
888  )
889 {
890  SCIP_CONSDATA* consdata;
891  SCIP_Real viol;
892  SCIP_Real maxviol;
893  int c;
894 
895  assert(scip != NULL);
896  assert(conshdlr != NULL);
897  assert(conss != NULL || nconss == 0);
898  assert(maxviolcon != NULL);
899 
900  *maxviolcon = NULL;
901 
902  maxviol = 0.0;
903 
904  for( c = 0; c < nconss; ++c )
905  {
906  assert(conss != NULL);
907  assert(conss[c] != NULL);
908 
909  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
910 
911  consdata = SCIPconsGetData(conss[c]);
912  assert(consdata != NULL);
913 
914  viol = MAX(consdata->lhsviol, consdata->rhsviol);
915  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
916  {
917  maxviol = viol;
918  *maxviolcon = conss[c];
919  }
920  }
921 
922  return SCIP_OKAY;
923 }
924 
925 /** setup vred(s;x0,y0,ylb,yub) for a given f(x,y) for computing a convex-concave underestimator
926  * vred(s;x0,y0,ylb,yub) = (yub-y0)/(yub-ylb) f((yub-ylb)/(yub-y0)x0 - (y0-ylb)/(yub-y0)*s, ylb) + (y0-ylb)/(yub-ylb) f(s,yub)
927  */
928 static
930  SCIP* scip, /**< SCIP data structure */
931  SCIP_EXPRTREE** vred, /**< buffer where to store exprtree for vred */
932  SCIP_EXPRTREE* f /**< function f(x,y) for which vred should be setup */
933  )
934 {
935  SCIP_EXPR* subst[2];
936  SCIP_Real minusone;
937  SCIP_EXPR* e1;
938  SCIP_EXPR* e2;
939  SCIP_EXPR* e3;
940  SCIP_EXPR* e4;
941  SCIP_EXPR* e5;
942  SCIP_EXPR* e6;
943  SCIP_EXPR* arg1;
944  SCIP_EXPR* arg2;
945  SCIP_EXPR* vredexpr;
946 
947  assert(scip != NULL);
948  assert(vred != NULL);
949  assert(f != NULL);
950  assert(SCIPexprGetOperator(SCIPexprtreeGetRoot(f)) != SCIP_EXPR_VARIDX); /* substitute cannot substitute the root node, but f should not be a single variable anyway */
951 
952  /* setup vred(s;x0,y0,ylb,yub) for computing a convex-concave underestimator in the case where y is not at one of its bounds
953  * vred(s;x0,y0,ylb,yub) = (yub-y0)/(yub-ylb) f((yub-ylb)/(yub-y0)x0 - (y0-ylb)/(yub-y0)*s, ylb) + (y0-ylb)/(yub-ylb) f(s,yub)
954  */
955  /* create expression for x0(yub-ylb)/(yub-y0) */
956  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e1, SCIP_EXPR_PARAM, 2) ); /* ylb */
957  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e2, SCIP_EXPR_PARAM, 3) ); /* yub */
958  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e3, SCIP_EXPR_MINUS, e2, e1) ); /* yub-ylb */
959 
960  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e1, SCIP_EXPR_PARAM, 0) ); /* x0 */
961  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e3, SCIP_EXPR_MUL, e1, e3) ); /* x0(yub-ylb) */
962 
963  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e1, SCIP_EXPR_PARAM, 1) ); /* y0 */
964  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e2, SCIP_EXPR_PARAM, 3) ); /* yub */
965  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e4, SCIP_EXPR_MINUS, e2, e1) ); /* yub-y0 */
966 
967  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e5, SCIP_EXPR_DIV, e3, e4) ); /* x0(yub-ylb)/(yub-y0) */
968 
969  /* create expression for s(y0-ylb)/(yub-y0) */
970  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e1, SCIP_EXPR_PARAM, 1) ); /* y0 */
971  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e2, SCIP_EXPR_PARAM, 2) ); /* ylb */
972  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e3, SCIP_EXPR_MINUS, e1, e2) ); /* y0-ylb */
973 
974  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e1, SCIP_EXPR_VARIDX, 0) ); /* s */
975  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e3, SCIP_EXPR_MUL, e1, e3) ); /* s(y0-ylb) */
976 
977  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e1, SCIP_EXPR_PARAM, 1) ); /* y0 */
978  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e2, SCIP_EXPR_PARAM, 3) ); /* yub */
979  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e4, SCIP_EXPR_MINUS, e2, e1) ); /* yub-y0 */
980 
981  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e6, SCIP_EXPR_DIV, e3, e4) ); /* s(y0-ylb)/(yub-y0) */
982 
983  /* create expression for (yub-ylb)/(yub-y0)x0 - (y0-ylb)/(yub-y0)*s */
984  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_MINUS, e5, e6) );
985 
986  /* create expression for ylb */
987  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_PARAM, 2) );
988 
989  /* create expression for f((yub-ylb)/(yub-y0)x0 - (y0-ylb)/(yub-y0)*s, ylb) */
991  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), arg1, subst) );
992  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
993  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
994 
995  /* create expression for f(s,yub) */
997  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_PARAM, 3) );
998  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), arg2, subst) );
999  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
1000 
1001  /* create expression for (yub-y0)/(yub-ylb) */
1002  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e1, SCIP_EXPR_PARAM, 1) ); /* y0 */
1003  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e2, SCIP_EXPR_PARAM, 3) ); /* yub */
1004  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e3, SCIP_EXPR_MINUS, e2, e1) ); /* yub-y0 */
1005 
1006  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e1, SCIP_EXPR_PARAM, 2) ); /* ylb */
1007  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e2, SCIP_EXPR_PARAM, 3) ); /* yub */
1008  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e4, SCIP_EXPR_MINUS, e2, e1) ); /* yub-ylb */
1009 
1010  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e5, SCIP_EXPR_DIV, e3, e4) ); /* (yub-y0)/(yub-ylb) */
1011 
1012  /* create expression for 1 - (yub-y0)/(yub-ylb) */
1013  minusone = -1.0;
1014  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e1, e5) ); /* (yub-y0)/(yub-ylb) */
1015  SCIP_CALL( SCIPexprCreateLinear(SCIPblkmem(scip), &e6, 1, &e1, &minusone, 1.0) ); /* 1 - (yub-y0)/(yub-ylb) */
1016 
1017  /* create expression for vred = e5*arg1 + e6*arg2 */
1018  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e1, SCIP_EXPR_MUL, e5, arg1) );
1019  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e2, SCIP_EXPR_MUL, e6, arg2) );
1020  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &vredexpr, SCIP_EXPR_PLUS, e1, e2) );
1021 
1022  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), vred, vredexpr, 1, 4, NULL) );
1023 
1024  return SCIP_OKAY;
1025 }
1026 
1027 /** initializes separation data */
1028 static
1030  SCIP* scip, /**< SCIP data structure */
1031  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
1032  SCIP_CONS* cons /**< constraint */
1033  )
1034 {
1035  SCIP_CONSDATA* consdata;
1036 
1037  assert(scip != NULL);
1038  assert(exprinterpreter != NULL);
1039  assert(cons != NULL);
1040 
1041  consdata = SCIPconsGetData(cons);
1042  assert(consdata != NULL);
1043  assert(consdata->f != NULL);
1044 
1045  switch( consdata->convextype )
1046  {
1048  {
1049  SCIP_VAR** xy;
1050  SCIP_Real ref[2];
1051  SCIP_Bool sparsity[4];
1052 
1053  if( SCIPexprtreeGetInterpreterData(consdata->f) == NULL )
1054  {
1055  SCIP_CALL( SCIPexprintCompile(exprinterpreter, consdata->f) );
1056  }
1057 
1058  xy = SCIPexprtreeGetVars(consdata->f);
1059  assert(xy != NULL);
1060 
1061  /* check if the function is linear in x or y */
1062  ref[0] = MIN(MAX(SCIPvarGetLbLocal(xy[0]), 0.0), SCIPvarGetUbLocal(xy[0])); /*lint !e666*/
1063  ref[1] = MIN(MAX(SCIPvarGetLbLocal(xy[1]), 0.0), SCIPvarGetUbLocal(xy[1])); /*lint !e666*/
1064 
1065  SCIP_CALL( SCIPexprintHessianSparsityDense(exprinterpreter, consdata->f, ref, sparsity) );
1066 
1067  consdata->sepaconvexconcave.linearinx = !sparsity[0];
1068  consdata->sepaconvexconcave.lineariny = !sparsity[3];
1069 
1070  if( !consdata->sepaconvexconcave.linearinx && !SCIPisInfinity(scip, consdata->rhs) )
1071  {
1072  SCIP_EXPR* subst[2];
1073  SCIP_Real one;
1074 
1075  /* setup f(x,yfixed) for computing a convex-concave underestimator in the case where y is at one of its bounds */
1076  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &consdata->sepaconvexconcave.f_yfixed, consdata->f) );
1077 
1078  /* x stays x, nothing to substitute
1079  * y is substituted by SCIP_EXPR_PARAM
1080  */
1081  subst[0] = NULL;
1082  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_PARAM, 0) );
1083 
1084  /* make y a parameter */
1085  SCIP_CALL( SCIPexprtreeSubstituteVars(consdata->sepaconvexconcave.f_yfixed, subst) );
1086 
1087  /* reset variables array to {x} and parameters array to {y} */
1088  one = 1.0;
1089  SCIP_CALL( SCIPexprtreeSetVars(consdata->sepaconvexconcave.f_yfixed, 1, &xy[0]) );
1090  SCIP_CALL( SCIPexprtreeSetParams(consdata->sepaconvexconcave.f_yfixed, 1, &one) );
1091 
1092  /* free subst[1] */
1093  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
1094 
1095  SCIP_CALL( SCIPexprintCompile(exprinterpreter, consdata->sepaconvexconcave.f_yfixed) );
1096 
1097  /* setup vred(s;x0,y0,ylb,yub) for computing a convex-concave underestimator in the case where y is not at one of its bounds
1098  * vred(s;x0,y0,ylb,yub) = (yub-y0)/(yub-ylb) f((yub-ylb)/(yub-y0)x0 - (y0-ylb)/(yub-y0)*s, ylb) + (y0-ylb)/(yub-ylb) f(s,yub)
1099  */
1100  SCIP_CALL( initSepaDataCreateVred(scip, &consdata->sepaconvexconcave.vred, consdata->f) );
1101  SCIP_CALL( SCIPexprintCompile(exprinterpreter, consdata->sepaconvexconcave.vred) );
1102  }
1103  else
1104  {
1105  consdata->sepaconvexconcave.f_yfixed = NULL;
1106  consdata->sepaconvexconcave.vred = NULL;
1107  }
1108 
1109  if( !consdata->sepaconvexconcave.lineariny && !SCIPisInfinity(scip, -consdata->lhs) )
1110  {
1111  /* if we have a left hand side and are not linear y in, then we may need to call
1112  * generateConvexConcaveUnderestimator for -f with swapped variables
1113  */
1114  SCIP_EXPR* minusf;
1115  SCIP_EXPR* fcopy;
1116  SCIP_VAR* vars[2];
1117  int reindex[2];
1118  SCIP_Real minusone;
1119  SCIP_Real one;
1120  SCIP_EXPR* subst[2];
1121 
1122  /* create expression for -f */
1123  minusone = -1.0;
1124  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &fcopy, SCIPexprtreeGetRoot(consdata->f)) );
1125  SCIP_CALL( SCIPexprCreateLinear(SCIPblkmem(scip), &minusf, 1, &fcopy, &minusone, 0.0) );
1126 
1127  /* reindex/swap variables */
1128  reindex[0] = 1;
1129  reindex[1] = 0;
1130  SCIPexprReindexVars(minusf, reindex);
1131 
1132  /* create expression tree for -f(y,x) */
1133  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &consdata->sepaconvexconcave.f_neg_swapped, minusf, 2, 0, NULL) );
1134 
1135  vars[0] = xy[1];
1136  vars[1] = xy[0];
1137  SCIP_CALL( SCIPexprtreeSetVars(consdata->sepaconvexconcave.f_neg_swapped, 2, vars) );
1138 
1139  SCIP_CALL( SCIPexprintCompile(exprinterpreter, consdata->sepaconvexconcave.f_neg_swapped) );
1140 
1141  /* setup -f(y, xfixed) for computing a convex-concave overestimator in the case where x is at on of it's bounds */
1142  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &consdata->sepaconvexconcave.f_neg_swapped_yfixed, consdata->sepaconvexconcave.f_neg_swapped) );
1143 
1144  /* y stays y, nothing to substitute
1145  * x is substituted by SCIP_EXPR_PARAM
1146  */
1147  subst[0] = NULL;
1148  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_PARAM, 0) );
1149 
1150  /* make x a parameter */
1151  SCIP_CALL( SCIPexprtreeSubstituteVars(consdata->sepaconvexconcave.f_neg_swapped_yfixed, subst) );
1152 
1153  /* reset variables array to {y} and parameters array to {x} */
1154  one = 1.0;
1155  SCIP_CALL( SCIPexprtreeSetVars(consdata->sepaconvexconcave.f_neg_swapped_yfixed, 1, &xy[1]) );
1156  SCIP_CALL( SCIPexprtreeSetParams(consdata->sepaconvexconcave.f_neg_swapped_yfixed, 1, &one) );
1157 
1158  /* free subst[1] */
1159  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
1160 
1161  SCIP_CALL( SCIPexprintCompile(exprinterpreter, consdata->sepaconvexconcave.f_neg_swapped_yfixed) );
1162 
1163  /* setup vred(s;y0,x0,xlb,xub) for computing a convex-concave underestimator in the case where x is not at one of its bounds */
1164  SCIP_CALL( initSepaDataCreateVred(scip, &consdata->sepaconvexconcave.vred_neg_swapped, consdata->sepaconvexconcave.f_neg_swapped) );
1165  SCIP_CALL( SCIPexprintCompile(exprinterpreter, consdata->sepaconvexconcave.vred_neg_swapped) );
1166  }
1167  else
1168  {
1169  consdata->sepaconvexconcave.f_neg_swapped = NULL;
1170  consdata->sepaconvexconcave.f_neg_swapped_yfixed = NULL;
1171  consdata->sepaconvexconcave.vred_neg_swapped = NULL;
1172  }
1173 
1174  break;
1175  }
1176 
1177  default: ;
1178  } /*lint !e788*/
1179 
1180  return SCIP_OKAY;
1181 }
1182 
1183 /** frees separation data */
1184 static
1186  SCIP* scip, /**< SCIP data structure */
1187  SCIP_CONS* cons /**< constraint */
1188  )
1189 {
1190  SCIP_CONSDATA* consdata;
1191 
1192  assert(scip != NULL);
1193  assert(cons != NULL);
1194 
1195  consdata = SCIPconsGetData(cons);
1196  assert(consdata != NULL);
1197  assert(consdata->f != NULL);
1198 
1199  switch( consdata->convextype )
1200  {
1202  {
1203  if( consdata->sepaconvexconcave.f_yfixed != NULL )
1204  {
1205  SCIP_CALL( SCIPexprtreeFree(&consdata->sepaconvexconcave.f_yfixed) );
1206  }
1207  if( consdata->sepaconvexconcave.f_neg_swapped != NULL )
1208  {
1209  SCIP_CALL( SCIPexprtreeFree(&consdata->sepaconvexconcave.f_neg_swapped) );
1210  }
1211  if( consdata->sepaconvexconcave.f_neg_swapped_yfixed != NULL )
1212  {
1213  SCIP_CALL( SCIPexprtreeFree(&consdata->sepaconvexconcave.f_neg_swapped_yfixed) );
1214  }
1215  if( consdata->sepaconvexconcave.vred != NULL )
1216  {
1217  SCIP_CALL( SCIPexprtreeFree(&consdata->sepaconvexconcave.vred) );
1218  }
1219  if( consdata->sepaconvexconcave.vred_neg_swapped != NULL )
1220  {
1221  SCIP_CALL( SCIPexprtreeFree(&consdata->sepaconvexconcave.vred_neg_swapped) );
1222  }
1223  break;
1224  }
1225 
1226  default: ;
1227  } /*lint !e788*/
1228 
1229  return SCIP_OKAY;
1230 }
1231 
1232 /** perturbs a value w.r.t. bounds */
1233 static
1234 void perturb(
1235  SCIP_Real* val, /**< value to perturb on input; perturbed value on output */
1236  SCIP_Real lb, /**< lower bound */
1237  SCIP_Real ub, /**< upper bound */
1238  SCIP_Real amount /**< relative amount of perturbation */
1239  )
1240 {
1241  SCIP_Real range;
1242  SCIP_Real mid;
1243 
1244  assert(val != NULL);
1245 
1246  range = ub - lb;
1247  mid = 0.5 * (lb + ub);
1248 
1249  if( *val < mid )
1250  *val += MIN(1.0, amount * range);
1251  else
1252  *val -= MIN(1.0, amount * range);
1253 }
1254 
1255 /** solves an equation f'(s) = constant for a univariate convex or concave function f with respect to bounds on s
1256  * if there is no s between the bounds such that f'(s) = constant, then it returns the closest bound (and still claims success)
1257  */
1258 static
1260  SCIP* scip, /**< SCIP data structure */
1261  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
1262  SCIP_EXPRTREE* f, /**< expression tree for f(s) */
1263  SCIP_Real targetvalue, /**< target value for derivative */
1264  SCIP_Real lb, /**< lower bound on variable */
1265  SCIP_Real ub, /**< upper bound on variable */
1266  SCIP_Real* val, /**< buffer to store solution value */
1267  SCIP_Bool* success /**< buffer to indicate whether a solution has been found */
1268  )
1269 {
1270  SCIP_Real fval;
1271  SCIP_Real grad;
1272  SCIP_Real hess;
1273  SCIP_Real s;
1274  SCIP_Real nexts;
1275  SCIP_Real step;
1276  int iter;
1277 
1278  assert(scip != NULL);
1279  assert(exprinterpreter != NULL);
1280  assert(f != NULL);
1281  assert(SCIPexprtreeGetInterpreterData(f) != NULL);
1282  assert(SCIPexprtreeGetNVars(f) == 1);
1283  assert(val != NULL);
1284  assert(success != NULL);
1285 
1286  if( SCIPisEQ(scip, lb, ub) )
1287  {
1288  *val = lb;
1289  *success = TRUE;
1290  return SCIP_OKAY;
1291  }
1292 
1293  *success = FALSE;
1294 
1295  iter = 0;
1296 
1297  /* start at 0.0, projected onto interior of interval
1298  * we don't want to start at a bound, because we would not recognize if hessian is 0.0 then
1299  */
1300  s = MIN(MAX(0.0, lb), ub);
1301  perturb(&s, lb, ub, 0.1);
1302 
1303  while( ++iter < NEWTONMAXITER )
1304  {
1305  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, &s, TRUE, &fval, &grad) );
1306 
1307  /* SCIPdebugMsg(scip, "s = %.20g [%g,%g] f(s) = %g grad = %g\n", s, lb, ub, fval, grad); */
1308 
1309  if( !SCIPisFinite(grad) )
1310  {
1311  /* if f cannot be differentiated at s, perturb s to some other point close by
1312  * for that, we perturb by 0.1 * 2^{-iter}, if iter <= 65, otherwise by 1e-20
1313  * if that amount is too small to get a change in s, we increase by a factor of 2
1314  */
1315  SCIP_Real amount;
1316  SCIP_Real sold;
1317 
1318  sold = s;
1319  amount = iter <= 65 ? 0.1 / (1u<<iter) : 1e-20; /*lint !e790*/
1320  do
1321  {
1322  perturb(&s, lb, ub, amount);
1323  amount *= 2.0;
1324  } while( s == sold ); /*lint !e777*/
1325 
1326  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, &s, TRUE, &fval, &grad) );
1327 
1328  /* SCIPdebugMsg(scip, "s = %.20g [%g,%g] f(s) = %g grad = %g (perturbed by %g)\n", s, lb, ub, fval, grad, iter <= 65 ? 0.1 / (1<<iter) : 1e-20); */
1329 
1330  assert(SCIPisFinite(grad));
1331  }
1332 
1333  if( SCIPisRelEQ(scip, grad, targetvalue) )
1334  {
1335  /* if grad is targetvalue (w.r.t. epsilon), then we are done */
1336  *val = s;
1337  *success = TRUE;
1338  break;
1339  }
1340 
1341  SCIP_CALL( SCIPexprintHessianDense(exprinterpreter, f, &s, FALSE, &fval, &hess) ); /* coverity ignore ARRAY_VS_SINGLETON warning */
1342 
1343  /* SCIPdebugMsg(scip, "s = %.20g [%g,%g] f(s) = %g hess = %g\n", s, lb, ub, fval, hess); */
1344 
1345  if( !SCIPisFinite(hess) )
1346  {
1347  SCIP_Real smod;
1348  SCIP_Real smodval;
1349 
1350  /* if f cannot be two times differentiated at s, take the Hessian from another point close by */
1351  smod = s;
1352  perturb(&smod, lb, ub, 0.01);
1353  SCIP_CALL( SCIPexprintHessianDense(exprinterpreter, f, &smod, TRUE, &smodval, &hess) );
1354 
1355  assert(SCIPisFinite(hess));
1356  }
1357 
1358  /* next iterate would be s - (grad - targetvalue) / hess */
1359 
1360  if( SCIPisEQ(scip, s, lb) && (grad - targetvalue) * hess >= 0 )
1361  {
1362  /* if we are on the left boundary and would go left (or stay), then stop
1363  * (multiply instead of divide by hess for the case that hess is zero and since only the sign matters
1364  */
1365  *val = lb;
1366  *success = TRUE;
1367  break;
1368  }
1369 
1370  if( SCIPisEQ(scip, s, ub) && (grad - targetvalue) * hess <= 0 )
1371  {
1372  /* similar, if we are on the right boundary and would go right (or stay), then stop */
1373  *val = ub;
1374  *success = TRUE;
1375  break;
1376  }
1377 
1378  if( SCIPisZero(scip, hess) )
1379  {
1380  /* hmm, stationary point, don't know how to continue; thus, give up */
1381  break;
1382  }
1383 
1384  if( SCIPisZero(scip, (grad - targetvalue) / hess) && SCIPisFeasEQ(scip, grad, targetvalue) )
1385  {
1386  /* if grad is targetvalue (w.r.t. feastol) and step length would be almost 0, then we are also done */
1387  *val = s;
1388  *success = TRUE;
1389  break;
1390  }
1391 
1392  /* @todo we could also implement a damped Newton method if the step is too large */
1393  step = (grad - targetvalue) / hess;
1394  assert(step != 0.0);
1395 
1396  nexts = s - step;
1397  while( s == nexts ) /*lint !e777*/
1398  {
1399  /* if steplength is so tiny that there is no change in s, go by 1e-9 into given direction */
1400  step *= 2.0;
1401  nexts = s - step;
1402  }
1403  assert(nexts != s); /*lint !e777*/
1404  s = nexts;
1405 
1406  if( s < lb )
1407  s = lb;
1408  else if( s > ub )
1409  s = ub;
1410  }
1411 
1412  return SCIP_OKAY;
1413 }
1414 
1415 /** generates a cut for f(x,y) + c*z <= rhs with f(x,y) being convex or 1-convex with x or y fixed or convex-concave with y fixed
1416  * f(x0, y0) + <grad, (x,y)-(x0,y0)> + c*z <= rhs, where grad is gradient of f in (x0, y0)
1417  */
1418 static
1420  SCIP* scip, /**< SCIP data structure */
1421  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
1422  SCIP_CONS* cons, /**< constraint */
1423  SCIP_Real* x0y0, /**< value of x and y variables where to generate cut */
1424  SCIP_Bool newxy, /**< whether the last evaluation of f(x,y) with the expression interpreter was at (x0, y0) */
1425  SCIP_ROW** row /**< storage for cut */
1426  )
1427 {
1428  SCIP_VAR* x;
1429  SCIP_VAR* y;
1430  SCIP_CONSDATA* consdata;
1431  char rowname[SCIP_MAXSTRLEN];
1432  SCIP_Real fval;
1433  SCIP_Real fgrad[2];
1434  SCIP_Real rhs;
1435 
1436  assert(scip != NULL);
1437  assert(cons != NULL);
1438  assert(row != NULL);
1439 
1440  consdata = SCIPconsGetData(cons);
1441  assert(consdata != NULL);
1442  assert(!SCIPisInfinity(scip, consdata->rhs));
1443  assert(newxy || SCIPexprtreeGetInterpreterData(consdata->f) != NULL);
1444 
1445  /* compile expression if evaluated the first time; can only happen if newxy is FALSE */
1446  if( newxy && SCIPexprtreeGetInterpreterData(consdata->f) == NULL )
1447  {
1448  SCIP_CALL( SCIPexprintCompile(exprinterpreter, consdata->f) );
1449  }
1450 
1451  x = SCIPexprtreeGetVars(consdata->f)[0];
1452  y = SCIPexprtreeGetVars(consdata->f)[1];
1453 
1454  assert(consdata->convextype == SCIP_BIVAR_ALLCONVEX ||
1455  (consdata->convextype == SCIP_BIVAR_1CONVEX_INDEFINITE && (SCIPisEQ(scip, SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x)) || SCIPisEQ(scip, SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y)))) ||
1456  (consdata->convextype == SCIP_BIVAR_CONVEX_CONCAVE && SCIPisEQ(scip, SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y))) );
1457 
1458  /* compute f(x,y) and gradient of f in (x, y) */
1459  SCIP_CALL( SCIPexprintGrad(exprinterpreter, consdata->f, x0y0, newxy, &fval, fgrad) );
1460 
1461  if( !SCIPisFinite(fval) || !SCIPisFinite(fgrad[0]) || !SCIPisFinite(fgrad[1]) )
1462  {
1463  perturb(&x0y0[0], SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x), 0.001);
1464  perturb(&x0y0[1], SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y), 0.001);
1465 
1466  SCIP_CALL( SCIPexprintGrad(exprinterpreter, consdata->f, x0y0, TRUE, &fval, fgrad) );
1467 
1468  if( !SCIPisFinite(fval) || !SCIPisFinite(fgrad[0]) || !SCIPisFinite(fgrad[1]) )
1469  {
1470  SCIPdebugMsg(scip, "could not evaluate f at given reference point and perturbed one");
1471  *row = NULL;
1472  return SCIP_OKAY;
1473  }
1474  }
1475 
1476  rhs = consdata->rhs - fval + fgrad[0] * x0y0[0] + fgrad[1] * x0y0[1];
1477 
1478  /* setup SCIP row */
1479  (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_linearization_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
1480 
1481  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), rhs, FALSE, FALSE /* modifiable */, TRUE /* removable */) );
1482 
1483  SCIP_CALL( SCIPaddVarsToRow(scip, *row, 2, SCIPexprtreeGetVars(consdata->f), fgrad) );
1484 
1485  if( consdata->z != NULL )
1486  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
1487 
1488  return SCIP_OKAY;
1489 }
1490 
1491 /** given a convex (concave, resp.) bivariate function, computes an over- (under-, resp.) estimating hyperplane
1492  * does not succeed if some variable is unbounded or both variables are fixed
1493  */
1494 static
1496  SCIP* scip, /**< SCIP data structure */
1497  SCIP_EXPRINT* exprinterpreter, /**< expression interpreter */
1498  SCIP_EXPRTREE* f, /**< bivariate function to compute under or overestimator for */
1499  SCIP_Bool doover, /**< whether to compute an overestimator (TRUE) or an underestimator (FALSE) */
1500  SCIP_Real* x0y0, /**< reference values for nonlinear variables */
1501  SCIP_Real* coefx, /**< coefficient of x in estimator */
1502  SCIP_Real* coefy, /**< coefficient of y in estimator */
1503  SCIP_Real* constant, /**< constant part of estimator */
1504  SCIP_Bool* success /**< pointer to indicate whether coefficients where successfully computed */
1505  )
1506 {
1507  SCIP_VAR* x;
1508  SCIP_VAR* y;
1509  SCIP_Real xlb;
1510  SCIP_Real xub;
1511  SCIP_Real ylb;
1512  SCIP_Real yub;
1513 
1514  SCIP_Real p1[2];
1515  SCIP_Real p2[2];
1516  SCIP_Real p3[2];
1517  SCIP_Real p4[2];
1518  SCIP_Real p1val;
1519  SCIP_Real p2val;
1520  SCIP_Real p3val;
1521  SCIP_Real p4val;
1522 
1523  SCIP_Real alpha;
1524  SCIP_Real beta;
1525  SCIP_Real gamma_;
1526  SCIP_Real delta;
1527 
1528  SCIP_Bool tryother;
1529 
1530  assert(scip != NULL);
1531  assert(exprinterpreter != NULL);
1532  assert(f != NULL);
1533  assert(x0y0 != NULL);
1534  assert(coefx != NULL);
1535  assert(coefy != NULL);
1536  assert(constant != NULL);
1537  assert(success != NULL);
1538 
1539  *success = FALSE;
1540 
1541  x = SCIPexprtreeGetVars(f)[0];
1542  y = SCIPexprtreeGetVars(f)[1];
1543 
1544  xlb = SCIPvarGetLbLocal(x);
1545  xub = SCIPvarGetUbLocal(x);
1546  ylb = SCIPvarGetLbLocal(y);
1547  yub = SCIPvarGetUbLocal(y);
1548 
1549  /* reference point should not be outside of bounds */
1550  assert(SCIPisLE(scip, xlb, x0y0[0]));
1551  assert(SCIPisGE(scip, xub, x0y0[0]));
1552  assert(SCIPisLE(scip, ylb, x0y0[1]));
1553  assert(SCIPisGE(scip, yub, x0y0[1]));
1554 
1555  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) || SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub) )
1556  {
1557  SCIPdebugMsg(scip, "skip estimating hyperplane since <%s> or <%s> is unbounded\n", SCIPvarGetName(x), SCIPvarGetName(y));
1558  return SCIP_OKAY;
1559  }
1560 
1561  if( SCIPisEQ(scip, xlb, xub) && SCIPisEQ(scip, ylb, yub) )
1562  {
1563  SCIPdebugMsg(scip, "skip estimating hyperplane since both <%s> and <%s> are fixed\n", SCIPvarGetName(x), SCIPvarGetName(y));
1564  return SCIP_OKAY;
1565  }
1566 
1567  /* unten links */
1568  p1[0] = xlb;
1569  p1[1] = ylb;
1570 
1571  /* unten rechts */
1572  p2[0] = xub;
1573  p2[1] = ylb;
1574 
1575  /* oben rechts */
1576  p3[0] = xub;
1577  p3[1] = yub;
1578 
1579  /* oben links */
1580  p4[0] = xlb;
1581  p4[1] = yub;
1582 
1583  if( SCIPisEQ(scip, xlb, xub) )
1584  {
1585  /* secant between p1 and p4: p1val + [(p4val - p1val) / (yub - ylb)] * (y - ylb) */
1586  assert(!SCIPisEQ(scip, ylb, yub));
1587 
1588  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p1, &p1val) );
1589  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p4, &p4val) );
1590 
1591  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p4val) || SCIPisInfinity(scip, REALABS(p4val)) )
1592  {
1593  SCIPdebugMsg(scip, "skip hyperplane since function cannot be evaluated\n");
1594  return SCIP_OKAY;
1595  }
1596 
1597  *coefx = 0.0;
1598  *coefy = (p4val - p1val) / (yub - ylb);
1599  *constant = p1val - *coefy * ylb;
1600 
1601  *success = TRUE;
1602 
1603  return SCIP_OKAY;
1604  }
1605 
1606  if( SCIPisEQ(scip, ylb, yub) )
1607  {
1608  /* secant between p1 and p2: p1val + [(p2val - p1val) / (xub - xlb)] * (x - xlb) */
1609  assert(!SCIPisEQ(scip, xlb, xub));
1610 
1611  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p1, &p1val) );
1612  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p2, &p2val) );
1613 
1614  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p2val) || SCIPisInfinity(scip, REALABS(p2val)) )
1615  {
1616  SCIPdebugMsg(scip, "skip hyperplane since function cannot be evaluated\n");
1617  return SCIP_OKAY;
1618  }
1619 
1620  *coefx = (p2val - p1val) / (xub - xlb);
1621  *coefy = 0.0;
1622  *constant = p1val - *coefx * xlb;
1623 
1624  *success = TRUE;
1625 
1626  return SCIP_OKAY;
1627  }
1628 
1629  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p1, &p1val) );
1630  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p2, &p2val) );
1631  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p3, &p3val) );
1632  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p4, &p4val) );
1633 
1634  /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
1635  if( !doover )
1636  {
1637  p1val = -p1val;
1638  p2val = -p2val;
1639  p3val = -p3val;
1640  p4val = -p4val;
1641  }
1642 
1643  SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
1644  SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
1645  SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
1646  SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
1647 
1648  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p2val) || SCIPisInfinity(scip, REALABS(p2val)) ||
1649  ! SCIPisFinite(p3val) || SCIPisInfinity(scip, REALABS(p3val)) || !SCIPisFinite(p4val) || SCIPisInfinity(scip, REALABS(p4val)) )
1650  {
1651  SCIPdebugMsg(scip, "skip hyperplane since function cannot be evaluated\n");
1652  return SCIP_OKAY;
1653  }
1654 
1655  /* compute coefficients alpha, beta, gamma (>0), delta such that
1656  * alpha*x + beta*y + gamma*z = delta
1657  * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
1658  * the fourth corner point lies below this hyperplane.
1659  * Since we assume that f is convex, we then know that all points (x,y,f(x,y)) are below this hyperplane, i.e.,
1660  * alpha*x + beta*y - delta <= -gamma * f(x,y),
1661  * or, equivalently,
1662  * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
1663  */
1664 
1665  tryother = FALSE;
1666  if( x0y0[1] <= ylb + (yub - ylb)/(xub - xlb) * (x0y0[0] - xlb) )
1667  {
1668  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val, &alpha,
1669  &beta, &gamma_, &delta) );
1670 
1671  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
1672  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
1673  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
1674 
1675  /* if hyperplane through p1,p2,p3 does not overestimate f(p4), then it must be the other variant */
1676  if( SCIPisInfinity(scip, delta) || alpha * p4[0] + beta * p4[1] + gamma_ * p4val > delta )
1677  tryother = TRUE;
1678  }
1679  else
1680  {
1681  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val, &alpha,
1682  &beta, &gamma_, &delta) );
1683 
1684  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
1685  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
1686  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
1687 
1688  /* if hyperplane through p1,p3,p4 does not overestimate f(p2), then it must be the other variant */
1689  if( SCIPisInfinity(scip, delta) || alpha * p2[0] + beta * p2[1] + gamma_ * p2val > delta )
1690  tryother = TRUE;
1691  }
1692 
1693  if( tryother )
1694  {
1695  if( x0y0[1] <= yub + (ylb - yub)/(xub - xlb) * (x0y0[0] - xlb) )
1696  {
1697  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
1698  &alpha, &beta, &gamma_, &delta) );
1699 
1700  /* hyperplane should be above (p3,f(p3)) and other points should lie on hyperplane */
1701  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
1702  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
1703  assert(SCIPisInfinity(scip, delta) || SCIPisFeasLE(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
1704  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
1705  }
1706  else
1707  {
1708  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
1709  &alpha, &beta, &gamma_, &delta) );
1710 
1711  /* hyperplane should be above (p1,f(p1)) and other points should lie on hyperplane */
1712  assert(SCIPisInfinity(scip, delta) || SCIPisFeasLE(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
1713  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
1714  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
1715  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
1716  }
1717  }
1718 
1719  SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
1720 
1721  /* check if bad luck: should not happen if xlb != xub and ylb != yub and numerics are fine */
1722  if( SCIPisInfinity(scip, delta) || SCIPisZero(scip, gamma_) )
1723  return SCIP_OKAY;
1724  assert(!SCIPisNegative(scip, gamma_));
1725 
1726  /* flip hyperplane */
1727  if( !doover )
1728  gamma_ = -gamma_;
1729 
1730  *coefx = -alpha / gamma_;
1731  *coefy = -beta / gamma_;
1732  *constant = delta / gamma_;
1733 
1734  *success = TRUE;
1735 
1736  return SCIP_OKAY;
1737 }
1738 
1739 /** generates a cut for lhs <= f(x,y) + c*z with f(x,y) being convex */
1740 static
1742  SCIP* scip, /**< SCIP data structure */
1743  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
1744  SCIP_CONS* cons, /**< constraint */
1745  SCIP_Real* x0y0, /**< reference values for nonlinear variables */
1746  SCIP_ROW** row /**< storage for cut */
1747  )
1748 {
1749  SCIP_CONSDATA* consdata;
1750  SCIP_Real coefs[2];
1751  SCIP_Real constant = SCIP_INVALID;
1752  SCIP_Bool success;
1753 
1754  assert(scip != NULL);
1755  assert(cons != NULL);
1756  assert(row != NULL);
1757 
1758  *row = NULL;
1759 
1760  consdata = SCIPconsGetData(cons);
1761  assert(consdata != NULL);
1762 
1763  SCIP_CALL( generateEstimatingHyperplane(scip, exprinterpreter, consdata->f, TRUE, x0y0, &coefs[0], &coefs[1], &constant, &success) );
1764 
1765  if( success )
1766  {
1767  assert(!SCIPisInfinity(scip, -consdata->lhs));
1768  assert(SCIPisFinite(coefs[0]));
1769  assert(SCIPisFinite(coefs[1]));
1770  assert(SCIPisFinite(constant));
1771 
1772  SCIP_CALL( SCIPcreateRowCons(scip, row, SCIPconsGetHdlr(cons), "bivaroveresthyperplanecut", 0, NULL, NULL, consdata->lhs - constant, SCIPinfinity(scip), TRUE, FALSE, TRUE) );
1773 
1774  SCIP_CALL( SCIPaddVarsToRow(scip, *row, 2, SCIPexprtreeGetVars(consdata->f), coefs) );
1775  if( consdata->z != NULL )
1776  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
1777  }
1778  else
1779  {
1780  SCIPdebugMsg(scip, "failed to compute overestimator for all-convex constraint <%s>\n", SCIPconsGetName(cons));
1781  }
1782 
1783  return SCIP_OKAY;
1784 }
1785 
1786 /** generates a linear underestimator for f(x,y)
1787  * when the generators of the underestimating segment
1788  * are contained in y=ylb and y=yub.
1789  * Generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
1790  * alpha * x + beta * y - delta <= gamma * f(x,y)
1791  */
1792 static
1794  SCIP* scip, /**< SCIP data structure */
1795  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
1796  SCIP_EXPRTREE* f, /**< function f(x,y) */
1797  SCIP_Real* xyref, /**< reference values for x and y */
1798  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
1799  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
1800  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
1801  )
1802 {
1803  SCIP_VAR* x;
1804  SCIP_VAR* y;
1805  SCIP_Real xval;
1806  SCIP_Real xlb;
1807  SCIP_Real xub;
1808  SCIP_Real yval;
1809  SCIP_Real ylb;
1810  SCIP_Real yub;
1811 
1812  SCIP_Real t;
1813  SCIP_EXPR* vred;
1814  SCIP_EXPRTREE* vredtree;
1815  SCIP_EXPR* e1;
1816  SCIP_EXPR* e2;
1817  SCIP_EXPR* tmp;
1818  SCIP_EXPR* tmp2;
1819  SCIP_EXPR* subst[2];
1820 
1821  SCIP_Real sval;
1822  SCIP_Real slb;
1823  SCIP_Real sub;
1824  SCIP_Real rval;
1825 
1826  SCIP_Real frval;
1827  SCIP_Real fsval;
1828  SCIP_Real x0y0[2];
1829  SCIP_Real grad[2];
1830 
1831  assert(scip != NULL);
1832  assert(exprinterpreter != NULL);
1833  assert(f != NULL);
1834  assert(xyref != NULL);
1835  assert(success != NULL);
1836 
1837  x = SCIPexprtreeGetVars(f)[0];
1838  y = SCIPexprtreeGetVars(f)[1];
1839 
1840  xlb = SCIPvarGetLbLocal(x);
1841  xub = SCIPvarGetUbLocal(x);
1842 
1843  ylb = SCIPvarGetLbLocal(y);
1844  yub = SCIPvarGetUbLocal(y);
1845 
1846  xval = xyref[0];
1847  yval = xyref[1];
1848 
1849  *success = FALSE;
1850 
1851  /* check that variables are not unbounded or fixed and reference point is in interior */
1852  assert(!SCIPisInfinity(scip, -xlb));
1853  assert(!SCIPisInfinity(scip, xub));
1854  assert(!SCIPisInfinity(scip, -ylb));
1855  assert(!SCIPisInfinity(scip, yub));
1856  assert(!SCIPisEQ(scip,xlb,xub));
1857  assert(!SCIPisEQ(scip,ylb,yub));
1858  assert(!SCIPisEQ(scip,xlb,xval));
1859  assert(!SCIPisEQ(scip,xub,xval));
1860  assert(!SCIPisEQ(scip,ylb,yval));
1861  assert(!SCIPisEQ(scip,yub,yval));
1862 
1863  SCIPdebugMsg(scip, "f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
1865  SCIPdebugMsgPrint(scip, "\n");
1866 
1867  t = (yub - yval) / (yub - ylb);
1868 
1869  /* construct v_red(s) := t f(1/t xval + (1-1/t) s, ylb) + (1-t) f(s, yub) */
1870 
1871  /* construct e1 := f(1/t xval + (1-1/t) s, ylb) */
1872  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e1, SCIPexprtreeGetRoot(f)) ); /* e1 = f(x,y) */
1873 
1874  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_VARIDX, 0) ); /* tmp = s */
1875  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp2, SCIP_EXPR_CONST, 1.0 - 1.0 / t) ); /* tmp2 = 1-1/t */
1876  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_MUL, tmp, tmp2) ); /* tmp = (1-1/t)*s */
1877  if( xval != 0.0 )
1878  {
1879  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp2, SCIP_EXPR_CONST, 1/t*xval) ); /* tmp2 = 1/t*xval */
1880  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_PLUS, tmp, tmp2) ); /* tmp = 1/t*xval + (1-1/t)*s */
1881  }
1882  subst[0] = tmp;
1883 
1884  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, ylb) ); /* tmp = ylb */
1885 
1886  assert(SCIPexprGetOperator(e1) != SCIP_EXPR_VARIDX); /* substitute cannot substitute the root node, but f should not be a single variable anyway */
1887  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e1, subst) ); /* e1 = f(1/t*xval + (1-1/t)*s, ylb) */
1888 
1889  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
1890  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
1891 
1892  /* construct e2 := f(s, yub) */
1893  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e2, SCIPexprtreeGetRoot(f)) ); /* e2 = f(x,y) */
1894 
1895  subst[0] = NULL;
1896 
1897  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, yub) );
1898 
1899  assert(SCIPexprGetOperator(e2) != SCIP_EXPR_VARIDX); /* substitute cannot substitute the root node, but f should not be a single variable anyway */
1900  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e2, subst) ); /* e2 = f(s,yub) */
1901 
1902  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
1903 
1904  /* construct vred := t * e1 + (1-t) * e2 */
1905  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, t) ); /* tmp = t */
1906  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e1, SCIP_EXPR_MUL, e1, tmp) ); /* e1 = t * f(1/t*xval+(1-1/t)*s,ylb) */
1907 
1908  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0 - t) ); /* tmp = 1 - t */
1909  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e2, SCIP_EXPR_MUL, e2, tmp) ); /* e2 = (1-t) * f(s, yub) */
1910 
1911  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &vred, SCIP_EXPR_PLUS, e1, e2) );
1912  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &vredtree, vred, 1, 0, NULL) );
1913 
1914  SCIP_CALL( SCIPexprintCompile(exprinterpreter, vredtree) );
1915 
1916  /* compute bounds on s */
1917  slb = (yval - yub) / (ylb - yval) * (xval / t - xub);
1918  sub = (yval - yub) / (ylb - yval) * (xval / t - xlb);
1919  if( slb < xlb )
1920  slb = xlb;
1921  if( sub > xub )
1922  sub = xub;
1923 
1924  /* find s in [slb, sub] such that vred'(s) = 0 */
1925  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vredtree, 0.0, slb, sub, &sval, success) );
1926 
1927  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
1928 
1929  if( *success == FALSE )
1930  {
1931  /* something went wrong when computing s */
1932  return SCIP_OKAY;
1933  }
1934 
1935  /* compute r from s */
1936  rval = 1.0 / t * xval + (1.0 - 1.0 / t) * sval;
1937  assert(SCIPisFeasGE(scip, rval, xlb));
1938  assert(SCIPisFeasLE(scip, rval, xub));
1939  rval = MAX(xlb, MIN(rval, xub));
1940 
1941  /* compute f(sval, yub) */
1942  x0y0[0] = sval;
1943  x0y0[1] = yub;
1944  SCIP_CALL( SCIPexprtreeEval(f, x0y0, &fsval) );
1945 
1946  /* compute f(rval, ylb) */
1947  x0y0[0] = rval;
1948  x0y0[1] = ylb;
1949  SCIP_CALL( SCIPexprtreeEval(f, x0y0, &frval) );
1950 
1951  if( !SCIPisEQ(scip, sval, xlb) && !SCIPisEQ(scip, sval, xub) )
1952  {
1953  x0y0[0] = sval;
1954  x0y0[1] = yub;
1955 
1956  /* compute f'(xbar, ybar) */
1957  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad) );
1958  }
1959  else if( !SCIPisEQ(scip, rval, xlb) && !SCIPisEQ(scip, rval, xub) )
1960  {
1961  x0y0[0] = rval;
1962  x0y0[1] = ylb;
1963 
1964  /* compute f'(xbar, ybar) */
1965  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad) );
1966  }
1967  else
1968  {
1969  /* rare case
1970  * both points (sval, yub) and (rval, ylb) should yield valid inequality
1971  * for now, just take the first one, if differentiable, otherwise second one */
1972  x0y0[0] = sval;
1973  x0y0[1] = yub;
1974 
1975  /* compute f'(xbar, ybar) */
1976  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad) );
1977 
1978  if( !SCIPisFinite(grad[0]) )
1979  {
1980  x0y0[0] = rval;
1981  x0y0[1] = ylb;
1982 
1983  /* compute f'(xbar, ybar) */
1984  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad) );
1985  }
1986  }
1987 
1988  /* compute vred(s) = t * f(rval, ylb) + (1-t) * f(s, yub) */
1989  /* SCIP_CALL( SCIPexprtreeEval(vredtree, &sval, &vredval) ); */
1990  *convenvvalue = t * frval + (1.0 - t) * fsval;
1991 
1992  SCIPdebugMsg(scip, "Parallel: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
1993  SCIPdebugMsg(scip, "Parallel: r=%g in [%g,%g], s=%g in [%g,%g], f(r,ylb)=%g, f(xlb,s)=%g\n",rval,xlb,xub,sval,ylb,yub,frval,fsval);
1994  SCIPdebugMsg(scip, "(r,ylb)=(%g,%g), (s,yub)=(%g,%g), vredval=%g\n",rval,ylb,sval,yub,*convenvvalue);
1995 
1996  if( !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
1997  {
1998  SCIPdebugMsg(scip, "f not differentiable in (x0,y0) w.r.t. x\n");
1999  return SCIP_OKAY;
2000  }
2001 
2002  /* compute cut coefficients */
2003  cutcoeff[0] = (yub - ylb) * grad[0];
2004  cutcoeff[1] = fsval - frval - (sval - rval) * grad[0];
2005  cutcoeff[2] = yub - ylb;
2006  cutcoeff[3] = cutcoeff[0] * xval + cutcoeff[1] * yval - cutcoeff[2] * *convenvvalue;
2007 
2008  SCIPdebugMsg(scip, "Parallel: cutcoeff[0]=%g, cutcoeff[1]=%g, cutcoeff[2]=1.0, cutcoeff[3]=%g\n",cutcoeff[0]/cutcoeff[2],cutcoeff[1]/cutcoeff[2],cutcoeff[3]/cutcoeff[2]);
2009 
2010  *success = TRUE;
2011 
2012  return SCIP_OKAY;
2013 }
2014 
2015 
2016 /** generates a linear underestimator for f(x,y)
2017  * with f(x,y) being convex in x and convex in y.
2018  * The segmenent connects orthogonal facets: Either (x=l_x,y=l_y)
2019  * or (x=u_x,y=u_y).
2020  * generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2021  * alpha * x + beta * y - delta <= gamma * f(x,y)
2022  */
2023 static
2025  SCIP* scip, /**< SCIP data structure */
2026  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
2027  SCIP_EXPRTREE* f, /**< function f(x,y) */
2028  SCIP_Real* xyref, /**< reference values for x and y */
2029  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
2030  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
2031  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
2032  )
2033 {
2034  SCIP_VAR* x;
2035  SCIP_VAR* y;
2036  SCIP_Real xval;
2037  SCIP_Real xlb;
2038  SCIP_Real xub;
2039  SCIP_Real yval;
2040  SCIP_Real ylb;
2041  SCIP_Real yub;
2042 
2043  SCIP_Real x0y0[2];
2044 
2045  SCIP_EXPR* vred;
2046  SCIP_EXPRTREE* vredtree;
2047  SCIP_EXPR* e1;
2048  SCIP_EXPR* e2;
2049  SCIP_EXPR* tmp;
2050  SCIP_EXPR* expr;
2051  SCIP_EXPR* expr1;
2052  SCIP_EXPR* expr2;
2053  SCIP_EXPR* subst[2];
2054 
2055  SCIP_Real tval, tlb, tub;
2056  SCIP_Real sval;
2057  SCIP_Real rval;
2058 
2059  SCIP_Real frval,fsval;
2060  SCIP_Real grad_rval[2];
2061  SCIP_Real grad_sval[2];
2062 
2063  assert(scip != NULL);
2064  assert(exprinterpreter != NULL);
2065  assert(f != NULL);
2066  assert(convenvvalue != NULL);
2067  assert(success != NULL);
2068 
2069  x = SCIPexprtreeGetVars(f)[0];
2070  y = SCIPexprtreeGetVars(f)[1];
2071 
2072  xlb = SCIPvarGetLbLocal(x);
2073  xub = SCIPvarGetUbLocal(x);
2074 
2075  ylb = SCIPvarGetLbLocal(y);
2076  yub = SCIPvarGetUbLocal(y);
2077 
2078  xval = xyref[0];
2079  yval = xyref[1];
2080 
2081  /* check that variables are not unbounded or fixed and reference point is in interior */
2082  assert(!SCIPisInfinity(scip, -xlb));
2083  assert(!SCIPisInfinity(scip, xub));
2084  assert(!SCIPisInfinity(scip, -ylb));
2085  assert(!SCIPisInfinity(scip, yub));
2086  assert(!SCIPisEQ(scip,xlb,xub));
2087  assert(!SCIPisEQ(scip,ylb,yub));
2088  assert(!SCIPisEQ(scip,xlb,xval));
2089  assert(!SCIPisEQ(scip,xub,xval));
2090  assert(!SCIPisEQ(scip,ylb,yval));
2091  assert(!SCIPisEQ(scip,yub,yval));
2092 
2093  *success = FALSE;
2094 
2095  SCIPdebugMsg(scip, "f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
2097  SCIPdebugMsgPrint(scip, "\n");
2098  SCIPdebugMsg(scip, "%s[%g,%g] = %g %s[%g,%g] = %g\n", SCIPvarGetName(x), xlb, xub, xval, SCIPvarGetName(y), ylb, yub, yval);
2099 
2100  /* check in which triangle the point (xval,yval) lies */
2101  if( yval <= (ylb-yub) / (xub-xlb) * (xval-xlb) + yub )
2102  {
2103  /* (xval,yval) lies in lower left triangle, i.e. region A_1 */
2104  /* construct v_red(t) := t f( xlb, (yval-(1-t)ylb)/t ) + (1-t)*f( (xval-xlb*t)/(1-t), ylb ) */
2105 
2106  /* construct e1 := f(xlb, ylb + (yval-ylb)/t) */
2107  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2108  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yval-ylb) ); /* tmp = yval-ylb */
2109  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, tmp, expr) ); /* expr = (yval-ylb) / t */
2110  if( ylb != 0.0 )
2111  {
2112  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, ylb) ); /* tmp = ylb */
2113  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, tmp) ); /* expr = ylb + (yval-ylb) / t */
2114  }
2115  subst[1] = expr;
2116 
2117  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_CONST, xlb) ); /* subst[0] = xlb */
2118 
2119  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e1, SCIPexprtreeGetRoot(f)) ); /* e1 = f(x,y) */
2120  assert(SCIPexprGetOperator(e1) != SCIP_EXPR_VARIDX); /* expr substitute vars cannot substitute the root node, but f should not be a single variable anyway */
2121  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e1, subst) ); /* e1 = f(xlb, ylb + (yval-ylb)/t) */
2122 
2123  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2124  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2125 
2126 
2127  /* construct e2 := f((xval-xlb*t)/(1-t), ylb) */
2128  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_VARIDX, 0) ); /* expr1 = t */
2129  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2130  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MINUS, tmp, expr1) ); /* expr1 = 1-t */
2131 
2132  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_VARIDX, 0) ); /* expr2 = t */
2133  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xlb) ); /* tmp = xlb */
2134  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, expr2, tmp) ); /* expr2 = xlb * t */
2135  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xval) ); /* tmp = xval */
2136  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MINUS, tmp, expr2) ); /* expr2 = xval - xlb * t */
2137 
2138  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, expr2, expr1) ); /* expr = (xval-t*xlb)/(1-t) */
2139  subst[0] = expr;
2140 
2141  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, ylb) ); /* subst[0] = ylb */
2142 
2143  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e2, SCIPexprtreeGetRoot(f)) ); /* e2 = f(x,y) */
2144  assert(SCIPexprGetOperator(e2) != SCIP_EXPR_VARIDX); /* expr substitute vars cannot substitute the root node, but f should not be a single variable anyway */
2145  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e2, subst) ); /* e2 = f((xval-xlb*t)/(1-t), ylb) */
2146 
2147  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2148  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2149 
2150 
2151  /* construct vred := t * e1 + (1-t) * e2 */
2152  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2153  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MUL, expr, e1) ); /* expr1 = t * e1*/
2154 
2155  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2156  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2157  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_MINUS, tmp, expr) ); /* expr = 1 - t */
2158  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, expr, e2) ); /* expr2 = (1-t) * e2 */
2159 
2160  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &vred, SCIP_EXPR_PLUS, expr1, expr2) );
2161  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &vredtree, vred, 1, 0, NULL) );
2162  SCIP_CALL( SCIPexprintCompile(exprinterpreter, vredtree) );
2163 
2164  /* compute bounds on t */
2165  tlb = (yval-ylb)/(yub-ylb);
2166  tub = (xub-xval)/(xub-xlb);
2167 
2168  /* find t in [lambalb, tub] such that vred'(t) = 0 */
2169  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vredtree, 0.0, tlb, tub, &tval, success) );
2170 
2171  /* computing the cut coefficients */
2172  if( *success == FALSE )
2173  {
2174  /* something went wrong when computing s */
2175  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2176  return SCIP_OKAY;
2177  }
2178 
2179  /* compute r and s from tval */
2180  rval = (yval-(1-tval)*ylb)/tval;
2181  rval = MAX(ylb, MIN(yub, rval));
2182  sval = (xval-xlb*tval)/(1-tval);
2183  sval = MAX(xlb, MIN(xub, sval));
2184 
2185  SCIPdebugMsg(scip, "LowerLeft: t[%g,%g] = %g -> r = %g, s = %g\n",tlb,tub,tval,rval,sval);
2186 
2187  /* compute vred(tval) */
2188  SCIP_CALL( SCIPexprtreeEval(vredtree, &tval, convenvvalue) );
2189 
2190  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2191 
2192  /* compute f(s, ylb) and f'(s, ylb) */
2193  x0y0[0] = sval;
2194  x0y0[1] = ylb;
2195  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad_sval) );
2196 
2197  /* compute f(xlb, r) and f'(xlb,r) */
2198  x0y0[0] = xlb;
2199  x0y0[1] = rval;
2200  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad_rval) );
2201 
2202  /* generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2203  * alpha * x + beta * y - delta <= gamma * f(x,y)
2204  * cf. Section 2.5.2 Aux.prob. 2 case (ii)
2205  */
2206  if( !SCIPisEQ(scip, sval, xub) )
2207  {
2208  /* use the x-axis to determine the second direction */
2209  if( !SCIPisFinite(grad_sval[0]) || SCIPisInfinity(scip, REALABS(grad_sval[0])) )
2210  {
2211  *success = FALSE;
2212  return SCIP_OKAY;
2213  }
2214  cutcoeff[0] = (rval-ylb) * grad_sval[0];
2215  cutcoeff[1] = (sval-xlb) * grad_sval[0] + frval - fsval;
2216  cutcoeff[2] = rval-ylb;
2217  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*rval-cutcoeff[2]*frval;
2218  }
2219  else if( !SCIPisEQ(scip,rval,yub) )
2220  {
2221  /* use the y-axis to determine the second direction */
2222  if( !SCIPisFinite(grad_rval[1]) || SCIPisInfinity(scip, REALABS(grad_rval[1])) )
2223  {
2224  *success = FALSE;
2225  return SCIP_OKAY;
2226  }
2227  cutcoeff[0] = (rval-ylb)*grad_rval[1]+fsval-frval;
2228  cutcoeff[1] = (sval-xlb)*grad_rval[1];
2229  cutcoeff[2] = sval-xlb;
2230  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*rval-cutcoeff[2]*frval;
2231  }
2232  else
2233  {
2234  /* the point lies on the segment between (xlb,yub) and (xub,ylb) */
2235  if( !SCIPisFinite(grad_sval[0]) || !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(MIN(grad_sval[0],grad_rval[0]))) )
2236  {
2237  /* FIXME maybe it is sufficient to have one of them finite, using that one for the MIN below? */
2238  *success = FALSE;
2239  return SCIP_OKAY;
2240  }
2241  cutcoeff[0] = (rval-ylb)* MIN(grad_sval[0],grad_rval[0]);
2242  cutcoeff[1] = (sval-xlb)* MIN(grad_sval[0],grad_rval[0])+frval-fsval;
2243  cutcoeff[2] = (rval-ylb);
2244  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*rval-cutcoeff[2]*frval;
2245  }
2246 
2247  SCIPdebugMsg(scip, "LowerLeft: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
2248  SCIPdebugMsg(scip, "LowerLeft: r=%g in [%g,%g], s=%g in [%g,%g], f(s,ylb)=%g, f(xlb,r)=%g\n",rval,xlb,xub,sval,ylb,yub,fsval,frval);
2249  SCIPdebugMsg(scip, "(s,ylb)=(%g,%g) (xlb,r)=(%g,%g) t=%g, vredval=%g\n",sval,ylb,xlb,rval,tval,*convenvvalue);
2250  SCIPdebugMsg(scip, "LowerLeft: cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=%g,cutcoeff[3]=%g\n",cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
2251  }
2252  else
2253  {
2254  /* (xval,yval) lies in the upper right triangle, i.e region A_2 */
2255  /* construct v_red(t) := t f( xub, yub + (yval-yub)/t ) + (1-t)*f((xval-xub*t)/(1-t), yub) */
2256 
2257  /* construct e1 := f(xub, yub+(yval-yub)/t) */
2258  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t*/
2259  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yval-yub) ); /* tmp = yval-yub*/
2260  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, tmp, expr) ); /* expr = (yval-yub) / t */
2261  if( yub != 0.0 )
2262  {
2263  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yub) ); /* tmp = yub */
2264  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, tmp) ); /* expr = yub + (yval-yub)/t */
2265  }
2266  subst[1] = expr;
2267 
2268  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_CONST, xub) ); /* tmp = xub */
2269 
2270  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e1, SCIPexprtreeGetRoot(f)) ); /* e1 = f(x,y) */
2271  assert(SCIPexprGetOperator(e1) != SCIP_EXPR_VARIDX); /* cannot substitute root */
2272  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e1, subst) ); /* e1 = f(xub, yub + (yval-yub)/t) */
2273 
2274  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2275  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2276 
2277  /* construct e2 := f((xval-t*xub)/(1-t), yub) */
2278  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_VARIDX, 0) ); /* expr1 = t */
2279  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2280  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MINUS, tmp, expr1) ); /* expr1 = 1-t */
2281 
2282  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_VARIDX, 0) ); /* expr2 = t */
2283  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xub) ); /* tmp = xub */
2284  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, expr2, tmp) ); /* expr2 = xub * t */
2285  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xval) ); /* tmp = xval */
2286  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MINUS, tmp, expr2) ); /* expr2 = xval - xub * t */
2287 
2288  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, expr2, expr1) ); /* expr = (xval-t*xub)/(1-t) */
2289  subst[0] = expr;
2290 
2291  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, yub) ); /* tmp = yub */
2292 
2293  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e2, SCIPexprtreeGetRoot(f)) ); /* e2 = f(x,y) */
2294  assert(SCIPexprGetOperator(e2) != SCIP_EXPR_VARIDX); /* cannot substitute root */
2295  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e2, subst) ); /* e2 = f((xval-t*xub)/(1-t), yub) */
2296 
2297  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2298  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2299 
2300  /* construct vred := t * e1 + (1-t) * e2 */
2301  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2302  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MUL, e1, expr) ); /* expr1 = t * e1*/
2303 
2304  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2305  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2306  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_MINUS, tmp, expr) ); /* expr = 1-t */
2307  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, e2, expr) ); /* expr2 = (1-t) * e2*/
2308 
2309 
2310  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &vred, SCIP_EXPR_PLUS, expr1, expr2) );
2311  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &vredtree, vred, 1, 0, NULL) );
2312  SCIP_CALL( SCIPexprintCompile(exprinterpreter, vredtree) );
2313 
2314  /* compute bounds on t */
2315  tlb = (yub-yval)/(yub-ylb);
2316  tub = (xval-xlb)/(xub-xlb);
2317 
2318  /* find t in [tlb, tub] such that vred'(t) = 0 */
2319  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vredtree, 0.0, tlb, tub, &tval, success) );
2320 
2321  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2322 
2323  if( *success == FALSE )
2324  {
2325  /* something went wrong when computing s */
2326  return SCIP_OKAY;
2327  }
2328 
2329  /* computing the cut coefficients */
2330 
2331  /* compute r and s from tval */
2332  rval = (yval-(1.0-tval)*yub)/tval;
2333  assert(SCIPisFeasGE(scip, rval, ylb));
2334  assert(SCIPisFeasLE(scip, rval, yub));
2335  rval = MAX(ylb, MIN(yub, rval));
2336 
2337  sval = (xval-xub*tval)/(1.0-tval);
2338  assert(SCIPisFeasGE(scip, sval, xlb));
2339  assert(SCIPisFeasLE(scip, sval, xub));
2340  sval = MAX(xlb, MIN(xub, sval));
2341 
2342  /* compute f(xub,r) and f'(xub,r) */
2343  x0y0[0] = xub;
2344  x0y0[1] = rval;
2345  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad_rval) );
2346 
2347  /* compute f(s,yub) and f'(s,yub) */
2348  x0y0[0] = sval;
2349  x0y0[1] = yub;
2350  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad_sval) );
2351 
2352  /* compute vred(tval) */
2353  *convenvvalue = tval * frval + (1.0-tval) * fsval;
2354 
2355  /* generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2356  * alpha * x + beta * y - delta <= gamma * f(x,y) */
2357 
2358  if( !SCIPisEQ(scip, sval, xlb) )
2359  {
2360  /* use the x-axis to determine the second direction */
2361  if( !SCIPisFinite(grad_sval[0]) || SCIPisInfinity(scip, REALABS(grad_sval[0])) )
2362  {
2363  *success = FALSE;
2364  return SCIP_OKAY;
2365  }
2366 
2367  cutcoeff[0] = (yub-rval)*grad_sval[0];
2368  cutcoeff[1] = (xub-sval)*grad_sval[0]+fsval-frval;
2369  cutcoeff[2] = yub-rval;
2370  cutcoeff[3] = cutcoeff[0]*sval+cutcoeff[1]*yub-cutcoeff[2]*fsval;
2371  }
2372  else if( !SCIPisEQ(scip,rval,ylb) )
2373  {
2374  /* use the y-axis to determine the second direction */
2375  if( !SCIPisFinite(grad_rval[1]) || SCIPisInfinity(scip, REALABS(grad_rval[1])) )
2376  {
2377  *success = FALSE;
2378  return SCIP_OKAY;
2379  }
2380  cutcoeff[0] = (yub-rval)*grad_rval[1]+frval-fsval;
2381  cutcoeff[1] = (xub-sval)*grad_rval[1];
2382  cutcoeff[2] = xub-sval;
2383  cutcoeff[3] = cutcoeff[0]*sval+cutcoeff[1]*yub-cutcoeff[2]*fsval;
2384  }
2385  else
2386  {
2387  /* the point lies on the segment between (xlb,yub) and (xub,ylb)
2388  * due to numerics, we get into this case here instead in the LowerLeft
2389  */
2390  assert(SCIPisFeasLE(scip, yval, (ylb-yub) / (xub-xlb) * (xval-xlb) + yub));
2391  if( !SCIPisFinite(grad_sval[0]) || !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(MIN(grad_sval[0],grad_rval[0]))) )
2392  {
2393  /* FIXME maybe it is sufficient to have one of them finite, using that one for the MIN below? */
2394  *success = FALSE;
2395  return SCIP_OKAY;
2396  }
2397 
2398  cutcoeff[0] = (yub-rval)*MIN(grad_sval[0],grad_rval[0]);
2399  cutcoeff[1] = (xub-sval)*MIN(grad_sval[0],grad_rval[0])+fsval-frval;
2400  cutcoeff[2] = xub-sval;
2401  cutcoeff[3] = cutcoeff[0]*sval+cutcoeff[1]*yub-cutcoeff[2]*fsval;
2402  }
2403 
2404  SCIPdebugMsg(scip, "UpperRight: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
2405  SCIPdebugMsg(scip, "UpperRight: r=%g in [%g,%g], s=%g in [%g,%g], f(r,yub)=%g, f(xub,s)=%g\n",rval,xlb,xub,sval,ylb,yub,frval,fsval);
2406  SCIPdebugMsg(scip, "(s,yub)=(%g,%g) (xub,r)=(%g,%g) t=%g, vredval=%g\n",sval,yub,xub,rval,tval,*convenvvalue);
2407  SCIPdebugMsg(scip, "UpperRight: cutcoeff[0]=%g, cutcoeff[1]=%g, cutcoeff[2]=%g, cutcoeff[3]=%g\n",cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
2408  }
2409 
2410  return SCIP_OKAY;
2411 }
2412 
2413 /** generates a linear underestimator for f(x,y) with f(x,y) being convex in x and convex in y
2414  * generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2415  * alpha * x + beta * y - delta <= gamma * f(x,y)
2416  */
2417 static
2419  SCIP* scip, /**< SCIP data structure */
2420  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
2421  SCIP_EXPRTREE* f, /**< function f(x,y) */
2422  SCIP_Real* xyref, /**< reference values for x and y */
2423  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
2424  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
2425  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
2426  )
2427 {
2428  SCIP_VAR* x;
2429  SCIP_VAR* y;
2430  SCIP_Real xval;
2431  SCIP_Real xlb;
2432  SCIP_Real xub;
2433  SCIP_Real yval;
2434  SCIP_Real ylb;
2435  SCIP_Real yub;
2436  SCIP_Real x0y0[2];
2437 
2438  SCIP_EXPR* vred;
2439  SCIP_EXPRTREE* vredtree;
2440  SCIP_EXPR* e1;
2441  SCIP_EXPR* e2;
2442  SCIP_EXPR* tmp;
2443  SCIP_EXPR* expr;
2444  SCIP_EXPR* expr1;
2445  SCIP_EXPR* expr2;
2446  SCIP_EXPR* subst[2];
2447 
2448  SCIP_Real tval;
2449  SCIP_Real tlb;
2450  SCIP_Real tub;
2451  SCIP_Real sval;
2452  SCIP_Real rval;
2453 
2454  SCIP_Real frval;
2455  SCIP_Real fsval;
2456  SCIP_Real grad_rval[2];
2457  SCIP_Real grad_sval[2];
2458 
2459  assert(scip != NULL);
2460  assert(exprinterpreter != NULL);
2461  assert(f != NULL);
2462  assert(convenvvalue != NULL);
2463  assert(success != NULL);
2464 
2465  x = SCIPexprtreeGetVars(f)[0];
2466  y = SCIPexprtreeGetVars(f)[1];
2467 
2468  xlb = SCIPvarGetLbLocal(x);
2469  xub = SCIPvarGetUbLocal(x);
2470 
2471  ylb = SCIPvarGetLbLocal(y);
2472  yub = SCIPvarGetUbLocal(y);
2473 
2474  xval = xyref[0];
2475  yval = xyref[1];
2476 
2477  /* check that variables are not unbounded or fixed and reference point is in interior */
2478  assert(!SCIPisInfinity(scip, -xlb));
2479  assert(!SCIPisInfinity(scip, xub));
2480  assert(!SCIPisInfinity(scip, -ylb));
2481  assert(!SCIPisInfinity(scip, yub));
2482  assert(!SCIPisEQ(scip,xlb,xub));
2483  assert(!SCIPisEQ(scip,ylb,yub));
2484  assert(!SCIPisEQ(scip,xlb,xval));
2485  assert(!SCIPisEQ(scip,xub,xval));
2486  assert(!SCIPisEQ(scip,ylb,yval));
2487  assert(!SCIPisEQ(scip,yub,yval));
2488 
2489  *success = FALSE;
2490 
2491  SCIPdebugMsg(scip, "f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
2493  SCIPdebugMsgPrint(scip, "\n");
2494 
2495  /* check in which triangle the point (xval,yval) lies */
2496  if( yval <= (yub-ylb)/(xub-xlb)*(xval-xlb)+ylb )
2497  {
2498  /* lower right triangle, i.e. region A_2 */
2499  /* construct v_red(t) := t f( xub+(xval-xub)/t, ylb ) + (1-t)*f( xub, (yval-ylb*t)/(1-t)) */
2500 
2501  /* construct e1:= f(xub+(xval-xub)/t, ylb) */
2502  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2503  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xval-xub) ); /* tmp = xval-xub */
2504  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, tmp, expr) ); /* expr = (xval-xub)/t */
2505  if( xub != 0.0 )
2506  {
2507  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xub) ); /* tmp = xub */
2508  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, tmp) ); /* expr = xub + (xval-xub)/t */
2509  }
2510  subst[0] = expr;
2511 
2512  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, ylb) ); /* subst[1] = ylb */
2513 
2514  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e1, SCIPexprtreeGetRoot(f)) ); /* e1 = f(x,y) */
2515  assert(SCIPexprGetOperator(e1) != SCIP_EXPR_VARIDX);
2516  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e1, subst) ); /* e1 = f(xub + (xval-xub)/t, ylb) */
2517 
2518  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2519  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2520 
2521 
2522  /* construct e2 := f(xub, (yval-t*ylb)/(1-t)) */
2523  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_VARIDX, 0) ); /* expr1 = t */
2524  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2525  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MINUS, tmp, expr1) ); /* expr1 = 1-t */
2526 
2527  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_VARIDX, 0) ); /* expr2 = t */
2528  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, ylb) ); /* tmp = ylb */
2529  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, expr2, tmp) ); /* expr2 = ylb * t */
2530  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yval) ); /* tmp = yval */
2531  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MINUS, tmp, expr2) ); /* expr2 = yval - ylb * t */
2532 
2533  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, expr2, expr1) ); /* expr = (yval-t*ylb)/(1-t) */
2534  subst[1] = expr;
2535 
2536  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_CONST, xub) ); /* subst[0] = xub */
2537 
2538  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e2, SCIPexprtreeGetRoot(f)) ); /* e2 = f(x,y) */
2539  assert(SCIPexprGetOperator(e2) != SCIP_EXPR_VARIDX);
2540  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e2, subst) ); /* e2 = f(xub, (yval-t*ylb)/(1-t)) */
2541 
2542  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2543  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2544 
2545 
2546  /* construct vred := t * e1 + (1-t) * e2 */
2547  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2548  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MUL, e1, expr) ); /* expr1 = t * e1*/
2549 
2550 
2551  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2552  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2553  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_MINUS, tmp, expr) ); /* expr = 1-t */
2554  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, e2, expr) ); /* expr2 = (1-t) * e2*/
2555 
2556 
2557  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &vred, SCIP_EXPR_PLUS, expr1, expr2) );
2558  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &vredtree, vred, 1, 0, NULL) );
2559  SCIP_CALL( SCIPexprintCompile(exprinterpreter, vredtree) );
2560 
2561 
2562  /* compute bounds on t */
2563  tlb = (xub-xval)/(xub-xlb);
2564  tub = (yub-yval)/(yub-ylb);
2565 
2566  /* find t in [tlb, tub] such that vred'(t) = 0 */
2567  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vredtree, 0.0, tlb, tub, &tval, success) );
2568 
2569  if( *success == FALSE )
2570  {
2571  /* something went wrong when computing t */
2572  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2573  return SCIP_OKAY;
2574  }
2575 
2576  /* computing the cut coefficients */
2577 
2578  /* compute r and s from tval */
2579  rval = xub+(xval-xub)/tval;
2580  rval = MAX(xlb, MIN(xub, rval));
2581  sval = (yval-tval*ylb)/(1-tval);
2582  sval = MAX(ylb, MIN(yub, sval));
2583 
2584  /* compute vred(tval) */
2585  SCIP_CALL( SCIPexprtreeEval(vredtree, &tval, convenvvalue) );
2586 
2587  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2588 
2589  /* compute f(r, ylb) and f'(r, ylb) */
2590  x0y0[0] = rval;
2591  x0y0[1] = ylb;
2592  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad_rval) );
2593 
2594  /* compute f(xub, s) and f'(xub,s) */
2595  x0y0[0] = xub;
2596  x0y0[1] = sval;
2597  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad_sval) );
2598 
2599  /* generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2600  * alpha * x + beta * y - delta <= gamma * f(x,y) */
2601  if( !(SCIPisEQ(scip,rval,xlb)) )
2602  {
2603  /* take the slope along the x-axis and the slope between the points */
2604  if( !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(grad_rval[0])) )
2605  {
2606  *success = FALSE;
2607  return SCIP_OKAY;
2608  }
2609  cutcoeff[0] = (sval-ylb)*grad_rval[0];
2610  cutcoeff[1] = (rval-xub)*grad_rval[0]-frval+fsval;
2611  cutcoeff[2] = sval-ylb;
2612  cutcoeff[3] = cutcoeff[0]*xub+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2613  }
2614  else if( !(SCIPisEQ(scip,sval,yub)) )
2615  {
2616  /* take the slope along the y-axis and the slope between the points */
2617  if( !SCIPisFinite(grad_sval[1]) || SCIPisInfinity(scip, REALABS(grad_sval[1])) )
2618  {
2619  *success = FALSE;
2620  return SCIP_OKAY;
2621  }
2622  cutcoeff[0] = (ylb-sval)*grad_sval[1]-frval+fsval;
2623  cutcoeff[1] = (xub-rval)*grad_sval[1];
2624  cutcoeff[2] = xub-rval;
2625  cutcoeff[3] = cutcoeff[0]*xub+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2626  }
2627  else
2628  {
2629  /* the point lies on the segment between (xlb,yub) and (xub,ylb) */
2630  if( !SCIPisFinite(grad_sval[0]) || !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(MIN(grad_sval[0],grad_rval[0]))) )
2631  {
2632  /* FIXME maybe it is sufficient to have one of them finite, using that one for the MIN below? */
2633  *success = FALSE;
2634  return SCIP_OKAY;
2635  }
2636  cutcoeff[0] = (sval-ylb)*MIN(grad_sval[0],grad_rval[0]);
2637  cutcoeff[1] = (rval-xub)*MIN(grad_sval[0],grad_rval[0])+fsval-frval;
2638  cutcoeff[2] = sval-ylb;
2639  cutcoeff[3] = cutcoeff[0]*xub+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2640  }
2641 
2642 
2643  SCIPdebugMsg(scip, "LowerRight: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
2644  SCIPdebugMsg(scip, "LowerRight: t=%g in [%g,%g], r=%g in [%g,%g], s=%g in [%g,%g]\n",tval,tlb,tub,rval,xlb,xub,sval,ylb,yub);
2645  SCIPdebugMsg(scip, "LowerRight: (r,ylb)=(%g,%g) (xub,sval)=(%g,%g) vredval=%g\n",rval,ylb,xub,sval,*convenvvalue);
2646  SCIPdebugMsg(scip, "LowerRight: cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=1.0,cutcoeff[3]=%g\n",cutcoeff[0]/cutcoeff[2],cutcoeff[1]/cutcoeff[2],cutcoeff[3]/cutcoeff[2]);
2647 
2648  }
2649  else
2650  {
2651  /* (xval,yval) lie in the upper left triangle, i.e. region A_1 */
2652  /* construct v_red(t) := t f( xlb+(xval-xlb)/t, yub ) + (1-t)*f( xlb, (yval-yub*t)/(1-t) ) */
2653 
2654  /* construct e1:= f(xlb+(xval-xlb)/t, yub) */
2655  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2656  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xval-xlb) ); /* tmp = xval-xlb */
2657  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, tmp, expr) ); /* expr = (xval-xlb)/lambda */
2658  if( xlb != 0.0 )
2659  {
2660  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xlb) ); /* tmp = xlb */
2661  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, tmp) ); /* expr = xlb + (xval-xlb)/t */
2662  }
2663  subst[0] = expr;
2664 
2665  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, yub) ); /* subst[1] = yub */
2666 
2667  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e1, SCIPexprtreeGetRoot(f)) ); /* e1 = f(x,y) */
2668  assert(SCIPexprGetOperator(e1) != SCIP_EXPR_VARIDX);
2669  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e1, subst) ); /* e1 = f(xlb + (xval-xlb)/t, yub) */
2670 
2671  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2672  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2673 
2674 
2675  /* construct e2 := f(xlb, (yval-t*yub)/(1-t) ) */
2676  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_VARIDX, 0) ); /* expr1 = t */
2677  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2678  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MINUS, tmp, expr1) ); /* expr1 = 1-t */
2679 
2680  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_VARIDX, 0) ); /* expr2 = t */
2681  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yub) ); /* tmp = yub */
2682  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, expr2, tmp) ); /* expr2 = yub * t */
2683  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yval) ); /* tmp = yval */
2684  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MINUS, tmp, expr2) ); /* expr2 = yval - yub * t */
2685 
2686  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, expr2, expr1) ); /* expr = (yval-t*yub)/(1-t) */
2687  subst[1] = expr;
2688 
2689  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_CONST, xlb) ); /* subst[0] = xlb */
2690 
2691  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e2, SCIPexprtreeGetRoot(f)) ); /* e2 = f(x,y) */
2692  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e2, subst) ); /* e2 = f( xlb , (yval-t*yub)/(1-t) ) */
2693 
2694  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2695  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2696 
2697 
2698  /* construct vred := t * e1 + (1-t) * e2 */
2699  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2700  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MUL, e1, expr) ); /* expr1 = t * e1*/
2701 
2702 
2703  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2704  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2705  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_MINUS, tmp, expr) ); /* expr = 1-t */
2706  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, e2, expr) ); /* expr2 = (1-t) * e2*/
2707 
2708 
2709  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &vred, SCIP_EXPR_PLUS, expr1, expr2) );
2710  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &vredtree, vred, 1, 0, NULL) );
2711  SCIP_CALL( SCIPexprintCompile(exprinterpreter, vredtree) );
2712 
2713 
2714  /* compute bounds on lambda */
2715  tlb = (xval-xlb)/(xub-xlb);
2716  tub = (yval-ylb)/(yub-ylb);
2717 
2718  /* find t in [tlb, tub] such that vred'(t) = 0 */
2719  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vredtree, 0.0, tlb, tub, &tval, success) );
2720 
2721  if( *success == FALSE )
2722  {
2723  /* something went wrong when computing s */
2724  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2725  return SCIP_OKAY;
2726  }
2727 
2728  /* computing the cut coefficients */
2729 
2730  /* compute r and s from tval */
2731  rval = xlb+(xval-xlb)/tval;
2732  rval = MAX(xlb, MIN(xub, rval));
2733  sval = (yval-tval*yub)/(1-tval);
2734  sval = MAX(ylb, MIN(yub, sval));
2735 
2736  /* compute vred(tval) */
2737  SCIP_CALL( SCIPexprtreeEval(vredtree, &tval, convenvvalue) );
2738 
2739  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2740 
2741  /* compute f(r, yub) and f'(r, yub) */
2742  x0y0[0] = rval;
2743  x0y0[1] = yub;
2744  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad_rval) );
2745 
2746  /* compute f(xlb, s) and f'(xlb, s) */
2747  x0y0[0] = xlb;
2748  x0y0[1] = sval;
2749  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad_sval) );
2750 
2751  /* generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2752  * alpha * x + beta * y - delta <= gamma * f(x,y) */
2753  if( !SCIPisEQ(scip,rval,xub) )
2754  {
2755  /* take the slope along the x-axis and the slope between the points */
2756  if( !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(grad_rval[0])) )
2757  {
2758  *success = FALSE;
2759  return SCIP_OKAY;
2760  }
2761  cutcoeff[0] = (yub-sval)*grad_rval[0];
2762  cutcoeff[1] = (xlb-rval)*grad_rval[0]-fsval+frval;
2763  cutcoeff[2] = yub-sval;
2764  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2765  }
2766  else if( !SCIPisEQ(scip,sval,ylb) )
2767  {
2768  /* take the slope along the y-axis and the slope between the points */
2769  if( !SCIPisFinite(grad_sval[1]) || SCIPisInfinity(scip, REALABS(grad_sval[1])) )
2770  {
2771  *success = FALSE;
2772  return SCIP_OKAY;
2773  }
2774  cutcoeff[0] = (sval-yub)*grad_sval[1]-fsval+frval;
2775  cutcoeff[1] = (rval-xlb)*grad_sval[1];
2776  cutcoeff[2] = rval-xlb;
2777  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2778  }
2779  else
2780  {
2781  /* the point lies on the segment between (xlb,yub) and (xub,ylb) */
2782  if( !SCIPisFinite(grad_sval[0]) || !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(MIN(grad_rval[0],grad_sval[0]))) )
2783  {
2784  /* FIXME maybe it is sufficient to have one of them finite, using that one for the MIN below? */
2785  *success = FALSE;
2786  return SCIP_OKAY;
2787  }
2788  cutcoeff[0] = (yub-sval)*MIN(grad_rval[0],grad_sval[0]);
2789  cutcoeff[1] = (xlb-rval)*MIN(grad_rval[0],grad_sval[0])-fsval+frval;
2790  cutcoeff[2] = yub-sval;
2791  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2792  }
2793 
2794  SCIPdebugMsg(scip, "UpperLeft: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
2795  SCIPdebugMsg(scip, "UpperLeft: r=%g in [%g,%g], s=%g in [%g,%g], f(r,yub)=%g, f(xlb,s)=%g\n",rval,xlb,xub,sval,ylb,yub,frval,fsval);
2796  SCIPdebugMsg(scip, "t=%g in [%g,%g], (r,yub)=(%g,%g) (xlb,sval)=(%g,%g) vredval=%g\n",tval,tlb,tub,rval,yub,xlb,sval,*convenvvalue);
2797  SCIPdebugMsg(scip, "UpperLeft: cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=1.0,cutcoeff[3]=%g\n",cutcoeff[0]/cutcoeff[2],cutcoeff[1]/cutcoeff[2],cutcoeff[3]/cutcoeff[2]);
2798  }
2799 
2800  return SCIP_OKAY;
2801 }
2802 
2803 
2804 /** generates a linear underestimator for f(x,y) with f(x,y) being STRICTLY convex in x and concave in y
2805  * generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that alpha * x + beta * y - delta <= gamma * f(x,y)
2806  */
2807 static
2809  SCIP* scip, /**< SCIP data structure */
2810  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
2811  SCIP_EXPRTREE* f, /**< function f(x,y) */
2812  SCIP_EXPRTREE* f_yfixed, /**< function f(x;y) with x variable and y parameter */
2813  SCIP_EXPRTREE* vred, /**< function vred(s;x0,y0,ylb,yub) */
2814  SCIP_Real xyref[2], /**< reference values for (x,y) */
2815  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
2816  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
2817  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
2818  )
2819 {
2820  SCIP_VAR* x;
2821  SCIP_VAR* y;
2822  SCIP_Real xval;
2823  SCIP_Real xlb;
2824  SCIP_Real xub;
2825  SCIP_Real yval;
2826  SCIP_Real ylb;
2827  SCIP_Real yub;
2828 
2829  assert(scip != NULL);
2830  assert(exprinterpreter != NULL);
2831  assert(f != NULL);
2832  assert(success != NULL);
2833  assert(xyref != NULL);
2834 
2835  x = SCIPexprtreeGetVars(f)[0];
2836  y = SCIPexprtreeGetVars(f)[1];
2837 
2838  xlb = SCIPvarGetLbLocal(x);
2839  xub = SCIPvarGetUbLocal(x);
2840 
2841  ylb = SCIPvarGetLbLocal(y);
2842  yub = SCIPvarGetUbLocal(y);
2843 
2844  xval = xyref[0];
2845  yval = xyref[1];
2846 
2847  /* reference point should not be outside of bounds */
2848  assert(SCIPisLE(scip, xlb, xval));
2849  assert(SCIPisGE(scip, xub, xval));
2850  assert(SCIPisLE(scip, ylb, yval));
2851  assert(SCIPisGE(scip, yub, yval));
2852 
2853  *success = FALSE;
2854 
2855  if( SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub) )
2856  {
2857  SCIPdebugMsg(scip, "skip convex-concave underestimator, since y is unbounded\n");
2858  return SCIP_OKAY;
2859  }
2860 
2861  SCIPdebugMsg(scip, "f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
2863  SCIPdebugMsgPrint(scip, "\n");
2864 
2865  if( SCIPisEQ(scip, xlb, xub) )
2866  {
2867  /* x is fixed, so function is now concave -> generate secant between (x, ylb) and (x, yub) */
2868  SCIP_Real xy[2];
2869  SCIP_Real f_ylb;
2870  SCIP_Real f_yub;
2871  SCIP_Real slope;
2872 
2873  if( SCIPisEQ(scip, ylb, yub) )
2874  {
2875  SCIPdebugMsg(scip, "skip convex-concave underestimator, since both x and y are fixed\n");
2876  return SCIP_OKAY;
2877  }
2878 
2879  /* get f(x, ylb) */
2880  xy[0] = xlb;
2881  xy[1] = ylb;
2882  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, xy, &f_ylb) );
2883 
2884  if( !SCIPisFinite(f_ylb) )
2885  {
2886  SCIPdebugMsg(scip, "cannot evaluate function at (xlb, ylb)\n");
2887  return SCIP_OKAY;
2888  }
2889 
2890  /* get f(x, yub) */
2891  xy[1] = yub;
2892  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, xy, &f_yub) );
2893 
2894  if( !SCIPisFinite(f_yub) )
2895  {
2896  SCIPdebugMsg(scip, "cannot evaluate function at (xlb, yub)\n");
2897  return SCIP_OKAY;
2898  }
2899 
2900  slope = (f_yub - f_ylb) / (yub - ylb);
2901 
2902  /* secant is f(x,ylb) + slope * (y - ylb) <= f(x,y)*/
2903 
2904  cutcoeff[0] = 0.0; /* coefficient of x == 0 */
2905  cutcoeff[1] = slope; /* coefficient of y == slope */
2906  cutcoeff[2] = 1.0; /* coefficient of f(x,y) == 1.0 */
2907  cutcoeff[3] = -(f_ylb - slope * ylb); /* constant == -(f(x,ylb) - slope * ylb) */
2908  *convenvvalue = f_ylb+slope*(yval-ylb);
2909 
2910  *success = TRUE;
2911  return SCIP_OKAY;
2912  }
2913 
2914  if( SCIPisEQ(scip, ylb, yub) )
2915  {
2916  /* y is fixed, so function is now convex -> linearize in (xval, ylb) */
2917  SCIP_Real xy[2];
2918  SCIP_Real grad[2];
2919  SCIP_Real fval;
2920 
2921  xy[0] = xval;
2922  xy[1] = ylb;
2923  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xy, TRUE, &fval, grad) );
2924 
2925  if( !SCIPisFinite(fval) || !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
2926  {
2927  perturb(&xval, xlb, xub, 0.001);
2928  xy[0] = xval;
2929 
2930  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xy, TRUE, &fval, grad) );
2931 
2932  if( !SCIPisFinite(fval) || !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
2933  {
2934  SCIPdebugMsg(scip, "cannot evaluate function or derivative in (xval,ylb), also after perturbation\n");
2935  return SCIP_OKAY;
2936  }
2937  }
2938 
2939  /* linearization is f(xval,ylb) + df/dx(xval,ylb) * (x - xval) <= f(x,y) */
2940 
2941  cutcoeff[0] = grad[0]; /* coefficient of x == gradient in x */
2942  cutcoeff[1] = 0.0; /* coefficient of y == 0 */
2943  cutcoeff[2] = 1.0; /* coefficient of f(x,y) == 1.0 */
2944  cutcoeff[3] = -(fval - grad[0] * xval); /* constant == -(f(xval,ylb) - grad * xval) */
2945  *convenvvalue = fval;
2946 
2947  *success = TRUE;
2948  return SCIP_OKAY;
2949  }
2950 
2951  /* compute coefficients of a valid underestimating hyperplane */
2952 
2953  if( SCIPisFeasEQ(scip, xlb, xval) || SCIPisFeasEQ(scip, xub, xval) )
2954  {
2955  /* x is at it's lower or upper bound */
2956  SCIP_Real x0y0[2];
2957  SCIP_Real gradylb[2];
2958  SCIP_Real gradyub[2];
2959  SCIP_Real fvalylb;
2960  SCIP_Real fvalyub;
2961 
2962  xval = SCIPisFeasEQ(scip, xlb, xval) ? xlb : xub;
2963 
2964  /* compute f'(xval, ylb) and f'(xval, yub) */
2965  x0y0[0] = xval;
2966  x0y0[1] = ylb;
2967  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fvalylb, gradylb) );
2968 
2969  x0y0[1] = yub;
2970  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fvalyub, gradyub) );
2971 
2972  if( !SCIPisFinite(gradylb[0]) || !SCIPisFinite(gradyub[0]) || !SCIPisFinite(fvalylb) || !SCIPisFinite(fvalyub) ||
2973  SCIPisInfinity(scip, REALABS(gradylb[0])) || SCIPisInfinity(scip, REALABS(gradyub[0])) )
2974  {
2975  /* move xval inside domain and continue below, hope this will work better */
2976  perturb(&xval, xlb, xub, 0.001);
2977  }
2978  else
2979  {
2980  /* setup cut coefficients */
2981  if( xval == xlb ) /*lint !e777*/
2982  cutcoeff[0] = (yub - ylb) * MIN(gradylb[0], gradyub[0]);/* coefficient of x */
2983  else
2984  cutcoeff[0] = (yub - ylb) * MAX(gradylb[0], gradyub[0]);/* coefficient of x */
2985  cutcoeff[1] = fvalyub - fvalylb; /* coefficient of y */
2986  cutcoeff[2] = yub - ylb; /* coefficient of f(x,y) */
2987  cutcoeff[3] = cutcoeff[0] * xval + cutcoeff[1] * ylb - cutcoeff[2] * fvalylb; /* constant */
2988  *convenvvalue = fvalylb;
2989 
2990  SCIPdebugMsg(scip, "alpha: %g, beta: %g, gamma: 1.0, delta: %g\n",
2991  cutcoeff[0]/cutcoeff[2], cutcoeff[1]/cutcoeff[2], cutcoeff[3]/cutcoeff[2]);
2992 
2993  *success = TRUE;
2994  return SCIP_OKAY;
2995  }
2996  }
2997 
2998  if( SCIPisFeasEQ(scip, ylb, yval) )
2999  {
3000  /* y is at it's lower bound */
3001  SCIP_Real x0y0[2];
3002  SCIP_Real grad[2];
3003  SCIP_Real xtilde;
3004  SCIP_Real fval, ftilde;
3005 
3006  /* these two cases should have been handled above */
3007  assert(!SCIPisEQ(scip, xlb, xval));
3008  assert(!SCIPisEQ(scip, xub, xval));
3009 
3010  assert(f_yfixed != NULL);
3011 
3012  /* compute f(xval, ylb) and f'(xval, ylb) */
3013  x0y0[0] = xval;
3014  x0y0[1] = ylb;
3015  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fval, grad) );
3016 
3017  if( !SCIPisFinite(fval) || !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
3018  {
3019  /* move yval inside domain and continue below, hope this will work better */
3020  perturb(&yval, ylb, yub, 0.001);
3021  }
3022  else
3023  {
3024  /* setup f(x,yub) */
3025  SCIPexprtreeSetParamVal(f_yfixed, 0, yub);
3026  SCIP_CALL( SCIPexprintNewParametrization(exprinterpreter, f_yfixed) );
3027 
3028  SCIPdebugMsg(scip, "f(x,yub) = ");
3030  SCIPdebugMsgPrint(scip, "\n");
3031 
3032  assert(SCIPexprtreeGetNVars(f_yfixed) == 1);
3033 
3034  /* find xtilde in [xlb, xub] such that f'(xtilde,yub) = f'(xval,ylb) */
3035  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, f_yfixed, grad[0], xlb, xub, &xtilde, success) );
3036 
3037  if( !*success )
3038  {
3039  SCIP_Real fxlb;
3040  SCIP_Real fxub;
3041 
3042  /* if we could not find an xtilde such that f'(xtilde,yub) = f'(xval,ylb), then probably because f'(x,yub) is constant
3043  * in this case, choose xtilde from {xlb, xub} such that it maximizes f'(xtilde, yub) - grad[0]*xtilde
3044  */
3045  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xlb, &fxlb) ); /* coverity ignore ARRAY_VS_SINGLETON warning */
3046  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xub, &fxub) ); /* coverity ignore ARRAY_VS_SINGLETON warning */
3047 
3048  SCIPdebugMsg(scip, "couldn't solve deriv equ, compare f(%g,%g) - %g*%g = %g and f(%g,%g) - %g*%g = %g\n",
3049  xlb, ylb, grad[0], xlb, fxlb - grad[0] * xlb,
3050  xub, ylb, grad[0], xub, fxub - grad[0] * xub);
3051 
3052  if( SCIPisFinite(fxlb) && SCIPisFinite(fxub) )
3053  {
3054  if( fxlb - grad[0] * xlb > fxub - grad[0] * xub )
3055  xtilde = xlb;
3056  else
3057  xtilde = xub;
3058  *success = TRUE;
3059  }
3060  else
3061  {
3062  /* move yval inside domain and continue below, hope this will work better */
3063  perturb(&yval, ylb, yub, 0.001);
3064  }
3065  }
3066 
3067  if( *success )
3068  {
3069  /* compute f(xtilde, yub) */
3070  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xtilde, &ftilde) ); /* coverity ignore ARRAY_VS_SINGLETON warning */
3071 
3072  SCIPdebugMsg(scip, "xtilde = %g, f(%g,%g) = %g\n", xtilde, xtilde, yub, ftilde);
3073 
3074  /* setup cut coefficients */
3075  cutcoeff[0] = (yub - ylb) * grad[0]; /* coefficient of x */
3076  cutcoeff[1] = ftilde - fval - grad[0] * (xtilde - xval); /* coefficient of y */
3077  cutcoeff[2] = yub - ylb; /* coefficient of f(x,y) */
3078  cutcoeff[3] = cutcoeff[0] * xval + cutcoeff[1] * ylb - cutcoeff[2] * fval; /* constant */
3079  *convenvvalue = fval;
3080 
3081  SCIPdebugMsg(scip, "alpha: %g, beta: %g, gamma: %g, delta: %g\n", cutcoeff[0], cutcoeff[1], cutcoeff[2], cutcoeff[3]);
3082 
3083  return SCIP_OKAY;
3084  }
3085  }
3086  }
3087 
3088  if( SCIPisFeasEQ(scip, yval, yub) )
3089  {
3090  /* y is at it's upper bound */
3091  SCIP_Real x0y0[2];
3092  SCIP_Real grad[2];
3093  SCIP_Real fval;
3094  SCIP_Real xtilde;
3095  SCIP_Real ftilde;
3096 
3097  assert(f_yfixed != NULL);
3098 
3099  /* compute f(xval, yub) and f'(xval, yub) */
3100  x0y0[0] = xval;
3101  x0y0[1] = yub;
3102  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fval, grad) );
3103 
3104  if( !SCIPisFinite(fval) || !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
3105  {
3106  /* move yval inside domain and continue below, hope this will work better */
3107  perturb(&yval, ylb, yub, 0.001);
3108  }
3109  else
3110  {
3111  /* setup f(x,ylb) */
3112  SCIPexprtreeSetParamVal(f_yfixed, 0, ylb);
3113  SCIP_CALL( SCIPexprintNewParametrization(exprinterpreter, f_yfixed) );
3114 
3115  assert(SCIPexprtreeGetNVars(f_yfixed) == 1);
3116 
3117  /* find xtilde in [xlb, xub] such that f'(x,ylb) = f'(xval,yub) */
3118  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, f_yfixed, grad[0], xlb, xub, &xtilde, success) );
3119 
3120  if( !*success )
3121  {
3122  SCIP_Real fxlb;
3123  SCIP_Real fxub;
3124 
3125  /* if we could not find an xtilde such that f'(xtilde,ylb) = f'(xval,yub), then probably because f'(x,ylb) is constant
3126  * in this case, choose xtilde from {xlb, xub} such that it maximizes f'(xtilde, yub) - grad[0]*xtilde
3127  */
3128  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xlb, &fxlb) ); /* coverity ignore ARRAY_VS_SINGLETON warning */
3129  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xub, &fxub) ); /* coverity ignore ARRAY_VS_SINGLETON warning */
3130 
3131  SCIPdebugMsg(scip, "couldn't solve deriv equ, compare f(%g,%g) - %g*%g = %g and f(%g,%g) - %g*%g = %g\n",
3132  xlb, yub, grad[0], xlb, fxlb - grad[0] * xlb,
3133  xub, yub, grad[0], xub, fxub - grad[0] * xub);
3134 
3135  if( SCIPisFinite(fxlb) && SCIPisFinite(fxub) )
3136  {
3137  if( fxlb - grad[0] * xlb < fxub - grad[0] * xub )
3138  xtilde = xlb;
3139  else
3140  xtilde = xub;
3141  *success = TRUE;
3142  }
3143  else
3144  {
3145  /* move yval inside domain and continue below, hope this will work better */
3146  perturb(&yval, ylb, yub, 0.001);
3147  }
3148  }
3149 
3150  if( *success )
3151  {
3152  /* compute f(xtilde, yub) */
3153  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xtilde, &ftilde) ); /* coverity ignore ARRAY_VS_SINGLETON warning */
3154 
3155  SCIPdebugMsg(scip, "xtilde = %g, f(%g,%g) = %g\n", xtilde, xtilde, ylb, ftilde);
3156 
3157  /* set up cut coefficients */
3158  cutcoeff[0] = (yub - ylb) * grad[0];
3159  cutcoeff[1] = grad[0] * (xtilde - xval) - ftilde + fval;
3160  cutcoeff[2] = yub - ylb;
3161  cutcoeff[3] = cutcoeff[0] * xval + cutcoeff[1] * yub - cutcoeff[2] * fval;
3162  *convenvvalue = fval;
3163 
3164  SCIPdebugMsg(scip, "alpha: %g, beta: %g, gamma: %g, delta: %g\n", cutcoeff[0], cutcoeff[1], cutcoeff[2], cutcoeff[3]);
3165 
3166  return SCIP_OKAY;
3167  }
3168  }
3169  }
3170 
3171  {
3172  /* x and y are somewhere between the bounds,
3173  * -> envelope is generated from f(x,y) in y=ylb and in y=yub
3174  */
3175  SCIP_Real paramvals[4];
3176 #ifdef SCIP_DEBUG
3177  const char* paramnames[4] = {"x0", "y0", "ylb", "yub"};
3178 #endif
3179  SCIP_Real t;
3180  SCIP_Real slb;
3181  SCIP_Real sub;
3182  SCIP_Real sval;
3183  SCIP_Real rval;
3184  SCIP_Real fsval;
3185  SCIP_Real frval;
3186  SCIP_Real grad[2];
3187  SCIP_Real x0y0[2];
3188 
3189  assert(vred != NULL);
3190 
3191  /* check that variables are not unbounded or fixed and reference point is in interior
3192  * @todo it should also work if x is unbounded, or? */
3193  /* assert(!SCIPisInfinity(scip, -xlb));
3194  assert(!SCIPisInfinity(scip, xub)); */
3195  assert(!SCIPisInfinity(scip, -ylb));
3196  assert(!SCIPisInfinity(scip, yub));
3197 
3198  /* update parameter values in vred */
3199  paramvals[0] = xval;
3200  paramvals[1] = yval;
3201  paramvals[2] = ylb;
3202  paramvals[3] = yub;
3203  SCIP_CALL( SCIPexprtreeSetParams(vred, 4, paramvals) );
3204  SCIP_CALL( SCIPexprintNewParametrization(exprinterpreter, vred) );
3205 
3206  SCIPdebugMsg(scip, "vred(s;x0,y0,ylb,yub) = ");
3207  SCIPdebug( SCIPexprtreePrint(vred, SCIPgetMessagehdlr(scip), NULL, NULL, paramnames) );
3208  SCIPdebugMsgPrint(scip, "\n");
3209 
3210  /* compute bounds on s */
3211  t = (yub - yval) / (yub - ylb);
3212  if( !SCIPisInfinity(scip, xub) )
3213  slb = (yval - yub) / (ylb - yval) * (xval / t - xub);
3214  else
3215  slb = -SCIPinfinity(scip);
3216  if( !SCIPisInfinity(scip, xlb) )
3217  sub = (yval - yub) / (ylb - yval) * (xval / t - xlb);
3218  else
3219  sub = SCIPinfinity(scip);
3220  if( slb < xlb )
3221  slb = xlb;
3222  if( sub > xub )
3223  sub = xub;
3224 
3225  /* find s in [slb, sub] such that vred'(s) = 0 */
3226  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vred, 0.0, slb, sub, &sval, success) );
3227  assert(!*success || !SCIPisInfinity(scip, REALABS(sval)));
3228 
3229  if( *success )
3230  {
3231  /* compute r from s */
3232  rval = xval / t + (1.0 - 1.0 / t) * sval;
3233  assert(SCIPisFeasGE(scip, rval, xlb));
3234  assert(SCIPisFeasLE(scip, rval, xub));
3235  rval = MAX(xlb, MIN(rval, xub));
3236 
3237  /* compute f(sval, yub) */
3238  x0y0[0] = sval;
3239  x0y0[1] = yub;
3240  SCIP_CALL( SCIPexprtreeEval(f, x0y0, &fsval) );
3241 
3242  /* compute f(rval, ylb) */
3243  x0y0[0] = rval;
3244  x0y0[1] = ylb;
3245  SCIP_CALL( SCIPexprtreeEval(f, x0y0, &frval) );
3246 
3247  if( !SCIPisEQ(scip, sval, xlb) && !SCIPisEQ(scip, sval, xub) )
3248  {
3249  x0y0[0] = sval;
3250  x0y0[1] = yub;
3251 
3252  /* compute f'(xbar, ybar) */
3253  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad) );
3254  }
3255  else if( !SCIPisEQ(scip, rval, xlb) && !SCIPisEQ(scip, rval, xub) )
3256  {
3257  x0y0[0] = rval;
3258  x0y0[1] = ylb;
3259 
3260  /* compute f'(xbar, ybar) */
3261  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad) );
3262  }
3263  else
3264  {
3265  /* rare case
3266  * both points (sval, yub) and (rval, ylb) should yield valid inequality
3267  * for now, just take the first one, if differentiable, otherwise second one
3268  */
3269  x0y0[0] = sval;
3270  x0y0[1] = yub;
3271 
3272  /* compute f'(xbar, ybar) */
3273  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad) );
3274 
3275  if( !SCIPisFinite(grad[0]) )
3276  {
3277  x0y0[0] = rval;
3278  x0y0[1] = ylb;
3279 
3280  /* compute new f'(xbar, ybar) */
3281  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad) );
3282  }
3283  }
3284 
3285  /* compute vred(s) = t * f(rval, ylb) + (1-t) * f(sval, yub) */
3286  *convenvvalue = t * frval + (1.0 - t) * fsval;
3287 
3288  SCIPdebugMsg(scip, "Parallel: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
3289  SCIPdebugMsg(scip, "Parallel: r=%g s=%g in [%g,%g], y in [%g,%g], f(r,ylb)=%g, f(xlb,s)=%g\n",rval,sval,xlb,xub,ylb,yub,frval,fsval);
3290  SCIPdebugMsg(scip, "(r,ylb)=(%g,%g), (s,yub)=(%g,%g), vredval=%g\n",rval,ylb,sval,yub,*convenvvalue);
3291 
3292  if( !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
3293  {
3294  SCIPdebugMsg(scip, "f not differentiable at (x0,y0) w.r.t. x\n");
3295  *success = FALSE;
3296  return SCIP_OKAY;
3297  }
3298 
3299  /* compute cut coefficients */
3300  cutcoeff[0] = (yub - ylb) * grad[0];
3301  cutcoeff[1] = fsval - frval - (sval - rval) * grad[0];
3302  cutcoeff[2] = yub - ylb;
3303  cutcoeff[3] = cutcoeff[0] * xval + cutcoeff[1] * yval - cutcoeff[2] * *convenvvalue;
3304 
3305  SCIPdebugMsg(scip, "Parallel: cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=1.0,cutcoeff[3]=%g\n",cutcoeff[0]/cutcoeff[2],cutcoeff[1]/cutcoeff[2],cutcoeff[3]/cutcoeff[2]);
3306  }
3307  }
3308 
3309  return SCIP_OKAY;
3310 }
3311 
3312 
3313 /** generates a cut for one side of lhs <= f(x,y) + c*z <= rhs with f(x,y) being convex in x and concave in y */
3314 static
3316  SCIP* scip, /**< SCIP data structure */
3317  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
3318  SCIP_CONS* cons, /**< constraint */
3319  SCIP_Real xyref[2], /**< reference values for nonlinear variables */
3320  SCIP_SIDETYPE violside, /**< for which side of constraint to find a cut */
3321  SCIP_ROW** row /**< storage for cut */
3322  )
3323 {
3324  SCIP_CONSDATA* consdata;
3325  SCIP_Real cutcoeff[4];
3326  SCIP_Real dummy;
3327  SCIP_Bool success;
3328  SCIP_Real coefs[2];
3329  char cutname[SCIP_MAXSTRLEN];
3330 
3331  assert(scip != NULL);
3332  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
3333  assert(cons != NULL);
3334  assert(row != NULL);
3335 
3336  consdata = SCIPconsGetData(cons);
3337  assert(consdata != NULL);
3338  assert(consdata->f != NULL);
3339  assert(consdata->convextype == SCIP_BIVAR_CONVEX_CONCAVE);
3340 
3341  *row = NULL;
3342 
3343  SCIPdebugMsg(scip, "generate %sestimator for convex-concave constraint <%s>\n",
3344  (violside == SCIP_SIDETYPE_LEFT ? "over" : "under"), SCIPconsGetName(cons));
3345  SCIPdebugPrintCons(scip, cons, NULL);
3346 
3347  if( violside == SCIP_SIDETYPE_LEFT )
3348  {
3349  /* need overestimator */
3350  assert(!SCIPisInfinity(scip, -consdata->lhs));
3351 
3352  if( consdata->sepaconvexconcave.lineariny )
3353  {
3354  /* f is strictly convex in x and linear in y -> overestimator is polyhedral */
3355  SCIP_Real constant;
3356 
3357  SCIP_CALL( generateEstimatingHyperplane(scip, exprinterpreter, consdata->f, TRUE, xyref, &coefs[0], &coefs[1], &constant, &success) );
3358 
3359  if( success )
3360  {
3361  assert(SCIPisFinite(coefs[0]));
3362  assert(SCIPisFinite(coefs[1]));
3363  assert(SCIPisFinite(constant));
3364 
3365  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_overesthyperplanecut_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
3366  SCIP_CALL( SCIPcreateRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, 0, NULL, NULL, consdata->lhs - constant, SCIPinfinity(scip), TRUE, FALSE, TRUE) );
3367 
3368  SCIP_CALL( SCIPaddVarsToRow(scip, *row, 2, SCIPexprtreeGetVars(consdata->f), coefs) );
3369  if( consdata->z != NULL )
3370  {
3371  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
3372  }
3373  }
3374  }
3375  else
3376  {
3377  SCIP_Real xyref_[2];
3378 
3379  /* f is strictly concave in y -> can compute overestimator by applying generateConvexConcaveUnderstimator on -f(y,x) */
3380  assert(consdata->sepaconvexconcave.f_neg_swapped != NULL);
3381 
3382  xyref_[0] = xyref[1];
3383  xyref_[1] = xyref[0];
3384  SCIP_CALL( generateConvexConcaveUnderestimator(scip, exprinterpreter, consdata->sepaconvexconcave.f_neg_swapped, consdata->sepaconvexconcave.f_neg_swapped_yfixed, consdata->sepaconvexconcave.vred_neg_swapped, xyref_, cutcoeff, &dummy, &success) );
3385 
3386  if( success )
3387  {
3388  assert(SCIPisFinite(cutcoeff[0]));
3389  assert(SCIPisFinite(cutcoeff[1]));
3390  assert(SCIPisFinite(cutcoeff[2]));
3391  assert(SCIPisFinite(cutcoeff[3]));
3392  assert(SCIPisPositive(scip, cutcoeff[2])); /* assert gamma > 0 */
3393 
3394  /* construct row from cut coefficients (alpha, beta, gamma, delta)
3395  * coefficients are such that alpha * y + beta * x - gamma * (-f(x,y)) <= delta,
3396  * i.e., gamma * f(x,y) <= delta - alpha * y - beta * x
3397  * -> lhs <= f(x,y) + c*z <= delta/gamma - alpha/gamma * y - beta/gamma * x + c*z
3398  */
3399  coefs[0] = -cutcoeff[1] / cutcoeff[2];
3400  coefs[1] = -cutcoeff[0] / cutcoeff[2];
3401  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_convexconcaveoverest_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
3402  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, consdata->lhs - cutcoeff[3]/cutcoeff[2], SCIPinfinity(scip),
3403  TRUE, FALSE /* modifiable */, TRUE /* removable */) );
3404  SCIP_CALL( SCIPaddVarsToRow(scip, *row, 2, SCIPexprtreeGetVars(consdata->f), coefs) );
3405  if( consdata->z != NULL )
3406  {
3407  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
3408  }
3409  }
3410  }
3411  }
3412  else
3413  {
3414  /* need underestimator */
3415  assert(violside == SCIP_SIDETYPE_RIGHT);
3416  assert(!SCIPisInfinity(scip, consdata->rhs));
3417 
3418  if( consdata->sepaconvexconcave.linearinx )
3419  {
3420  /* f is linear in x and strictly concave in y -> underestimator is polyhedral */
3421  SCIP_Real constant;
3422 
3423  SCIP_CALL( generateEstimatingHyperplane(scip, exprinterpreter, consdata->f, FALSE, xyref, &coefs[0], &coefs[1], &constant, &success) );
3424 
3425  if( success )
3426  {
3427  assert(SCIPisFinite(coefs[0]));
3428  assert(SCIPisFinite(coefs[1]));
3429  assert(SCIPisFinite(constant));
3430 
3431  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_underesthyperplanecut_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
3432  SCIP_CALL( SCIPcreateRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, 0, NULL, NULL, -SCIPinfinity(scip), consdata->rhs - constant, TRUE, FALSE, TRUE) );
3433 
3434  SCIP_CALL( SCIPaddVarsToRow(scip, *row, 2, SCIPexprtreeGetVars(consdata->f), coefs) );
3435  if( consdata->z != NULL )
3436  {
3437  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
3438  }
3439  }
3440  }
3441  else
3442  {
3443  /* f is strictly convex in x -> can compute underestimator by applying generateConvexConcaveUnderstimator */
3444  assert(!consdata->sepaconvexconcave.linearinx); /* generateConvexConcaveUnderestimator assumes that if f is strictly convex in x */
3445 
3446  SCIP_CALL( generateConvexConcaveUnderestimator(scip, exprinterpreter, consdata->f, consdata->sepaconvexconcave.f_yfixed, consdata->sepaconvexconcave.vred, xyref, cutcoeff, &dummy, &success) );
3447 
3448  if( success )
3449  {
3450  assert(SCIPisFinite(cutcoeff[0]));
3451  assert(SCIPisFinite(cutcoeff[1]));
3452  assert(SCIPisFinite(cutcoeff[2]));
3453  assert(SCIPisFinite(cutcoeff[3]));
3454  assert(SCIPisPositive(scip, cutcoeff[2])); /* assert gamma > 0 */
3455 
3456  /* construct row from cut coefficients (alpha, beta, gamma, delta)
3457  * coefficients are such that alpha * x + beta * y - gamma * f(x,y) <= delta,
3458  * i.e., alpha/gamma * x + beta/gamma * y - delta/gamma <= f(x,y)
3459  * -> alpha/gamma * x + beta/gamma * y - delta/gamma + c*z <= f(x,y) + c*z <= rhs
3460  */
3461 
3462  coefs[0] = cutcoeff[0] / cutcoeff[2];
3463  coefs[1] = cutcoeff[1] / cutcoeff[2];
3464  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_convexconcaveunderest_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
3465  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, -SCIPinfinity(scip), consdata->rhs + cutcoeff[3]/cutcoeff[2],
3466  TRUE, FALSE /* modifiable */, TRUE /* removable */) );
3467  SCIP_CALL( SCIPaddVarsToRow(scip, *row, 2, SCIPexprtreeGetVars(consdata->f), coefs) );
3468  if( consdata->z != NULL )
3469  {
3470  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
3471  }
3472  }
3473  }
3474  }
3475 
3476  return SCIP_OKAY;
3477 }
3478 
3479 
3480 /** computes an underestimating hyperplane for functions that are convex in x and y if the point to cut off lies on the boundary */
3481 static
3483  SCIP* scip, /**< SCIP data structure */
3484  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
3485  SCIP_EXPRTREE* f, /**< function f(x,y) */
3486  SCIP_Real xval, /**< current x value */
3487  SCIP_Real yval, /**< current y value */
3488  SCIP_Real xlb, /**< lower bound x */
3489  SCIP_Real xub, /**< upper bound x */
3490  SCIP_Real ylb, /**< lower bound y */
3491  SCIP_Real yub, /**< upper bound y */
3492  int min_max, /**< min=-1 max=1 */
3493  SCIP_Real cutcoeff[4], /**< returns the lifting coefficient*/
3494  SCIP_Real* convenvvalue, /**< value of the convex envelope at (xval,yval) */
3495  SCIP_Bool* success /**< buffer to indicate whether lifting was successful */
3496  )
3497 {
3498  int idx; /* indicates which variable is at the boundary */
3499 
3500  SCIP_Real mu;
3501  SCIP_Real fval;
3502  SCIP_Real grad[2];
3503 
3504  SCIP_Real x0y0[2];
3505  SCIP_Real f_lb;
3506  SCIP_Real f_ub;
3507  SCIP_Real grad_lb[2];
3508  SCIP_Real grad_ub[2];
3509 
3510  assert(SCIPisEQ(scip,xlb,xub) || SCIPisEQ(scip,ylb,yub));
3511  assert(success != NULL);
3512 
3513  *success = FALSE;
3514  idx = SCIPisEQ(scip, xlb, xub) ? 0 : 1;
3515 
3516  /* determine mu
3517  * if f is bivariate quadratic then f_x(xlb,yval) is linear in yval
3518  * thus the minimum is attained at the lower or the upper bound
3519  */
3520  x0y0[0] = xlb;
3521  x0y0[1] = ylb;
3522  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &f_lb, grad_lb) );
3523  if( !SCIPisFinite(grad_lb[idx]) )
3524  return SCIP_OKAY;
3525 
3526  x0y0[0] = xub;
3527  x0y0[1] = yub;
3528  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &f_ub, grad_ub) );
3529  if( !SCIPisFinite(grad_ub[idx]) )
3530  return SCIP_OKAY;
3531 
3532  /* if min_max=-1 choose min( grad_lb[idx], grad_ub[idx] )
3533  * if min_max= 1 choose max( grad_lb[idx], grad_ub[idx] )
3534  */
3535  if( min_max * (grad_lb[idx] - grad_ub[idx]) >= 0 )
3536  mu = grad_lb[idx];
3537  else
3538  mu = grad_ub[idx];
3539 
3540  /* determine coefficients for the hyperplane */
3541  x0y0[0] = xval;
3542  x0y0[1] = yval;
3543  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fval, grad) );
3544 
3545  if( idx == 0 )
3546  {
3547  if( !SCIPisFinite(grad[1]) || SCIPisInfinity(scip, REALABS(grad[1])) )
3548  return SCIP_OKAY;
3549  cutcoeff[0] = mu;
3550  cutcoeff[1] = grad[1];
3551  }
3552  else
3553  {
3554  assert(idx == 1);
3555  if( !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
3556  return SCIP_OKAY;
3557  cutcoeff[0] = grad[0];
3558  cutcoeff[1] = mu;
3559  }
3560  cutcoeff[2] = 1;
3561  cutcoeff[3] = -(fval-cutcoeff[0]*xval-cutcoeff[1]*yval);
3562  *convenvvalue = fval;
3563  *success = TRUE;
3564 
3565  return SCIP_OKAY;
3566 }
3567 
3568 /** generate a linear underestimator for f(x,y) with f(x,y) being convex in x and convex in y and the point to cut off lies on the boundary
3569  * generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that alpha * x + beta * y - delta <= gamma * f(x,y)
3570  */
3571 static
3573  SCIP* scip, /**< SCIP data structure */
3574  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
3575  SCIP_EXPRTREE* f, /**< function f(x,y) */
3576  SCIP_Real xyref[2], /**< reference values for x and y */
3577  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
3578  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
3579  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
3580  )
3581 {
3582  SCIP_VAR* x;
3583  SCIP_VAR* y;
3584  SCIP_Real xval;
3585  SCIP_Real xlb;
3586  SCIP_Real xub;
3587  SCIP_Real yval;
3588  SCIP_Real ylb;
3589  SCIP_Real yub;
3590 
3591  assert(scip != NULL);
3592  assert(exprinterpreter != NULL);
3593  assert(f != NULL);
3594  assert(convenvvalue != NULL);
3595  assert(success != NULL);
3596 
3597  x = SCIPexprtreeGetVars(f)[0];
3598  y = SCIPexprtreeGetVars(f)[1];
3599 
3600  xlb = SCIPvarGetLbLocal(x);
3601  xub = SCIPvarGetUbLocal(x);
3602 
3603  ylb = SCIPvarGetLbLocal(y);
3604  yub = SCIPvarGetUbLocal(y);
3605 
3606  *success = FALSE;
3607 
3608  SCIPdebugMsg(scip, "f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
3610  SCIPdebugMsgPrint(scip, "\n");
3611 
3612  xval = xyref[0];
3613  yval = xyref[1];
3614 
3615  SCIPdebugMsg(scip, "xval=%g in [%g,%g], yval=%g in [%g,%g]\n",xval,xlb,xub,yval,ylb,yub);
3616 
3617  if( SCIPisEQ(scip, ylb, yub) )
3618  {
3619  /* y is fixed, so function is now convex -> linearize in (xval, ylb) */
3620  SCIP_Real xy[2];
3621  SCIP_Real grad[2];
3622  SCIP_Real fval;
3623 
3624  xy[0] = xval;
3625  xy[1] = ylb;
3626  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xy, TRUE, &fval, grad) );
3627  if( !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
3628  return SCIP_OKAY;
3629 
3630  /* linearization is f(xval,ylb) + df/dx(xval,ylb) * (x - xval) <= f(x,y) */
3631 
3632  cutcoeff[0] = grad[0]; /* coefficient of x == gradient in x */
3633  cutcoeff[1] = 0.0; /* coefficient of y == 0 */
3634  cutcoeff[2] = 1.0; /* coefficient of f(x,y) == 1.0 */
3635  cutcoeff[3] = -(fval - grad[0] * xval); /* constant == -(f(xval,ylb) - grad * xval) */
3636 
3637  *success = TRUE;
3638  return SCIP_OKAY;
3639  }
3640 
3641  if( SCIPisEQ(scip, xlb, xub) )
3642  {
3643  /* x is fixed, so function is now convex -> linearize in (xlb, yval) */
3644  SCIP_Real xy[2];
3645  SCIP_Real grad[2];
3646  SCIP_Real fval;
3647 
3648  xy[0] = xlb;
3649  xy[1] = yval;
3650  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xy, TRUE, &fval, grad) );
3651  if( !SCIPisFinite(grad[1]) || SCIPisInfinity(scip, REALABS(grad[1])) )
3652  return SCIP_OKAY;
3653 
3654  /* linearization is f(xlb,yval) + df/dy(xlb,yval) * (y - yval) <= f(x,y) */
3655 
3656  cutcoeff[0] = 0.0; /* coefficient of x == 0.0 */
3657  cutcoeff[1] = grad[1]; /* coefficient of y == gradient in y */
3658  cutcoeff[2] = 1.0; /* coefficient of f(x,y) == 1.0 */
3659  cutcoeff[3] = -(fval - grad[1] * yval); /* constant == -(f(xlb,yval) - grad * yval) */
3660 
3661  *success = TRUE;
3662  return SCIP_OKAY;
3663  }
3664 
3665  /* check if the points lie on a boundary */
3666  if( SCIPisFeasEQ(scip, xlb, xval) )
3667  {
3668  /* apply a lifting and exploit that the function is convex in x and y
3669  * Idea: f(xlb,y) + mu (x-xlb) <= f(x,y)
3670  * determine mu with mu <= min_{x,y} ( f(x,y)-f(xlb,y) ) / (x-xlb)
3671  * f is convex in x: mu<= min_{y} f_x(xlb,y)
3672  *
3673  * mu (x-lb) + f_y(xlb,yval) * y <= f(x,y)
3674  */
3675  xval = xlb;
3676 
3677  SCIP_CALL( lifting(scip,exprinterpreter,f,xval,yval,xlb,xlb,ylb,yub,-1,cutcoeff,convenvvalue,success) );
3678 
3679  if( !*success )
3680  return SCIP_OKAY;
3681 
3682  SCIPdebugMsg(scip, "Boundary x=lb: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
3683  SCIPdebugMsg(scip, "convenvvalue = %g\n",*convenvvalue);
3684  SCIPdebugMsg(scip, "cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=%g,cutcoeff[3]=%g\n",
3685  cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
3686 
3687  return SCIP_OKAY;
3688  }
3689 
3690  if( SCIPisFeasEQ(scip, ylb, yval) )
3691  {
3692  yval = ylb;
3693 
3694  SCIP_CALL( lifting(scip,exprinterpreter,f,xval,yval,xlb,xub,ylb,ylb,-1,cutcoeff,convenvvalue,success) );
3695 
3696  if( !*success )
3697  return SCIP_OKAY;
3698 
3699  SCIPdebugMsg(scip, "Boundary y=lb: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
3700  SCIPdebugMsg(scip, "convenvvalue = %g\n",*convenvvalue);
3701  SCIPdebugMsg(scip, "cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=%g,cutcoeff[3]=%g\n",
3702  cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
3703 
3704  return SCIP_OKAY;
3705  }
3706 
3707  if( SCIPisFeasEQ(scip, xub, xval) )
3708  {
3709  /* apply a lifting and exploit that the function is convex in x and y
3710  * Idea: f(xlb,y) + mu (xub-x) <= f(x,y)
3711  * determine mu with mu <= min_{x,y} ( f(x,y)-f(xub,y) ) / (xub-x)
3712  * f is convex in x: -1 * mu >= min_{y} f_x(xub,y)
3713  *
3714  * mu (xub-x) + f_y(xub,yval) * y <= f(x,y)
3715  * -mu*x -mu*xub + f_y(xub,yval) * y <= f(x,y)
3716  */
3717  xval = xub;
3718 
3719  SCIP_CALL( lifting(scip,exprinterpreter,f,xval,yval,xub,xub,ylb,yub,1,cutcoeff,convenvvalue,success) );
3720 
3721  if( !*success )
3722  return SCIP_OKAY;
3723 
3724  SCIPdebugMsg(scip, "Boundary x=ub: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
3725  SCIPdebugMsg(scip, "convenvvalue = %g\n",*convenvvalue);
3726  SCIPdebugMsg(scip, "cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=%g,cutcoeff[3]=%g\n",
3727  cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
3728 
3729  return SCIP_OKAY;
3730  }
3731 
3732  if( SCIPisFeasEQ(scip, yub, yval) )
3733  {
3734  yval = yub;
3735 
3736  SCIP_CALL( lifting(scip,exprinterpreter,f,xval,yval,xlb,xub,yub,yub,1,cutcoeff,convenvvalue,success) );
3737 
3738  if( !*success )
3739  return SCIP_OKAY;
3740 
3741  SCIPdebugMsg(scip, "Boundary y=ub: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
3742  SCIPdebugMsg(scip, "convenvvalue = %g\n",*convenvvalue);
3743  SCIPdebugMsg(scip, "cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=%g,cutcoeff[3]=%g\n",
3744  cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
3745 
3746  return SCIP_OKAY;
3747  }
3748 
3749  /* (xval,yval) lies in the interior */
3750  SCIPerrorMessage("Tries to compute underestimator for a point at the boundary. But point is not on the boundary!\n");
3751  return SCIP_ERROR;
3752 }
3753 
3754 /** generates a linear underestimator for f(x,y) with f(x,y) being convex in x and convex in y but indefinite
3755  * This is for the case where the cone of the concave directions is (R_+ x R_-) union (R_\- x R_+).
3756  * We consider two cases:
3757  * a) the underestimating segmenent connects parallel facets
3758  * b) the underestimating segmenent connects orthogonal facets where
3759  * x=l_x, y=l_y and x=u_x, y=u_y
3760  * We ensure that the parallel facets are the horizontal with y=l_y and y=u_y
3761  * We compute the objective value of the two problems.
3762  * The smaller objective value corresponds to the convex envelope.
3763  * The supporting hyperplane is then constructed at the this point.
3764  */
3765 static
3767  SCIP* scip, /**< SCIP data structure */
3768  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
3769  SCIP_EXPRTREE* f, /**< function f(x,y) */
3770  SCIP_Real xyref[2], /**< reference values for x and y */
3771  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
3772  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
3773  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
3774  )
3775 {
3776  SCIP_VAR* x;
3777  SCIP_VAR* y;
3778  SCIP_Real xlb;
3779  SCIP_Real xub;
3780  SCIP_Real ylb;
3781  SCIP_Real yub;
3782  SCIP_Real xub_ylb[2];
3783  SCIP_Real xlb_yub[2];
3784  SCIP_Real grad_xub_ylb[2];
3785  SCIP_Real grad_xlb_yub[2];
3786  SCIP_Real fval_xub_ylb;
3787  SCIP_Real fval_xlb_yub;
3788 
3789  SCIP_Real all_cutcoeff[2][4];
3790  SCIP_Real all_convenvvalue[2];
3791  SCIP_Bool all_success[2];
3792 
3793  SCIP_Real lowest;
3794  int lowestidx;
3795  int i;
3796 
3797  SCIP_EXPRTREE* fswapped;
3798  SCIP_VAR* vars[2];
3799  SCIP_Bool swapped;
3800  SCIP_Real swap_buffer;
3801  SCIP_EXPR* subst[2];
3802 
3803  assert(scip != NULL);
3804  assert(exprinterpreter != NULL);
3805  assert(f != NULL);
3806  assert(convenvvalue != NULL);
3807  assert(success != NULL);
3808 
3809  x = SCIPexprtreeGetVars(f)[0];
3810  y = SCIPexprtreeGetVars(f)[1];
3811 
3812  xlb = SCIPvarGetLbLocal(x);
3813  xub = SCIPvarGetUbLocal(x);
3814 
3815  ylb = SCIPvarGetLbLocal(y);
3816  yub = SCIPvarGetUbLocal(y);
3817 
3818  *success = FALSE;
3819 
3820  xub_ylb[0] = xub;
3821  xub_ylb[1] = ylb;
3822  xlb_yub[0] = xlb;
3823  xlb_yub[1] = yub;
3824 
3825  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xub_ylb, TRUE, &fval_xub_ylb, grad_xub_ylb) );
3826  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xlb_yub, TRUE, &fval_xlb_yub, grad_xlb_yub) );
3827 
3828  if( !SCIPisFinite(fval_xub_ylb) || SCIPisInfinity(scip, REALABS(fval_xub_ylb)) || !SCIPisFinite(fval_xlb_yub) || SCIPisInfinity(scip, REALABS(fval_xlb_yub)) )
3829  {
3830  SCIPdebugMsg(scip, "skip 1-convex underestimator since function cannot be evaluated\n");
3831  return SCIP_OKAY;
3832  }
3833 
3834  if( !SCIPisFinite(grad_xub_ylb[0]) || !SCIPisFinite(grad_xlb_yub[1]) )
3835  {
3836  SCIPdebugMsg(scip, "skip 1-convex underestimator since function cannot be differentiated\n");
3837  return SCIP_OKAY;
3838  }
3839 
3840  SCIPdebugMsg(scip, "f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
3842  SCIPdebugMsgPrint(scip, "\n");
3843 
3844  SCIPdebugMsg(scip, "xval=%g in [%g,%g], yval=%g in [%g,%g]\n", xyref[0], xlb, xub, xyref[1], ylb, yub);
3845 
3846  /* assure (xub-xlb)*f_x(xub,ylb) - (yub-ylb)*f_y(xlb,yub) >= f(xub,ylb) - f(xlb,yub) */
3847  /* f_y(xlb,yub)*(ylb-yub)* + f(xlb,yub) >= f_x(xub,ylb)*(xub-xlb) + f(xub,ylb) */
3848  if( fval_xub_ylb-fval_xlb_yub <= (xub-xlb)*grad_xub_ylb[0]-(yub-ylb)*grad_xlb_yub[1] )
3849  {
3850  swapped = 0;
3851  }
3852  else
3853  {
3854  /* swap the variables */
3855  swapped = 1;
3856 
3857  vars[0] = SCIPexprtreeGetVars(f)[1];
3858  vars[1] = SCIPexprtreeGetVars(f)[0];
3859 
3860  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_VARIDX, 1) );
3861  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_VARIDX, 0) );
3862 
3863  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &fswapped, f) );
3864  SCIP_CALL( SCIPexprtreeSubstituteVars(fswapped, subst) );
3865  SCIP_CALL( SCIPexprtreeSetVars(fswapped, 2, vars) );
3866  SCIP_CALL( SCIPexprintCompile(exprinterpreter, fswapped) );
3867 
3868  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
3869  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
3870  }
3871 
3872  if( swapped == 0 )
3873  {
3874  /* assume (xval,yval) lie in A1 (lower left triangle) or A2 (upper right triangle) */
3875  SCIP_CALL( generateOrthogonal_lx_ly_Underestimator(scip, exprinterpreter, f, xyref, all_cutcoeff[0], &all_convenvvalue[0], &all_success[0]) );
3876  /* assume (xval,yval) lie in A3 */
3877  SCIP_CALL( generateUnderestimatorParallelYFacets(scip, exprinterpreter, f, xyref, all_cutcoeff[1], &all_convenvvalue[1], &all_success[1]) );
3878  }
3879  else
3880  {
3881  SCIP_Real xyref_[2];
3882 
3883  assert(swapped == 1);
3884 
3885  xyref_[0] = xyref[1];
3886  xyref_[1] = xyref[0];
3887 
3888  /* assume (xval,yval) lie in A1 (lower left triangle) or A2 (upper right triangle) */
3889  SCIP_CALL( generateOrthogonal_lx_ly_Underestimator(scip, exprinterpreter, fswapped, xyref_, all_cutcoeff[0], &all_convenvvalue[0], &all_success[0]) ); /*lint !e644*/
3890  /* assume (xval,yval) lie in A3 */
3891  SCIP_CALL( generateUnderestimatorParallelYFacets(scip, exprinterpreter, fswapped, xyref_, all_cutcoeff[1], &all_convenvvalue[1], &all_success[1]) );
3892 
3893  /* swap back */
3894  swap_buffer = all_cutcoeff[0][0];
3895  all_cutcoeff[0][0] = all_cutcoeff[0][1];
3896  all_cutcoeff[0][1] = swap_buffer;
3897 
3898  swap_buffer = all_cutcoeff[1][0];
3899  all_cutcoeff[1][0] = all_cutcoeff[1][1];
3900  all_cutcoeff[1][1] = swap_buffer;
3901 
3902  SCIP_CALL( SCIPexprtreeFree(&fswapped) );
3903  }
3904 
3905  /* Select the underestimator with the lowest convex envelope */
3906  SCIPdebugMsg(scip, "\n");
3907  SCIPdebugMsg(scip, "Triangulation: convenvvalue=%g\n", all_convenvvalue[0]);
3908  SCIPdebugMsg(scip, "Parallel Y: convenvvalue=%g\n", all_convenvvalue[1]);
3909 
3910  lowest = SCIPinfinity(scip);
3911  lowestidx = -1;
3912 
3913  if( all_success[0] && all_success[1] )
3914  {
3915  *success = TRUE;
3916  for( i = 0; i < 2; ++i )
3917  {
3918  assert(SCIPisFinite(all_cutcoeff[i][0]));
3919  assert(SCIPisFinite(all_cutcoeff[i][1]));
3920  assert(SCIPisFinite(all_cutcoeff[i][2]));
3921  assert(SCIPisFinite(all_cutcoeff[i][3]));
3922 
3923  if( all_convenvvalue[i] < lowest )
3924  {
3925  /* if all_convenvvalue[0] == all_convenvalue[1], take all_convenvvalue[0] */
3926  lowest = all_convenvvalue[i];
3927  lowestidx = i;
3928  }
3929  }
3930  assert(lowestidx >= 0);
3931 
3932  *convenvvalue = all_convenvvalue[lowestidx];
3933  cutcoeff[0] = all_cutcoeff[lowestidx][0];
3934  cutcoeff[1] = all_cutcoeff[lowestidx][1];
3935  cutcoeff[2] = all_cutcoeff[lowestidx][2];
3936  cutcoeff[3] = all_cutcoeff[lowestidx][3];
3937  assert(SCIPisPositive(scip, cutcoeff[2])); /* assert gamma > 0 */
3938  }
3939  else
3940  {
3941  *success = FALSE;
3942  }
3943 
3944  return SCIP_OKAY;
3945 }
3946 
3947 
3948 /** generates a linear underestimator for f(x,y) with f(x,y) being convex in x and convex in y but indefinite
3949  * This is for the case where the cone of the concave directions is (R_+ x R_+) union (R_- x R_-).
3950  * We consider two cases:
3951  * a) the underestimating segmenent connects parallel facets
3952  * b) the underestimating segmenent connects orthogonal facets where
3953  * x=l_x, y=u_y and x=u_x, y=l_y
3954  * We ensure that the parallel facets are the horizontal with y=l_y and y=u_y
3955  * We compute the objective value of the two problems.
3956  * The smaller objective value corresponds to the convex envelope.
3957  * The supporting hyperplane is then constructed at the this point.
3958  * Generates coefficients cutcoeff = (alpha, beta, gamma, delta), such that alpha * x + beta * y - delta <= gamma * f(x,y)
3959  */
3960 static
3962  SCIP* scip, /**< SCIP data structure */
3963  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
3964  SCIP_EXPRTREE* f, /**< function f(x,y) */
3965  SCIP_Real xyref[2], /**< reference values for x and y */
3966  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
3967  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
3968  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
3969  )
3970 {
3971  SCIP_VAR* x;
3972  SCIP_VAR* y;
3973  SCIP_Real xlb;
3974  SCIP_Real xub;
3975  SCIP_Real ylb;
3976  SCIP_Real yub;
3977  SCIP_Real xlb_ylb[2];
3978  SCIP_Real xub_yub[2];
3979  SCIP_Real grad_xlb_ylb[2];
3980  SCIP_Real grad_xub_yub[2];
3981  SCIP_Real fval_xlb_ylb;
3982  SCIP_Real fval_xub_yub;
3983 
3984  SCIP_Real all_cutcoeff[2][4];
3985  SCIP_Real all_convenvvalue[2];
3986  SCIP_Bool all_success[2];
3987 
3988  SCIP_Real lowest;
3989  int lowestidx;
3990  int i;
3991 
3992  SCIP_EXPRTREE* fswapped;
3993  SCIP_VAR* vars[2];
3994  SCIP_Bool swapped;
3995  SCIP_Real swap_buffer;
3996  SCIP_EXPR* subst[2];
3997 
3998  assert(scip != NULL);
3999  assert(exprinterpreter != NULL);
4000  assert(f != NULL);
4001  assert(convenvvalue != NULL);
4002  assert(success != NULL);
4003 
4004  x = SCIPexprtreeGetVars(f)[0];
4005  y = SCIPexprtreeGetVars(f)[1];
4006 
4007  xlb = SCIPvarGetLbLocal(x);
4008  xub = SCIPvarGetUbLocal(x);
4009 
4010  ylb = SCIPvarGetLbLocal(y);
4011  yub = SCIPvarGetUbLocal(y);
4012 
4013  *success = FALSE;
4014 
4015  SCIPdebugMsg(scip, "f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
4017  SCIPdebugMsgPrint(scip, "\n");
4018 
4019  xlb_ylb[0] = xlb;
4020  xlb_ylb[1] = ylb;
4021  xub_yub[0] = xub;
4022  xub_yub[1] = yub;
4023 
4024  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xlb_ylb, TRUE, &fval_xlb_ylb, grad_xlb_ylb) );
4025  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xub_yub, TRUE, &fval_xub_yub, grad_xub_yub) );
4026 
4027  if( !SCIPisFinite(fval_xlb_ylb) || SCIPisInfinity(scip, REALABS(fval_xlb_ylb)) || !SCIPisFinite(fval_xub_yub) || SCIPisInfinity(scip, REALABS(fval_xub_yub)) )
4028  {
4029  SCIPdebugMsg(scip, "skip 1-convex underestimator since function cannot be evaluated\n");
4030  return SCIP_OKAY;
4031  }
4032 
4033  if( !SCIPisFinite(grad_xlb_ylb[1]) || !SCIPisFinite(grad_xub_yub[0]) )
4034  {
4035  SCIPdebugMsg(scip, "skip 1-convex underestimator since function cannot be differentiated\n");
4036  return SCIP_OKAY;
4037  }
4038 
4039  SCIPdebugMsg(scip, "xval=%g in [%g,%g], yval=%g in [%g,%g]\n",xyref[0],xlb,xub,xyref[1],ylb,yub);
4040 
4041  /* assure f_y(xlb,ylb)*(yub-ylb)* + f(xlb,ylb) >= f_x(xub,yub)*(xlb-xub) + f(xub,yub) */
4042  if( SCIPisGE( scip, fval_xlb_ylb+(yub-ylb)*grad_xlb_ylb[1], fval_xub_yub+(xlb-xub)*grad_xub_yub[0] ) )
4043  {
4044  swapped = 0;
4045  }
4046  else
4047  {
4048  /* swap the variables */
4049  swapped = 1;
4050 
4051  vars[0] = SCIPexprtreeGetVars(f)[1];
4052  vars[1] = SCIPexprtreeGetVars(f)[0];
4053 
4054  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_VARIDX, 1) );
4055  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_VARIDX, 0) );
4056 
4057  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &fswapped, f) );
4058  SCIP_CALL( SCIPexprtreeSubstituteVars(fswapped, subst) );
4059  SCIP_CALL( SCIPexprtreeSetVars(fswapped, 2, vars) );
4060  SCIP_CALL( SCIPexprintCompile(exprinterpreter, fswapped) );
4061 
4062  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
4063  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
4064  }
4065 
4066  if( swapped == 0 )
4067  {
4068  /* assume (xval,yval) lie in A1 (lower left triangle) or A2 (upper right triangle) */
4069  SCIP_CALL( generateOrthogonal_lx_uy_Underestimator(scip, exprinterpreter, f, xyref, all_cutcoeff[0], &all_convenvvalue[0], &all_success[0]) );
4070  /* assume (xval,yval) lie in A3*/
4071  SCIP_CALL( generateUnderestimatorParallelYFacets(scip, exprinterpreter, f, xyref, all_cutcoeff[1], &all_convenvvalue[1], &all_success[1]) );
4072  }
4073  else
4074  {
4075  SCIP_Real xyref_[2];
4076 
4077  assert(swapped == 1);
4078 
4079  xyref_[0] = xyref[1];
4080  xyref_[1] = xyref[0];
4081  /* assume (xval,yval) lie in A1 (upper left triangle) or A2 (lower left triangle) */
4082  SCIP_CALL( generateOrthogonal_lx_uy_Underestimator(scip, exprinterpreter, fswapped, xyref_, all_cutcoeff[0], &all_convenvvalue[0], &all_success[0]) ); /*lint !e644*/
4083  /* assume (xval,yval) lie in A3 */
4084  SCIP_CALL( generateUnderestimatorParallelYFacets(scip, exprinterpreter, fswapped, xyref_, all_cutcoeff[1], &all_convenvvalue[1], &all_success[1]) );
4085 
4086  /* swap back */
4087  swap_buffer = all_cutcoeff[0][0];
4088  all_cutcoeff[0][0] = all_cutcoeff[0][1];
4089  all_cutcoeff[0][1] = swap_buffer;
4090 
4091  swap_buffer = all_cutcoeff[1][0];
4092  all_cutcoeff[1][0] = all_cutcoeff[1][1];
4093  all_cutcoeff[1][1] = swap_buffer;
4094 
4095  SCIP_CALL( SCIPexprtreeFree(&fswapped) );
4096  }
4097 
4098  /* select the underestimator with the lowest convex envelope */
4099  SCIPdebugMsg(scip, "\n");
4100  SCIPdebugMsg(scip, "Triangulation: convenvvalue=%g\n", all_convenvvalue[0]);
4101  SCIPdebugMsg(scip, "Parallel Y: convenvvalue=%g\n", all_convenvvalue[1]);
4102 
4103  lowest = SCIPinfinity(scip);
4104  lowestidx = -1;
4105 
4106  if( all_success[0] && all_success[1] )
4107  {
4108  *success = TRUE;
4109  for( i = 0; i < 2; ++i )
4110  {
4111  assert(SCIPisFinite(all_cutcoeff[i][0]));
4112  assert(SCIPisFinite(all_cutcoeff[i][1]));
4113  assert(SCIPisFinite(all_cutcoeff[i][2]));
4114  assert(SCIPisFinite(all_cutcoeff[i][3]));
4115 
4116  /* if all_convenvvalue[0]==all_convenvalue[1], take all_convenvvalue[0] */
4117  if( all_convenvvalue[i] < lowest )
4118  {
4119  lowest = all_convenvvalue[i];
4120  lowestidx = i;
4121  }
4122  }
4123  assert(lowestidx >= 0);
4124 
4125  *convenvvalue = all_convenvvalue[lowestidx];
4126  cutcoeff[0] = all_cutcoeff[lowestidx][0];
4127  cutcoeff[1] = all_cutcoeff[lowestidx][1];
4128  cutcoeff[2] = all_cutcoeff[lowestidx][2];
4129  cutcoeff[3] = all_cutcoeff[lowestidx][3];
4130  assert(SCIPisPositive(scip, cutcoeff[2])); /* assert gamma > 0 */
4131  }
4132  else
4133  {
4134  *success = FALSE;
4135  }
4136 
4137  return SCIP_OKAY;
4138 }
4139 
4140 
4141 /** generates a linear underestimator for f(x,y) with f(x,y) being convex in x and convex in y but indefinite
4142  * generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that alpha * x + beta * y - delta <= gamma * f(x,y)
4143  * 1. If the point lies on the boundary we apply the lifting technique.
4144  * 2. If the point lies in the interior we check the pattern of
4145  * the concave directions and compute the corresponding underestimators.
4146  */
4147 static
4149  SCIP* scip, /**< SCIP data structure */
4150  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
4151  SCIP_CONS* cons, /**< constraint */
4152  SCIP_Real* xyref, /**< reference values for x and y */
4153  SCIP_ROW** row /**< storage for cut */
4154  )
4155 {
4156  SCIP_CONSDATA* consdata;
4157  SCIP_EXPRTREE* f;
4158  SCIP_Real cutcoeff[4];
4159  SCIP_Bool success;
4160  SCIP_Real rhs;
4161  SCIP_Real convenvvalue;
4162 
4163  SCIP_VAR* x;
4164  SCIP_VAR* y;
4165  SCIP_Real xlb;
4166  SCIP_Real xub;
4167  SCIP_Real ylb;
4168  SCIP_Real yub;
4169  SCIP_Real xy_mid[2];
4170  SCIP_Real fval_mid;
4171  SCIP_Real hess[4];
4172 
4173  assert(scip != NULL);
4174  assert(cons != NULL);
4175  assert(row != NULL);
4176 
4177  consdata = SCIPconsGetData(cons);
4178  assert(consdata != NULL);
4179 
4180  assert(consdata->convextype == SCIP_BIVAR_1CONVEX_INDEFINITE);
4181 
4182  assert(!SCIPisInfinity(scip, consdata->rhs));
4183 
4184  f = consdata->f;
4185 
4186  x = SCIPexprtreeGetVars(f)[0];
4187  y = SCIPexprtreeGetVars(f)[1];
4188 
4189  xlb = SCIPvarGetLbLocal(x);
4190  xub = SCIPvarGetUbLocal(x);
4191 
4192  ylb = SCIPvarGetLbLocal(y);
4193  yub = SCIPvarGetUbLocal(y);
4194 
4195  xy_mid[0] = 0.5 * (xlb+xub);
4196  xy_mid[1] = 0.5 * (ylb+yub);
4197 
4198  /* assert that the bounds are finite */
4199  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) || SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub) )
4200  {
4201  SCIPdebugMsg(scip, "skip underestimate for 1-convex indefinite constraint <%s> since <%s> or <%s> is unbounded\n", SCIPconsGetName(cons), SCIPvarGetName(x), SCIPvarGetName(y));
4202  return SCIP_OKAY;
4203  }
4204 
4205  success = FALSE;
4206  cutcoeff[0] = SCIP_INVALID;
4207  cutcoeff[1] = SCIP_INVALID;
4208  cutcoeff[2] = SCIP_INVALID;
4209  cutcoeff[3] = SCIP_INVALID;
4210 
4211  /* (xval,yval) lie on a boundary */
4212  if( SCIPisFeasEQ(scip,xyref[0],xlb) || SCIPisFeasEQ(scip,xyref[0],xub) || SCIPisFeasEQ(scip,xyref[1],ylb) || SCIPisFeasEQ(scip,xyref[1],yub) )
4213  {
4214  SCIP_CALL( generate1ConvexIndefiniteUnderestimatorAtBoundary(scip, exprinterpreter, f, xyref, cutcoeff, &convenvvalue, &success) );
4215 
4216  if( !success )
4217  {
4218  /* maybe f is not differentiable on boundary, so move reference point into interior
4219  * we do this here w.r.t. both coordinates
4220  */
4221  perturb(&xyref[0], xlb, xub, 0.001);
4222  perturb(&xyref[1], ylb, yub, 0.001);
4223  }
4224  }
4225 
4226  if( !success )
4227  {
4228  /* xyref lies in the interior */
4229  /* check the pattern of the concave directions */
4230  SCIP_CALL( SCIPexprintHessianDense(exprinterpreter, f, xy_mid, TRUE, &fval_mid, hess) );
4231  assert(SCIPisFinite(hess[1]));
4232 
4233  if( hess[1] > 0.0 )
4234  {
4235  /* Pattern A: (R>=0 x R<=0) union (R<=0 x R>=0)*/
4236  SCIPdebugMsg(scip, "Pattern A\n");
4237  SCIP_CALL( generate1ConvexIndefiniteUnderestimatorInTheInteriorPatternA(scip, exprinterpreter, f, xyref, cutcoeff, &convenvvalue, &success) );
4238  }
4239  else
4240  {
4241  /* Pattern B: (R>=0 x R>=0) union (R<=0 x R <=0)*/
4242  SCIPdebugMsg(scip, "Pattern B\n");
4243  SCIP_CALL( generate1ConvexIndefiniteUnderestimatorInTheInteriorPatternB(scip, exprinterpreter, f, xyref, cutcoeff, &convenvvalue, &success) );
4244  }
4245  }
4246 
4247  if( !success )
4248  {
4249  /* bad luck */
4250  *row = NULL;
4251  return SCIP_OKAY;
4252  }
4253 
4254 
4255  /* construct row from cut coefficients (alpha, beta, gamma, delta)
4256  * coefficients are such that alpha * x + beta * y - gamma * f(x,y) <= delta,
4257  * i.e., alpha/gamma * x + beta/gamma * y - delta/gamma <= f(x,y)
4258  * -> alpha/gamma * x + beta/gamma * y - delta/gamma + c*z <= f(x,y) + c*z <= rhs
4259  */
4260 
4261  assert(cutcoeff[0] != SCIP_INVALID); /*lint !e777*/
4262  assert(cutcoeff[1] != SCIP_INVALID); /*lint !e777*/
4263  assert(cutcoeff[2] != SCIP_INVALID); /*lint !e777*/
4264  assert(cutcoeff[3] != SCIP_INVALID); /*lint !e777*/
4265  assert(SCIPisFinite(cutcoeff[0]));
4266  assert(SCIPisFinite(cutcoeff[1]));
4267  assert(SCIPisFinite(cutcoeff[2]));
4268  assert(SCIPisFinite(cutcoeff[3]));
4269  assert(SCIPisPositive(scip, cutcoeff[2])); /* assert gamma > 0 */
4270 
4271  if( SCIPisInfinity(scip, REALABS(cutcoeff[0]/cutcoeff[2])) ||
4272  SCIPisInfinity( scip, REALABS(cutcoeff[1]/cutcoeff[2])) ||
4273  SCIPisInfinity( scip, REALABS(cutcoeff[3]/cutcoeff[2])) )
4274  {
4275  *row = NULL;
4276  return SCIP_OKAY;
4277  }
4278 
4279  rhs = consdata->rhs + cutcoeff[3]/cutcoeff[2];
4280  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), "1ConvexUnderest", -SCIPinfinity(scip), rhs,
4281  TRUE, FALSE /* modifiable */, TRUE /* removable */) );
4282  SCIP_CALL( SCIPaddVarToRow(scip, *row, SCIPexprtreeGetVars(consdata->f)[0], cutcoeff[0] / cutcoeff[2]) );
4283  SCIP_CALL( SCIPaddVarToRow(scip, *row, SCIPexprtreeGetVars(consdata->f)[1], cutcoeff[1] / cutcoeff[2]) );
4284  if( consdata->z != NULL )
4285  {
4286  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
4287  }
4288 
4289  return SCIP_OKAY;
4290 }
4291 
4292 /** generates a cut */
4293 static
4295  SCIP* scip, /**< SCIP data structure */
4296  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
4297  SCIP_CONS* cons, /**< constraint */
4298  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
4299  SCIP_SIDETYPE violside, /**< for which side of constraint we want to generate a cut */
4300  SCIP_Real cutmaxrange, /**< bound on cut coef range */
4301  SCIP_ROW** row /**< storage for cut */
4302  )
4303 {
4304  SCIP_CONSDATA* consdata;
4305  SCIP_VAR* x;
4306  SCIP_VAR* y;
4307  SCIP_Real x0y0[2];
4308 
4309  assert(scip != NULL);
4310  assert(cons != NULL);
4311  assert(row != NULL);
4312 
4313  consdata = SCIPconsGetData(cons);
4314  assert(consdata != NULL);
4315 
4316  *row = NULL;
4317 
4318  x = SCIPexprtreeGetVars(consdata->f)[0];
4319  y = SCIPexprtreeGetVars(consdata->f)[1];
4320 
4321  x0y0[0] = SCIPgetSolVal(scip, sol, x);
4322  x0y0[1] = SCIPgetSolVal(scip, sol, y);
4323 
4324  assert(SCIPisFeasLE(scip, SCIPvarGetLbLocal(x), x0y0[0]));
4325  assert(SCIPisFeasGE(scip, SCIPvarGetUbLocal(x), x0y0[0]));
4326  assert(SCIPisFeasLE(scip, SCIPvarGetLbLocal(y), x0y0[1]));
4327  assert(SCIPisFeasGE(scip, SCIPvarGetUbLocal(y), x0y0[1]));
4328 
4329  /* project into box */
4330  x0y0[0] = MIN(MAX(SCIPvarGetLbLocal(x),x0y0[0]),SCIPvarGetUbLocal(x)); /*lint !e666*/
4331  x0y0[1] = MIN(MAX(SCIPvarGetLbLocal(y),x0y0[1]),SCIPvarGetUbLocal(y)); /*lint !e666*/
4332 
4333  SCIPdebugMsgPrint(scip, "\n");
4334  SCIPdebugMsg(scip, "generate cut for constraint <%s> with %s hand side violated by %g\n", SCIPconsGetName(cons), violside == SCIP_SIDETYPE_LEFT ? "left" : "right", violside == SCIP_SIDETYPE_LEFT ? consdata->lhsviol : consdata->rhsviol);
4335  SCIPdebugMsg(scip, "convextype = %d\n",consdata->convextype);
4336  SCIPdebugMsg(scip, "%s = %g with bounds [%g, %g], %s = %g with bounds [%g, %g]",
4339  if( consdata->z != NULL )
4340  SCIPdebugMsgPrint(scip, ", %s = %g with bounds [%g, %g]", SCIPvarGetName(consdata->z), SCIPgetSolVal(scip, sol, consdata->z), SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z));
4341  SCIPdebugMsgPrint(scip, "\n");
4342  SCIPdebugPrintCons(scip, cons, NULL);
4343  SCIPdebugMsgPrint(scip, "\n");
4344 
4345  switch( consdata->convextype )
4346  {
4347  case SCIP_BIVAR_ALLCONVEX:
4348  {
4349  if( violside == SCIP_SIDETYPE_RIGHT )
4350  {
4351  /* rhs is violated */
4352  SCIP_CALL( generateLinearizationCut(scip, exprinterpreter, cons, x0y0, FALSE, row) );
4353  }
4354  else
4355  {
4356  /* lhs is violated */
4357  SCIP_CALL( generateOverestimatingHyperplaneCut(scip, exprinterpreter, cons, x0y0, row) );
4358  }
4359 
4360  break;
4361  }
4362 
4364  {
4365  SCIP_CALL( generateConvexConcaveEstimator(scip, exprinterpreter, cons, x0y0, violside, row) );
4366  break;
4367  }
4368 
4370  {
4371  if( violside == SCIP_SIDETYPE_RIGHT )
4372  {
4373  /* rhs is violated */
4374  SCIP_CALL( generate1ConvexIndefiniteUnderestimator(scip, exprinterpreter, cons, x0y0, row) );
4375  }
4376  else
4377  {
4378  /* lhs is violated */
4379  SCIP_CALL( generateOverestimatingHyperplaneCut(scip, exprinterpreter, cons, x0y0, row) );
4380  }
4381  break;
4382  }
4383  default:
4384  {
4385  SCIPdebugMsg(scip, "cut generation for convexity type not implemented\n");
4386  }
4387  } /*lint !e788*/
4388 
4389  if( *row == NULL )
4390  return SCIP_OKAY;
4391 
4392  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *row, NULL) ) );
4393 
4394  /* check numerics */
4395  {
4396  SCIP_Real mincoef;
4397  SCIP_Real maxcoef;
4398 
4399  mincoef = SCIPgetRowMinCoef(scip, *row);
4400  maxcoef = SCIPgetRowMaxCoef(scip, *row);
4401 
4402  while( maxcoef / mincoef > cutmaxrange )
4403  {
4404  SCIP_VAR* var;
4405  SCIP_Real coef;
4406  SCIP_Real constant;
4407  int j;
4408 
4409  /* if range of coefficients is bad, find very small coefficients and make them zero */
4410  SCIPdebugMsg(scip, "cut coefficients for constraint <%s> have very large range: mincoef = %g maxcoef = %g\n", SCIPconsGetName(cons), mincoef, maxcoef);
4411 
4412  /* if minimal coefficient is given by z, then give up (probably the maximal coefficient is the problem) */
4413  if( mincoef == consdata->zcoef ) /*lint !e777*/
4414  {
4415  SCIPdebugMsg(scip, "could not eliminate small coefficient, since it comes from linear part\n");
4416  break;
4417  }
4418 
4419  constant = 0.0;
4420  for( j = 0; j < SCIProwGetNNonz(*row); ++j )
4421  {
4422  coef = SCIProwGetVals(*row)[j];
4423  if( !SCIPisEQ(scip, REALABS(coef), mincoef) )
4424  continue;
4425 
4426  var = SCIPcolGetVar(SCIProwGetCols(*row)[j]);
4427  assert(var != NULL);
4428 
4429  /* try to eliminate coefficient with minimal absolute value by weakening cut and try again */
4430  if( ((coef > 0.0 && violside == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && violside == SCIP_SIDETYPE_LEFT)) && !SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
4431  {
4432  SCIPdebugMsg(scip, "eliminate coefficient %g for <%s> = %g [%g, %g]\n", coef, SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
4433 
4434  constant += coef * (SCIProwIsLocal(*row) ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var));
4435  SCIP_CALL( SCIPaddVarToRow(scip, *row, var, -coef) );
4436  continue;
4437  }
4438 
4439  if( ((coef < 0.0 && violside == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && violside == SCIP_SIDETYPE_LEFT)) && !SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
4440  {
4441  SCIPdebugMsg(scip, "eliminate coefficient %g for <%s> = %g [%g, %g]\n", coef, SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
4442 
4443  constant += coef * (SCIProwIsLocal(*row) ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var));
4444  SCIP_CALL( SCIPaddVarToRow(scip, *row, var, -coef) );
4445  continue;
4446  }
4447 
4448  break;
4449  }
4450 
4451  if( j < SCIProwGetNNonz(*row) )
4452  {
4453  SCIPdebugMsg(scip, "could not eliminate small coefficient\n");
4454  SCIP_CALL( SCIPreleaseRow(scip, row) );
4455  break;
4456  }
4457 
4458  if( violside == SCIP_SIDETYPE_LEFT )
4459  {
4460  SCIP_CALL( SCIPchgRowLhs(scip, *row, SCIProwGetLhs(*row) - constant) );
4461  }
4462  else
4463  {
4464  SCIP_CALL( SCIPchgRowRhs(scip, *row, SCIProwGetRhs(*row) - constant) );
4465  }
4466 
4467  /* update min/max coefficient */
4468  mincoef = SCIPgetRowMinCoef(scip, *row);
4469  maxcoef = SCIPgetRowMaxCoef(scip, *row);
4470  };
4471 
4472  /* avoid numerically very bad cuts */
4473  if( maxcoef / mincoef > cutmaxrange )
4474  {
4475  SCIPdebugMsg(scip, "drop row for constraint <%s> because range of coefficients is too large: mincoef = %g, maxcoef = %g -> range = %g\n",
4476  SCIPconsGetName(cons), mincoef, maxcoef, maxcoef / mincoef);
4477  }
4478 
4479  if( *row != NULL &&
4480  ( (violside == SCIP_SIDETYPE_LEFT && SCIPisInfinity(scip, -SCIProwGetLhs(*row))) ||
4481  (violside == SCIP_SIDETYPE_RIGHT && SCIPisInfinity(scip, SCIProwGetRhs(*row)))) )
4482  {
4483  SCIPdebugMsg(scip, "drop row for constraint <%s> because of very large side: %g\n", SCIPconsGetName(cons), violside == SCIP_SIDETYPE_LEFT ? -SCIProwGetLhs(*row) : SCIProwGetRhs(*row));
4484  SCIP_CALL( SCIPreleaseRow(scip, row) );
4485  }
4486  }
4487 
4488  return SCIP_OKAY;
4489 }
4490 
4491 /** returns whether one side of a constraint function is convex w.r.t. local bounds
4492  * i.e., if side == RIGHT, then returns whether constraint function is convex w.r.t. local bounds
4493  * and if side == LEFT, then returns whether constraint function is concave w.r.t. local bounds
4494  */
4495 static
4497  SCIP* scip, /**< SCIP data structure */
4498  SCIP_CONS* cons, /**< constraint */
4499  SCIP_SIDETYPE side /**< constraint side to consider */
4500  )
4501 {
4502  SCIP_CONSDATA* consdata;
4503  SCIP_VAR** xy;
4504 
4505  consdata = SCIPconsGetData(cons);
4506  assert(consdata != NULL);
4507  assert(consdata->f != NULL);
4508 
4509  switch( consdata->convextype )
4510  {
4511  case SCIP_BIVAR_ALLCONVEX:
4512  /* always convex w.r.t. right hand side and concave w.r.t. left hand side */
4513  return side == SCIP_SIDETYPE_RIGHT;
4514 
4516  {
4517  /* always not convex w.r.t. left hand side */
4518  if( side == SCIP_SIDETYPE_LEFT )
4519  return FALSE;
4520 
4521  xy = SCIPexprtreeGetVars(consdata->f);
4522  assert(xy != NULL);
4523 
4524  /* convex w.r.t. right hand side if one of the variables is fixed */
4525  return SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])) ||
4526  SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1]));
4527  }
4528 
4530  {
4531  xy = SCIPexprtreeGetVars(consdata->f);
4532  assert(xy != NULL);
4533 
4534  /* convex w.r.t. right hand side if y is fixed and
4535  * convex w.r.t. left hand side if x is fixed */
4536  return (side == SCIP_SIDETYPE_RIGHT && SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1]))) ||
4537  (side == SCIP_SIDETYPE_LEFT && SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])));
4538  }
4539 
4540  default:
4541  return FALSE;
4542  } /*lint !e788*/
4543 }
4544 
4545 #ifdef SCIP_DEBUG
4546 static
4547 void printEstimator(
4548  SCIP* scip, /**< SCIP data structure */
4549  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
4550  SCIP_CONS* cons, /**< constraint */
4551  SCIP_SIDETYPE side, /**< violated side of constraint */
4552  SCIP_ROW* row /**< row */
4553  )
4554 {
4555  SCIP_CONSDATA* consdata;
4556  const char* varnames[2] = {"x", "y"};
4557  SCIP_VAR* x;
4558  SCIP_VAR* y;
4559  int i;
4560 
4561  assert(scip != NULL);
4562  assert(cons != NULL);
4563  assert(row != NULL);
4564 
4565  consdata = SCIPconsGetData(cons);
4566  assert(consdata != NULL);
4567  x = SCIPexprtreeGetVars(consdata->f)[0];
4568  y = SCIPexprtreeGetVars(consdata->f)[1];
4569 
4570  SCIPinfoMessage(scip, NULL, "splot [%g:%g] [%g:%g] ", SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x), SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y));
4571  SCIPexprtreePrint(consdata->f, SCIPgetMessagehdlr(scip), NULL, varnames, NULL);
4572  SCIPinfoMessage(scip, NULL, "%+g", side == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
4573 
4574  SCIPinfoMessage(scip, NULL, ", %g", SCIPisInfinity(scip, SCIProwGetRhs(row)) ? -SCIProwGetLhs(row) : -SCIProwGetRhs(row));
4575  for( i = 0; i < SCIProwGetNNonz(row); ++i )
4576  {
4577  SCIP_VAR* var;
4578 
4579  var = SCIPcolGetVar(SCIProwGetCols(row)[i]);
4580  if( var != x && var != y )
4581  continue;
4582 
4583  SCIPinfoMessage(scip, NULL, "%+g * %s", SCIProwGetVals(row)[i], var == x ? "x" : "y");
4584  }
4585 
4586  SCIPinfoMessage(scip, NULL, ", \"< echo '%g %g %g'\" with circles", SCIPgetSolVal(scip, sol, x), SCIPgetSolVal(scip, sol, y), consdata->activity);
4587 
4588  SCIPinfoMessage(scip, NULL, "\n");
4589 }
4590 #endif
4591 
4592 /** tries to separate solution or LP solution by a linear cut
4593  *
4594  * assumes that constraint violations have been computed
4595  */
4596 static
4598  SCIP* scip, /**< SCIP data structure */
4599  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
4600  SCIP_CONS** conss, /**< constraints */
4601  int nconss, /**< number of constraints */
4602  int nusefulconss, /**< number of constraints that seem to be useful */
4603  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
4604  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
4605  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
4606  SCIP_RESULT* result, /**< result of separation */
4607  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 */
4608  )
4609 {
4610  SCIP_CONSHDLRDATA* conshdlrdata;
4611  SCIP_CONSDATA* consdata;
4612  SCIP_SIDETYPE violside;
4613  SCIP_Real feasibility;
4614  SCIP_Real efficacy;
4615  int c;
4616  SCIP_ROW* row;
4617 
4618  assert(scip != NULL);
4619  assert(conshdlr != NULL);
4620  assert(conss != NULL || nconss == 0);
4621  assert(nusefulconss <= nconss);
4622  assert(result != NULL);
4623 
4624  *result = SCIP_FEASIBLE;
4625 
4626  if( bestefficacy != NULL )
4627  *bestefficacy = 0.0;
4628 
4629  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4630  assert(conshdlrdata != NULL);
4631 
4632  for( c = 0; c < nconss; ++c )
4633  {
4634  assert(conss != NULL);
4635  consdata = SCIPconsGetData(conss[c]);
4636  assert(consdata != NULL);
4637 
4638  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
4639  {
4640  /* we are not feasible anymore */
4641  if( *result == SCIP_FEASIBLE )
4642  *result = SCIP_DIDNOTFIND;
4643 
4644  violside = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT;
4645 
4646  /* generate cut */
4647  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], sol, violside, conshdlrdata->cutmaxrange, &row) );
4648  if( row == NULL ) /* failed to generate cut */
4649  continue;
4650 
4651  if( sol == NULL )
4652  feasibility = SCIPgetRowLPFeasibility(scip, row);
4653  else
4654  feasibility = SCIPgetRowSolFeasibility(scip, row, sol);
4655  efficacy = -feasibility;
4656 
4657  SCIPdebug( printEstimator(scip, sol, conss[c], violside, row) );
4658 
4659  /* if cut is strong enough or it's weak but we separate on a convex function and accept weak cuts there, add cut to SCIP */
4660  if( (SCIPisGT(scip, efficacy, minefficacy) ||
4661  (inenforcement && SCIPisGT(scip, efficacy, SCIPfeastol(scip)) && isConvexLocal(scip, conss[c], violside))) &&
4662  SCIPisCutApplicable(scip, row) )
4663  {
4664  SCIP_Bool infeasible;
4665 
4666  /* cut cuts off solution sufficiently */
4667  SCIP_CALL( SCIPaddRow(scip, row, FALSE, &infeasible) );
4668  if( infeasible )
4669  {
4670  SCIPdebugMsg(scip, "cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(conss[c]));
4671  *result = SCIP_CUTOFF;
4672  }
4673  else
4674  {
4675  SCIPdebugMsg(scip, "added cut with efficacy %g for constraint <%s> violated by %g\n", efficacy, SCIPconsGetName(conss[c]), MAX(consdata->lhsviol, consdata->rhsviol));
4676  *result = SCIP_SEPARATED;
4677  }
4678  if( bestefficacy != NULL && efficacy > *bestefficacy )
4679  *bestefficacy = efficacy;
4680 
4681  /* mark row as not removable from LP for current node, if in enforcement */
4682  if( inenforcement && !conshdlrdata->enfocutsremovable )
4683  SCIPmarkRowNotRemovableLocal(scip, row);
4684  }
4685  else
4686  {
4687  SCIPdebugMsg(scip, "abandon cut since efficacy %g is too small or not applicable\n", efficacy);
4688  }
4689 
4690  SCIP_CALL( SCIPreleaseRow(scip, &row) );
4691  }
4692 
4693  if( *result == SCIP_CUTOFF )
4694  break;
4695 
4696  /* enforce only useful constraints
4697  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
4698  */
4699  if( c >= nusefulconss && *result == SCIP_FEASIBLE )
4700  break;
4701  }
4702 
4703  return SCIP_OKAY;
4704 }
4705 
4706 /** processes the event that a new primal solution has been found adds linearizations of all-convex constraints to the cutpool */
4707 static
4708 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
4710  SCIP_CONSHDLR* conshdlr;
4711  SCIP_CONSHDLRDATA* conshdlrdata;
4712  SCIP_CONS** conss;
4713  int nconss;
4714  SCIP_CONSDATA* consdata;
4715  int c;
4716  SCIP_SOL* sol;
4717  SCIP_ROW* row;
4718  SCIP_Real x0y0[2];
4719 
4720  assert(scip != NULL);
4721  assert(event != NULL);
4722  assert(eventdata != NULL);
4723  assert(eventhdlr != NULL);
4724 
4725  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
4726 
4727  conshdlr = (SCIP_CONSHDLR*)eventdata;
4728 
4729  nconss = SCIPconshdlrGetNConss(conshdlr);
4730 
4731  if( nconss == 0 )
4732  return SCIP_OKAY;
4733 
4734  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4735  assert(conshdlrdata != NULL);
4736 
4737  sol = SCIPeventGetSol(event);
4738  assert(sol != NULL);
4739 
4740  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
4741  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
4742  * or are from the tree, but postprocessed via proposeFeasibleSolution
4743  */
4744  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
4745  return SCIP_OKAY;
4746 
4747  conss = SCIPconshdlrGetConss(conshdlr);
4748  assert(conss != NULL);
4749 
4750  SCIPdebugMsg(scip, "catched new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
4751 
4752  row = NULL;
4753 
4754  for( c = 0; c < nconss; ++c )
4755  {
4756  if( SCIPconsIsLocal(conss[c]) )
4757  continue;
4758 
4759  consdata = SCIPconsGetData(conss[c]);
4760  assert(consdata != NULL);
4761 
4762  if( consdata->convextype == SCIP_BIVAR_ALLCONVEX && !SCIPisInfinity(scip, consdata->rhs) )
4763  {
4764  SCIP_CALL( SCIPgetSolVals(scip, sol, 2, SCIPexprtreeGetVars(consdata->f), x0y0) );
4765  SCIP_CALL( generateLinearizationCut(scip, conshdlrdata->exprinterpreter, conss[c], x0y0, TRUE, &row) );
4766  }
4767  else
4768  continue;
4769 
4770  if( row == NULL )
4771  continue;
4772 
4773  assert(!SCIProwIsLocal(row));
4774 
4775  SCIP_CALL( SCIPaddPoolCut(scip, row) );
4776  SCIP_CALL( SCIPreleaseRow(scip, &row) );
4777  }
4778 
4779  return SCIP_OKAY;
4780 }
4781 
4782 /** registers unfixed variables in nonlinear terms of violated constraints as external branching candidates
4783  * We score the variables by their gap between the convex envelope and the bivariate function in the current (x,y).
4784  * This value is given by the constraint violation, since we assume that cuts have been generated which support
4785  * the convex envelope in the LP.
4786  */
4787 static
4789  SCIP* scip, /**< SCIP data structure */
4790  SCIP_CONS** conss, /**< constraints to check */
4791  int nconss, /**< number of constraints to check */
4792  int* nnotify /**< counter for number of notifications performed */
4793  )
4794 {
4795  SCIP_CONSDATA* consdata;
4796  SCIP_VAR** xy;
4797  int c;
4798 
4799  assert(scip != NULL);
4800  assert(conss != NULL || nconss == 0);
4801 
4802  *nnotify = 0;
4803 
4804  for( c = 0; c < nconss; ++c )
4805  {
4806  assert(conss != NULL);
4807  consdata = SCIPconsGetData(conss[c]);
4808  assert(consdata != NULL);
4809  SCIPdebugMsg(scip, "cons <%s> violation: %g %g\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);
4810 
4811  xy = SCIPexprtreeGetVars(consdata->f);
4812  assert(xy != NULL);
4813 
4814  /* @todo prefer binary before continuous, prefer unbounded before bounded */
4815 
4816  switch( consdata->convextype )
4817  {
4819  {
4820  /* need to branch on the variable in which function is concave (or linear) */
4821  if( !SCIPisFeasZero(scip, consdata->lhsviol) )
4822  {
4823  /* regarding left hand side, we are concave in x and convex in y, so branch on x, if not fixed */
4824  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])) )
4825  {
4826  SCIPdebugMsg(scip, "register variable x = <%s>[%g,%g] in convex-concave <%s> with violation %g %g\n", SCIPvarGetName(xy[0]), SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0]), SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);
4827  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[0], consdata->lhsviol, SCIP_INVALID) );
4828  ++*nnotify;
4829  }
4830  }
4831  if( !SCIPisFeasZero(scip, consdata->rhsviol) )
4832  {
4833  /* regarding right hand side, we are convex in x and concave in y, so branch on y, if not fixed */
4834  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1])) )
4835  {
4836  SCIPdebugMsg(scip, "register variable y = <%s>[%g,%g] in convex-concave <%s> with violation %g %g\n", SCIPvarGetName(xy[1]), SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1]), SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);
4837  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[1], consdata->lhsviol, SCIP_INVALID) );
4838  ++*nnotify;
4839  }
4840  }
4841  break;
4842  }
4843 
4845  {
4846  if( !SCIPisFeasZero(scip, consdata->rhsviol) )
4847  if( SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])) || SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1])) )
4848  break;
4849 
4850  /* register both variables, if not fixed */
4851  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])) )
4852  {
4853  SCIPdebugMsg(scip, "register variable x = <%s>[%g,%g] in 1-convex <%s> with violation %g %g\n", SCIPvarGetName(xy[0]), SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0]), SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);
4854  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[0], consdata->lhsviol, SCIP_INVALID) );
4855  ++*nnotify;
4856  }
4857 
4858  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1])) )
4859  {
4860  SCIPdebugMsg(scip, "register variable y = <%s>[%g,%g] in 1-convex <%s> with violation %g %g\n", SCIPvarGetName(xy[1]), SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1]), SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);
4861  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[1], consdata->lhsviol, SCIP_INVALID) );
4862  ++*nnotify;
4863  }
4864 
4865  break;
4866  }
4867 
4868  case SCIP_BIVAR_ALLCONVEX:
4869  {
4870  if( SCIPisFeasZero(scip, consdata->lhsviol) )
4871  continue;
4872  } /*lint -fallthrough*/
4873 
4874  default:
4875  {
4876  /* register both variables, if not fixed */
4877  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])) )
4878  {
4879  SCIPdebugMsg(scip, "register variable x = <%s>[%g,%g] in allconvex <%s> with violation %g %g\n", SCIPvarGetName(xy[0]), SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0]), SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);
4880  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[0], consdata->lhsviol, SCIP_INVALID) );
4881  ++*nnotify;
4882  }
4883 
4884  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1])) )
4885  {
4886  SCIPdebugMsg(scip, "register variable y = <%s>[%g,%g] in allconvex <%s> with violation %g %g\n", SCIPvarGetName(xy[1]), SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1]), SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);
4887  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[1], consdata->lhsviol, SCIP_INVALID) );
4888  ++*nnotify;
4889  }
4890  }
4891  } /*lint !e788*/
4892  }
4893 
4894  return SCIP_OKAY;
4895 }
4896 
4897 /** registers a nonlinear variable from a violated constraint as branching candidate that has a large absolute value in the relaxation */
4898 static
4900  SCIP* scip, /**< SCIP data structure */
4901  SCIP_CONS** conss, /**< constraints */
4902  int nconss, /**< number of constraints */
4903  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
4904  SCIP_VAR** brvar /**< buffer to store branching variable */
4905  )
4906 {
4907  SCIP_CONSDATA* consdata;
4908  SCIP_VAR* var;
4909  SCIP_Real val;
4910  SCIP_Real brvarval;
4911  int i;
4912  int c;
4913 
4914  assert(scip != NULL);
4915  assert(conss != NULL || nconss == 0);
4916 
4917  *brvar = NULL;
4918  brvarval = -1.0;
4919 
4920  for( c = 0; c < nconss; ++c )
4921  {
4922  assert(conss != NULL);
4923  consdata = SCIPconsGetData(conss[c]);
4924  assert(consdata != NULL);
4925  assert(consdata->f != NULL);
4926 
4927  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
4928  continue;
4929 
4930  for( i = 0; i < 2; ++i )
4931  {
4932  var = SCIPexprtreeGetVars(consdata->f)[i];
4933  /* do not propose fixed variables */
4934  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
4935  continue;
4936  val = SCIPgetSolVal(scip, sol, var);
4937  if( REALABS(val) > brvarval )
4938  {
4939  brvarval = REALABS(val);
4940  *brvar = var;
4941  }
4942  }
4943  }
4944 
4945  if( *brvar != NULL )
4946  {
4947  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
4948  }
4949 
4950  return SCIP_OKAY;
4951 }
4952 
4953 /** enforces violated bivariate constraints where both nonlinear variables can be assumed to be fixed
4954  * apply a bound change to the remaining linear variable, or recognizing infeasibility
4955  */
4956 static
4958  SCIP* scip, /**< SCIP data structure */
4959  SCIP_CONS** conss, /**< constraints */
4960  int nconss, /**< number of constraints */
4961  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
4962  SCIP_Bool* infeasible /**< whether we detected infeasibility */
4963  )
4964 {
4965  SCIP_CONSDATA* consdata;
4966  SCIP_INTERVAL nonlinact;
4967  SCIP_Real lhs;
4968  SCIP_Real rhs;
4969  int c;
4970 
4971  assert(scip != NULL);
4972  assert(conss != NULL || nconss == 0);
4973  assert(reduceddom != NULL);
4974  assert(infeasible != NULL);
4975 
4976  *reduceddom = FALSE;
4977  *infeasible = FALSE;
4978 
4979  for( c = 0; c < nconss; ++c )
4980  {
4981  assert(conss != NULL);
4982  consdata = SCIPconsGetData(conss[c]);
4983  assert(consdata != NULL);
4984 
4985  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
4986  continue;
4987 
4988  /* get activity for f(x,y) */
4989  SCIP_CALL( SCIPevalExprtreeLocalBounds(scip, consdata->f, SCIPinfinity(scip), &nonlinact) );
4990  assert(!SCIPintervalIsEmpty(SCIPinfinity(scip), nonlinact));
4991 
4992  /* if all variables are fixed (at least up to epsilson), then the activity of the nonlinear part should be bounded */
4993  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(nonlinact)));
4994  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(nonlinact)));
4995 
4996  if( !SCIPisInfinity(scip, -consdata->lhs) )
4997  lhs = consdata->lhs - SCIPintervalGetSup(nonlinact);
4998  else
4999  lhs = -SCIPinfinity(scip);
5000 
5001  if( !SCIPisInfinity(scip, consdata->rhs) )
5002  rhs = consdata->rhs - SCIPintervalGetInf(nonlinact);
5003  else
5004  rhs = SCIPinfinity(scip);
5005 
5006  if( consdata->z != NULL )
5007  {
5008  SCIP_Bool tightened;
5009  SCIP_Real coef;
5010 
5011  coef = consdata->zcoef;
5012  assert(!SCIPisZero(scip, coef));
5013 
5014  SCIPdebugMsg(scip, "Linear constraint with one variable: %g <= %g <%s> <= %g\n", lhs, coef, SCIPvarGetName(consdata->z), rhs);
5015 
5016  /* possibly correct lhs/rhs */
5017  if( coef >= 0.0 )
5018  {
5019  if( !SCIPisInfinity(scip, -lhs) )
5020  lhs /= coef;
5021  if( !SCIPisInfinity(scip, rhs) )
5022  rhs /= coef;
5023  }
5024  else
5025  {
5026  SCIP_Real h;
5027  h = rhs;
5028  if( !SCIPisInfinity(scip, -lhs) )
5029  rhs = lhs/coef;
5030  else
5031  rhs = SCIPinfinity(scip);
5032 
5033  if( !SCIPisInfinity(scip, h) )
5034  lhs = h/coef;
5035  else
5036  lhs = -SCIPinfinity(scip);
5037  }
5038  SCIPdebugMsg(scip, "Linear constraint is a bound: %g <= <%s> <= %g\n", lhs, SCIPvarGetName(consdata->z), rhs);
5039 
5040  if( !SCIPisInfinity(scip, -lhs) )
5041  {
5042  SCIP_CALL( SCIPtightenVarLb(scip, consdata->z, lhs, TRUE, infeasible, &tightened) );
5043  if( *infeasible )
5044  {
5045  SCIPdebugMsg(scip, "Lower bound leads to infeasibility.\n");
5046  return SCIP_OKAY;
5047  }
5048  if( tightened )
5049  {
5050  SCIPdebugMsg(scip, "Lower bound changed.\n");
5051  *reduceddom = TRUE;
5052  return SCIP_OKAY;
5053  }
5054  }
5055 
5056  if( !SCIPisInfinity(scip, rhs) )
5057  {
5058  SCIP_CALL( SCIPtightenVarUb(scip, consdata->z, rhs, TRUE, infeasible, &tightened) );
5059  if( *infeasible )
5060  {
5061  SCIPdebugMsg(scip, "Upper bound leads to infeasibility.\n");
5062  return SCIP_OKAY;
5063  }
5064  if( tightened )
5065  {
5066  SCIPdebugMsg(scip, "Upper bound changed.\n");
5067  *reduceddom = TRUE;
5068  return SCIP_OKAY;
5069  }
5070  }
5071  }
5072  else
5073  {
5074  /* no variable, thus check feasibility of lhs <= 0.0 <= rhs */
5075  *infeasible = SCIPisFeasGT(scip, lhs, 0.0) || SCIPisFeasLT(scip, rhs, 0.0);
5076  }
5077  }
5078 
5079  return SCIP_OKAY;
5080 }
5081 
5082 /** tightens bounds on a variable to given interval */
5083 static
5085  SCIP* scip, /**< SCIP data structure */
5086  SCIP_VAR* var, /**< variable which bounds to tighten */
5087  SCIP_INTERVAL bounds, /**< new bounds */
5088  SCIP_CONS* cons, /**< constraint that is propagated */
5089  SCIP_RESULT* result, /**< pointer where to update the result of the propagation call */
5090  int* nchgbds /**< buffer where to add the the number of changed bounds */
5091  )
5092 {
5093  SCIP_Bool infeas;
5094  SCIP_Bool tightened;
5095  SCIP_Real bnd;
5096 
5097  assert(scip != NULL);
5098  assert(var != NULL);
5099  assert(result != NULL);
5100  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
5101  assert(nchgbds != NULL);
5102 
5103  if( SCIPintervalIsPositiveInfinity(SCIPinfinity(scip), bounds) ||
5105  SCIPintervalIsEmpty(SCIPinfinity(scip), bounds) )
5106  {
5107  /* domain outside [-infty, +infty] or empty -> declare node infeasible */
5108  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for variable <%s>\n", cons != NULL ? SCIPconsGetName(cons) : "???", SCIPvarGetName(var)); /*lint !e585*/
5109  *result = SCIP_CUTOFF;
5110  return SCIP_OKAY;
5111  }
5112 
5114  {
5115  bnd = SCIPadjustedVarLb(scip, var, SCIPintervalGetInf(bounds));
5116  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
5117  if( infeas )
5118  {
5119  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for variable <%s>\n", cons != NULL ? SCIPconsGetName(cons) : "???", SCIPvarGetName(var)); /*lint !e585*/
5120  *result = SCIP_CUTOFF;
5121  return SCIP_OKAY;
5122  }
5123  if( tightened )
5124  {
5125  SCIPdebugMsg(scip, "tightened lower bound of variable <%s> in constraint <%s> to %g\n", SCIPvarGetName(var), cons != NULL ? SCIPconsGetName(cons) : "???", SCIPvarGetLbLocal(var)); /*lint !e585*/
5126  ++*nchgbds;
5127  *result = SCIP_REDUCEDDOM;
5128  }
5129  }
5130 
5132  {
5133  bnd = SCIPadjustedVarLb(scip, var, SCIPintervalGetSup(bounds));
5134  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
5135  if( infeas )
5136  {
5137  SCIPdebugMsg(scip, "found <%s> infeasible due to domain propagation for variable <%s>\n", cons != NULL ? SCIPconsGetName(cons) : "???", SCIPvarGetName(var)); /*lint !e585*/
5138  *result = SCIP_CUTOFF;
5139  return SCIP_OKAY;
5140  }
5141  if( tightened )
5142  {
5143  SCIPdebugMsg(scip, "tightened upper bound of variable <%s> in constraint <%s> to %g\n", SCIPvarGetName(var), cons != NULL ? SCIPconsGetName(cons) : "???", SCIPvarGetUbLocal(var)); /*lint !e585*/
5144  ++*nchgbds;
5145  *result = SCIP_REDUCEDDOM;
5146  }
5147  }
5148 
5149  return SCIP_OKAY;
5150 }
5151 
5152 /** tightens bounds of z in a single bivariate constraint
5153  * checks for redundancy and infeasibility
5154  */
5155 static
5157  SCIP* scip, /**< SCIP data structure */
5158  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5159  SCIP_CONS* cons, /**< constraint to process */
5160  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
5161  int* nchgbds, /**< buffer where to add the the number of changed bounds */
5162  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
5163  )
5164 {
5165  SCIP_CONSHDLRDATA* conshdlrdata;
5166  SCIP_CONSDATA* consdata;
5167  SCIP_INTERVAL consbounds; /* left and right side of constraint */
5168  SCIP_INTERVAL ftermactivity; /* activity of f(x,y) */
5169  SCIP_INTERVAL ztermactivity; /* activity of c*z */
5170  SCIP_INTERVAL consactivity; /* activity of f(x,y) + c*z */
5171  SCIP_INTERVAL tmp;
5172  SCIP_Bool cutoff;
5173 
5174  assert(scip != NULL);
5175  assert(cons != NULL);
5176  assert(result != NULL);
5177  assert(nchgbds != NULL);
5178 
5179  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5180  assert(conshdlrdata != NULL);
5181  assert(conshdlrdata->exprgraph != NULL);
5182 
5183  consdata = SCIPconsGetData(cons);
5184  assert(consdata != NULL);
5185  assert(consdata->exprgraphnode != NULL);
5186 
5187  *result = SCIP_DIDNOTRUN;
5188  *redundant = FALSE;
5189 
5190  /* extend interval by epsilon to avoid cutoff in forward propagation if constraint is only almost feasible */
5191  SCIPintervalSetBounds(&consbounds,
5192  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -consdata->lhs+SCIPepsilon(scip)), /*lint !e666*/
5193  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, consdata->rhs+SCIPepsilon(scip)) ); /*lint !e666*/
5194 
5195  /* get activity for f(x,y) */
5196  ftermactivity = SCIPexprgraphGetNodeBounds(consdata->exprgraphnode);
5197  assert(!SCIPintervalIsEmpty(SCIPinfinity(scip), ftermactivity) );
5198 
5199  /* get activity for c*z */
5200  if( consdata->z != NULL )
5201  {
5202  SCIPintervalSetBounds(&ztermactivity,
5203  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -MIN(SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z))), /*lint !e666*/
5204  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, MAX(SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z)))); /*lint !e666*/
5205  SCIPintervalMulScalar(INTERVALINFTY, &ztermactivity, ztermactivity, consdata->zcoef);
5206  }
5207  else
5208  {
5209  SCIPintervalSet(&ztermactivity, 0.0);
5210  }
5211 
5212  /* get activity for f(x,y)+c*z */
5213  SCIPintervalAdd(INTERVALINFTY, &consactivity, ftermactivity, ztermactivity);
5214 
5215  /* check redundancy */
5216  if( SCIPintervalIsSubsetEQ(INTERVALINFTY, consactivity, consbounds) )
5217  {
5218  SCIPdebugMsg(scip, "found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
5219  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
5220  *redundant = TRUE;
5221  return SCIP_OKAY;
5222  }
5223 
5224  /* check infeasibility */
5225  if( SCIPintervalAreDisjoint(consbounds, consactivity) )
5226  {
5227  SCIPdebugMsg(scip, "found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
5228  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
5229  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs)); /*lint !e666*/
5230  *result = SCIP_CUTOFF;
5231  return SCIP_OKAY;
5232  }
5233 
5234  /* try to tighten bounds on z */
5235  if( consdata->z != NULL )
5236  {
5237  *result = SCIP_DIDNOTFIND;
5238 
5239  /* compute ([lhs, rhs] - f([xlb,xub], [ylb,yub])) / zcoef */
5240  SCIPintervalSub(INTERVALINFTY, &tmp, consbounds, ftermactivity);
5241  SCIPintervalDivScalar(INTERVALINFTY, &tmp, tmp, consdata->zcoef);
5242 
5243  SCIP_CALL( propagateBoundsTightenVar(scip, consdata->z, tmp, cons, result, nchgbds) );
5244 
5245  if( *result == SCIP_CUTOFF )
5246  return SCIP_OKAY;
5247 
5248  if( *result == SCIP_SUCCESS )
5249  {
5250  SCIPintervalSetBounds(&ztermactivity,
5251  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -MIN(SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z))), /*lint !e666*/
5252  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, MAX(SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z)))); /*lint !e666*/
5253  SCIPintervalMulScalar(INTERVALINFTY, &ztermactivity, ztermactivity, consdata->zcoef);
5254  }
5255  }
5256 
5257  /* set bounds for exprgraphnode = [lhs,rhs] - c*z */
5258  SCIPintervalSub(INTERVALINFTY, &tmp, consbounds, ztermactivity);
5259  SCIPexprgraphTightenNodeBounds(conshdlrdata->exprgraph, consdata->exprgraphnode, tmp, 0.05, INTERVALINFTY, &cutoff);
5260  if( cutoff )
5261  {
5262  SCIPdebugMsg(scip, "found constraint <%s> infeasible%s\n", SCIPconsGetName(cons), SCIPinProbing(scip) ? " in probing" : "");
5263  *result = SCIP_CUTOFF;
5264  return SCIP_OKAY;
5265  }
5266 
5267  return SCIP_OKAY;
5268 }
5269 
5270 /** calls domain propagation for a set of constraints */
5271 static
5273  SCIP* scip, /**< SCIP data structure */
5274  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5275  SCIP_CONS** conss, /**< constraints to process */
5276  int nconss, /**< number of constraints */
5277  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
5278  int* nchgbds, /**< buffer where to add the the number of changed bounds */
5279  int* ndelconss /**< buffer where to increase if a constraint was deleted (locally) due to redundancy */
5280  )
5281 {
5282  SCIP_CONSHDLRDATA* conshdlrdata;
5283  SCIP_RESULT propresult;
5284  SCIP_Bool redundant;
5285  SCIP_Bool domainerror;
5286  int roundnr;
5287  SCIP_Bool success;
5288  int nvars;
5289  SCIP_VAR** vars;
5290  SCIP_EXPRGRAPHNODE** varnodes;
5291  SCIP_Bool cutoff;
5292  int c;
5293  int i;
5294 
5295  assert(scip != NULL);
5296  assert(conshdlr != NULL);
5297  assert(conss != NULL || nconss == 0);
5298  assert(result != NULL);
5299  assert(nchgbds != NULL);
5300  assert(ndelconss != NULL);
5301 
5302  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5303  assert(conshdlrdata != NULL);
5304  assert(conshdlrdata->exprgraph != NULL);
5305 
5306  *result = SCIP_DIDNOTRUN;
5307 
5308  if( nconss == 0 )
5309  return SCIP_OKAY;
5310 
5311  if( conshdlrdata->ispropagated )
5312  {
5313  /* check whether there was also no tightening in the bounds of the linear variables
5314  * @todo put this in processLinearVarEvent
5315  */
5316  for( c = 0; c < nconss; ++c )
5317  {
5318  assert(conss[c] != NULL); /*lint !e613*/
5319 
5320  if( SCIPconsIsMarkedPropagate(conss[c]) ) /*lint !e613*/
5321  break;
5322  }
5323  if( c == nconss )
5324  return SCIP_OKAY;
5325  }
5326 
5327  *result = SCIP_DIDNOTFIND;
5328 
5329  roundnr = 0;
5330  do
5331  {
5332  success = FALSE;
5333 
5334  SCIPdebugMsg(scip, "starting domain propagation round %d for %d constraints\n", roundnr, nconss);
5335 
5336  conshdlrdata->ispropagated = TRUE;
5337 
5338  /* propagate variable bounds through expression graph
5339  * roundnr == 0 clears remainings from a previous backward propagation
5340  * @todo could give FALSE if no linear variable in the constraints had been relaxed since last time
5341  */
5342  SCIP_CALL( SCIPexprgraphPropagateVarBounds(conshdlrdata->exprgraph, INTERVALINFTY, roundnr == 0, &domainerror) );
5343 
5344  if( domainerror )
5345  {
5346  SCIPdebugMsg(scip, "current bounds out of domain for some expression, do cutoff\n");
5347  *result = SCIP_CUTOFF;
5348  break;
5349  }
5350 
5351  /* check for redundancy and infeasibility of constraints
5352  * tighten bounds on linear variables
5353  * setup bounds for expression graph nodes */
5354  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
5355  {
5356  assert(conss != NULL);
5357  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
5358  continue;
5359 
5360  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
5361  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
5362  {
5363  *result = propresult;
5364  success = TRUE;
5365  }
5366  if( redundant )
5367  {
5368  SCIPdebugMsg(scip, "delete redundant constraint <%s> locally\n", SCIPconsGetName(conss[c]));
5369  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
5370  ++*ndelconss;
5371  }
5372 
5373  SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[c]) );
5374  }
5375  if( *result == SCIP_CUTOFF )
5376  break;
5377 
5378  /* propagate backward through expression graph */
5379  SCIPdebugMsg(scip, "start backward propagation in expression graph\n");
5380 
5381  /* compute bound tightenings for nonlinear variables */
5382  SCIPexprgraphPropagateNodeBounds(conshdlrdata->exprgraph, INTERVALINFTY, 0.05, &cutoff);
5383 
5384  if( cutoff )
5385  {
5386  SCIPdebugMsg(scip, "backward propagation found problem infeasible%s\n", SCIPinProbing(scip) ? " in probing" : "");
5387  *result = SCIP_CUTOFF;
5388  break;
5389  }
5390 
5391  /* put back new bounds into SCIP variables */
5392  nvars = SCIPexprgraphGetNVars(conshdlrdata->exprgraph);
5393  vars = (SCIP_VAR**)SCIPexprgraphGetVars(conshdlrdata->exprgraph);
5394  varnodes = SCIPexprgraphGetVarNodes(conshdlrdata->exprgraph);
5395  propresult = SCIP_DIDNOTFIND;
5396  for( i = 0; i < nvars && propresult != SCIP_CUTOFF; ++i )
5397  {
5398  SCIP_CALL( propagateBoundsTightenVar(scip, vars[i], SCIPexprgraphGetNodeBounds(varnodes[i]), NULL, &propresult, nchgbds) );
5399  }
5400  if( propresult != SCIP_DIDNOTFIND )
5401  {
5402  *result = propresult;
5403  success = TRUE;
5404  }
5405  }
5406  while( success && *result != SCIP_CUTOFF && ++roundnr < conshdlrdata->maxproprounds );
5407 
5408  return SCIP_OKAY;
5409 }
5410 
5411 
5412 /** Given a solution where every bivariate constraint is either feasible or can be made feasible by
5413  * moving the linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
5414  * The method assumes that this is always possible and that not all constraints are feasible already.
5415  */
5416 static
5418  SCIP* scip, /**< SCIP data structure */
5419  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5420  SCIP_CONS** conss, /**< constraints to process */
5421  int nconss, /**< number of constraints */
5422  SCIP_SOL* sol, /**< solution to process */
5423  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
5424  )
5425 {
5426  SCIP_CONSHDLRDATA* conshdlrdata;
5427  SCIP_CONSDATA* consdata;
5428  SCIP_SOL* newsol;
5429  SCIP_VAR* var;
5430  int c;
5431  SCIP_Real viol;
5432  SCIP_Real delta;
5433  SCIP_Real gap;
5434 
5435  assert(scip != NULL);
5436  assert(conshdlr != NULL);
5437  assert(conss != NULL || nconss == 0);
5438  assert(success != NULL);
5439 
5440  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5441  assert(conshdlrdata != NULL);
5442  assert(conshdlrdata->trysolheur != NULL);
5443 
5444  *success = FALSE;
5445 
5446  /* don't propose new solutions if not in presolve or solving */
5448  return SCIP_OKAY;
5449 
5450  if( sol != NULL )
5451  {
5452  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
5453  }
5454  else
5455  {
5456  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
5457  }
5458  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
5459 
5460  for( c = 0; c < nconss; ++c )
5461  {
5462  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
5463  assert(consdata != NULL);
5464 
5465  /* recompute violation of solution in case solution has changed
5466  * get absolution violation and sign */
5467  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
5468  {
5469  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
5470  viol = consdata->lhs - consdata->activity;
5471  }
5472  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5473  {
5474  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
5475  viol = consdata->rhs - consdata->activity;
5476  }
5477  else
5478  continue; /* constraint is satisfied */
5479 
5480  assert(viol != 0.0);
5481  if( consdata->mayincreasez &&
5482  ((viol > 0.0 && consdata->zcoef > 0.0) || (viol < 0.0 && consdata->zcoef < 0.0)) )
5483  {
5484  /* have variable where increasing makes the constraint less violated */
5485  var = consdata->z;
5486  /* compute how much we would like to increase var */
5487  delta = viol / consdata->zcoef;
5488  assert(delta > 0.0);
5489  /* if var has an upper bound, may need to reduce delta */
5490  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5491  {
5492  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
5493  delta = MIN(MAX(0.0, gap), delta);
5494  }
5495  if( SCIPisPositive(scip, delta) )
5496  {
5497  /* if variable is integral, round delta up so that it will still have an integer value */
5498  if( SCIPvarIsIntegral(var) )
5499  delta = SCIPceil(scip, delta);
5500 
5501  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
5502  SCIPdebugMsg(scip, "increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
5503 
5504  /* adjust constraint violation, if satisfied go on to next constraint */
5505  viol -= consdata->zcoef * delta;
5506  if( SCIPisZero(scip, viol) )
5507  continue;
5508  }
5509  }
5510 
5511  assert(viol != 0.0);
5512  if( consdata->maydecreasez &&
5513  ((viol > 0.0 && consdata->zcoef < 0.0) || (viol < 0.0 && consdata->zcoef > 0.0)) )
5514  {
5515  /* have variable where decreasing makes constraint less violated */
5516  var = consdata->z;
5517  /* compute how much we would like to decrease var */
5518  delta = viol / consdata->zcoef;
5519  assert(delta < 0.0);
5520  /* if var has a lower bound, may need to reduce delta */
5521  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
5522  {
5523  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
5524  delta = MAX(MIN(0.0, gap), delta);
5525  }
5526  if( SCIPisNegative(scip, delta) )
5527  {
5528  /* if variable is integral, round delta down so that it will still have an integer value */
5529  if( SCIPvarIsIntegral(var) )
5530  delta = SCIPfloor(scip, delta);
5531  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
5532  SCIPdebugMsg(scip, "increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
5533 
5534  /* adjust constraint violation, if satisfied go on to next constraint */
5535  viol -= consdata->zcoef * delta;
5536  if( SCIPisZero(scip, viol) )
5537  continue;
5538  }
5539  }
5540 
5541  /* still here... so maybe we could not make constraint feasible due to variable bounds
5542  * check if we are feasible w.r.t. (relative) feasibility tolerance */
5543  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
5544  /* if still violated, we give up */
5545  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5546  break;
5547 
5548  /* if objective value is not better than current upper bound, we give up */
5549  if( !SCIPisInfinity(scip, SCIPgetUpperbound(scip)) && !SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip)) )
5550  break;
5551  }
5552 
5553  /* if we have a solution that should satisfy all nonlinear constraints and has a better objective than the current upper bound,
5554  * then pass it to the trysol heuristic */
5555  if( c == nconss )
5556  {
5557  SCIPdebugMsg(scip, "pass solution with objective value %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
5558 
5559  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
5560  *success = TRUE;
5561  }
5562 
5563  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
5564 
5565  return SCIP_OKAY;
5566 }
5567 
5568 /** creates bivariate constraint from quadratic constraint data of the form
5569  * lhs <= xsqrcoef * x^2 + xlincoef * x + ysqrcoef * y^2 + ylincoef * y + bilincoef * x*y + zcoef * z <= rhs
5570  */
5571 static
5573  SCIP* scip, /**< SCIP data structure */
5574  SCIP_CONS* srccons, /**< source constraint to take attributes from */
5575  SCIP_CONS** cons, /**< pointer to store new constraint */
5576  const char* name, /**< name of new constraint */
5577  SCIP_VAR* x, /**< first nonlinear variable */
5578  SCIP_VAR* y, /**< second nonlinear variable */
5579  SCIP_VAR* z, /**< linear variable, can be NULL */
5580  SCIP_Real coefxx, /**< coefficient of x^2 */
5581  SCIP_Real coefx, /**< coefficient of x */
5582  SCIP_Real coefyy, /**< coefficient of y^2 */
5583  SCIP_Real coefy, /**< coefficient of y */
5584  SCIP_Real coefxy, /**< coefficient of x*y */
5585  SCIP_Real coefz, /**< coefficient of z */
5586  SCIP_Real lhs, /**< left-hand-side */
5587  SCIP_Real rhs /**< right-hand-side */
5588  )
5589 {
5590  SCIP_Real mult;
5591  SCIP_VAR* xy[2];
5592  SCIP_BIVAR_CONVEXITY convextype;
5593  SCIP_EXPR* e;
5594  SCIP_EXPRTREE* exprtree;
5595 
5596  SCIP_EXPR* children[2];
5597  SCIP_Real lincoefs[2];
5598  SCIP_QUADELEM quadelems[3];
5599  int nquadelems;
5600 
5601  assert(scip != NULL);
5602  assert(srccons != NULL);
5603  assert(cons != NULL);
5604  assert(name != NULL);
5605 
5606  assert(x != NULL);
5607  assert(y != NULL);
5608  assert(SCIPisLE(scip, lhs, rhs));
5609 
5610  if( coefxx >= 0 && coefyy >= 0 && 4 * coefxx * coefyy >= coefxy * coefxy )
5611  {
5612  /* quadratic term is convex in both variables (jointly) */
5613  mult = 1.0;
5614  convextype = SCIP_BIVAR_ALLCONVEX;
5615  }
5616  else if( coefxx <= 0 && coefyy <= 0 && 4 * coefxx * coefyy >= coefxy * coefxy )
5617  {
5618  /* quadratic term is concave in both variables (jointly) */
5619  mult = -1.0;
5620  convextype = SCIP_BIVAR_ALLCONVEX;
5621  }
5622  else if( coefxx > 0 && coefyy > 0 )
5623  {
5624  /* indefinite but 1-convex */
5625  assert(4 * coefxx * coefyy < coefxy * coefxy); /* assert indefiniteness */
5626  mult = 1.0;
5627  convextype = SCIP_BIVAR_1CONVEX_INDEFINITE;
5628  }
5629  else if( coefxx < 0 && coefyy < 0 )
5630  {
5631  /* indefinite but 1-convex */
5632  assert(4 * coefxx * coefyy < coefxy * coefxy); /* assert indefiniteness */
5633  mult = -1.0;
5634  convextype = SCIP_BIVAR_1CONVEX_INDEFINITE;
5635  }
5636  else
5637  {
5638  /* convex in one variable and concave in other variable */
5639  assert(coefxx * coefyy <= 0);
5640  convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5641  if( coefxx != 0.0 )
5642  {
5643  /* if coefxx < 0 (and thus coefyy >= 0) f(x,y) is concave in x and convex in y
5644  * but we need convex in x and concave in y, thus we multiply by -1
5645  */
5646  if( coefxx < 0.0 )
5647  mult = -1.0;
5648  else
5649  mult = 1.0;
5650  }
5651  else if( coefyy != 0.0 )
5652  {
5653  /* coefxx == 0.0 */
5654  /* if coefyy < 0 (and coefxx == 0) f(x,y) is concave in y and convex in x
5655  * otherwise we convert to convex in y and concave in x by multiplying by -1
5656  */
5657  if( coefyy < 0.0 )
5658  mult = 1.0;
5659  else
5660  mult = -1.0;
5661  }
5662  else
5663  {
5664  /* coefxx == 0.0 && coefyy == 0.0 && coefxy != 0.0 */
5665  assert(coefxy != 0.0);
5666  mult = 1.0;
5667  }
5668  }
5669 
5670  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &children[0], SCIP_EXPR_VARIDX, 0) );
5671  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &children[1], SCIP_EXPR_VARIDX, 1) );
5672 
5673  lincoefs[0] = coefx * mult;
5674  lincoefs[1] = coefy * mult;
5675 
5676  nquadelems = 0;
5677  if( coefxx != 0.0 )
5678  {
5679  quadelems[nquadelems].idx1 = 0;
5680  quadelems[nquadelems].idx2 = 0;
5681  quadelems[nquadelems].coef = coefxx * mult;
5682  ++nquadelems;
5683  }
5684  if( coefyy != 0.0 )
5685  {
5686  quadelems[nquadelems].idx1 = 1;
5687  quadelems[nquadelems].idx2 = 1;
5688  quadelems[nquadelems].coef = coefyy * mult;
5689  ++nquadelems;
5690  }
5691  if( coefxy != 0.0 )
5692  {
5693  quadelems[nquadelems].idx1 = 0;
5694  quadelems[nquadelems].idx2 = 1;
5695  quadelems[nquadelems].coef = coefxy * mult;
5696  ++nquadelems;
5697  }
5698 
5699  SCIP_CALL( SCIPexprCreateQuadratic(SCIPblkmem(scip), &e, 2, children, 0.0, (coefx != 0.0 || coefy != 0.0) ? lincoefs : NULL, nquadelems, quadelems) ); /*lint !e826*/
5700  assert(e != NULL);
5701 
5702  xy[0] = x;
5703  xy[1] = y;
5704 
5705  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtree, e, 2, 0, NULL) );
5706  SCIP_CALL( SCIPexprtreeSetVars(exprtree, 2, xy) );
5707 
5708  if( mult == -1.0 )
5709  {
5710  SCIP_Real tmp;
5711  tmp = lhs;
5712  lhs = -rhs;
5713  rhs = -tmp;
5714  coefz = -coefz;
5715  }
5716  else
5717  {
5718  assert(mult == 1.0);
5719  }
5720 
5721  SCIPdebugMsg(scip, "upgrading constraint <%s> to bivariate constraint <%s> with convexity type %d\n", SCIPconsGetName(srccons), name, convextype);
5722 
5723  SCIP_CALL( SCIPcreateConsBivariate(scip, cons, name,
5724  exprtree, convextype, z, coefz, lhs, rhs,
5725  SCIPconsIsInitial(srccons), SCIPconsIsSeparated(srccons), SCIPconsIsEnforced(srccons),
5726  SCIPconsIsChecked(srccons), SCIPconsIsPropagated(srccons), SCIPconsIsLocal(srccons),
5727  SCIPconsIsModifiable(srccons), SCIPconsIsDynamic(srccons), SCIPconsIsRemovable(srccons),
5728  SCIPconsIsStickingAtNode(srccons)) );
5729  SCIPdebugPrintCons(scip, *cons, NULL);
5730 
5731  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
5732 
5733  return SCIP_OKAY;
5734 }
5735 
5736 /** creates expression tree for monomial of the form coef * x^p * y^q with x >= 0 and y >= 0 and checks its convexity type */
5737 static
5739  SCIP* scip, /**< SCIP data structure */
5740  SCIP_VAR* x, /**< first variable */
5741  SCIP_VAR* y, /**< second variable */
5742  SCIP_Real coef, /**< monomial coefficient */
5743  SCIP_Real p, /**< exponent of x */
5744  SCIP_Real q, /**< exponent of y */
5745  SCIP_EXPRTREE** exprtree, /**< buffer to store pointer to expression tree */
5746  SCIP_Real* mult, /**< buffer to store multiplicator for generated expression tree */
5747  SCIP_BIVAR_CONVEXITY* convextype /**< buffer to store convexity type of expression tree */
5748  )
5749 {
5750  SCIP_Bool swapvars;
5751  SCIP_EXPR* children[2];
5752  int childidxs[2];
5753  SCIP_Real exponents[2];
5754  SCIP_VAR* vars[2];
5755  SCIP_EXPR* e;
5756  SCIP_EXPRDATA_MONOMIAL* monomial;
5757 
5758  assert(scip != NULL);
5759  assert(x != NULL);
5760  assert(y != NULL);
5761  assert(!SCIPisZero(scip, coef));
5762  assert(!SCIPisZero(scip, p));
5763  assert(!SCIPisZero(scip, q));
5764  assert(exprtree != NULL);
5765  assert(mult != NULL);
5766  assert(convextype != NULL);
5767 
5768  /* determine convexity type, and whether to negate monomial or swap variables */
5769  *mult = coef < 0.0 ? -1.0 : 1.0; /* for the check, assume that monomial has positive coefficient */
5770  swapvars = FALSE;
5771  *convextype = SCIP_BIVAR_UNKNOWN;
5772  if( (p + q >= 1.0 && ((p > 1.0 && q < 0.0) || (p < 0.0 && q > 1.0))) ||
5773  (p < 0.0 && q < 0.0) )
5774  {
5775  *convextype = SCIP_BIVAR_ALLCONVEX;
5776  }
5777  else if( (p > 1.0 && q > 1.0) || (p + q < 1.0 && ((p > 1.0 && q < 0.0) || (p < 0.0 && q > 1.0))) )
5778  {
5779  *convextype = SCIP_BIVAR_1CONVEX_INDEFINITE;
5780  }
5781  else if( (p < 0.0 || p > 1.0) && q > 0.0 && q < 1.0 )
5782  {
5783  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5784  }
5785  else if( (p < 0.0 || p > 1.0) && q == 1.0 )
5786  {
5787  *mult *= -1.0;
5788  swapvars = TRUE;
5789  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5790  }
5791  else if( (q < 0.0 || q > 1.0) && p > 0.0 && p <= 1.0 )
5792  {
5793  swapvars = TRUE;
5794  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5795  }
5796  else if( p > 0.0 && p < 1.0 && q > 0.0 && q < 1.0 && p + q > 1.0 )
5797  {
5798  *mult *= -1.0;
5799  *convextype = SCIP_BIVAR_1CONVEX_INDEFINITE;
5800  }
5801  else if( p == 1.0 && q > 0.0 && q < 1.0 )
5802  {
5803  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5804  }
5805  else if( q == 1.0 && p > 0.0 && p < 1.0 )
5806  {
5807  swapvars = TRUE;
5808  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5809  }
5810  else if( p == 1.0 && q == 1.0 )
5811  {
5812  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5813  }
5814  else if( p > 0.0 && p < 1.0 && q > 0.0 && q < 1.0 && p + q <= 1.0 )
5815  {
5816  *mult *= -1.0;
5817  *convextype = SCIP_BIVAR_ALLCONVEX;
5818  }
5819  assert(*convextype != SCIP_BIVAR_UNKNOWN); /* there should be no case where this can still happen */
5820 
5821  /* setup expression tree */
5822  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &children[0], SCIP_EXPR_VARIDX, 0) );
5823  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &children[1], SCIP_EXPR_VARIDX, 1) );
5824  childidxs[0] = 0;
5825  childidxs[1] = 1;
5826  if( !swapvars )
5827  {
5828  exponents[0] = p;
5829  exponents[1] = q;
5830  vars[0] = x;
5831  vars[1] = y;
5832  }
5833  else
5834  {
5835  exponents[0] = q;
5836  exponents[1] = p;
5837  vars[0] = y;
5838  vars[1] = x;
5839  }
5840  SCIP_CALL( SCIPexprCreateMonomial(SCIPblkmem(scip), &monomial, *mult*coef, 2, childidxs, exponents) );
5841 
5842  SCIP_CALL( SCIPexprCreatePolynomial(SCIPblkmem(scip), &e, 2, children, 1, &monomial, 0.0, FALSE) );
5843  assert( e != NULL );
5844 
5845  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), exprtree, e, 2, 0, NULL) );
5846  SCIP_CALL( SCIPexprtreeSetVars(*exprtree, 2, vars) );
5847 
5848  return SCIP_OKAY;
5849 }
5850 
5851 /** creates bivariate constraint from monomial of the form coef * x^p * y^q with x >= 0 and y >= 0
5852  * lhs <= coef * x^p * y^q + zcoef * z <= rhs
5853  */
5854 static
5856  SCIP* scip, /**< SCIP data structure */
5857  SCIP_CONS* srccons, /**< source constraint to take attributes from, or NULL */
5858  SCIP_CONS** cons, /**< pointer to store new constraint */
5859  const char* name, /**< name of new constraint */
5860  SCIP_VAR* x, /**< first nonlinear variable */
5861  SCIP_VAR* y, /**< second nonlinear variable */
5862  SCIP_VAR* z, /**< linear variable, can be NULL */
5863  SCIP_Real coef, /**< monomial coefficient */
5864  SCIP_Real p, /**< exponent of x */
5865  SCIP_Real q, /**< exponent of y */
5866  SCIP_Real zcoef, /**< coefficient of z */
5867  SCIP_Real lhs, /**< left-hand-side */
5868  SCIP_Real rhs /**< right-hand-side */
5869  )
5870 {
5871  SCIP_Real mult;
5872  SCIP_BIVAR_CONVEXITY convextype;
5873  SCIP_EXPRTREE* exprtree;
5874 
5875  assert(scip != NULL);
5876  assert(cons != NULL);
5877  assert(name != NULL);
5878 
5879  assert(x != NULL);
5880  assert(y != NULL);
5881  assert(!SCIPisZero(scip, coef));
5882  assert(!SCIPisZero(scip, p));
5883  assert(!SCIPisZero(scip, q));
5884  assert(SCIPisLE(scip, lhs, rhs));
5885 
5886  SCIP_CALL( createExprtreeFromMonomial(scip, x, y, coef, p, q, &exprtree, &mult, &convextype) );
5887 
5888  if( mult == -1.0 )
5889  {
5890  SCIP_Real tmp;
5891  tmp = lhs;
5892  lhs = -rhs;
5893  rhs = -tmp;
5894  zcoef = -zcoef;
5895  }
5896  else
5897  {
5898  assert(mult == 1.0);
5899  }
5900 
5901  SCIPdebugMsg(scip, "upgrading monomial %g<%s>^%g<%s>^%g from constraint <%s> to bivariate constraint with convexity type %d\n", /*lint !e585*/
5902  coef, SCIPvarGetName(x), p, SCIPvarGetName(y), q, srccons != NULL ? SCIPconsGetName(srccons) : "n/a", convextype); /*lint !e585*/
5903 
5904  if( srccons != NULL )
5905  {
5906  SCIP_CALL( SCIPcreateConsBivariate(scip, cons, name,
5907  exprtree, convextype, z, zcoef, lhs, rhs,
5908  SCIPconsIsInitial(srccons), SCIPconsIsSeparated(srccons), SCIPconsIsEnforced(srccons),
5909  SCIPconsIsChecked(srccons), SCIPconsIsPropagated(srccons), SCIPconsIsLocal(srccons),
5910  SCIPconsIsModifiable(srccons), SCIPconsIsDynamic(srccons), SCIPconsIsRemovable(srccons),
5911  SCIPconsIsStickingAtNode(srccons)) );
5912  }
5913  else
5914  {
5915  SCIP_CALL( SCIPcreateConsBivariate(scip, cons, name,
5916  exprtree, convextype, z, zcoef, lhs, rhs,
5917  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5918  }
5919  SCIPdebugPrintCons(scip, *cons, NULL);
5920 
5921  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
5922 
5923  return SCIP_OKAY;
5924 }
5925 
5926 /** helper function to enforce constraints */
5927 static
5929  SCIP* scip, /**< SCIP data structure */
5930  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5931  SCIP_CONS** conss, /**< constraints to process */
5932  int nconss, /**< number of constraints */
5933  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
5934  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
5935  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
5936  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
5937  )
5938 {
5939  SCIP_CONSHDLRDATA* conshdlrdata;
5940  SCIP_CONSDATA* consdata;
5941  SCIP_CONS* maxviolcons;
5942  SCIP_Real maxviol;
5943  SCIP_RESULT propresult;
5944  SCIP_RESULT separateresult;
5945  int dummy;
5946  int nnotify;
5947  SCIP_Real sepaefficacy;
5948  SCIP_Real minefficacy;
5949  SCIP_Real leastpossibleefficacy;
5950 
5951  assert(scip != NULL);
5952  assert(conshdlr != NULL);
5953  assert(conss != NULL || nconss == 0);
5954  assert(result != NULL);
5955 
5956  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5957  assert(conshdlrdata != NULL);
5958 
5959  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &maxviolcons) );
5960  if( maxviolcons == NULL )
5961  {
5962  *result = SCIP_FEASIBLE;
5963  return SCIP_OKAY;
5964  }
5965 
5966  *result = SCIP_INFEASIBLE;
5967 
5968  /* if we are above the 100'th enforcement round for this node, something is strange (maybe the relaxation does not
5969  * think that the cuts we add are violated, or we do ECP on a high-dimensional convex function) in this case, check
5970  * if some limit is hit or SCIP should stop for some other reason and terminate enforcement by creating a dummy node
5971  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an
5972  * assert in scip.c) the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may
5973  * be expensive we only increment nenforounds until 101 to avoid an overflow
5974  */
5975  if( conshdlrdata->lastenfonode == SCIPgetCurrentNode(scip) )
5976  {
5977  if( conshdlrdata->nenforounds > 100 )
5978  {
5979  if( SCIPisStopped(scip) )
5980  {
5981  SCIP_NODE* child;
5982 
5983  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
5984  *result = SCIP_BRANCHED;
5985 
5986  return SCIP_OKAY;
5987  }
5988  }
5989  else
5990  ++conshdlrdata->nenforounds;
5991  }
5992  else
5993  {
5994  conshdlrdata->lastenfonode = SCIPgetCurrentNode(scip);
5995  conshdlrdata->nenforounds = 0;
5996  }
5997 
5998  consdata = SCIPconsGetData(maxviolcons);
5999  assert(consdata != NULL);
6000  maxviol = consdata->lhsviol + consdata->rhsviol;
6001  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
6002 
6003  SCIPdebugMsg(scip, "enforcement with max violation %g in cons <%s> for %s solution\n", maxviol, SCIPconsGetName(maxviolcons),
6004  sol == NULL ? "LP" : "relaxation");
6005 
6006  /* run domain propagation */
6007  dummy = 0;
6008  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &dummy, &dummy) );
6009  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
6010  {
6011  *result = propresult;
6012  return SCIP_OKAY;
6013  }
6014 
6015  /* we would like a cut that is efficient enough that it is not redundant in the LP (>lpfeastol)
6016  * however, if the maximal violation is very small, also the best cut efficacy cannot be large
6017  * thus, in the latter case, we are also happy if the efficacy is at least, say, 75% of the maximal violation
6018  * but in any case we need an efficacy that is at least lpfeastol
6019  */
6020  minefficacy = MIN(0.75*maxviol, 2.0 * SCIPlpfeastol(scip)); /*lint !e666*/
6021  minefficacy = MAX(minefficacy, SCIPlpfeastol(scip)); /*lint !e666*/
6022  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, minefficacy, TRUE, &separateresult,
6023  &sepaefficacy) );
6024  if( separateresult == SCIP_SEPARATED || separateresult == SCIP_CUTOFF )
6025  {
6026  SCIPdebugMessage("separation succeeded (bestefficacy = %g, minefficacy = %g, cutoff = %d)\n", sepaefficacy,
6027  minefficacy, separateresult == SCIP_CUTOFF);
6028  *result = separateresult;
6029  return SCIP_OKAY;
6030  }
6031 
6032  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
6033  * -> collect variables for branching
6034  */
6035 
6036  SCIPdebugMsg(scip, "separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy,
6037  minefficacy, maxviol);
6038 
6039  /* find branching candidates */
6040  SCIP_CALL( registerBranchingVariables(scip, conss, nconss, &nnotify) );
6041 
6042  leastpossibleefficacy = SCIPlpfeastol(scip);
6043  if( nnotify == 0 && !solinfeasible && minefficacy > leastpossibleefficacy )
6044  {
6045  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
6046  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, leastpossibleefficacy, TRUE,
6047  &separateresult, &sepaefficacy) );
6048  if( separateresult == SCIP_SEPARATED || separateresult == SCIP_CUTOFF )
6049  {
6050  *result = separateresult;
6051  return SCIP_OKAY;
6052  }
6053  }
6054 
6055  if( nnotify == 0 && !solinfeasible )
6056  {
6057  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
6058  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
6059  */
6060  SCIP_VAR* brvar = NULL;
6061  SCIP_CALL( registerLargeRelaxValueVariableForBranching(scip, conss, nconss, sol, &brvar) );
6062  if( brvar == NULL )
6063  {
6064  /* fallback 3: all nonlinear variables in all violated constraints seem to be fixed -> treat as linear
6065  * constraint in one variable
6066  */
6067  SCIP_Bool reduceddom;
6068  SCIP_Bool infeasible;
6069 
6070  SCIP_CALL( enforceViolatedFixedNonlinear(scip, conss, nconss, &reduceddom, &infeasible) );
6071  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
6072  * when it enforces the new constraints again and nothing resolves the infeasiblity that we declare here thus,
6073  * we only add them if considered violated, and otherwise claim the solution is feasible (but print a warning)
6074  */
6075  if ( infeasible )
6076  *result = SCIP_CUTOFF;
6077  else if ( reduceddom )
6078  *result = SCIP_REDUCEDDOM;
6079  else
6080  {
6081  *result = SCIP_FEASIBLE;
6082  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
6083  }
6084  return SCIP_OKAY;
6085  }
6086  else
6087  {
6088  SCIPdebugMsg(scip, "Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
6089  SCIPvarGetName(brvar), SCIPgetSolVal(scip, sol, brvar));
6090  nnotify = 1;
6091  }
6092  }
6093 
6094  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
6095  return SCIP_OKAY;
6096 }
6097 
6098 /*
6099  * Callback methods of constraint handler
6100  */
6101 
6102 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
6103 static
6104 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyBivariate)
6105 { /*lint --e{715}*/
6106  assert(scip != NULL);
6107  assert(conshdlr != NULL);
6108  /* assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); */
6109 
6110  /* call inclusion method of constraint handler */
6112 
6113  *valid = TRUE;
6114 
6115  return SCIP_OKAY;
6116 }
6117 
6118 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
6119 static
6120 SCIP_DECL_CONSFREE(consFreeBivariate)
6121 { /*lint --e{715}*/
6122  SCIP_CONSHDLRDATA* conshdlrdata;
6123 
6124  assert(scip != NULL);
6125  assert(conshdlr != NULL);
6126 
6127  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6128  assert(conshdlrdata != NULL);
6129  assert(conshdlrdata->exprinterpreter != NULL);
6130  assert(conshdlrdata->exprgraph != NULL);
6131  assert(SCIPexprgraphGetNVars(conshdlrdata->exprgraph) == 0);
6132 
6133  /* free expression graph */
6134  SCIP_CALL( SCIPexprgraphFree(&conshdlrdata->exprgraph) );
6135 
6136  if( conshdlrdata->exprinterpreter != NULL )
6137  {
6138  SCIP_CALL( SCIPexprintFree(&conshdlrdata->exprinterpreter) );
6139  }
6140 
6141  SCIPfreeBlockMemory(scip, &conshdlrdata);
6142 
6143  return SCIP_OKAY;
6144 }
6145 
6146 /** initialization method of constraint handler (called after problem was transformed) */
6147 static
6148 SCIP_DECL_CONSINIT(consInitBivariate)
6149 { /*lint --e{715}*/
6150  SCIP_CONSHDLRDATA* conshdlrdata;
6151 
6152  assert(scip != NULL);
6153  assert(conshdlr != NULL);
6154 
6155  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6156  assert(conshdlrdata != NULL);
6157 
6158  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
6159  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
6160 
6161  return SCIP_OKAY;
6162 }
6163 
6164 /** deinitialization method of constraint handler (called before transformed problem is freed) */
6165 static
6166 SCIP_DECL_CONSEXIT(consExitBivariate)
6167 { /*lint --e{715}*/
6168  SCIP_CONSHDLRDATA* conshdlrdata;
6169 
6170  assert(scip != NULL);
6171  assert(conshdlr != NULL);
6172 
6173  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6174  assert(conshdlrdata != NULL);
6175 
6176  conshdlrdata->subnlpheur = NULL;
6177  conshdlrdata->trysolheur = NULL;
6178 
6179  return SCIP_OKAY;
6180 }
6181 
6182 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
6183 static
6184 SCIP_DECL_CONSINITPRE(consInitpreBivariate)
6185 { /*lint --e{715}*/
6186  SCIP_CONSDATA* consdata;
6187  int c;
6188 
6189  assert(scip != NULL);
6190  assert(conss != NULL || nconss == 0);
6191 
6192  for( c = 0; c < nconss; ++c )
6193  {
6194  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6195  assert(consdata != NULL);
6196 
6197  /* reset may{in,de}creasez to FALSE in case some values are still set from a previous solve round */
6198  consdata->mayincreasez = FALSE;
6199  consdata->maydecreasez = FALSE;
6200 
6201  /* mark the constraint to be propagated */
6202  SCIP_CALL( SCIPmarkConsPropagate(scip, conss[c]) ); /*lint !e613*/
6203  }
6204 
6205  return SCIP_OKAY;
6206 }
6207 
6208 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
6209 static
6210 SCIP_DECL_CONSEXITPRE(consExitpreBivariate)
6211 { /*lint --e{715}*/
6212  SCIP_CONSHDLRDATA* conshdlrdata;
6213  int c;
6214  SCIP_Bool changed;
6215  SCIP_Bool upgraded;
6216 #ifndef NDEBUG
6217  SCIP_CONSDATA* consdata;
6218 #endif
6219 
6220  assert(scip != NULL);
6221  assert(conss != NULL || nconss == 0);
6222 
6223  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6224  assert(conshdlrdata != NULL);
6225 
6226  if( !conshdlrdata->isremovedfixings )
6227  {
6228  SCIP_CALL( removeFixedNonlinearVariables(scip, conshdlr) );
6229  assert(conshdlrdata->isremovedfixings);
6230  /* @todo call expression graph simplifier? */
6231  }
6232 
6233  for( c = 0; c < nconss; ++c )
6234  {
6235  assert(conss != NULL); /* for flexelint */
6236  assert(conss[c] != NULL);
6237 
6238  /* make sure variable fixations have been resolved */
6239  SCIP_CALL( removeFixedVariables(scip, conshdlr, conss[c], &changed, &upgraded) );
6240  assert(!upgraded);
6241 
6242 #ifndef NDEBUG
6243  consdata = SCIPconsGetData(conss[c]);
6244  assert(consdata != NULL);
6245 
6246  assert(consdata->f != NULL);
6247  assert(SCIPexprtreeGetNVars(consdata->f) == 2);
6248  assert(consdata->z == NULL || SCIPvarIsActive(consdata->z) || SCIPvarGetStatus(consdata->z) == SCIP_VARSTATUS_MULTAGGR);
6249 #endif
6250 
6251  /* tell SCIP that we have something nonlinear */
6252  if( SCIPconsIsAdded(conss[c]) )
6253  SCIPenableNLP(scip);
6254  }
6255 
6256  return SCIP_OKAY;
6257 }
6258 
6259 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
6260 static
6261 SCIP_DECL_CONSINITSOL(consInitsolBivariate)
6262 { /*lint --e{715}*/
6263  SCIP_CONSHDLRDATA* conshdlrdata;
6264  SCIP_CONSDATA* consdata;
6265  int c;
6266 #ifdef TYPESTATISTICS
6267  int nconvextypeslhs[(int)SCIP_BIVAR_UNKNOWN+1];
6268  int nconvextypesrhs[(int)SCIP_BIVAR_UNKNOWN+1];
6269 #endif
6270 
6271  assert(scip != NULL);
6272  assert(conss != NULL || nconss == 0);
6273 
6274  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6275  assert(conshdlrdata != NULL);
6276 
6277 #ifdef TYPESTATISTICS
6278  BMSclearMemoryArray(nconvextypeslhs, (int)SCIP_BIVAR_UNKNOWN+1);
6279  BMSclearMemoryArray(nconvextypesrhs, (int)SCIP_BIVAR_UNKNOWN+1);
6280 #endif
6281 
6282  for( c = 0; c < nconss; ++c )
6283  {
6284  assert(conss[c] != NULL); /*lint !e613*/
6285 
6286  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6287  assert(consdata != NULL);
6288 
6289  /* check if linear variable can be rounded up or down without harming other constraints */
6290  if( consdata->z != NULL )
6291  {
6292  int poslock;
6293  int neglock;
6294 
6295  if( consdata->zcoef > 0.0 )
6296  {
6297  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
6298  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
6299  }
6300  else
6301  {
6302  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
6303  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
6304  }
6305 
6306  if( SCIPvarGetNLocksDown(consdata->z) - neglock == 0 )
6307  {
6308  /* for c*z + f(x,y) \in [lhs, rhs], we can decrease z without harming other constraints */
6309  consdata->maydecreasez = TRUE;
6310  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->z));
6311  }
6312 
6313  if( SCIPvarGetNLocksDown(consdata->z) - poslock == 0 )
6314  {
6315  /* for c*x + f(x,y) \in [lhs, rhs], we can increase x without harming other constraints */
6316  consdata->mayincreasez = TRUE;
6317  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->z));
6318  }
6319  }
6320 
6321  /* add nlrow respresentation to NLP, if NLP had been constructed */
6322  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) ) /*lint !e613*/
6323  {
6324  SCIP_NLROW* nlrow;
6325 
6326  SCIP_CALL( SCIPcreateNlRow(scip, &nlrow, SCIPconsGetName(conss[c]), 0.0,
6327  consdata->z != NULL ? 1 : 0, consdata->z != NULL ? &consdata->z : NULL, &consdata->zcoef,
6328  0, NULL, 0, NULL,
6329  consdata->f, consdata->lhs, consdata->rhs,
6330  consdata->convextype == SCIP_BIVAR_ALLCONVEX ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_UNKNOWN) ); /*lint !e826 !e613*/
6331 
6332  SCIP_CALL( SCIPaddNlRow(scip, nlrow) );
6333  SCIP_CALL( SCIPreleaseNlRow(scip, &nlrow) );
6334  }
6335 
6336  /* initialize data for cut generation */
6337  SCIP_CALL( initSepaData(scip, conshdlrdata->exprinterpreter, conss[c]) ); /*lint !e613*/
6338 
6339 #ifdef TYPESTATISTICS
6340  if( !SCIPisInfinity(scip, -consdata->lhs) )
6341  ++nconvextypeslhs[consdata->convextype];
6342  if( !SCIPisInfinity(scip, consdata->rhs) )
6343  ++nconvextypesrhs[consdata->convextype];
6344 #endif
6345  }
6346 
6347  conshdlrdata->newsoleventfilterpos = -1;
6348  if( nconss != 0 )
6349  {
6350  SCIP_EVENTHDLR* eventhdlr;
6351 
6352  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
6353  assert(eventhdlr != NULL);
6354 
6355  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
6356 
6357 #ifdef TYPESTATISTICS
6358  for( c = 0; c <= (int)SCIP_BIVAR_UNKNOWN; ++c )
6359  {
6360  const char* typename;
6361  switch( c )
6362  {
6363  case SCIP_BIVAR_ALLCONVEX:
6364  typename = "allconvex";
6365  break;
6367  typename = "1-convex";
6368  break;
6370  typename = "convex-concave";
6371  break;
6372  case SCIP_BIVAR_UNKNOWN:
6373  default:
6374  typename = "unknown";
6375  break;
6376  }
6377  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "%4d left and %4d right bivariate constraints of type [%s]\n", nconvextypeslhs[c], nconvextypesrhs[c], typename);
6378  }
6379 #endif
6380  }
6381 
6382  /* reset counter */
6383  conshdlrdata->lastenfonode = NULL;
6384  conshdlrdata->nenforounds = 0;
6385 
6386  return SCIP_OKAY;
6387 }
6388 
6389 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
6390 static
6391 SCIP_DECL_CONSEXITSOL(consExitsolBivariate)
6392 { /*lint --e{715}*/
6393  SCIP_CONSHDLRDATA* conshdlrdata;
6394  int c;
6395 
6396  assert(scip != NULL);
6397  assert(conss != NULL || nconss == 0);
6398 
6399  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6400  assert(conshdlrdata != NULL);
6401 
6402  if( conshdlrdata->newsoleventfilterpos >= 0 )
6403  {
6404  SCIP_EVENTHDLR* eventhdlr;
6405 
6406  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
6407  assert(eventhdlr != NULL);
6408 
6409  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
6410  conshdlrdata->newsoleventfilterpos = -1;
6411  }
6412 
6413  for( c = 0; c < nconss; ++c )
6414  {
6415  /* free data for cut generation */
6416  assert(conss[c] != NULL); /*lint !e613*/
6417 
6418  SCIP_CALL( freeSepaData(scip, conss[c]) ); /*lint !e613*/
6419  }
6420 
6421  return SCIP_OKAY;
6422 }
6423 
6424 /** frees specific constraint data */
6425 static
6426 SCIP_DECL_CONSDELETE(consDeleteBivariate)
6427 { /*lint --e{715}*/
6428 #ifndef NDEBUG
6429  SCIP_CONSHDLRDATA* conshdlrdata;
6430 #endif
6431 
6432  assert(scip != NULL);
6433  assert(cons != NULL);
6434  assert(consdata != NULL);
6435 
6436 #ifndef NDEBUG
6437  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6438  assert(conshdlrdata != NULL);
6439 #endif
6440 
6441  /* expression should have been removed from expression graph when constraint was deactivated */
6442  assert((*consdata)->exprgraphnode == NULL);
6443 
6444  if( (*consdata)->f != NULL )
6445  {
6446  SCIP_CALL( SCIPexprtreeFree(&(*consdata)->f) );
6447  }
6448 
6449  SCIPfreeBlockMemory(scip, consdata);
6450  *consdata = NULL;
6451 
6452  return SCIP_OKAY;
6453 }
6454 
6455 /** transforms constraint data into data belonging to the transformed problem */
6456 static
6457 SCIP_DECL_CONSTRANS(consTransBivariate)
6458 { /*lint --e{715}*/
6459  SCIP_CONSDATA* sourcedata;
6460  SCIP_CONSDATA* targetdata;
6461 
6462  SCIP_VAR* targetvars[2];
6463 
6464  sourcedata = SCIPconsGetData(sourcecons);
6465  assert(sourcedata != NULL);
6466 
6467  SCIP_CALL( SCIPduplicateBlockMemory(scip, &targetdata, sourcedata) );
6468  assert(targetdata->eventfilterpos == -1);
6469 
6470  assert(sourcedata->f != NULL);
6471  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &targetdata->f, sourcedata->f) );
6472  SCIP_CALL( SCIPgetTransformedVars(scip, 2, SCIPexprtreeGetVars(sourcedata->f), targetvars) );
6473  SCIP_CALL( SCIPexprtreeSetVars(targetdata->f, 2, targetvars) );
6474 
6475  if( sourcedata->z != NULL )
6476  {
6477  SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->z, &targetdata->z) );
6478  }
6479 
6480  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
6481  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
6482  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
6483  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
6484  SCIPconsIsStickingAtNode(sourcecons)) );
6485 
6486  return SCIP_OKAY;
6487 }
6488 
6489 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
6490 static
6491 SCIP_DECL_CONSINITLP(consInitlpBivariate)
6492 { /*lint --e{715}*/
6493  SCIP_CONSHDLRDATA* conshdlrdata;
6494  SCIP_CONSDATA* consdata;
6495  SCIP_ROW* row1;
6496  SCIP_ROW* row2;
6497  SCIP_Real xy[2];
6498  int c;
6499  int i;
6500  int ix;
6501  int iy;
6502  int nref;
6503  SCIP_Real lb[2];
6504  SCIP_Real ub[2];
6505  SCIP_Bool unbounded[2];
6506 
6507  assert(scip != NULL);
6508  assert(conshdlr != NULL);
6509  assert(conss != NULL || nconss == 0);
6510 
6511  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6512  assert(conshdlrdata != NULL);
6513 
6514  *infeasible = FALSE;
6515 
6516  nref = conshdlrdata->ninitlprefpoints;
6517 
6518  if( nref == 0 )
6519  {
6520  SCIPdebugMsg(scip, "skip LP initialization since ninitlprefpoints is 0\n");
6521  return SCIP_OKAY;
6522  }
6523 
6524  row1 = NULL;
6525  row2 = NULL;
6526 
6527  for( c = 0; c < nconss; ++c )
6528  {
6529  assert(conss[c] != NULL); /*lint !e613*/
6530 
6531  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6532  assert(consdata != NULL);
6533  assert(consdata->f != NULL);
6534 
6535  if( SCIPexprtreeGetInterpreterData(consdata->f) == NULL )
6536  {
6537  SCIP_CALL( SCIPexprintCompile(conshdlrdata->exprinterpreter, consdata->f) );
6538  }
6539 
6540  /* create a bounded rectangle in which we take reference points for initial cut generation
6541  * For a missing bound, we either reflect the other bound at 0.0 if finite and on the right side,
6542  * or double the other bound if on the same side but not 0.0, or set it to +/-1000.0.
6543  */
6544  for( i = 0; i < 2; ++i )
6545  {
6546  lb[i] = SCIPvarGetLbGlobal(SCIPexprtreeGetVars(consdata->f)[i]);
6547  ub[i] = SCIPvarGetUbGlobal(SCIPexprtreeGetVars(consdata->f)[i]);
6548 
6549  unbounded[i] = FALSE;
6550  if( SCIPisInfinity(scip, -lb[i]) )
6551  {
6552  unbounded[i] = TRUE;
6553  ub[i] = MIN(INITLPMAXVARVAL, ub[i]);
6554  if( SCIPisPositive(scip, ub[i]) )
6555  lb[i] = -ub[i];
6556  else if( SCIPisZero(scip, ub[i]) )
6557  lb[i] = -INITLPMAXVARVAL;
6558  else
6559  lb[i] = 2.0 * ub[i];
6560  }
6561  else if( SCIPisInfinity(scip, ub[i]) )
6562  {
6563  unbounded[i] = TRUE;
6564  assert(!SCIPisInfinity(scip, -lb[i]));
6565  lb[i] = MAX(-INITLPMAXVARVAL, lb[i]);
6566  if( SCIPisNegative(scip, lb[i]) )
6567  ub[i] = -lb[i];
6568  else if( SCIPisZero(scip, lb[i]) )
6569  ub[i] = INITLPMAXVARVAL;
6570  else
6571  ub[i] = 2.0 * lb[i];
6572  }
6573  }
6574 
6575  for( ix = 0; ix < nref; ++ix )
6576  {
6577  if( nref > 1 )
6578  xy[0] = lb[0] + ix * (ub[0] - lb[0]) / (nref - 1.0);
6579  else
6580  xy[0] = (lb[0] + ub[0]) / 2.0;
6581 
6582  for( iy = 0; iy < nref; ++iy )
6583  {
6584  if( nref > 1 )
6585  xy[1] = lb[1] + iy * (ub[1] - lb[1]) / (nref - 1.0);
6586  else
6587  xy[1] = (lb[1] + ub[1]) / 2.0;
6588 
6589  SCIPdebugMsg(scip, "cons <%s>: generate cuts for <%s> = %g [%g,%g], <%s> = %g [%g,%g]\n",
6590  SCIPconsGetName(conss[c]), /*lint !e613*/
6591  SCIPvarGetName(SCIPexprtreeGetVars(consdata->f)[0]), xy[0],
6593  SCIPvarGetName(SCIPexprtreeGetVars(consdata->f)[1]), xy[1],
6595  );
6596 
6597  /* try to generate one cut for each side */
6598  switch( consdata->convextype )
6599  {
6600  case SCIP_BIVAR_ALLCONVEX:
6601  {
6602  if( !SCIPisInfinity(scip, -consdata->lhs) && !unbounded[0] && !unbounded[1] && (ix == 0 || ix == nref-1) && (iy == 0 || iy == nref-1) )
6603  {
6604  /* lhs is finite and both variables are bounded, so can do overest. hyperplane
6605  * do this only for corner points, since we can get at most two cuts out of it
6606  * @todo generate only two cuts instead of four
6607  */
6608  SCIP_CALL( generateOverestimatingHyperplaneCut(scip, conshdlrdata->exprinterpreter, conss[c], xy, &row1) ); /*lint !e613*/
6609  }
6610  if( !SCIPisInfinity(scip, consdata->rhs) )
6611  {
6612  /* rhs is finite */
6613  SCIP_CALL( generateLinearizationCut(scip, conshdlrdata->exprinterpreter, conss[c], xy, TRUE, &row2) ); /*lint !e613*/
6614  }
6615  break;
6616  }
6617 
6619  {
6620  if( !SCIPisInfinity(scip, -consdata->lhs) && !unbounded[0])
6621  {
6622  /* lhs is finite and x is bounded */
6623  SCIP_CALL( generateConvexConcaveEstimator(scip, conshdlrdata->exprinterpreter, conss[c], xy, SCIP_SIDETYPE_LEFT, &row1) ); /*lint !e613*/
6624  }
6625  if( !SCIPisInfinity(scip, consdata->rhs) && !unbounded[1])
6626  {
6627  /* rhs is finite and y is bounded */
6628  SCIP_CALL( generateConvexConcaveEstimator(scip, conshdlrdata->exprinterpreter, conss[c], xy, SCIP_SIDETYPE_RIGHT, &row2) ); /*lint !e613*/
6629  }
6630  break;
6631  }
6632 
6634  {
6635  if( !SCIPisInfinity(scip, -consdata->lhs) && !unbounded[0] && !unbounded[1] && (ix == 0 || ix == nref-1) && (iy == 0 || iy == nref-1) )
6636  {
6637  /* lhs is finite and both variables are bounded
6638  * do this only for corner points, since we can get at most two cuts out of it
6639  * @todo generate only two cuts instead of four
6640  */
6641  SCIP_CALL( generateOverestimatingHyperplaneCut(scip, conshdlrdata->exprinterpreter, conss[c], xy, &row1) ); /*lint !e613*/
6642  }
6643  if( !SCIPisInfinity(scip, consdata->rhs) && !unbounded[0] && !unbounded[1] )
6644  { /* rhs is finite and both variables are bounded */
6645  SCIP_CALL( generate1ConvexIndefiniteUnderestimator(scip, conshdlrdata->exprinterpreter, conss[c], xy, &row2) ); /*lint !e613*/
6646  }
6647  break;
6648  }
6649 
6650  default:
6651  {
6652  SCIPwarningMessage(scip, "initlp for convexity type %d not implemented\n", consdata->convextype);
6653  }
6654  } /*lint !e788*/
6655 
6656  /* check numerics */
6657  if( row1 != NULL )
6658  {
6659  if( SCIPgetRowMaxCoef(scip, row1) / SCIPgetRowMinCoef(scip, row1) > conshdlrdata->cutmaxrange )
6660  {
6661  SCIPdebugMsg(scip, "drop row1 for constraint <%s> because range of coefficients is too large: mincoef = %g, maxcoef = %g -> range = %g\n",
6662  SCIPconsGetName(conss[c]), SCIPgetRowMinCoef(scip, row1), SCIPgetRowMaxCoef(scip, row1), SCIPgetRowMaxCoef(scip, row1) / SCIPgetRowMinCoef(scip, row1)); /*lint !e613*/
6663  }
6664  else if( SCIPisInfinity(scip, -SCIProwGetLhs(row1)) )
6665  {
6666  /* row1 should be a cut with finite lhs, but infinite rhs */
6667  assert(SCIPisInfinity(scip, SCIProwGetRhs(row1)));
6668  SCIPdebugMsg(scip, "drop row1 for constraint <%s> because of very large lhs: %g\n", SCIPconsGetName(conss[c]), SCIProwGetLhs(row1)); /*lint !e613*/
6669  }
6670  /* add row to LP */
6671  else
6672  {
6673  SCIP_CALL( SCIPaddRow(scip, row1, FALSE /* forcecut */, infeasible) );
6674  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row1, NULL) ) );
6675  }
6676  SCIP_CALL( SCIPreleaseRow(scip, &row1) );
6677  }
6678 
6679  if( row2 != NULL )
6680  {
6681  if( SCIPgetRowMaxCoef(scip, row2) / SCIPgetRowMinCoef(scip, row2) > conshdlrdata->cutmaxrange )
6682  {
6683  SCIPdebugMsg(scip, "drop row2 for constraint <%s> because range of coefficients is too large: mincoef = %g, maxcoef = %g -> range = %g\n",
6684  SCIPconsGetName(conss[c]), SCIPgetRowMinCoef(scip, row2), SCIPgetRowMaxCoef(scip, row2), SCIPgetRowMaxCoef(scip, row2) / SCIPgetRowMinCoef(scip, row2)); /*lint !e613*/
6685  }
6686  else if( SCIPisInfinity(scip, SCIProwGetRhs(row2)) )
6687  {
6688  /* row2 should be a cut with finite rhs, but infinite lhs */
6689  assert(SCIPisInfinity(scip, SCIProwGetRhs(row2)));
6690  SCIPdebugMsg(scip, "drop row2 for constraint <%s> because of very large rhs: %g\n", SCIPconsGetName(conss[c]), SCIProwGetLhs(row2)); /*lint !e613*/
6691  }
6692  /* add row to LP */
6693  else if( !(*infeasible) )
6694  {
6695  SCIP_CALL( SCIPaddRow(scip, row2, FALSE /* forcecut */, infeasible) );
6696  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row2, NULL) ) );
6697  }
6698  SCIP_CALL( SCIPreleaseRow(scip, &row2) );
6699  }
6700 
6701  if( *infeasible )
6702  return SCIP_OKAY;
6703  }
6704  }
6705  }
6706 
6707  return SCIP_OKAY;
6708 }
6709 
6710 /** separation method of constraint handler for LP solutions */
6711 static
6712 SCIP_DECL_CONSSEPALP(consSepalpBivariate)
6713 { /*lint --e{715}*/
6714  SCIP_CONS* maxviolcon;
6715 
6716  assert(scip != NULL);
6717  assert(conshdlr != NULL);
6718  assert(conss != NULL || nconss == 0);
6719  assert(result != NULL);
6720 
6721  *result = SCIP_DIDNOTFIND;
6722 
6723  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
6724  if( maxviolcon == NULL )
6725  return SCIP_OKAY;
6726 
6727  /* @todo add separation of convex (only?) constraints in nlp relaxation solution */
6728 
6729  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
6730 
6731  return SCIP_OKAY;
6732 }
6733 
6734 /** separation method of constraint handler for arbitrary primal solutions */
6735 static
6736 SCIP_DECL_CONSSEPASOL(consSepasolBivariate)
6737 { /*lint --e{715}*/
6738  SCIP_CONS* maxviolcon;
6739 
6740  assert(scip != NULL);
6741  assert(conshdlr != NULL);
6742  assert(conss != NULL || nconss == 0);
6743  assert(sol != NULL);
6744  assert(result != NULL);
6745 
6746  *result = SCIP_DIDNOTFIND;
6747 
6748  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &maxviolcon) );
6749  if( maxviolcon == NULL )
6750  return SCIP_OKAY;
6751 
6752  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
6753 
6754  return SCIP_OKAY;
6755 }
6756 
6757 /** constraint enforcing method of constraint handler for LP solutions */
6758 static
6759 SCIP_DECL_CONSENFOLP(consEnfolpBivariate)
6760 { /*lint --e{715}*/
6761  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
6762 
6763  return SCIP_OKAY;
6764 }
6765 
6766 /** constraint enforcing method of constraint handler for relaxation solutions */
6767 static
6768 SCIP_DECL_CONSENFORELAX(consEnforelaxBivariate)
6769 { /*lint --e{715}*/
6770  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
6771 
6772  return SCIP_OKAY;
6773 }
6774 
6775 
6776 /** constraint enforcing method of constraint handler for pseudo solutions */
6777 static
6778 SCIP_DECL_CONSENFOPS(consEnfopsBivariate)
6779 { /*lint --e{715}*/
6780  SCIP_CONS* maxviolcons;
6781  SCIP_CONSDATA* consdata;
6782  SCIP_RESULT propresult;
6783  SCIP_VAR* var;
6784  int nnotify;
6785  int dummy;
6786  int c;
6787  int i;
6788 
6789  assert(scip != NULL);
6790  assert(conss != NULL || nconss == 0);
6791 
6792  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcons) );
6793  if( maxviolcons == NULL )
6794  {
6795  *result = SCIP_FEASIBLE;
6796  return SCIP_OKAY;
6797  }
6798 
6799  *result = SCIP_INFEASIBLE;
6800 
6801  SCIPdebugMsg(scip, "enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcons));
6802 
6803  /* run domain propagation */
6804  dummy = 0;
6805  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &dummy, &dummy) );
6806  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
6807  {
6808  *result = propresult;
6809  return SCIP_OKAY;
6810  }
6811 
6812  /* we are not feasible and we cannot proof that the whole node is infeasible
6813  * -> collect all variables in violated constraints for branching
6814  */
6815 
6816  nnotify = 0;
6817  for( c = 0; c < nconss; ++c )
6818  {
6819  assert(conss != NULL);
6820  consdata = SCIPconsGetData(conss[c]);
6821  assert(consdata != NULL);
6822  assert(consdata->f != NULL);
6823 
6824  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6825  continue;
6826 
6827  /* if nonlinear variables are fixed, z should be propagated such that the constraint becomes feasible,
6828  * so there should be no branching on z necessary
6829  */
6830  if( consdata->z != NULL && !SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z)) )
6831  {
6832  SCIP_CALL( SCIPaddExternBranchCand(scip, consdata->z, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
6833  ++nnotify;
6834  }
6835 
6836  for( i = 0; i < 2; ++i )
6837  {
6838  var = SCIPexprtreeGetVars(consdata->f)[i];
6839  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6840  {
6841  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
6842  ++nnotify;
6843  }
6844  }
6845  }
6846 
6847  if( nnotify == 0 )
6848  {
6849  SCIPdebugMsg(scip, "All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
6850  *result = SCIP_SOLVELP;
6851  }
6852 
6853  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
6854  return SCIP_OKAY;
6855 }
6856 
6857 /** feasibility check method of constraint handler for integral solutions */
6858 static
6859 SCIP_DECL_CONSCHECK(consCheckBivariate)
6860 { /*lint --e{715}*/
6861  SCIP_CONSHDLRDATA* conshdlrdata;
6862  SCIP_CONSDATA* consdata;
6863  SCIP_Real maxviol;
6864  int c;
6865  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
6866 
6867  assert(scip != NULL);
6868  assert(conss != NULL || nconss == 0);
6869  assert(sol != NULL);
6870  assert(result != NULL);
6871 
6872  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6873  assert(conshdlrdata != NULL);
6874 
6875  *result = SCIP_FEASIBLE;
6876 
6877  maxviol = 0.0;
6878  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL);
6879  for( c = 0; c < nconss; ++c )
6880  {
6881  assert(conss != NULL);
6882  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
6883 
6884  consdata = SCIPconsGetData(conss[c]);
6885  assert(consdata != NULL);
6886 
6887  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6888  {
6889  *result = SCIP_INFEASIBLE;
6890  if( printreason )
6891  {
6892  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
6893  SCIPinfoMessage(scip, NULL, ";\n");
6894  {
6895  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g (scaled: %.15g)\n", consdata->lhs - consdata->activity, consdata->lhsviol);
6896  }
6897  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6898  {
6899  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g (scaled: %.15g)\n", consdata->activity - consdata->rhs, consdata->rhsviol);
6900  }
6901  }
6902 
6903  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
6904  return SCIP_OKAY;
6905 
6906  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
6907  maxviol = consdata->lhsviol + consdata->rhsviol;
6908 
6909  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
6910  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
6911  maypropfeasible = FALSE;
6912 
6913  if( maypropfeasible )
6914  {
6915  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
6916  {
6917  /* check if the linear variable may help to get the left hand side satisfied
6918  * if not, then we cannot get feasible */
6919  if( !(consdata->mayincreasez && consdata->zcoef > 0.0) && !(consdata->maydecreasez && consdata->zcoef < 0.0) )
6920  maypropfeasible = FALSE;
6921  }
6922  else
6923  {
6924  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
6925  /* check if the linear variable may help to get the right hand side satisfied
6926  * if not, then we cannot get feasible */
6927  if( !(consdata->mayincreasez && consdata->zcoef < 0.0) && !(consdata->maydecreasez && consdata->zcoef > 0.0) )
6928  maypropfeasible = FALSE;
6929  }
6930  }
6931  }
6932  }
6933 
6934  if( *result == SCIP_INFEASIBLE && maypropfeasible )
6935  {
6936  SCIP_Bool success;
6937 
6938  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
6939 
6940  /* do not pass solution to NLP heuristic if we made it feasible this way */
6941  if( success )
6942  return SCIP_OKAY;
6943  }
6944 
6945  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
6946  {
6947  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
6948  }
6949 
6950  return SCIP_OKAY;
6951 }
6952 
6953 /** domain propagation method of constraint handler */
6954 static
6955 SCIP_DECL_CONSPROP(consPropBivariate)
6956 { /*lint --e{715}*/
6957  int dummy;
6958 
6959  assert(scip != NULL);
6960  assert(conshdlr != NULL);
6961  assert(conss != NULL || nconss == 0);
6962  assert(result != NULL);
6963 
6964  dummy = 0;
6965  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, result, &dummy, &dummy) );
6966 
6967  return SCIP_OKAY;
6968 }
6969 
6970 /** presolving method of constraint handler */
6971 static
6972 SCIP_DECL_CONSPRESOL(consPresolBivariate)
6973 { /*lint --e{715}*/
6974 #ifndef NDEBUG
6975  SCIP_CONSDATA* consdata;
6976 #endif
6977  SCIP_CONSHDLRDATA* conshdlrdata;
6978  SCIP_RESULT propresult;
6979  SCIP_Bool havechange;
6980  SCIP_Bool upgraded;
6981  int c;
6982 
6983  assert(scip != NULL);
6984  assert(conshdlr != NULL);
6985  assert(conss != NULL || nconss == 0);
6986  assert(result != NULL);
6987 
6988  *result = SCIP_DIDNOTFIND;
6989 
6990  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6991  assert(conshdlrdata != NULL);
6992  assert(conshdlrdata->exprgraph != NULL);
6993 
6994  if( !conshdlrdata->isremovedfixings )
6995  {
6996  SCIP_CALL( removeFixedNonlinearVariables(scip, conshdlr) );
6997  assert(conshdlrdata->isremovedfixings);
6998  }
6999  /* @todo call expression graph simplifier, if not done yet? */
7000 
7001  for( c = 0; c < nconss; ++c )
7002  {
7003  assert(conss != NULL);
7004 
7005 #ifndef NDEBUG
7006  consdata = SCIPconsGetData(conss[c]);
7007  assert(consdata != NULL);
7008 #endif
7009 
7010  SCIPdebugMsg(scip, "process constraint <%s>\n", SCIPconsGetName(conss[c]));
7011  SCIPdebugPrintCons(scip, conss[c], NULL);
7012 
7013  havechange = FALSE;
7014 
7015  SCIP_CALL( removeFixedVariables(scip, conshdlr, conss[c], &havechange, &upgraded) );
7016  if( upgraded )
7017  {
7018  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
7019  ++*nupgdconss;
7020  continue;
7021  }
7022  if( havechange )
7023  {
7024  SCIPdebugMsg(scip, "removed fixed variables -> ");
7025  SCIPdebugPrintCons(scip, conss[c], NULL);
7026  }
7027  }
7028 
7029  /* run domain propagation */
7030  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, nchgbds, ndelconss) );
7031  switch( propresult )
7032  {
7033  case SCIP_REDUCEDDOM:
7034  *result = SCIP_SUCCESS;
7035  break;
7036  case SCIP_CUTOFF:
7037  SCIPdebugMsg(scip, "propagation says problem is infeasible in presolve\n");
7038  *result = SCIP_CUTOFF;
7039  return SCIP_OKAY;
7040  default:
7041  assert(propresult == SCIP_DIDNOTFIND || propresult == SCIP_DIDNOTRUN);
7042  } /*lint !e788*/
7043 
7044  return SCIP_OKAY;
7045 }
7046 
7047 /** variable rounding lock method of constraint handler */
7048 static
7049 SCIP_DECL_CONSLOCK(consLockBivariate)
7050 { /*lint --e{715}*/
7051  SCIP_CONSDATA* consdata;
7052 
7053  assert(scip != NULL);
7054  assert(cons != NULL);
7055 
7056  consdata = SCIPconsGetData(cons);
7057  assert(consdata != NULL);
7058 
7059  if( consdata->z != NULL )
7060  {
7061  if( consdata->zcoef > 0 )
7062  {
7063  if( !SCIPisInfinity(scip, -consdata->lhs) )
7064  {
7065  SCIP_CALL( SCIPaddVarLocks(scip, consdata->z, nlockspos, nlocksneg) );
7066  }
7067  if( !SCIPisInfinity(scip, consdata->rhs) )
7068  {
7069  SCIP_CALL( SCIPaddVarLocks(scip, consdata->z, nlocksneg, nlockspos) );
7070  }
7071  }
7072  else
7073  {
7074  if( !SCIPisInfinity(scip, -consdata->lhs) )
7075  {
7076  SCIP_CALL( SCIPaddVarLocks(scip, consdata->z, nlocksneg, nlockspos) );
7077  }
7078  if( !SCIPisInfinity(scip, consdata->rhs) )
7079  {
7080  SCIP_CALL( SCIPaddVarLocks(scip, consdata->z, nlockspos, nlocksneg) );
7081  }
7082  }
7083  }
7084 
7085  return SCIP_OKAY;
7086 }
7087 
7088 
7089 /** constraint activation notification method of constraint handler */
7090 static
7091 SCIP_DECL_CONSACTIVE(consActiveBivariate)
7092 { /*lint --e{715}*/
7093  SCIP_CONSHDLRDATA* conshdlrdata;
7094  SCIP_CONSDATA* consdata;
7095  SCIP_Bool exprtreeisnew;
7096 
7097  assert(scip != NULL);
7098  assert(conshdlr != NULL);
7099  assert(cons != NULL);
7100  assert(SCIPconsIsTransformed(cons));
7101 
7102  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7103  assert(conshdlrdata != NULL);
7104  assert(conshdlrdata->exprgraph != NULL);
7105 
7106  consdata = SCIPconsGetData(cons);
7107  assert(consdata != NULL);
7108  assert(consdata->exprgraphnode == NULL);
7109 
7110  SCIPdebugMsg(scip, "activate %scons <%s>\n", SCIPconsIsTransformed(cons) ? "transformed " : "", SCIPconsGetName(cons));
7111 
7112  /* add exprtree to expression graph */
7113  SCIP_CALL( SCIPexprgraphAddExprtreeSum(conshdlrdata->exprgraph, 1, &consdata->f, NULL, &consdata->exprgraphnode, &exprtreeisnew) );
7114  assert(consdata->exprgraphnode != NULL);
7115 
7116  /* mark that variables in constraint should not be multiaggregated (bad for bound tightening and branching) */
7117  if( SCIPvarIsActive(SCIPexprtreeGetVars(consdata->f)[0]) )
7118  {
7119  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPexprtreeGetVars(consdata->f)[0]) );
7120  }
7121  if( SCIPvarIsActive(SCIPexprtreeGetVars(consdata->f)[1]) )
7122  {
7123  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPexprtreeGetVars(consdata->f)[1]) );
7124  }
7125  if( consdata->z != NULL && SCIPvarIsActive(consdata->z) )
7126  {
7127  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->z) );
7128  }
7129 
7130  return SCIP_OKAY;
7131 }
7132 
7133 /** constraint deactivation notification method of constraint handler */
7134 static
7135 SCIP_DECL_CONSDEACTIVE(consDeactiveBivariate)
7136 { /*lint --e{715}*/
7137  SCIP_CONSHDLRDATA* conshdlrdata;
7138  SCIP_CONSDATA* consdata;
7139 
7140  assert(scip != NULL);
7141  assert(conshdlr != NULL);
7142  assert(cons != NULL);
7143  assert(SCIPconsIsTransformed(cons));
7144 
7145  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7146  assert(conshdlrdata != NULL);
7147  assert(conshdlrdata->exprgraph != NULL);
7148 
7149  consdata = SCIPconsGetData(cons);
7150  assert(consdata != NULL);
7151  assert(consdata->exprgraphnode != NULL);
7152 
7153  SCIPdebugMsg(scip, "deactivate %scons <%s>\n", SCIPconsIsTransformed(cons) ? "transformed " : "", SCIPconsGetName(cons));
7154 
7155  SCIP_CALL( SCIPexprgraphReleaseNode(conshdlrdata->exprgraph, &consdata->exprgraphnode) );
7156 
7157  return SCIP_OKAY;
7158 }
7159 
7160 /** constraint enabling notification method of constraint handler */
7161 static
7162 SCIP_DECL_CONSENABLE(consEnableBivariate)
7163 { /*lint --e{715}*/
7164  SCIP_CONSHDLRDATA* conshdlrdata;
7165  SCIP_CONSDATA* consdata;
7166 
7167  assert(scip != NULL);
7168  assert(conshdlr != NULL);
7169  assert(cons != NULL);
7170  assert(SCIPconsIsTransformed(cons));
7171  assert(SCIPconsIsActive(cons));
7172 
7173  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7174  assert(conshdlrdata != NULL);
7175  assert(conshdlrdata->exprgraph != NULL);
7176 
7177  consdata = SCIPconsGetData(cons);
7178  assert(consdata != NULL);
7179  assert(consdata->exprgraphnode != NULL);
7180 
7181  SCIPdebugMsg(scip, "enable %scons <%s>\n", SCIPconsIsTransformed(cons) ? "transformed " : "", SCIPconsGetName(cons));
7182 
7183  /* enable node of expression in expression graph */
7184  SCIPexprgraphEnableNode(conshdlrdata->exprgraph, consdata->exprgraphnode);
7185 
7186  /* enable event catching for linear variables */
7187  SCIP_CALL( catchLinearVarEvents(scip, cons) );
7188 
7189  return SCIP_OKAY;
7190 }
7191 
7192 /** constraint disabling notification method of constraint handler */
7193 static
7194 SCIP_DECL_CONSDISABLE(consDisableBivariate)
7195 { /*lint --e{715}*/
7196  SCIP_CONSHDLRDATA* conshdlrdata;
7197  SCIP_CONSDATA* consdata;
7198 
7199  assert(scip != NULL);
7200  assert(conshdlr != NULL);
7201  assert(cons != NULL);
7202  assert(SCIPconsIsTransformed(cons));
7203 
7204  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7205  assert(conshdlrdata != NULL);
7206  assert(conshdlrdata->exprgraph != NULL);
7207 
7208  consdata = SCIPconsGetData(cons);
7209  assert(consdata != NULL);
7210  assert(consdata->exprgraphnode != NULL);
7211 
7212  SCIPdebugMsg(scip, "disable %scons <%s>\n", SCIPconsIsTransformed(cons) ? "transformed " : "", SCIPconsGetName(cons));
7213 
7214  /* disable node of expression in expression graph */
7215  SCIPexprgraphDisableNode(conshdlrdata->exprgraph, consdata->exprgraphnode);
7216 
7217  SCIP_CALL( dropLinearVarEvents(scip, cons) );
7218 
7219  return SCIP_OKAY;
7220 }
7221 
7222 /** constraint display method of constraint handler */
7223 static
7224 SCIP_DECL_CONSPRINT(consPrintBivariate)
7225 { /*lint --e{715}*/
7226  SCIP_CONSDATA* consdata;
7227 
7228  assert(scip != NULL);
7229  assert(cons != NULL);
7230 
7231  consdata = SCIPconsGetData(cons);
7232  assert(consdata != NULL);
7233 
7234  /* print left hand side for ranged rows */
7235  if( !SCIPisInfinity(scip, -consdata->lhs)
7236  && !SCIPisInfinity(scip, consdata->rhs)
7237  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
7238  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
7239 
7240  /* print coefficients and variables */
7241  SCIP_CALL( SCIPexprtreePrintWithNames(consdata->f, SCIPgetMessagehdlr(scip), file) );
7242 
7243  if( consdata->z != NULL )
7244  {
7245  SCIPinfoMessage(scip, file, "%+.15g", consdata->zcoef);
7246  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->z, TRUE) );
7247  }
7248 
7249  /* print right hand side */
7250  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
7251  {
7252  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
7253  }
7254  else if( !SCIPisInfinity(scip, consdata->rhs) )
7255  {
7256  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
7257  }
7258  else if( !SCIPisInfinity(scip, -consdata->lhs) )
7259  {
7260  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
7261  }
7262  else
7263  {
7264  SCIPinfoMessage(scip, file, " [free]");
7265  }
7266 
7267  /* print convexity type, if known */
7268  switch( consdata->convextype )
7269  {
7270  case SCIP_BIVAR_ALLCONVEX:
7271  SCIPinfoMessage(scip, file, " [allconvex]");
7272  break;
7274  SCIPinfoMessage(scip, file, " [1-convex]");
7275  break;
7277  SCIPinfoMessage(scip, file, " [convex-concave]");
7278  break;
7279  default: ;
7280  } /*lint !e788*/
7281 
7282  return SCIP_OKAY;
7283 }
7284 
7285 /** constraint copying method of constraint handler */
7286 static
7287 SCIP_DECL_CONSCOPY(consCopyBivariate)
7288 { /*lint --e{715}*/
7289  SCIP_CONSDATA* consdata;
7290  SCIP_EXPRTREE* f;
7291  SCIP_VAR* xy[2];
7292  SCIP_VAR* z;
7293 
7294  assert(scip != NULL);
7295  assert(cons != NULL);
7296  assert(sourcescip != NULL);
7297  assert(sourceconshdlr != NULL);
7298  assert(sourcecons != NULL);
7299  assert(varmap != NULL);
7300  assert(valid != NULL);
7301 
7302  consdata = SCIPconsGetData(sourcecons);
7303  assert(consdata != NULL);
7304  assert(consdata->f != NULL);
7305 
7306  *valid = TRUE;
7307 
7308  if( consdata->z != NULL )
7309  {
7310  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->z, &z, varmap, consmap, global, valid) );
7311  assert(!*valid || z != NULL);
7312  }
7313  else
7314  z = NULL;
7315 
7316  if( *valid )
7317  {
7318  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, SCIPexprtreeGetVars(consdata->f)[0], &xy[0], varmap, consmap, global, valid) );
7319  assert(!*valid || xy[0] != NULL);
7320  }
7321 
7322  if( *valid )
7323  {
7324  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, SCIPexprtreeGetVars(consdata->f)[1], &xy[1], varmap, consmap, global, valid) );
7325  assert(!*valid || xy[1] != NULL);
7326  }
7327 
7328  if( *valid )
7329  {
7330  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &f, consdata->f) );
7331  SCIP_CALL( SCIPexprtreeSetVars(f, 2, xy) );
7332  }
7333  else
7334  f = NULL;
7335 
7336  if( *valid )
7337  {
7338  SCIP_CALL( SCIPcreateConsBivariate(scip, cons, name ? name : SCIPconsGetName(sourcecons),
7339  f, consdata->convextype, z, consdata->zcoef, consdata->lhs, consdata->rhs,
7340  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
7341  }
7342 
7343  if( f != NULL )
7344  {
7345  SCIP_CALL( SCIPexprtreeFree(&f) );
7346  }
7347 
7348  return SCIP_OKAY;
7349 }
7350 
7351 /** constraint method of constraint handler which returns the variables (if possible) */
7352 static
7353 SCIP_DECL_CONSGETVARS(consGetVarsBivariate)
7354 { /*lint --e{715}*/
7355 
7356  if( varssize < 3 )
7357  (*success) = FALSE;
7358  else
7359  {
7360  SCIP_CONSDATA* consdata;
7361 
7362  assert(cons != NULL);
7363  assert(vars != NULL);
7364 
7365  consdata = SCIPconsGetData(cons);
7366  assert(consdata != NULL);
7367 
7368  vars[0] = SCIPexprtreeGetVars(consdata->f)[0];
7369  vars[1] = SCIPexprtreeGetVars(consdata->f)[1];
7370  vars[2] = consdata->z;
7371  (*success) = TRUE;
7372  }
7373 
7374  return SCIP_OKAY;
7375 }
7376 
7377 /** constraint method of constraint handler which returns the number of variables (if possible) */
7378 static
7379 SCIP_DECL_CONSGETNVARS(consGetNVarsBivariate)
7380 { /*lint --e{715}*/
7381 
7382  (*nvars) = 3;
7383  (*success) = TRUE;
7384 
7385  return SCIP_OKAY;
7386 }
7387 
7388 /*
7389  * Quadratic constraint upgrading
7390  */
7391 
7392 /** tries to upgrade a quadratic constraint into a bivariate constraint */
7393 static
7394 SCIP_DECL_QUADCONSUPGD(quadconsUpgdBivariate)
7395 { /*lint --e{715}*/
7396  SCIP_QUADVARTERM* quadvarterms;
7397  SCIP_BILINTERM* bilinterms;
7398  int nquadvarterms;
7399  int nbilinterms;
7400 
7401  SCIP_VAR* x;
7402  SCIP_VAR* y;
7403 
7404  SCIP_Real coefxx;
7405  SCIP_Real coefxy;
7406  SCIP_Real coefyy;
7407  SCIP_Real coefx;
7408  SCIP_Real coefy;
7409 
7410  SCIP_Real zcoef;
7411  SCIP_VAR* z;
7412 
7413  assert(nupgdconss != NULL);
7414  assert(upgdconss != NULL);
7415 
7416  *nupgdconss = 0;
7417 
7418  /* not interested in univariate case */
7419  if( nbinquad + nintquad + ncontquad < 2 )
7420  return SCIP_OKAY;
7421 
7422  if( SCIPgetNBilinTermsQuadratic(scip, cons) == 0 )
7423  return SCIP_OKAY;
7424 
7425  quadvarterms = SCIPgetQuadVarTermsQuadratic(scip, cons);
7426  nquadvarterms = SCIPgetNQuadVarTermsQuadratic(scip, cons);
7427  bilinterms = SCIPgetBilinTermsQuadratic(scip, cons);
7428  nbilinterms = SCIPgetNBilinTermsQuadratic(scip, cons);
7429 
7430  if( nquadvarterms == 2 && SCIPgetNLinearVarsQuadratic(scip, cons) <= 1 )
7431  {
7432  x = quadvarterms[0].var;
7433  y = quadvarterms[1].var;
7434 
7435  coefxx = quadvarterms[0].sqrcoef;
7436  coefyy = quadvarterms[1].sqrcoef;
7437 
7438  /* only one bilinear term -> not interesting for us */
7439  if( coefxx == 0.0 && coefyy == 0.0 )
7440  return SCIP_OKAY;
7441 
7442  /* two square terms without bilinear term -> also not interesting for us */
7443  if( nbilinterms == 0 )
7444  return SCIP_OKAY;
7445  assert(nbilinterms == 1);
7446 
7447  assert(bilinterms[0].var1 == x || bilinterms[0].var1 == y);
7448  assert(bilinterms[0].var2 == x || bilinterms[0].var2 == y);
7449 
7450  coefxy = bilinterms[0].coef;
7451 
7452  coefx = quadvarterms[0].lincoef;
7453  coefy = quadvarterms[1].lincoef;
7454 
7455  if( SCIPgetNLinearVarsQuadratic(scip, cons) )
7456  {
7457  assert(SCIPgetNLinearVarsQuadratic(scip, cons) == 1);
7458  zcoef = SCIPgetCoefsLinearVarsQuadratic(scip, cons)[0];
7459  z = SCIPgetLinearVarsQuadratic(scip, cons)[0];
7460  }
7461  else
7462  {
7463  z = NULL;
7464  zcoef = 0.0;
7465  }
7466 
7467  if( upgdconsssize < 1 )
7468  {
7469  *nupgdconss = -1;
7470  return SCIP_OKAY;
7471  }
7472 
7473  SCIP_CALL( createConsFromQuadTerm(scip, cons, &upgdconss[0], SCIPconsGetName(cons),
7474  x, y, z, coefxx, coefx, coefyy, coefy, coefxy, zcoef, SCIPgetLhsQuadratic(scip, cons), SCIPgetRhsQuadratic(scip, cons)) );
7475  *nupgdconss = 1;
7476  }
7477  else
7478  {
7479  SCIP_CONS* quadcons;
7480  SCIP_Bool upgdlhs;
7481  SCIP_Bool upgdrhs;
7482  SCIP_Bool keeporig;
7483  SCIP_Bool* marked;
7484  char name[SCIP_MAXSTRLEN];
7485  SCIP_VAR* auxvar;
7486  int xpos;
7487  int ypos;
7488  int pos;
7489  int i;
7490 
7491  /* needs to check curvature, which might be expensive */
7492  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 && nquadvarterms > 10 )
7493  return SCIP_OKAY;
7494  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 && nquadvarterms > 50 )
7495  return SCIP_OKAY;
7496 
7497  /* check if we find at least one bilinear term for which we would create a bivariate constraint
7498  * thus, we search for a variable that has a square term and is involved in at least one bivariate term */
7499  for( i = 0; i < nquadvarterms; ++i )
7500  if( quadvarterms[i].sqrcoef != 0.0 && quadvarterms[i].nadjbilin > 0 )
7501  break;
7502 
7503  /* if nothing found, then don't try upgrade and return */
7504  if( i == nquadvarterms )
7505  return SCIP_OKAY;
7506 
7507  /* check which constraint side we want to upgrade and whether to keep some
7508  * we want to upgrade those that are nonconvex */
7509  SCIP_CALL( SCIPcheckCurvatureQuadratic(scip, cons) );
7510  upgdlhs = FALSE;
7511  upgdrhs = FALSE;
7512  keeporig = FALSE;
7513  if( !SCIPisInfinity(scip, -SCIPgetLhsQuadratic(scip, cons)) )
7514  {
7515  if( SCIPisConcaveQuadratic(scip, cons) )
7516  keeporig = TRUE;
7517  else
7518  upgdlhs = TRUE;
7519  }
7520  if( !SCIPisInfinity(scip, SCIPgetRhsQuadratic(scip, cons)) )
7521  {
7522  if( SCIPisConvexQuadratic(scip, cons) )
7523  keeporig = TRUE;
7524  else
7525  upgdrhs = TRUE;
7526  }
7527 
7528  /* if nothing to upgrade, then return */
7529  if( !upgdlhs && !upgdrhs )
7530  return SCIP_OKAY;
7531 
7532  /* require enough space here already, so we do not create and add aux vars that we cannot get rid of easily later */
7533  if( upgdconsssize < nbilinterms + 1 + (keeporig ? 1 : 0) )
7534  {
7535  *nupgdconss = -(nbilinterms + 1 + (keeporig ? 1 : 0));
7536  return SCIP_OKAY;
7537  }
7538 
7539  /* initial remaining quadratic constraint: take linear part and constraint sides from original constraint */
7540  SCIP_CALL( SCIPcreateConsQuadratic(scip, &quadcons, SCIPconsGetName(cons),
7542  0, NULL, NULL, NULL,
7543  upgdlhs ? SCIPgetLhsQuadratic(scip, cons) : -SCIPinfinity(scip),
7544  upgdrhs ? SCIPgetRhsQuadratic(scip, cons) : SCIPinfinity(scip),
7548 
7549  /* remember for each quadratic variable whether its linear and square part has been moved into a bivariate constraint */
7550  SCIP_CALL( SCIPallocBufferArray(scip, &marked, nquadvarterms) );
7552 
7553  /* @todo what is a good partition of a number of quadratic terms into bivariate terms? */
7554 
7555  /* check for each bilinear term, whether we want to create a bivariate constraint for it and associated square terms */
7556  for( i = 0; i < nbilinterms; ++i )
7557  {
7558  assert(bilinterms[i].coef != 0.0);
7559 
7560  x = bilinterms[i].var1;
7561  y = bilinterms[i].var2;
7562 
7563  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, cons, x, &xpos) );
7564  assert(xpos >= 0);
7565  assert(xpos < nquadvarterms);
7566  assert(quadvarterms[xpos].var == x);
7567 
7568  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, cons, y, &ypos) );
7569  assert(ypos >= 0);
7570  assert(ypos < nquadvarterms);
7571  assert(quadvarterms[ypos].var == y);
7572 
7573  coefxx = marked[xpos] ? 0.0 : quadvarterms[xpos].sqrcoef;
7574  coefyy = marked[ypos] ? 0.0 : quadvarterms[ypos].sqrcoef;
7575 
7576  /* if there are no square terms, then do not upgrade bilinear term to bivariate constraint
7577  * thus, add bivariate term to quadcons and continue
7578  */
7579  if( coefxx == 0.0 && coefyy == 0.0 )
7580  {
7581  /* check if x and y already are in quadcons and add if not there yet */
7582  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, quadcons, x, &pos) );
7583  if( pos == -1 )
7584  {
7585  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, quadcons, x, 0.0, 0.0) );
7586  }
7587  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, quadcons, y, &pos) );
7588  if( pos == -1 )
7589  {
7590  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, quadcons, y, 0.0, 0.0) );
7591  }
7592 
7593  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, quadcons, x, y, bilinterms[i].coef) );
7594 
7595  continue;
7596  }
7597 
7598  coefx = marked[xpos] ? 0.0 : quadvarterms[xpos].lincoef;
7599  coefy = marked[ypos] ? 0.0 : quadvarterms[ypos].lincoef;
7600  coefxy = bilinterms[i].coef;
7601 
7602  /* create new auxiliary variable for bilinear quad. term in x and y */
7603  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_auxvar%d", SCIPconsGetName(cons), *nupgdconss);
7604  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
7605  SCIP_VARTYPE_CONTINUOUS, SCIPconsIsInitial(cons), TRUE, NULL, NULL, NULL, NULL, NULL) );
7606  SCIP_CALL( SCIPaddVar(scip, auxvar) );
7607 
7608  /* add 1*auxvar to quadcons */
7609  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, quadcons, auxvar, 1.0) );
7610 
7611  /* create new bivariate constraint */
7612  assert(*nupgdconss < upgdconsssize);
7613  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_auxcons%d", SCIPconsGetName(cons), *nupgdconss);
7614  SCIP_CALL( createConsFromQuadTerm(scip, cons, &upgdconss[*nupgdconss], name,
7615  x, y, auxvar, coefxx, coefx, coefyy, coefy, coefxy, -1.0,
7616  SCIPisInfinity(scip, -SCIPgetLhsQuadratic(scip, cons)) ? -SCIPinfinity(scip) : 0.0,
7617  SCIPisInfinity(scip, SCIPgetRhsQuadratic(scip, cons)) ? SCIPinfinity(scip) : 0.0) );
7618  /* need to enforce new constraints, as relation auxvar = f(x,y) is not redundant, even if original constraint is */
7619  SCIP_CALL( SCIPsetConsEnforced(scip, upgdconss[*nupgdconss], TRUE) );
7620  SCIP_CALL( SCIPsetConsChecked(scip, upgdconss[*nupgdconss], TRUE) );
7621  ++*nupgdconss;
7622 
7623  /* compute value of auxvar in debug solution */
7624 #ifdef WITH_DEBUG_SOLUTION
7625  if( SCIPdebugIsMainscip(scip) )
7626  {
7627  SCIP_Real xval;
7628  SCIP_Real yval;
7629  SCIP_CALL( SCIPdebugGetSolVal(scip, x, &xval) );
7630  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &yval) );
7631  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, coefxx * xval * xval + coefyy * yval * yval + coefxy * xval * yval + coefx * xval + coefy * yval) );
7632  }
7633 #endif
7634 
7635  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
7636 
7637  marked[xpos] = TRUE;
7638  marked[ypos] = TRUE;
7639  }
7640 
7641  if( *nupgdconss == 0 )
7642  {
7643  /* if no constraints created, then forget also quadcons and do no upgrade */
7644  SCIP_CALL( SCIPreleaseCons(scip, &quadcons) );
7645  }
7646  else
7647  {
7648  /* complete quadcons: check for unmarked quadvarterms and add their linear and square coefficients to quadcons */
7649  for( i = 0; i < nquadvarterms; ++i )
7650  {
7651  if( marked[i] )
7652  continue;
7653 
7654  x = quadvarterms[i].var;
7655 
7656  /* check if variable is already in quadcons
7657  * if the variable appears in a bilinear term, then this term should have been added to quadcons above, so the variable is there
7658  */
7659  pos = -1;
7660  if( quadvarterms[i].nadjbilin > 0 )
7661  {
7662  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, quadcons, x, &pos) );
7663  }
7664 
7665  /* create new quad var or add existing quad var */
7666  if( quadvarterms[i].sqrcoef != 0.0 )
7667  {
7668  if( pos == -1 )
7669  {
7670  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, quadcons, x, quadvarterms[i].lincoef, quadvarterms[i].sqrcoef) );
7671  }
7672  else
7673  {
7674  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, quadcons, x, quadvarterms[i].sqrcoef) );
7675  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, quadcons, x, quadvarterms[i].lincoef) );
7676  }
7677  }
7678  else if( quadvarterms[i].lincoef != 0.0 )
7679  {
7680  /* if no square term and no quadratic variable term, then add to linear part */
7681  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, quadcons, x, quadvarterms[i].lincoef) );
7682  }
7683  }
7684 
7685  /* add quadcons to set of upgrade constraints */
7686  assert(*nupgdconss < upgdconsssize);
7687  upgdconss[*nupgdconss] = quadcons;
7688  ++*nupgdconss;
7689 
7690  SCIPdebugPrintCons(scip, quadcons, NULL);
7691 
7692  if( keeporig )
7693  {
7694  assert(*nupgdconss < upgdconsssize);
7695  /* copy of original quadratic constraint with one of the sides relaxed */
7696  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &upgdconss[*nupgdconss], SCIPconsGetName(cons),
7700  upgdlhs ? -SCIPinfinity(scip) : SCIPgetLhsQuadratic(scip, cons),
7701  upgdrhs ? SCIPinfinity(scip) : SCIPgetRhsQuadratic(scip, cons),
7705  ++*nupgdconss;
7706  }
7707  }
7708 
7709  SCIPfreeBufferArray(scip, &marked);
7710  }
7711 
7712  return SCIP_OKAY;
7713 }
7714 
7715 
7716 /*
7717  * Nonlinear constraint upgrading
7718  */
7719 
7720 /** tries to reformulate a expression graph node that is a monomial in two variables */
7721 static
7722 SCIP_DECL_EXPRGRAPHNODEREFORM(exprgraphnodeReformBivariate)
7724  SCIP_EXPRDATA_MONOMIAL* monomial;
7725  SCIP_CONS* cons;
7726  SCIP_VAR* auxvar;
7727  char name[SCIP_MAXSTRLEN];
7728  SCIP_VAR* x;
7729  SCIP_VAR* y;
7730  SCIP_Real expx;
7731  SCIP_Real expy;
7732 
7733  assert(scip != NULL);
7734  assert(exprgraph != NULL);
7735  assert(node != NULL);
7736  assert(naddcons != NULL);
7737  assert(reformnode != NULL);
7738 
7739  *reformnode = NULL;
7740 
7741  /* could also upgrade bivariate quadratic, but if we don't then node will appear in cons_quadratic later, from which we also upgrade...
7742  * @todo could also upgrade x/y from EXPR_DIV */
7744  return SCIP_OKAY;
7745 
7746  /* sums of monomials are split up by reformulation, so wait that this happened */
7748  return SCIP_OKAY;
7749 
7750  /* we are only interested in monomials that are not convex or concave, since cons_nonlinear can handle these the same was as we do */
7752  return SCIP_OKAY;
7753 
7754  monomial = SCIPexprgraphGetNodePolynomialMonomials(node)[0];
7755  assert(monomial != NULL);
7756 
7757  /* @todo we could also do some more complex reformulation for n-variate monomials, something better than what reformMonomial in cons_nonlinear is doing */
7758  if( SCIPexprGetMonomialNFactors(monomial) != 2 )
7759  return SCIP_OKAY;
7760  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
7761 
7762  expx = SCIPexprGetMonomialExponents(monomial)[0];
7763  expy = SCIPexprGetMonomialExponents(monomial)[1];
7764 
7765  /* no interest in upgrading x*y -> let cons_quadratic do this */
7766  if( SCIPisEQ(scip, expx, 1.0) && SCIPisEQ(scip, expy, 1.0) )
7767  return SCIP_OKAY;
7768 
7769  /* so far only support variables as arguments @todo could allow more here, e.g., f(x)^pg(y)^q */
7772  return SCIP_OKAY;
7773 
7776  assert(x != y);
7777 
7778  /* so far only allow positive x and y @todo could also allow x<0 or y<0 */
7780  return SCIP_OKAY;
7781 
7782  SCIPdebugMsg(scip, "reformulate bivariate monomial in node %p\n", (void*)node);
7783 
7784  /* create auxiliary variable */
7785  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%dbv", *naddcons);
7786  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, SCIPexprgraphGetNodeBounds(node).inf, SCIPexprgraphGetNodeBounds(node).sup,
7787  0.0, SCIP_VARTYPE_CONTINUOUS, TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
7788  SCIP_CALL( SCIPaddVar(scip, auxvar) );
7789 
7790  /* create bivariate constraint */
7791  SCIP_CALL( createConsFromMonomial(scip, NULL, &cons, name, x, y, auxvar,
7793  SCIP_CALL( SCIPaddCons(scip, cons) );
7794  SCIPdebugPrintCons(scip, cons, NULL);
7795  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
7796  ++*naddcons;
7797 
7798  /* add auxvar to exprgraph and return it in reformnode */
7799  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, reformnode) );
7800 
7801  /* set value of auxvar and reformnode in debug solution */
7802 #ifdef WITH_DEBUG_SOLUTION
7803  if( SCIPdebugIsMainscip(scip) )
7804  {
7805  SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(node));
7807  }
7808 #endif
7809 
7810  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
7811 
7812  return SCIP_OKAY;
7813 }
7814 
7815 /*
7816  * constraint specific interface methods
7817  */
7818 
7819 /** creates the handler for bivariate constraints and includes it in SCIP */
7821  SCIP* scip /**< SCIP data structure */
7822  )
7823 {
7824  SCIP_CONSHDLRDATA* conshdlrdata;
7825  SCIP_CONSHDLR* conshdlr;
7826 
7827  /* create bivariate constraint handler data */
7828  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
7829  BMSclearMemory(conshdlrdata);
7830 
7831  /* include constraint handler */
7834  consEnfolpBivariate, consEnfopsBivariate, consCheckBivariate, consLockBivariate,
7835  conshdlrdata) );
7836 
7837  assert(conshdlr != NULL);
7838 
7839  /* set non-fundamental callbacks via specific setter functions */
7840  SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveBivariate) );
7841  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyBivariate, consCopyBivariate) );
7842  SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveBivariate) );
7843  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteBivariate) );
7844  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableBivariate) );
7845  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableBivariate) );
7846  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitBivariate) );
7847  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreBivariate) );
7848  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolBivariate) );
7849  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeBivariate) );
7850  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsBivariate) );
7851  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsBivariate) );
7852  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitBivariate) );
7853  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreBivariate) );
7854  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolBivariate) );
7855  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpBivariate) );
7856  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolBivariate, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
7857  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintBivariate) );
7858  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropBivariate, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
7860  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpBivariate, consSepasolBivariate, CONSHDLR_SEPAFREQ,
7862  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransBivariate) );
7863  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxBivariate) );
7864 
7865  /* include the quadratic constraint upgrade in the quadratic constraint handler */
7867 
7868  /* include the quadratic constraint upgrade in the quadratic constraint handler */
7869  SCIP_CALL( SCIPincludeNonlinconsUpgrade(scip, NULL, exprgraphnodeReformBivariate, NONLINCONSUPGD_PRIORITY, FALSE, CONSHDLR_NAME) );
7870 
7871  /* add bivariate constraint handler parameters */
7872  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
7873  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
7874  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
7875 
7876  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
7877  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
7878  &conshdlrdata->linfeasshift, FALSE, TRUE, NULL, NULL) );
7879 
7880  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
7881  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation",
7882  &conshdlrdata->maxproprounds, FALSE, 1, 0, INT_MAX, NULL, NULL) );
7883 
7884  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/ninitlprefpoints",
7885  "number of reference points in each direction where to compute linear support for envelope in LP initialization",
7886  &conshdlrdata->ninitlprefpoints, FALSE, 3, 0, INT_MAX, NULL, NULL) );
7887 
7888  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
7889  "are cuts added during enforcement removable from the LP in the same node?",
7890  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
7891 
7892  conshdlrdata->linvareventhdlr = NULL;
7893  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->linvareventhdlr), CONSHDLR_NAME"_boundchange", "signals a bound tightening in a linear variable to a bivariate constraint",
7894  processLinearVarEvent, NULL) );
7895  assert(conshdlrdata->linvareventhdlr != NULL);
7896 
7897  conshdlrdata->nonlinvareventhdlr = NULL;
7898  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->nonlinvareventhdlr), CONSHDLR_NAME"_boundchange2", "signals a bound change in a nonlinear variable to the bivariate constraint handler",
7899  processNonlinearVarEvent, (SCIP_EVENTHDLRDATA*)conshdlrdata) );
7900  assert(conshdlrdata->nonlinvareventhdlr != NULL);
7901 
7902  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
7903  processNewSolutionEvent, NULL) );
7904 
7905  /* create expression interpreter */
7906  SCIP_CALL( SCIPexprintCreate(SCIPblkmem(scip), &conshdlrdata->exprinterpreter) );
7907 
7908  /* create expression graph */
7909  SCIP_CALL( SCIPexprgraphCreate(SCIPblkmem(scip), &conshdlrdata->exprgraph, -1, -1,
7910  exprgraphVarAdded, exprgraphVarRemove, NULL, (void*)conshdlrdata) );
7911  conshdlrdata->isremovedfixings = TRUE;
7912  conshdlrdata->ispropagated = TRUE;
7913 
7914  conshdlrdata->scip = scip;
7915 
7916  return SCIP_OKAY;
7917 }
7918 
7919 /** creates and captures a bivariate constraint
7920  *
7921  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7922  */
7924  SCIP* scip, /**< SCIP data structure */
7925  SCIP_CONS** cons, /**< pointer to hold the created constraint */
7926  const char* name, /**< name of constraint */
7927  SCIP_EXPRTREE* f, /**< expression tree specifying bivariate function f(x,y) */
7928  SCIP_BIVAR_CONVEXITY convextype, /**< kind of convexity of f(x,y) */
7929  SCIP_VAR* z, /**< linear variable in constraint */
7930  SCIP_Real zcoef, /**< coefficient of linear variable */
7931  SCIP_Real lhs, /**< left hand side of constraint */
7932  SCIP_Real rhs, /**< right hand side of constraint */
7933  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
7934  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
7935  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
7936  * Usually set to TRUE. */
7937  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
7938  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7939  SCIP_Bool check, /**< should the constraint be checked for feasibility?
7940  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7941  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
7942  * Usually set to TRUE. */
7943  SCIP_Bool local, /**< is constraint only valid locally?
7944  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
7945  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
7946  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
7947  * adds coefficients to this constraint. */
7948  SCIP_Bool dynamic, /**< is constraint subject to aging?
7949  * Usually set to FALSE. Set to TRUE for own cuts which
7950  * are seperated as constraints. */
7951  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
7952  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
7953  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
7954  * if it may be moved to a more global node?
7955  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
7956  )
7957 {
7958  SCIP_CONSHDLR* conshdlr;
7959  SCIP_CONSDATA* consdata;
7960 
7961  assert(f != NULL);
7962  assert(!SCIPisInfinity(scip, REALABS(zcoef)));
7963  assert(modifiable == FALSE); /* we do not support column generation */
7964 
7965  /* find the bivariate constraint handler */
7966  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
7967  if( conshdlr == NULL )
7968  {
7969  SCIPerrorMessage("bivariate constraint handler not found\n");
7970  return SCIP_PLUGINNOTFOUND;
7971  }
7972 
7973  /* create constraint data */
7974  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
7975  BMSclearMemory(consdata);
7976 
7977  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &consdata->f, f) );
7978  consdata->convextype = convextype;
7979  consdata->z = z;
7980  consdata->zcoef = zcoef;
7981  consdata->lhs = lhs;
7982  consdata->rhs = rhs;
7983 
7984  assert(SCIPexprtreeGetNVars(consdata->f) == 2);
7985  assert(SCIPexprtreeGetVars(consdata->f) != NULL);
7986  assert(SCIPexprtreeGetVars(consdata->f)[0] != NULL);
7987  assert(SCIPexprtreeGetVars(consdata->f)[1] != NULL);
7988 
7989  /* mark that variable events are not catched so far */
7990  consdata->eventfilterpos = -1;
7991 
7992  /* create constraint */
7993  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
7994  local, modifiable, dynamic, removable, stickingatnode) );
7995 
7996  return SCIP_OKAY;
7997 }
7998 
7999 /** creates and captures an absolute power constraint
8000  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
8001  * method SCIPcreateConsBivariate(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
8002  *
8003  * @see SCIPcreateConsBivariate() for information about the basic constraint flag configuration
8004  *
8005  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8006  */
8008  SCIP* scip, /**< SCIP data structure */
8009  SCIP_CONS** cons, /**< pointer to hold the created constraint */
8010  const char* name, /**< name of constraint */
8011  SCIP_EXPRTREE* f, /**< expression tree specifying bivariate function f(x,y) */
8012  SCIP_BIVAR_CONVEXITY convextype, /**< kind of convexity of f(x,y) */
8013  SCIP_VAR* z, /**< linear variable in constraint */
8014  SCIP_Real zcoef, /**< coefficient of linear variable */
8015  SCIP_Real lhs, /**< left hand side of constraint */
8016  SCIP_Real rhs /**< right hand side of constraint */
8017  )
8018 {
8019  assert(scip != NULL);
8020 
8021  SCIP_CALL( SCIPcreateConsBivariate(scip, cons, name, f, convextype, z, zcoef, lhs, rhs,
8022  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
8023 
8024  return SCIP_OKAY;
8025 }
8026 
8027 /** gets the linear variable of a bivariate constraint, or NULL if no such variable */
8029  SCIP* scip, /**< SCIP data structure */
8030  SCIP_CONS* cons /**< constraint */
8031  )
8032 {
8033  assert(cons != NULL);
8034  assert(SCIPconsGetData(cons) != NULL);
8035 
8036  return SCIPconsGetData(cons)->z;
8037 }
8038 
8039 /** gets the coefficients of the linear variable of a bivariate constraint */
8041  SCIP* scip, /**< SCIP data structure */
8042  SCIP_CONS* cons /**< constraint */
8043  )
8044 {
8045  assert(cons != NULL);
8046  assert(SCIPconsGetData(cons) != NULL);
8047 
8048  return SCIPconsGetData(cons)->zcoef;
8049 }
8050 
8051 /** gets the expression tree of a bivariate constraint */
8053  SCIP* scip, /**< SCIP data structure */
8054  SCIP_CONS* cons /**< constraint */
8055  )
8056 {
8057  assert(cons != NULL);
8058  assert(SCIPconsGetData(cons) != NULL);
8059 
8060  return SCIPconsGetData(cons)->f;
8061 }
8062 
8063 /** gets the left hand side of a bivariate constraint */
8065  SCIP* scip, /**< SCIP data structure */
8066  SCIP_CONS* cons /**< constraint */
8067  )
8068 {
8069  assert(cons != NULL);
8070  assert(SCIPconsGetData(cons) != NULL);
8071 
8072  return SCIPconsGetData(cons)->lhs;
8073 }
8074 
8075 /** gets the right hand side of a bivariate constraint */
8077  SCIP* scip, /**< SCIP data structure */
8078  SCIP_CONS* cons /**< constraint */
8079  )
8080 {
8081  assert(cons != NULL);
8082  assert(SCIPconsGetData(cons) != NULL);
8083 
8084  return SCIPconsGetData(cons)->rhs;
8085 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
static SCIP_DECL_CONSENFOLP(consEnfolpBivariate)
SCIP_VAR ** SCIPgetLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetLinearCoefBivariate(SCIP *scip, SCIP_CONS *cons)
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13311
static SCIP_RETCODE createExprtreeFromMonomial(SCIP *scip, SCIP_VAR *x, SCIP_VAR *y, SCIP_Real coef, SCIP_Real p, SCIP_Real q, SCIP_EXPRTREE **exprtree, SCIP_Real *mult, SCIP_BIVAR_CONVEXITY *convextype)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:47363
#define CONSHDLR_NAME
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15816
void SCIPexprFreeDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6183
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:6291
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15497
static SCIP_RETCODE catchLinearVarEvents(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol)
SCIP_RETCODE SCIPincludeNonlinconsUpgrade(SCIP *scip, SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)), SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)), int priority, SCIP_Bool active, const char *conshdlrname)
static SCIP_RETCODE generateConvexConcaveEstimator(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_CONS *cons, SCIP_Real xyref[2], SCIP_SIDETYPE violside, SCIP_ROW **row)
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:46443
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14953
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8083
SCIP_RETCODE SCIPexprSubstituteVars(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR **substexprs)
Definition: expr.c:8145
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
primal heuristic that tries a given solution
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip.c:31233
SCIP_RETCODE SCIPaddQuadVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real lincoef, SCIP_Real sqrcoef)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22523
static SCIP_DECL_CONSPRESOL(consPresolBivariate)
SCIP_VAR * var2
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47298
static SCIP_DECL_QUADCONSUPGD(quadconsUpgdBivariate)
static SCIP_RETCODE initSepaData(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_CONS *cons)
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:15237
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip.c:41404
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:821
methods to interpret (evaluate) an expression tree "fast"
static SCIP_RETCODE registerLargeRelaxValueVariableForBranching(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_VAR **brvar)
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:58
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8245
void SCIPexprtreePrint(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, const char **paramnames)
Definition: expr.c:8756
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip.c:38868
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:6314
SCIP_RETCODE SCIPcreateConsBivariate(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPRTREE *f, SCIP_BIVAR_CONVEXITY convextype, SCIP_VAR *z, SCIP_Real zcoef, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47311
#define NEWTONMAXITER
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47674
static SCIP_DECL_EXPRGRAPHNODEREFORM(exprgraphnodeReformBivariate)
SCIP_RETCODE SCIPaddSquareCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_RETCODE generateOverestimatingHyperplaneCut(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_CONS *cons, SCIP_Real *x0y0, SCIP_ROW **row)
#define CONSHDLR_NEEDSCONS
SCIP_Real SCIPgetRhsBivariate(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE propagateBoundsCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_RESULT *result, int *nchgbds, SCIP_Bool *redundant)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:41226
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:6604
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12947
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5693
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17276
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14923
SCIP_RETCODE SCIPincludeQuadconsUpgrade(SCIP *scip, SCIP_DECL_QUADCONSUPGD((*quadconsupgd)), int priority, SCIP_Bool active, const char *conshdlrname)
static SCIP_RETCODE dropLinearVarEvents(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:6544
#define SCIP_MAXSTRLEN
Definition: def.h:259
static SCIP_RETCODE removeFixedNonlinearVariables(SCIP *scip, SCIP_CONSHDLR *conshdlr)
SCIP_VAR * var1
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip.c:6036
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12663
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:30668
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:16405
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:47088
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17332
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47015
internal methods for NLPI solver interfaces
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDEACTIVE((*consdeactive)))
Definition: scip.c:6406
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:8355
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:8611
static SCIP_RETCODE computeViolations(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_CONS **maxviolcon)
SCIP_RETCODE SCIPexprCreateMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial, SCIP_Real coef, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:7035
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:14997
static SCIP_RETCODE separatePoint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Real minefficacy, SCIP_Bool inenforcement, SCIP_RESULT *result, SCIP_Real *bestefficacy)
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip.c:18957
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:18766
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:138
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyBivariate)
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip.c:6205
#define CONSHDLR_PROP_TIMING
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47350
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4485
void SCIPexprgraphPropagateNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:15870
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:16484
#define FALSE
Definition: def.h:64
SCIP_RETCODE SCIPcreateConsBasicBivariate(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_EXPRTREE *f, SCIP_BIVAR_CONVEXITY convextype, SCIP_VAR *z, SCIP_Real zcoef, SCIP_Real lhs, SCIP_Real rhs)
#define CONSHDLR_SEPAPRIORITY
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14943
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10289
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip.c:5894
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:47028
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10011
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:47100
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28630
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
#define infty2infty(infty1, infty2, val)
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:21660
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8265
static SCIP_DECL_CONSCHECK(consCheckBivariate)
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)
SCIP_INTERVAL SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13301
void SCIPexprReindexVars(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8183
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
static SCIP_RETCODE solveDerivativeEquation(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_EXPRTREE *f, SCIP_Real targetvalue, SCIP_Real lb, SCIP_Real ub, SCIP_Real *val, SCIP_Bool *success)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8295
static SCIP_DECL_CONSGETNVARS(consGetNVarsBivariate)
SCIP_RETCODE SCIPexprtreeSetVars(SCIP_EXPRTREE *tree, int nvars, SCIP_VAR **vars)
Definition: nlp.c:111
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:22639
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:22602
#define CONSHDLR_ENFOPRIORITY
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip.c:5948
SCIP_Bool SCIPintervalIsNegativeInfinity(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip.c:8741
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip.c:1235
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15357
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46963
SCIP_RETCODE SCIPincludeConshdlrBivariate(SCIP *scip)
static SCIP_RETCODE createConsFromMonomial(SCIP *scip, SCIP_CONS *srccons, SCIP_CONS **cons, const char *name, SCIP_VAR *x, SCIP_VAR *y, SCIP_VAR *z, SCIP_Real coef, SCIP_Real p, SCIP_Real q, SCIP_Real zcoef, SCIP_Real lhs, SCIP_Real rhs)
static SCIP_DECL_CONSACTIVE(consActiveBivariate)
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:37920
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8771
static SCIP_RETCODE generate1ConvexIndefiniteUnderestimatorAtBoundary(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_EXPRTREE *f, SCIP_Real xyref[2], SCIP_Real cutcoeff[4], SCIP_Real *convenvvalue, SCIP_Bool *success)
static SCIP_RETCODE generateOrthogonal_lx_ly_Underestimator(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_EXPRTREE *f, SCIP_Real *xyref, SCIP_Real cutcoeff[4], SCIP_Real *convenvvalue, SCIP_Bool *success)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:22632
static SCIP_RETCODE createConsFromQuadTerm(SCIP *scip, SCIP_CONS *srccons, SCIP_CONS **cons, const char *name, SCIP_VAR *x, SCIP_VAR *y, SCIP_VAR *z, SCIP_Real coefxx, SCIP_Real coefx, SCIP_Real coefyy, SCIP_Real coefy, SCIP_Real coefxy, SCIP_Real coefz, SCIP_Real lhs, SCIP_Real rhs)
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip.c:21953
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:22585
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8642
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8255
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:108
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:6337
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1267
#define SCIPdebugMsgPrint
Definition: scip.h:456
#define SCIPdebugMsg
Definition: scip.h:455
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4265
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip.c:18998
SCIP_Real SCIPgetLhsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:15104
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8047
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1343
SCIP_VAR ** SCIPexprtreeGetVars(SCIP_EXPRTREE *tree)
Definition: nlp.c:101
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip.c:27584
SCIP_Real SCIPepsilon(SCIP *scip)
Definition: scip.c:46415
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13170
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30889
SCIP_RETCODE SCIPaddLinearVarQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPcreateConsQuadratic(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadterms, SCIP_VAR **quadvars1, SCIP_VAR **quadvars2, SCIP_Real *quadcoefs, 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)
int SCIPgetNQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE registerBranchingVariables(SCIP *scip, SCIP_CONS **conss, int nconss, int *nnotify)
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:104
SCIP_Bool SCIPintervalIsPositiveInfinity(SCIP_Real infinity, SCIP_INTERVAL operand)
int SCIPexprGetMonomialNFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5910
SCIP_RETCODE SCIPexprtreePrintWithNames(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: nlp.c:172
static SCIP_DECL_CONSENFORELAX(consEnforelaxBivariate)
SCIP_EXPRTREE * SCIPgetExprtreeBivariate(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_DELAYPROP
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:236
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13007
static SCIP_DECL_CONSPROP(consPropBivariate)
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13158
SCIP_RETCODE SCIPexprgraphCreate(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPH **exprgraph, int varssizeinit, int depthinit, SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), void *userdata)
Definition: expr.c:15065
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17286
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:11628
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip.c:6157
SCIP_Bool SCIPisConcaveQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Real coef
Definition: type_expr.h:102
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:127
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1162
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip.c:38168
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13182
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30835
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:6060
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13321
SCIP_RETCODE SCIPexprCreateQuadratic(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real constant, SCIP_Real *lincoefs, int nquadelems, SCIP_QUADELEM *quadelems)
Definition: expr.c:6584
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1198
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip.c:8225
SCIP_RETCODE SCIPfindQuadVarTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, int *pos)
SCIP_Real SCIPgetRowMinCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30871
#define QUADCONSUPGD_PRIORITY
#define SCIPerrorMessage
Definition: pub_message.h:45
SCIP_RETCODE SCIPexprintEval(SCIP_EXPRINT *exprint, SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12591
SCIP_RETCODE SCIPexprintCreate(BMS_BLKMEM *blkmem, SCIP_EXPRINT **exprint)
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip.c:31484
static SCIP_RETCODE unlockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_DECL_CONSINITSOL(consInitsolBivariate)
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:13297
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:38948
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
SCIP_RETCODE SCIPexprCopyDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **targetexpr, SCIP_EXPR *sourceexpr)
Definition: expr.c:6141
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip.c:32299
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:16593
static SCIP_DECL_CONSLOCK(consLockBivariate)
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:19311
SCIP_Real * SCIPgetCoefsLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_DESC
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:46731
static SCIP_DECL_CONSDELETE(consDeleteBivariate)
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21788
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip.c:27934
static SCIP_DECL_CONSCOPY(consCopyBivariate)
#define CONSHDLR_EAGERFREQ
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7986
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:25932
static SCIP_DECL_EXPRGRAPHVARADDED(exprgraphVarAdded)
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8205
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16662
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:6085
constraint handler for quadratic constraints
static SCIP_DECL_CONSENFOPS(consEnfopsBivariate)
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4133
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:28602
SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2548
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:39041
static SCIP_RETCODE propagateBounds(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_RESULT *result, int *nchgbds, int *ndelconss)
#define REALABS(x)
Definition: def.h:173
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:8612
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip.c:37577
SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
Definition: scip.c:7583
#define SCIP_CALL(x)
Definition: def.h:350
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:63
static SCIP_DECL_EXPRGRAPHVARREMOVE(exprgraphVarRemove)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47337
SCIP_RETCODE SCIPexprCreatePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:6632
SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize, SCIP_Bool mergemultiples)
Definition: scip.c:19255
static SCIP_DECL_CONSTRANS(consTransBivariate)
static SCIP_RETCODE lockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47324
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:16494
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1360
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8225
void SCIPexprgraphTightenNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_INTERVAL nodebounds, SCIP_Real minstrength, SCIP_Real infinity, SCIP_Bool *cutoff)
Definition: expr.c:14680
static SCIP_RETCODE freeSepaData(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
SCIP_RETCODE SCIPcreateRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, int len, SCIP_COL **cols, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:30270
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:34661
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:262
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
SCIP_BILINTERM * SCIPgetBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:106
SCIP_EXPR * SCIPexprtreeGetRoot(SCIP_EXPRTREE *tree)
Definition: expr.c:8602
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:16430
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4515
static SCIP_DECL_CONSDEACTIVE(consDeactiveBivariate)
SCIP_Real SCIPgetRhsQuadratic(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_EVENTEXEC(processLinearVarEvent)
SCIP_RETCODE SCIPaddBilinTermQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real coef)
static SCIP_DECL_CONSSEPALP(consSepalpBivariate)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:22620
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:16440
static SCIP_RETCODE lifting(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_EXPRTREE *f, SCIP_Real xval, SCIP_Real yval, SCIP_Real xlb, SCIP_Real xub, SCIP_Real ylb, SCIP_Real yub, int min_max, SCIP_Real cutcoeff[4], SCIP_Real *convenvvalue, SCIP_Bool *success)
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:982
#define SCIP_Bool
Definition: def.h:61
SCIP_RETCODE SCIPchgRowRhs(SCIP *scip, SCIP_ROW *row, SCIP_Real rhs)
Definition: scip.c:30585
SCIP_RETCODE SCIPexprintNewParametrization(SCIP_EXPRINT *exprint, SCIP_EXPRTREE *tree)
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:41158
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:959
SCIP_Real SCIPgetLhsBivariate(SCIP *scip, SCIP_CONS *cons)
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:15017
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:30402
static SCIP_Bool isConvexLocal(SCIP *scip, SCIP_CONS *cons, SCIP_SIDETYPE side)
SCIP_Real SCIPlpfeastol(SCIP *scip)
Definition: scip.c:46457
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8657
constraint handler for nonlinear constraints
static SCIP_DECL_CONSDISABLE(consDisableBivariate)
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:29091
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:34772
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8006
methods for debugging
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:15037
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8115
SCIP_RETCODE SCIPchgRowLhs(SCIP *scip, SCIP_ROW *row, SCIP_Real lhs)
Definition: scip.c:30561
SCIP_RETCODE SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
Definition: scip.c:6452
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:41192
SCIP_RETCODE SCIPexprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op,...)
Definition: expr.c:5973
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:38535
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8185
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8155
SCIP_RETCODE SCIPexprtreeFree(SCIP_EXPRTREE **tree)
Definition: expr.c:8852
static SCIP_RETCODE removeFixedVariables(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *ischanged, SCIP_Bool *isupgraded)
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:41272
static SCIP_DECL_CONSEXITSOL(consExitsolBivariate)
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip.c:17619
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:37272
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14554
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
SCIP_Bool SCIPintervalAreDisjoint(SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:21714
static SCIP_DECL_CONSINITPRE(consInitpreBivariate)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:6498
SCIP_RETCODE SCIPexprintHessianDense(SCIP_EXPRINT *exprint, SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Bool new_varvals, SCIP_Real *val, SCIP_Real *hessian)
constraint handler for bivariate nonlinear constraints
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:65
Constraint handler for linear constraints in their most general form, .
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip.c:34618
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:47039
#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_BIVAR_CONVEXITY
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip.c:6429
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13039
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:35836
SCIP_VAR * SCIPgetLinearVarBivariate(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcheckCurvatureQuadratic(SCIP *scip, SCIP_CONS *cons)
#define SCIP_EVENTTYPE_DISABLED
Definition: type_event.h:53
static SCIP_DECL_CONSSEPASOL(consSepasolBivariate)
#define CONSHDLR_CHECKPRIORITY
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7372
void SCIPenableNLP(SCIP *scip)
Definition: scip.c:31218
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip.c:6229
#define INITLPMAXVARVAL
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:30540
int SCIPgetNLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3162
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47002
static SCIP_DECL_CONSEXIT(consExitBivariate)
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16254
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip.c:1920
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:11492
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8016
SCIP_RETCODE SCIPsetConshdlrInit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINIT((*consinit)))
Definition: scip.c:6109
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip.c:27909
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip.c:6133
static SCIP_DECL_CONSINITLP(consInitlpBivariate)
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:135
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:27761
#define CONSHDLR_PROPFREQ
static SCIP_DECL_CONSGETVARS(consGetVarsBivariate)
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:6253
NLP local search primal heuristic using sub-SCIPs.
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip.c:13790
SCIP_RETCODE SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14408
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:30977
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1138
#define CONSHDLR_MAXPREROUNDS
static SCIP_RETCODE generateEstimatingHyperplane(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_EXPRTREE *f, SCIP_Bool doover, SCIP_Real *x0y0, SCIP_Real *coefx, SCIP_Real *coefy, SCIP_Real *constant, SCIP_Bool *success)
#define NONLINCONSUPGD_PRIORITY
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16781
static SCIP_DECL_CONSINIT(consInitBivariate)
static SCIP_RETCODE generateOrthogonal_lx_uy_Underestimator(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_EXPRTREE *f, SCIP_Real *xyref, SCIP_Real cutcoeff[4], SCIP_Real *convenvvalue, SCIP_Bool *success)
#define SCIP_Real
Definition: def.h:149
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8235
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:30694
static SCIP_RETCODE generateConvexConcaveUnderestimator(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_EXPRTREE *f, SCIP_EXPRTREE *f_yfixed, SCIP_EXPRTREE *vred, SCIP_Real xyref[2], SCIP_Real cutcoeff[4], SCIP_Real *convenvvalue, SCIP_Bool *success)
static SCIP_RETCODE propagateBoundsTightenVar(SCIP *scip, SCIP_VAR *var, SCIP_INTERVAL bounds, SCIP_CONS *cons, SCIP_RESULT *result, int *nchgbds)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1145
static SCIP_RETCODE generate1ConvexIndefiniteUnderestimatorInTheInteriorPatternB(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_EXPRTREE *f, SCIP_Real xyref[2], SCIP_Real cutcoeff[4], SCIP_Real *convenvvalue, SCIP_Bool *success)
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:6567
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_RETCODE SCIPcreateConsNonlinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *nonlincoefs, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8175
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12957
#define SCIP_INVALID
Definition: def.h:169
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8165
SCIP_RETCODE SCIPexprintHessianSparsityDense(SCIP_EXPRINT *exprint, SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Bool *sparsity)
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:31160
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5930
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:9029
SCIP_RETCODE SCIPcreateConsQuadratic2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvarterms, SCIP_QUADVARTERM *quadvarterms, int nbilinterms, SCIP_BILINTERM *bilinterms, 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_RETCODE SCIPaddQuadVarLinearCoefQuadratic(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_DECL_CONSENABLE(consEnableBivariate)
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip.c:31134
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:38740
static SCIP_RETCODE generate1ConvexIndefiniteUnderestimatorInTheInteriorPatternA(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_EXPRTREE *f, SCIP_Real xyref[2], SCIP_Real cutcoeff[4], SCIP_Real *convenvvalue, SCIP_Bool *success)
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:261
#define SCIPisFinite(x)
Definition: pub_misc.h:1768
static SCIP_RETCODE generateCut(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_SIDETYPE violside, SCIP_Real cutmaxrange, SCIP_ROW **row)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:47076
static SCIP_RETCODE enforceViolatedFixedNonlinear(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *reduceddom, SCIP_Bool *infeasible)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:46989
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
SCIP_RETCODE SCIPcomputeHyperplaneThreePoints(SCIP *scip, SCIP_Real a1, SCIP_Real a2, SCIP_Real a3, SCIP_Real b1, SCIP_Real b2, SCIP_Real b3, SCIP_Real c1, SCIP_Real c2, SCIP_Real c3, SCIP_Real *alpha, SCIP_Real *beta, SCIP_Real *gamma_, SCIP_Real *delta)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17342
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2425
SCIP_Bool SCIPconsIsMarkedPropagate(SCIP_CONS *cons)
Definition: cons.c:8195
static SCIP_RETCODE generateLinearizationCut(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_CONS *cons, SCIP_Real *x0y0, SCIP_Bool newxy, SCIP_ROW **row)
static SCIP_RETCODE generate1ConvexIndefiniteUnderestimator(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_CONS *cons, SCIP_Real *xyref, SCIP_ROW **row)
SCIP_Real SCIPgetUpperbound(SCIP *scip)
Definition: scip.c:43426
#define INTERVALINFTY
SCIP_RETCODE SCIPexprintFree(SCIP_EXPRINT **exprint)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:112
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:47210
static SCIP_DECL_CONSFREE(consFreeBivariate)
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSACTIVE((*consactive)))
Definition: scip.c:6383
SCIP_QUADVARTERM * SCIPgetQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define CONSHDLR_SEPAFREQ
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nquadvars, SCIP_VAR **quadvars, int nquadelems, SCIP_QUADELEM *quadelems, SCIP_EXPRTREE *expression, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip.c:32191
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
Definition: scip.c:47161
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14933
SCIP_EVENTHDLRDATA * SCIPeventhdlrGetData(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:288
SCIP_RETCODE SCIPexprCreateLinear(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:6502
static SCIP_RETCODE generateUnderestimatorParallelYFacets(SCIP *scip, SCIP_EXPRINT *exprinterpreter, SCIP_EXPRTREE *f, SCIP_Real *xyref, SCIP_Real cutcoeff[4], SCIP_Real *convenvvalue, SCIP_Bool *success)
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:6181
SCIP_Longint SCIPgetNLPs(SCIP *scip)
Definition: scip.c:42314
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip.c:17735
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16853
static SCIP_RETCODE initSepaDataCreateVred(SCIP *scip, SCIP_EXPRTREE **vred, SCIP_EXPRTREE *f)
SCIP_RETCODE SCIPexprtreeSetParams(SCIP_EXPRTREE *tree, int nparams, SCIP_Real *paramvals)
Definition: expr.c:8876
static SCIP_DECL_CONSPRINT(consPrintBivariate)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:38911
static void perturb(SCIP_Real *val, SCIP_Real lb, SCIP_Real ub, SCIP_Real amount)
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1223
#define CONSHDLR_PRESOLTIMING
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4321
#define SCIPduplicateBlockMemory(scip, ptr, source)
Definition: scip.h:22597
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:47149
static SCIP_DECL_CONSEXITPRE(consExitpreBivariate)
SCIP_Bool SCIPisConvexQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPevalExprtreeLocalBounds(SCIP *scip, SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *val)
Definition: scip.c:33231
SCIP_Bool SCIPintervalIsSubsetEQ(SCIP_Real infinity, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPexprtreeEval(SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
Definition: expr.c:8723
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:4239
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16949
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:22624
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:134
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5994
#define CONSHDLR_DELAYSEPA
void SCIPexprgraphEnableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14527
enum SCIP_SideType SCIP_SIDETYPE
Definition: type_lp.h:58