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