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