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