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