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