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-2016 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 a convex (concave, resp.) bivariate function, computes an over- (under-, resp.) estimating hyperplane
1517  * does not succeed if some variable is unbounded or both variables are fixed
1518  */
1519 static
1521  SCIP* scip, /**< SCIP data structure */
1522  SCIP_EXPRINT* exprinterpreter, /**< expression interpreter */
1523  SCIP_EXPRTREE* f, /**< bivariate function to compute under or overestimator for */
1524  SCIP_Bool doover, /**< whether to compute an overestimator (TRUE) or an underestimator (FALSE) */
1525  SCIP_Real* x0y0, /**< reference values for nonlinear variables */
1526  SCIP_Real* coefx, /**< coefficient of x in estimator */
1527  SCIP_Real* coefy, /**< coefficient of y in estimator */
1528  SCIP_Real* constant, /**< constant part of estimator */
1529  SCIP_Bool* success /**< pointer to indicate whether coefficients where successfully computed */
1530  )
1531 {
1532  SCIP_VAR* x;
1533  SCIP_VAR* y;
1534  SCIP_Real xlb;
1535  SCIP_Real xub;
1536  SCIP_Real ylb;
1537  SCIP_Real yub;
1538 
1539  SCIP_Real p1[2];
1540  SCIP_Real p2[2];
1541  SCIP_Real p3[2];
1542  SCIP_Real p4[2];
1543  SCIP_Real p1val;
1544  SCIP_Real p2val;
1545  SCIP_Real p3val;
1546  SCIP_Real p4val;
1547 
1548  SCIP_Real alpha;
1549  SCIP_Real beta;
1550  SCIP_Real gamma_;
1551  SCIP_Real delta;
1552 
1553  SCIP_Bool tryother;
1554 
1555  assert(scip != NULL);
1556  assert(exprinterpreter != NULL);
1557  assert(f != NULL);
1558  assert(x0y0 != NULL);
1559  assert(coefx != NULL);
1560  assert(coefy != NULL);
1561  assert(constant != NULL);
1562  assert(success != NULL);
1563 
1564  *success = FALSE;
1565 
1566  x = SCIPexprtreeGetVars(f)[0];
1567  y = SCIPexprtreeGetVars(f)[1];
1568 
1569  xlb = SCIPvarGetLbLocal(x);
1570  xub = SCIPvarGetUbLocal(x);
1571  ylb = SCIPvarGetLbLocal(y);
1572  yub = SCIPvarGetUbLocal(y);
1573 
1574  /* reference point should not be outside of bounds */
1575  assert(SCIPisLE(scip, xlb, x0y0[0]));
1576  assert(SCIPisGE(scip, xub, x0y0[0]));
1577  assert(SCIPisLE(scip, ylb, x0y0[1]));
1578  assert(SCIPisGE(scip, yub, x0y0[1]));
1579 
1580  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) || SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub) )
1581  {
1582  SCIPdebugMessage("skip estimating hyperplane since <%s> or <%s> is unbounded\n", SCIPvarGetName(x), SCIPvarGetName(y));
1583  return SCIP_OKAY;
1584  }
1585 
1586  if( SCIPisEQ(scip, xlb, xub) && SCIPisEQ(scip, ylb, yub) )
1587  {
1588  SCIPdebugMessage("skip estimating hyperplane since both <%s> and <%s> are fixed\n", SCIPvarGetName(x), SCIPvarGetName(y));
1589  return SCIP_OKAY;
1590  }
1591 
1592  /* unten links */
1593  p1[0] = xlb;
1594  p1[1] = ylb;
1595 
1596  /* unten rechts */
1597  p2[0] = xub;
1598  p2[1] = ylb;
1599 
1600  /* oben rechts */
1601  p3[0] = xub;
1602  p3[1] = yub;
1603 
1604  /* oben links */
1605  p4[0] = xlb;
1606  p4[1] = yub;
1607 
1608  if( SCIPisEQ(scip, xlb, xub) )
1609  {
1610  /* secant between p1 and p4: p1val + [(p4val - p1val) / (yub - ylb)] * (y - ylb) */
1611  assert(!SCIPisEQ(scip, ylb, yub));
1612 
1613  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p1, &p1val) );
1614  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p4, &p4val) );
1615 
1616  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p4val) || SCIPisInfinity(scip, REALABS(p4val)) )
1617  {
1618  SCIPdebugMessage("skip hyperplane since function cannot be evaluated\n");
1619  return SCIP_OKAY;
1620  }
1621 
1622  *coefx = 0.0;
1623  *coefy = (p4val - p1val) / (yub - ylb);
1624  *constant = p1val - *coefy * ylb;
1625 
1626  *success = TRUE;
1627 
1628  return SCIP_OKAY;
1629  }
1630 
1631  if( SCIPisEQ(scip, ylb, yub) )
1632  {
1633  /* secant between p1 and p2: p1val + [(p2val - p1val) / (xub - xlb)] * (x - xlb) */
1634  assert(!SCIPisEQ(scip, xlb, xub));
1635 
1636  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p1, &p1val) );
1637  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p2, &p2val) );
1638 
1639  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p2val) || SCIPisInfinity(scip, REALABS(p2val)) )
1640  {
1641  SCIPdebugMessage("skip hyperplane since function cannot be evaluated\n");
1642  return SCIP_OKAY;
1643  }
1644 
1645  *coefx = (p2val - p1val) / (xub - xlb);
1646  *coefy = 0.0;
1647  *constant = p1val - *coefx * xlb;
1648 
1649  *success = TRUE;
1650 
1651  return SCIP_OKAY;
1652  }
1653 
1654  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p1, &p1val) );
1655  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p2, &p2val) );
1656  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p3, &p3val) );
1657  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, p4, &p4val) );
1658 
1659  /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
1660  if( !doover )
1661  {
1662  p1val = -p1val;
1663  p2val = -p2val;
1664  p3val = -p3val;
1665  p4val = -p4val;
1666  }
1667 
1668  SCIPdebugMessage("p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
1669  SCIPdebugMessage("p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
1670  SCIPdebugMessage("p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
1671  SCIPdebugMessage("p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
1672 
1673  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p2val) || SCIPisInfinity(scip, REALABS(p2val)) ||
1674  ! SCIPisFinite(p3val) || SCIPisInfinity(scip, REALABS(p3val)) || !SCIPisFinite(p4val) || SCIPisInfinity(scip, REALABS(p4val)) )
1675  {
1676  SCIPdebugMessage("skip hyperplane since function cannot be evaluated\n");
1677  return SCIP_OKAY;
1678  }
1679 
1680  /* compute coefficients alpha, beta, gamma (>0), delta such that
1681  * alpha*x + beta*y + gamma*z = delta
1682  * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
1683  * the fourth corner point lies below this hyperplane.
1684  * Since we assume that f is convex, we then know that all points (x,y,f(x,y)) are below this hyperplane, i.e.,
1685  * alpha*x + beta*y - delta <= -gamma * f(x,y),
1686  * or, equivalently,
1687  * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
1688  */
1689 
1690  tryother = FALSE;
1691  if( x0y0[1] <= ylb + (yub - ylb)/(xub - xlb) * (x0y0[0] - xlb) )
1692  {
1693  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val, &alpha,
1694  &beta, &gamma_, &delta) );
1695 
1696  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
1697  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
1698  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
1699 
1700  /* if hyperplane through p1,p2,p3 does not overestimate f(p4), then it must be the other variant */
1701  if( SCIPisInfinity(scip, delta) || alpha * p4[0] + beta * p4[1] + gamma_ * p4val > delta )
1702  tryother = TRUE;
1703  }
1704  else
1705  {
1706  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val, &alpha,
1707  &beta, &gamma_, &delta) );
1708 
1709  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
1710  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
1711  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
1712 
1713  /* if hyperplane through p1,p3,p4 does not overestimate f(p2), then it must be the other variant */
1714  if( SCIPisInfinity(scip, delta) || alpha * p2[0] + beta * p2[1] + gamma_ * p2val > delta )
1715  tryother = TRUE;
1716  }
1717 
1718  if( tryother )
1719  {
1720  if( x0y0[1] <= yub + (ylb - yub)/(xub - xlb) * (x0y0[0] - xlb) )
1721  {
1722  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1], p4val,
1723  &alpha, &beta, &gamma_, &delta) );
1724 
1725  /* hyperplane should be above (p3,f(p3)) and other points should lie on hyperplane */
1726  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
1727  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
1728  assert(SCIPisInfinity(scip, delta) || SCIPisFeasLE(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
1729  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
1730  }
1731  else
1732  {
1733  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
1734  &alpha, &beta, &gamma_, &delta) );
1735 
1736  /* hyperplane should be above (p1,f(p1)) and other points should lie on hyperplane */
1737  assert(SCIPisInfinity(scip, delta) || SCIPisFeasLE(scip, alpha * p1[0] + beta * p1[1] + gamma_ * p1val, delta));
1738  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p2[0] + beta * p2[1] + gamma_ * p2val, delta));
1739  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p3[0] + beta * p3[1] + gamma_ * p3val, delta));
1740  assert(SCIPisInfinity(scip, delta) || SCIPisFeasEQ(scip, alpha * p4[0] + beta * p4[1] + gamma_ * p4val, delta));
1741  }
1742  }
1743 
1744  SCIPdebugMessage("alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
1745 
1746  /* check if bad luck: should not happen if xlb != xub and ylb != yub and numerics are fine */
1747  if( SCIPisInfinity(scip, delta) || SCIPisZero(scip, gamma_) )
1748  return SCIP_OKAY;
1749  assert(!SCIPisNegative(scip, gamma_));
1750 
1751  /* flip hyperplane */
1752  if( !doover )
1753  gamma_ = -gamma_;
1754 
1755  *coefx = -alpha / gamma_;
1756  *coefy = -beta / gamma_;
1757  *constant = delta / gamma_;
1758 
1759  *success = TRUE;
1760 
1761  return SCIP_OKAY;
1762 }
1763 
1764 /** generates a cut for lhs <= f(x,y) + c*z with f(x,y) being convex */
1765 static
1767  SCIP* scip, /**< SCIP data structure */
1768  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
1769  SCIP_CONS* cons, /**< constraint */
1770  SCIP_Real* x0y0, /**< reference values for nonlinear variables */
1771  SCIP_ROW** row /**< storage for cut */
1772  )
1773 {
1774  SCIP_CONSDATA* consdata;
1775  SCIP_Real coefs[2];
1776  SCIP_Real constant = SCIP_INVALID;
1777  SCIP_Bool success;
1778 
1779  assert(scip != NULL);
1780  assert(cons != NULL);
1781  assert(row != NULL);
1782 
1783  *row = NULL;
1784 
1785  consdata = SCIPconsGetData(cons);
1786  assert(consdata != NULL);
1787 
1788  SCIP_CALL( generateEstimatingHyperplane(scip, exprinterpreter, consdata->f, TRUE, x0y0, &coefs[0], &coefs[1], &constant, &success) );
1789 
1790  if( success )
1791  {
1792  assert(!SCIPisInfinity(scip, -consdata->lhs));
1793  assert(SCIPisFinite(coefs[0]));
1794  assert(SCIPisFinite(coefs[1]));
1795  assert(SCIPisFinite(constant));
1796 
1797  SCIP_CALL( SCIPcreateRowCons(scip, row, SCIPconsGetHdlr(cons), "bivaroveresthyperplanecut", 0, NULL, NULL, consdata->lhs - constant, SCIPinfinity(scip), TRUE, FALSE, TRUE) );
1798 
1799  SCIP_CALL( SCIPaddVarsToRow(scip, *row, 2, SCIPexprtreeGetVars(consdata->f), coefs) );
1800  if( consdata->z != NULL )
1801  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
1802  }
1803  else
1804  {
1805  SCIPdebugMessage("failed to compute overestimator for all-convex constraint <%s>\n", SCIPconsGetName(cons));
1806  }
1807 
1808  return SCIP_OKAY;
1809 }
1810 
1811 /** generates a linear underestimator for f(x,y)
1812  * when the generators of the underestimating segment
1813  * are contained in y=ylb and y=yub.
1814  * Generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
1815  * alpha * x + beta * y - delta <= gamma * f(x,y)
1816  */
1817 static
1819  SCIP* scip, /**< SCIP data structure */
1820  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
1821  SCIP_EXPRTREE* f, /**< function f(x,y) */
1822  SCIP_Real* xyref, /**< reference values for x and y */
1823  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
1824  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
1825  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
1826  )
1827 {
1828  SCIP_VAR* x;
1829  SCIP_VAR* y;
1830  SCIP_Real xval;
1831  SCIP_Real xlb;
1832  SCIP_Real xub;
1833  SCIP_Real yval;
1834  SCIP_Real ylb;
1835  SCIP_Real yub;
1836 
1837  SCIP_Real t;
1838  SCIP_EXPR* vred;
1839  SCIP_EXPRTREE* vredtree;
1840  SCIP_EXPR* e1;
1841  SCIP_EXPR* e2;
1842  SCIP_EXPR* tmp;
1843  SCIP_EXPR* tmp2;
1844  SCIP_EXPR* subst[2];
1845 
1846  SCIP_Real sval;
1847  SCIP_Real slb;
1848  SCIP_Real sub;
1849  SCIP_Real rval;
1850 
1851  SCIP_Real frval;
1852  SCIP_Real fsval;
1853  SCIP_Real x0y0[2];
1854  SCIP_Real grad[2];
1855 
1856  assert(scip != NULL);
1857  assert(exprinterpreter != NULL);
1858  assert(f != NULL);
1859  assert(xyref != NULL);
1860  assert(success != NULL);
1861 
1862  x = SCIPexprtreeGetVars(f)[0];
1863  y = SCIPexprtreeGetVars(f)[1];
1864 
1865  xlb = SCIPvarGetLbLocal(x);
1866  xub = SCIPvarGetUbLocal(x);
1867 
1868  ylb = SCIPvarGetLbLocal(y);
1869  yub = SCIPvarGetUbLocal(y);
1870 
1871  xval = xyref[0];
1872  yval = xyref[1];
1873 
1874  *success = FALSE;
1875 
1876  /* check that variables are not unbounded or fixed and reference point is in interior */
1877  assert(!SCIPisInfinity(scip, -xlb));
1878  assert(!SCIPisInfinity(scip, xub));
1879  assert(!SCIPisInfinity(scip, -ylb));
1880  assert(!SCIPisInfinity(scip, yub));
1881  assert(!SCIPisEQ(scip,xlb,xub));
1882  assert(!SCIPisEQ(scip,ylb,yub));
1883  assert(!SCIPisEQ(scip,xlb,xval));
1884  assert(!SCIPisEQ(scip,xub,xval));
1885  assert(!SCIPisEQ(scip,ylb,yval));
1886  assert(!SCIPisEQ(scip,yub,yval));
1887 
1888  SCIPdebugMessage("f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
1890  SCIPdebugPrintf("\n");
1891 
1892  t = (yub - yval) / (yub - ylb);
1893 
1894  /* construct v_red(s) := t f(1/t xval + (1-1/t) s, ylb) + (1-t) f(s, yub) */
1895 
1896  /* construct e1 := f(1/t xval + (1-1/t) s, ylb) */
1897  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e1, SCIPexprtreeGetRoot(f)) ); /* e1 = f(x,y) */
1898 
1899  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_VARIDX, 0) ); /* tmp = s */
1900  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp2, SCIP_EXPR_CONST, 1.0 - 1.0 / t) ); /* tmp2 = 1-1/t */
1901  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_MUL, tmp, tmp2) ); /* tmp = (1-1/t)*s */
1902  if( xval != 0.0 )
1903  {
1904  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp2, SCIP_EXPR_CONST, 1/t*xval) ); /* tmp2 = 1/t*xval */
1905  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_PLUS, tmp, tmp2) ); /* tmp = 1/t*xval + (1-1/t)*s */
1906  }
1907  subst[0] = tmp;
1908 
1909  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, ylb) ); /* tmp = ylb */
1910 
1911  assert(SCIPexprGetOperator(e1) != SCIP_EXPR_VARIDX); /* substitute cannot substitute the root node, but f should not be a single variable anyway */
1912  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e1, subst) ); /* e1 = f(1/t*xval + (1-1/t)*s, ylb) */
1913 
1914  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
1915  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
1916 
1917  /* construct e2 := f(s, yub) */
1918  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e2, SCIPexprtreeGetRoot(f)) ); /* e2 = f(x,y) */
1919 
1920  subst[0] = NULL;
1921 
1922  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, yub) );
1923 
1924  assert(SCIPexprGetOperator(e2) != SCIP_EXPR_VARIDX); /* substitute cannot substitute the root node, but f should not be a single variable anyway */
1925  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e2, subst) ); /* e2 = f(s,yub) */
1926 
1927  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
1928 
1929  /* construct vred := t * e1 + (1-t) * e2 */
1930  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, t) ); /* tmp = t */
1931  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e1, SCIP_EXPR_MUL, e1, tmp) ); /* e1 = t * f(1/t*xval+(1-1/t)*s,ylb) */
1932 
1933  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0 - t) ); /* tmp = 1 - t */
1934  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &e2, SCIP_EXPR_MUL, e2, tmp) ); /* e2 = (1-t) * f(s, yub) */
1935 
1936  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &vred, SCIP_EXPR_PLUS, e1, e2) );
1937  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &vredtree, vred, 1, 0, NULL) );
1938 
1939  SCIP_CALL( SCIPexprintCompile(exprinterpreter, vredtree) );
1940 
1941  /* compute bounds on s */
1942  slb = (yval - yub) / (ylb - yval) * (xval / t - xub);
1943  sub = (yval - yub) / (ylb - yval) * (xval / t - xlb);
1944  if( slb < xlb )
1945  slb = xlb;
1946  if( sub > xub )
1947  sub = xub;
1948 
1949  /* find s in [slb, sub] such that vred'(s) = 0 */
1950  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vredtree, 0.0, slb, sub, &sval, success) );
1951 
1952  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
1953 
1954  if( *success == FALSE )
1955  {
1956  /* something went wrong when computing s */
1957  return SCIP_OKAY;
1958  }
1959 
1960  /* compute r from s */
1961  rval = 1.0 / t * xval + (1.0 - 1.0 / t) * sval;
1962  assert(SCIPisFeasGE(scip, rval, xlb));
1963  assert(SCIPisFeasLE(scip, rval, xub));
1964  rval = MAX(xlb, MIN(rval, xub));
1965 
1966  /* compute f(sval, yub) */
1967  x0y0[0] = sval;
1968  x0y0[1] = yub;
1969  SCIP_CALL( SCIPexprtreeEval(f, x0y0, &fsval) );
1970 
1971  /* compute f(rval, ylb) */
1972  x0y0[0] = rval;
1973  x0y0[1] = ylb;
1974  SCIP_CALL( SCIPexprtreeEval(f, x0y0, &frval) );
1975 
1976  if( !SCIPisEQ(scip, sval, xlb) && !SCIPisEQ(scip, sval, xub) )
1977  {
1978  x0y0[0] = sval;
1979  x0y0[1] = yub;
1980 
1981  /* compute f'(xbar, ybar) */
1982  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad) );
1983  }
1984  else if( !SCIPisEQ(scip, rval, xlb) && !SCIPisEQ(scip, rval, xub) )
1985  {
1986  x0y0[0] = rval;
1987  x0y0[1] = ylb;
1988 
1989  /* compute f'(xbar, ybar) */
1990  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad) );
1991  }
1992  else
1993  {
1994  /* rare case
1995  * both points (sval, yub) and (rval, ylb) should yield valid inequality
1996  * for now, just take the first one, if differentiable, otherwise second one */
1997  x0y0[0] = sval;
1998  x0y0[1] = yub;
1999 
2000  /* compute f'(xbar, ybar) */
2001  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad) );
2002 
2003  if( !SCIPisFinite(grad[0]) )
2004  {
2005  x0y0[0] = rval;
2006  x0y0[1] = ylb;
2007 
2008  /* compute f'(xbar, ybar) */
2009  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad) );
2010  }
2011  }
2012 
2013  /* compute vred(s) = t * f(rval, ylb) + (1-t) * f(s, yub) */
2014  /* SCIP_CALL( SCIPexprtreeEval(vredtree, &sval, &vredval) ); */
2015  *convenvvalue = t * frval + (1.0 - t) * fsval;
2016 
2017  SCIPdebugMessage("Parallel: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
2018  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);
2019  SCIPdebugMessage("(r,ylb)=(%g,%g), (s,yub)=(%g,%g), vredval=%g\n",rval,ylb,sval,yub,*convenvvalue);
2020 
2021  if( !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
2022  {
2023  SCIPdebugMessage("f not differentiable in (x0,y0) w.r.t. x\n");
2024  return SCIP_OKAY;
2025  }
2026 
2027  /* compute cut coefficients */
2028  cutcoeff[0] = (yub - ylb) * grad[0];
2029  cutcoeff[1] = fsval - frval - (sval - rval) * grad[0];
2030  cutcoeff[2] = yub - ylb;
2031  cutcoeff[3] = cutcoeff[0] * xval + cutcoeff[1] * yval - cutcoeff[2] * *convenvvalue;
2032 
2033  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]);
2034 
2035  *success = TRUE;
2036 
2037  return SCIP_OKAY;
2038 }
2039 
2040 
2041 /** generates a linear underestimator for f(x,y)
2042  * with f(x,y) being convex in x and convex in y.
2043  * The segmenent connects orthogonal facets: Either (x=l_x,y=l_y)
2044  * or (x=u_x,y=u_y).
2045  * generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2046  * alpha * x + beta * y - delta <= gamma * f(x,y)
2047  */
2048 static
2050  SCIP* scip, /**< SCIP data structure */
2051  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
2052  SCIP_EXPRTREE* f, /**< function f(x,y) */
2053  SCIP_Real* xyref, /**< reference values for x and y */
2054  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
2055  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
2056  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
2057  )
2058 {
2059  SCIP_VAR* x;
2060  SCIP_VAR* y;
2061  SCIP_Real xval;
2062  SCIP_Real xlb;
2063  SCIP_Real xub;
2064  SCIP_Real yval;
2065  SCIP_Real ylb;
2066  SCIP_Real yub;
2067 
2068  SCIP_Real x0y0[2];
2069 
2070  SCIP_EXPR* vred;
2071  SCIP_EXPRTREE* vredtree;
2072  SCIP_EXPR* e1;
2073  SCIP_EXPR* e2;
2074  SCIP_EXPR* tmp;
2075  SCIP_EXPR* expr;
2076  SCIP_EXPR* expr1;
2077  SCIP_EXPR* expr2;
2078  SCIP_EXPR* subst[2];
2079 
2080  SCIP_Real tval, tlb, tub;
2081  SCIP_Real sval;
2082  SCIP_Real rval;
2083 
2084  SCIP_Real frval,fsval;
2085  SCIP_Real grad_rval[2];
2086  SCIP_Real grad_sval[2];
2087 
2088  assert(scip != NULL);
2089  assert(exprinterpreter != NULL);
2090  assert(f != NULL);
2091  assert(convenvvalue != NULL);
2092  assert(success != NULL);
2093 
2094  x = SCIPexprtreeGetVars(f)[0];
2095  y = SCIPexprtreeGetVars(f)[1];
2096 
2097  xlb = SCIPvarGetLbLocal(x);
2098  xub = SCIPvarGetUbLocal(x);
2099 
2100  ylb = SCIPvarGetLbLocal(y);
2101  yub = SCIPvarGetUbLocal(y);
2102 
2103  xval = xyref[0];
2104  yval = xyref[1];
2105 
2106  /* check that variables are not unbounded or fixed and reference point is in interior */
2107  assert(!SCIPisInfinity(scip, -xlb));
2108  assert(!SCIPisInfinity(scip, xub));
2109  assert(!SCIPisInfinity(scip, -ylb));
2110  assert(!SCIPisInfinity(scip, yub));
2111  assert(!SCIPisEQ(scip,xlb,xub));
2112  assert(!SCIPisEQ(scip,ylb,yub));
2113  assert(!SCIPisEQ(scip,xlb,xval));
2114  assert(!SCIPisEQ(scip,xub,xval));
2115  assert(!SCIPisEQ(scip,ylb,yval));
2116  assert(!SCIPisEQ(scip,yub,yval));
2117 
2118  *success = FALSE;
2119 
2120  SCIPdebugMessage("f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
2122  SCIPdebugPrintf("\n");
2123  SCIPdebugMessage("%s[%g,%g] = %g %s[%g,%g] = %g\n", SCIPvarGetName(x), xlb, xub, xval, SCIPvarGetName(y), ylb, yub, yval);
2124 
2125  /* check in which triangle the point (xval,yval) lies */
2126  if( yval <= (ylb-yub) / (xub-xlb) * (xval-xlb) + yub )
2127  {
2128  /* (xval,yval) lies in lower left triangle, i.e. region A_1 */
2129  /* construct v_red(t) := t f( xlb, (yval-(1-t)ylb)/t ) + (1-t)*f( (xval-xlb*t)/(1-t), ylb ) */
2130 
2131  /* construct e1 := f(xlb, ylb + (yval-ylb)/t) */
2132  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2133  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yval-ylb) ); /* tmp = yval-ylb */
2134  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, tmp, expr) ); /* expr = (yval-ylb) / t */
2135  if( ylb != 0.0 )
2136  {
2137  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, ylb) ); /* tmp = ylb */
2138  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, tmp) ); /* expr = ylb + (yval-ylb) / t */
2139  }
2140  subst[1] = expr;
2141 
2142  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_CONST, xlb) ); /* subst[0] = xlb */
2143 
2144  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e1, SCIPexprtreeGetRoot(f)) ); /* e1 = f(x,y) */
2145  assert(SCIPexprGetOperator(e1) != SCIP_EXPR_VARIDX); /* expr substitute vars cannot substitute the root node, but f should not be a single variable anyway */
2146  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e1, subst) ); /* e1 = f(xlb, ylb + (yval-ylb)/t) */
2147 
2148  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2149  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2150 
2151 
2152  /* construct e2 := f((xval-xlb*t)/(1-t), ylb) */
2153  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_VARIDX, 0) ); /* expr1 = t */
2154  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2155  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MINUS, tmp, expr1) ); /* expr1 = 1-t */
2156 
2157  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_VARIDX, 0) ); /* expr2 = t */
2158  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xlb) ); /* tmp = xlb */
2159  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, expr2, tmp) ); /* expr2 = xlb * t */
2160  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xval) ); /* tmp = xval */
2161  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MINUS, tmp, expr2) ); /* expr2 = xval - xlb * t */
2162 
2163  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, expr2, expr1) ); /* expr = (xval-t*xlb)/(1-t) */
2164  subst[0] = expr;
2165 
2166  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, ylb) ); /* subst[0] = ylb */
2167 
2168  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e2, SCIPexprtreeGetRoot(f)) ); /* e2 = f(x,y) */
2169  assert(SCIPexprGetOperator(e2) != SCIP_EXPR_VARIDX); /* expr substitute vars cannot substitute the root node, but f should not be a single variable anyway */
2170  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e2, subst) ); /* e2 = f((xval-xlb*t)/(1-t), ylb) */
2171 
2172  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2173  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2174 
2175 
2176  /* construct vred := t * e1 + (1-t) * e2 */
2177  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2178  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MUL, expr, e1) ); /* expr1 = t * e1*/
2179 
2180  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2181  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2182  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_MINUS, tmp, expr) ); /* expr = 1 - t */
2183  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, expr, e2) ); /* expr2 = (1-t) * e2 */
2184 
2185  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &vred, SCIP_EXPR_PLUS, expr1, expr2) );
2186  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &vredtree, vred, 1, 0, NULL) );
2187  SCIP_CALL( SCIPexprintCompile(exprinterpreter, vredtree) );
2188 
2189  /* compute bounds on t */
2190  tlb = (yval-ylb)/(yub-ylb);
2191  tub = (xub-xval)/(xub-xlb);
2192 
2193  /* find t in [lambalb, tub] such that vred'(t) = 0 */
2194  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vredtree, 0.0, tlb, tub, &tval, success) );
2195 
2196  /* computing the cut coefficients */
2197  if( *success == FALSE )
2198  {
2199  /* something went wrong when computing s */
2200  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2201  return SCIP_OKAY;
2202  }
2203 
2204  /* compute r and s from tval */
2205  rval = (yval-(1-tval)*ylb)/tval;
2206  rval = MAX(ylb, MIN(yub, rval));
2207  sval = (xval-xlb*tval)/(1-tval);
2208  sval = MAX(xlb, MIN(xub, sval));
2209 
2210  SCIPdebugMessage("LowerLeft: t[%g,%g] = %g -> r = %g, s = %g\n",tlb,tub,tval,rval,sval);
2211 
2212  /* compute vred(tval) */
2213  SCIP_CALL( SCIPexprtreeEval(vredtree, &tval, convenvvalue) );
2214 
2215  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2216 
2217  /* compute f(s, ylb) and f'(s, ylb) */
2218  x0y0[0] = sval;
2219  x0y0[1] = ylb;
2220  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad_sval) );
2221 
2222  /* compute f(xlb, r) and f'(xlb,r) */
2223  x0y0[0] = xlb;
2224  x0y0[1] = rval;
2225  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad_rval) );
2226 
2227  /* generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2228  * alpha * x + beta * y - delta <= gamma * f(x,y)
2229  * cf. Section 2.5.2 Aux.prob. 2 case (ii)
2230  */
2231  if( !SCIPisEQ(scip, sval, xub) )
2232  {
2233  /* use the x-axis to determine the second direction */
2234  if( !SCIPisFinite(grad_sval[0]) || SCIPisInfinity(scip, REALABS(grad_sval[0])) )
2235  {
2236  *success = FALSE;
2237  return SCIP_OKAY;
2238  }
2239  cutcoeff[0] = (rval-ylb) * grad_sval[0];
2240  cutcoeff[1] = (sval-xlb) * grad_sval[0] + frval - fsval;
2241  cutcoeff[2] = rval-ylb;
2242  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*rval-cutcoeff[2]*frval;
2243  }
2244  else if( !SCIPisEQ(scip,rval,yub) )
2245  {
2246  /* use the y-axis to determine the second direction */
2247  if( !SCIPisFinite(grad_rval[1]) || SCIPisInfinity(scip, REALABS(grad_rval[1])) )
2248  {
2249  *success = FALSE;
2250  return SCIP_OKAY;
2251  }
2252  cutcoeff[0] = (rval-ylb)*grad_rval[1]+fsval-frval;
2253  cutcoeff[1] = (sval-xlb)*grad_rval[1];
2254  cutcoeff[2] = sval-xlb;
2255  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*rval-cutcoeff[2]*frval;
2256  }
2257  else
2258  {
2259  /* the point lies on the segment between (xlb,yub) and (xub,ylb) */
2260  if( !SCIPisFinite(grad_sval[0]) || !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(MIN(grad_sval[0],grad_rval[0]))) )
2261  {
2262  /* FIXME maybe it is sufficient to have one of them finite, using that one for the MIN below? */
2263  *success = FALSE;
2264  return SCIP_OKAY;
2265  }
2266  cutcoeff[0] = (rval-ylb)* MIN(grad_sval[0],grad_rval[0]);
2267  cutcoeff[1] = (sval-xlb)* MIN(grad_sval[0],grad_rval[0])+frval-fsval;
2268  cutcoeff[2] = (rval-ylb);
2269  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*rval-cutcoeff[2]*frval;
2270  }
2271 
2272  SCIPdebugMessage("LowerLeft: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
2273  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);
2274  SCIPdebugMessage("(s,ylb)=(%g,%g) (xlb,r)=(%g,%g) t=%g, vredval=%g\n",sval,ylb,xlb,rval,tval,*convenvvalue);
2275  SCIPdebugMessage("LowerLeft: cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=%g,cutcoeff[3]=%g\n",cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
2276  }
2277  else
2278  {
2279  /* (xval,yval) lies in the upper right triangle, i.e region A_2 */
2280  /* construct v_red(t) := t f( xub, yub + (yval-yub)/t ) + (1-t)*f((xval-xub*t)/(1-t), yub) */
2281 
2282  /* construct e1 := f(xub, yub+(yval-yub)/t) */
2283  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t*/
2284  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yval-yub) ); /* tmp = yval-yub*/
2285  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, tmp, expr) ); /* expr = (yval-yub) / t */
2286  if( yub != 0.0 )
2287  {
2288  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yub) ); /* tmp = yub */
2289  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, tmp) ); /* expr = yub + (yval-yub)/t */
2290  }
2291  subst[1] = expr;
2292 
2293  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_CONST, xub) ); /* tmp = xub */
2294 
2295  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e1, SCIPexprtreeGetRoot(f)) ); /* e1 = f(x,y) */
2296  assert(SCIPexprGetOperator(e1) != SCIP_EXPR_VARIDX); /* cannot substitute root */
2297  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e1, subst) ); /* e1 = f(xub, yub + (yval-yub)/t) */
2298 
2299  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2300  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2301 
2302  /* construct e2 := f((xval-t*xub)/(1-t), yub) */
2303  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_VARIDX, 0) ); /* expr1 = t */
2304  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2305  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MINUS, tmp, expr1) ); /* expr1 = 1-t */
2306 
2307  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_VARIDX, 0) ); /* expr2 = t */
2308  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xub) ); /* tmp = xub */
2309  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, expr2, tmp) ); /* expr2 = xub * t */
2310  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xval) ); /* tmp = xval */
2311  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MINUS, tmp, expr2) ); /* expr2 = xval - xub * t */
2312 
2313  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, expr2, expr1) ); /* expr = (xval-t*xub)/(1-t) */
2314  subst[0] = expr;
2315 
2316  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, yub) ); /* tmp = yub */
2317 
2318  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e2, SCIPexprtreeGetRoot(f)) ); /* e2 = f(x,y) */
2319  assert(SCIPexprGetOperator(e2) != SCIP_EXPR_VARIDX); /* cannot substitute root */
2320  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e2, subst) ); /* e2 = f((xval-t*xub)/(1-t), yub) */
2321 
2322  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2323  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2324 
2325  /* construct vred := t * e1 + (1-t) * e2 */
2326  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2327  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MUL, e1, expr) ); /* expr1 = t * e1*/
2328 
2329  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2330  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2331  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_MINUS, tmp, expr) ); /* expr = 1-t */
2332  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, e2, expr) ); /* expr2 = (1-t) * e2*/
2333 
2334 
2335  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &vred, SCIP_EXPR_PLUS, expr1, expr2) );
2336  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &vredtree, vred, 1, 0, NULL) );
2337  SCIP_CALL( SCIPexprintCompile(exprinterpreter, vredtree) );
2338 
2339  /* compute bounds on t */
2340  tlb = (yub-yval)/(yub-ylb);
2341  tub = (xval-xlb)/(xub-xlb);
2342 
2343  /* find t in [tlb, tub] such that vred'(t) = 0 */
2344  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vredtree, 0.0, tlb, tub, &tval, success) );
2345 
2346  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2347 
2348  if( *success == FALSE )
2349  {
2350  /* something went wrong when computing s */
2351  return SCIP_OKAY;
2352  }
2353 
2354  /* computing the cut coefficients */
2355 
2356  /* compute r and s from tval */
2357  rval = (yval-(1.0-tval)*yub)/tval;
2358  assert(SCIPisFeasGE(scip, rval, ylb));
2359  assert(SCIPisFeasLE(scip, rval, yub));
2360  rval = MAX(ylb, MIN(yub, rval));
2361 
2362  sval = (xval-xub*tval)/(1.0-tval);
2363  assert(SCIPisFeasGE(scip, sval, xlb));
2364  assert(SCIPisFeasLE(scip, sval, xub));
2365  sval = MAX(xlb, MIN(xub, sval));
2366 
2367  /* compute f(xub,r) and f'(xub,r) */
2368  x0y0[0] = xub;
2369  x0y0[1] = rval;
2370  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad_rval) );
2371 
2372  /* compute f(s,yub) and f'(s,yub) */
2373  x0y0[0] = sval;
2374  x0y0[1] = yub;
2375  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad_sval) );
2376 
2377  /* compute vred(tval) */
2378  *convenvvalue = tval * frval + (1.0-tval) * fsval;
2379 
2380  /* generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2381  * alpha * x + beta * y - delta <= gamma * f(x,y) */
2382 
2383  if( !SCIPisEQ(scip, sval, xlb) )
2384  {
2385  /* use the x-axis to determine the second direction */
2386  if( !SCIPisFinite(grad_sval[0]) || SCIPisInfinity(scip, REALABS(grad_sval[0])) )
2387  {
2388  *success = FALSE;
2389  return SCIP_OKAY;
2390  }
2391 
2392  cutcoeff[0] = (yub-rval)*grad_sval[0];
2393  cutcoeff[1] = (xub-sval)*grad_sval[0]+fsval-frval;
2394  cutcoeff[2] = yub-rval;
2395  cutcoeff[3] = cutcoeff[0]*sval+cutcoeff[1]*yub-cutcoeff[2]*fsval;
2396  }
2397  else if( !SCIPisEQ(scip,rval,ylb) )
2398  {
2399  /* use the y-axis to determine the second direction */
2400  if( !SCIPisFinite(grad_rval[1]) || SCIPisInfinity(scip, REALABS(grad_rval[1])) )
2401  {
2402  *success = FALSE;
2403  return SCIP_OKAY;
2404  }
2405  cutcoeff[0] = (yub-rval)*grad_rval[1]+frval-fsval;
2406  cutcoeff[1] = (xub-sval)*grad_rval[1];
2407  cutcoeff[2] = xub-sval;
2408  cutcoeff[3] = cutcoeff[0]*sval+cutcoeff[1]*yub-cutcoeff[2]*fsval;
2409  }
2410  else
2411  {
2412  /* the point lies on the segment between (xlb,yub) and (xub,ylb)
2413  * due to numerics, we get into this case here instead in the LowerLeft
2414  */
2415  assert(SCIPisFeasLE(scip, yval, (ylb-yub) / (xub-xlb) * (xval-xlb) + yub));
2416  if( !SCIPisFinite(grad_sval[0]) || !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(MIN(grad_sval[0],grad_rval[0]))) )
2417  {
2418  /* FIXME maybe it is sufficient to have one of them finite, using that one for the MIN below? */
2419  *success = FALSE;
2420  return SCIP_OKAY;
2421  }
2422 
2423  cutcoeff[0] = (yub-rval)*MIN(grad_sval[0],grad_rval[0]);
2424  cutcoeff[1] = (xub-sval)*MIN(grad_sval[0],grad_rval[0])+fsval-frval;
2425  cutcoeff[2] = xub-sval;
2426  cutcoeff[3] = cutcoeff[0]*sval+cutcoeff[1]*yub-cutcoeff[2]*fsval;
2427  }
2428 
2429  SCIPdebugMessage("UpperRight: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
2430  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);
2431  SCIPdebugMessage("(s,yub)=(%g,%g) (xub,r)=(%g,%g) t=%g, vredval=%g\n",sval,yub,xub,rval,tval,*convenvvalue);
2432  SCIPdebugMessage("UpperRight: cutcoeff[0]=%g, cutcoeff[1]=%g, cutcoeff[2]=%g, cutcoeff[3]=%g\n",cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
2433  }
2434 
2435  return SCIP_OKAY;
2436 }
2437 
2438 /** generates a linear underestimator for f(x,y) with f(x,y) being convex in x and convex in y
2439  * generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2440  * alpha * x + beta * y - delta <= gamma * f(x,y)
2441  */
2442 static
2444  SCIP* scip, /**< SCIP data structure */
2445  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
2446  SCIP_EXPRTREE* f, /**< function f(x,y) */
2447  SCIP_Real* xyref, /**< reference values for x and y */
2448  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
2449  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
2450  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
2451  )
2452 {
2453  SCIP_VAR* x;
2454  SCIP_VAR* y;
2455  SCIP_Real xval;
2456  SCIP_Real xlb;
2457  SCIP_Real xub;
2458  SCIP_Real yval;
2459  SCIP_Real ylb;
2460  SCIP_Real yub;
2461  SCIP_Real x0y0[2];
2462 
2463  SCIP_EXPR* vred;
2464  SCIP_EXPRTREE* vredtree;
2465  SCIP_EXPR* e1;
2466  SCIP_EXPR* e2;
2467  SCIP_EXPR* tmp;
2468  SCIP_EXPR* expr;
2469  SCIP_EXPR* expr1;
2470  SCIP_EXPR* expr2;
2471  SCIP_EXPR* subst[2];
2472 
2473  SCIP_Real tval;
2474  SCIP_Real tlb;
2475  SCIP_Real tub;
2476  SCIP_Real sval;
2477  SCIP_Real rval;
2478 
2479  SCIP_Real frval;
2480  SCIP_Real fsval;
2481  SCIP_Real grad_rval[2];
2482  SCIP_Real grad_sval[2];
2483 
2484  assert(scip != NULL);
2485  assert(exprinterpreter != NULL);
2486  assert(f != NULL);
2487  assert(convenvvalue != NULL);
2488  assert(success != NULL);
2489 
2490  x = SCIPexprtreeGetVars(f)[0];
2491  y = SCIPexprtreeGetVars(f)[1];
2492 
2493  xlb = SCIPvarGetLbLocal(x);
2494  xub = SCIPvarGetUbLocal(x);
2495 
2496  ylb = SCIPvarGetLbLocal(y);
2497  yub = SCIPvarGetUbLocal(y);
2498 
2499  xval = xyref[0];
2500  yval = xyref[1];
2501 
2502  /* check that variables are not unbounded or fixed and reference point is in interior */
2503  assert(!SCIPisInfinity(scip, -xlb));
2504  assert(!SCIPisInfinity(scip, xub));
2505  assert(!SCIPisInfinity(scip, -ylb));
2506  assert(!SCIPisInfinity(scip, yub));
2507  assert(!SCIPisEQ(scip,xlb,xub));
2508  assert(!SCIPisEQ(scip,ylb,yub));
2509  assert(!SCIPisEQ(scip,xlb,xval));
2510  assert(!SCIPisEQ(scip,xub,xval));
2511  assert(!SCIPisEQ(scip,ylb,yval));
2512  assert(!SCIPisEQ(scip,yub,yval));
2513 
2514  *success = FALSE;
2515 
2516  SCIPdebugMessage("f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
2518  SCIPdebugPrintf("\n");
2519 
2520  /* check in which triangle the point (xval,yval) lies */
2521  if( yval <= (yub-ylb)/(xub-xlb)*(xval-xlb)+ylb )
2522  {
2523  /* lower right triangle, i.e. region A_2 */
2524  /* construct v_red(t) := t f( xub+(xval-xub)/t, ylb ) + (1-t)*f( xub, (yval-ylb*t)/(1-t)) */
2525 
2526  /* construct e1:= f(xub+(xval-xub)/t, ylb) */
2527  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2528  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xval-xub) ); /* tmp = xval-xub */
2529  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, tmp, expr) ); /* expr = (xval-xub)/t */
2530  if( xub != 0.0 )
2531  {
2532  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xub) ); /* tmp = xub */
2533  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, tmp) ); /* expr = xub + (xval-xub)/t */
2534  }
2535  subst[0] = expr;
2536 
2537  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, ylb) ); /* subst[1] = ylb */
2538 
2539  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e1, SCIPexprtreeGetRoot(f)) ); /* e1 = f(x,y) */
2540  assert(SCIPexprGetOperator(e1) != SCIP_EXPR_VARIDX);
2541  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e1, subst) ); /* e1 = f(xub + (xval-xub)/t, ylb) */
2542 
2543  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2544  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2545 
2546 
2547  /* construct e2 := f(xub, (yval-t*ylb)/(1-t)) */
2548  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_VARIDX, 0) ); /* expr1 = t */
2549  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2550  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MINUS, tmp, expr1) ); /* expr1 = 1-t */
2551 
2552  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_VARIDX, 0) ); /* expr2 = t */
2553  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, ylb) ); /* tmp = ylb */
2554  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, expr2, tmp) ); /* expr2 = ylb * t */
2555  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yval) ); /* tmp = yval */
2556  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MINUS, tmp, expr2) ); /* expr2 = yval - ylb * t */
2557 
2558  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, expr2, expr1) ); /* expr = (yval-t*ylb)/(1-t) */
2559  subst[1] = expr;
2560 
2561  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_CONST, xub) ); /* subst[0] = xub */
2562 
2563  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e2, SCIPexprtreeGetRoot(f)) ); /* e2 = f(x,y) */
2564  assert(SCIPexprGetOperator(e2) != SCIP_EXPR_VARIDX);
2565  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e2, subst) ); /* e2 = f(xub, (yval-t*ylb)/(1-t)) */
2566 
2567  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2568  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2569 
2570 
2571  /* construct vred := t * e1 + (1-t) * e2 */
2572  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2573  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MUL, e1, expr) ); /* expr1 = t * e1*/
2574 
2575 
2576  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2577  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2578  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_MINUS, tmp, expr) ); /* expr = 1-t */
2579  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, e2, expr) ); /* expr2 = (1-t) * e2*/
2580 
2581 
2582  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &vred, SCIP_EXPR_PLUS, expr1, expr2) );
2583  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &vredtree, vred, 1, 0, NULL) );
2584  SCIP_CALL( SCIPexprintCompile(exprinterpreter, vredtree) );
2585 
2586 
2587  /* compute bounds on t */
2588  tlb = (xub-xval)/(xub-xlb);
2589  tub = (yub-yval)/(yub-ylb);
2590 
2591  /* find t in [tlb, tub] such that vred'(t) = 0 */
2592  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vredtree, 0.0, tlb, tub, &tval, success) );
2593 
2594  if( *success == FALSE )
2595  {
2596  /* something went wrong when computing t */
2597  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2598  return SCIP_OKAY;
2599  }
2600 
2601  /* computing the cut coefficients */
2602 
2603  /* compute r and s from tval */
2604  rval = xub+(xval-xub)/tval;
2605  rval = MAX(xlb, MIN(xub, rval));
2606  sval = (yval-tval*ylb)/(1-tval);
2607  sval = MAX(ylb, MIN(yub, sval));
2608 
2609  /* compute vred(tval) */
2610  SCIP_CALL( SCIPexprtreeEval(vredtree, &tval, convenvvalue) );
2611 
2612  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2613 
2614  /* compute f(r, ylb) and f'(r, ylb) */
2615  x0y0[0] = rval;
2616  x0y0[1] = ylb;
2617  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad_rval) );
2618 
2619  /* compute f(xub, s) and f'(xub,s) */
2620  x0y0[0] = xub;
2621  x0y0[1] = sval;
2622  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad_sval) );
2623 
2624  /* generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2625  * alpha * x + beta * y - delta <= gamma * f(x,y) */
2626  if( !(SCIPisEQ(scip,rval,xlb)) )
2627  {
2628  /* take the slope along the x-axis and the slope between the points */
2629  if( !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(grad_rval[0])) )
2630  {
2631  *success = FALSE;
2632  return SCIP_OKAY;
2633  }
2634  cutcoeff[0] = (sval-ylb)*grad_rval[0];
2635  cutcoeff[1] = (rval-xub)*grad_rval[0]-frval+fsval;
2636  cutcoeff[2] = sval-ylb;
2637  cutcoeff[3] = cutcoeff[0]*xub+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2638  }
2639  else if( !(SCIPisEQ(scip,sval,yub)) )
2640  {
2641  /* take the slope along the y-axis and the slope between the points */
2642  if( !SCIPisFinite(grad_sval[1]) || SCIPisInfinity(scip, REALABS(grad_sval[1])) )
2643  {
2644  *success = FALSE;
2645  return SCIP_OKAY;
2646  }
2647  cutcoeff[0] = (ylb-sval)*grad_sval[1]-frval+fsval;
2648  cutcoeff[1] = (xub-rval)*grad_sval[1];
2649  cutcoeff[2] = xub-rval;
2650  cutcoeff[3] = cutcoeff[0]*xub+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2651  }
2652  else
2653  {
2654  /* the point lies on the segment between (xlb,yub) and (xub,ylb) */
2655  if( !SCIPisFinite(grad_sval[0]) || !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(MIN(grad_sval[0],grad_rval[0]))) )
2656  {
2657  /* FIXME maybe it is sufficient to have one of them finite, using that one for the MIN below? */
2658  *success = FALSE;
2659  return SCIP_OKAY;
2660  }
2661  cutcoeff[0] = (sval-ylb)*MIN(grad_sval[0],grad_rval[0]);
2662  cutcoeff[1] = (rval-xub)*MIN(grad_sval[0],grad_rval[0])+fsval-frval;
2663  cutcoeff[2] = sval-ylb;
2664  cutcoeff[3] = cutcoeff[0]*xub+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2665  }
2666 
2667 
2668  SCIPdebugMessage("LowerRight: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
2669  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);
2670  SCIPdebugMessage("LowerRight: (r,ylb)=(%g,%g) (xub,sval)=(%g,%g) vredval=%g\n",rval,ylb,xub,sval,*convenvvalue);
2671  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]);
2672 
2673  }
2674  else
2675  {
2676  /* (xval,yval) lie in the upper left triangle, i.e. region A_1 */
2677  /* construct v_red(t) := t f( xlb+(xval-xlb)/t, yub ) + (1-t)*f( xlb, (yval-yub*t)/(1-t) ) */
2678 
2679  /* construct e1:= f(xlb+(xval-xlb)/t, yub) */
2680  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2681  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xval-xlb) ); /* tmp = xval-xlb */
2682  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, tmp, expr) ); /* expr = (xval-xlb)/lambda */
2683  if( xlb != 0.0 )
2684  {
2685  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, xlb) ); /* tmp = xlb */
2686  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_PLUS, expr, tmp) ); /* expr = xlb + (xval-xlb)/t */
2687  }
2688  subst[0] = expr;
2689 
2690  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_CONST, yub) ); /* subst[1] = yub */
2691 
2692  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e1, SCIPexprtreeGetRoot(f)) ); /* e1 = f(x,y) */
2693  assert(SCIPexprGetOperator(e1) != SCIP_EXPR_VARIDX);
2694  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e1, subst) ); /* e1 = f(xlb + (xval-xlb)/t, yub) */
2695 
2696  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2697  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2698 
2699 
2700  /* construct e2 := f(xlb, (yval-t*yub)/(1-t) ) */
2701  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_VARIDX, 0) ); /* expr1 = t */
2702  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2703  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MINUS, tmp, expr1) ); /* expr1 = 1-t */
2704 
2705  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_VARIDX, 0) ); /* expr2 = t */
2706  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yub) ); /* tmp = yub */
2707  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, expr2, tmp) ); /* expr2 = yub * t */
2708  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, yval) ); /* tmp = yval */
2709  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MINUS, tmp, expr2) ); /* expr2 = yval - yub * t */
2710 
2711  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_DIV, expr2, expr1) ); /* expr = (yval-t*yub)/(1-t) */
2712  subst[1] = expr;
2713 
2714  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_CONST, xlb) ); /* subst[0] = xlb */
2715 
2716  SCIP_CALL( SCIPexprCopyDeep(SCIPblkmem(scip), &e2, SCIPexprtreeGetRoot(f)) ); /* e2 = f(x,y) */
2717  SCIP_CALL( SCIPexprSubstituteVars(SCIPblkmem(scip), e2, subst) ); /* e2 = f( xlb , (yval-t*yub)/(1-t) ) */
2718 
2719  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
2720  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
2721 
2722 
2723  /* construct vred := t * e1 + (1-t) * e2 */
2724  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2725  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr1, SCIP_EXPR_MUL, e1, expr) ); /* expr1 = t * e1*/
2726 
2727 
2728  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_VARIDX, 0) ); /* expr = t */
2729  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &tmp, SCIP_EXPR_CONST, 1.0) ); /* tmp = 1.0 */
2730  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr, SCIP_EXPR_MINUS, tmp, expr) ); /* expr = 1-t */
2731  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &expr2, SCIP_EXPR_MUL, e2, expr) ); /* expr2 = (1-t) * e2*/
2732 
2733 
2734  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &vred, SCIP_EXPR_PLUS, expr1, expr2) );
2735  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &vredtree, vred, 1, 0, NULL) );
2736  SCIP_CALL( SCIPexprintCompile(exprinterpreter, vredtree) );
2737 
2738 
2739  /* compute bounds on lambda */
2740  tlb = (xval-xlb)/(xub-xlb);
2741  tub = (yval-ylb)/(yub-ylb);
2742 
2743  /* find t in [tlb, tub] such that vred'(t) = 0 */
2744  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vredtree, 0.0, tlb, tub, &tval, success) );
2745 
2746  if( *success == FALSE )
2747  {
2748  /* something went wrong when computing s */
2749  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2750  return SCIP_OKAY;
2751  }
2752 
2753  /* computing the cut coefficients */
2754 
2755  /* compute r and s from tval */
2756  rval = xlb+(xval-xlb)/tval;
2757  rval = MAX(xlb, MIN(xub, rval));
2758  sval = (yval-tval*yub)/(1-tval);
2759  sval = MAX(ylb, MIN(yub, sval));
2760 
2761  /* compute vred(tval) */
2762  SCIP_CALL( SCIPexprtreeEval(vredtree, &tval, convenvvalue) );
2763 
2764  SCIP_CALL( SCIPexprtreeFree(&vredtree) );
2765 
2766  /* compute f(r, yub) and f'(r, yub) */
2767  x0y0[0] = rval;
2768  x0y0[1] = yub;
2769  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad_rval) );
2770 
2771  /* compute f(xlb, s) and f'(xlb, s) */
2772  x0y0[0] = xlb;
2773  x0y0[1] = sval;
2774  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad_sval) );
2775 
2776  /* generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that
2777  * alpha * x + beta * y - delta <= gamma * f(x,y) */
2778  if( !SCIPisEQ(scip,rval,xub) )
2779  {
2780  /* take the slope along the x-axis and the slope between the points */
2781  if( !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(grad_rval[0])) )
2782  {
2783  *success = FALSE;
2784  return SCIP_OKAY;
2785  }
2786  cutcoeff[0] = (yub-sval)*grad_rval[0];
2787  cutcoeff[1] = (xlb-rval)*grad_rval[0]-fsval+frval;
2788  cutcoeff[2] = yub-sval;
2789  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2790  }
2791  else if( !SCIPisEQ(scip,sval,ylb) )
2792  {
2793  /* take the slope along the y-axis and the slope between the points */
2794  if( !SCIPisFinite(grad_sval[1]) || SCIPisInfinity(scip, REALABS(grad_sval[1])) )
2795  {
2796  *success = FALSE;
2797  return SCIP_OKAY;
2798  }
2799  cutcoeff[0] = (sval-yub)*grad_sval[1]-fsval+frval;
2800  cutcoeff[1] = (rval-xlb)*grad_sval[1];
2801  cutcoeff[2] = rval-xlb;
2802  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2803  }
2804  else
2805  {
2806  /* the point lies on the segment between (xlb,yub) and (xub,ylb) */
2807  if( !SCIPisFinite(grad_sval[0]) || !SCIPisFinite(grad_rval[0]) || SCIPisInfinity(scip, REALABS(MIN(grad_rval[0],grad_sval[0]))) )
2808  {
2809  /* FIXME maybe it is sufficient to have one of them finite, using that one for the MIN below? */
2810  *success = FALSE;
2811  return SCIP_OKAY;
2812  }
2813  cutcoeff[0] = (yub-sval)*MIN(grad_rval[0],grad_sval[0]);
2814  cutcoeff[1] = (xlb-rval)*MIN(grad_rval[0],grad_sval[0])-fsval+frval;
2815  cutcoeff[2] = yub-sval;
2816  cutcoeff[3] = cutcoeff[0]*xlb+cutcoeff[1]*sval-cutcoeff[2]*fsval;
2817  }
2818 
2819  SCIPdebugMessage("UpperLeft: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
2820  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);
2821  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);
2822  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]);
2823  }
2824 
2825  return SCIP_OKAY;
2826 }
2827 
2828 
2829 /** generates a linear underestimator for f(x,y) with f(x,y) being STRICTLY convex in x and concave in y
2830  * generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that alpha * x + beta * y - delta <= gamma * f(x,y)
2831  */
2832 static
2834  SCIP* scip, /**< SCIP data structure */
2835  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
2836  SCIP_EXPRTREE* f, /**< function f(x,y) */
2837  SCIP_EXPRTREE* f_yfixed, /**< function f(x;y) with x variable and y parameter */
2838  SCIP_EXPRTREE* vred, /**< function vred(s;x0,y0,ylb,yub) */
2839  SCIP_Real xyref[2], /**< reference values for (x,y) */
2840  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
2841  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
2842  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
2843  )
2844 {
2845  SCIP_VAR* x;
2846  SCIP_VAR* y;
2847  SCIP_Real xval;
2848  SCIP_Real xlb;
2849  SCIP_Real xub;
2850  SCIP_Real yval;
2851  SCIP_Real ylb;
2852  SCIP_Real yub;
2853 
2854  assert(scip != NULL);
2855  assert(exprinterpreter != NULL);
2856  assert(f != NULL);
2857  assert(success != NULL);
2858  assert(xyref != NULL);
2859 
2860  x = SCIPexprtreeGetVars(f)[0];
2861  y = SCIPexprtreeGetVars(f)[1];
2862 
2863  xlb = SCIPvarGetLbLocal(x);
2864  xub = SCIPvarGetUbLocal(x);
2865 
2866  ylb = SCIPvarGetLbLocal(y);
2867  yub = SCIPvarGetUbLocal(y);
2868 
2869  xval = xyref[0];
2870  yval = xyref[1];
2871 
2872  /* reference point should not be outside of bounds */
2873  assert(SCIPisLE(scip, xlb, xval));
2874  assert(SCIPisGE(scip, xub, xval));
2875  assert(SCIPisLE(scip, ylb, yval));
2876  assert(SCIPisGE(scip, yub, yval));
2877 
2878  *success = FALSE;
2879 
2880  if( SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub) )
2881  {
2882  SCIPdebugMessage("skip convex-concave underestimator, since y is unbounded\n");
2883  return SCIP_OKAY;
2884  }
2885 
2886  SCIPdebugMessage("f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
2888  SCIPdebugPrintf("\n");
2889 
2890  if( SCIPisEQ(scip, xlb, xub) )
2891  {
2892  /* x is fixed, so function is now concave -> generate secant between (x, ylb) and (x, yub) */
2893  SCIP_Real xy[2];
2894  SCIP_Real f_ylb;
2895  SCIP_Real f_yub;
2896  SCIP_Real slope;
2897 
2898  if( SCIPisEQ(scip, ylb, yub) )
2899  {
2900  SCIPdebugMessage("skip convex-concave underestimator, since both x and y are fixed\n");
2901  return SCIP_OKAY;
2902  }
2903 
2904  /* get f(x, ylb) */
2905  xy[0] = xlb;
2906  xy[1] = ylb;
2907  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, xy, &f_ylb) );
2908 
2909  if( !SCIPisFinite(f_ylb) )
2910  {
2911  SCIPdebugMessage("cannot evaluate function at (xlb, ylb)\n");
2912  return SCIP_OKAY;
2913  }
2914 
2915  /* get f(x, yub) */
2916  xy[1] = yub;
2917  SCIP_CALL( SCIPexprintEval(exprinterpreter, f, xy, &f_yub) );
2918 
2919  if( !SCIPisFinite(f_yub) )
2920  {
2921  SCIPdebugMessage("cannot evaluate function at (xlb, yub)\n");
2922  return SCIP_OKAY;
2923  }
2924 
2925  slope = (f_yub - f_ylb) / (yub - ylb);
2926 
2927  /* secant is f(x,ylb) + slope * (y - ylb) <= f(x,y)*/
2928 
2929  cutcoeff[0] = 0.0; /* coefficient of x == 0 */
2930  cutcoeff[1] = slope; /* coefficient of y == slope */
2931  cutcoeff[2] = 1.0; /* coefficient of f(x,y) == 1.0 */
2932  cutcoeff[3] = -(f_ylb - slope * ylb); /* constant == -(f(x,ylb) - slope * ylb) */
2933  *convenvvalue = f_ylb+slope*(yval-ylb);
2934 
2935  *success = TRUE;
2936  return SCIP_OKAY;
2937  }
2938 
2939  if( SCIPisEQ(scip, ylb, yub) )
2940  {
2941  /* y is fixed, so function is now convex -> linearize in (xval, ylb) */
2942  SCIP_Real xy[2];
2943  SCIP_Real grad[2];
2944  SCIP_Real fval;
2945 
2946  xy[0] = xval;
2947  xy[1] = ylb;
2948  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xy, TRUE, &fval, grad) );
2949 
2950  if( !SCIPisFinite(fval) || !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
2951  {
2952  perturb(&xval, xlb, xub, 0.001);
2953  xy[0] = xval;
2954 
2955  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xy, TRUE, &fval, grad) );
2956 
2957  if( !SCIPisFinite(fval) || !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
2958  {
2959  SCIPdebugMessage("cannot evaluate function or derivative in (xval,ylb), also after perturbation\n");
2960  return SCIP_OKAY;
2961  }
2962  }
2963 
2964  /* linearization is f(xval,ylb) + df/dx(xval,ylb) * (x - xval) <= f(x,y) */
2965 
2966  cutcoeff[0] = grad[0]; /* coefficient of x == gradient in x */
2967  cutcoeff[1] = 0.0; /* coefficient of y == 0 */
2968  cutcoeff[2] = 1.0; /* coefficient of f(x,y) == 1.0 */
2969  cutcoeff[3] = -(fval - grad[0] * xval); /* constant == -(f(xval,ylb) - grad * xval) */
2970  *convenvvalue = fval;
2971 
2972  *success = TRUE;
2973  return SCIP_OKAY;
2974  }
2975 
2976  /* compute coefficients of a valid underestimating hyperplane */
2977 
2978  if( SCIPisFeasEQ(scip, xlb, xval) || SCIPisFeasEQ(scip, xub, xval) )
2979  {
2980  /* x is at it's lower or upper bound */
2981  SCIP_Real x0y0[2];
2982  SCIP_Real gradylb[2];
2983  SCIP_Real gradyub[2];
2984  SCIP_Real fvalylb;
2985  SCIP_Real fvalyub;
2986 
2987  xval = SCIPisFeasEQ(scip, xlb, xval) ? xlb : xub;
2988 
2989  /* compute f'(xval, ylb) and f'(xval, yub) */
2990  x0y0[0] = xval;
2991  x0y0[1] = ylb;
2992  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fvalylb, gradylb) );
2993 
2994  x0y0[1] = yub;
2995  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fvalyub, gradyub) );
2996 
2997  if( !SCIPisFinite(gradylb[0]) || !SCIPisFinite(gradyub[0]) || !SCIPisFinite(fvalylb) || !SCIPisFinite(fvalyub) ||
2998  SCIPisInfinity(scip, REALABS(gradylb[0])) || SCIPisInfinity(scip, REALABS(gradyub[0])) )
2999  {
3000  /* move xval inside domain and continue below, hope this will work better */
3001  perturb(&xval, xlb, xub, 0.001);
3002  }
3003  else
3004  {
3005  /* setup cut coefficients */
3006  if( xval == xlb ) /*lint !e777*/
3007  cutcoeff[0] = (yub - ylb) * MIN(gradylb[0], gradyub[0]);/* coefficient of x */
3008  else
3009  cutcoeff[0] = (yub - ylb) * MAX(gradylb[0], gradyub[0]);/* coefficient of x */
3010  cutcoeff[1] = fvalyub - fvalylb; /* coefficient of y */
3011  cutcoeff[2] = yub - ylb; /* coefficient of f(x,y) */
3012  cutcoeff[3] = cutcoeff[0] * xval + cutcoeff[1] * ylb - cutcoeff[2] * fvalylb; /* constant */
3013  *convenvvalue = fvalylb;
3014 
3015  SCIPdebugMessage("alpha: %g, beta: %g, gamma: %g, delta: %g\n",
3016  cutcoeff[0]/cutcoeff[2], cutcoeff[1]/cutcoeff[2], cutcoeff[2]/cutcoeff[2], cutcoeff[3]/cutcoeff[2]);
3017 
3018  *success = TRUE;
3019  return SCIP_OKAY;
3020  }
3021  }
3022 
3023  if( SCIPisFeasEQ(scip, ylb, yval) )
3024  {
3025  /* y is at it's lower bound */
3026  SCIP_Real x0y0[2];
3027  SCIP_Real grad[2];
3028  SCIP_Real xtilde;
3029  SCIP_Real fval, ftilde;
3030 
3031  /* these two cases should have been handled above */
3032  assert(!SCIPisEQ(scip, xlb, xval));
3033  assert(!SCIPisEQ(scip, xub, xval));
3034 
3035  assert(f_yfixed != NULL);
3036 
3037  /* compute f(xval, ylb) and f'(xval, ylb) */
3038  x0y0[0] = xval;
3039  x0y0[1] = ylb;
3040  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fval, grad) );
3041 
3042  if( !SCIPisFinite(fval) || !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
3043  {
3044  /* move yval inside domain and continue below, hope this will work better */
3045  perturb(&yval, ylb, yub, 0.001);
3046  }
3047  else
3048  {
3049  /* setup f(x,yub) */
3050  SCIPexprtreeSetParamVal(f_yfixed, 0, yub);
3051  SCIP_CALL( SCIPexprintNewParametrization(exprinterpreter, f_yfixed) );
3052 
3053  SCIPdebugMessage("f(x,yub) = ");
3055  SCIPdebugPrintf("\n");
3056 
3057  /* find xtilde in [xlb, xub] such that f'(xtilde,yub) = f'(xval,ylb) */
3058  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, f_yfixed, grad[0], xlb, xub, &xtilde, success) );
3059 
3060  if( !*success )
3061  {
3062  SCIP_Real fxlb;
3063  SCIP_Real fxub;
3064 
3065  /* if we could not find an xtilde such that f'(xtilde,yub) = f'(xval,ylb), then probably because f'(x,yub) is constant
3066  * in this case, choose xtilde from {xlb, xub} such that it maximizes f'(xtilde, yub) - grad[0]*xtilde
3067  */
3068  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xlb, &fxlb) );
3069  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xub, &fxub) );
3070 
3071  SCIPdebugMessage("couldn't solve deriv equ, compare f(%g,%g) - %g*%g = %g and f(%g,%g) - %g*%g = %g\n",
3072  xlb, ylb, grad[0], xlb, fxlb - grad[0] * xlb,
3073  xub, ylb, grad[0], xub, fxub - grad[0] * xub);
3074 
3075  if( SCIPisFinite(fxlb) && SCIPisFinite(fxub) )
3076  {
3077  if( fxlb - grad[0] * xlb > fxub - grad[0] * xub )
3078  xtilde = xlb;
3079  else
3080  xtilde = xub;
3081  *success = TRUE;
3082  }
3083  else
3084  {
3085  /* move yval inside domain and continue below, hope this will work better */
3086  perturb(&yval, ylb, yub, 0.001);
3087  }
3088  }
3089 
3090  if( *success )
3091  {
3092  /* compute f(xtilde, yub) */
3093  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xtilde, &ftilde) );
3094 
3095  SCIPdebugMessage("xtilde = %g, f(%g,%g) = %g\n", xtilde, xtilde, yub, ftilde);
3096 
3097  /* setup cut coefficients */
3098  cutcoeff[0] = (yub - ylb) * grad[0]; /* coefficient of x */
3099  cutcoeff[1] = ftilde - fval - grad[0] * (xtilde - xval); /* coefficient of y */
3100  cutcoeff[2] = yub - ylb; /* coefficient of f(x,y) */
3101  cutcoeff[3] = cutcoeff[0] * xval + cutcoeff[1] * ylb - cutcoeff[2] * fval; /* constant */
3102  *convenvvalue = fval;
3103 
3104  SCIPdebugMessage("alpha: %g, beta: %g, gamma: %g, delta: %g\n", cutcoeff[0], cutcoeff[1], cutcoeff[2], cutcoeff[3]);
3105 
3106  return SCIP_OKAY;
3107  }
3108  }
3109  }
3110 
3111  if( SCIPisFeasEQ(scip, yval, yub) )
3112  {
3113  /* y is at it's upper bound */
3114  SCIP_Real x0y0[2];
3115  SCIP_Real grad[2];
3116  SCIP_Real fval;
3117  SCIP_Real xtilde;
3118  SCIP_Real ftilde;
3119 
3120  assert(f_yfixed != NULL);
3121 
3122  /* compute f(xval, yub) and f'(xval, yub) */
3123  x0y0[0] = xval;
3124  x0y0[1] = yub;
3125  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fval, grad) );
3126 
3127  if( !SCIPisFinite(fval) || !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
3128  {
3129  /* move yval inside domain and continue below, hope this will work better */
3130  perturb(&yval, ylb, yub, 0.001);
3131  }
3132  else
3133  {
3134  /* setup f(x,ylb) */
3135  SCIPexprtreeSetParamVal(f_yfixed, 0, ylb);
3136  SCIP_CALL( SCIPexprintNewParametrization(exprinterpreter, f_yfixed) );
3137 
3138  /* find xtilde in [xlb, xub] such that f'(x,ylb) = f'(xval,yub) */
3139  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, f_yfixed, grad[0], xlb, xub, &xtilde, success) );
3140 
3141  if( !*success )
3142  {
3143  SCIP_Real fxlb;
3144  SCIP_Real fxub;
3145 
3146  /* if we could not find an xtilde such that f'(xtilde,ylb) = f'(xval,yub), then probably because f'(x,ylb) is constant
3147  * in this case, choose xtilde from {xlb, xub} such that it maximizes f'(xtilde, yub) - grad[0]*xtilde
3148  */
3149  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xlb, &fxlb) );
3150  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xub, &fxub) );
3151 
3152  SCIPdebugMessage("couldn't solve deriv equ, compare f(%g,%g) - %g*%g = %g and f(%g,%g) - %g*%g = %g\n",
3153  xlb, yub, grad[0], xlb, fxlb - grad[0] * xlb,
3154  xub, yub, grad[0], xub, fxub - grad[0] * xub);
3155 
3156  if( SCIPisFinite(fxlb) && SCIPisFinite(fxub) )
3157  {
3158  if( fxlb - grad[0] * xlb < fxub - grad[0] * xub )
3159  xtilde = xlb;
3160  else
3161  xtilde = xub;
3162  *success = TRUE;
3163  }
3164  else
3165  {
3166  /* move yval inside domain and continue below, hope this will work better */
3167  perturb(&yval, ylb, yub, 0.001);
3168  }
3169  }
3170 
3171  if( *success )
3172  {
3173  /* compute f(xtilde, yub) */
3174  SCIP_CALL( SCIPexprintEval(exprinterpreter, f_yfixed, &xtilde, &ftilde) );
3175 
3176  SCIPdebugMessage("xtilde = %g, f(%g,%g) = %g\n", xtilde, xtilde, ylb, ftilde);
3177 
3178  /* set up cut coefficients */
3179  cutcoeff[0] = (yub - ylb) * grad[0];
3180  cutcoeff[1] = grad[0] * (xtilde - xval) - ftilde + fval;
3181  cutcoeff[2] = yub - ylb;
3182  cutcoeff[3] = cutcoeff[0] * xval + cutcoeff[1] * yub - cutcoeff[2] * fval;
3183  *convenvvalue = fval;
3184 
3185  SCIPdebugMessage("alpha: %g, beta: %g, gamma: %g, delta: %g\n", cutcoeff[0], cutcoeff[1], cutcoeff[2], cutcoeff[3]);
3186 
3187  return SCIP_OKAY;
3188  }
3189  }
3190  }
3191 
3192  {
3193  /* x and y are somewhere between the bounds,
3194  * -> envelope is generated from f(x,y) in y=ylb and in y=yub
3195  */
3196  SCIP_Real paramvals[4];
3197 #ifdef SCIP_DEBUG
3198  const char* paramnames[4] = {"x0", "y0", "ylb", "yub"};
3199 #endif
3200  SCIP_Real t;
3201  SCIP_Real slb;
3202  SCIP_Real sub;
3203  SCIP_Real sval;
3204  SCIP_Real rval;
3205  SCIP_Real fsval;
3206  SCIP_Real frval;
3207  SCIP_Real grad[2];
3208  SCIP_Real x0y0[2];
3209 
3210  assert(vred != NULL);
3211 
3212  /* check that variables are not unbounded or fixed and reference point is in interior
3213  * @todo it should also work if x is unbounded, or? */
3214  /* assert(!SCIPisInfinity(scip, -xlb));
3215  assert(!SCIPisInfinity(scip, xub)); */
3216  assert(!SCIPisInfinity(scip, -ylb));
3217  assert(!SCIPisInfinity(scip, yub));
3218 
3219  /* update parameter values in vred */
3220  paramvals[0] = xval;
3221  paramvals[1] = yval;
3222  paramvals[2] = ylb;
3223  paramvals[3] = yub;
3224  SCIP_CALL( SCIPexprtreeSetParams(vred, 4, paramvals) );
3225  SCIP_CALL( SCIPexprintNewParametrization(exprinterpreter, vred) );
3226 
3227  SCIPdebugMessage("vred(s;x0,y0,ylb,yub) = ");
3228  SCIPdebug( SCIPexprtreePrint(vred, SCIPgetMessagehdlr(scip), NULL, NULL, paramnames) );
3229  SCIPdebugPrintf("\n");
3230 
3231  /* compute bounds on s */
3232  t = (yub - yval) / (yub - ylb);
3233  if( !SCIPisInfinity(scip, xub) )
3234  slb = (yval - yub) / (ylb - yval) * (xval / t - xub);
3235  else
3236  slb = -SCIPinfinity(scip);
3237  if( !SCIPisInfinity(scip, xlb) )
3238  sub = (yval - yub) / (ylb - yval) * (xval / t - xlb);
3239  else
3240  sub = SCIPinfinity(scip);
3241  if( slb < xlb )
3242  slb = xlb;
3243  if( sub > xub )
3244  sub = xub;
3245 
3246  /* find s in [slb, sub] such that vred'(s) = 0 */
3247  SCIP_CALL( solveDerivativeEquation(scip, exprinterpreter, vred, 0.0, slb, sub, &sval, success) );
3248  assert(!*success || !SCIPisInfinity(scip, REALABS(sval)));
3249 
3250  if( *success )
3251  {
3252  /* compute r from s */
3253  rval = xval / t + (1.0 - 1.0 / t) * sval;
3254  assert(SCIPisFeasGE(scip, rval, xlb));
3255  assert(SCIPisFeasLE(scip, rval, xub));
3256  rval = MAX(xlb, MIN(rval, xub));
3257 
3258  /* compute f(sval, yub) */
3259  x0y0[0] = sval;
3260  x0y0[1] = yub;
3261  SCIP_CALL( SCIPexprtreeEval(f, x0y0, &fsval) );
3262 
3263  /* compute f(rval, ylb) */
3264  x0y0[0] = rval;
3265  x0y0[1] = ylb;
3266  SCIP_CALL( SCIPexprtreeEval(f, x0y0, &frval) );
3267 
3268  if( !SCIPisEQ(scip, sval, xlb) && !SCIPisEQ(scip, sval, xub) )
3269  {
3270  x0y0[0] = sval;
3271  x0y0[1] = yub;
3272 
3273  /* compute f'(xbar, ybar) */
3274  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad) );
3275  }
3276  else if( !SCIPisEQ(scip, rval, xlb) && !SCIPisEQ(scip, rval, xub) )
3277  {
3278  x0y0[0] = rval;
3279  x0y0[1] = ylb;
3280 
3281  /* compute f'(xbar, ybar) */
3282  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad) );
3283  }
3284  else
3285  {
3286  /* rare case
3287  * both points (sval, yub) and (rval, ylb) should yield valid inequality
3288  * for now, just take the first one, if differentiable, otherwise second one
3289  */
3290  x0y0[0] = sval;
3291  x0y0[1] = yub;
3292 
3293  /* compute f'(xbar, ybar) */
3294  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fsval, grad) );
3295 
3296  if( !SCIPisFinite(grad[0]) )
3297  {
3298  x0y0[0] = rval;
3299  x0y0[1] = ylb;
3300 
3301  /* compute new f'(xbar, ybar) */
3302  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &frval, grad) );
3303  }
3304  }
3305 
3306  /* compute vred(s) = t * f(rval, ylb) + (1-t) * f(sval, yub) */
3307  *convenvvalue = t * frval + (1.0 - t) * fsval;
3308 
3309  SCIPdebugMessage("Parallel: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
3310  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);
3311  SCIPdebugMessage("(r,ylb)=(%g,%g), (s,yub)=(%g,%g), vredval=%g\n",rval,ylb,sval,yub,*convenvvalue);
3312 
3313  if( !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
3314  {
3315  SCIPdebugMessage("f not differentiable at (x0,y0) w.r.t. x\n");
3316  *success = FALSE;
3317  return SCIP_OKAY;
3318  }
3319 
3320  /* compute cut coefficients */
3321  cutcoeff[0] = (yub - ylb) * grad[0];
3322  cutcoeff[1] = fsval - frval - (sval - rval) * grad[0];
3323  cutcoeff[2] = yub - ylb;
3324  cutcoeff[3] = cutcoeff[0] * xval + cutcoeff[1] * yval - cutcoeff[2] * *convenvvalue;
3325 
3326  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]);
3327  }
3328  }
3329 
3330  return SCIP_OKAY;
3331 }
3332 
3333 
3334 /** 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 */
3335 static
3337  SCIP* scip, /**< SCIP data structure */
3338  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
3339  SCIP_CONS* cons, /**< constraint */
3340  SCIP_Real xyref[2], /**< reference values for nonlinear variables */
3341  SCIP_SIDETYPE violside, /**< for which side of constraint to find a cut */
3342  SCIP_ROW** row /**< storage for cut */
3343  )
3344 {
3345  SCIP_CONSDATA* consdata;
3346  SCIP_Real cutcoeff[4];
3347  SCIP_Real dummy;
3348  SCIP_Bool success;
3349  SCIP_Real coefs[2];
3350  char cutname[SCIP_MAXSTRLEN];
3351 
3352  assert(scip != NULL);
3353  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);
3354  assert(cons != NULL);
3355  assert(row != NULL);
3356 
3357  consdata = SCIPconsGetData(cons);
3358  assert(consdata != NULL);
3359  assert(consdata->f != NULL);
3360  assert(consdata->convextype == SCIP_BIVAR_CONVEX_CONCAVE);
3361 
3362  *row = NULL;
3363 
3364  SCIPdebugMessage("generate %sestimator for convex-concave constraint <%s>\n",
3365  (violside == SCIP_SIDETYPE_LEFT ? "over" : "under"), SCIPconsGetName(cons));
3366  SCIPdebugPrintCons(scip, cons, NULL);
3367 
3368  if( violside == SCIP_SIDETYPE_LEFT )
3369  {
3370  /* need overestimator */
3371  assert(!SCIPisInfinity(scip, -consdata->lhs));
3372 
3373  if( consdata->sepaconvexconcave.lineariny )
3374  {
3375  /* f is strictly convex in x and linear in y -> overestimator is polyhedral */
3376  SCIP_Real constant;
3377 
3378  SCIP_CALL( generateEstimatingHyperplane(scip, exprinterpreter, consdata->f, TRUE, xyref, &coefs[0], &coefs[1], &constant, &success) );
3379 
3380  if( success )
3381  {
3382  assert(SCIPisFinite(coefs[0]));
3383  assert(SCIPisFinite(coefs[1]));
3384  assert(SCIPisFinite(constant));
3385 
3386  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_overesthyperplanecut_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
3387  SCIP_CALL( SCIPcreateRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, 0, NULL, NULL, consdata->lhs - constant, SCIPinfinity(scip), TRUE, FALSE, TRUE) );
3388 
3389  SCIP_CALL( SCIPaddVarsToRow(scip, *row, 2, SCIPexprtreeGetVars(consdata->f), coefs) );
3390  if( consdata->z != NULL )
3391  {
3392  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
3393  }
3394  }
3395  }
3396  else
3397  {
3398  SCIP_Real xyref_[2];
3399 
3400  /* f is strictly concave in y -> can compute overestimator by applying generateConvexConcaveUnderstimator on -f(y,x) */
3401  assert(consdata->sepaconvexconcave.f_neg_swapped != NULL);
3402 
3403  xyref_[0] = xyref[1];
3404  xyref_[1] = xyref[0];
3405  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) );
3406 
3407  if( success )
3408  {
3409  assert(SCIPisFinite(cutcoeff[0]));
3410  assert(SCIPisFinite(cutcoeff[1]));
3411  assert(SCIPisFinite(cutcoeff[2]));
3412  assert(SCIPisFinite(cutcoeff[3]));
3413  assert(SCIPisPositive(scip, cutcoeff[2])); /* assert gamma > 0 */
3414 
3415  /* construct row from cut coefficients (alpha, beta, gamma, delta)
3416  * coefficients are such that alpha * y + beta * x - gamma * (-f(x,y)) <= delta,
3417  * i.e., gamma * f(x,y) <= delta - alpha * y - beta * x
3418  * -> lhs <= f(x,y) + c*z <= delta/gamma - alpha/gamma * y - beta/gamma * x + c*z
3419  */
3420  coefs[0] = -cutcoeff[1] / cutcoeff[2];
3421  coefs[1] = -cutcoeff[0] / cutcoeff[2];
3422  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_convexconcaveoverest_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
3423  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, consdata->lhs - cutcoeff[3]/cutcoeff[2], SCIPinfinity(scip),
3424  TRUE, FALSE /* modifiable */, TRUE /* removable */) );
3425  SCIP_CALL( SCIPaddVarsToRow(scip, *row, 2, SCIPexprtreeGetVars(consdata->f), coefs) );
3426  if( consdata->z != NULL )
3427  {
3428  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
3429  }
3430  }
3431  }
3432  }
3433  else
3434  {
3435  /* need underestimator */
3436  assert(violside == SCIP_SIDETYPE_RIGHT);
3437  assert(!SCIPisInfinity(scip, consdata->rhs));
3438 
3439  if( consdata->sepaconvexconcave.linearinx )
3440  {
3441  /* f is linear in x and strictly concave in y -> underestimator is polyhedral */
3442  SCIP_Real constant;
3443 
3444  SCIP_CALL( generateEstimatingHyperplane(scip, exprinterpreter, consdata->f, FALSE, xyref, &coefs[0], &coefs[1], &constant, &success) );
3445 
3446  if( success )
3447  {
3448  assert(SCIPisFinite(coefs[0]));
3449  assert(SCIPisFinite(coefs[1]));
3450  assert(SCIPisFinite(constant));
3451 
3452  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_underesthyperplanecut_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
3453  SCIP_CALL( SCIPcreateRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, 0, NULL, NULL, -SCIPinfinity(scip), consdata->rhs - constant, TRUE, FALSE, TRUE) );
3454 
3455  SCIP_CALL( SCIPaddVarsToRow(scip, *row, 2, SCIPexprtreeGetVars(consdata->f), coefs) );
3456  if( consdata->z != NULL )
3457  {
3458  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
3459  }
3460  }
3461  }
3462  else
3463  {
3464  /* f is strictly convex in x -> can compute underestimator by applying generateConvexConcaveUnderstimator */
3465  assert(!consdata->sepaconvexconcave.linearinx); /* generateConvexConcaveUnderestimator assumes that if f is strictly convex in x */
3466 
3467  SCIP_CALL( generateConvexConcaveUnderestimator(scip, exprinterpreter, consdata->f, consdata->sepaconvexconcave.f_yfixed, consdata->sepaconvexconcave.vred, xyref, cutcoeff, &dummy, &success) );
3468 
3469  if( success )
3470  {
3471  assert(SCIPisFinite(cutcoeff[0]));
3472  assert(SCIPisFinite(cutcoeff[1]));
3473  assert(SCIPisFinite(cutcoeff[2]));
3474  assert(SCIPisFinite(cutcoeff[3]));
3475  assert(SCIPisPositive(scip, cutcoeff[2])); /* assert gamma > 0 */
3476 
3477  /* construct row from cut coefficients (alpha, beta, gamma, delta)
3478  * coefficients are such that alpha * x + beta * y - gamma * f(x,y) <= delta,
3479  * i.e., alpha/gamma * x + beta/gamma * y - delta/gamma <= f(x,y)
3480  * -> alpha/gamma * x + beta/gamma * y - delta/gamma + c*z <= f(x,y) + c*z <= rhs
3481  */
3482 
3483  coefs[0] = cutcoeff[0] / cutcoeff[2];
3484  coefs[1] = cutcoeff[1] / cutcoeff[2];
3485  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_convexconcaveunderest_%d", SCIPconsGetName(cons), SCIPgetNLPs(scip));
3486  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), cutname, -SCIPinfinity(scip), consdata->rhs + cutcoeff[3]/cutcoeff[2],
3487  TRUE, FALSE /* modifiable */, TRUE /* removable */) );
3488  SCIP_CALL( SCIPaddVarsToRow(scip, *row, 2, SCIPexprtreeGetVars(consdata->f), coefs) );
3489  if( consdata->z != NULL )
3490  {
3491  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
3492  }
3493  }
3494  }
3495  }
3496 
3497  return SCIP_OKAY;
3498 }
3499 
3500 
3501 /** computes an underestimating hyperplane for functions that are convex in x and y if the point to cut off lies on the boundary */
3502 static
3504  SCIP* scip, /**< SCIP data structure */
3505  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
3506  SCIP_EXPRTREE* f, /**< function f(x,y) */
3507  SCIP_Real xval, /**< current x value */
3508  SCIP_Real yval, /**< current y value */
3509  SCIP_Real xlb, /**< lower bound x */
3510  SCIP_Real xub, /**< upper bound x */
3511  SCIP_Real ylb, /**< lower bound y */
3512  SCIP_Real yub, /**< upper bound y */
3513  int min_max, /**< min=-1 max=1 */
3514  SCIP_Real cutcoeff[4], /**< returns the lifting coefficient*/
3515  SCIP_Real* convenvvalue, /**< value of the convex envelope at (xval,yval) */
3516  SCIP_Bool* success /**< buffer to indicate whether lifting was successful */
3517  )
3518 {
3519  int idx; /* indicates which variable is at the boundary */
3520 
3521  SCIP_Real mu;
3522  SCIP_Real fval;
3523  SCIP_Real grad[2];
3524 
3525  SCIP_Real x0y0[2];
3526  SCIP_Real f_lb;
3527  SCIP_Real f_ub;
3528  SCIP_Real grad_lb[2];
3529  SCIP_Real grad_ub[2];
3530 
3531  assert(SCIPisEQ(scip,xlb,xub) || SCIPisEQ(scip,ylb,yub));
3532  assert(success != NULL);
3533 
3534  *success = FALSE;
3535  idx = SCIPisEQ(scip, xlb, xub) ? 0 : 1;
3536 
3537  /* determine mu
3538  * if f is bivariate quadratic then f_x(xlb,yval) is linear in yval
3539  * thus the minimum is attained at the lower or the upper bound
3540  */
3541  x0y0[0] = xlb;
3542  x0y0[1] = ylb;
3543  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &f_lb, grad_lb) );
3544  if( !SCIPisFinite(grad_lb[idx]) )
3545  return SCIP_OKAY;
3546 
3547  x0y0[0] = xub;
3548  x0y0[1] = yub;
3549  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &f_ub, grad_ub) );
3550  if( !SCIPisFinite(grad_ub[idx]) )
3551  return SCIP_OKAY;
3552 
3553  /* if min_max=-1 choose min( grad_lb[idx], grad_ub[idx] )
3554  * if min_max= 1 choose max( grad_lb[idx], grad_ub[idx] )
3555  */
3556  if( min_max * (grad_lb[idx] - grad_ub[idx]) >= 0 )
3557  mu = grad_lb[idx];
3558  else
3559  mu = grad_ub[idx];
3560 
3561  /* determine coefficients for the hyperplane */
3562  x0y0[0] = xval;
3563  x0y0[1] = yval;
3564  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, x0y0, TRUE, &fval, grad) );
3565 
3566  if( idx == 0 )
3567  {
3568  if( !SCIPisFinite(grad[1]) || SCIPisInfinity(scip, REALABS(grad[1])) )
3569  return SCIP_OKAY;
3570  cutcoeff[0] = mu;
3571  cutcoeff[1] = grad[1];
3572  }
3573  else
3574  {
3575  assert(idx == 1);
3576  if( !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
3577  return SCIP_OKAY;
3578  cutcoeff[0] = grad[0];
3579  cutcoeff[1] = mu;
3580  }
3581  cutcoeff[2] = 1;
3582  cutcoeff[3] = -(fval-cutcoeff[0]*xval-cutcoeff[1]*yval);
3583  *convenvvalue = fval;
3584  *success = TRUE;
3585 
3586  return SCIP_OKAY;
3587 }
3588 
3589 /** 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
3590  * generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that alpha * x + beta * y - delta <= gamma * f(x,y)
3591  */
3592 static
3594  SCIP* scip, /**< SCIP data structure */
3595  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
3596  SCIP_EXPRTREE* f, /**< function f(x,y) */
3597  SCIP_Real xyref[2], /**< reference values for x and y */
3598  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
3599  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
3600  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
3601  )
3602 {
3603  SCIP_VAR* x;
3604  SCIP_VAR* y;
3605  SCIP_Real xval;
3606  SCIP_Real xlb;
3607  SCIP_Real xub;
3608  SCIP_Real yval;
3609  SCIP_Real ylb;
3610  SCIP_Real yub;
3611 
3612  assert(scip != NULL);
3613  assert(exprinterpreter != NULL);
3614  assert(f != NULL);
3615  assert(convenvvalue != NULL);
3616  assert(success != NULL);
3617 
3618  x = SCIPexprtreeGetVars(f)[0];
3619  y = SCIPexprtreeGetVars(f)[1];
3620 
3621  xlb = SCIPvarGetLbLocal(x);
3622  xub = SCIPvarGetUbLocal(x);
3623 
3624  ylb = SCIPvarGetLbLocal(y);
3625  yub = SCIPvarGetUbLocal(y);
3626 
3627  *success = FALSE;
3628 
3629  SCIPdebugMessage("f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
3631  SCIPdebugPrintf("\n");
3632 
3633  xval = xyref[0];
3634  yval = xyref[1];
3635 
3636  SCIPdebugMessage("xval=%g in [%g,%g], yval=%g in [%g,%g]\n",xval,xlb,xub,yval,ylb,yub);
3637 
3638  if( SCIPisEQ(scip, ylb, yub) )
3639  {
3640  /* y is fixed, so function is now convex -> linearize in (xval, ylb) */
3641  SCIP_Real xy[2];
3642  SCIP_Real grad[2];
3643  SCIP_Real fval;
3644 
3645  xy[0] = xval;
3646  xy[1] = ylb;
3647  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xy, TRUE, &fval, grad) );
3648  if( !SCIPisFinite(grad[0]) || SCIPisInfinity(scip, REALABS(grad[0])) )
3649  return SCIP_OKAY;
3650 
3651  /* linearization is f(xval,ylb) + df/dx(xval,ylb) * (x - xval) <= f(x,y) */
3652 
3653  cutcoeff[0] = grad[0]; /* coefficient of x == gradient in x */
3654  cutcoeff[1] = 0.0; /* coefficient of y == 0 */
3655  cutcoeff[2] = 1.0; /* coefficient of f(x,y) == 1.0 */
3656  cutcoeff[3] = -(fval - grad[0] * xval); /* constant == -(f(xval,ylb) - grad * xval) */
3657 
3658  *success = TRUE;
3659  return SCIP_OKAY;
3660  }
3661 
3662  if( SCIPisEQ(scip, xlb, xub) )
3663  {
3664  /* x is fixed, so function is now convex -> linearize in (xlb, yval) */
3665  SCIP_Real xy[2];
3666  SCIP_Real grad[2];
3667  SCIP_Real fval;
3668 
3669  xy[0] = xlb;
3670  xy[1] = yval;
3671  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xy, TRUE, &fval, grad) );
3672  if( !SCIPisFinite(grad[1]) || SCIPisInfinity(scip, REALABS(grad[1])) )
3673  return SCIP_OKAY;
3674 
3675  /* linearization is f(xlb,yval) + df/dy(xlb,yval) * (y - yval) <= f(x,y) */
3676 
3677  cutcoeff[0] = 0.0; /* coefficient of x == 0.0 */
3678  cutcoeff[1] = grad[1]; /* coefficient of y == gradient in y */
3679  cutcoeff[2] = 1.0; /* coefficient of f(x,y) == 1.0 */
3680  cutcoeff[3] = -(fval - grad[1] * yval); /* constant == -(f(xlb,yval) - grad * yval) */
3681 
3682  *success = TRUE;
3683  return SCIP_OKAY;
3684  }
3685 
3686  /* check if the points lie on a boundary */
3687  if( SCIPisFeasEQ(scip, xlb, xval) )
3688  {
3689  /* apply a lifting and exploit that the function is convex in x and y
3690  * Idea: f(xlb,y) + mu (x-xlb) <= f(x,y)
3691  * determine mu with mu <= min_{x,y} ( f(x,y)-f(xlb,y) ) / (x-xlb)
3692  * f is convex in x: mu<= min_{y} f_x(xlb,y)
3693  *
3694  * mu (x-lb) + f_y(xlb,yval) * y <= f(x,y)
3695  */
3696  xval = xlb;
3697 
3698  SCIP_CALL( lifting(scip,exprinterpreter,f,xval,yval,xlb,xlb,ylb,yub,-1,cutcoeff,convenvvalue,success) );
3699 
3700  if( !*success )
3701  return SCIP_OKAY;
3702 
3703  SCIPdebugMessage("Boundary x=lb: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
3704  SCIPdebugMessage("convenvvalue = %g\n",*convenvvalue);
3705  SCIPdebugMessage("cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=%g,cutcoeff[3]=%g\n",
3706  cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
3707 
3708  return SCIP_OKAY;
3709  }
3710 
3711  if( SCIPisFeasEQ(scip, ylb, yval) )
3712  {
3713  yval = ylb;
3714 
3715  SCIP_CALL( lifting(scip,exprinterpreter,f,xval,yval,xlb,xub,ylb,ylb,-1,cutcoeff,convenvvalue,success) );
3716 
3717  if( !*success )
3718  return SCIP_OKAY;
3719 
3720  SCIPdebugMessage("Boundary y=lb: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
3721  SCIPdebugMessage("convenvvalue = %g\n",*convenvvalue);
3722  SCIPdebugMessage("cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=%g,cutcoeff[3]=%g\n",
3723  cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
3724 
3725  return SCIP_OKAY;
3726  }
3727 
3728  if( SCIPisFeasEQ(scip, xub, xval) )
3729  {
3730  /* apply a lifting and exploit that the function is convex in x and y
3731  * Idea: f(xlb,y) + mu (xub-x) <= f(x,y)
3732  * determine mu with mu <= min_{x,y} ( f(x,y)-f(xub,y) ) / (xub-x)
3733  * f is convex in x: -1 * mu >= min_{y} f_x(xub,y)
3734  *
3735  * mu (xub-x) + f_y(xub,yval) * y <= f(x,y)
3736  * -mu*x -mu*xub + f_y(xub,yval) * y <= f(x,y)
3737  */
3738  xval = xub;
3739 
3740  SCIP_CALL( lifting(scip,exprinterpreter,f,xval,yval,xub,xub,ylb,yub,1,cutcoeff,convenvvalue,success) );
3741 
3742  if( !*success )
3743  return SCIP_OKAY;
3744 
3745  SCIPdebugMessage("Boundary x=ub: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
3746  SCIPdebugMessage("convenvvalue = %g\n",*convenvvalue);
3747  SCIPdebugMessage("cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=%g,cutcoeff[3]=%g\n",
3748  cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
3749 
3750  return SCIP_OKAY;
3751  }
3752 
3753  if( SCIPisFeasEQ(scip, yub, yval) )
3754  {
3755  yval = yub;
3756 
3757  SCIP_CALL( lifting(scip,exprinterpreter,f,xval,yval,xlb,xub,yub,yub,1,cutcoeff,convenvvalue,success) );
3758 
3759  if( !*success )
3760  return SCIP_OKAY;
3761 
3762  SCIPdebugMessage("Boundary y=ub: Cut of (xval,yval)=(%g,%g)\n",xval,yval);
3763  SCIPdebugMessage("convenvvalue = %g\n",*convenvvalue);
3764  SCIPdebugMessage("cutcoeff[0]=%g, cutcoeff[1]=%g,cutcoeff[2]=%g,cutcoeff[3]=%g\n",
3765  cutcoeff[0],cutcoeff[1],cutcoeff[2],cutcoeff[3]);
3766 
3767  return SCIP_OKAY;
3768  }
3769 
3770  /* (xval,yval) lies in the interior */
3771  SCIPerrorMessage("Tries to compute underestimator for a point at the boundary. But point is not on the boundary!\n");
3772  return SCIP_ERROR;
3773 }
3774 
3775 /** generates a linear underestimator for f(x,y) with f(x,y) being convex in x and convex in y but indefinite
3776  * This is for the case where the cone of the concave directions is (R_+ x R_-) union (R_\- x R_+).
3777  * We consider two cases:
3778  * a) the underestimating segmenent connects parallel facets
3779  * b) the underestimating segmenent connects orthogonal facets where
3780  * x=l_x, y=l_y and x=u_x, y=u_y
3781  * We ensure that the parallel facets are the horizontal with y=l_y and y=u_y
3782  * We compute the objective value of the two problems.
3783  * The smaller objective value corresponds to the convex envelope.
3784  * The supporting hyperplane is then constructed at the this point.
3785  */
3786 static
3788  SCIP* scip, /**< SCIP data structure */
3789  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
3790  SCIP_EXPRTREE* f, /**< function f(x,y) */
3791  SCIP_Real xyref[2], /**< reference values for x and y */
3792  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
3793  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
3794  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
3795  )
3796 {
3797  SCIP_VAR* x;
3798  SCIP_VAR* y;
3799  SCIP_Real xval;
3800  SCIP_Real xlb;
3801  SCIP_Real xub;
3802  SCIP_Real yval;
3803  SCIP_Real ylb;
3804  SCIP_Real yub;
3805  SCIP_Real xub_ylb[2];
3806  SCIP_Real xlb_yub[2];
3807  SCIP_Real grad_xub_ylb[2];
3808  SCIP_Real grad_xlb_yub[2];
3809  SCIP_Real fval_xub_ylb;
3810  SCIP_Real fval_xlb_yub;
3811 
3812  SCIP_Real all_cutcoeff[2][4];
3813  SCIP_Real all_convenvvalue[2];
3814  SCIP_Bool all_success[2];
3815 
3816  SCIP_Real lowest;
3817  int lowestidx;
3818  int i;
3819 
3820  SCIP_EXPRTREE* fswapped;
3821  SCIP_VAR* vars[2];
3822  SCIP_Bool swapped;
3823  SCIP_Real swap_buffer;
3824  SCIP_EXPR* subst[2];
3825 
3826  assert(scip != NULL);
3827  assert(exprinterpreter != NULL);
3828  assert(f != NULL);
3829  assert(convenvvalue != NULL);
3830  assert(success != NULL);
3831 
3832  x = SCIPexprtreeGetVars(f)[0];
3833  y = SCIPexprtreeGetVars(f)[1];
3834 
3835  xlb = SCIPvarGetLbLocal(x);
3836  xub = SCIPvarGetUbLocal(x);
3837 
3838  ylb = SCIPvarGetLbLocal(y);
3839  yub = SCIPvarGetUbLocal(y);
3840 
3841  *success = FALSE;
3842 
3843  xval = xyref[0];
3844  yval = xyref[1];
3845 
3846  xub_ylb[0] = xub;
3847  xub_ylb[1] = ylb;
3848  xlb_yub[0] = xlb;
3849  xlb_yub[1] = yub;
3850 
3851  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xub_ylb, TRUE, &fval_xub_ylb, grad_xub_ylb) );
3852  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xlb_yub, TRUE, &fval_xlb_yub, grad_xlb_yub) );
3853 
3854  if( !SCIPisFinite(fval_xub_ylb) || SCIPisInfinity(scip, REALABS(fval_xub_ylb)) || !SCIPisFinite(fval_xlb_yub) || SCIPisInfinity(scip, REALABS(fval_xlb_yub)) )
3855  {
3856  SCIPdebugMessage("skip 1-convex underestimator since function cannot be evaluated\n");
3857  return SCIP_OKAY;
3858  }
3859 
3860  if( !SCIPisFinite(grad_xub_ylb[0]) || !SCIPisFinite(grad_xlb_yub[1]) )
3861  {
3862  SCIPdebugMessage("skip 1-convex underestimator since function cannot be differentiated\n");
3863  return SCIP_OKAY;
3864  }
3865 
3866  SCIPdebugMessage("f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
3868  SCIPdebugPrintf("\n");
3869 
3870  SCIPdebugMessage("xval=%g in [%g,%g], yval=%g in [%g,%g]\n", xval, xlb, xub, yval, ylb, yub);
3871 
3872  /* assure (xub-xlb)*f_x(xub,ylb) - (yub-ylb)*f_y(xlb,yub) >= f(xub,ylb) - f(xlb,yub) */
3873  /* f_y(xlb,yub)*(ylb-yub)* + f(xlb,yub) >= f_x(xub,ylb)*(xub-xlb) + f(xub,ylb) */
3874  if( fval_xub_ylb-fval_xlb_yub <= (xub-xlb)*grad_xub_ylb[0]-(yub-ylb)*grad_xlb_yub[1] )
3875  {
3876  swapped = 0;
3877  }
3878  else
3879  {
3880  /* swap the variables */
3881  swapped = 1;
3882 
3883  vars[0] = SCIPexprtreeGetVars(f)[1];
3884  vars[1] = SCIPexprtreeGetVars(f)[0];
3885 
3886  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_VARIDX, 1) );
3887  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_VARIDX, 0) );
3888 
3889  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &fswapped, f) );
3890  SCIP_CALL( SCIPexprtreeSubstituteVars(fswapped, subst) );
3891  SCIP_CALL( SCIPexprtreeSetVars(fswapped, 2, vars) );
3892  SCIP_CALL( SCIPexprintCompile(exprinterpreter, fswapped) );
3893 
3894  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
3895  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
3896  }
3897 
3898  if( swapped == 0 )
3899  {
3900  /* assume (xval,yval) lie in A1 (lower left triangle) or A2 (upper right triangle) */
3901  SCIP_CALL( generateOrthogonal_lx_ly_Underestimator(scip, exprinterpreter, f, xyref, all_cutcoeff[0], &all_convenvvalue[0], &all_success[0]) );
3902  /* assume (xval,yval) lie in A3 */
3903  SCIP_CALL( generateUnderestimatorParallelYFacets(scip, exprinterpreter, f, xyref, all_cutcoeff[1], &all_convenvvalue[1], &all_success[1]) );
3904  }
3905  else
3906  {
3907  SCIP_Real xyref_[2];
3908 
3909  assert(swapped == 1);
3910 
3911  xyref_[0] = xyref[1];
3912  xyref_[1] = xyref[0];
3913 
3914  /* assume (xval,yval) lie in A1 (lower left triangle) or A2 (upper right triangle) */
3915  SCIP_CALL( generateOrthogonal_lx_ly_Underestimator(scip, exprinterpreter, fswapped, xyref_, all_cutcoeff[0], &all_convenvvalue[0], &all_success[0]) ); /*lint !e644*/
3916  /* assume (xval,yval) lie in A3 */
3917  SCIP_CALL( generateUnderestimatorParallelYFacets(scip, exprinterpreter, fswapped, xyref_, all_cutcoeff[1], &all_convenvvalue[1], &all_success[1]) );
3918 
3919  /* swap back */
3920  swap_buffer = all_cutcoeff[0][0];
3921  all_cutcoeff[0][0] = all_cutcoeff[0][1];
3922  all_cutcoeff[0][1] = swap_buffer;
3923 
3924  swap_buffer = all_cutcoeff[1][0];
3925  all_cutcoeff[1][0] = all_cutcoeff[1][1];
3926  all_cutcoeff[1][1] = swap_buffer;
3927 
3928  SCIP_CALL( SCIPexprtreeFree(&fswapped) );
3929  }
3930 
3931  /* Select the underestimator with the lowest convex envelope */
3932  SCIPdebugMessage("\n");
3933  SCIPdebugMessage("Triangulation: convenvvalue=%g\n", all_convenvvalue[0]);
3934  SCIPdebugMessage("Parallel Y: convenvvalue=%g\n", all_convenvvalue[1]);
3935 
3936  lowest = SCIPinfinity(scip);
3937  lowestidx = -1;
3938 
3939  if( all_success[0] && all_success[1] )
3940  {
3941  *success = TRUE;
3942  for( i = 0; i < 2; ++i )
3943  {
3944  assert(SCIPisFinite(all_cutcoeff[i][0]));
3945  assert(SCIPisFinite(all_cutcoeff[i][1]));
3946  assert(SCIPisFinite(all_cutcoeff[i][2]));
3947  assert(SCIPisFinite(all_cutcoeff[i][3]));
3948 
3949  if( all_convenvvalue[i] < lowest )
3950  {
3951  /* if all_convenvvalue[0] == all_convenvalue[1], take all_convenvvalue[0] */
3952  lowest = all_convenvvalue[i];
3953  lowestidx = i;
3954  }
3955  }
3956  assert(lowestidx >= 0);
3957 
3958  *convenvvalue = all_convenvvalue[lowestidx];
3959  cutcoeff[0] = all_cutcoeff[lowestidx][0];
3960  cutcoeff[1] = all_cutcoeff[lowestidx][1];
3961  cutcoeff[2] = all_cutcoeff[lowestidx][2];
3962  cutcoeff[3] = all_cutcoeff[lowestidx][3];
3963  assert(SCIPisPositive(scip, cutcoeff[2])); /* assert gamma > 0 */
3964  }
3965  else
3966  {
3967  *success = FALSE;
3968  }
3969 
3970  return SCIP_OKAY;
3971 }
3972 
3973 
3974 /** generates a linear underestimator for f(x,y) with f(x,y) being convex in x and convex in y but indefinite
3975  * This is for the case where the cone of the concave directions is (R_+ x R_+) union (R_- x R_-).
3976  * We consider two cases:
3977  * a) the underestimating segmenent connects parallel facets
3978  * b) the underestimating segmenent connects orthogonal facets where
3979  * x=l_x, y=u_y and x=u_x, y=l_y
3980  * We ensure that the parallel facets are the horizontal with y=l_y and y=u_y
3981  * We compute the objective value of the two problems.
3982  * The smaller objective value corresponds to the convex envelope.
3983  * The supporting hyperplane is then constructed at the this point.
3984  * Generates coefficients cutcoeff = (alpha, beta, gamma, delta), such that alpha * x + beta * y - delta <= gamma * f(x,y)
3985  */
3986 static
3988  SCIP* scip, /**< SCIP data structure */
3989  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
3990  SCIP_EXPRTREE* f, /**< function f(x,y) */
3991  SCIP_Real xyref[2], /**< reference values for x and y */
3992  SCIP_Real cutcoeff[4], /**< cut coefficients alpha, beta, gamma, delta */
3993  SCIP_Real* convenvvalue, /**< function value of the convex envelope */
3994  SCIP_Bool* success /**< buffer to store whether coefficients were successfully computed */
3995  )
3996 {
3997  SCIP_VAR* x;
3998  SCIP_VAR* y;
3999  SCIP_Real xval;
4000  SCIP_Real xlb;
4001  SCIP_Real xub;
4002  SCIP_Real yval;
4003  SCIP_Real ylb;
4004  SCIP_Real yub;
4005  SCIP_Real xlb_ylb[2];
4006  SCIP_Real xub_yub[2];
4007  SCIP_Real grad_xlb_ylb[2];
4008  SCIP_Real grad_xub_yub[2];
4009  SCIP_Real fval_xlb_ylb;
4010  SCIP_Real fval_xub_yub;
4011 
4012  SCIP_Real all_cutcoeff[2][4];
4013  SCIP_Real all_convenvvalue[2];
4014  SCIP_Bool all_success[2];
4015 
4016  SCIP_Real lowest;
4017  int lowestidx;
4018  int i;
4019 
4020  SCIP_EXPRTREE* fswapped;
4021  SCIP_VAR* vars[2];
4022  SCIP_Bool swapped;
4023  SCIP_Real swap_buffer;
4024  SCIP_EXPR* subst[2];
4025 
4026  assert(scip != NULL);
4027  assert(exprinterpreter != NULL);
4028  assert(f != NULL);
4029  assert(convenvvalue != NULL);
4030  assert(success != NULL);
4031 
4032  x = SCIPexprtreeGetVars(f)[0];
4033  y = SCIPexprtreeGetVars(f)[1];
4034 
4035  xlb = SCIPvarGetLbLocal(x);
4036  xub = SCIPvarGetUbLocal(x);
4037 
4038  ylb = SCIPvarGetLbLocal(y);
4039  yub = SCIPvarGetUbLocal(y);
4040 
4041  *success = FALSE;
4042 
4043  SCIPdebugMessage("f(%s, %s) = ", SCIPvarGetName(x), SCIPvarGetName(y));
4045  SCIPdebugPrintf("\n");
4046 
4047  xval = xyref[0];
4048  yval = xyref[1];
4049 
4050  xlb_ylb[0] = xlb;
4051  xlb_ylb[1] = ylb;
4052  xub_yub[0] = xub;
4053  xub_yub[1] = yub;
4054 
4055  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xlb_ylb, TRUE, &fval_xlb_ylb, grad_xlb_ylb) );
4056  SCIP_CALL( SCIPexprintGrad(exprinterpreter, f, xub_yub, TRUE, &fval_xub_yub, grad_xub_yub) );
4057 
4058  if( !SCIPisFinite(fval_xlb_ylb) || SCIPisInfinity(scip, REALABS(fval_xlb_ylb)) || !SCIPisFinite(fval_xub_yub) || SCIPisInfinity(scip, REALABS(fval_xub_yub)) )
4059  {
4060  SCIPdebugMessage("skip 1-convex underestimator since function cannot be evaluated\n");
4061  return SCIP_OKAY;
4062  }
4063 
4064  if( !SCIPisFinite(grad_xlb_ylb[1]) || !SCIPisFinite(grad_xub_yub[0]) )
4065  {
4066  SCIPdebugMessage("skip 1-convex underestimator since function cannot be differentiated\n");
4067  return SCIP_OKAY;
4068  }
4069 
4070  SCIPdebugMessage("xval=%g in [%g,%g], yval=%g in [%g,%g]\n",xval,xlb,xub,yval,ylb,yub);
4071 
4072  /* assure f_y(xlb,ylb)*(yub-ylb)* + f(xlb,ylb) >= f_x(xub,yub)*(xlb-xub) + f(xub,yub) */
4073  if( SCIPisGE( scip, fval_xlb_ylb+(yub-ylb)*grad_xlb_ylb[1], fval_xub_yub+(xlb-xub)*grad_xub_yub[0] ) )
4074  {
4075  swapped = 0;
4076  }
4077  else
4078  {
4079  /* swap the variables */
4080  swapped = 1;
4081 
4082  vars[0] = SCIPexprtreeGetVars(f)[1];
4083  vars[1] = SCIPexprtreeGetVars(f)[0];
4084 
4085  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[0], SCIP_EXPR_VARIDX, 1) );
4086  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &subst[1], SCIP_EXPR_VARIDX, 0) );
4087 
4088  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &fswapped, f) );
4089  SCIP_CALL( SCIPexprtreeSubstituteVars(fswapped, subst) );
4090  SCIP_CALL( SCIPexprtreeSetVars(fswapped, 2, vars) );
4091  SCIP_CALL( SCIPexprintCompile(exprinterpreter, fswapped) );
4092 
4093  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[0]);
4094  SCIPexprFreeDeep(SCIPblkmem(scip), &subst[1]);
4095  }
4096 
4097  if( swapped == 0 )
4098  {
4099  /* assume (xval,yval) lie in A1 (lower left triangle) or A2 (upper right triangle) */
4100  SCIP_CALL( generateOrthogonal_lx_uy_Underestimator(scip, exprinterpreter, f, xyref, all_cutcoeff[0], &all_convenvvalue[0], &all_success[0]) );
4101  /* assume (xval,yval) lie in A3*/
4102  SCIP_CALL( generateUnderestimatorParallelYFacets(scip, exprinterpreter, f, xyref, all_cutcoeff[1], &all_convenvvalue[1], &all_success[1]) );
4103  }
4104  else
4105  {
4106  SCIP_Real xyref_[2];
4107 
4108  assert(swapped == 1);
4109 
4110  xyref_[0] = xyref[1];
4111  xyref_[1] = xyref[0];
4112  /* assume (xval,yval) lie in A1 (upper left triangle) or A2 (lower left triangle) */
4113  SCIP_CALL( generateOrthogonal_lx_uy_Underestimator(scip, exprinterpreter, fswapped, xyref_, all_cutcoeff[0], &all_convenvvalue[0], &all_success[0]) ); /*lint !e644*/
4114  /* assume (xval,yval) lie in A3 */
4115  SCIP_CALL( generateUnderestimatorParallelYFacets(scip, exprinterpreter, fswapped, xyref_, all_cutcoeff[1], &all_convenvvalue[1], &all_success[1]) );
4116 
4117  /* swap back */
4118  swap_buffer = all_cutcoeff[0][0];
4119  all_cutcoeff[0][0] = all_cutcoeff[0][1];
4120  all_cutcoeff[0][1] = swap_buffer;
4121 
4122  swap_buffer = all_cutcoeff[1][0];
4123  all_cutcoeff[1][0] = all_cutcoeff[1][1];
4124  all_cutcoeff[1][1] = swap_buffer;
4125 
4126  SCIP_CALL( SCIPexprtreeFree(&fswapped) );
4127  }
4128 
4129  /* select the underestimator with the lowest convex envelope */
4130  SCIPdebugMessage("\n");
4131  SCIPdebugMessage("Triangulation: convenvvalue=%g\n", all_convenvvalue[0]);
4132  SCIPdebugMessage("Parallel Y: convenvvalue=%g\n", all_convenvvalue[1]);
4133 
4134  lowest = SCIPinfinity(scip);
4135  lowestidx = -1;
4136 
4137  if( all_success[0] && all_success[1] )
4138  {
4139  *success = TRUE;
4140  for( i = 0; i < 2; ++i )
4141  {
4142  assert(SCIPisFinite(all_cutcoeff[i][0]));
4143  assert(SCIPisFinite(all_cutcoeff[i][1]));
4144  assert(SCIPisFinite(all_cutcoeff[i][2]));
4145  assert(SCIPisFinite(all_cutcoeff[i][3]));
4146 
4147  /* if all_convenvvalue[0]==all_convenvalue[1], take all_convenvvalue[0] */
4148  if( all_convenvvalue[i] < lowest )
4149  {
4150  lowest = all_convenvvalue[i];
4151  lowestidx = i;
4152  }
4153  }
4154  assert(lowestidx >= 0);
4155 
4156  *convenvvalue = all_convenvvalue[lowestidx];
4157  cutcoeff[0] = all_cutcoeff[lowestidx][0];
4158  cutcoeff[1] = all_cutcoeff[lowestidx][1];
4159  cutcoeff[2] = all_cutcoeff[lowestidx][2];
4160  cutcoeff[3] = all_cutcoeff[lowestidx][3];
4161  assert(SCIPisPositive(scip, cutcoeff[2])); /* assert gamma > 0 */
4162  }
4163  else
4164  {
4165  *success = FALSE;
4166  }
4167 
4168  return SCIP_OKAY;
4169 }
4170 
4171 
4172 /** generates a linear underestimator for f(x,y) with f(x,y) being convex in x and convex in y but indefinite
4173  * generate coefficients cutcoeff = (alpha, beta, gamma, delta), such that alpha * x + beta * y - delta <= gamma * f(x,y)
4174  * 1. If the point lies on the boundary we apply the lifting technique.
4175  * 2. If the point lies in the interior we check the pattern of
4176  * the concave directions and compute the corresponding underestimators.
4177  */
4178 static
4180  SCIP* scip, /**< SCIP data structure */
4181  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
4182  SCIP_CONS* cons, /**< constraint */
4183  SCIP_Real* xyref, /**< reference values for x and y */
4184  SCIP_ROW** row /**< storage for cut */
4185  )
4186 {
4187  SCIP_CONSDATA* consdata;
4188  SCIP_EXPRTREE* f;
4189  SCIP_Real cutcoeff[4];
4190  SCIP_Bool success;
4191  SCIP_Real rhs;
4192  SCIP_Real convenvvalue;
4193 
4194  SCIP_VAR* x;
4195  SCIP_VAR* y;
4196  SCIP_Real xlb;
4197  SCIP_Real xub;
4198  SCIP_Real ylb;
4199  SCIP_Real yub;
4200  SCIP_Real xy_mid[2];
4201  SCIP_Real fval_mid;
4202  SCIP_Real hess[4];
4203 
4204  assert(scip != NULL);
4205  assert(cons != NULL);
4206  assert(row != NULL);
4207 
4208  consdata = SCIPconsGetData(cons);
4209  assert(consdata != NULL);
4210 
4211  assert(consdata->convextype == SCIP_BIVAR_1CONVEX_INDEFINITE);
4212 
4213  assert(!SCIPisInfinity(scip, consdata->rhs));
4214 
4215  f = consdata->f;
4216 
4217  x = SCIPexprtreeGetVars(f)[0];
4218  y = SCIPexprtreeGetVars(f)[1];
4219 
4220  xlb = SCIPvarGetLbLocal(x);
4221  xub = SCIPvarGetUbLocal(x);
4222 
4223  ylb = SCIPvarGetLbLocal(y);
4224  yub = SCIPvarGetUbLocal(y);
4225 
4226  xy_mid[0] = 0.5 * (xlb+xub);
4227  xy_mid[1] = 0.5 * (ylb+yub);
4228 
4229  /* assert that the bounds are finite */
4230  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) || SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub) )
4231  {
4232  SCIPdebugMessage("skip underestimate for 1-convex indefinite constraint <%s> since <%s> or <%s> is unbounded\n", SCIPconsGetName(cons), SCIPvarGetName(x), SCIPvarGetName(y));
4233  return SCIP_OKAY;
4234  }
4235 
4236  success = FALSE;
4237  cutcoeff[0] = SCIP_INVALID;
4238  cutcoeff[1] = SCIP_INVALID;
4239  cutcoeff[2] = SCIP_INVALID;
4240  cutcoeff[3] = SCIP_INVALID;
4241 
4242  /* (xval,yval) lie on a boundary */
4243  if( SCIPisFeasEQ(scip,xyref[0],xlb) || SCIPisFeasEQ(scip,xyref[0],xub) || SCIPisFeasEQ(scip,xyref[1],ylb) || SCIPisFeasEQ(scip,xyref[1],yub) )
4244  {
4245  SCIP_CALL( generate1ConvexIndefiniteUnderestimatorAtBoundary(scip, exprinterpreter, f, xyref, cutcoeff, &convenvvalue, &success) );
4246 
4247  if( !success )
4248  {
4249  /* maybe f is not differentiable on boundary, so move reference point into interior
4250  * we do this here w.r.t. both coordinates
4251  */
4252  perturb(&xyref[0], xlb, xub, 0.001);
4253  perturb(&xyref[1], ylb, yub, 0.001);
4254  }
4255  }
4256 
4257  if( !success )
4258  {
4259  /* xyref lies in the interior */
4260  /* check the pattern of the concave directions */
4261  SCIP_CALL( SCIPexprintHessianDense(exprinterpreter, f, xy_mid, TRUE, &fval_mid, hess) );
4262  assert(SCIPisFinite(hess[1]));
4263 
4264  if( hess[1] > 0.0 )
4265  {
4266  /* Pattern A: (R>=0 x R<=0) union (R<=0 x R>=0)*/
4267  SCIPdebugMessage("Pattern A\n");
4268  SCIP_CALL( generate1ConvexIndefiniteUnderestimatorInTheInteriorPatternA(scip, exprinterpreter, f, xyref, cutcoeff, &convenvvalue, &success) );
4269  }
4270  else
4271  {
4272  /* Pattern B: (R>=0 x R>=0) union (R<=0 x R <=0)*/
4273  SCIPdebugMessage("Pattern B\n");
4274  SCIP_CALL( generate1ConvexIndefiniteUnderestimatorInTheInteriorPatternB(scip, exprinterpreter, f, xyref, cutcoeff, &convenvvalue, &success) );
4275  }
4276  }
4277 
4278  if( !success )
4279  {
4280  /* bad luck */
4281  *row = NULL;
4282  return SCIP_OKAY;
4283  }
4284 
4285 
4286  /* construct row from cut coefficients (alpha, beta, gamma, delta)
4287  * coefficients are such that alpha * x + beta * y - gamma * f(x,y) <= delta,
4288  * i.e., alpha/gamma * x + beta/gamma * y - delta/gamma <= f(x,y)
4289  * -> alpha/gamma * x + beta/gamma * y - delta/gamma + c*z <= f(x,y) + c*z <= rhs
4290  */
4291 
4292  assert(cutcoeff[0] != SCIP_INVALID); /*lint !e777*/
4293  assert(cutcoeff[1] != SCIP_INVALID); /*lint !e777*/
4294  assert(cutcoeff[2] != SCIP_INVALID); /*lint !e777*/
4295  assert(cutcoeff[3] != SCIP_INVALID); /*lint !e777*/
4296  assert(SCIPisFinite(cutcoeff[0]));
4297  assert(SCIPisFinite(cutcoeff[1]));
4298  assert(SCIPisFinite(cutcoeff[2]));
4299  assert(SCIPisFinite(cutcoeff[3]));
4300  assert(SCIPisPositive(scip, cutcoeff[2])); /* assert gamma > 0 */
4301 
4302  if( SCIPisInfinity(scip, REALABS(cutcoeff[0]/cutcoeff[2])) ||
4303  SCIPisInfinity( scip, REALABS(cutcoeff[1]/cutcoeff[2])) ||
4304  SCIPisInfinity( scip, REALABS(cutcoeff[3]/cutcoeff[2])) )
4305  {
4306  *row = NULL;
4307  return SCIP_OKAY;
4308  }
4309 
4310  rhs = consdata->rhs + cutcoeff[3]/cutcoeff[2];
4311  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), "1ConvexUnderest", -SCIPinfinity(scip), rhs,
4312  TRUE, FALSE /* modifiable */, TRUE /* removable */) );
4313  SCIP_CALL( SCIPaddVarToRow(scip, *row, SCIPexprtreeGetVars(consdata->f)[0], cutcoeff[0] / cutcoeff[2]) );
4314  SCIP_CALL( SCIPaddVarToRow(scip, *row, SCIPexprtreeGetVars(consdata->f)[1], cutcoeff[1] / cutcoeff[2]) );
4315  if( consdata->z != NULL )
4316  {
4317  SCIP_CALL( SCIPaddVarToRow(scip, *row, consdata->z, consdata->zcoef) );
4318  }
4319 
4320  return SCIP_OKAY;
4321 }
4322 
4323 /** generates a cut */
4324 static
4326  SCIP* scip, /**< SCIP data structure */
4327  SCIP_EXPRINT* exprinterpreter, /**< expressions interpreter */
4328  SCIP_CONS* cons, /**< constraint */
4329  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
4330  SCIP_SIDETYPE violside, /**< for which side of constraint we want to generate a cut */
4331  SCIP_Real cutmaxrange, /**< bound on cut coef range */
4332  SCIP_ROW** row /**< storage for cut */
4333  )
4334 {
4335  SCIP_CONSDATA* consdata;
4336  SCIP_VAR* x;
4337  SCIP_VAR* y;
4338  SCIP_Real x0y0[2];
4339 
4340  assert(scip != NULL);
4341  assert(cons != NULL);
4342  assert(row != NULL);
4343 
4344  consdata = SCIPconsGetData(cons);
4345  assert(consdata != NULL);
4346 
4347  *row = NULL;
4348 
4349  x = SCIPexprtreeGetVars(consdata->f)[0];
4350  y = SCIPexprtreeGetVars(consdata->f)[1];
4351 
4352  x0y0[0] = SCIPgetSolVal(scip, sol, x);
4353  x0y0[1] = SCIPgetSolVal(scip, sol, y);
4354 
4355  assert(SCIPisFeasLE(scip, SCIPvarGetLbLocal(x), x0y0[0]));
4356  assert(SCIPisFeasGE(scip, SCIPvarGetUbLocal(x), x0y0[0]));
4357  assert(SCIPisFeasLE(scip, SCIPvarGetLbLocal(y), x0y0[1]));
4358  assert(SCIPisFeasGE(scip, SCIPvarGetUbLocal(y), x0y0[1]));
4359 
4360  /* project into box */
4361  x0y0[0] = MIN(MAX(SCIPvarGetLbLocal(x),x0y0[0]),SCIPvarGetUbLocal(x)); /*lint !e666*/
4362  x0y0[1] = MIN(MAX(SCIPvarGetLbLocal(y),x0y0[1]),SCIPvarGetUbLocal(y)); /*lint !e666*/
4363 
4364  SCIPdebugPrintf("\n");
4365  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);
4366  SCIPdebugMessage("convextype = %d\n",consdata->convextype);
4367  SCIPdebugMessage("%s = %g with bounds [%g, %g], %s = %g with bounds [%g, %g]",
4370  if( consdata->z != NULL )
4371  SCIPdebugPrintf(", %s = %g with bounds [%g, %g]", SCIPvarGetName(consdata->z), SCIPgetSolVal(scip, sol, consdata->z), SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z));
4372  SCIPdebugPrintf("\n");
4373  SCIPdebugPrintCons(scip, cons, NULL);
4374  SCIPdebugPrintf("\n");
4375 
4376  switch( consdata->convextype )
4377  {
4378  case SCIP_BIVAR_ALLCONVEX:
4379  {
4380  if( violside == SCIP_SIDETYPE_RIGHT )
4381  {
4382  /* rhs is violated */
4383  SCIP_CALL( generateLinearizationCut(scip, exprinterpreter, cons, x0y0, FALSE, row) );
4384  }
4385  else
4386  {
4387  /* lhs is violated */
4388  SCIP_CALL( generateOverestimatingHyperplaneCut(scip, exprinterpreter, cons, x0y0, row) );
4389  }
4390 
4391  break;
4392  }
4393 
4395  {
4396  SCIP_CALL( generateConvexConcaveEstimator(scip, exprinterpreter, cons, x0y0, violside, row) );
4397  break;
4398  }
4399 
4401  {
4402  if( violside == SCIP_SIDETYPE_RIGHT )
4403  {
4404  /* rhs is violated */
4405  SCIP_CALL( generate1ConvexIndefiniteUnderestimator(scip, exprinterpreter, cons, x0y0, row) );
4406  }
4407  else
4408  {
4409  /* lhs is violated */
4410  SCIP_CALL( generateOverestimatingHyperplaneCut(scip, exprinterpreter, cons, x0y0, row) );
4411  }
4412  break;
4413  }
4414  default:
4415  {
4416  SCIPdebugMessage("cut generation for convexity type not implemented\n");
4417  }
4418  } /*lint !e788*/
4419 
4420  if( *row == NULL )
4421  return SCIP_OKAY;
4422 
4423  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *row, NULL) ) );
4424 
4425  /* check numerics */
4426  {
4427  SCIP_Real mincoef;
4428  SCIP_Real maxcoef;
4429 
4430  mincoef = SCIPgetRowMinCoef(scip, *row);
4431  maxcoef = SCIPgetRowMaxCoef(scip, *row);
4432 
4433  while( maxcoef / mincoef > cutmaxrange )
4434  {
4435  SCIP_VAR* var;
4436  SCIP_Real coef;
4437  SCIP_Real constant;
4438  int j;
4439 
4440  /* if range of coefficients is bad, find very small coefficients and make them zero */
4441  SCIPdebugMessage("cut coefficients for constraint <%s> have very large range: mincoef = %g maxcoef = %g\n", SCIPconsGetName(cons), mincoef, maxcoef);
4442 
4443  /* if minimal coefficient is given by z, then give up (probably the maximal coefficient is the problem) */
4444  if( mincoef == consdata->zcoef ) /*lint !e777*/
4445  {
4446  SCIPdebugMessage("could not eliminate small coefficient, since it comes from linear part\n");
4447  break;
4448  }
4449 
4450  constant = 0.0;
4451  for( j = 0; j < SCIProwGetNNonz(*row); ++j )
4452  {
4453  coef = SCIProwGetVals(*row)[j];
4454  if( !SCIPisEQ(scip, REALABS(coef), mincoef) )
4455  continue;
4456 
4457  var = SCIPcolGetVar(SCIProwGetCols(*row)[j]);
4458  assert(var != NULL);
4459 
4460  /* try to eliminate coefficient with minimal absolute value by weakening cut and try again */
4461  if( ((coef > 0.0 && violside == SCIP_SIDETYPE_RIGHT) || (coef < 0.0 && violside == SCIP_SIDETYPE_LEFT)) && !SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
4462  {
4463  SCIPdebugMessage("eliminate coefficient %g for <%s> = %g [%g, %g]\n", coef, SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
4464 
4465  constant += coef * (SCIProwIsLocal(*row) ? SCIPvarGetLbLocal(var) : SCIPvarGetLbGlobal(var));
4466  SCIP_CALL( SCIPaddVarToRow(scip, *row, var, -coef) );
4467  continue;
4468  }
4469 
4470  if( ((coef < 0.0 && violside == SCIP_SIDETYPE_RIGHT) || (coef > 0.0 && violside == SCIP_SIDETYPE_LEFT)) && !SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
4471  {
4472  SCIPdebugMessage("eliminate coefficient %g for <%s> = %g [%g, %g]\n", coef, SCIPvarGetName(var), SCIPgetSolVal(scip, sol, var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
4473 
4474  constant += coef * (SCIProwIsLocal(*row) ? SCIPvarGetUbLocal(var) : SCIPvarGetUbGlobal(var));
4475  SCIP_CALL( SCIPaddVarToRow(scip, *row, var, -coef) );
4476  continue;
4477  }
4478 
4479  break;
4480  }
4481 
4482  if( j < SCIProwGetNNonz(*row) )
4483  {
4484  SCIPdebugMessage("could not eliminate small coefficient\n");
4485  SCIP_CALL( SCIPreleaseRow(scip, row) );
4486  break;
4487  }
4488 
4489  if( violside == SCIP_SIDETYPE_LEFT )
4490  {
4491  SCIP_CALL( SCIPchgRowLhs(scip, *row, SCIProwGetLhs(*row) - constant) );
4492  }
4493  else
4494  {
4495  SCIP_CALL( SCIPchgRowRhs(scip, *row, SCIProwGetRhs(*row) - constant) );
4496  }
4497 
4498  /* update min/max coefficient */
4499  mincoef = SCIPgetRowMinCoef(scip, *row);
4500  maxcoef = SCIPgetRowMaxCoef(scip, *row);
4501  };
4502 
4503  /* avoid numerically very bad cuts */
4504  if( maxcoef / mincoef > cutmaxrange )
4505  {
4506  SCIPdebugMessage("drop row for constraint <%s> because range of coefficients is too large: mincoef = %g, maxcoef = %g -> range = %g\n",
4507  SCIPconsGetName(cons), mincoef, maxcoef, maxcoef / mincoef);
4508  }
4509 
4510  if( *row != NULL &&
4511  ( (violside == SCIP_SIDETYPE_LEFT && SCIPisInfinity(scip, -SCIProwGetLhs(*row))) ||
4512  (violside == SCIP_SIDETYPE_RIGHT && SCIPisInfinity(scip, SCIProwGetRhs(*row)))) )
4513  {
4514  SCIPdebugMessage("drop row for constraint <%s> because of very large side: %g\n", SCIPconsGetName(cons), violside == SCIP_SIDETYPE_LEFT ? -SCIProwGetLhs(*row) : SCIProwGetRhs(*row));
4515  SCIP_CALL( SCIPreleaseRow(scip, row) );
4516  }
4517  }
4518 
4519  return SCIP_OKAY;
4520 }
4521 
4522 /** returns whether one side of a constraint function is convex w.r.t. local bounds
4523  * i.e., if side == RIGHT, then returns whether constraint function is convex w.r.t. local bounds
4524  * and if side == LEFT, then returns whether constraint function is concave w.r.t. local bounds
4525  */
4526 static
4528  SCIP* scip, /**< SCIP data structure */
4529  SCIP_CONS* cons, /**< constraint */
4530  SCIP_SIDETYPE side /**< constraint side to consider */
4531  )
4532 {
4533  SCIP_CONSDATA* consdata;
4534  SCIP_VAR** xy;
4535 
4536  consdata = SCIPconsGetData(cons);
4537  assert(consdata != NULL);
4538  assert(consdata->f != NULL);
4539 
4540  switch( consdata->convextype )
4541  {
4542  case SCIP_BIVAR_ALLCONVEX:
4543  /* always convex w.r.t. right hand side and concave w.r.t. left hand side */
4544  return side == SCIP_SIDETYPE_RIGHT;
4545 
4547  {
4548  /* always not convex w.r.t. left hand side */
4549  if( side == SCIP_SIDETYPE_LEFT )
4550  return FALSE;
4551 
4552  xy = SCIPexprtreeGetVars(consdata->f);
4553  assert(xy != NULL);
4554 
4555  /* convex w.r.t. right hand side if one of the variables is fixed */
4556  return SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])) ||
4557  SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1]));
4558  }
4559 
4561  {
4562  xy = SCIPexprtreeGetVars(consdata->f);
4563  assert(xy != NULL);
4564 
4565  /* convex w.r.t. right hand side if y is fixed and
4566  * convex w.r.t. left hand side if x is fixed */
4567  return (side == SCIP_SIDETYPE_RIGHT && SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1]))) ||
4568  (side == SCIP_SIDETYPE_LEFT && SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])));
4569  }
4570 
4571  default:
4572  return FALSE;
4573  } /*lint !e788*/
4574 }
4575 
4576 #ifdef SCIP_DEBUG
4577 static
4578 void printEstimator(
4579  SCIP* scip, /**< SCIP data structure */
4580  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
4581  SCIP_CONS* cons, /**< constraint */
4582  SCIP_SIDETYPE side, /**< violated side of constraint */
4583  SCIP_ROW* row /**< row */
4584  )
4585 {
4586  SCIP_CONSDATA* consdata;
4587  const char* varnames[2] = {"x", "y"};
4588  SCIP_VAR* x;
4589  SCIP_VAR* y;
4590  int i;
4591 
4592  assert(scip != NULL);
4593  assert(cons != NULL);
4594  assert(row != NULL);
4595 
4596  consdata = SCIPconsGetData(cons);
4597  assert(consdata != NULL);
4598  x = SCIPexprtreeGetVars(consdata->f)[0];
4599  y = SCIPexprtreeGetVars(consdata->f)[1];
4600 
4601  SCIPinfoMessage(scip, NULL, "splot [%g:%g] [%g:%g] ", SCIPvarGetLbLocal(x), SCIPvarGetUbLocal(x), SCIPvarGetLbLocal(y), SCIPvarGetUbLocal(y));
4602  SCIPexprtreePrint(consdata->f, SCIPgetMessagehdlr(scip), NULL, varnames, NULL);
4603  SCIPinfoMessage(scip, NULL, "%+g", side == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
4604 
4605  SCIPinfoMessage(scip, NULL, ", %g", SCIPisInfinity(scip, SCIProwGetRhs(row)) ? -SCIProwGetLhs(row) : -SCIProwGetRhs(row));
4606  for( i = 0; i < SCIProwGetNNonz(row); ++i )
4607  {
4608  SCIP_VAR* var;
4609 
4610  var = SCIPcolGetVar(SCIProwGetCols(row)[i]);
4611  if( var != x && var != y )
4612  continue;
4613 
4614  SCIPinfoMessage(scip, NULL, "%+g * %s", SCIProwGetVals(row)[i], var == x ? "x" : "y");
4615  }
4616 
4617  SCIPinfoMessage(scip, NULL, ", \"< echo '%g %g %g'\" with circles", SCIPgetSolVal(scip, sol, x), SCIPgetSolVal(scip, sol, y), consdata->activity);
4618 
4619  SCIPinfoMessage(scip, NULL, "\n");
4620 }
4621 #endif
4622 
4623 /** tries to separate solution or LP solution by a linear cut
4624  *
4625  * assumes that constraint violations have been computed
4626  */
4627 static
4629  SCIP* scip, /**< SCIP data structure */
4630  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
4631  SCIP_CONS** conss, /**< constraints */
4632  int nconss, /**< number of constraints */
4633  int nusefulconss, /**< number of constraints that seem to be useful */
4634  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
4635  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
4636  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
4637  SCIP_RESULT* result, /**< result of separation */
4638  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 */
4639  )
4640 {
4641  SCIP_CONSHDLRDATA* conshdlrdata;
4642  SCIP_CONSDATA* consdata;
4643  SCIP_SIDETYPE violside;
4644  SCIP_Real feasibility;
4645  SCIP_Real efficacy;
4646  SCIP_Real norm;
4647  int c;
4648  SCIP_ROW* row;
4649 
4650  assert(scip != NULL);
4651  assert(conshdlr != NULL);
4652  assert(conss != NULL || nconss == 0);
4653  assert(nusefulconss <= nconss);
4654  assert(result != NULL);
4655 
4656  *result = SCIP_FEASIBLE;
4657 
4658  if( bestefficacy != NULL )
4659  *bestefficacy = 0.0;
4660 
4661  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4662  assert(conshdlrdata != NULL);
4663 
4664  for( c = 0; c < nconss; ++c )
4665  {
4666  assert(conss != NULL);
4667  consdata = SCIPconsGetData(conss[c]);
4668  assert(consdata != NULL);
4669 
4670  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
4671  {
4672  /* we are not feasible anymore */
4673  if( *result == SCIP_FEASIBLE )
4674  *result = SCIP_DIDNOTFIND;
4675 
4676  violside = SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) ? SCIP_SIDETYPE_LEFT : SCIP_SIDETYPE_RIGHT;
4677 
4678  /* generate cut */
4679  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], sol, violside, conshdlrdata->cutmaxrange, &row) );
4680  if( row == NULL ) /* failed to generate cut */
4681  continue;
4682 
4683  if( sol == NULL )
4684  feasibility = SCIPgetRowLPFeasibility(scip, row);
4685  else
4686  feasibility = SCIPgetRowSolFeasibility(scip, row, sol);
4687 
4688  switch( conshdlrdata->scaling )
4689  {
4690  case 'o' :
4691  efficacy = -feasibility;
4692  break;
4693 
4694  case 'g' :
4695  /* in difference to SCIPgetCutEfficacy, we scale by norm only if the norm is > 1.0 this avoid finding cuts
4696  * efficient which are only very slightly violated CPLEX does not seem to scale row coefficients up too
4697  * also we use infinity norm, since that seem to be the usual scaling strategy in LP solvers (equilibrium
4698  * scaling) */
4699  norm = SCIPgetRowMaxCoef(scip, row);
4700  efficacy = -feasibility / MAX(1.0, norm);
4701  break;
4702 
4703  case 's' :
4704  {
4705  SCIP_Real abslhs = REALABS(SCIProwGetLhs(row));
4706  SCIP_Real absrhs = REALABS(SCIProwGetRhs(row));
4707  SCIP_Real minval = MIN(abslhs, absrhs);
4708 
4709  efficacy = -feasibility / MAX(1.0, minval);
4710  break;
4711  }
4712 
4713  default:
4714  SCIPerrorMessage("Unknown scaling method '%c'.", conshdlrdata->scaling);
4715  SCIPABORT();
4716  return SCIP_INVALIDDATA; /*lint !e527*/
4717  }
4718 
4719  SCIPdebug( printEstimator(scip, sol, conss[c], violside, row) );
4720 
4721  /* 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 */
4722  if( (SCIPisGT(scip, efficacy, minefficacy) ||
4723  (inenforcement && SCIPisGT(scip, efficacy, SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip)) && isConvexLocal(scip, conss[c], violside))) &&
4724  SCIPisCutApplicable(scip, row) )
4725  {
4726  SCIP_Bool infeasible;
4727 
4728  /* cut cuts off solution sufficiently */
4729  SCIP_CALL( SCIPaddCut(scip, sol, row, FALSE, &infeasible) );
4730  if( infeasible )
4731  {
4732  SCIPdebugMessage("cut for constraint <%s> is infeasible -> cutoff.\n", SCIPconsGetName(conss[c]));
4733  *result = SCIP_CUTOFF;
4734  }
4735  else
4736  {
4737  SCIPdebugMessage("added cut with efficacy %g for constraint <%s> violated by %g\n", efficacy, SCIPconsGetName(conss[c]), MAX(consdata->lhsviol, consdata->rhsviol));
4738  *result = SCIP_SEPARATED;
4739  }
4740  if( bestefficacy != NULL && efficacy > *bestefficacy )
4741  *bestefficacy = efficacy;
4742 
4743  /* mark row as not removable from LP for current node, if in enforcement */
4744  if( inenforcement && !conshdlrdata->enfocutsremovable )
4745  SCIPmarkRowNotRemovableLocal(scip, row);
4746  }
4747  else
4748  {
4749  SCIPdebugMessage("abandon cut since efficacy %g is too small or not applicable\n", efficacy);
4750  }
4751 
4752  SCIP_CALL( SCIPreleaseRow(scip, &row) );
4753  }
4754 
4755  if( *result == SCIP_CUTOFF )
4756  break;
4757 
4758  /* enforce only useful constraints
4759  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
4760  */
4761  if( c >= nusefulconss && *result == SCIP_FEASIBLE )
4762  break;
4763  }
4764 
4765  return SCIP_OKAY;
4766 }
4767 
4768 /** processes the event that a new primal solution has been found adds linearizations of all-convex constraints to the cutpool */
4769 static
4770 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
4772  SCIP_CONSHDLR* conshdlr;
4773  SCIP_CONSHDLRDATA* conshdlrdata;
4774  SCIP_CONS** conss;
4775  int nconss;
4776  SCIP_CONSDATA* consdata;
4777  int c;
4778  SCIP_SOL* sol;
4779  SCIP_ROW* row;
4780  SCIP_Real x0y0[2];
4781 
4782  assert(scip != NULL);
4783  assert(event != NULL);
4784  assert(eventdata != NULL);
4785  assert(eventhdlr != NULL);
4786 
4787  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
4788 
4789  conshdlr = (SCIP_CONSHDLR*)eventdata;
4790 
4791  nconss = SCIPconshdlrGetNConss(conshdlr);
4792 
4793  if( nconss == 0 )
4794  return SCIP_OKAY;
4795 
4796  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4797  assert(conshdlrdata != NULL);
4798 
4799  sol = SCIPeventGetSol(event);
4800  assert(sol != NULL);
4801 
4802  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
4803  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
4804  * or are from the tree, but postprocessed via proposeFeasibleSolution
4805  */
4806  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
4807  return SCIP_OKAY;
4808 
4809  conss = SCIPconshdlrGetConss(conshdlr);
4810  assert(conss != NULL);
4811 
4812  SCIPdebugMessage("catched new sol event %x from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
4813 
4814  row = NULL;
4815 
4816  for( c = 0; c < nconss; ++c )
4817  {
4818  if( SCIPconsIsLocal(conss[c]) )
4819  continue;
4820 
4821  consdata = SCIPconsGetData(conss[c]);
4822  assert(consdata != NULL);
4823 
4824  if( consdata->convextype == SCIP_BIVAR_ALLCONVEX && !SCIPisInfinity(scip, consdata->rhs) )
4825  {
4826  SCIP_CALL( SCIPgetSolVals(scip, sol, 2, SCIPexprtreeGetVars(consdata->f), x0y0) );
4827  SCIP_CALL( generateLinearizationCut(scip, conshdlrdata->exprinterpreter, conss[c], x0y0, TRUE, &row) );
4828  }
4829  else
4830  continue;
4831 
4832  if( row == NULL )
4833  continue;
4834 
4835  assert(!SCIProwIsLocal(row));
4836 
4837  SCIP_CALL( SCIPaddPoolCut(scip, row) );
4838  SCIP_CALL( SCIPreleaseRow(scip, &row) );
4839  }
4840 
4841  return SCIP_OKAY;
4842 }
4843 
4844 /** registers unfixed variables in nonlinear terms of violated constraints as external branching candidates
4845  * We score the variables by their gap between the convex envelope and the bivariate function in the current (x,y).
4846  * This value is given by the constraint violation, since we assume that cuts have been generated which support
4847  * the convex envelope in the LP.
4848  */
4849 static
4851  SCIP* scip, /**< SCIP data structure */
4852  SCIP_CONS** conss, /**< constraints to check */
4853  int nconss, /**< number of constraints to check */
4854  int* nnotify /**< counter for number of notifications performed */
4855  )
4856 {
4857  SCIP_CONSDATA* consdata;
4858  SCIP_VAR** xy;
4859  int c;
4860 
4861  assert(scip != NULL);
4862  assert(conss != NULL || nconss == 0);
4863 
4864  *nnotify = 0;
4865 
4866  for( c = 0; c < nconss; ++c )
4867  {
4868  assert(conss != NULL);
4869  consdata = SCIPconsGetData(conss[c]);
4870  assert(consdata != NULL);
4871  SCIPdebugMessage("cons <%s> violation: %g %g\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol);
4872 
4873  xy = SCIPexprtreeGetVars(consdata->f);
4874  assert(xy != NULL);
4875 
4876  /* @todo prefer binary before continuous, prefer unbounded before bounded */
4877 
4878  switch( consdata->convextype )
4879  {
4881  {
4882  /* need to branch on the variable in which function is concave (or linear) */
4883  if( !SCIPisFeasZero(scip, consdata->lhsviol) )
4884  {
4885  /* regarding left hand side, we are concave in x and convex in y, so branch on x, if not fixed */
4886  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])) )
4887  {
4888  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);
4889  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[0], consdata->lhsviol, SCIP_INVALID) );
4890  ++*nnotify;
4891  }
4892  }
4893  if( !SCIPisFeasZero(scip, consdata->rhsviol) )
4894  {
4895  /* regarding right hand side, we are convex in x and concave in y, so branch on y, if not fixed */
4896  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1])) )
4897  {
4898  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);
4899  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[1], consdata->lhsviol, SCIP_INVALID) );
4900  ++*nnotify;
4901  }
4902  }
4903  break;
4904  }
4905 
4907  {
4908  if( !SCIPisFeasZero(scip, consdata->rhsviol) )
4909  if( SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])) || SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1])) )
4910  break;
4911 
4912  /* register both variables, if not fixed */
4913  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])) )
4914  {
4915  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);
4916  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[0], consdata->lhsviol, SCIP_INVALID) );
4917  ++*nnotify;
4918  }
4919 
4920  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1])) )
4921  {
4922  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);
4923  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[1], consdata->lhsviol, SCIP_INVALID) );
4924  ++*nnotify;
4925  }
4926 
4927  break;
4928  }
4929 
4930  case SCIP_BIVAR_ALLCONVEX:
4931  {
4932  if( SCIPisFeasZero(scip, consdata->lhsviol) )
4933  continue;
4934  } /*lint -fallthrough*/
4935 
4936  default:
4937  {
4938  /* register both variables, if not fixed */
4939  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[0]), SCIPvarGetUbLocal(xy[0])) )
4940  {
4941  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);
4942  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[0], consdata->lhsviol, SCIP_INVALID) );
4943  ++*nnotify;
4944  }
4945 
4946  if( !SCIPisEQ(scip, SCIPvarGetLbLocal(xy[1]), SCIPvarGetUbLocal(xy[1])) )
4947  {
4948  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);
4949  SCIP_CALL( SCIPaddExternBranchCand(scip, xy[1], consdata->lhsviol, SCIP_INVALID) );
4950  ++*nnotify;
4951  }
4952  }
4953  } /*lint !e788*/
4954  }
4955 
4956  return SCIP_OKAY;
4957 }
4958 
4959 /** registers a nonlinear variable from a violated constraint as branching candidate that has a large absolute value in the LP relaxation */
4960 static
4962  SCIP* scip, /**< SCIP data structure */
4963  SCIP_CONS** conss, /**< constraints */
4964  int nconss, /**< number of constraints */
4965  SCIP_VAR** brvar /**< buffer to store branching variable */
4966  )
4967 {
4968  SCIP_CONSDATA* consdata;
4969  SCIP_VAR* var;
4970  SCIP_Real val;
4971  SCIP_Real brvarval;
4972  int i;
4973  int c;
4974 
4975  assert(scip != NULL);
4976  assert(conss != NULL || nconss == 0);
4977 
4978  *brvar = NULL;
4979  brvarval = -1.0;
4980 
4981  for( c = 0; c < nconss; ++c )
4982  {
4983  assert(conss != NULL);
4984  consdata = SCIPconsGetData(conss[c]);
4985  assert(consdata != NULL);
4986  assert(consdata->f != NULL);
4987 
4988  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
4989  continue;
4990 
4991  for( i = 0; i < 2; ++i )
4992  {
4993  var = SCIPexprtreeGetVars(consdata->f)[i];
4994  /* do not propose fixed variables */
4995  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
4996  continue;
4997  val = SCIPgetSolVal(scip, NULL, var);
4998  if( REALABS(val) > brvarval )
4999  {
5000  brvarval = REALABS(val);
5001  *brvar = var;
5002  }
5003  }
5004  }
5005 
5006  if( *brvar != NULL )
5007  {
5008  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
5009  }
5010 
5011  return SCIP_OKAY;
5012 }
5013 
5014 /** enforces violated bivariate constraints where both nonlinear variables can be assumed to be fixed
5015  * apply a bound change to the remaining linear variable, or recognizing infeasibility
5016  */
5017 static
5019  SCIP* scip, /**< SCIP data structure */
5020  SCIP_CONS** conss, /**< constraints */
5021  int nconss, /**< number of constraints */
5022  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
5023  SCIP_Bool* infeasible /**< whether we detected infeasibility */
5024  )
5025 {
5026  SCIP_CONSDATA* consdata;
5027  SCIP_INTERVAL nonlinact;
5028  SCIP_Real lhs;
5029  SCIP_Real rhs;
5030  int c;
5031 
5032  assert(scip != NULL);
5033  assert(conss != NULL || nconss == 0);
5034  assert(reduceddom != NULL);
5035  assert(infeasible != NULL);
5036 
5037  *reduceddom = FALSE;
5038  *infeasible = FALSE;
5039 
5040  for( c = 0; c < nconss; ++c )
5041  {
5042  assert(conss != NULL);
5043  consdata = SCIPconsGetData(conss[c]);
5044  assert(consdata != NULL);
5045 
5046  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5047  continue;
5048 
5049  /* get activity for f(x,y) */
5050  SCIP_CALL( SCIPevalExprtreeLocalBounds(scip, consdata->f, SCIPinfinity(scip), &nonlinact) );
5051  assert(!SCIPintervalIsEmpty(SCIPinfinity(scip), nonlinact));
5052 
5053  /* if all variables are fixed (at least up to epsilson), then the activity of the nonlinear part should be bounded */
5054  assert(!SCIPisInfinity(scip, -SCIPintervalGetInf(nonlinact)));
5055  assert(!SCIPisInfinity(scip, SCIPintervalGetSup(nonlinact)));
5056 
5057  if( !SCIPisInfinity(scip, -consdata->lhs) )
5058  lhs = consdata->lhs - SCIPintervalGetSup(nonlinact);
5059  else
5060  lhs = -SCIPinfinity(scip);
5061 
5062  if( !SCIPisInfinity(scip, consdata->rhs) )
5063  rhs = consdata->rhs - SCIPintervalGetInf(nonlinact);
5064  else
5065  rhs = SCIPinfinity(scip);
5066 
5067  if( consdata->z != NULL )
5068  {
5069  SCIP_Bool tightened;
5070  SCIP_Real coef;
5071 
5072  coef = consdata->zcoef;
5073  assert(!SCIPisZero(scip, coef));
5074 
5075  SCIPdebugMessage("Linear constraint with one variable: %g <= %g <%s> <= %g\n", lhs, coef, SCIPvarGetName(consdata->z), rhs);
5076 
5077  /* possibly correct lhs/rhs */
5078  if( coef >= 0.0 )
5079  {
5080  if( !SCIPisInfinity(scip, -lhs) )
5081  lhs /= coef;
5082  if( !SCIPisInfinity(scip, rhs) )
5083  rhs /= coef;
5084  }
5085  else
5086  {
5087  SCIP_Real h;
5088  h = rhs;
5089  if( !SCIPisInfinity(scip, -lhs) )
5090  rhs = lhs/coef;
5091  else
5092  rhs = SCIPinfinity(scip);
5093 
5094  if( !SCIPisInfinity(scip, h) )
5095  lhs = h/coef;
5096  else
5097  lhs = -SCIPinfinity(scip);
5098  }
5099  SCIPdebugMessage("Linear constraint is a bound: %g <= <%s> <= %g\n", lhs, SCIPvarGetName(consdata->z), rhs);
5100 
5101  if( !SCIPisInfinity(scip, -lhs) )
5102  {
5103  SCIP_CALL( SCIPtightenVarLb(scip, consdata->z, lhs, TRUE, infeasible, &tightened) );
5104  if( *infeasible )
5105  {
5106  SCIPdebugMessage("Lower bound leads to infeasibility.\n");
5107  return SCIP_OKAY;
5108  }
5109  if( tightened )
5110  {
5111  SCIPdebugMessage("Lower bound changed.\n");
5112  *reduceddom = TRUE;
5113  return SCIP_OKAY;
5114  }
5115  }
5116 
5117  if( !SCIPisInfinity(scip, rhs) )
5118  {
5119  SCIP_CALL( SCIPtightenVarUb(scip, consdata->z, rhs, TRUE, infeasible, &tightened) );
5120  if( *infeasible )
5121  {
5122  SCIPdebugMessage("Upper bound leads to infeasibility.\n");
5123  return SCIP_OKAY;
5124  }
5125  if( tightened )
5126  {
5127  SCIPdebugMessage("Upper bound changed.\n");
5128  *reduceddom = TRUE;
5129  return SCIP_OKAY;
5130  }
5131  }
5132  }
5133  else
5134  {
5135  /* no variable, thus check feasibility of lhs <= 0.0 <= rhs */
5136  *infeasible = SCIPisFeasGT(scip, lhs, 0.0) || SCIPisFeasLT(scip, rhs, 0.0);
5137  }
5138  }
5139 
5140  return SCIP_OKAY;
5141 }
5142 
5143 /** tightens bounds on a variable to given interval */
5144 static
5146  SCIP* scip, /**< SCIP data structure */
5147  SCIP_VAR* var, /**< variable which bounds to tighten */
5148  SCIP_INTERVAL bounds, /**< new bounds */
5149  SCIP_CONS* cons, /**< constraint that is propagated */
5150  SCIP_RESULT* result, /**< pointer where to update the result of the propagation call */
5151  int* nchgbds /**< buffer where to add the the number of changed bounds */
5152  )
5153 {
5154  SCIP_Bool infeas;
5155  SCIP_Bool tightened;
5156  SCIP_Real bnd;
5157 
5158  assert(scip != NULL);
5159  assert(var != NULL);
5160  assert(result != NULL);
5161  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
5162  assert(nchgbds != NULL);
5163 
5164  if( SCIPintervalIsPositiveInfinity(SCIPinfinity(scip), bounds) ||
5166  SCIPintervalIsEmpty(SCIPinfinity(scip), bounds) )
5167  {
5168  /* domain outside [-infty, +infty] or empty -> declare node infeasible */
5169  SCIPdebugMessage("found <%s> infeasible due to domain propagation for variable <%s>\n", cons != NULL ? SCIPconsGetName(cons) : "???", SCIPvarGetName(var)); /*lint !e585*/
5170  *result = SCIP_CUTOFF;
5171  return SCIP_OKAY;
5172  }
5173 
5175  {
5176  bnd = SCIPadjustedVarLb(scip, var, SCIPintervalGetInf(bounds));
5177  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
5178  if( infeas )
5179  {
5180  SCIPdebugMessage("found <%s> infeasible due to domain propagation for variable <%s>\n", cons != NULL ? SCIPconsGetName(cons) : "???", SCIPvarGetName(var)); /*lint !e585*/
5181  *result = SCIP_CUTOFF;
5182  return SCIP_OKAY;
5183  }
5184  if( tightened )
5185  {
5186  SCIPdebugMessage("tightened lower bound of variable <%s> in constraint <%s> to %g\n", SCIPvarGetName(var), cons != NULL ? SCIPconsGetName(cons) : "???", SCIPvarGetLbLocal(var)); /*lint !e585*/
5187  ++*nchgbds;
5188  *result = SCIP_REDUCEDDOM;
5189  }
5190  }
5191 
5193  {
5194  bnd = SCIPadjustedVarLb(scip, var, SCIPintervalGetSup(bounds));
5195  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
5196  if( infeas )
5197  {
5198  SCIPdebugMessage("found <%s> infeasible due to domain propagation for variable <%s>\n", cons != NULL ? SCIPconsGetName(cons) : "???", SCIPvarGetName(var)); /*lint !e585*/
5199  *result = SCIP_CUTOFF;
5200  return SCIP_OKAY;
5201  }
5202  if( tightened )
5203  {
5204  SCIPdebugMessage("tightened upper bound of variable <%s> in constraint <%s> to %g\n", SCIPvarGetName(var), cons != NULL ? SCIPconsGetName(cons) : "???", SCIPvarGetUbLocal(var)); /*lint !e585*/
5205  ++*nchgbds;
5206  *result = SCIP_REDUCEDDOM;
5207  }
5208  }
5209 
5210  return SCIP_OKAY;
5211 }
5212 
5213 /** tightens bounds of z in a single bivariate constraint
5214  * checks for redundancy and infeasibility
5215  */
5216 static
5218  SCIP* scip, /**< SCIP data structure */
5219  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5220  SCIP_CONS* cons, /**< constraint to process */
5221  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
5222  int* nchgbds, /**< buffer where to add the the number of changed bounds */
5223  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
5224  )
5225 {
5226  SCIP_CONSHDLRDATA* conshdlrdata;
5227  SCIP_CONSDATA* consdata;
5228  SCIP_INTERVAL consbounds; /* left and right side of constraint */
5229  SCIP_INTERVAL ftermactivity; /* activity of f(x,y) */
5230  SCIP_INTERVAL ztermactivity; /* activity of c*z */
5231  SCIP_INTERVAL consactivity; /* activity of f(x,y) + c*z */
5232  SCIP_INTERVAL tmp;
5233  SCIP_Bool cutoff;
5234 
5235  assert(scip != NULL);
5236  assert(cons != NULL);
5237  assert(result != NULL);
5238  assert(nchgbds != NULL);
5239 
5240  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5241  assert(conshdlrdata != NULL);
5242  assert(conshdlrdata->exprgraph != NULL);
5243 
5244  consdata = SCIPconsGetData(cons);
5245  assert(consdata != NULL);
5246  assert(consdata->exprgraphnode != NULL);
5247 
5248  *result = SCIP_DIDNOTRUN;
5249  *redundant = FALSE;
5250 
5251  /* extend interval by epsilon to avoid cutoff in forward propagation if constraint is only almost feasible */
5252  SCIPintervalSetBounds(&consbounds,
5253  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -consdata->lhs+SCIPepsilon(scip)), /*lint !e666*/
5254  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, consdata->rhs+SCIPepsilon(scip)) ); /*lint !e666*/
5255 
5256  /* get activity for f(x,y) */
5257  ftermactivity = SCIPexprgraphGetNodeBounds(consdata->exprgraphnode);
5258  assert(!SCIPintervalIsEmpty(SCIPinfinity(scip), ftermactivity) );
5259 
5260  /* get activity for c*z */
5261  if( consdata->z != NULL )
5262  {
5263  SCIPintervalSetBounds(&ztermactivity,
5264  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -MIN(SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z))), /*lint !e666*/
5265  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, MAX(SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z)))); /*lint !e666*/
5266  SCIPintervalMulScalar(INTERVALINFTY, &ztermactivity, ztermactivity, consdata->zcoef);
5267  }
5268  else
5269  {
5270  SCIPintervalSet(&ztermactivity, 0.0);
5271  }
5272 
5273  /* get activity for f(x,y)+c*z */
5274  SCIPintervalAdd(INTERVALINFTY, &consactivity, ftermactivity, ztermactivity);
5275 
5276  /* check redundancy */
5277  if( SCIPintervalIsSubsetEQ(INTERVALINFTY, consactivity, consbounds) )
5278  {
5279  SCIPdebugMessage("found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
5280  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
5281  *redundant = TRUE;
5282  return SCIP_OKAY;
5283  }
5284 
5285  /* check infeasibility */
5286  if( SCIPintervalAreDisjoint(consbounds, consactivity) )
5287  {
5288  SCIPdebugMessage("found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %g\n",
5289  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
5290  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs)); /*lint !e666*/
5291  *result = SCIP_CUTOFF;
5292  return SCIP_OKAY;
5293  }
5294 
5295  /* try to tighten bounds on z */
5296  if( consdata->z != NULL )
5297  {
5298  *result = SCIP_DIDNOTFIND;
5299 
5300  /* compute ([lhs, rhs] - f([xlb,xub], [ylb,yub])) / zcoef */
5301  SCIPintervalSub(INTERVALINFTY, &tmp, consbounds, ftermactivity);
5302  SCIPintervalDivScalar(INTERVALINFTY, &tmp, tmp, consdata->zcoef);
5303 
5304  SCIP_CALL( propagateBoundsTightenVar(scip, consdata->z, tmp, cons, result, nchgbds) );
5305 
5306  if( *result == SCIP_CUTOFF )
5307  return SCIP_OKAY;
5308 
5309  if( *result == SCIP_SUCCESS )
5310  {
5311  SCIPintervalSetBounds(&ztermactivity,
5312  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -MIN(SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z))), /*lint !e666*/
5313  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, MAX(SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z)))); /*lint !e666*/
5314  SCIPintervalMulScalar(INTERVALINFTY, &ztermactivity, ztermactivity, consdata->zcoef);
5315  }
5316  }
5317 
5318  /* set bounds for exprgraphnode = [lhs,rhs] - c*z */
5319  SCIPintervalSub(INTERVALINFTY, &tmp, consbounds, ztermactivity);
5320  SCIPexprgraphTightenNodeBounds(conshdlrdata->exprgraph, consdata->exprgraphnode, tmp, 0.05, INTERVALINFTY, &cutoff);
5321  if( cutoff )
5322  {
5323  SCIPdebugMessage("found constraint <%s> infeasible%s\n", SCIPconsGetName(cons), SCIPinProbing(scip) ? " in probing" : "");
5324  *result = SCIP_CUTOFF;
5325  return SCIP_OKAY;
5326  }
5327 
5328  return SCIP_OKAY;
5329 }
5330 
5331 /** calls domain propagation for a set of constraints */
5332 static
5334  SCIP* scip, /**< SCIP data structure */
5335  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5336  SCIP_CONS** conss, /**< constraints to process */
5337  int nconss, /**< number of constraints */
5338  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
5339  int* nchgbds, /**< buffer where to add the the number of changed bounds */
5340  int* ndelconss /**< buffer where to increase if a constraint was deleted (locally) due to redundancy */
5341  )
5342 {
5343  SCIP_CONSHDLRDATA* conshdlrdata;
5344  SCIP_CONSDATA* consdata;
5345  SCIP_RESULT propresult;
5346  SCIP_Bool redundant;
5347  SCIP_Bool domainerror;
5348  int roundnr;
5349  SCIP_Bool success;
5350  int nvars;
5351  SCIP_VAR** vars;
5352  SCIP_EXPRGRAPHNODE** varnodes;
5353  SCIP_Bool cutoff;
5354  int c;
5355  int i;
5356 
5357  assert(scip != NULL);
5358  assert(conshdlr != NULL);
5359  assert(conss != NULL || nconss == 0);
5360  assert(result != NULL);
5361  assert(nchgbds != NULL);
5362  assert(ndelconss != NULL);
5363 
5364  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5365  assert(conshdlrdata != NULL);
5366  assert(conshdlrdata->exprgraph != NULL);
5367 
5368  *result = SCIP_DIDNOTRUN;
5369 
5370  if( nconss == 0 )
5371  return SCIP_OKAY;
5372 
5373  if( conshdlrdata->ispropagated )
5374  {
5375  /* check whether there was also no tightening in the bounds of the linear variables
5376  * @todo put this in processLinearVarEvent
5377  */
5378  for( c = 0; c < nconss; ++c )
5379  {
5380  assert(conss[c] != NULL); /*lint !e613*/
5381 
5382  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
5383  assert(consdata != NULL);
5384  if( !consdata->ispropagated )
5385  break;
5386  }
5387  if( c == nconss )
5388  return SCIP_OKAY;
5389  }
5390 
5391  *result = SCIP_DIDNOTFIND;
5392 
5393  roundnr = 0;
5394  do
5395  {
5396  success = FALSE;
5397 
5398  SCIPdebugMessage("starting domain propagation round %d for %d constraints\n", roundnr, nconss);
5399 
5400  conshdlrdata->ispropagated = TRUE;
5401 
5402  /* propagate variable bounds through expression graph
5403  * roundnr == 0 clears remainings from a previous backward propagation
5404  * @todo could give FALSE if no linear variable in the constraints had been relaxed since last time
5405  */
5406  SCIP_CALL( SCIPexprgraphPropagateVarBounds(conshdlrdata->exprgraph, INTERVALINFTY, roundnr == 0, &domainerror) );
5407 
5408  if( domainerror )
5409  {
5410  SCIPdebugMessage("current bounds out of domain for some expression, do cutoff\n");
5411  *result = SCIP_CUTOFF;
5412  break;
5413  }
5414 
5415  /* check for redundancy and infeasibility of constraints
5416  * tighten bounds on linear variables
5417  * setup bounds for expression graph nodes */
5418  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
5419  {
5420  assert(conss != NULL);
5421  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
5422  continue;
5423 
5424  consdata = SCIPconsGetData(conss[c]);
5425  assert(consdata != NULL);
5426 
5427  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
5428  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
5429  {
5430  *result = propresult;
5431  success = TRUE;
5432  }
5433  if( redundant )
5434  {
5435  SCIPdebugMessage("delete redundant constraint <%s> locally\n", SCIPconsGetName(conss[c]));
5436  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
5437  ++*ndelconss;
5438  }
5439 
5440  consdata->ispropagated = TRUE;
5441  }
5442  if( *result == SCIP_CUTOFF )
5443  break;
5444 
5445  /* propagate backward through expression graph */
5446  SCIPdebugMessage("start backward propagation in expression graph\n");
5447 
5448  /* compute bound tightenings for nonlinear variables */
5449  SCIPexprgraphPropagateNodeBounds(conshdlrdata->exprgraph, INTERVALINFTY, 0.05, &cutoff);
5450 
5451  if( cutoff )
5452  {
5453  SCIPdebugMessage("backward propagation found problem infeasible%s\n", SCIPinProbing(scip) ? " in probing" : "");
5454  *result = SCIP_CUTOFF;
5455  break;
5456  }
5457 
5458  /* put back new bounds into SCIP variables */
5459  nvars = SCIPexprgraphGetNVars(conshdlrdata->exprgraph);
5460  vars = (SCIP_VAR**)SCIPexprgraphGetVars(conshdlrdata->exprgraph);
5461  varnodes = SCIPexprgraphGetVarNodes(conshdlrdata->exprgraph);
5462  propresult = SCIP_DIDNOTFIND;
5463  for( i = 0; i < nvars && propresult != SCIP_CUTOFF; ++i )
5464  {
5465  SCIP_CALL( propagateBoundsTightenVar(scip, vars[i], SCIPexprgraphGetNodeBounds(varnodes[i]), NULL, &propresult, nchgbds) );
5466  }
5467  if( propresult != SCIP_DIDNOTFIND )
5468  {
5469  *result = propresult;
5470  success = TRUE;
5471  }
5472  }
5473  while( success && *result != SCIP_CUTOFF && ++roundnr < conshdlrdata->maxproprounds );
5474 
5475  return SCIP_OKAY;
5476 }
5477 
5478 
5479 /** Given a solution where every bivariate constraint is either feasible or can be made feasible by
5480  * moving the linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
5481  * The method assumes that this is always possible and that not all constraints are feasible already.
5482  */
5483 static
5485  SCIP* scip, /**< SCIP data structure */
5486  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5487  SCIP_CONS** conss, /**< constraints to process */
5488  int nconss, /**< number of constraints */
5489  SCIP_SOL* sol, /**< solution to process */
5490  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
5491  )
5492 {
5493  SCIP_CONSHDLRDATA* conshdlrdata;
5494  SCIP_CONSDATA* consdata;
5495  SCIP_SOL* newsol;
5496  SCIP_VAR* var;
5497  int c;
5498  SCIP_Real viol;
5499  SCIP_Real delta;
5500  SCIP_Real gap;
5501 
5502  assert(scip != NULL);
5503  assert(conshdlr != NULL);
5504  assert(conss != NULL || nconss == 0);
5505  assert(success != NULL);
5506 
5507  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5508  assert(conshdlrdata != NULL);
5509  assert(conshdlrdata->trysolheur != NULL);
5510 
5511  *success = FALSE;
5512 
5513  /* don't propose new solutions if not in presolve or solving */
5515  return SCIP_OKAY;
5516 
5517  if( sol != NULL )
5518  {
5519  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
5520  }
5521  else
5522  {
5523  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
5524  }
5525  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
5526 
5527  for( c = 0; c < nconss; ++c )
5528  {
5529  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
5530  assert(consdata != NULL);
5531 
5532  /* recompute violation of solution in case solution has changed
5533  * get absolution violation and sign */
5534  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
5535  {
5536  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
5537  viol = consdata->lhs - consdata->activity;
5538  }
5539  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5540  {
5541  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
5542  viol = consdata->rhs - consdata->activity;
5543  }
5544  else
5545  continue; /* constraint is satisfied */
5546 
5547  assert(viol != 0.0);
5548  if( consdata->mayincreasez &&
5549  ((viol > 0.0 && consdata->zcoef > 0.0) || (viol < 0.0 && consdata->zcoef < 0.0)) )
5550  {
5551  /* have variable where increasing makes the constraint less violated */
5552  var = consdata->z;
5553  /* compute how much we would like to increase var */
5554  delta = viol / consdata->zcoef;
5555  assert(delta > 0.0);
5556  /* if var has an upper bound, may need to reduce delta */
5557  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
5558  {
5559  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
5560  delta = MIN(MAX(0.0, gap), delta);
5561  }
5562  if( SCIPisPositive(scip, delta) )
5563  {
5564  /* if variable is integral, round delta up so that it will still have an integer value */
5565  if( SCIPvarIsIntegral(var) )
5566  delta = SCIPceil(scip, delta);
5567 
5568  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
5569  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
5570 
5571  /* adjust constraint violation, if satisfied go on to next constraint */
5572  viol -= consdata->zcoef * delta;
5573  if( SCIPisZero(scip, viol) )
5574  continue;
5575  }
5576  }
5577 
5578  assert(viol != 0.0);
5579  if( consdata->maydecreasez &&
5580  ((viol > 0.0 && consdata->zcoef < 0.0) || (viol < 0.0 && consdata->zcoef > 0.0)) )
5581  {
5582  /* have variable where decreasing makes constraint less violated */
5583  var = consdata->z;
5584  /* compute how much we would like to decrease var */
5585  delta = viol / consdata->zcoef;
5586  assert(delta < 0.0);
5587  /* if var has a lower bound, may need to reduce delta */
5588  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
5589  {
5590  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
5591  delta = MAX(MIN(0.0, gap), delta);
5592  }
5593  if( SCIPisNegative(scip, delta) )
5594  {
5595  /* if variable is integral, round delta down so that it will still have an integer value */
5596  if( SCIPvarIsIntegral(var) )
5597  delta = SCIPfloor(scip, delta);
5598  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
5599  SCIPdebugMessage("increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
5600 
5601  /* adjust constraint violation, if satisfied go on to next constraint */
5602  viol -= consdata->zcoef * delta;
5603  if( SCIPisZero(scip, viol) )
5604  continue;
5605  }
5606  }
5607 
5608  /* still here... so maybe we could not make constraint feasible due to variable bounds
5609  * check if we are feasible w.r.t. (relative) feasibility tolerance */
5610  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol) ); /*lint !e613*/
5611  /* if still violated, we give up */
5612  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5613  break;
5614 
5615  /* if objective value is not better than current upper bound, we give up */
5616  if( !SCIPisInfinity(scip, SCIPgetUpperbound(scip)) && !SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip)) )
5617  break;
5618  }
5619 
5620  /* if we have a solution that should satisfy all nonlinear constraints and has a better objective than the current upper bound,
5621  * then pass it to the trysol heuristic */
5622  if( c == nconss )
5623  {
5624  SCIPdebugMessage("pass solution with objective value %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
5625 
5626  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
5627  *success = TRUE;
5628  }
5629 
5630  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
5631 
5632  return SCIP_OKAY;
5633 }
5634 
5635 /** creates bivariate constraint from quadratic constraint data of the form
5636  * lhs <= xsqrcoef * x^2 + xlincoef * x + ysqrcoef * y^2 + ylincoef * y + bilincoef * x*y + zcoef * z <= rhs
5637  */
5638 static
5640  SCIP* scip, /**< SCIP data structure */
5641  SCIP_CONS* srccons, /**< source constraint to take attributes from */
5642  SCIP_CONS** cons, /**< pointer to store new constraint */
5643  const char* name, /**< name of new constraint */
5644  SCIP_VAR* x, /**< first nonlinear variable */
5645  SCIP_VAR* y, /**< second nonlinear variable */
5646  SCIP_VAR* z, /**< linear variable, can be NULL */
5647  SCIP_Real coefxx, /**< coefficient of x^2 */
5648  SCIP_Real coefx, /**< coefficient of x */
5649  SCIP_Real coefyy, /**< coefficient of y^2 */
5650  SCIP_Real coefy, /**< coefficient of y */
5651  SCIP_Real coefxy, /**< coefficient of x*y */
5652  SCIP_Real coefz, /**< coefficient of z */
5653  SCIP_Real lhs, /**< left-hand-side */
5654  SCIP_Real rhs /**< right-hand-side */
5655  )
5656 {
5657  SCIP_Real mult;
5658  SCIP_VAR* xy[2];
5659  SCIP_BIVAR_CONVEXITY convextype;
5660  SCIP_EXPR* e;
5661  SCIP_EXPRTREE* exprtree;
5662 
5663  SCIP_EXPR* children[2];
5664  SCIP_Real lincoefs[2];
5665  SCIP_QUADELEM quadelems[3];
5666  int nquadelems;
5667 
5668  assert(scip != NULL);
5669  assert(srccons != NULL);
5670  assert(cons != NULL);
5671  assert(name != NULL);
5672 
5673  assert(x != NULL);
5674  assert(y != NULL);
5675  assert(SCIPisLE(scip, lhs, rhs));
5676 
5677  if( coefxx >= 0 && coefyy >= 0 && 4 * coefxx * coefyy >= coefxy * coefxy )
5678  {
5679  /* quadratic term is convex in both variables (jointly) */
5680  mult = 1.0;
5681  convextype = SCIP_BIVAR_ALLCONVEX;
5682  }
5683  else if( coefxx <= 0 && coefyy <= 0 && 4 * coefxx * coefyy >= coefxy * coefxy )
5684  {
5685  /* quadratic term is concave in both variables (jointly) */
5686  mult = -1.0;
5687  convextype = SCIP_BIVAR_ALLCONVEX;
5688  }
5689  else if( coefxx > 0 && coefyy > 0 )
5690  {
5691  /* indefinite but 1-convex */
5692  assert(4 * coefxx * coefyy < coefxy * coefxy); /* assert indefiniteness */
5693  mult = 1.0;
5694  convextype = SCIP_BIVAR_1CONVEX_INDEFINITE;
5695  }
5696  else if( coefxx < 0 && coefyy < 0 )
5697  {
5698  /* indefinite but 1-convex */
5699  assert(4 * coefxx * coefyy < coefxy * coefxy); /* assert indefiniteness */
5700  mult = -1.0;
5701  convextype = SCIP_BIVAR_1CONVEX_INDEFINITE;
5702  }
5703  else
5704  {
5705  /* convex in one variable and concave in other variable */
5706  assert(coefxx * coefyy <= 0);
5707  convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5708  if( coefxx != 0.0 )
5709  {
5710  /* if coefxx < 0 (and thus coefyy >= 0) f(x,y) is concave in x and convex in y
5711  * but we need convex in x and concave in y, thus we multiply by -1
5712  */
5713  if( coefxx < 0.0 )
5714  mult = -1.0;
5715  else
5716  mult = 1.0;
5717  }
5718  else if( coefyy != 0.0 )
5719  {
5720  /* coefxx == 0.0 */
5721  /* if coefyy < 0 (and coefxx == 0) f(x,y) is concave in y and convex in x
5722  * otherwise we convert to convex in y and concave in x by multiplying by -1
5723  */
5724  if( coefyy < 0.0 )
5725  mult = 1.0;
5726  else
5727  mult = -1.0;
5728  }
5729  else
5730  {
5731  /* coefxx == 0.0 && coefyy == 0.0 && coefxy != 0.0 */
5732  assert(coefxy != 0.0);
5733  mult = 1.0;
5734  }
5735  }
5736 
5737  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &children[0], SCIP_EXPR_VARIDX, 0) );
5738  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &children[1], SCIP_EXPR_VARIDX, 1) );
5739 
5740  lincoefs[0] = coefx * mult;
5741  lincoefs[1] = coefy * mult;
5742 
5743  nquadelems = 0;
5744  if( coefxx != 0.0 )
5745  {
5746  quadelems[nquadelems].idx1 = 0;
5747  quadelems[nquadelems].idx2 = 0;
5748  quadelems[nquadelems].coef = coefxx * mult;
5749  ++nquadelems;
5750  }
5751  if( coefyy != 0.0 )
5752  {
5753  quadelems[nquadelems].idx1 = 1;
5754  quadelems[nquadelems].idx2 = 1;
5755  quadelems[nquadelems].coef = coefyy * mult;
5756  ++nquadelems;
5757  }
5758  if( coefxy != 0.0 )
5759  {
5760  quadelems[nquadelems].idx1 = 0;
5761  quadelems[nquadelems].idx2 = 1;
5762  quadelems[nquadelems].coef = coefxy * mult;
5763  ++nquadelems;
5764  }
5765 
5766  SCIP_CALL( SCIPexprCreateQuadratic(SCIPblkmem(scip), &e, 2, children, 0.0, (coefx != 0.0 || coefy != 0.0) ? lincoefs : NULL, nquadelems, quadelems) ); /*lint !e826*/
5767  assert(e != NULL);
5768 
5769  xy[0] = x;
5770  xy[1] = y;
5771 
5772  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtree, e, 2, 0, NULL) );
5773  SCIP_CALL( SCIPexprtreeSetVars(exprtree, 2, xy) );
5774 
5775  if( mult == -1.0 )
5776  {
5777  SCIP_Real tmp;
5778  tmp = lhs;
5779  lhs = -rhs;
5780  rhs = -tmp;
5781  coefz = -coefz;
5782  }
5783  else
5784  {
5785  assert(mult == 1.0);
5786  }
5787 
5788  SCIPdebugMessage("upgrading constraint <%s> to bivariate constraint <%s> with convexity type %d\n", SCIPconsGetName(srccons), name, convextype);
5789 
5790  SCIP_CALL( SCIPcreateConsBivariate(scip, cons, name,
5791  exprtree, convextype, z, coefz, lhs, rhs,
5792  SCIPconsIsInitial(srccons), SCIPconsIsSeparated(srccons), SCIPconsIsEnforced(srccons),
5793  SCIPconsIsChecked(srccons), SCIPconsIsPropagated(srccons), SCIPconsIsLocal(srccons),
5794  SCIPconsIsModifiable(srccons), SCIPconsIsDynamic(srccons), SCIPconsIsRemovable(srccons),
5795  SCIPconsIsStickingAtNode(srccons)) );
5796  SCIPdebugPrintCons(scip, *cons, NULL);
5797 
5798  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
5799 
5800  return SCIP_OKAY;
5801 }
5802 
5803 /** creates expression tree for monomial of the form coef * x^p * y^q with x >= 0 and y >= 0 and checks its convexity type */
5804 static
5806  SCIP* scip, /**< SCIP data structure */
5807  SCIP_VAR* x, /**< first variable */
5808  SCIP_VAR* y, /**< second variable */
5809  SCIP_Real coef, /**< monomial coefficient */
5810  SCIP_Real p, /**< exponent of x */
5811  SCIP_Real q, /**< exponent of y */
5812  SCIP_EXPRTREE** exprtree, /**< buffer to store pointer to expression tree */
5813  SCIP_Real* mult, /**< buffer to store multiplicator for generated expression tree */
5814  SCIP_BIVAR_CONVEXITY* convextype /**< buffer to store convexity type of expression tree */
5815  )
5816 {
5817  SCIP_Bool swapvars;
5818  SCIP_EXPR* children[2];
5819  int childidxs[2];
5820  SCIP_Real exponents[2];
5821  SCIP_VAR* vars[2];
5822  SCIP_EXPR* e;
5823  SCIP_EXPRDATA_MONOMIAL* monomial;
5824 
5825  assert(scip != NULL);
5826  assert(x != NULL);
5827  assert(y != NULL);
5828  assert(!SCIPisZero(scip, coef));
5829  assert(!SCIPisZero(scip, p));
5830  assert(!SCIPisZero(scip, q));
5831  assert(exprtree != NULL);
5832  assert(mult != NULL);
5833  assert(convextype != NULL);
5834 
5835  /* determine convexity type, and whether to negate monomial or swap variables */
5836  *mult = coef < 0.0 ? -1.0 : 1.0; /* for the check, assume that monomial has positive coefficient */
5837  swapvars = FALSE;
5838  *convextype = SCIP_BIVAR_UNKNOWN;
5839  if( (p + q >= 1.0 && ((p > 1.0 && q < 0.0) || (p < 0.0 && q > 1.0))) ||
5840  (p < 0.0 && q < 0.0) )
5841  {
5842  *convextype = SCIP_BIVAR_ALLCONVEX;
5843  }
5844  else if( (p > 1.0 && q > 1.0) || (p + q < 1.0 && ((p > 1.0 && q < 0.0) || (p < 0.0 && q > 1.0))) )
5845  {
5846  *convextype = SCIP_BIVAR_1CONVEX_INDEFINITE;
5847  }
5848  else if( (p < 0.0 || p > 1.0) && q > 0.0 && q < 1.0 )
5849  {
5850  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5851  }
5852  else if( (p < 0.0 || p > 1.0) && q == 1.0 )
5853  {
5854  *mult *= -1.0;
5855  swapvars = TRUE;
5856  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5857  }
5858  else if( (q < 0.0 || q > 1.0) && p > 0.0 && p <= 1.0 )
5859  {
5860  swapvars = TRUE;
5861  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5862  }
5863  else if( p > 0.0 && p < 1.0 && q > 0.0 && q < 1.0 && p + q > 1.0 )
5864  {
5865  *mult *= -1.0;
5866  *convextype = SCIP_BIVAR_1CONVEX_INDEFINITE;
5867  }
5868  else if( p == 1.0 && q > 0.0 && q < 1.0 )
5869  {
5870  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5871  }
5872  else if( q == 1.0 && p > 0.0 && p < 1.0 )
5873  {
5874  swapvars = TRUE;
5875  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5876  }
5877  else if( p == 1.0 && q == 1.0 )
5878  {
5879  *convextype = SCIP_BIVAR_CONVEX_CONCAVE;
5880  }
5881  else if( p > 0.0 && p < 1.0 && q > 0.0 && q < 1.0 && p + q <= 1.0 )
5882  {
5883  *mult *= -1.0;
5884  *convextype = SCIP_BIVAR_ALLCONVEX;
5885  }
5886  assert(*convextype != SCIP_BIVAR_UNKNOWN); /* there should be no case where this can still happen */
5887 
5888  /* setup expression tree */
5889  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &children[0], SCIP_EXPR_VARIDX, 0) );
5890  SCIP_CALL( SCIPexprCreate(SCIPblkmem(scip), &children[1], SCIP_EXPR_VARIDX, 1) );
5891  childidxs[0] = 0;
5892  childidxs[1] = 1;
5893  if( !swapvars )
5894  {
5895  exponents[0] = p;
5896  exponents[1] = q;
5897  vars[0] = x;
5898  vars[1] = y;
5899  }
5900  else
5901  {
5902  exponents[0] = q;
5903  exponents[1] = p;
5904  vars[0] = y;
5905  vars[1] = x;
5906  }
5907  SCIP_CALL( SCIPexprCreateMonomial(SCIPblkmem(scip), &monomial, *mult*coef, 2, childidxs, exponents) );
5908 
5909  SCIP_CALL( SCIPexprCreatePolynomial(SCIPblkmem(scip), &e, 2, children, 1, &monomial, 0.0, FALSE) );
5910  assert( e != NULL );
5911 
5912  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), exprtree, e, 2, 0, NULL) );
5913  SCIP_CALL( SCIPexprtreeSetVars(*exprtree, 2, vars) );
5914 
5915  return SCIP_OKAY;
5916 }
5917 
5918 /** creates bivariate constraint from monomial of the form coef * x^p * y^q with x >= 0 and y >= 0
5919  * lhs <= coef * x^p * y^q + zcoef * z <= rhs
5920  */
5921 static
5923  SCIP* scip, /**< SCIP data structure */
5924  SCIP_CONS* srccons, /**< source constraint to take attributes from, or NULL */
5925  SCIP_CONS** cons, /**< pointer to store new constraint */
5926  const char* name, /**< name of new constraint */
5927  SCIP_VAR* x, /**< first nonlinear variable */
5928  SCIP_VAR* y, /**< second nonlinear variable */
5929  SCIP_VAR* z, /**< linear variable, can be NULL */
5930  SCIP_Real coef, /**< monomial coefficient */
5931  SCIP_Real p, /**< exponent of x */
5932  SCIP_Real q, /**< exponent of y */
5933  SCIP_Real zcoef, /**< coefficient of z */
5934  SCIP_Real lhs, /**< left-hand-side */
5935  SCIP_Real rhs /**< right-hand-side */
5936  )
5937 {
5938  SCIP_Real mult;
5939  SCIP_BIVAR_CONVEXITY convextype;
5940  SCIP_EXPRTREE* exprtree;
5941 
5942  assert(scip != NULL);
5943  assert(cons != NULL);
5944  assert(name != NULL);
5945 
5946  assert(x != NULL);
5947  assert(y != NULL);
5948  assert(!SCIPisZero(scip, coef));
5949  assert(!SCIPisZero(scip, p));
5950  assert(!SCIPisZero(scip, q));
5951  assert(SCIPisLE(scip, lhs, rhs));
5952 
5953  SCIP_CALL( createExprtreeFromMonomial(scip, x, y, coef, p, q, &exprtree, &mult, &convextype) );
5954 
5955  if( mult == -1.0 )
5956  {
5957  SCIP_Real tmp;
5958  tmp = lhs;
5959  lhs = -rhs;
5960  rhs = -tmp;
5961  zcoef = -zcoef;
5962  }
5963  else
5964  {
5965  assert(mult == 1.0);
5966  }
5967 
5968  SCIPdebugMessage("upgrading monomial %g<%s>^%g<%s>^%g from constraint <%s> to bivariate constraint with convexity type %d\n", /*lint !e585*/
5969  coef, SCIPvarGetName(x), p, SCIPvarGetName(y), q, srccons != NULL ? SCIPconsGetName(srccons) : "??", convextype); /*lint !e585*/
5970 
5971  if( srccons != NULL )
5972  {
5973  SCIP_CALL( SCIPcreateConsBivariate(scip, cons, name,
5974  exprtree, convextype, z, zcoef, lhs, rhs,
5975  SCIPconsIsInitial(srccons), SCIPconsIsSeparated(srccons), SCIPconsIsEnforced(srccons),
5976  SCIPconsIsChecked(srccons), SCIPconsIsPropagated(srccons), SCIPconsIsLocal(srccons),
5977  SCIPconsIsModifiable(srccons), SCIPconsIsDynamic(srccons), SCIPconsIsRemovable(srccons),
5978  SCIPconsIsStickingAtNode(srccons)) );
5979  }
5980  else
5981  {
5982  SCIP_CALL( SCIPcreateConsBivariate(scip, cons, name,
5983  exprtree, convextype, z, zcoef, lhs, rhs,
5984  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5985  }
5986  SCIPdebugPrintCons(scip, *cons, NULL);
5987 
5988  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
5989 
5990  return SCIP_OKAY;
5991 }
5992 
5993 /*
5994  * Callback methods of constraint handler
5995  */
5996 
5997 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
5998 static
5999 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyBivariate)
6000 { /*lint --e{715}*/
6001  assert(scip != NULL);
6002  assert(conshdlr != NULL);
6003  /* assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); */
6004 
6005  /* call inclusion method of constraint handler */
6007 
6008  *valid = TRUE;
6009 
6010  return SCIP_OKAY;
6011 }
6012 
6013 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
6014 static
6015 SCIP_DECL_CONSFREE(consFreeBivariate)
6016 { /*lint --e{715}*/
6017  SCIP_CONSHDLRDATA* conshdlrdata;
6018 
6019  assert(scip != NULL);
6020  assert(conshdlr != NULL);
6021 
6022  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6023  assert(conshdlrdata != NULL);
6024  assert(conshdlrdata->exprinterpreter != NULL);
6025  assert(conshdlrdata->exprgraph != NULL);
6026  assert(SCIPexprgraphGetNVars(conshdlrdata->exprgraph) == 0);
6027 
6028  /* free expression graph */
6029  SCIP_CALL( SCIPexprgraphFree(&conshdlrdata->exprgraph) );
6030 
6031  if( conshdlrdata->exprinterpreter != NULL )
6032  {
6033  SCIP_CALL( SCIPexprintFree(&conshdlrdata->exprinterpreter) );
6034  }
6035 
6036  SCIPfreeMemory(scip, &conshdlrdata);
6037 
6038  return SCIP_OKAY;
6039 }
6040 
6041 /** initialization method of constraint handler (called after problem was transformed) */
6042 static
6043 SCIP_DECL_CONSINIT(consInitBivariate)
6044 { /*lint --e{715}*/
6045  SCIP_CONSHDLRDATA* conshdlrdata;
6046 
6047  assert(scip != NULL);
6048  assert(conshdlr != NULL);
6049 
6050  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6051  assert(conshdlrdata != NULL);
6052 
6053  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
6054  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
6055 
6056  return SCIP_OKAY;
6057 }
6058 
6059 /** deinitialization method of constraint handler (called before transformed problem is freed) */
6060 static
6061 SCIP_DECL_CONSEXIT(consExitBivariate)
6062 { /*lint --e{715}*/
6063  SCIP_CONSHDLRDATA* conshdlrdata;
6064 
6065  assert(scip != NULL);
6066  assert(conshdlr != NULL);
6067 
6068  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6069  assert(conshdlrdata != NULL);
6070 
6071  conshdlrdata->subnlpheur = NULL;
6072  conshdlrdata->trysolheur = NULL;
6073 
6074  return SCIP_OKAY;
6075 }
6076 
6077 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
6078 static
6079 SCIP_DECL_CONSINITPRE(consInitpreBivariate)
6080 { /*lint --e{715}*/
6081  SCIP_CONSDATA* consdata;
6082  int c;
6083 
6084  assert(scip != NULL);
6085  assert(conss != NULL || nconss == 0);
6086 
6087  for( c = 0; c < nconss; ++c )
6088  {
6089  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6090  assert(consdata != NULL);
6091 
6092  /* reset may{in,de}creasez to FALSE in case some values are still set from a previous solve round */
6093  consdata->mayincreasez = FALSE;
6094  consdata->maydecreasez = FALSE;
6095  }
6096 
6097  return SCIP_OKAY;
6098 }
6099 
6100 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
6101 static
6102 SCIP_DECL_CONSEXITPRE(consExitpreBivariate)
6103 { /*lint --e{715}*/
6104  SCIP_CONSHDLRDATA* conshdlrdata;
6105  int c;
6106  SCIP_Bool changed;
6107  SCIP_Bool upgraded;
6108 #ifndef NDEBUG
6109  SCIP_CONSDATA* consdata;
6110 #endif
6111 
6112  assert(scip != NULL);
6113  assert(conss != NULL || nconss == 0);
6114 
6115  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6116  assert(conshdlrdata != NULL);
6117 
6118  if( !conshdlrdata->isremovedfixings )
6119  {
6120  SCIP_CALL( removeFixedNonlinearVariables(scip, conshdlr) );
6121  assert(conshdlrdata->isremovedfixings);
6122  /* @todo call expression graph simplifier? */
6123  }
6124 
6125  for( c = 0; c < nconss; ++c )
6126  {
6127  assert(conss != NULL); /* for flexelint */
6128  assert(conss[c] != NULL);
6129 
6130  /* make sure variable fixations have been resolved */
6131  SCIP_CALL( removeFixedVariables(scip, conshdlr, conss[c], &changed, &upgraded) );
6132  assert(!upgraded);
6133 
6134 #ifndef NDEBUG
6135  consdata = SCIPconsGetData(conss[c]);
6136  assert(consdata != NULL);
6137 
6138  assert(consdata->f != NULL);
6139  assert(SCIPexprtreeGetNVars(consdata->f) == 2);
6140  assert(consdata->z == NULL || SCIPvarIsActive(consdata->z) || SCIPvarGetStatus(consdata->z) == SCIP_VARSTATUS_MULTAGGR);
6141 #endif
6142 
6143  /* tell SCIP that we have something nonlinear */
6144  if( SCIPconsIsAdded(conss[c]) )
6145  SCIPenableNLP(scip);
6146  }
6147 
6148  return SCIP_OKAY;
6149 }
6150 
6151 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
6152 static
6153 SCIP_DECL_CONSINITSOL(consInitsolBivariate)
6154 { /*lint --e{715}*/
6155  SCIP_CONSHDLRDATA* conshdlrdata;
6156  SCIP_CONSDATA* consdata;
6157  int c;
6158 #ifdef TYPESTATISTICS
6159  int nconvextypeslhs[(int)SCIP_BIVAR_UNKNOWN+1];
6160  int nconvextypesrhs[(int)SCIP_BIVAR_UNKNOWN+1];
6161 #endif
6162 
6163  assert(scip != NULL);
6164  assert(conss != NULL || nconss == 0);
6165 
6166  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6167  assert(conshdlrdata != NULL);
6168 
6169 #ifdef TYPESTATISTICS
6170  BMSclearMemoryArray(nconvextypeslhs, (int)SCIP_BIVAR_UNKNOWN+1);
6171  BMSclearMemoryArray(nconvextypesrhs, (int)SCIP_BIVAR_UNKNOWN+1);
6172 #endif
6173 
6174  for( c = 0; c < nconss; ++c )
6175  {
6176  assert(conss[c] != NULL); /*lint !e613*/
6177 
6178  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6179  assert(consdata != NULL);
6180 
6181  /* check if linear variable can be rounded up or down without harming other constraints */
6182  if( consdata->z != NULL )
6183  {
6184  int poslock;
6185  int neglock;
6186 
6187  if( consdata->zcoef > 0.0 )
6188  {
6189  poslock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
6190  neglock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
6191  }
6192  else
6193  {
6194  poslock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0;
6195  neglock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0;
6196  }
6197 
6198  if( SCIPvarGetNLocksDown(consdata->z) - neglock == 0 )
6199  {
6200  /* for c*z + f(x,y) \in [lhs, rhs], we can decrease z without harming other constraints */
6201  consdata->maydecreasez = TRUE;
6202  SCIPdebugMessage("may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->z));
6203  }
6204 
6205  if( SCIPvarGetNLocksDown(consdata->z) - poslock == 0 )
6206  {
6207  /* for c*x + f(x,y) \in [lhs, rhs], we can increase x without harming other constraints */
6208  consdata->mayincreasez = TRUE;
6209  SCIPdebugMessage("may increase <%s> to become feasible\n", SCIPvarGetName(consdata->z));
6210  }
6211  }
6212 
6213  /* add nlrow respresentation to NLP, if NLP had been constructed */
6214  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) ) /*lint !e613*/
6215  {
6216  SCIP_NLROW* nlrow;
6217 
6218  SCIP_CALL( SCIPcreateNlRow(scip, &nlrow, SCIPconsGetName(conss[c]), 0.0,
6219  consdata->z != NULL ? 1 : 0, consdata->z != NULL ? &consdata->z : NULL, &consdata->zcoef,
6220  0, NULL, 0, NULL,
6221  consdata->f, consdata->lhs, consdata->rhs) ); /*lint !e826 !e613*/
6222 
6223  SCIP_CALL( SCIPaddNlRow(scip, nlrow) );
6224  SCIP_CALL( SCIPreleaseNlRow(scip, &nlrow) );
6225  }
6226 
6227  /* initialize data for cut generation */
6228  SCIP_CALL( initSepaData(scip, conshdlrdata->exprinterpreter, conss[c]) ); /*lint !e613*/
6229 
6230 #ifdef TYPESTATISTICS
6231  if( !SCIPisInfinity(scip, -consdata->lhs) )
6232  ++nconvextypeslhs[consdata->convextype];
6233  if( !SCIPisInfinity(scip, consdata->rhs) )
6234  ++nconvextypesrhs[consdata->convextype];
6235 #endif
6236  }
6237 
6238  conshdlrdata->newsoleventfilterpos = -1;
6239  if( nconss != 0 )
6240  {
6241  SCIP_EVENTHDLR* eventhdlr;
6242 
6243  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
6244  assert(eventhdlr != NULL);
6245 
6246  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
6247 
6248 #ifdef TYPESTATISTICS
6249  for( c = 0; c <= (int)SCIP_BIVAR_UNKNOWN; ++c )
6250  {
6251  const char* typename;
6252  switch( c )
6253  {
6254  case SCIP_BIVAR_ALLCONVEX:
6255  typename = "allconvex";
6256  break;
6258  typename = "1-convex";
6259  break;
6261  typename = "convex-concave";
6262  break;
6263  case SCIP_BIVAR_UNKNOWN:
6264  default:
6265  typename = "unknown";
6266  break;
6267  }
6268  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "%4d left and %4d right bivariate constraints of type [%s]\n", nconvextypeslhs[c], nconvextypesrhs[c], typename);
6269  }
6270 #endif
6271  }
6272 
6273  /* reset counter */
6274  conshdlrdata->lastenfolpnode = NULL;
6275  conshdlrdata->nenfolprounds = 0;
6276 
6277  return SCIP_OKAY;
6278 }
6279 
6280 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
6281 static
6282 SCIP_DECL_CONSEXITSOL(consExitsolBivariate)
6283 { /*lint --e{715}*/
6284  SCIP_CONSHDLRDATA* conshdlrdata;
6285  int c;
6286 
6287  assert(scip != NULL);
6288  assert(conss != NULL || nconss == 0);
6289 
6290  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6291  assert(conshdlrdata != NULL);
6292 
6293  if( conshdlrdata->newsoleventfilterpos >= 0 )
6294  {
6295  SCIP_EVENTHDLR* eventhdlr;
6296 
6297  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
6298  assert(eventhdlr != NULL);
6299 
6300  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
6301  conshdlrdata->newsoleventfilterpos = -1;
6302  }
6303 
6304  for( c = 0; c < nconss; ++c )
6305  {
6306  /* free data for cut generation */
6307  assert(conss[c] != NULL); /*lint !e613*/
6308 
6309  SCIP_CALL( freeSepaData(scip, conss[c]) ); /*lint !e613*/
6310  }
6311 
6312  return SCIP_OKAY;
6313 }
6314 
6315 /** frees specific constraint data */
6316 static
6317 SCIP_DECL_CONSDELETE(consDeleteBivariate)
6318 { /*lint --e{715}*/
6319 #ifndef NDEBUG
6320  SCIP_CONSHDLRDATA* conshdlrdata;
6321 #endif
6322 
6323  assert(scip != NULL);
6324  assert(cons != NULL);
6325  assert(consdata != NULL);
6326 
6327 #ifndef NDEBUG
6328  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6329  assert(conshdlrdata != NULL);
6330 #endif
6331 
6332  /* expression should have been removed from expression graph when constraint was deactivated */
6333  assert((*consdata)->exprgraphnode == NULL);
6334 
6335  if( (*consdata)->f != NULL )
6336  {
6337  SCIP_CALL( SCIPexprtreeFree(&(*consdata)->f) );
6338  }
6339 
6340  SCIPfreeMemory(scip, consdata);
6341  *consdata = NULL;
6342 
6343  return SCIP_OKAY;
6344 }
6345 
6346 /** transforms constraint data into data belonging to the transformed problem */
6347 static
6348 SCIP_DECL_CONSTRANS(consTransBivariate)
6349 { /*lint --e{715}*/
6350  SCIP_CONSDATA* sourcedata;
6351  SCIP_CONSDATA* targetdata;
6352 
6353  SCIP_VAR* targetvars[2];
6354 
6355  sourcedata = SCIPconsGetData(sourcecons);
6356  assert(sourcedata != NULL);
6357 
6358  SCIP_CALL( SCIPduplicateMemory(scip, &targetdata, sourcedata) );
6359  assert(targetdata->eventfilterpos == -1);
6360 
6361  assert(sourcedata->f != NULL);
6362  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &targetdata->f, sourcedata->f) );
6363  SCIP_CALL( SCIPgetTransformedVars(scip, 2, SCIPexprtreeGetVars(sourcedata->f), targetvars) );
6364  SCIP_CALL( SCIPexprtreeSetVars(targetdata->f, 2, targetvars) );
6365 
6366  if( sourcedata->z != NULL )
6367  {
6368  SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->z, &targetdata->z) );
6369  }
6370 
6371  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
6372  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
6373  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
6374  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
6375  SCIPconsIsStickingAtNode(sourcecons)) );
6376 
6377  return SCIP_OKAY;
6378 }
6379 
6380 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
6381 static
6382 SCIP_DECL_CONSINITLP(consInitlpBivariate)
6383 { /*lint --e{715}*/
6384  SCIP_CONSHDLRDATA* conshdlrdata;
6385  SCIP_CONSDATA* consdata;
6386  SCIP_ROW* row1;
6387  SCIP_ROW* row2;
6388  SCIP_Real xy[2];
6389  int c;
6390  int i;
6391  int ix;
6392  int iy;
6393  int nref;
6394  SCIP_Real lb[2];
6395  SCIP_Real ub[2];
6396  SCIP_Bool unbounded[2];
6397 
6398  assert(scip != NULL);
6399  assert(conshdlr != NULL);
6400  assert(conss != NULL || nconss == 0);
6401 
6402  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6403  assert(conshdlrdata != NULL);
6404 
6405  nref = conshdlrdata->ninitlprefpoints;
6406 
6407  if( nref == 0 )
6408  {
6409  SCIPdebugMessage("skip LP initialization since ninitlprefpoints is 0\n");
6410  return SCIP_OKAY;
6411  }
6412 
6413  row1 = NULL;
6414  row2 = NULL;
6415 
6416  for( c = 0; c < nconss; ++c )
6417  {
6418  assert(conss[c] != NULL); /*lint !e613*/
6419 
6420  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6421  assert(consdata != NULL);
6422  assert(consdata->f != NULL);
6423 
6424  if( SCIPexprtreeGetInterpreterData(consdata->f) == NULL )
6425  {
6426  SCIP_CALL( SCIPexprintCompile(conshdlrdata->exprinterpreter, consdata->f) );
6427  }
6428 
6429  /* create a bounded rectangle in which we take reference points for initial cut generation
6430  * For a missing bound, we either reflect the other bound at 0.0 if finite and on the right side,
6431  * or double the other bound if on the same side but not 0.0, or set it to +/-1000.0.
6432  */
6433  for( i = 0; i < 2; ++i )
6434  {
6435  lb[i] = SCIPvarGetLbGlobal(SCIPexprtreeGetVars(consdata->f)[i]);
6436  ub[i] = SCIPvarGetUbGlobal(SCIPexprtreeGetVars(consdata->f)[i]);
6437 
6438  unbounded[i] = FALSE;
6439  if( SCIPisInfinity(scip, -lb[i]) )
6440  {
6441  unbounded[i] = TRUE;
6442  ub[i] = MIN(INITLPMAXVARVAL, ub[i]);
6443  if( SCIPisPositive(scip, ub[i]) )
6444  lb[i] = -ub[i];
6445  else if( SCIPisZero(scip, ub[i]) )
6446  lb[i] = -INITLPMAXVARVAL;
6447  else
6448  lb[i] = 2.0 * ub[i];
6449  }
6450  else if( SCIPisInfinity(scip, ub[i]) )
6451  {
6452  unbounded[i] = TRUE;
6453  assert(!SCIPisInfinity(scip, -lb[i]));
6454  lb[i] = MAX(-INITLPMAXVARVAL, lb[i]);
6455  if( SCIPisNegative(scip, lb[i]) )
6456  ub[i] = -lb[i];
6457  else if( SCIPisZero(scip, lb[i]) )
6458  ub[i] = INITLPMAXVARVAL;
6459  else
6460  ub[i] = 2.0 * lb[i];
6461  }
6462  }
6463 
6464  for( ix = 0; ix < nref; ++ix )
6465  {
6466  if( nref > 1 )
6467  xy[0] = lb[0] + ix * (ub[0] - lb[0]) / (nref - 1.0);
6468  else
6469  xy[0] = (lb[0] + ub[0]) / 2.0;
6470 
6471  for( iy = 0; iy < nref; ++iy )
6472  {
6473  if( nref > 1 )
6474  xy[1] = lb[1] + iy * (ub[1] - lb[1]) / (nref - 1.0);
6475  else
6476  xy[1] = (lb[1] + ub[1]) / 2.0;
6477 
6478  SCIPdebugMessage("cons <%s>: generate cuts for <%s> = %g [%g,%g], <%s> = %g [%g,%g]\n",
6479  SCIPconsGetName(conss[c]), /*lint !e613*/
6480  SCIPvarGetName(SCIPexprtreeGetVars(consdata->f)[0]), xy[0],
6482  SCIPvarGetName(SCIPexprtreeGetVars(consdata->f)[1]), xy[1],
6484  );
6485 
6486  /* try to generate one cut for each side */
6487  switch( consdata->convextype )
6488  {
6489  case SCIP_BIVAR_ALLCONVEX:
6490  {
6491  if( !SCIPisInfinity(scip, -consdata->lhs) && !unbounded[0] && !unbounded[1] && (ix == 0 || ix == nref-1) && (iy == 0 || iy == nref-1) )
6492  {
6493  /* lhs is finite and both variables are bounded, so can do overest. hyperplane
6494  * do this only for corner points, since we can get at most two cuts out of it
6495  * @todo generate only two cuts instead of four
6496  */
6497  SCIP_CALL( generateOverestimatingHyperplaneCut(scip, conshdlrdata->exprinterpreter, conss[c], xy, &row1) ); /*lint !e613*/
6498  }
6499  if( !SCIPisInfinity(scip, consdata->rhs) )
6500  {
6501  /* rhs is finite */
6502  SCIP_CALL( generateLinearizationCut(scip, conshdlrdata->exprinterpreter, conss[c], xy, TRUE, &row2) ); /*lint !e613*/
6503  }
6504  break;
6505  }
6506 
6508  {
6509  if( !SCIPisInfinity(scip, -consdata->lhs) && !unbounded[0])
6510  {
6511  /* lhs is finite and x is bounded */
6512  SCIP_CALL( generateConvexConcaveEstimator(scip, conshdlrdata->exprinterpreter, conss[c], xy, SCIP_SIDETYPE_LEFT, &row1) ); /*lint !e613*/
6513  }
6514  if( !SCIPisInfinity(scip, consdata->rhs) && !unbounded[1])
6515  {
6516  /* rhs is finite and y is bounded */
6517  SCIP_CALL( generateConvexConcaveEstimator(scip, conshdlrdata->exprinterpreter, conss[c], xy, SCIP_SIDETYPE_RIGHT, &row2) ); /*lint !e613*/
6518  }
6519  break;
6520  }
6521 
6523  {
6524  if( !SCIPisInfinity(scip, -consdata->lhs) && !unbounded[0] && !unbounded[1] && (ix == 0 || ix == nref-1) && (iy == 0 || iy == nref-1) )
6525  {
6526  /* lhs is finite and both variables are bounded
6527  * do this only for corner points, since we can get at most two cuts out of it
6528  * @todo generate only two cuts instead of four
6529  */
6530  SCIP_CALL( generateOverestimatingHyperplaneCut(scip, conshdlrdata->exprinterpreter, conss[c], xy, &row1) ); /*lint !e613*/
6531  }
6532  if( !SCIPisInfinity(scip, consdata->rhs) && !unbounded[0] && !unbounded[1] )
6533  { /* rhs is finite and both variables are bounded */
6534  SCIP_CALL( generate1ConvexIndefiniteUnderestimator(scip, conshdlrdata->exprinterpreter, conss[c], xy, &row2) ); /*lint !e613*/
6535  }
6536  break;
6537  }
6538 
6539  default:
6540  {
6541  SCIPwarningMessage(scip, "initlp for convexity type %d not implemented\n", consdata->convextype);
6542  }
6543  } /*lint !e788*/
6544 
6545  /* check numerics */
6546  if( row1 != NULL )
6547  {
6548  if( SCIPgetRowMaxCoef(scip, row1) / SCIPgetRowMinCoef(scip, row1) > conshdlrdata->cutmaxrange )
6549  {
6550  SCIPdebugMessage("drop row1 for constraint <%s> because range of coefficients is too large: mincoef = %g, maxcoef = %g -> range = %g\n",
6551  SCIPconsGetName(conss[c]), SCIPgetRowMinCoef(scip, row1), SCIPgetRowMaxCoef(scip, row1), SCIPgetRowMaxCoef(scip, row1) / SCIPgetRowMinCoef(scip, row1)); /*lint !e613*/
6552  SCIP_CALL( SCIPreleaseRow(scip, &row1) );
6553  }
6554  else if( SCIPisInfinity(scip, -SCIProwGetLhs(row1)) )
6555  {
6556  /* row1 should be a cut with finite lhs, but infinite rhs */
6557  assert(SCIPisInfinity(scip, SCIProwGetRhs(row1)));
6558  SCIPdebugMessage("drop row1 for constraint <%s> because of very large lhs: %g\n", SCIPconsGetName(conss[c]), SCIProwGetLhs(row1)); /*lint !e613*/
6559  SCIP_CALL( SCIPreleaseRow(scip, &row1) );
6560  }
6561  }
6562 
6563  if( row2 != NULL )
6564  {
6565  if( SCIPgetRowMaxCoef(scip, row2) / SCIPgetRowMinCoef(scip, row2) > conshdlrdata->cutmaxrange )
6566  {
6567  SCIPdebugMessage("drop row2 for constraint <%s> because range of coefficients is too large: mincoef = %g, maxcoef = %g -> range = %g\n",
6568  SCIPconsGetName(conss[c]), SCIPgetRowMinCoef(scip, row2), SCIPgetRowMaxCoef(scip, row2), SCIPgetRowMaxCoef(scip, row2) / SCIPgetRowMinCoef(scip, row2)); /*lint !e613*/
6569  SCIP_CALL( SCIPreleaseRow(scip, &row2) );
6570  }
6571  else if( SCIPisInfinity(scip, SCIProwGetRhs(row2)) )
6572  {
6573  /* row2 should be a cut with finite rhs, but infinite lhs */
6574  assert(SCIPisInfinity(scip, SCIProwGetRhs(row2)));
6575  SCIPdebugMessage("drop row2 for constraint <%s> because of very large rhs: %g\n", SCIPconsGetName(conss[c]), SCIProwGetLhs(row2)); /*lint !e613*/
6576  SCIP_CALL( SCIPreleaseRow(scip, &row2) );
6577  }
6578  }
6579 
6580  /* add to LP */
6581  if( row1 != NULL )
6582  {
6583  SCIP_Bool infeasible;
6584  SCIP_CALL( SCIPaddCut(scip, NULL, row1, FALSE /* forcecut */, &infeasible) );
6585  assert( ! infeasible );
6586  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row1, NULL) ) );
6587  SCIP_CALL( SCIPreleaseRow(scip, &row1) );
6588  }
6589  if( row2 != NULL )
6590  {
6591  SCIP_Bool infeasible;
6592  SCIP_CALL( SCIPaddCut(scip, NULL, row2, FALSE /* forcecut */, &infeasible) );
6593  assert( ! infeasible );
6594  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row2, NULL) ) );
6595  SCIP_CALL( SCIPreleaseRow(scip, &row2) );
6596  }
6597  }
6598  }
6599  }
6600 
6601  return SCIP_OKAY;
6602 }
6603 
6604 /** separation method of constraint handler for LP solutions */
6605 static
6606 SCIP_DECL_CONSSEPALP(consSepalpBivariate)
6607 { /*lint --e{715}*/
6608  SCIP_CONSHDLRDATA* conshdlrdata;
6609  SCIP_CONS* maxviolcon;
6610 
6611  assert(scip != NULL);
6612  assert(conshdlr != NULL);
6613  assert(conss != NULL || nconss == 0);
6614  assert(result != NULL);
6615 
6616  *result = SCIP_DIDNOTFIND;
6617 
6618  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6619  assert(conshdlrdata != NULL);
6620 
6621  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcon) );
6622  if( maxviolcon == NULL )
6623  return SCIP_OKAY;
6624 
6625  /* @todo add separation of convex (only?) constraints in nlp relaxation solution */
6626 
6627  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
6628 
6629  return SCIP_OKAY;
6630 }
6631 
6632 /** separation method of constraint handler for arbitrary primal solutions */
6633 static
6634 SCIP_DECL_CONSSEPASOL(consSepasolBivariate)
6635 { /*lint --e{715}*/
6636  SCIP_CONSHDLRDATA* conshdlrdata;
6637  SCIP_CONS* maxviolcon;
6638 
6639  assert(scip != NULL);
6640  assert(conshdlr != NULL);
6641  assert(conss != NULL || nconss == 0);
6642  assert(sol != NULL);
6643  assert(result != NULL);
6644 
6645  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6646  assert(conshdlrdata != NULL);
6647 
6648  *result = SCIP_DIDNOTFIND;
6649 
6650  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &maxviolcon) );
6651  if( maxviolcon == NULL )
6652  return SCIP_OKAY;
6653 
6654  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, conshdlrdata->mincutefficacysepa, FALSE, result, NULL) );
6655 
6656  return SCIP_OKAY;
6657 }
6658 
6659 /** constraint enforcing method of constraint handler for LP solutions */
6660 static
6661 SCIP_DECL_CONSENFOLP(consEnfolpBivariate)
6662 { /*lint --e{715}*/
6663  SCIP_CONSHDLRDATA* conshdlrdata;
6664  SCIP_CONSDATA* consdata;
6665  SCIP_CONS* maxviolcons;
6666  SCIP_Real maxviol;
6667  SCIP_RESULT propresult;
6668  SCIP_RESULT separateresult;
6669  int dummy;
6670  int nnotify;
6671  SCIP_Real sepaefficacy;
6672  SCIP_Real minefficacy;
6673  SCIP_Real leastpossibleefficacy;
6674 
6675  assert(scip != NULL);
6676  assert(conshdlr != NULL);
6677  assert(conss != NULL || nconss == 0);
6678  assert(result != NULL);
6679 
6680  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6681  assert(conshdlrdata != NULL);
6682 
6683  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcons) );
6684  if( maxviolcons == NULL )
6685  {
6686  *result = SCIP_FEASIBLE;
6687  return SCIP_OKAY;
6688  }
6689 
6690  *result = SCIP_INFEASIBLE;
6691 
6692  /* if we are above the 100'th enforcement round for this node, something is strange
6693  * (maybe the LP does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
6694  * 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
6695  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
6696  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
6697  * we only increment nenfolprounds until 101 to avoid an overflow
6698  */
6699  if( conshdlrdata->lastenfolpnode == SCIPgetCurrentNode(scip) )
6700  {
6701  if( conshdlrdata->nenfolprounds > 100 )
6702  {
6703  if( SCIPisStopped(scip) )
6704  {
6705  SCIP_NODE* child;
6706 
6707  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
6708  *result = SCIP_BRANCHED;
6709 
6710  return SCIP_OKAY;
6711  }
6712  }
6713  else
6714  ++conshdlrdata->nenfolprounds;
6715  }
6716  else
6717  {
6718  conshdlrdata->lastenfolpnode = SCIPgetCurrentNode(scip);
6719  conshdlrdata->nenfolprounds = 0;
6720  }
6721 
6722  consdata = SCIPconsGetData(maxviolcons);
6723  assert(consdata != NULL);
6724  maxviol = consdata->lhsviol + consdata->rhsviol;
6725  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
6726 
6727  SCIPdebugMessage("enfolp with max violation %g in cons <%s>\n", maxviol, SCIPconsGetName(maxviolcons));
6728 
6729  /* run domain propagation */
6730  dummy = 0;
6731  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &dummy, &dummy) );
6732  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
6733  {
6734  *result = propresult;
6735  return SCIP_OKAY;
6736  }
6737 
6738  /* we would like a cut that is efficient enough that it is not redundant in the LP (>feastol)
6739  * however, if the maximal violation is very small, also the best cut efficacy cannot be large
6740  * thus, in the latter case, we are also happy if the efficacy is at least, say, 75% of the maximal violation
6741  * but in any case we need an efficacy that is at least feastol
6742  */
6743  minefficacy = MIN(0.75*maxviol, conshdlrdata->mincutefficacyenfo); /*lint !e666*/
6744  minefficacy = MAX(minefficacy, SCIPfeastol(scip)); /*lint !e666*/
6745  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, minefficacy, TRUE, &separateresult, &sepaefficacy) );
6746  if( separateresult == SCIP_SEPARATED || separateresult == SCIP_CUTOFF )
6747  {
6748  SCIPdebugMessage("separation succeeded (bestefficacy = %g, minefficacy = %g, cutoff = %d)\n", sepaefficacy, minefficacy, separateresult == SCIP_CUTOFF);
6749  *result = separateresult;
6750  return SCIP_OKAY;
6751  }
6752 
6753  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
6754  * -> collect variables for branching
6755  */
6756 
6757  SCIPdebugMessage("separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, minefficacy, maxviol);
6758 
6759  /* find branching candidates */
6760  SCIP_CALL( registerBranchingVariables(scip, conss, nconss, &nnotify) );
6761 
6762  /* if sepastore can decrease LP feasibility tolerance, we can add cuts with efficacy in [eps, feastol] */
6763  leastpossibleefficacy = SCIPgetRelaxFeastolFactor(scip) > 0.0 ? SCIPepsilon(scip) : SCIPfeastol(scip);
6764  if( nnotify == 0 && !solinfeasible && minefficacy > leastpossibleefficacy )
6765  {
6766  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
6767  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, leastpossibleefficacy, TRUE, &separateresult, &sepaefficacy) );
6768  if( separateresult == SCIP_SEPARATED || separateresult == SCIP_CUTOFF )
6769  {
6770  *result = separateresult;
6771  return SCIP_OKAY;
6772  }
6773  }
6774 
6775  if( nnotify == 0 && !solinfeasible )
6776  {
6777  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
6778  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
6779  */
6780  SCIP_VAR* brvar = NULL;
6781  SCIP_CALL( registerLargeLPValueVariableForBranching(scip, conss, nconss, &brvar) );
6782  if( brvar == NULL )
6783  {
6784  /* fallback 3: all nonlinear variables in all violated constraints seem to be fixed -> treat as linear constraint in one variable */
6785  SCIP_Bool reduceddom;
6786  SCIP_Bool infeasible;
6787 
6788  SCIP_CALL( enforceViolatedFixedNonlinear(scip, conss, nconss, &reduceddom, &infeasible) );
6789  /* 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
6790  * thus, we only add them if considered violated, and otherwise claim the solution is feasible (but print a warning)
6791  */
6792  if ( infeasible )
6793  *result = SCIP_CUTOFF;
6794  else if ( reduceddom )
6795  *result = SCIP_REDUCEDDOM;
6796  else
6797  {
6798  *result = SCIP_FEASIBLE;
6799  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
6800  }
6801  return SCIP_OKAY;
6802  }
6803  else
6804  {
6805  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));
6806  nnotify = 1;
6807  }
6808  }
6809 
6810  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
6811  return SCIP_OKAY;
6812 }
6813 
6814 
6815 /** constraint enforcing method of constraint handler for pseudo solutions */
6816 static
6817 SCIP_DECL_CONSENFOPS(consEnfopsBivariate)
6818 { /*lint --e{715}*/
6819  SCIP_CONS* maxviolcons;
6820  SCIP_CONSDATA* consdata;
6821  SCIP_RESULT propresult;
6822  SCIP_VAR* var;
6823  int nnotify;
6824  int dummy;
6825  int c;
6826  int i;
6827 
6828  assert(scip != NULL);
6829  assert(conss != NULL || nconss == 0);
6830 
6831  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &maxviolcons) );
6832  if( maxviolcons == NULL )
6833  {
6834  *result = SCIP_FEASIBLE;
6835  return SCIP_OKAY;
6836  }
6837 
6838  *result = SCIP_INFEASIBLE;
6839 
6840  SCIPdebugMessage("enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcons));
6841 
6842  /* run domain propagation */
6843  dummy = 0;
6844  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, &dummy, &dummy) );
6845  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
6846  {
6847  *result = propresult;
6848  return SCIP_OKAY;
6849  }
6850 
6851  /* we are not feasible and we cannot proof that the whole node is infeasible
6852  * -> collect all variables in violated constraints for branching
6853  */
6854 
6855  nnotify = 0;
6856  for( c = 0; c < nconss; ++c )
6857  {
6858  assert(conss != NULL);
6859  consdata = SCIPconsGetData(conss[c]);
6860  assert(consdata != NULL);
6861  assert(consdata->f != NULL);
6862 
6863  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6864  continue;
6865 
6866  /* if nonlinear variables are fixed, z should be propagated such that the constraint becomes feasible,
6867  * so there should be no branching on z necessary
6868  */
6869  if( consdata->z != NULL && !SCIPisRelEQ(scip, SCIPvarGetLbLocal(consdata->z), SCIPvarGetUbLocal(consdata->z)) )
6870  {
6871  SCIP_CALL( SCIPaddExternBranchCand(scip, consdata->z, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
6872  ++nnotify;
6873  }
6874 
6875  for( i = 0; i < 2; ++i )
6876  {
6877  var = SCIPexprtreeGetVars(consdata->f)[i];
6878  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6879  {
6880  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
6881  ++nnotify;
6882  }
6883  }
6884  }
6885 
6886  if( nnotify == 0 )
6887  {
6888  SCIPdebugMessage("All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
6889  *result = SCIP_SOLVELP;
6890  }
6891 
6892  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
6893  return SCIP_OKAY;
6894 }
6895 
6896 /** feasibility check method of constraint handler for integral solutions */
6897 static
6898 SCIP_DECL_CONSCHECK(consCheckBivariate)
6899 { /*lint --e{715}*/
6900  SCIP_CONSHDLRDATA* conshdlrdata;
6901  SCIP_CONSDATA* consdata;
6902  SCIP_Real maxviol;
6903  int c;
6904  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
6905 
6906  assert(scip != NULL);
6907  assert(conss != NULL || nconss == 0);
6908  assert(sol != NULL);
6909  assert(result != NULL);
6910 
6911  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6912  assert(conshdlrdata != NULL);
6913 
6914  *result = SCIP_FEASIBLE;
6915 
6916  maxviol = 0.0;
6917  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL);
6918  for( c = 0; c < nconss; ++c )
6919  {
6920  assert(conss != NULL);
6921  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol) );
6922 
6923  consdata = SCIPconsGetData(conss[c]);
6924  assert(consdata != NULL);
6925 
6926  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6927  {
6928  *result = SCIP_INFEASIBLE;
6929  if( printreason )
6930  {
6931  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
6932  SCIPinfoMessage(scip, NULL, ";\n");
6933  {
6934  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g (scaled: %.15g)\n", consdata->lhs - consdata->activity, consdata->lhsviol);
6935  }
6936  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6937  {
6938  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g (scaled: %.15g)\n", consdata->activity - consdata->rhs, consdata->rhsviol);
6939  }
6940  }
6941 
6942  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible )
6943  return SCIP_OKAY;
6944 
6945  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
6946  maxviol = consdata->lhsviol + consdata->rhsviol;
6947 
6948  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
6949  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
6950  maypropfeasible = FALSE;
6951 
6952  if( maypropfeasible )
6953  {
6954  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
6955  {
6956  /* check if the linear variable may help to get the left hand side satisfied
6957  * if not, then we cannot get feasible */
6958  if( !(consdata->mayincreasez && consdata->zcoef > 0.0) && !(consdata->maydecreasez && consdata->zcoef < 0.0) )
6959  maypropfeasible = FALSE;
6960  }
6961  else
6962  {
6963  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
6964  /* check if the linear variable may help to get the right hand side satisfied
6965  * if not, then we cannot get feasible */
6966  if( !(consdata->mayincreasez && consdata->zcoef < 0.0) && !(consdata->maydecreasez && consdata->zcoef > 0.0) )
6967  maypropfeasible = FALSE;
6968  }
6969  }
6970  }
6971  }
6972 
6973  if( *result == SCIP_INFEASIBLE && maypropfeasible )
6974  {
6975  SCIP_Bool success;
6976 
6977  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
6978 
6979  /* do not pass solution to NLP heuristic if we made it feasible this way */
6980  if( success )
6981  return SCIP_OKAY;
6982  }
6983 
6984  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL )
6985  {
6986  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
6987  }
6988 
6989  return SCIP_OKAY;
6990 }
6991 
6992 /** domain propagation method of constraint handler */
6993 static
6994 SCIP_DECL_CONSPROP(consPropBivariate)
6995 { /*lint --e{715}*/
6996  int dummy;
6997 
6998  assert(scip != NULL);
6999  assert(conshdlr != NULL);
7000  assert(conss != NULL || nconss == 0);
7001  assert(result != NULL);
7002 
7003  dummy = 0;
7004  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, result, &dummy, &dummy) );
7005 
7006  return SCIP_OKAY;
7007 }
7008 
7009 /** presolving method of constraint handler */
7010 static
7011 SCIP_DECL_CONSPRESOL(consPresolBivariate)
7012 { /*lint --e{715}*/
7013 #ifndef NDEBUG
7014  SCIP_CONSDATA* consdata;
7015 #endif
7016  SCIP_CONSHDLRDATA* conshdlrdata;
7017  SCIP_RESULT propresult;
7018  SCIP_Bool havechange;
7019  SCIP_Bool upgraded;
7020  int c;
7021 
7022  assert(scip != NULL);
7023  assert(conshdlr != NULL);
7024  assert(conss != NULL || nconss == 0);
7025  assert(result != NULL);
7026 
7027  *result = SCIP_DIDNOTFIND;
7028 
7029  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7030  assert(conshdlrdata != NULL);
7031  assert(conshdlrdata->exprgraph != NULL);
7032 
7033  if( !conshdlrdata->isremovedfixings )
7034  {
7035  SCIP_CALL( removeFixedNonlinearVariables(scip, conshdlr) );
7036  assert(conshdlrdata->isremovedfixings);
7037  }
7038  /* @todo call expression graph simplifier, if not done yet? */
7039 
7040  for( c = 0; c < nconss; ++c )
7041  {
7042  assert(conss != NULL);
7043 
7044 #ifndef NDEBUG
7045  consdata = SCIPconsGetData(conss[c]);
7046  assert(consdata != NULL);
7047 #endif
7048 
7049  SCIPdebugMessage("process constraint <%s>\n", SCIPconsGetName(conss[c]));
7050  SCIPdebugPrintCons(scip, conss[c], NULL);
7051 
7052  havechange = FALSE;
7053 
7054  SCIP_CALL( removeFixedVariables(scip, conshdlr, conss[c], &havechange, &upgraded) );
7055  if( upgraded )
7056  {
7057  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
7058  ++*nupgdconss;
7059  continue;
7060  }
7061  if( havechange )
7062  {
7063  SCIPdebugMessage("removed fixed variables -> ");
7064  SCIPdebugPrintCons(scip, conss[c], NULL);
7065  }
7066  }
7067 
7068  /* run domain propagation */
7069  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, &propresult, nchgbds, ndelconss) );
7070  switch( propresult )
7071  {
7072  case SCIP_REDUCEDDOM:
7073  *result = SCIP_SUCCESS;
7074  break;
7075  case SCIP_CUTOFF:
7076  SCIPdebugMessage("propagation says problem is infeasible in presolve\n");
7077  *result = SCIP_CUTOFF;
7078  return SCIP_OKAY;
7079  default:
7080  assert(propresult == SCIP_DIDNOTFIND || propresult == SCIP_DIDNOTRUN);
7081  } /*lint !e788*/
7082 
7083  return SCIP_OKAY;
7084 }
7085 
7086 /** variable rounding lock method of constraint handler */
7087 static
7088 SCIP_DECL_CONSLOCK(consLockBivariate)
7089 { /*lint --e{715}*/
7090  SCIP_CONSDATA* consdata;
7091 
7092  assert(scip != NULL);
7093  assert(cons != NULL);
7094 
7095  consdata = SCIPconsGetData(cons);
7096  assert(consdata != NULL);
7097 
7098  if( consdata->z != NULL )
7099  {
7100  if( consdata->zcoef > 0 )
7101  {
7102  if( !SCIPisInfinity(scip, -consdata->lhs) )
7103  {
7104  SCIP_CALL( SCIPaddVarLocks(scip, consdata->z, nlockspos, nlocksneg) );
7105  }
7106  if( !SCIPisInfinity(scip, consdata->rhs) )
7107  {
7108  SCIP_CALL( SCIPaddVarLocks(scip, consdata->z, nlocksneg, nlockspos) );
7109  }
7110  }
7111  else
7112  {
7113  if( !SCIPisInfinity(scip, -consdata->lhs) )
7114  {
7115  SCIP_CALL( SCIPaddVarLocks(scip, consdata->z, nlocksneg, nlockspos) );
7116  }
7117  if( !SCIPisInfinity(scip, consdata->rhs) )
7118  {
7119  SCIP_CALL( SCIPaddVarLocks(scip, consdata->z, nlockspos, nlocksneg) );
7120  }
7121  }
7122  }
7123 
7124  return SCIP_OKAY;
7125 }
7126 
7127 
7128 /** constraint activation notification method of constraint handler */
7129 static
7130 SCIP_DECL_CONSACTIVE(consActiveBivariate)
7131 { /*lint --e{715}*/
7132  SCIP_CONSHDLRDATA* conshdlrdata;
7133  SCIP_CONSDATA* consdata;
7134  SCIP_Bool exprtreeisnew;
7135 
7136  assert(scip != NULL);
7137  assert(conshdlr != NULL);
7138  assert(cons != NULL);
7139  assert(SCIPconsIsTransformed(cons));
7140 
7141  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7142  assert(conshdlrdata != NULL);
7143  assert(conshdlrdata->exprgraph != NULL);
7144 
7145  consdata = SCIPconsGetData(cons);
7146  assert(consdata != NULL);
7147  assert(consdata->exprgraphnode == NULL);
7148 
7149  SCIPdebugMessage("activate %scons <%s>\n", SCIPconsIsTransformed(cons) ? "transformed " : "", SCIPconsGetName(cons));
7150 
7151  /* add exprtree to expression graph */
7152  SCIP_CALL( SCIPexprgraphAddExprtreeSum(conshdlrdata->exprgraph, 1, &consdata->f, NULL, &consdata->exprgraphnode, &exprtreeisnew) );
7153  assert(consdata->exprgraphnode != NULL);
7154 
7155  /* mark that variables in constraint should not be multiaggregated (bad for bound tightening and branching) */
7156  if( SCIPvarIsActive(SCIPexprtreeGetVars(consdata->f)[0]) )
7157  {
7158  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPexprtreeGetVars(consdata->f)[0]) );
7159  }
7160  if( SCIPvarIsActive(SCIPexprtreeGetVars(consdata->f)[1]) )
7161  {
7162  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, SCIPexprtreeGetVars(consdata->f)[1]) );
7163  }
7164  if( consdata->z != NULL && SCIPvarIsActive(consdata->z) )
7165  {
7166  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->z) );
7167  }
7168 
7169  return SCIP_OKAY;
7170 }
7171 
7172 /** constraint deactivation notification method of constraint handler */
7173 static
7174 SCIP_DECL_CONSDEACTIVE(consDeactiveBivariate)
7175 { /*lint --e{715}*/
7176  SCIP_CONSHDLRDATA* conshdlrdata;
7177  SCIP_CONSDATA* consdata;
7178 
7179  assert(scip != NULL);
7180  assert(conshdlr != NULL);
7181  assert(cons != NULL);
7182  assert(SCIPconsIsTransformed(cons));
7183 
7184  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7185  assert(conshdlrdata != NULL);
7186  assert(conshdlrdata->exprgraph != NULL);
7187 
7188  consdata = SCIPconsGetData(cons);
7189  assert(consdata != NULL);
7190  assert(consdata->exprgraphnode != NULL);
7191 
7192  SCIPdebugMessage("deactivate %scons <%s>\n", SCIPconsIsTransformed(cons) ? "transformed " : "", SCIPconsGetName(cons));
7193 
7194  SCIP_CALL( SCIPexprgraphReleaseNode(conshdlrdata->exprgraph, &consdata->exprgraphnode) );
7195 
7196  return SCIP_OKAY;
7197 }
7198 
7199 /** constraint enabling notification method of constraint handler */
7200 static
7201 SCIP_DECL_CONSENABLE(consEnableBivariate)
7202 { /*lint --e{715}*/
7203  SCIP_CONSHDLRDATA* conshdlrdata;
7204  SCIP_CONSDATA* consdata;
7205 
7206  assert(scip != NULL);
7207  assert(conshdlr != NULL);
7208  assert(cons != NULL);
7209  assert(SCIPconsIsTransformed(cons));
7210  assert(SCIPconsIsActive(cons));
7211 
7212  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7213  assert(conshdlrdata != NULL);
7214  assert(conshdlrdata->exprgraph != NULL);
7215 
7216  consdata = SCIPconsGetData(cons);
7217  assert(consdata != NULL);
7218  assert(consdata->exprgraphnode != NULL);
7219 
7220  SCIPdebugMessage("enable %scons <%s>\n", SCIPconsIsTransformed(cons) ? "transformed " : "", SCIPconsGetName(cons));
7221 
7222  /* enable node of expression in expression graph */
7223  SCIPexprgraphEnableNode(conshdlrdata->exprgraph, consdata->exprgraphnode);
7224 
7225  /* enable event catching for linear variables */
7226  SCIP_CALL( catchLinearVarEvents(scip, cons) );
7227 
7228  return SCIP_OKAY;
7229 }
7230 
7231 /** constraint disabling notification method of constraint handler */
7232 static
7233 SCIP_DECL_CONSDISABLE(consDisableBivariate)
7234 { /*lint --e{715}*/
7235  SCIP_CONSHDLRDATA* conshdlrdata;
7236  SCIP_CONSDATA* consdata;
7237 
7238  assert(scip != NULL);
7239  assert(conshdlr != NULL);
7240  assert(cons != NULL);
7241  assert(SCIPconsIsTransformed(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("disable %scons <%s>\n", SCIPconsIsTransformed(cons) ? "transformed " : "", SCIPconsGetName(cons));
7252 
7253  /* disable node of expression in expression graph */
7254  SCIPexprgraphDisableNode(conshdlrdata->exprgraph, consdata->exprgraphnode);
7255 
7256  SCIP_CALL( dropLinearVarEvents(scip, cons) );
7257 
7258  return SCIP_OKAY;
7259 }
7260 
7261 /** constraint display method of constraint handler */
7262 static
7263 SCIP_DECL_CONSPRINT(consPrintBivariate)
7264 { /*lint --e{715}*/
7265  SCIP_CONSDATA* consdata;
7266 
7267  assert(scip != NULL);
7268  assert(cons != NULL);
7269 
7270  consdata = SCIPconsGetData(cons);
7271  assert(consdata != NULL);
7272 
7273  /* print left hand side for ranged rows */
7274  if( !SCIPisInfinity(scip, -consdata->lhs)
7275  && !SCIPisInfinity(scip, consdata->rhs)
7276  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
7277  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
7278 
7279  /* print coefficients and variables */
7280  SCIP_CALL( SCIPexprtreePrintWithNames(consdata->f, SCIPgetMessagehdlr(scip), file) );
7281 
7282  if( consdata->z != NULL )
7283  {
7284  SCIPinfoMessage(scip, file, "%+.15g", consdata->zcoef);
7285  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->z, TRUE) );
7286  }
7287 
7288  /* print right hand side */
7289  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
7290  {
7291  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
7292  }
7293  else if( !SCIPisInfinity(scip, consdata->rhs) )
7294  {
7295  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
7296  }
7297  else if( !SCIPisInfinity(scip, -consdata->lhs) )
7298  {
7299  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
7300  }
7301  else
7302  {
7303  SCIPinfoMessage(scip, file, " [free]");
7304  }
7305 
7306  /* print convexity type, if known */
7307  switch( consdata->convextype )
7308  {
7309  case SCIP_BIVAR_ALLCONVEX:
7310  SCIPinfoMessage(scip, file, " [allconvex]");
7311  break;
7313  SCIPinfoMessage(scip, file, " [1-convex]");
7314  break;
7316  SCIPinfoMessage(scip, file, " [convex-concave]");
7317  break;
7318  default: ;
7319  } /*lint !e788*/
7320 
7321  return SCIP_OKAY;
7322 }
7323 
7324 /** constraint copying method of constraint handler */
7325 static
7326 SCIP_DECL_CONSCOPY(consCopyBivariate)
7327 { /*lint --e{715}*/
7328  SCIP_CONSDATA* consdata;
7329  SCIP_EXPRTREE* f;
7330  SCIP_VAR* xy[2];
7331  SCIP_VAR* z;
7332 
7333  assert(scip != NULL);
7334  assert(cons != NULL);
7335  assert(sourcescip != NULL);
7336  assert(sourceconshdlr != NULL);
7337  assert(sourcecons != NULL);
7338  assert(varmap != NULL);
7339  assert(valid != NULL);
7340 
7341  consdata = SCIPconsGetData(sourcecons);
7342  assert(consdata != NULL);
7343  assert(consdata->f != NULL);
7344 
7345  *valid = TRUE;
7346 
7347  if( consdata->z != NULL )
7348  {
7349  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->z, &z, varmap, consmap, global, valid) );
7350  assert(!*valid || z != NULL);
7351  }
7352  else
7353  z = NULL;
7354 
7355  if( *valid )
7356  {
7357  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, SCIPexprtreeGetVars(consdata->f)[0], &xy[0], varmap, consmap, global, valid) );
7358  assert(!*valid || xy[0] != NULL);
7359  }
7360 
7361  if( *valid )
7362  {
7363  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, SCIPexprtreeGetVars(consdata->f)[1], &xy[1], varmap, consmap, global, valid) );
7364  assert(!*valid || xy[1] != NULL);
7365  }
7366 
7367  if( *valid )
7368  {
7369  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &f, consdata->f) );
7370  SCIP_CALL( SCIPexprtreeSetVars(f, 2, xy) );
7371  }
7372  else
7373  f = NULL;
7374 
7375  if( *valid )
7376  {
7377  SCIP_CALL( SCIPcreateConsBivariate(scip, cons, name ? name : SCIPconsGetName(sourcecons),
7378  f, consdata->convextype, z, consdata->zcoef, consdata->lhs, consdata->rhs,
7379  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
7380  }
7381 
7382  if( f != NULL )
7383  {
7384  SCIP_CALL( SCIPexprtreeFree(&f) );
7385  }
7386 
7387  return SCIP_OKAY;
7388 }
7389 
7390 /** constraint method of constraint handler which returns the variables (if possible) */
7391 static
7392 SCIP_DECL_CONSGETVARS(consGetVarsBivariate)
7393 { /*lint --e{715}*/
7394 
7395  if( varssize < 3 )
7396  (*success) = FALSE;
7397  else
7398  {
7399  SCIP_CONSDATA* consdata;
7400 
7401  assert(cons != NULL);
7402  assert(vars != NULL);
7403 
7404  consdata = SCIPconsGetData(cons);
7405  assert(consdata != NULL);
7406 
7407  vars[0] = SCIPexprtreeGetVars(consdata->f)[0];
7408  vars[1] = SCIPexprtreeGetVars(consdata->f)[1];
7409  vars[2] = consdata->z;
7410  (*success) = TRUE;
7411  }
7412 
7413  return SCIP_OKAY;
7414 }
7415 
7416 /** constraint method of constraint handler which returns the number of variables (if possible) */
7417 static
7418 SCIP_DECL_CONSGETNVARS(consGetNVarsBivariate)
7419 { /*lint --e{715}*/
7420 
7421  (*nvars) = 3;
7422  (*success) = TRUE;
7423 
7424  return SCIP_OKAY;
7425 }
7426 
7427 /*
7428  * Quadratic constraint upgrading
7429  */
7430 
7431 /** tries to upgrade a quadratic constraint into a bivariate constraint */
7432 static
7433 SCIP_DECL_QUADCONSUPGD(quadconsUpgdBivariate)
7434 { /*lint --e{715}*/
7435  SCIP_QUADVARTERM* quadvarterms;
7436  SCIP_BILINTERM* bilinterms;
7437  int nquadvarterms;
7438  int nbilinterms;
7439 
7440  SCIP_VAR* x;
7441  SCIP_VAR* y;
7442 
7443  SCIP_Real coefxx;
7444  SCIP_Real coefxy;
7445  SCIP_Real coefyy;
7446  SCIP_Real coefx;
7447  SCIP_Real coefy;
7448 
7449  SCIP_Real zcoef;
7450  SCIP_VAR* z;
7451 
7452  assert(nupgdconss != NULL);
7453  assert(upgdconss != NULL);
7454 
7455  *nupgdconss = 0;
7456 
7457  /* not interested in univariate case */
7458  if( nbinquad + nintquad + ncontquad < 2 )
7459  return SCIP_OKAY;
7460 
7461  if( SCIPgetNBilinTermsQuadratic(scip, cons) == 0 )
7462  return SCIP_OKAY;
7463 
7464  quadvarterms = SCIPgetQuadVarTermsQuadratic(scip, cons);
7465  nquadvarterms = SCIPgetNQuadVarTermsQuadratic(scip, cons);
7466  bilinterms = SCIPgetBilinTermsQuadratic(scip, cons);
7467  nbilinterms = SCIPgetNBilinTermsQuadratic(scip, cons);
7468 
7469  if( nquadvarterms == 2 && SCIPgetNLinearVarsQuadratic(scip, cons) <= 1 )
7470  {
7471  x = quadvarterms[0].var;
7472  y = quadvarterms[1].var;
7473 
7474  coefxx = quadvarterms[0].sqrcoef;
7475  coefyy = quadvarterms[1].sqrcoef;
7476 
7477  /* only one bilinear term -> not interesting for us */
7478  if( coefxx == 0.0 && coefyy == 0.0 )
7479  return SCIP_OKAY;
7480 
7481  /* two square terms without bilinear term -> also not interesting for us */
7482  if( nbilinterms == 0 )
7483  return SCIP_OKAY;
7484  assert(nbilinterms == 1);
7485 
7486  assert(bilinterms[0].var1 == x || bilinterms[0].var1 == y);
7487  assert(bilinterms[0].var2 == x || bilinterms[0].var2 == y);
7488 
7489  coefxy = bilinterms[0].coef;
7490 
7491  coefx = quadvarterms[0].lincoef;
7492  coefy = quadvarterms[1].lincoef;
7493 
7494  if( SCIPgetNLinearVarsQuadratic(scip, cons) )
7495  {
7496  assert(SCIPgetNLinearVarsQuadratic(scip, cons) == 1);
7497  zcoef = SCIPgetCoefsLinearVarsQuadratic(scip, cons)[0];
7498  z = SCIPgetLinearVarsQuadratic(scip, cons)[0];
7499  }
7500  else
7501  {
7502  z = NULL;
7503  zcoef = 0.0;
7504  }
7505 
7506  if( upgdconsssize < 1 )
7507  {
7508  *nupgdconss = -1;
7509  return SCIP_OKAY;
7510  }
7511 
7512  SCIP_CALL( createConsFromQuadTerm(scip, cons, &upgdconss[0], SCIPconsGetName(cons),
7513  x, y, z, coefxx, coefx, coefyy, coefy, coefxy, zcoef, SCIPgetLhsQuadratic(scip, cons), SCIPgetRhsQuadratic(scip, cons)) );
7514  *nupgdconss = 1;
7515  }
7516  else
7517  {
7518  SCIP_CONS* quadcons;
7519  SCIP_Bool upgdlhs;
7520  SCIP_Bool upgdrhs;
7521  SCIP_Bool keeporig;
7522  SCIP_Bool* marked;
7523  char name[SCIP_MAXSTRLEN];
7524  SCIP_VAR* auxvar;
7525  int xpos;
7526  int ypos;
7527  int pos;
7528  int i;
7529 
7530  /* needs to check curvature, which might be expensive */
7531  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 && nquadvarterms > 10 )
7532  return SCIP_OKAY;
7533  if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 && nquadvarterms > 50 )
7534  return SCIP_OKAY;
7535 
7536  /* check if we find at least one bilinear term for which we would create a bivariate constraint
7537  * thus, we search for a variable that has a square term and is involved in at least one bivariate term */
7538  for( i = 0; i < nquadvarterms; ++i )
7539  if( quadvarterms[i].sqrcoef != 0.0 && quadvarterms[i].nadjbilin > 0 )
7540  break;
7541 
7542  /* if nothing found, then don't try upgrade and return */
7543  if( i == nquadvarterms )
7544  return SCIP_OKAY;
7545 
7546  /* check which constraint side we want to upgrade and whether to keep some
7547  * we want to upgrade those that are nonconvex */
7548  SCIP_CALL( SCIPcheckCurvatureQuadratic(scip, cons) );
7549  upgdlhs = FALSE;
7550  upgdrhs = FALSE;
7551  keeporig = FALSE;
7552  if( !SCIPisInfinity(scip, -SCIPgetLhsQuadratic(scip, cons)) )
7553  {
7554  if( SCIPisConcaveQuadratic(scip, cons) )
7555  keeporig = TRUE;
7556  else
7557  upgdlhs = TRUE;
7558  }
7559  if( !SCIPisInfinity(scip, SCIPgetRhsQuadratic(scip, cons)) )
7560  {
7561  if( SCIPisConvexQuadratic(scip, cons) )
7562  keeporig = TRUE;
7563  else
7564  upgdrhs = TRUE;
7565  }
7566 
7567  /* if nothing to upgrade, then return */
7568  if( !upgdlhs && !upgdrhs )
7569  return SCIP_OKAY;
7570 
7571  /* require enough space here already, so we do not create and add aux vars that we cannot get rid of easily later */
7572  if( upgdconsssize < nbilinterms + 1 + (keeporig ? 1 : 0) )
7573  {
7574  *nupgdconss = -(nbilinterms + 1 + (keeporig ? 1 : 0));
7575  return SCIP_OKAY;
7576  }
7577 
7578  /* initial remaining quadratic constraint: take linear part and constraint sides from original constraint */
7579  SCIP_CALL( SCIPcreateConsQuadratic(scip, &quadcons, SCIPconsGetName(cons),
7581  0, NULL, NULL, NULL,
7582  upgdlhs ? SCIPgetLhsQuadratic(scip, cons) : -SCIPinfinity(scip),
7583  upgdrhs ? SCIPgetRhsQuadratic(scip, cons) : SCIPinfinity(scip),
7587 
7588  /* remember for each quadratic variable whether its linear and square part has been moved into a bivariate constraint */
7589  SCIP_CALL( SCIPallocBufferArray(scip, &marked, nquadvarterms) );
7591 
7592  /* @todo what is a good partition of a number of quadratic terms into bivariate terms? */
7593 
7594  /* check for each bilinear term, whether we want to create a bivariate constraint for it and associated square terms */
7595  for( i = 0; i < nbilinterms; ++i )
7596  {
7597  assert(bilinterms[i].coef != 0.0);
7598 
7599  x = bilinterms[i].var1;
7600  y = bilinterms[i].var2;
7601 
7602  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, cons, x, &xpos) );
7603  assert(xpos >= 0);
7604  assert(xpos < nquadvarterms);
7605  assert(quadvarterms[xpos].var == x);
7606 
7607  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, cons, y, &ypos) );
7608  assert(ypos >= 0);
7609  assert(ypos < nquadvarterms);
7610  assert(quadvarterms[ypos].var == y);
7611 
7612  coefxx = marked[xpos] ? 0.0 : quadvarterms[xpos].sqrcoef;
7613  coefyy = marked[ypos] ? 0.0 : quadvarterms[ypos].sqrcoef;
7614 
7615  /* if there are no square terms, then do not upgrade bilinear term to bivariate constraint
7616  * thus, add bivariate term to quadcons and continue
7617  */
7618  if( coefxx == 0.0 && coefyy == 0.0 )
7619  {
7620  /* check if x and y already are in quadcons and add if not there yet */
7621  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, quadcons, x, &pos) );
7622  if( pos == -1 )
7623  {
7624  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, quadcons, x, 0.0, 0.0) );
7625  }
7626  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, quadcons, y, &pos) );
7627  if( pos == -1 )
7628  {
7629  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, quadcons, y, 0.0, 0.0) );
7630  }
7631 
7632  SCIP_CALL( SCIPaddBilinTermQuadratic(scip, quadcons, x, y, bilinterms[i].coef) );
7633 
7634  continue;
7635  }
7636 
7637  coefx = marked[xpos] ? 0.0 : quadvarterms[xpos].lincoef;
7638  coefy = marked[ypos] ? 0.0 : quadvarterms[ypos].lincoef;
7639  coefxy = bilinterms[i].coef;
7640 
7641  /* create new auxiliary variable for bilinear quad. term in x and y */
7642  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_auxvar%d", SCIPconsGetName(cons), *nupgdconss);
7643  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
7645  SCIP_CALL( SCIPaddVar(scip, auxvar) );
7646 
7647  /* add 1*auxvar to quadcons */
7648  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, quadcons, auxvar, 1.0) );
7649 
7650  /* create new bivariate constraint */
7651  assert(*nupgdconss < upgdconsssize);
7652  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_auxcons%d", SCIPconsGetName(cons), *nupgdconss);
7653  SCIP_CALL( createConsFromQuadTerm(scip, cons, &upgdconss[*nupgdconss], name,
7654  x, y, auxvar, coefxx, coefx, coefyy, coefy, coefxy, -1.0,
7655  SCIPisInfinity(scip, -SCIPgetLhsQuadratic(scip, cons)) ? -SCIPinfinity(scip) : 0.0,
7656  SCIPisInfinity(scip, SCIPgetRhsQuadratic(scip, cons)) ? SCIPinfinity(scip) : 0.0) );
7657  /* need to enforce new constraints, as relation auxvar = f(x,y) is not redundant, even if original constraint is */
7658  SCIP_CALL( SCIPsetConsEnforced(scip, upgdconss[*nupgdconss], TRUE) );
7659  SCIP_CALL( SCIPsetConsChecked(scip, upgdconss[*nupgdconss], TRUE) );
7660  ++*nupgdconss;
7661 
7662  /* compute value of auxvar in debug solution */
7663 #ifdef SCIP_DEBUG_SOLUTION
7664  if( SCIPdebugIsMainscip(scip) )
7665  {
7666  SCIP_Real xval;
7667  SCIP_Real yval;
7668  SCIP_CALL( SCIPdebugGetSolVal(scip, x, &xval) );
7669  SCIP_CALL( SCIPdebugGetSolVal(scip, y, &yval) );
7670  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, coefxx * xval * xval + coefyy * yval * yval + coefxy * xval * yval + coefx * xval + coefy * yval) );
7671  }
7672 #endif
7673 
7674  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
7675 
7676  marked[xpos] = TRUE;
7677  marked[ypos] = TRUE;
7678  }
7679 
7680  if( *nupgdconss == 0 )
7681  {
7682  /* if no constraints created, then forget also quadcons and do no upgrade */
7683  SCIP_CALL( SCIPreleaseCons(scip, &quadcons) );
7684  }
7685  else
7686  {
7687  /* complete quadcons: check for unmarked quadvarterms and add their linear and square coefficients to quadcons */
7688  for( i = 0; i < nquadvarterms; ++i )
7689  {
7690  if( marked[i] )
7691  continue;
7692 
7693  x = quadvarterms[i].var;
7694 
7695  /* check if variable is already in quadcons
7696  * if the variable appears in a bilinear term, then this term should have been added to quadcons above, so the variable is there
7697  */
7698  pos = -1;
7699  if( quadvarterms[i].nadjbilin > 0 )
7700  {
7701  SCIP_CALL( SCIPfindQuadVarTermQuadratic(scip, quadcons, x, &pos) );
7702  }
7703 
7704  /* create new quad var or add existing quad var */
7705  if( quadvarterms[i].sqrcoef != 0.0 )
7706  {
7707  if( pos == -1 )
7708  {
7709  SCIP_CALL( SCIPaddQuadVarQuadratic(scip, quadcons, x, quadvarterms[i].lincoef, quadvarterms[i].sqrcoef) );
7710  }
7711  else
7712  {
7713  SCIP_CALL( SCIPaddSquareCoefQuadratic(scip, quadcons, x, quadvarterms[i].sqrcoef) );
7714  SCIP_CALL( SCIPaddQuadVarLinearCoefQuadratic(scip, quadcons, x, quadvarterms[i].lincoef) );
7715  }
7716  }
7717  else if( quadvarterms[i].lincoef != 0.0 )
7718  {
7719  /* if no square term and no quadratic variable term, then add to linear part */
7720  SCIP_CALL( SCIPaddLinearVarQuadratic(scip, quadcons, x, quadvarterms[i].lincoef) );
7721  }
7722  }
7723 
7724  /* add quadcons to set of upgrade constraints */
7725  assert(*nupgdconss < upgdconsssize);
7726  upgdconss[*nupgdconss] = quadcons;
7727  ++*nupgdconss;
7728 
7729  SCIPdebugPrintCons(scip, quadcons, NULL);
7730 
7731  if( keeporig )
7732  {
7733  assert(*nupgdconss < upgdconsssize);
7734  /* copy of original quadratic constraint with one of the sides relaxed */
7735  SCIP_CALL( SCIPcreateConsQuadratic2(scip, &upgdconss[*nupgdconss], SCIPconsGetName(cons),
7739  upgdlhs ? -SCIPinfinity(scip) : SCIPgetLhsQuadratic(scip, cons),
7740  upgdrhs ? SCIPinfinity(scip) : SCIPgetRhsQuadratic(scip, cons),
7744  ++*nupgdconss;
7745  }
7746  }
7747 
7748  SCIPfreeBufferArray(scip, &marked);
7749  }
7750 
7751  return SCIP_OKAY;
7752 }
7753 
7754 
7755 /*
7756  * Nonlinear constraint upgrading
7757  */
7758 
7759 /** tries to reformulate a expression graph node that is a monomial in two variables */
7760 static
7761 SCIP_DECL_EXPRGRAPHNODEREFORM(exprgraphnodeReformBivariate)
7763  SCIP_EXPRDATA_MONOMIAL* monomial;
7764  SCIP_CONS* cons;
7765  SCIP_VAR* auxvar;
7766  char name[SCIP_MAXSTRLEN];
7767  SCIP_VAR* x;
7768  SCIP_VAR* y;
7769  SCIP_Real expx;
7770  SCIP_Real expy;
7771 
7772  assert(scip != NULL);
7773  assert(exprgraph != NULL);
7774  assert(node != NULL);
7775  assert(naddcons != NULL);
7776  assert(reformnode != NULL);
7777 
7778  *reformnode = NULL;
7779 
7780  /* could also upgrade bivariate quadratic, but if we don't then node will appear in cons_quadratic later, from which we also upgrade...
7781  * @todo could also upgrade x/y from EXPR_DIV */
7783  return SCIP_OKAY;
7784 
7785  /* sums of monomials are split up by reformulation, so wait that this happened */
7787  return SCIP_OKAY;
7788 
7789  /* we are only interested in monomials that are not convex or concave, since cons_nonlinear can handle these the same was as we do */
7791  return SCIP_OKAY;
7792 
7793  monomial = SCIPexprgraphGetNodePolynomialMonomials(node)[0];
7794  assert(monomial != NULL);
7795 
7796  /* @todo we could also do some more complex reformulation for n-variate monomials, something better than what reformMonomial in cons_nonlinear is doing */
7797  if( SCIPexprGetMonomialNFactors(monomial) != 2 )
7798  return SCIP_OKAY;
7799  assert(SCIPexprgraphGetNodeNChildren(node) == 2);
7800 
7801  expx = SCIPexprGetMonomialExponents(monomial)[0];
7802  expy = SCIPexprGetMonomialExponents(monomial)[1];
7803 
7804  /* no interest in upgrading x*y -> let cons_quadratic do this */
7805  if( SCIPisEQ(scip, expx, 1.0) && SCIPisEQ(scip, expy, 1.0) )
7806  return SCIP_OKAY;
7807 
7808  /* so far only support variables as arguments @todo could allow more here, e.g., f(x)^pg(y)^q */
7811  return SCIP_OKAY;
7812 
7815  assert(x != y);
7816 
7817  /* so far only allow positive x and y @todo could also allow x<0 or y<0 */
7819  return SCIP_OKAY;
7820 
7821  SCIPdebugMessage("reformulate bivariate monomial in node %p\n", (void*)node);
7822 
7823  /* create auxiliary variable */
7824  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%dbv", *naddcons);
7825  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, SCIPexprgraphGetNodeBounds(node).inf, SCIPexprgraphGetNodeBounds(node).sup,
7827  SCIP_CALL( SCIPaddVar(scip, auxvar) );
7828 
7829  /* create bivariate constraint */
7830  SCIP_CALL( createConsFromMonomial(scip, NULL, &cons, name, x, y, auxvar,
7832  SCIP_CALL( SCIPaddCons(scip, cons) );
7833  SCIPdebugPrintCons(scip, cons, NULL);
7834  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
7835  ++*naddcons;
7836 
7837  /* add auxvar to exprgraph and return it in reformnode */
7838  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, reformnode) );
7839 
7840  /* set value of auxvar and reformnode in debug solution */
7841 #ifdef SCIP_DEBUG_SOLUTION
7842  if( SCIPdebugIsMainscip(scip) )
7843  {
7844  SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(node));
7846  }
7847 #endif
7848 
7849  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
7850 
7851  return SCIP_OKAY;
7852 }
7853 
7854 /*
7855  * constraint specific interface methods
7856  */
7857 
7858 /** creates the handler for bivariate constraints and includes it in SCIP */
7860  SCIP* scip /**< SCIP data structure */
7861  )
7862 {
7863  SCIP_CONSHDLRDATA* conshdlrdata;
7864  SCIP_CONSHDLR* conshdlr;
7865 
7866  /* create bivariate constraint handler data */
7867  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
7868  BMSclearMemory(conshdlrdata);
7869 
7870  /* include constraint handler */
7873  consEnfolpBivariate, consEnfopsBivariate, consCheckBivariate, consLockBivariate,
7874  conshdlrdata) );
7875 
7876  assert(conshdlr != NULL);
7877 
7878  /* set non-fundamental callbacks via specific setter functions */
7879  SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveBivariate) );
7880  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyBivariate, consCopyBivariate) );
7881  SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveBivariate) );
7882  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteBivariate) );
7883  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableBivariate) );
7884  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableBivariate) );
7885  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitBivariate) );
7886  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreBivariate) );
7887  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolBivariate) );
7888  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeBivariate) );
7889  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsBivariate) );
7890  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsBivariate) );
7891  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitBivariate) );
7892  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreBivariate) );
7893  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolBivariate) );
7894  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpBivariate) );
7895  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolBivariate, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
7896  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintBivariate) );
7897  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropBivariate, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
7899  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpBivariate, consSepasolBivariate, CONSHDLR_SEPAFREQ,
7901  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransBivariate) );
7902 
7903  /* include the quadratic constraint upgrade in the quadratic constraint handler */
7905 
7906  /* include the quadratic constraint upgrade in the quadratic constraint handler */
7907  SCIP_CALL( SCIPincludeNonlinconsUpgrade(scip, NULL, exprgraphnodeReformBivariate, NONLINCONSUPGD_PRIORITY, FALSE, CONSHDLR_NAME) );
7908 
7909  /* add bivariate constraint handler parameters */
7910  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacysepa",
7911  "minimal efficacy for a cut to be added to the LP during separation; overwrites separating/efficacy",
7912  &conshdlrdata->mincutefficacysepa, FALSE, 0.0001, 0.0, SCIPinfinity(scip), NULL, NULL) );
7913 
7914  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/minefficacyenfo",
7915  "minimal target efficacy of a cut in order to add it to relaxation during enforcement (may be ignored)",
7916  &conshdlrdata->mincutefficacyenfo, FALSE, 2.0*SCIPfeastol(scip), 0.0, SCIPinfinity(scip), NULL, NULL) );
7917 
7918  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
7919  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
7920  &conshdlrdata->cutmaxrange, TRUE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
7921 
7922  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
7923  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
7924  &conshdlrdata->linfeasshift, FALSE, TRUE, NULL, NULL) );
7925 
7926  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
7927  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation",
7928  &conshdlrdata->maxproprounds, FALSE, 1, 0, INT_MAX, NULL, NULL) );
7929 
7930  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/ninitlprefpoints",
7931  "number of reference points in each direction where to compute linear support for envelope in LP initialization",
7932  &conshdlrdata->ninitlprefpoints, FALSE, 3, 0, INT_MAX, NULL, NULL) );
7933 
7934  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
7935  "are cuts added during enforcement removable from the LP in the same node?",
7936  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
7937 
7938  SCIP_CALL( SCIPaddCharParam(scip, "constraints/" CONSHDLR_NAME "/scaling",
7939  "whether scaling of infeasibility is 'o'ff, by sup-norm of function 'g'radient, or by left/right hand 's'ide",
7940  &conshdlrdata->scaling, TRUE, 'o', "ogs", NULL, NULL) );
7941 
7942  conshdlrdata->linvareventhdlr = NULL;
7943  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->linvareventhdlr), CONSHDLR_NAME"_boundchange", "signals a bound tightening in a linear variable to a bivariate constraint",
7944  processLinearVarEvent, NULL) );
7945  assert(conshdlrdata->linvareventhdlr != NULL);
7946 
7947  conshdlrdata->nonlinvareventhdlr = NULL;
7948  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->nonlinvareventhdlr), CONSHDLR_NAME"_boundchange2", "signals a bound change in a nonlinear variable to the bivariate constraint handler",
7949  processNonlinearVarEvent, (SCIP_EVENTHDLRDATA*)conshdlrdata) );
7950  assert(conshdlrdata->nonlinvareventhdlr != NULL);
7951 
7952  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
7953  processNewSolutionEvent, NULL) );
7954 
7955  /* create expression interpreter */
7956  SCIP_CALL( SCIPexprintCreate(SCIPblkmem(scip), &conshdlrdata->exprinterpreter) );
7957 
7958  /* create expression graph */
7959  SCIP_CALL( SCIPexprgraphCreate(SCIPblkmem(scip), &conshdlrdata->exprgraph, -1, -1,
7960  exprgraphVarAdded, exprgraphVarRemove, NULL, (void*)conshdlrdata) );
7961  conshdlrdata->isremovedfixings = TRUE;
7962  conshdlrdata->ispropagated = TRUE;
7963 
7964  conshdlrdata->scip = scip;
7965 
7966  return SCIP_OKAY;
7967 }
7968 
7969 /** creates and captures a bivariate constraint
7970  *
7971  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
7972  */
7974  SCIP* scip, /**< SCIP data structure */
7975  SCIP_CONS** cons, /**< pointer to hold the created constraint */
7976  const char* name, /**< name of constraint */
7977  SCIP_EXPRTREE* f, /**< expression tree specifying bivariate function f(x,y) */
7978  SCIP_BIVAR_CONVEXITY convextype, /**< kind of convexity of f(x,y) */
7979  SCIP_VAR* z, /**< linear variable in constraint */
7980  SCIP_Real zcoef, /**< coefficient of linear variable */
7981  SCIP_Real lhs, /**< left hand side of constraint */
7982  SCIP_Real rhs, /**< right hand side of constraint */
7983  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
7984  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
7985  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
7986  * Usually set to TRUE. */
7987  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
7988  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7989  SCIP_Bool check, /**< should the constraint be checked for feasibility?
7990  * TRUE for model constraints, FALSE for additional, redundant constraints. */
7991  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
7992  * Usually set to TRUE. */
7993  SCIP_Bool local, /**< is constraint only valid locally?
7994  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
7995  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
7996  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
7997  * adds coefficients to this constraint. */
7998  SCIP_Bool dynamic, /**< is constraint subject to aging?
7999  * Usually set to FALSE. Set to TRUE for own cuts which
8000  * are seperated as constraints. */
8001  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
8002  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
8003  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
8004  * if it may be moved to a more global node?
8005  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
8006  )
8007 {
8008  SCIP_CONSHDLR* conshdlr;
8009  SCIP_CONSDATA* consdata;
8010 
8011  assert(f != NULL);
8012  assert(!SCIPisInfinity(scip, REALABS(zcoef)));
8013  assert(modifiable == FALSE); /* we do not support column generation */
8014 
8015  /* find the bivariate constraint handler */
8016  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
8017  if( conshdlr == NULL )
8018  {
8019  SCIPerrorMessage("bivariate constraint handler not found\n");
8020  return SCIP_PLUGINNOTFOUND;
8021  }
8022 
8023  /* create constraint data */
8024  SCIP_CALL( SCIPallocMemory(scip, &consdata) );
8025  BMSclearMemory(consdata);
8026 
8027  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &consdata->f, f) );
8028  consdata->convextype = convextype;
8029  consdata->z = z;
8030  consdata->zcoef = zcoef;
8031  consdata->lhs = lhs;
8032  consdata->rhs = rhs;
8033 
8034  assert(SCIPexprtreeGetNVars(consdata->f) == 2);
8035  assert(SCIPexprtreeGetVars(consdata->f) != NULL);
8036  assert(SCIPexprtreeGetVars(consdata->f)[0] != NULL);
8037  assert(SCIPexprtreeGetVars(consdata->f)[1] != NULL);
8038 
8039  /* mark that variable events are not catched so far */
8040  consdata->eventfilterpos = -1;
8041 
8042  /* create constraint */
8043  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
8044  local, modifiable, dynamic, removable, stickingatnode) );
8045 
8046  return SCIP_OKAY;
8047 }
8048 
8049 /** creates and captures an absolute power constraint
8050  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
8051  * method SCIPcreateConsBivariate(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
8052  *
8053  * @see SCIPcreateConsBivariate() for information about the basic constraint flag configuration
8054  *
8055  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
8056  */
8058  SCIP* scip, /**< SCIP data structure */
8059  SCIP_CONS** cons, /**< pointer to hold the created constraint */
8060  const char* name, /**< name of constraint */
8061  SCIP_EXPRTREE* f, /**< expression tree specifying bivariate function f(x,y) */
8062  SCIP_BIVAR_CONVEXITY convextype, /**< kind of convexity of f(x,y) */
8063  SCIP_VAR* z, /**< linear variable in constraint */
8064  SCIP_Real zcoef, /**< coefficient of linear variable */
8065  SCIP_Real lhs, /**< left hand side of constraint */
8066  SCIP_Real rhs /**< right hand side of constraint */
8067  )
8068 {
8069  assert(scip != NULL);
8070 
8071  SCIP_CALL( SCIPcreateConsBivariate(scip, cons, name, f, convextype, z, zcoef, lhs, rhs,
8072  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
8073 
8074  return SCIP_OKAY;
8075 }
8076 
8077 /** gets the linear variable of a bivariate constraint, or NULL if no such variable */
8079  SCIP* scip, /**< SCIP data structure */
8080  SCIP_CONS* cons /**< constraint */
8081  )
8082 {
8083  assert(cons != NULL);
8084  assert(SCIPconsGetData(cons) != NULL);
8085 
8086  return SCIPconsGetData(cons)->z;
8087 }
8088 
8089 /** gets the coefficients of the linear variable of a bivariate constraint */
8091  SCIP* scip, /**< SCIP data structure */
8092  SCIP_CONS* cons /**< constraint */
8093  )
8094 {
8095  assert(cons != NULL);
8096  assert(SCIPconsGetData(cons) != NULL);
8097 
8098  return SCIPconsGetData(cons)->zcoef;
8099 }
8100 
8101 /** gets the expression tree of a bivariate constraint */
8103  SCIP* scip, /**< SCIP data structure */
8104  SCIP_CONS* cons /**< constraint */
8105  )
8106 {
8107  assert(cons != NULL);
8108  assert(SCIPconsGetData(cons) != NULL);
8109 
8110  return SCIPconsGetData(cons)->f;
8111 }
8112 
8113 /** gets the left hand side of a bivariate constraint */
8115  SCIP* scip, /**< SCIP data structure */
8116  SCIP_CONS* cons /**< constraint */
8117  )
8118 {
8119  assert(cons != NULL);
8120  assert(SCIPconsGetData(cons) != NULL);
8121 
8122  return SCIPconsGetData(cons)->lhs;
8123 }
8124 
8125 /** gets the right hand side of a bivariate constraint */
8127  SCIP* scip, /**< SCIP data structure */
8128  SCIP_CONS* cons /**< constraint */
8129  )
8130 {
8131  assert(cons != NULL);
8132  assert(SCIPconsGetData(cons) != NULL);
8133 
8134  return SCIPconsGetData(cons)->rhs;
8135 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:51
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:34812
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:41572
void SCIPintervalDivScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13095
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:15853
#define CONSHDLR_NAME
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15586
void SCIPexprFreeDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6061
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41685
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15267
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip.c:28308
static SCIP_RETCODE catchLinearVarEvents(SCIP *scip, SCIP_CONS *cons)
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:5878
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:20526
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:5588
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:5657
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:14723
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:2252
primal heuristic that tries a given solution
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16443
static SCIP_DECL_CONSPRESOL(consPresolBivariate)
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:15007
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:17373
#define NEWTONMAXITER
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:20589
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:41648
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:20538
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12733
SCIP_Real SCIPgetRowMinCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28045
SCIP_QUADVARTERM * SCIPgetQuadVarTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:10378
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11540
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5573
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip.c:1248
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:15737
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14693
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41920
static SCIP_RETCODE dropLinearVarEvents(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetRelaxFeastolFactor(SCIP *scip)
Definition: scip.c:31547
#define SCIP_MAXSTRLEN
Definition: def.h:201
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:5246
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4288
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:17113
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4258
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:29365
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:940
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:7849
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:18915
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:18861
internal methods for NLPI solver interfaces
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:7681
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:5334
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:17067
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:14767
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:17429
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:5818
SCIP_RETCODE SCIPevalExprtreeLocalBounds(SCIP *scip, SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *val)
Definition: scip.c:30394
#define BMSclearMemory(ptr)
Definition: memory.h:84
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip.c:5703
void SCIPexprgraphPropagateNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:15640
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip.c:7393
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:7909
#define FALSE
Definition: def.h:56
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:35113
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:14713
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:7778
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:8174
#define TRUE
Definition: def.h:55
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7640
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip.c:33396
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
#define infty2infty(infty1, infty2, val)
static SCIP_DECL_CONSCHECK(consCheckBivariate)
#define SCIP_CALL(x)
Definition: def.h:266
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:13085
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41972
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:30949
static SCIP_DECL_CONSGETNVARS(consGetNVarsBivariate)
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:27888
#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:34983
SCIP_Bool SCIPintervalIsNegativeInfinity(SCIP_Real infinity, SCIP_INTERVAL operand)
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15127
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:27783
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:7839
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:7779
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:26237
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:30967
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:24949
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8482
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:99
SCIP_RETCODE SCIPexprintCreate(BMS_BLKMEM *blkmem, SCIP_EXPRINT **exprint)
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28063
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:14874
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12956
#define SCIP_PRESOLTIMING_FAST
Definition: type_timing.h:43
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:5359
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:7769
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip.c:7908
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:28658
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:5383
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:3547
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16562
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:3573
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16634
#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:12793
static SCIP_DECL_CONSPROP(consPropBivariate)
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3917
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12944
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:14835
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDEACTIVE((*consdeactive)))
Definition: scip.c:5680
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:36622
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
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:20542
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:1781
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:44
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12968
SCIP_RETCODE SCIPcheckCurvatureQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13105
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:41709
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip.c:17075
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:7879
SCIP_Real SCIPgetLhsBivariate(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
#define QUADCONSUPGD_PRIORITY
#define SCIPerrorMessage
Definition: pub_message.h:45
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:18925
#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:19526
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:41118
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip.c:28407
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41598
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:5527
#define CONSHDLR_DESC
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28151
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:31062
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:41353
static SCIP_DECL_CONSDELETE(consDeleteBivariate)
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7620
static SCIP_DECL_CONSCOPY(consCopyBivariate)
#define CONSHDLR_EAGERFREQ
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41907
static SCIP_DECL_EXPRGRAPHVARADDED(exprgraphVarAdded)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:41758
SCIP_BIVAR_CONVEXITY
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:19024
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:5503
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)
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:28392
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:35020
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:41637
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5292
#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:5192
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 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:37435
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:14451
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip.c:32131
SCIP_VAR ** SCIPgetLinearVarsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41946
static SCIP_RETCODE freeSepaData(SCIP *scip, SCIP_CONS *cons)
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:264
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:7650
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip.c:16884
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:5726
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12080
static SCIP_DECL_CONSDEACTIVE(consDeactiveBivariate)
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip.c:17116
SCIP_Real SCIPgetUpperbound(SCIP *scip)
Definition: scip.c:38534
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41611
static SCIP_DECL_EVENTEXEC(processLinearVarEvent)
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:23119
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:20193
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17123
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:5479
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:24772
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41819
SCIP_RETCODE SCIPsetConsEnforced(SCIP *scip, SCIP_CONS *cons, SCIP_Bool enforce)
Definition: scip.c:25097
#define SCIP_Bool
Definition: def.h:53
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip.c:1216
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:14787
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:7859
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:34271
methods for debugging
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:14807
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:7869
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:7969
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:7739
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:5611
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14332
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:28027
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, .
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:36779
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip.c:34940
SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7046
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12825
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1298
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41624
#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:36668
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:5565
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11477
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip.c:5431
#define INITLPMAXVARVAL
SCIP_RETCODE SCIPupdateStartpointHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *solcand, SCIP_Real violation)
Definition: heur_subnlp.c:2364
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
Definition: scip.c:41770
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:20585
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17057
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:36588
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:5772
static SCIP_DECL_CONSEXIT(consExitBivariate)
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip.c:29472
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1281
#define REALABS(x)
Definition: def.h:151
static SCIP_DECL_CONSINITLP(consInitlpBivariate)
int SCIPgetNBilinTermsQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcomputeHyperplaneThreePoints(SCIP *scip, SCIP_Real a1, SCIP_Real a2, SCIP_Real a3, SCIP_Real b1, SCIP_Real b2, SCIP_Real b3, SCIP_Real c1, SCIP_Real c2, SCIP_Real c3, SCIP_Real *alpha, SCIP_Real *beta, SCIP_Real *gamma_, SCIP_Real *delta)
#define CONSHDLR_PROPFREQ
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:18871
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:5455
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:14190
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41933
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:19453
#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:127
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:7799
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:3657
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:20299
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:67
SCIP_RETCODE SCIPsetConsChecked(SCIP *scip, SCIP_CONS *cons, SCIP_Bool check)
Definition: scip.c:25122
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:27600
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip.c:34044
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:28334
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41959
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:12743
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:147
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:41146
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5810
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:27738
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:19685
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:263
#define SCIPisFinite(x)
Definition: pub_misc.h:5428
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:5407
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:19399
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:42283
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:18836
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
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:20597
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16730
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip.c:33701
#define SCIPdebug(x)
Definition: pub_message.h:74
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
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:18685
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41697
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14703
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:3629
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:5841
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:7707
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:27864
#define SCIPABORT()
Definition: def.h:238
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:7789
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:7819
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:27759
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:36554
SCIP_Bool SCIPisConvexQuadratic(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip.c:34607
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:27472
#define CONSHDLR_DELAYSEPA
void SCIPexprgraphEnableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14305
enum SCIP_SideType SCIP_SIDETYPE
Definition: type_lp.h:58