Scippy

SCIP

Solving Constraint Integer Programs

cons_nonlinear.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2019 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_nonlinear.c
17  * @brief constraint handler for nonlinear constraints \f$\textrm{lhs} \leq \sum_{i=1}^n a_ix_i + \sum_{j=1}^m c_jf_j(x) \leq \textrm{rhs}\f$
18  * @author Stefan Vigerske
19  * @author Ingmar Vierhaus (consparse)
20  */
21 
22 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
23 
24 #include "blockmemshell/memory.h"
25 #include <ctype.h>
26 #include "lpi/lpi.h"
27 #include "lpi/type_lpi.h"
28 #include "nlpi/exprinterpret.h"
29 #include "nlpi/nlpi_ipopt.h"
30 #include "nlpi/pub_expr.h"
32 #include "nlpi/type_nlpi.h"
33 #include "scip/cons_linear.h"
34 #include "scip/cons_nonlinear.h"
35 #define SCIP_PRIVATE_ROWPREP
36 #include "scip/cons_quadratic.h" /* for SCIP_ROWPREP */
37 #include "scip/debug.h"
38 #include "scip/heur_subnlp.h"
39 #include "scip/heur_trysol.h"
40 #include "scip/intervalarith.h"
41 #include "scip/pub_cons.h"
42 #include "scip/pub_event.h"
43 #include "scip/pub_heur.h"
44 #include "scip/pub_lp.h"
45 #include "scip/pub_message.h"
46 #include "scip/pub_misc.h"
47 #include "scip/pub_misc_sort.h"
48 #include "scip/pub_nlp.h"
49 #include "scip/pub_sol.h"
50 #include "scip/pub_tree.h"
51 #include "scip/pub_var.h"
52 #include "scip/scip_branch.h"
53 #include "scip/scip_cons.h"
54 #include "scip/scip_copy.h"
55 #include "scip/scip_cut.h"
56 #include "scip/scip_event.h"
57 #include "scip/scip_expr.h"
58 #include "scip/scip_general.h"
59 #include "scip/scip_heur.h"
60 #include "scip/scip_lp.h"
61 #include "scip/scip_mem.h"
62 #include "scip/scip_message.h"
63 #include "scip/scip_nlp.h"
64 #include "scip/scip_numerics.h"
65 #include "scip/scip_param.h"
66 #include "scip/scip_prob.h"
67 #include "scip/scip_probing.h"
68 #include "scip/scip_sepa.h"
69 #include "scip/scip_sol.h"
70 #include "scip/scip_solvingstats.h"
71 #include "scip/scip_tree.h"
72 #include "scip/scip_var.h"
73 #include <string.h>
74 
75 /* Inform compiler that this code accesses the floating-point environment, so that
76  * certain optimizations should be omitted (http://www.cplusplus.com/reference/cfenv/FENV_ACCESS/).
77  * Not supported by Clang (gives warning) and GCC (silently), at the moment.
78  */
79 #ifndef __clang__
80 #pragma STD FENV_ACCESS ON
81 #endif
82 
83 /* constraint handler properties */
84 #define CONSHDLR_NAME "nonlinear"
85 #define CONSHDLR_DESC "constraint handler for nonlinear constraints"
86 #define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
87 #define CONSHDLR_ENFOPRIORITY -60 /**< priority of the constraint handler for constraint enforcing */
88 #define CONSHDLR_CHECKPRIORITY -4000010 /**< priority of the constraint handler for checking feasibility */
89 #define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
90 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
91 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
92  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
93 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
94 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
95 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
96 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
97 
98 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
99 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
101 #define INTERVALINFTY 1E+43 /**< value for infinity in interval operations */
102 #define BOUNDTIGHTENING_MINSTRENGTH 0.05/**< minimal required bound tightening strength in expression graph domain tightening for propagating bound change */
103 #define INITLPMAXVARVAL 1000.0 /**< maximal absolute value of variable for still generating a linearization cut at that point in initlp */
105 /*
106  * Data structures
107  */
108 
109 /** event data for linear variable bound change events */
110 struct LinVarEventData
111 {
112  SCIP_CONSHDLRDATA* conshdlrdata; /**< the constraint handler data */
113  SCIP_CONS* cons; /**< the constraint */
114  int varidx; /**< the index of the linear variable which bound change is catched */
115  int filterpos; /**< position of eventdata in SCIP's event filter */
116 };
117 typedef struct LinVarEventData LINVAREVENTDATA;
119 /** constraint data for nonlinear constraints */
120 struct SCIP_ConsData
121 {
122  SCIP_Real lhs; /**< left hand side of constraint */
123  SCIP_Real rhs; /**< right hand side of constraint */
124 
125  int nlinvars; /**< number of linear variables */
126  int linvarssize; /**< length of linear variable arrays */
127  SCIP_VAR** linvars; /**< linear variables */
128  SCIP_Real* lincoefs; /**< coefficients of linear variables */
129  LINVAREVENTDATA** lineventdata; /**< eventdata for bound change of linear variable */
130 
131  int nexprtrees; /**< number of expression trees */
132  SCIP_Real* nonlincoefs; /**< coefficients of expression trees */
133  SCIP_EXPRTREE** exprtrees; /**< nonlinear part of constraint */
134  SCIP_EXPRCURV* curvatures; /**< curvature of each expression tree (taking nonlincoefs into account) */
135  SCIP_EXPRGRAPHNODE* exprgraphnode; /**< node in expression graph corresponding to expression tree of this constraint */
136  SCIP_EXPRCURV curvature; /**< curvature of complete nonlinear part, if checked */
137 
138  SCIP_NLROW* nlrow; /**< a nonlinear row representation of this constraint */
139 
140  unsigned int linvarssorted:1; /**< are the linear variables already sorted? */
141  unsigned int linvarsmerged:1; /**< are equal linear variables already merged? */
142 
143  unsigned int iscurvchecked:1; /**< is nonlinear function checked on convexity or concavity ? */
144  unsigned int isremovedfixingslin:1; /**< did we removed fixed/aggr/multiaggr variables in linear part? */
145  unsigned int ispresolved:1; /**< did we checked for possibilities of upgrading or implicit integer variables? */
146  unsigned int forcebackprop:1; /**< should we force to run the backward propagation on our subgraph in the exprgraph? */
147 
148  SCIP_Real minlinactivity; /**< sum of minimal activities of all linear terms with finite minimal activity */
149  SCIP_Real maxlinactivity; /**< sum of maximal activities of all linear terms with finite maximal activity */
150  int minlinactivityinf; /**< number of linear terms with infinite minimal activity */
151  int maxlinactivityinf; /**< number of linear terms with infinity maximal activity */
152  SCIP_Real activity; /**< activity of constraint function w.r.t. current solution */
153  SCIP_Real lhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
154  SCIP_Real rhsviol; /**< violation of lower bound by current solution (used temporarily inside constraint handler) */
155 
156  int linvar_maydecrease; /**< index of a variable in linvars that may be decreased without making any other constraint infeasible, or -1 if none */
157  int linvar_mayincrease; /**< index of a variable in linvars that may be increased without making any other constraint infeasible, or -1 if none */
158 
159  SCIP_Real lincoefsmin; /**< maximal absolute value of coefficients in linear part, only available in solving stage */
160  SCIP_Real lincoefsmax; /**< minimal absolute value of coefficients in linear part, only available in solving stage */
161  unsigned int ncuts; /**< number of cuts created for this constraint so far */
162 };
163 
164 /** nonlinear constraint update method */
165 struct SCIP_NlConsUpgrade
166 {
167  SCIP_DECL_NONLINCONSUPGD((*nlconsupgd)); /**< method to call for upgrading nonlinear constraint */
168  SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform));/**< method to call for reformulating an expression graph node */
169  int priority; /**< priority of upgrading method */
170  SCIP_Bool active; /**< is upgrading enabled */
171 };
174 /** constraint handler data */
175 struct SCIP_ConshdlrData
176 {
177  SCIP_EXPRINT* exprinterpreter; /**< expression interpreter to compute gradients */
178 
179  SCIP_Real cutmaxrange; /**< maximal range (maximal coef / minimal coef) of a cut in order to be added to LP */
180  SCIP_Bool linfeasshift; /**< whether to make solutions in check feasible if possible */
181  SCIP_Bool checkconvexexpensive;/**< whether to apply expensive curvature checking methods */
182  SCIP_Bool assumeconvex; /**< whether functions in inequalities should be assumed to be convex */
183  int maxproprounds; /**< limit on number of propagation rounds for a single constraint within one round of SCIP propagation */
184  SCIP_Bool reformulate; /**< whether to reformulate expression graph */
185  int maxexpansionexponent;/**< maximal exponent where still expanding non-monomial polynomials in expression simplification */
186  SCIP_Real sepanlpmincont; /**< minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation */
187  SCIP_Bool enfocutsremovable; /**< are cuts added during enforcement removable from the LP in the same node? */
188 
189  SCIP_HEUR* subnlpheur; /**< a pointer to the subNLP heuristic, if available */
190  SCIP_HEUR* trysolheur; /**< a pointer to the TRYSOL heuristic, if available */
191  SCIP_EVENTHDLR* linvareventhdlr; /**< our handler for linear variable bound change events */
192  SCIP_EVENTHDLR* nonlinvareventhdlr; /**< our handler for nonlinear variable bound change events */
193  int newsoleventfilterpos;/**< filter position of new solution event handler, if catched */
194 
195  SCIP_NLCONSUPGRADE** nlconsupgrades; /**< nonlinear constraint upgrade methods for specializing nonlinear constraints */
196  int nlconsupgradessize; /**< size of nlconsupgrade array */
197  int nnlconsupgrades; /**< number of nonlinear constraint upgrade methods */
198 
199  SCIP_EXPRGRAPH* exprgraph; /**< expression graph */
200  SCIP* scip; /**< SCIP pointer for use in expression graph callbacks */
201  unsigned int isremovedfixings:1; /**< have fixed variables been removed in the expression graph? */
202  unsigned int ispropagated:1; /**< have current bounds of linear variables in constraints and variables in expression graph been propagated? */
203  unsigned int isreformulated:1; /**< has expression graph been reformulated? */
204  unsigned int sepanlp:1; /**< has a linearization in the NLP relaxation been added? */
205  int naddedreformconss; /**< number of constraints added via reformulation */
206  SCIP_NODE* lastenfonode; /**< the node for which enforcement was called the last time (and some constraint was violated) */
207  int nenforounds; /**< counter on number of enforcement rounds for the current node */
208 };
209 
210 /*
211  * Local methods
212  */
213 
214 /** translate from one value of infinity to another
215  *
216  * if val is >= infty1, then give infty2, else give val
217  */
218 #define infty2infty(infty1, infty2, val) ((val) >= (infty1) ? (infty2) : (val))
220 /* catches variable bound change events on a linear variable in a nonlinear constraint */
221 static
223  SCIP* scip, /**< SCIP data structure */
224  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
225  int linvarpos /**< position of variable in linear variables array */
226  )
227 {
229  SCIP_CONSDATA* consdata;
230  LINVAREVENTDATA* eventdata;
231  SCIP_EVENTTYPE eventtype;
232 
233  assert(scip != NULL);
234  assert(cons != NULL);
235  assert(SCIPconsIsEnabled(cons));
236  assert(SCIPconsIsTransformed(cons));
237 
238  assert(SCIPconsGetHdlr(cons) != NULL);
239  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
240  assert(conshdlrdata != NULL);
241  assert(conshdlrdata->linvareventhdlr != NULL);
242 
243  consdata = SCIPconsGetData(cons);
244  assert(consdata != NULL);
245 
246  assert(linvarpos >= 0);
247  assert(linvarpos < consdata->nlinvars);
248 
249  SCIP_CALL( SCIPallocBlockMemory(scip, &eventdata) );
250 
251  eventtype = SCIP_EVENTTYPE_VARFIXED;
252  if( !SCIPisInfinity(scip, consdata->rhs) )
253  {
254  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest */
255  if( consdata->lincoefs[linvarpos] > 0.0 )
256  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
257  else
258  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
259  }
260  if( !SCIPisInfinity(scip, -consdata->lhs) )
261  {
262  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest */
263  if( consdata->lincoefs[linvarpos] > 0.0 )
264  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
265  else
266  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
267  }
268 
269  eventdata->conshdlrdata = conshdlrdata;
270  eventdata->cons = cons;
271  eventdata->varidx = linvarpos;
272  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->linvars[linvarpos], eventtype, conshdlrdata->linvareventhdlr, (SCIP_EVENTDATA*)eventdata, &eventdata->filterpos) );
273 
274  /* ensure lineventdata array is existing */
275  if( consdata->lineventdata == NULL )
276  {
277  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize) );
278  }
279 
280  consdata->lineventdata[linvarpos] = eventdata;
281 
282  /* since bound changes were not catched before, a possibly stored linear activity may have become outdated, so set to invalid */
283  consdata->minlinactivity = SCIP_INVALID;
284  consdata->maxlinactivity = SCIP_INVALID;
285 
286  /* mark constraint for propagation */
287  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
288 
289  return SCIP_OKAY;
290 }
291 
292 /* drops variable bound change events on a linear variable in a nonlinear constraint */
293 static
295  SCIP* scip, /**< SCIP data structure */
296  SCIP_CONS* cons, /**< constraint for which to catch bound change events */
297  int linvarpos /**< position of variable in linear variables array */
298  )
299 {
301  SCIP_CONSDATA* consdata;
302  SCIP_EVENTTYPE eventtype;
303 
304  assert(scip != NULL);
305  assert(cons != NULL);
306  assert(SCIPconsIsTransformed(cons));
307 
308  assert(SCIPconsGetHdlr(cons) != NULL);
310  assert(conshdlrdata != NULL);
311  assert(conshdlrdata->linvareventhdlr != NULL);
312 
313  consdata = SCIPconsGetData(cons);
314  assert(consdata != NULL);
315 
316  assert(linvarpos >= 0);
317  assert(linvarpos < consdata->nlinvars);
318  assert(consdata->lineventdata != NULL);
319  assert(consdata->lineventdata[linvarpos] != NULL);
320  assert(consdata->lineventdata[linvarpos]->cons == cons);
321  assert(consdata->lineventdata[linvarpos]->varidx == linvarpos);
322  assert(consdata->lineventdata[linvarpos]->filterpos >= 0);
323 
324  eventtype = SCIP_EVENTTYPE_VARFIXED;
325  if( !SCIPisInfinity(scip, consdata->rhs) )
326  {
327  /* if right hand side is finite, then a tightening in the lower bound of coef*linvar is of interest */
328  if( consdata->lincoefs[linvarpos] > 0.0 )
329  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
330  else
331  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
332  }
333  if( !SCIPisInfinity(scip, -consdata->lhs) )
334  {
335  /* if left hand side is finite, then a tightening in the upper bound of coef*linvar is of interest */
336  if( consdata->lincoefs[linvarpos] > 0.0 )
337  eventtype |= SCIP_EVENTTYPE_UBCHANGED;
338  else
339  eventtype |= SCIP_EVENTTYPE_LBCHANGED;
340  }
341 
342  SCIP_CALL( SCIPdropVarEvent(scip, consdata->linvars[linvarpos], eventtype, conshdlrdata->linvareventhdlr, (SCIP_EVENTDATA*)consdata->lineventdata[linvarpos], consdata->lineventdata[linvarpos]->filterpos) );
343 
344  SCIPfreeBlockMemory(scip, &consdata->lineventdata[linvarpos]); /*lint !e866*/
345 
346  return SCIP_OKAY;
347 }
348 
349 /** locks a linear variable in a constraint */
350 static
352  SCIP* scip, /**< SCIP data structure */
353  SCIP_CONS* cons, /**< constraint where to lock a variable */
354  SCIP_VAR* var, /**< variable to lock */
355  SCIP_Real coef /**< coefficient of variable in constraint */
356  )
357 {
358  SCIP_CONSDATA* consdata;
359 
360  assert(scip != NULL);
361  assert(cons != NULL);
362  assert(var != NULL);
363  assert(coef != 0.0);
364 
365  consdata = SCIPconsGetData(cons);
366  assert(consdata != NULL);
367 
368  if( coef > 0.0 )
369  {
370  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
371  }
372  else
373  {
374  SCIP_CALL( SCIPlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
375  }
376 
377  return SCIP_OKAY;
378 }
379 
380 /** unlocks a linear variable in a constraint */
381 static
383  SCIP* scip, /**< SCIP data structure */
384  SCIP_CONS* cons, /**< constraint where to unlock a variable */
385  SCIP_VAR* var, /**< variable to unlock */
386  SCIP_Real coef /**< coefficient of variable in constraint */
387  )
388 {
389  SCIP_CONSDATA* consdata;
390 
391  assert(scip != NULL);
392  assert(cons != NULL);
394  assert(var != NULL);
395  assert(coef != 0.0);
396 
397  consdata = SCIPconsGetData(cons);
398  assert(consdata != NULL);
399 
400  if( coef > 0.0 )
401  {
402  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
403  }
404  else
405  {
406  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
407  }
408 
409  return SCIP_OKAY;
410 }
411 
412 /** computes the minimal and maximal activity for the linear part in a constraint data
413  * only sums up terms that contribute finite values
414  * gives the number of terms that contribute infinite values
415  * only computes those activities where the corresponding side of the constraint is finite
416  */
417 static
419  SCIP* scip, /**< SCIP data structure */
420  SCIP_CONSDATA* consdata /**< constraint data */
421  )
422 { /*lint --e{666}*/
423  SCIP_ROUNDMODE prevroundmode;
424  int i;
425  SCIP_Real bnd;
426 
427  assert(scip != NULL);
428  assert(consdata != NULL);
429 
430  if( consdata->minlinactivity != SCIP_INVALID && consdata->maxlinactivity != SCIP_INVALID ) /*lint !e777*/
431  {
432  /* activities should be uptodate */
433  assert(consdata->minlinactivityinf >= 0);
434  assert(consdata->maxlinactivityinf >= 0);
435  return;
436  }
437 
438  consdata->minlinactivityinf = 0;
439  consdata->maxlinactivityinf = 0;
440 
441  /* if lhs is -infinite, then we do not compute a maximal activity, so we set it to infinity
442  * if rhs is infinite, then we do not compute a minimal activity, so we set it to -infinity
443  */
444  consdata->minlinactivity = SCIPisInfinity(scip, consdata->rhs) ? -INTERVALINFTY : 0.0;
445  consdata->maxlinactivity = SCIPisInfinity(scip, -consdata->lhs) ? INTERVALINFTY : 0.0;
446 
447  if( consdata->nlinvars == 0 )
448  return;
449 
450  /* if the activities computed here should be still uptodate after boundchanges,
451  * variable events need to be catched */
452  assert(consdata->lineventdata != NULL);
453 
454  prevroundmode = SCIPintervalGetRoundingMode();
455 
456  if( !SCIPisInfinity(scip, consdata->rhs) )
457  {
458  /* compute minimal activity only if there is a finite right hand side */
460 
461  for( i = 0; i < consdata->nlinvars; ++i )
462  {
463  assert(SCIPvarGetLbLocal(consdata->linvars[i]) <= SCIPvarGetUbLocal(consdata->linvars[i]));
464  assert(consdata->lineventdata[i] != NULL);
465  if( consdata->lincoefs[i] >= 0.0 )
466  {
467  bnd = SCIPvarGetLbLocal(consdata->linvars[i]);
468  if( SCIPisInfinity(scip, -bnd) )
469  {
470  ++consdata->minlinactivityinf;
471  continue;
472  }
473  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
474  }
475  else
476  {
477  bnd = SCIPvarGetUbLocal(consdata->linvars[i]);
478  if( SCIPisInfinity(scip, bnd) )
479  {
480  ++consdata->minlinactivityinf;
481  continue;
482  }
483  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
484  }
485  consdata->minlinactivity += consdata->lincoefs[i] * bnd;
486  }
487  }
488 
489  if( !SCIPisInfinity(scip, -consdata->lhs) )
490  {
491  /* compute maximal activity only if there is a finite left hand side */
493 
494  for( i = 0; i < consdata->nlinvars; ++i )
495  {
496  assert(consdata->lineventdata[i] != NULL);
497  assert(SCIPvarGetLbLocal(consdata->linvars[i]) <= SCIPvarGetUbLocal(consdata->linvars[i]));
498  if( consdata->lincoefs[i] >= 0.0 )
499  {
500  bnd = SCIPvarGetUbLocal(consdata->linvars[i]);
501  if( SCIPisInfinity(scip, bnd) )
502  {
503  ++consdata->maxlinactivityinf;
504  continue;
505  }
506  assert(!SCIPisInfinity(scip, -bnd)); /* do not like variables that are fixed at -infinity */
507  }
508  else
509  {
510  bnd = SCIPvarGetLbLocal(consdata->linvars[i]);
511  if( SCIPisInfinity(scip, -bnd) )
512  {
513  ++consdata->maxlinactivityinf;
514  continue;
515  }
516  assert(!SCIPisInfinity(scip, bnd)); /* do not like variables that are fixed at +infinity */
517  }
518  consdata->maxlinactivity += consdata->lincoefs[i] * bnd;
519  }
520  }
521  assert(consdata->minlinactivity <= consdata->maxlinactivity || consdata->minlinactivityinf > 0 || consdata->maxlinactivityinf > 0);
522 
523  SCIPintervalSetRoundingMode(prevroundmode);
524 }
525 
526 /** update the linear activities after a change in the lower bound of a variable */
527 static
529  SCIP* scip, /**< SCIP data structure */
530  SCIP_CONSDATA* consdata, /**< constraint data */
531  SCIP_Real coef, /**< coefficient of variable in constraint */
532  SCIP_Real oldbnd, /**< previous lower bound of variable */
533  SCIP_Real newbnd /**< new lower bound of variable */
534  )
535 {
536  SCIP_ROUNDMODE prevroundmode;
537 
538  assert(scip != NULL);
539  assert(consdata != NULL);
540  /* we can't deal with lower bounds at infinity */
541  assert(!SCIPisInfinity(scip, oldbnd));
542  assert(!SCIPisInfinity(scip, newbnd));
543 
544  /* assume lhs <= a*x + y <= rhs, then the following boundchanges can be deduced:
545  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
546  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
547  */
548 
549  if( coef > 0.0 )
550  {
551  /* we should only be called if rhs is finite */
552  assert(!SCIPisInfinity(scip, consdata->rhs));
553 
554  /* we have no min activities computed so far, so cannot update */
555  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777*/
556  return;
557 
558  assert(consdata->minlinactivity > -INTERVALINFTY);
559 
560  prevroundmode = SCIPintervalGetRoundingMode();
562 
563  /* update min activity */
564  if( SCIPisInfinity(scip, -oldbnd) )
565  {
566  --consdata->minlinactivityinf;
567  assert(consdata->minlinactivityinf >= 0);
568  }
569  else
570  {
571  consdata->minlinactivity += SCIPintervalNegateReal(coef) * oldbnd;
572  }
573 
574  if( SCIPisInfinity(scip, -newbnd) )
575  {
576  ++consdata->minlinactivityinf;
577  }
578  else
579  {
580  consdata->minlinactivity += coef * newbnd;
581  }
582 
583  SCIPintervalSetRoundingMode(prevroundmode);
584  }
585  else
586  {
587  /* we should only be called if lhs is finite */
588  assert(!SCIPisInfinity(scip, -consdata->lhs));
589 
590  /* we have no max activities computed so far, so cannot update */
591  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777*/
592  return;
593 
594  assert(consdata->maxlinactivity < INTERVALINFTY);
595 
596  prevroundmode = SCIPintervalGetRoundingMode();
598 
599  /* update max activity */
600  if( SCIPisInfinity(scip, -oldbnd) )
601  {
602  --consdata->maxlinactivityinf;
603  assert(consdata->maxlinactivityinf >= 0);
604  }
605  else
606  {
607  consdata->maxlinactivity += SCIPintervalNegateReal(coef) * oldbnd;
608  }
609 
610  if( SCIPisInfinity(scip, -newbnd) )
611  {
612  ++consdata->maxlinactivityinf;
613  }
614  else
615  {
616  consdata->maxlinactivity += coef * newbnd;
617  }
618 
619  SCIPintervalSetRoundingMode(prevroundmode);
620  }
621 }
622 
623 /** update the linear activities after a change in the upper bound of a variable */
624 static
626  SCIP* scip, /**< SCIP data structure */
627  SCIP_CONSDATA* consdata, /**< constraint data */
628  SCIP_Real coef, /**< coefficient of variable in constraint */
629  SCIP_Real oldbnd, /**< previous lower bound of variable */
630  SCIP_Real newbnd /**< new lower bound of variable */
631  )
632 {
633  SCIP_ROUNDMODE prevroundmode;
634 
635  assert(scip != NULL);
636  assert(consdata != NULL);
637  /* we can't deal with upper bounds at -infinity */
638  assert(!SCIPisInfinity(scip, -oldbnd));
639  assert(!SCIPisInfinity(scip, -newbnd));
640 
641  /* assume lhs <= a*x + y <= rhs, then the following boundchanges can be deduced:
642  * a > 0: y <= rhs - a*lb(x), y >= lhs - a*ub(x)
643  * a < 0: y <= rhs - a*ub(x), y >= lhs - a*lb(x)
644  */
645  if( coef > 0.0 )
646  {
647  /* we should only be called if lhs is finite */
648  assert(!SCIPisInfinity(scip, -consdata->lhs));
649 
650  /* we have no max activities computed so far, so cannot update */
651  if( consdata->maxlinactivity == SCIP_INVALID ) /*lint !e777*/
652  return;
653 
654  assert(consdata->maxlinactivity < INTERVALINFTY);
655 
656  prevroundmode = SCIPintervalGetRoundingMode();
658 
659  /* update max activity */
660  if( SCIPisInfinity(scip, oldbnd) )
661  {
662  --consdata->maxlinactivityinf;
663  assert(consdata->maxlinactivityinf >= 0);
664  }
665  else
666  {
667  consdata->maxlinactivity += SCIPintervalNegateReal(coef) * oldbnd;
668  }
669 
670  if( SCIPisInfinity(scip, newbnd) )
671  {
672  ++consdata->maxlinactivityinf;
673  }
674  else
675  {
676  consdata->maxlinactivity += coef * newbnd;
677  }
678 
679  SCIPintervalSetRoundingMode(prevroundmode);
680  }
681  else
682  {
683  /* we should only be called if rhs is finite */
684  assert(!SCIPisInfinity(scip, consdata->rhs));
685 
686  /* we have no min activities computed so far, so cannot update */
687  if( consdata->minlinactivity == SCIP_INVALID ) /*lint !e777*/
688  return;
689 
690  assert(consdata->minlinactivity > -INTERVALINFTY);
691 
692  prevroundmode = SCIPintervalGetRoundingMode();
694 
695  /* update min activity */
696  if( SCIPisInfinity(scip, oldbnd) )
697  {
698  --consdata->minlinactivityinf;
699  assert(consdata->minlinactivityinf >= 0);
700  }
701  else
702  {
703  consdata->minlinactivity += SCIPintervalNegateReal(coef) * oldbnd;
704  }
705 
706  if( SCIPisInfinity(scip, newbnd) )
707  {
708  ++consdata->minlinactivityinf;
709  }
710  else
711  {
712  consdata->minlinactivity += coef * newbnd;
713  }
714 
715  SCIPintervalSetRoundingMode(prevroundmode);
716  }
717 }
718 
719 /** processes variable fixing or bound change event */
720 static
721 SCIP_DECL_EVENTEXEC(processLinearVarEvent)
722 {
723  SCIP_CONS* cons;
724  SCIP_CONSDATA* consdata;
725  SCIP_EVENTTYPE eventtype;
726  int varidx;
727 
728  assert(scip != NULL);
729  assert(event != NULL);
730  assert(eventdata != NULL);
731  assert(eventhdlr != NULL);
732 
733  cons = ((LINVAREVENTDATA*)eventdata)->cons;
734  assert(cons != NULL);
735 
736  consdata = SCIPconsGetData(cons);
737  assert(consdata != NULL);
738 
739  varidx = ((LINVAREVENTDATA*)eventdata)->varidx;
740  assert(varidx >= 0);
741  assert(varidx < consdata->nlinvars);
742 
743  eventtype = SCIPeventGetType(event);
744 
745  if( eventtype & SCIP_EVENTTYPE_VARFIXED )
746  {
747  consdata->isremovedfixingslin = FALSE;
748  }
749 
750  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
751  {
752  /* update activity bounds for linear terms */
753  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
754  consdataUpdateLinearActivityLbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
755  else
756  consdataUpdateLinearActivityUbChange(scip, consdata, consdata->lincoefs[varidx], SCIPeventGetOldbound(event), SCIPeventGetNewbound(event));
757 
758  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
759  {
760  assert(((LINVAREVENTDATA*)eventdata)->conshdlrdata != NULL);
761  ((LINVAREVENTDATA*)eventdata)->conshdlrdata->ispropagated = FALSE;
762 
763  /* mark constraint for propagation */
764  SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
765  }
766  }
767 
768  return SCIP_OKAY;
769 }
770 
771 /** processes bound change events for variables in expression graph */
772 static
773 SCIP_DECL_EVENTEXEC(processNonlinearVarEvent)
774 {
776  SCIP_EVENTTYPE eventtype;
777 
778  assert(scip != NULL);
779  assert(event != NULL);
780  assert(eventdata != NULL);
781  assert(eventhdlr != NULL);
782 
783  conshdlrdata = (SCIP_CONSHDLRDATA*)SCIPeventhdlrGetData(eventhdlr);
784  assert(conshdlrdata != NULL);
785  assert(conshdlrdata->exprgraph != NULL);
786 
787  eventtype = SCIPeventGetType(event);
788  assert( eventtype & (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED) );
789 
790  if( eventtype & SCIP_EVENTTYPE_BOUNDCHANGED )
791  {
792  SCIP_Real newbd;
793 
794  SCIPdebugMsg(scip, "changed %s bound on expression graph variable <%s> from %g to %g\n",
795  (eventtype & SCIP_EVENTTYPE_LBCHANGED) ? "lower" : "upper",
797 
798  if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
799  conshdlrdata->ispropagated = FALSE;
800  /* @todo a global bound tightening may yield in convex/concave curvatures, maybe the iscurvcheck flag should be reset? */
801 
802  /* update variable bound in expression graph, with epsilon added */
803  if( eventtype & SCIP_EVENTTYPE_LBCHANGED )
804  {
805  newbd = -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -SCIPeventGetNewbound(event)); /*lint !e666*/
806  /* if newbd in [0,eps], then relax to 0.0, otherwise relax by -epsilon
807  * this is to ensure that an original positive variable does not get negative by this, which may have an adverse effect on convexity recoginition, for example */
808  if( newbd >= 0.0 && newbd <= SCIPepsilon(scip) )
809  newbd = 0.0;
810  else
811  newbd -= SCIPepsilon(scip);
812  SCIPexprgraphSetVarNodeLb(conshdlrdata->exprgraph, (SCIP_EXPRGRAPHNODE*)eventdata, newbd);
813  }
814  else
815  {
816  newbd = +infty2infty(SCIPinfinity(scip), INTERVALINFTY, SCIPeventGetNewbound(event)); /*lint !e666*/
817  /* if newbd in [-eps,0], then relax to 0.0, otherwise relax by +epsilon */
818  if( newbd >= -SCIPepsilon(scip) && newbd <= 0.0 )
819  newbd = 0.0;
820  else
821  newbd += SCIPepsilon(scip);
822  SCIPexprgraphSetVarNodeUb(conshdlrdata->exprgraph, (SCIP_EXPRGRAPHNODE*)eventdata, newbd);
823  }
824  }
825  else
826  {
827  assert(eventtype & SCIP_EVENTTYPE_VARFIXED);
828  conshdlrdata->isremovedfixings = FALSE;
829  }
830 
831  return SCIP_OKAY;
832 }
833 
834 /** callback method for variable addition in expression graph */
835 static
836 SCIP_DECL_EXPRGRAPHVARADDED( exprgraphVarAdded )
837 {
839  SCIP_INTERVAL varbounds;
840  SCIP_VAR* var_;
841 
842  assert(exprgraph != NULL);
843  assert(var != NULL);
844  assert(varnode != NULL);
845 
846  var_ = (SCIP_VAR*)var;
847 
848  conshdlrdata = (SCIP_CONSHDLRDATA*)userdata;
849  assert(conshdlrdata != NULL);
850  assert(conshdlrdata->exprgraph == exprgraph);
851 
852  /* catch variable bound change events */
853  SCIP_CALL( SCIPcatchVarEvent(conshdlrdata->scip, (SCIP_VAR*)var, SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED, conshdlrdata->nonlinvareventhdlr, (SCIP_EVENTDATA*)varnode, NULL) );
854  SCIPdebugMessage("catch boundchange events on new expression graph variable <%s>\n", SCIPvarGetName(var_));
855 
856  /* set current bounds in expression graph */
857  SCIPintervalSetBounds(&varbounds,
858  -infty2infty(SCIPinfinity(conshdlrdata->scip), INTERVALINFTY, -MIN(SCIPvarGetLbLocal(var_), SCIPvarGetUbLocal(var_))), /*lint !e666*/
859  +infty2infty(SCIPinfinity(conshdlrdata->scip), INTERVALINFTY, MAX(SCIPvarGetLbLocal(var_), SCIPvarGetUbLocal(var_))) /*lint !e666*/
860  );
861  SCIPexprgraphSetVarNodeBounds(exprgraph, varnode, varbounds);
862 
863  SCIP_CALL( SCIPaddVarLocksType(conshdlrdata->scip, var_, SCIP_LOCKTYPE_MODEL, 1, 1) );
864  SCIPdebugMessage("increased up- and downlocks of variable <%s>\n", SCIPvarGetName(var_));
865 
866  SCIP_CALL( SCIPcaptureVar(conshdlrdata->scip, var_) );
867  SCIPdebugMessage("capture variable <%s>\n", SCIPvarGetName(var_));
868 
869  conshdlrdata->isremovedfixings &= SCIPvarIsActive(var_);
870  conshdlrdata->ispropagated = FALSE;
871 
872  return SCIP_OKAY;
873 }
874 
875 /** callback method for variable removal in expression graph */
876 static
877 SCIP_DECL_EXPRGRAPHVARREMOVE( exprgraphVarRemove )
878 {
880  SCIP_VAR* var_;
881 
882  assert(exprgraph != NULL);
883  assert(var != NULL);
884  assert(varnode != NULL);
885 
886  var_ = (SCIP_VAR*)var;
887 
888  conshdlrdata = (SCIP_CONSHDLRDATA*)userdata;
889  assert(conshdlrdata != NULL);
890  assert(conshdlrdata->exprgraph == exprgraph);
891 
892  SCIP_CALL( SCIPdropVarEvent(conshdlrdata->scip, var_, SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED, conshdlrdata->nonlinvareventhdlr, (SCIP_EVENTDATA*)varnode, -1) );
893  SCIPdebugMessage("drop boundchange events on expression graph variable <%s>\n", SCIPvarGetName(var_));
894 
895  SCIP_CALL( SCIPaddVarLocksType(conshdlrdata->scip, var_, SCIP_LOCKTYPE_MODEL, -1, -1) );
896  SCIPdebugMessage("decreased up- and downlocks of variable <%s>\n", SCIPvarGetName(var_));
897 
898  SCIPdebugMessage("release variable <%s>\n", SCIPvarGetName(var_));
899  SCIP_CALL( SCIPreleaseVar(conshdlrdata->scip, &var_) );
900 
901  return SCIP_OKAY;
902 }
903 
904 /* adds expression trees to constraint */
905 static
907  SCIP* scip, /**< SCIP data structure */
908  SCIP_CONSDATA* consdata, /**< nonlinear constraint data */
909  int nexprtrees, /**< number of expression trees */
910  SCIP_EXPRTREE** exprtrees, /**< expression trees */
911  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
912  SCIP_Bool copytrees /**< whether trees should be copied or ownership should be assumed */
913  )
914 {
915  int i;
916 
917  assert(scip != NULL);
918  assert(consdata != NULL);
919  assert(consdata->exprtrees != NULL || consdata->nexprtrees == 0);
920 
921  if( nexprtrees == 0 )
922  return SCIP_OKAY;
923 
924  /* invalidate activity information */
925  consdata->activity = SCIP_INVALID;
926 
927  /* invalidate nonlinear row */
928  if( consdata->nlrow != NULL )
929  {
930  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
931  }
932 
933  consdata->ispresolved = FALSE;
934  consdata->curvature = SCIP_EXPRCURV_UNKNOWN;
935  consdata->iscurvchecked = FALSE;
936 
937  if( consdata->nexprtrees == 0 )
938  {
939  assert(consdata->exprtrees == NULL);
940  assert(consdata->nonlincoefs == NULL);
941  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->exprtrees, nexprtrees) );
942  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->nonlincoefs, nexprtrees) );
943  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->curvatures, nexprtrees) );
944  }
945  else
946  {
947  assert(consdata->exprtrees != NULL);
948  assert(consdata->nonlincoefs != NULL);
949  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->exprtrees, consdata->nexprtrees, consdata->nexprtrees + nexprtrees) );
950  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->nonlincoefs, consdata->nexprtrees, consdata->nexprtrees + nexprtrees) );
951  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->curvatures, consdata->nexprtrees, consdata->nexprtrees + nexprtrees) );
952  }
953 
954  for( i = 0; i < nexprtrees; ++i )
955  {
956  assert(exprtrees[i] != NULL);
957  /* the expression tree need to have SCIP_VAR*'s stored */
958  assert(SCIPexprtreeGetNVars(exprtrees[i]) == 0 || SCIPexprtreeGetVars(exprtrees[i]) != NULL);
959 
960  if( copytrees )
961  {
962  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &consdata->exprtrees[consdata->nexprtrees + i], exprtrees[i]) );
963  }
964  else
965  {
966  consdata->exprtrees[consdata->nexprtrees + i] = exprtrees[i];
967  }
968 
969  consdata->nonlincoefs[consdata->nexprtrees + i] = (coefs != NULL ? coefs[i] : 1.0);
970  consdata->curvatures[consdata->nexprtrees + i] = SCIP_EXPRCURV_UNKNOWN;
971  }
972  consdata->nexprtrees += nexprtrees;
973 
974  return SCIP_OKAY;
975 }
976 
977 /* sets expression trees of constraints, clears previously ones */
978 static
980  SCIP* scip, /**< SCIP data structure */
981  SCIP_CONSDATA* consdata, /**< nonlinear constraint data */
982  int nexprtrees, /**< number of expression trees */
983  SCIP_EXPRTREE** exprtrees, /**< expression trees */
984  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
985  SCIP_Bool copytrees /**< whether trees should be copied or ownership should be assumed */
986  )
987 {
988  int i;
989 
990  assert(scip != NULL);
991  assert(consdata != NULL);
992  assert(consdata->exprtrees != NULL || consdata->nexprtrees == 0);
993 
994  /* clear existing expression trees */
995  if( consdata->nexprtrees > 0 )
996  {
997  for( i = 0; i < consdata->nexprtrees; ++i )
998  {
999  assert(consdata->exprtrees[i] != NULL);
1000  SCIP_CALL( SCIPexprtreeFree(&consdata->exprtrees[i]) );
1001  }
1002 
1003  /* invalidate activity information */
1004  consdata->activity = SCIP_INVALID;
1005 
1006  /* invalidate nonlinear row */
1007  if( consdata->nlrow != NULL )
1008  {
1009  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1010  }
1011 
1012  consdata->ispresolved = FALSE;
1013  consdata->curvature = SCIP_EXPRCURV_LINEAR;
1014  consdata->iscurvchecked = TRUE;
1015 
1016  SCIPfreeBlockMemoryArray(scip, &consdata->exprtrees, consdata->nexprtrees);
1017  SCIPfreeBlockMemoryArray(scip, &consdata->nonlincoefs, consdata->nexprtrees);
1018  SCIPfreeBlockMemoryArray(scip, &consdata->curvatures, consdata->nexprtrees);
1019  consdata->nexprtrees = 0;
1020  }
1021 
1022  SCIP_CALL( consdataAddExprtrees(scip, consdata, nexprtrees, exprtrees, coefs, copytrees) );
1023 
1024  return SCIP_OKAY;
1025 }
1026 
1027 /** ensures, that linear vars and coefs arrays can store at least num entries */
1028 static
1030  SCIP* scip, /**< SCIP data structure */
1031  SCIP_CONSDATA* consdata, /**< nonlinear constraint data */
1032  int num /**< minimum number of entries to store */
1033  )
1034 {
1035  assert(scip != NULL);
1036  assert(consdata != NULL);
1037  assert(consdata->nlinvars <= consdata->linvarssize);
1038 
1039  if( num > consdata->linvarssize )
1040  {
1041  int newsize;
1042 
1043  newsize = SCIPcalcMemGrowSize(scip, num);
1044  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->linvars, consdata->linvarssize, newsize) );
1045  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lincoefs, consdata->linvarssize, newsize) );
1046  if( consdata->lineventdata != NULL )
1047  {
1048  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->lineventdata, consdata->linvarssize, newsize) );
1049  }
1050  consdata->linvarssize = newsize;
1051  }
1052  assert(num <= consdata->linvarssize);
1053 
1054  return SCIP_OKAY;
1055 }
1056 
1057 /** creates constraint data structure */
1058 static
1060  SCIP* scip, /**< SCIP data structure */
1061  SCIP_CONSDATA** consdata, /**< a buffer to store pointer to new constraint data */
1062  SCIP_Real lhs, /**< left hand side of constraint */
1063  SCIP_Real rhs, /**< right hand side of constraint */
1064  int nlinvars, /**< number of linear variables */
1065  SCIP_VAR** linvars, /**< array of linear variables */
1066  SCIP_Real* lincoefs, /**< array of coefficients of linear variables */
1067  int nexprtrees, /**< number of expression trees */
1068  SCIP_EXPRTREE** exprtrees, /**< expression trees */
1069  SCIP_Real* nonlincoefs, /**< coefficients of expression trees */
1070  SCIP_Bool capturevars /**< whether we should capture variables */
1071  )
1072 {
1073  int i;
1074 
1075  assert(scip != NULL);
1076  assert(consdata != NULL);
1077 
1078  assert(nlinvars == 0 || linvars != NULL);
1079  assert(nlinvars == 0 || lincoefs != NULL);
1080  assert(nexprtrees == 0 || exprtrees != NULL);
1081  assert(nexprtrees == 0 || nonlincoefs != NULL);
1082 
1083  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1084  BMSclearMemory(*consdata);
1085 
1086  (*consdata)->minlinactivity = SCIP_INVALID;
1087  (*consdata)->maxlinactivity = SCIP_INVALID;
1088  (*consdata)->minlinactivityinf = -1;
1089  (*consdata)->maxlinactivityinf = -1;
1090 
1091  (*consdata)->lhs = lhs;
1092  (*consdata)->rhs = rhs;
1093 
1094  if( nlinvars > 0 )
1095  {
1096  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->linvars, linvars, nlinvars) );
1097  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->lincoefs, lincoefs, nlinvars) );
1098  (*consdata)->nlinvars = nlinvars;
1099  (*consdata)->linvarssize = nlinvars;
1100 
1101  if( capturevars )
1102  for( i = 0; i < nlinvars; ++i )
1103  {
1104  SCIP_CALL( SCIPcaptureVar(scip, linvars[i]) );
1105  }
1106  }
1107  else
1108  {
1109  (*consdata)->linvarssorted = TRUE;
1110  (*consdata)->linvarsmerged = TRUE;
1111  }
1112 
1113  SCIP_CALL( consdataSetExprtrees(scip, *consdata, nexprtrees, exprtrees, nonlincoefs, TRUE) );
1114 
1115  (*consdata)->linvar_maydecrease = -1;
1116  (*consdata)->linvar_mayincrease = -1;
1117 
1118  (*consdata)->activity = SCIP_INVALID;
1119  (*consdata)->lhsviol = SCIPisInfinity(scip, -lhs) ? 0.0 : SCIP_INVALID;
1120  (*consdata)->rhsviol = SCIPisInfinity(scip, rhs) ? 0.0 : SCIP_INVALID;
1121 
1122  return SCIP_OKAY;
1123 }
1124 
1125 /** creates empty constraint data structure */
1126 static
1128  SCIP* scip, /**< SCIP data structure */
1129  SCIP_CONSDATA** consdata /**< a buffer to store pointer to new constraint data */
1130  )
1131 {
1132  assert(scip != NULL);
1133  assert(consdata != NULL);
1134 
1135  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1136  BMSclearMemory(*consdata);
1137 
1138  (*consdata)->lhs = -SCIPinfinity(scip);
1139  (*consdata)->rhs = SCIPinfinity(scip);
1140 
1141  (*consdata)->linvarssorted = TRUE;
1142  (*consdata)->linvarsmerged = TRUE;
1143 
1144  (*consdata)->isremovedfixingslin = TRUE;
1145 
1146  (*consdata)->linvar_maydecrease = -1;
1147  (*consdata)->linvar_mayincrease = -1;
1148 
1149  (*consdata)->minlinactivity = SCIP_INVALID;
1150  (*consdata)->maxlinactivity = SCIP_INVALID;
1151  (*consdata)->minlinactivityinf = -1;
1152  (*consdata)->maxlinactivityinf = -1;
1153 
1154  (*consdata)->curvature = SCIP_EXPRCURV_LINEAR;
1155  (*consdata)->iscurvchecked = TRUE;
1156 
1157  (*consdata)->ncuts = 0;
1158 
1159  return SCIP_OKAY;
1160 }
1161 
1162 /** frees constraint data structure */
1163 static
1165  SCIP* scip, /**< SCIP data structure */
1166  SCIP_CONSDATA** consdata /**< pointer to constraint data to free */
1167  )
1168 {
1169  int i;
1170 
1171  assert(scip != NULL);
1172  assert(consdata != NULL);
1173  assert(*consdata != NULL);
1174 
1175  /* release linear variables and free linear part */
1176  if( (*consdata)->linvarssize > 0 )
1177  {
1178  for( i = 0; i < (*consdata)->nlinvars; ++i )
1179  {
1180  assert((*consdata)->lineventdata == NULL || (*consdata)->lineventdata[i] == NULL); /* variable events should have been dropped earlier */
1181  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->linvars[i]) );
1182  }
1183  SCIPfreeBlockMemoryArray(scip, &(*consdata)->linvars, (*consdata)->linvarssize);
1184  SCIPfreeBlockMemoryArray(scip, &(*consdata)->lincoefs, (*consdata)->linvarssize);
1185  SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->lineventdata, (*consdata)->linvarssize);
1186  }
1187  assert((*consdata)->linvars == NULL);
1188  assert((*consdata)->lincoefs == NULL);
1189  assert((*consdata)->lineventdata == NULL);
1190 
1191  if( (*consdata)->nexprtrees > 0 )
1192  {
1193  assert((*consdata)->exprtrees != NULL);
1194  assert((*consdata)->nonlincoefs != NULL);
1195  assert((*consdata)->curvatures != NULL);
1196  for( i = 0; i < (*consdata)->nexprtrees; ++i )
1197  {
1198  assert((*consdata)->exprtrees[i] != NULL);
1199  SCIP_CALL( SCIPexprtreeFree(&(*consdata)->exprtrees[i]) );
1200  assert((*consdata)->exprtrees[i] == NULL);
1201  }
1202  SCIPfreeBlockMemoryArray(scip, &(*consdata)->exprtrees, (*consdata)->nexprtrees);
1203  SCIPfreeBlockMemoryArray(scip, &(*consdata)->nonlincoefs, (*consdata)->nexprtrees);
1204  SCIPfreeBlockMemoryArray(scip, &(*consdata)->curvatures, (*consdata)->nexprtrees);
1205  }
1206  assert((*consdata)->exprtrees == NULL);
1207  assert((*consdata)->nonlincoefs == NULL);
1208  assert((*consdata)->curvatures == NULL);
1209 
1210  /* free nonlinear row representation */
1211  if( (*consdata)->nlrow != NULL )
1212  {
1213  SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
1214  }
1215 
1216  SCIPfreeBlockMemory(scip, consdata);
1217  *consdata = NULL;
1218 
1219  return SCIP_OKAY;
1220 }
1221 
1222 /** sorts linear part of constraint data */
1223 static
1225  SCIP_CONSDATA* consdata /**< nonlinear constraint data */
1226  )
1227 {
1228  assert(consdata != NULL);
1229 
1230  if( consdata->linvarssorted )
1231  return;
1232 
1233  if( consdata->nlinvars <= 1 )
1234  {
1235  consdata->linvarssorted = TRUE;
1236  return;
1237  }
1238 
1239  if( consdata->lineventdata == NULL )
1240  {
1241  SCIPsortPtrReal((void**)consdata->linvars, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1242  }
1243  else
1244  {
1245  int i;
1246 
1247  SCIPsortPtrPtrReal((void**)consdata->linvars, (void**)consdata->lineventdata, consdata->lincoefs, SCIPvarComp, consdata->nlinvars);
1248 
1249  /* update variable indices in event data */
1250  for( i = 0; i < consdata->nlinvars; ++i )
1251  if( consdata->lineventdata[i] != NULL )
1252  consdata->lineventdata[i]->varidx = i;
1253  }
1254 
1255  consdata->linvarssorted = TRUE;
1256 }
1257 
1258 /* this function is currently not needed, but also to nice to be deleted, so it is only deactivated */
1259 #ifdef SCIP_DISABLED_CODE
1260 /** returns the position of variable in the linear coefficients array of a constraint, or -1 if not found */
1261 static
1262 int consdataFindLinearVar(
1263  SCIP_CONSDATA* consdata, /**< nonlinear constraint data */
1264  SCIP_VAR* var /**< variable to search for */
1265  )
1266 {
1267  int pos;
1268 
1269  assert(consdata != NULL);
1270  assert(var != NULL);
1271 
1272  if( consdata->nlinvars == 0 )
1273  return -1;
1274 
1275  consdataSortLinearVars(consdata);
1276 
1277  if( !SCIPsortedvecFindPtr((void**)consdata->linvars, SCIPvarComp, (void*)var, consdata->nlinvars, &pos) )
1278  pos = -1;
1279 
1280  return pos;
1281 }
1282 #endif
1283 
1284 /** moves a linear variable from one position to another */
1285 static
1287  SCIP_CONSDATA* consdata, /**< constraint data */
1288  int oldpos, /**< position of variable that shall be moved */
1289  int newpos /**< new position of variable */
1290  )
1291 {
1292  assert(consdata != NULL);
1293  assert(oldpos >= 0);
1294  assert(oldpos < consdata->nlinvars);
1295  assert(newpos >= 0);
1296  assert(newpos < consdata->linvarssize);
1297 
1298  if( newpos == oldpos )
1299  return;
1300 
1301  consdata->linvars [newpos] = consdata->linvars [oldpos];
1302  consdata->lincoefs[newpos] = consdata->lincoefs[oldpos];
1303 
1304  if( consdata->lineventdata != NULL )
1305  {
1306  assert(newpos >= consdata->nlinvars || consdata->lineventdata[newpos] == NULL);
1307 
1308  consdata->lineventdata[newpos] = consdata->lineventdata[oldpos];
1309  consdata->lineventdata[newpos]->varidx = newpos;
1310 
1311  consdata->lineventdata[oldpos] = NULL;
1312  }
1313 
1314  consdata->linvarssorted = FALSE;
1315 }
1316 
1317 /** adds linear coefficient in nonlinear constraint */
1318 static
1320  SCIP* scip, /**< SCIP data structure */
1321  SCIP_CONS* cons, /**< nonlinear constraint */
1322  SCIP_VAR* var, /**< variable of constraint entry */
1323  SCIP_Real coef /**< coefficient of constraint entry */
1324  )
1325 {
1326  SCIP_CONSDATA* consdata;
1327  SCIP_Bool transformed;
1328 
1329  assert(scip != NULL);
1330  assert(cons != NULL);
1331  assert(var != NULL);
1332 
1333  /* ignore coefficient if it is nearly zero */
1334  if( SCIPisZero(scip, coef) )
1335  return SCIP_OKAY;
1336 
1337  consdata = SCIPconsGetData(cons);
1338  assert(consdata != NULL);
1339 
1340  /* are we in the transformed problem? */
1341  transformed = SCIPconsIsTransformed(cons);
1342 
1343  /* always use transformed variables in transformed constraints */
1344  if( transformed )
1345  {
1346  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1347  }
1348  assert(var != NULL);
1349  assert(transformed == SCIPvarIsTransformed(var));
1350 
1351  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars+1) );
1352  consdata->linvars [consdata->nlinvars] = var;
1353  consdata->lincoefs[consdata->nlinvars] = coef;
1354 
1355  ++consdata->nlinvars;
1356 
1357  /* catch variable events */
1358  if( SCIPconsIsEnabled(cons) )
1359  {
1360  /* catch bound change events of variable */
1361  SCIP_CALL( catchLinearVarEvents(scip, cons, consdata->nlinvars-1) );
1362  }
1363 
1364  /* invalidate activity information */
1365  consdata->activity = SCIP_INVALID;
1366  consdata->minlinactivity = SCIP_INVALID;
1367  consdata->maxlinactivity = SCIP_INVALID;
1368  consdata->minlinactivityinf = -1;
1369  consdata->maxlinactivityinf = -1;
1370 
1371  /* invalidate nonlinear row */
1372  if( consdata->nlrow != NULL )
1373  {
1374  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1375  }
1376 
1377  /* install rounding locks for new variable */
1378  SCIP_CALL( lockLinearVariable(scip, cons, var, coef) );
1379 
1380  /* capture new variable */
1381  SCIP_CALL( SCIPcaptureVar(scip, var) );
1382 
1383  consdata->ispresolved = FALSE;
1384  consdata->isremovedfixingslin = consdata->isremovedfixingslin && SCIPvarIsActive(var);
1385  if( consdata->nlinvars == 1 )
1386  consdata->linvarssorted = TRUE;
1387  else
1388  consdata->linvarssorted = consdata->linvarssorted &&
1389  (SCIPvarCompare(consdata->linvars[consdata->nlinvars-2], consdata->linvars[consdata->nlinvars-1]) == -1);
1390  /* always set too FALSE since the new linear variable should be checked if already existing as quad var term */
1391  consdata->linvarsmerged = FALSE;
1392 
1393  return SCIP_OKAY;
1394 }
1395 
1396 /** deletes linear coefficient at given position from nonlinear constraint data */
1397 static
1399  SCIP* scip, /**< SCIP data structure */
1400  SCIP_CONS* cons, /**< nonlinear constraint */
1401  int pos /**< position of coefficient to delete */
1402  )
1403 {
1404  SCIP_CONSDATA* consdata;
1405  SCIP_VAR* var;
1406  SCIP_Real coef;
1407 
1408  assert(scip != NULL);
1409  assert(cons != NULL);
1410 
1411  consdata = SCIPconsGetData(cons);
1412  assert(consdata != NULL);
1413  assert(0 <= pos && pos < consdata->nlinvars);
1414 
1415  var = consdata->linvars[pos];
1416  coef = consdata->lincoefs[pos];
1417  assert(var != NULL);
1418 
1419  /* remove rounding locks for deleted variable */
1420  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1421 
1422  /* if constraint is enabled, drop the events on the variable */
1423  if( SCIPconsIsEnabled(cons) )
1424  {
1425  /* drop bound change events of variable */
1426  SCIP_CALL( dropLinearVarEvents(scip, cons, pos) );
1427  }
1428 
1429  /* release variable */
1430  SCIP_CALL( SCIPreleaseVar(scip, &consdata->linvars[pos]) );
1431 
1432  /* move the last variable to the free slot */
1433  consdataMoveLinearVar(consdata, consdata->nlinvars-1, pos);
1434 
1435  --consdata->nlinvars;
1436 
1437  /* invalidate activity */
1438  consdata->activity = SCIP_INVALID;
1439  consdata->minlinactivity = SCIP_INVALID;
1440  consdata->maxlinactivity = SCIP_INVALID;
1441  consdata->minlinactivityinf = -1;
1442  consdata->maxlinactivityinf = -1;
1443 
1444  /* invalidate nonlinear row */
1445  if( consdata->nlrow != NULL )
1446  {
1447  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1448  }
1449 
1450  consdata->ispresolved = FALSE;
1451 
1452  return SCIP_OKAY;
1453 }
1454 
1455 /** changes linear coefficient value at given position of nonlinear constraint */
1456 static
1458  SCIP* scip, /**< SCIP data structure */
1459  SCIP_CONS* cons, /**< nonlinear constraint */
1460  int pos, /**< position of linear coefficient to change */
1461  SCIP_Real newcoef /**< new value of linear coefficient */
1462  )
1463 {
1464  SCIP_CONSDATA* consdata;
1465  SCIP_VAR* var;
1466  SCIP_Real coef;
1467  SCIP_Bool locked;
1468  int i;
1469 
1470  assert(scip != NULL);
1471  assert(cons != NULL);
1472  assert(!SCIPisZero(scip, newcoef));
1473 
1474  consdata = SCIPconsGetData(cons);
1475  assert(consdata != NULL);
1476  assert(0 <= pos);
1477  assert(pos < consdata->nlinvars);
1478  assert(!SCIPisZero(scip, newcoef));
1479 
1480  var = consdata->linvars[pos];
1481  coef = consdata->lincoefs[pos];
1482  assert(var != NULL);
1483  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
1484 
1485  /* invalidate activity */
1486  consdata->activity = SCIP_INVALID;
1487  consdata->minlinactivity = SCIP_INVALID;
1488  consdata->maxlinactivity = SCIP_INVALID;
1489  consdata->minlinactivityinf = -1;
1490  consdata->maxlinactivityinf = -1;
1491 
1492  /* invalidate nonlinear row */
1493  if( consdata->nlrow != NULL )
1494  {
1495  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1496  }
1497 
1498  locked = FALSE;
1499  for( i = 0; i < NLOCKTYPES && !locked; i++ )
1500  locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) i);
1501 
1502  /* if necessary, remove the rounding locks and event catching of the variable */
1503  if( newcoef * coef < 0.0 )
1504  {
1505  if( locked )
1506  {
1507  assert(SCIPconsIsTransformed(cons));
1508 
1509  /* remove rounding locks for variable with old coefficient */
1510  SCIP_CALL( unlockLinearVariable(scip, cons, var, coef) );
1511  }
1512 
1513  if( SCIPconsIsEnabled(cons) )
1514  {
1515  /* drop bound change events of variable */
1516  SCIP_CALL( dropLinearVarEvents(scip, cons, pos) );
1517  }
1518  }
1519 
1520  /* change the coefficient */
1521  consdata->lincoefs[pos] = newcoef;
1522 
1523  /* if necessary, install the rounding locks and event catching of the variable again */
1524  if( newcoef * coef < 0.0 )
1525  {
1526  if( locked )
1527  {
1528  /* install rounding locks for variable with new coefficient */
1529  SCIP_CALL( lockLinearVariable(scip, cons, var, newcoef) );
1530  }
1531 
1532  if( SCIPconsIsEnabled(cons) )
1533  {
1534  /* catch bound change events of variable */
1535  SCIP_CALL( catchLinearVarEvents(scip, cons, pos) );
1536  }
1537  }
1538 
1539  consdata->ispresolved = FALSE;
1540 
1541  return SCIP_OKAY;
1542 }
1543 
1544 
1545 /* merges entries with same linear variable into one entry and cleans up entries with coefficient 0.0 */
1546 static
1548  SCIP* scip, /**< SCIP data structure */
1549  SCIP_CONS* cons /**< nonlinear constraint */
1550  )
1551 {
1552  SCIP_CONSDATA* consdata;
1553  SCIP_Real newcoef;
1554  int i;
1555  int j;
1556 
1557  assert(scip != NULL);
1558  assert(cons != NULL);
1559 
1560  consdata = SCIPconsGetData(cons);
1561 
1562  if( consdata->linvarsmerged )
1563  return SCIP_OKAY;
1564 
1565  if( consdata->nlinvars == 0 )
1566  {
1567  consdata->linvarsmerged = TRUE;
1568  return SCIP_OKAY;
1569  }
1570 
1571  i = 0;
1572  while( i < consdata->nlinvars )
1573  {
1574  /* make sure linear variables are sorted (do this in every round, since we may move variables around) */
1575  consdataSortLinearVars(consdata);
1576 
1577  /* sum up coefficients that correspond to variable i */
1578  newcoef = consdata->lincoefs[i];
1579  for( j = i+1; j < consdata->nlinvars && consdata->linvars[i] == consdata->linvars[j]; ++j )
1580  newcoef += consdata->lincoefs[j];
1581  /* delete the additional variables in backward order */
1582  for( j = j-1; j > i; --j )
1583  {
1584  SCIP_CALL( delLinearCoefPos(scip, cons, j) );
1585  }
1586 
1587  /* delete also entry at position i, if it became zero (or was zero before) */
1588  if( SCIPisZero(scip, newcoef) )
1589  {
1590  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
1591  }
1592  else
1593  {
1594  SCIP_CALL( chgLinearCoefPos(scip, cons, i, newcoef) );
1595  ++i;
1596  }
1597  }
1598 
1599  consdata->linvarsmerged = TRUE;
1600 
1601  return SCIP_OKAY;
1602 }
1603 
1604 /** removes fixes (or aggregated) linear variables from a nonlinear constraint */
1605 static
1607  SCIP* scip, /**< SCIP data structure */
1608  SCIP_CONS* cons /**< nonlinearconstraint */
1609  )
1610 {
1611  SCIP_CONSDATA* consdata;
1612  SCIP_Real coef;
1613  SCIP_Real offset;
1614  SCIP_VAR* var;
1615  int i;
1616  int j;
1617 
1618  assert(scip != NULL);
1619  assert(cons != NULL);
1620 
1621  consdata = SCIPconsGetData(cons);
1622 
1623  if( !consdata->isremovedfixingslin )
1624  {
1625  i = 0;
1626  while( i < consdata->nlinvars )
1627  {
1628  var = consdata->linvars[i];
1629 
1630  if( SCIPvarIsActive(var) )
1631  {
1632  ++i;
1633  continue;
1634  }
1635 
1636  coef = consdata->lincoefs[i];
1637  offset = 0.0;
1638 
1639  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &coef, &offset) );
1640 
1641  SCIPdebugMsg(scip, " linear term %g*<%s> is replaced by %g * <%s> + %g\n", consdata->lincoefs[i], SCIPvarGetName(consdata->linvars[i]), coef, SCIPvarGetName(var), offset);
1642 
1643  /* delete previous variable (this will move another variable to position i) */
1644  SCIP_CALL( delLinearCoefPos(scip, cons, i) );
1645 
1646  /* put constant part into bounds */
1647  if( offset != 0.0 )
1648  {
1649  if( !SCIPisInfinity(scip, -consdata->lhs) )
1650  {
1651  consdata->lhs -= offset;
1652  assert(!SCIPisInfinity(scip, REALABS(consdata->lhs)));
1653  }
1654  if( !SCIPisInfinity(scip, consdata->rhs) )
1655  {
1656  consdata->rhs -= offset;
1657  assert(!SCIPisInfinity(scip, REALABS(consdata->rhs)));
1658  }
1659  }
1660 
1661  /* nothing left to do if variable had been fixed */
1662  if( coef == 0.0 )
1663  continue;
1664 
1665  /* if GetProbvar gave a linear variable, just add it
1666  * if it's a multilinear variable, add it's disaggregated variables */
1667  if( SCIPvarIsActive(var) )
1668  {
1669  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
1670  }
1671  else
1672  {
1673  int naggrs;
1674  SCIP_VAR** aggrvars;
1675  SCIP_Real* aggrscalars;
1676  SCIP_Real aggrconstant;
1677 
1678  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
1679 
1680  naggrs = SCIPvarGetMultaggrNVars(var);
1681  aggrvars = SCIPvarGetMultaggrVars(var);
1682  aggrscalars = SCIPvarGetMultaggrScalars(var);
1683  aggrconstant = SCIPvarGetMultaggrConstant(var);
1684 
1685  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, consdata->nlinvars + naggrs) );
1686 
1687  for( j = 0; j < naggrs; ++j )
1688  {
1689  SCIP_CALL( addLinearCoef(scip, cons, aggrvars[j], coef * aggrscalars[j]) );
1690  }
1691 
1692  if( aggrconstant != 0.0 )
1693  {
1694  if( !SCIPisInfinity(scip, -consdata->lhs) )
1695  {
1696  consdata->lhs -= coef * aggrconstant;
1697  assert(!SCIPisInfinity(scip, REALABS(consdata->lhs)));
1698  }
1699  if( !SCIPisInfinity(scip, consdata->rhs) )
1700  {
1701  consdata->rhs -= coef * aggrconstant;
1702  assert(!SCIPisInfinity(scip, REALABS(consdata->rhs)));
1703  }
1704  }
1705  }
1706  }
1707 
1708  SCIP_CALL( mergeAndCleanLinearVars(scip, cons) );
1709 
1710  consdata->isremovedfixingslin = TRUE;
1711  }
1712 
1713  SCIPdebugMsg(scip, "removed fixations of linear variables from <%s>\n -> ", SCIPconsGetName(cons));
1714  SCIPdebugPrintCons(scip, cons, NULL);
1715 
1716 #ifndef NDEBUG
1717  for( i = 0; i < consdata->nlinvars; ++i )
1718  assert(SCIPvarIsActive(consdata->linvars[i]));
1719 #endif
1720 
1721  return SCIP_OKAY;
1722 }
1723 
1724 /** removes fixed variables from expression graph */
1725 static
1727  SCIP* scip, /**< SCIP data structure */
1728  SCIP_CONSHDLR* conshdlr /**< constraint handler */
1729  )
1730 {
1732  SCIP_VAR* var;
1733  SCIP_VAR** vars;
1734  SCIP_Real* coefs;
1735  int nvars;
1736  int varssize;
1737  SCIP_Real constant;
1738  int i;
1739  int requsize;
1740  SCIPdebug( int j );
1741 
1742  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1743  assert(conshdlrdata != NULL);
1744  assert(conshdlrdata->exprgraph != NULL);
1745 
1746  if( conshdlrdata->isremovedfixings )
1747  return SCIP_OKAY;
1748 
1749  varssize = 5;
1750  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
1751  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, varssize) );
1752 
1753  i = 0;
1754  while( i < SCIPexprgraphGetNVars(conshdlrdata->exprgraph) )
1755  {
1756  var = (SCIP_VAR*)SCIPexprgraphGetVars(conshdlrdata->exprgraph)[i];
1757  if( SCIPvarIsActive(var) )
1758  {
1759  ++i;
1760  continue;
1761  }
1762 
1763  vars[0] = var;
1764  coefs[0] = 1.0;
1765  constant = 0.0;
1766  nvars = 1;
1767  SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, coefs, &nvars, varssize, &constant, &requsize, TRUE) );
1768 
1769  if( requsize > varssize )
1770  {
1771  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requsize) );
1772  SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, requsize) );
1773  varssize = requsize;
1774 
1775  SCIP_CALL( SCIPgetProbvarLinearSum(scip, vars, coefs, &nvars, varssize, &constant, &requsize, TRUE) );
1776  }
1777 
1778 #ifdef SCIP_DEBUG
1779  SCIPdebugMsg(scip, "replace fixed variable <%s> by %g", SCIPvarGetName(var), constant);
1780  for( j = 0; j < nvars; ++j )
1781  {
1782  SCIPdebugMsgPrint(scip, " %+g <%s>", coefs[j], SCIPvarGetName(vars[j]));
1783  }
1784  SCIPdebugMsgPrint(scip, "\n");
1785 #endif
1786 
1787  SCIP_CALL( SCIPexprgraphReplaceVarByLinearSum(conshdlrdata->exprgraph, var, nvars, coefs, (void**)vars, constant) );
1788 
1789  i = 0;
1790  }
1791 
1792  SCIPfreeBufferArray(scip, &coefs);
1793  SCIPfreeBufferArray(scip, &vars);
1794 
1795  conshdlrdata->isremovedfixings = TRUE;
1796 
1797  return SCIP_OKAY;
1798 }
1799 
1800 /** moves constant and linear part from expression graph node into constraint sides and linear part
1801  * frees expression graph node if expression is constant or linear */
1802 static
1804  SCIP* scip, /**< SCIP data structure */
1805  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1806  SCIP_CONS* cons, /**< nonlinear constraint */
1807  SCIP_Bool* infeasible /**< pointer to store whether the problem is infeasible or not */
1808  )
1809 {
1811  SCIP_CONSDATA* consdata;
1812  SCIP_VAR** linvars;
1813  SCIP_Real* lincoefs;
1814  SCIP_Real constant;
1815  int linvarssize;
1816  int nlinvars;
1817  int i;
1818 
1819  assert(scip != NULL);
1820  assert(conshdlr != NULL);
1821  assert(cons != NULL);
1822 
1823  consdata = SCIPconsGetData(cons);
1824  assert(consdata != NULL);
1825 
1826  *infeasible = FALSE;
1827 
1828  if( consdata->exprgraphnode == NULL )
1829  return SCIP_OKAY;
1830 
1831  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1832  assert(conshdlrdata != NULL);
1833  assert(conshdlrdata->exprgraph != NULL);
1834 
1835  /* number of children of expression graph node is a good upper estimate on number of linear variables */
1836  linvarssize = MAX(SCIPexprgraphGetNodeNChildren(consdata->exprgraphnode), 1); /*lint !e666*/
1837  SCIP_CALL( SCIPallocBufferArray(scip, &linvars, linvarssize) );
1838  SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, linvarssize) );
1839 
1840  /* get linear and constant part from expression graph node
1841  * releases expression graph node if not uses otherwise */
1842  SCIP_CALL( SCIPexprgraphNodeSplitOffLinear(conshdlrdata->exprgraph, &consdata->exprgraphnode, linvarssize, &nlinvars, (void**)linvars, lincoefs, &constant) );
1843 
1844  if( SCIPisInfinity(scip, constant) )
1845  {
1846  if( !SCIPisInfinity(scip, -consdata->lhs) )
1847  {
1848  /* setting constraint lhs to -infinity; this may change linear variable locks and events */
1849  for( i = 0; i < consdata->nlinvars; ++i )
1850  {
1851  SCIP_Bool locked = FALSE;
1852  int j;
1853 
1854  for( j = 0; j < NLOCKTYPES && !locked; j++ )
1855  locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) j);
1856 
1857  if( locked )
1858  {
1859  SCIP_CALL( unlockLinearVariable(scip, cons, consdata->linvars[i], consdata->lincoefs[i]) );
1860  }
1861  if( SCIPconsIsEnabled(cons) )
1862  {
1863  SCIP_CALL( dropLinearVarEvents(scip, cons, i) );
1864  }
1865  }
1866 
1867  consdata->lhs = -SCIPinfinity(scip);
1868 
1869  for( i = 0; i < consdata->nlinvars; ++i )
1870  {
1871  SCIP_Bool locked = FALSE;
1872  int j;
1873 
1874  for( j = 0; j < NLOCKTYPES && !locked; j++ )
1875  locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) j);
1876 
1877  if( SCIPconsIsEnabled(cons) )
1878  {
1879  SCIP_CALL( catchLinearVarEvents(scip, cons, i) );
1880  }
1881  if( locked )
1882  {
1883  SCIP_CALL( lockLinearVariable(scip, cons, consdata->linvars[i], consdata->lincoefs[i]) );
1884  }
1885  }
1886  }
1887 
1888  if( !SCIPisInfinity(scip, consdata->rhs) )
1889  {
1890  *infeasible = TRUE;
1891  goto TERMINATE;
1892  }
1893  }
1894  else if( SCIPisInfinity(scip, -constant) )
1895  {
1896  if( !SCIPisInfinity(scip, consdata->rhs) )
1897  {
1898  /* setting constraint rhs to infinity; this may change linear variable locks and events */
1899  for( i = 0; i < consdata->nlinvars; ++i )
1900  {
1901  SCIP_Bool locked = FALSE;
1902  int j;
1903 
1904  for( j = 0; j < NLOCKTYPES && !locked; j++ )
1905  locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) j);
1906 
1907  if( locked )
1908  {
1909  SCIP_CALL( unlockLinearVariable(scip, cons, consdata->linvars[i], consdata->lincoefs[i]) );
1910  }
1911  if( SCIPconsIsEnabled(cons) )
1912  {
1913  SCIP_CALL( dropLinearVarEvents(scip, cons, i) );
1914  }
1915  }
1916 
1917  consdata->rhs = SCIPinfinity(scip);
1918 
1919  for( i = 0; i < consdata->nlinvars; ++i )
1920  {
1921  SCIP_Bool locked = FALSE;
1922  int j;
1923 
1924  for( j = 0; j < NLOCKTYPES && !locked; j++ )
1925  locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) j);
1926 
1927  if( SCIPconsIsEnabled(cons) )
1928  {
1929  SCIP_CALL( catchLinearVarEvents(scip, cons, i) );
1930  }
1931  if( locked )
1932  {
1933  SCIP_CALL( lockLinearVariable(scip, cons, consdata->linvars[i], consdata->lincoefs[i]) );
1934  }
1935  }
1936  }
1937  if( !SCIPisInfinity(scip, -consdata->lhs) )
1938  {
1939  *infeasible = TRUE;
1940  goto TERMINATE;
1941  }
1942  }
1943  else if( constant != 0.0 )
1944  {
1945  if( !SCIPisInfinity(scip, -consdata->lhs) )
1946  {
1947  consdata->lhs -= constant;
1948  assert(!SCIPisInfinity(scip, REALABS(consdata->lhs)));
1949  }
1950  if( !SCIPisInfinity(scip, consdata->rhs) )
1951  {
1952  consdata->rhs -= constant;
1953  assert(!SCIPisInfinity(scip, REALABS(consdata->rhs)));
1954  }
1955  }
1956 
1957 TERMINATE:
1958  for( i = 0; i < nlinvars; ++i )
1959  {
1960  SCIP_CALL( addLinearCoef(scip, cons, linvars[i], lincoefs[i]) );
1961  }
1962 
1963  SCIPfreeBufferArray(scip, &lincoefs);
1964  SCIPfreeBufferArray(scip, &linvars);
1965 
1966  /* @todo linear variables that are also children of exprgraphnode could be moved into the expression graph for certain nonlinear operators (quadratic, polynomial), since that may allow better bound tightening */
1967 
1968  return SCIP_OKAY;
1969 }
1970 
1971 /** create a nonlinear row representation of the constraint and stores them in consdata */
1972 static
1974  SCIP* scip, /**< SCIP data structure */
1975  SCIP_CONS* cons /**< nonlinear constraint */
1976  )
1977 {
1978  SCIP_CONSDATA* consdata;
1979 
1980  assert(scip != NULL);
1981  assert(cons != NULL);
1982 
1983  consdata = SCIPconsGetData(cons);
1984  assert(consdata != NULL);
1985 
1986  if( consdata->nlrow != NULL )
1987  {
1988  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
1989  }
1990 
1991  if( consdata->nexprtrees == 0 )
1992  {
1993  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
1994  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
1995  0, NULL, 0, NULL,
1996  NULL, consdata->lhs, consdata->rhs,
1997  consdata->curvature) );
1998  }
1999  else if( consdata->nexprtrees == 1 && consdata->nonlincoefs[0] == 1.0 )
2000  {
2001  assert(consdata->exprtrees[0] != NULL);
2002  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
2003  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
2004  0, NULL, 0, NULL,
2005  consdata->exprtrees[0], consdata->lhs, consdata->rhs,
2006  consdata->curvature) );
2007  }
2008  else
2009  {
2010  /* since expression trees may share variable, we cannot easily sum them up,
2011  * but we can request a single expression tree from the expression graph
2012  */
2014  SCIP_EXPRTREE* exprtree;
2015 
2016  assert(consdata->exprgraphnode != NULL); /* since nexprtrees > 0 */
2017  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
2018  assert(conshdlrdata != NULL);
2019 
2020  SCIP_CALL( SCIPexprgraphGetTree(conshdlrdata->exprgraph, consdata->exprgraphnode, &exprtree) );
2021  SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons), 0.0,
2022  consdata->nlinvars, consdata->linvars, consdata->lincoefs,
2023  0, NULL, 0, NULL,
2024  exprtree, consdata->lhs, consdata->rhs,
2025  consdata->curvature) );
2026  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
2027  }
2028 
2029  return SCIP_OKAY;
2030 }
2031 
2032 /** tries to automatically convert a nonlinear constraint (or a part of it) into a more specific and more specialized constraint */
2033 static
2035  SCIP* scip, /**< SCIP data structure */
2036  SCIP_CONSHDLR* conshdlr, /**< constraint handler data structure */
2037  SCIP_CONS* cons, /**< source constraint to try to convert */
2038  SCIP_Bool* upgraded, /**< buffer to store whether constraint was upgraded */
2039  int* nupgdconss, /**< buffer to increase if constraint was upgraded */
2040  int* naddconss /**< buffer to increase with number of additional constraints created during upgrade */
2041  )
2042 {
2044  SCIP_CONS** upgdconss;
2045  int upgdconsssize;
2046  int nupgdconss_;
2047  int i;
2048 
2049  assert(scip != NULL);
2050  assert(conshdlr != NULL);
2051  assert(cons != NULL);
2052  assert(!SCIPconsIsModifiable(cons));
2053  assert(upgraded != NULL);
2054  assert(nupgdconss != NULL);
2055  assert(naddconss != NULL);
2056 
2057  *upgraded = FALSE;
2058 
2059  nupgdconss_ = 0;
2060 
2061  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2062  assert(conshdlrdata != NULL);
2063 
2064  /* if there are no upgrade methods, we can stop */
2065  if( conshdlrdata->nnlconsupgrades == 0 )
2066  return SCIP_OKAY;
2067 
2068  /* set debug solution in expression graph and evaluate nodes, so reformulation methods can compute debug solution values for new auxiliary variables */
2069 #ifdef WITH_DEBUG_SOLUTION
2070  if( SCIPdebugIsMainscip(scip) )
2071  {
2072  SCIP_Real* varvals;
2073 
2074  SCIP_CALL( SCIPallocBufferArray(scip, &varvals, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
2075 
2076  for( i = 0; i < SCIPexprgraphGetNVars(conshdlrdata->exprgraph); ++i )
2077  SCIP_CALL( SCIPdebugGetSolVal(scip, (SCIP_VAR*)SCIPexprgraphGetVars(conshdlrdata->exprgraph)[i], &varvals[i]) );
2078 
2079  SCIP_CALL( SCIPexprgraphEval(conshdlrdata->exprgraph, varvals) );
2080 
2081  SCIPfreeBufferArray(scip, &varvals);
2082  }
2083 #endif
2084 
2085  upgdconsssize = 2;
2086  SCIP_CALL( SCIPallocBufferArray(scip, &upgdconss, upgdconsssize) );
2087 
2088  /* call the upgrading methods */
2089 
2090  SCIPdebugMsg(scip, "upgrading nonlinear constraint <%s> (up to %d upgrade methods):\n",
2091  SCIPconsGetName(cons), conshdlrdata->nnlconsupgrades);
2092  SCIPdebugPrintCons(scip, cons, NULL);
2093 
2094  /* try all upgrading methods in priority order in case the upgrading step is enable */
2095  for( i = 0; i < conshdlrdata->nnlconsupgrades; ++i )
2096  {
2097  if( !conshdlrdata->nlconsupgrades[i]->active )
2098  continue;
2099  if( conshdlrdata->nlconsupgrades[i]->nlconsupgd == NULL )
2100  continue;
2101 
2102  SCIP_CALL( conshdlrdata->nlconsupgrades[i]->nlconsupgd(scip, cons, &nupgdconss_, upgdconss, upgdconsssize) );
2103 
2104  while( nupgdconss_ < 0 )
2105  {
2106  /* upgrade function requires more memory: resize upgdconss and call again */
2107  assert(-nupgdconss_ > upgdconsssize);
2108  upgdconsssize = -nupgdconss_;
2109  SCIP_CALL( SCIPreallocBufferArray(scip, &upgdconss, -nupgdconss_) );
2110 
2111  SCIP_CALL( conshdlrdata->nlconsupgrades[i]->nlconsupgd(scip, cons, &nupgdconss_, upgdconss, upgdconsssize) );
2112 
2113  assert(nupgdconss_ != 0);
2114  }
2115 
2116  if( nupgdconss_ > 0 )
2117  {
2118  /* got upgrade */
2119  int j;
2120 
2121  SCIPdebugMsg(scip, " -> upgraded to %d constraints:\n", nupgdconss_);
2122 
2123  /* add the upgraded constraints to the problem and forget them */
2124  for( j = 0; j < nupgdconss_; ++j )
2125  {
2126  SCIPdebugMsgPrint(scip, "\t");
2127  SCIPdebugPrintCons(scip, upgdconss[j], NULL);
2128 
2129  SCIP_CALL( SCIPaddCons(scip, upgdconss[j]) ); /*lint !e613*/
2130  SCIP_CALL( SCIPreleaseCons(scip, &upgdconss[j]) ); /*lint !e613*/
2131  }
2132 
2133  /* count the first upgrade constraint as constraint upgrade and the remaining ones as added constraints */
2134  *nupgdconss += 1;
2135  *naddconss += nupgdconss_ - 1;
2136  *upgraded = TRUE;
2137 
2138  /* delete upgraded constraint */
2139  SCIPdebugMsg(scip, "delete constraint <%s> after upgrade\n", SCIPconsGetName(cons));
2140  SCIP_CALL( SCIPdelCons(scip, cons) );
2141 
2142  break;
2143  }
2144  }
2145 
2146  SCIPfreeBufferArray(scip, &upgdconss);
2147 
2148  return SCIP_OKAY;
2149 }
2150 
2151 /** checks a nonlinear constraint for convexity and/or concavity */
2152 static
2154  SCIP* scip, /**< SCIP data structure */
2155  SCIP_CONS* cons, /**< nonlinear constraint */
2156  SCIP_Bool expensivechecks, /**< whether also expensive checks should be executed */
2157  SCIP_Bool assumeconvex /**< whether to assume convexity in inequalities */
2158  )
2159 {
2160  SCIP_CONSDATA* consdata;
2161  SCIP_INTERVAL* varbounds;
2162  int varboundssize;
2163  SCIP_VAR* var;
2164  int i;
2165  int j;
2166 
2167  assert(scip != NULL);
2168  assert(cons != NULL);
2169 
2170  consdata = SCIPconsGetData(cons);
2171  assert(consdata != NULL);
2172 
2173  if( consdata->iscurvchecked )
2174  return SCIP_OKAY;
2175 
2176  SCIPdebugMsg(scip, "Checking curvature of constraint <%s>\n", SCIPconsGetName(cons));
2177 
2178  consdata->curvature = SCIP_EXPRCURV_LINEAR;
2179  consdata->iscurvchecked = TRUE;
2180 
2181  varbounds = NULL;
2182  varboundssize = 0;
2183 
2184  for( i = 0; i < consdata->nexprtrees; ++i )
2185  {
2186  assert(consdata->exprtrees[i] != NULL);
2187  assert(SCIPexprtreeGetNVars(consdata->exprtrees[i]) > 0 );
2188 
2189  if( assumeconvex )
2190  {
2191  /* for constraints a*f(x) <= rhs, we assume that it is convex */
2192  if( SCIPisInfinity(scip, -consdata->lhs) )
2193  consdata->curvatures[i] = SCIP_EXPRCURV_CONVEX;
2194 
2195  /* for constraints lhs <= a*f(x), we assume that it is concave */
2196  if( SCIPisInfinity(scip, consdata->rhs) )
2197  consdata->curvatures[i] = SCIP_EXPRCURV_CONCAVE;
2198  }
2199  else
2200  {
2201  if( varboundssize == 0 )
2202  {
2203  SCIP_CALL( SCIPallocBufferArray(scip, &varbounds, SCIPexprtreeGetNVars(consdata->exprtrees[i])) );
2204  varboundssize = SCIPexprtreeGetNVars(consdata->exprtrees[i]);
2205  }
2206  else if( varboundssize < SCIPexprtreeGetNVars(consdata->exprtrees[i]) )
2207  {
2208  SCIP_CALL( SCIPreallocBufferArray(scip, &varbounds, SCIPexprtreeGetNVars(consdata->exprtrees[i])) );
2209  varboundssize = SCIPexprtreeGetNVars(consdata->exprtrees[i]);
2210  }
2211  assert(varbounds != NULL);
2212 
2213  for( j = 0; j < SCIPexprtreeGetNVars(consdata->exprtrees[i]); ++j )
2214  {
2215  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[j];
2216  SCIPintervalSetBounds(&varbounds[j],
2217  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -MIN(SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var))), /*lint !e666*/
2218  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, MAX(SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var))) ); /*lint !e666*/
2219  }
2220 
2221  SCIP_CALL( SCIPexprtreeCheckCurvature(consdata->exprtrees[i], INTERVALINFTY, varbounds, &consdata->curvatures[i], NULL) );
2222  consdata->curvatures[i] = SCIPexprcurvMultiply(consdata->nonlincoefs[i], consdata->curvatures[i]);
2223 
2224  if( consdata->curvatures[i] == SCIP_EXPRCURV_UNKNOWN && SCIPconshdlrGetData(SCIPconsGetHdlr(cons))->isreformulated && SCIPexprGetOperator(SCIPexprtreeGetRoot(consdata->exprtrees[i])) != SCIP_EXPR_USER )
2225  {
2226  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "indefinite expression tree in constraint <%s>\n", SCIPconsGetName(cons));
2227  SCIPdebug( SCIP_CALL( SCIPexprtreePrintWithNames(consdata->exprtrees[i], SCIPgetMessagehdlr(scip), NULL) ) );
2228  SCIPdebugMsgPrint(scip, "\n");
2229  }
2230  }
2231 
2232  /* @todo implement some more expensive checks */
2233 
2234  consdata->curvature = SCIPexprcurvAdd(consdata->curvature, consdata->curvatures[i]);
2235 
2236  SCIPdebugMsg(scip, "-> tree %d with coef %g is %s -> nonlinear part is %s\n", i, consdata->nonlincoefs[i], SCIPexprcurvGetName(consdata->curvatures[i]), SCIPexprcurvGetName(consdata->curvature));
2237  }
2238 
2239  SCIPfreeBufferArrayNull(scip, &varbounds);
2240 
2241  return SCIP_OKAY;
2242 } /*lint !e715*/
2243 
2244 /* replaces a node by another node in expression graph
2245  * moves all parents of node to replacement
2246  * replaces all exprgraphnode's in constraints that are node by replacement
2247  * node may be freed, if captured only by given constraints
2248  */
2249 static
2251  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
2252  SCIP_EXPRGRAPHNODE** node, /**< pointer to node to be replaced in expression graph */
2253  SCIP_EXPRGRAPHNODE* replacement, /**< node which takes node's place */
2254  SCIP_CONS** conss, /**< constraints */
2255  int nconss /**< number of constraints */
2256  )
2257 {
2258  SCIP_CONSDATA* consdata;
2259  int c;
2260 
2261  assert(exprgraph != NULL);
2262  assert(node != NULL);
2263  assert(*node != NULL);
2264  assert(replacement != NULL);
2265  assert(conss != NULL || nconss == 0);
2266 
2267  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, node, replacement) );
2268 
2269  /* node was not captured by any constraint */
2270  if( *node == NULL )
2271  return SCIP_OKAY;
2272 
2273  /* if node still exists, then because it is captured by some constraint (it should not have parents anymore)
2274  * thus, look into the given constraints and replace their exprgraphnode by replacement
2275  * @todo may be expensive when this is done more often, esp. when we know that node will not be freed due to an added auxiliary constraint
2276  */
2277  assert(*node == NULL || SCIPexprgraphGetNodeNParents(*node) == 0);
2278  for( c = 0; c < nconss; ++c )
2279  {
2280  assert(conss[c] != NULL); /*lint !e613*/
2281 
2282  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
2283  assert(consdata != NULL);
2284 
2285  if( consdata->exprgraphnode == *node )
2286  {
2287  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &consdata->exprgraphnode) );
2288  consdata->exprgraphnode = replacement;
2289  SCIPexprgraphCaptureNode(replacement);
2290 
2291  /* since we change the node, also the constraint changes, so ensure that it is presolved again */
2292  consdata->ispresolved = FALSE;
2293  }
2294  }
2295  *node = NULL;
2296 
2297  return SCIP_OKAY;
2298 }
2299 
2300 /** creates a new auxiliary variable and a new auxiliary nonlinear constraint connecting the var and a given node
2301  * node is replaced by new new auxiliary variables node in all parents of node in expression graph and in all constraints that use node
2302  */
2303 static
2305  SCIP* scip, /**< SCIP data structure */
2306  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
2307  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
2308  SCIP_CONS** conss, /**< constraints where to update exprgraphnode */
2309  int nconss, /**< number of constraints */
2310  int* naddcons, /**< counter to increase when constraint is added */
2311  SCIP_Bool donotmultaggr /**< whether to mark auxiliary variable as not to multiaggregate */
2312  )
2313 {
2314  char name[SCIP_MAXSTRLEN];
2315  SCIP_VAR* auxvar;
2316  SCIP_CONS* auxcons;
2317  SCIP_EXPRGRAPHNODE* auxvarnode;
2318  SCIP_INTERVAL bounds;
2319  SCIP_Real minusone;
2320  SCIP_Bool cutoff;
2321 
2322  assert(scip != NULL);
2323  assert(exprgraph != NULL);
2324  assert(node != NULL);
2325  assert(naddcons != NULL);
2326  assert(SCIPexprgraphGetNodeDepth(node) >= 1); /* do not turn vars or consts into new vars */
2327 
2328  bounds = SCIPexprgraphGetNodeBounds(node);
2329  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2330 
2331  SCIPdebugMsg(scip, "add auxiliary variable and constraint %s for node %p(%d,%d)\n", name, (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
2332 
2333  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, SCIPintervalGetInf(bounds), SCIPintervalGetSup(bounds), 0.0,
2335  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2336  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, &auxvarnode) );
2337 #ifdef WITH_DEBUG_SOLUTION
2338  if( SCIPdebugIsMainscip(scip) )
2339  {
2340  /* store debug sol value of node as value for auxvar in debug solution and as value for auxvarnode */
2342  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(node)) );
2343  }
2344 #endif
2345 
2346  if( donotmultaggr )
2347  {
2348  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, auxvar) );
2349  }
2350 
2351  /* set also bounds of auxvarnode to bounds, so it is available for new parent nodes (currently node->parents)
2352  * when updating their curvature information; avoid having to run domain propagation through exprgraph
2353  */
2354  SCIPexprgraphTightenNodeBounds(exprgraph, auxvarnode, bounds, BOUNDTIGHTENING_MINSTRENGTH, INTERVALINFTY, &cutoff);
2355  assert(!cutoff); /* we tightenend bounds from [-inf,+inf] to bounds, this should not be infeasible */
2356 
2357  /* add new constraint auxvar == node */
2358  minusone = -1.0;
2359  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 1, &auxvar, &minusone, node, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
2360  FALSE, FALSE, FALSE, FALSE, FALSE) );
2361  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2362 
2363  /* move parents of node in expression graph to auxvarnode
2364  * replace node by auxvarnode in constraints that use node */
2365  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxvarnode, conss, nconss) );
2366 
2367  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2368  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2369 
2370  ++*naddcons;
2371 
2372  return SCIP_OKAY;
2373 }
2374 
2375 /** ensures that all children of a node have at least a given curvature by adding auxiliary variables */
2376 static
2378  SCIP* scip, /**< SCIP data structure */
2379  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
2380  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
2381  SCIP_EXPRCURV mincurv, /**< minimal desired curvature */
2382  SCIP_CONS** conss, /**< constraints to check whether they use one of the replaced nodes */
2383  int nconss, /**< number of constraints to check */
2384  int* naddcons /**< counter to increase when constraint is added */
2385  )
2386 {
2387  SCIP_EXPRGRAPHNODE* child;
2388  SCIP_Bool needupdate;
2389 
2390  int i;
2391  assert(scip != NULL);
2392  assert(exprgraph != NULL);
2393  assert(node != NULL);
2394  assert(naddcons != NULL);
2395  assert(SCIPexprgraphGetNodeDepth(node) >= 1); /* do not turn vars or consts into new vars */
2396  assert(mincurv != SCIP_EXPRCURV_UNKNOWN); /* this is trivial and makes no sense */
2397 
2398  needupdate = FALSE; /* whether we need to update curvature of node */
2399 
2400  for( i = 0; i < SCIPexprgraphGetNodeNChildren(node); ++i )
2401  {
2402  child = SCIPexprgraphGetNodeChildren(node)[i];
2403  assert(child != NULL);
2404 
2405  if( (SCIPexprgraphGetNodeCurvature(child) & mincurv) != mincurv )
2406  {
2407  SCIPdebugMsg(scip, "add auxiliary variable for child %p(%d,%d) with curvature %s\n",
2409 
2410  SCIP_CALL( reformNode2Var(scip, exprgraph, child, conss, nconss, naddcons, FALSE) );
2411  needupdate = TRUE;
2412 
2413  /* i'th child of node should now be a variable */
2414  assert(SCIPexprgraphGetNodeChildren(node)[i] != child);
2416  }
2417 
2418  assert(SCIPexprgraphGetNodeCurvature(SCIPexprgraphGetNodeChildren(node)[i]) & mincurv);
2419  }
2420 
2421  if( needupdate )
2422  {
2425  }
2426 
2427  return SCIP_OKAY;
2428 }
2429 
2430 /** reformulates a monomial by adding auxiliary variables and constraints for bilinear terms */
2431 static
2433  SCIP* scip, /**< SCIP data structure */
2434  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
2435  int nfactors, /**< number of factors */
2436  SCIP_EXPRGRAPHNODE** factors, /**< factors */
2437  SCIP_Real* exponents, /**< exponents, or NULL if all 1.0 */
2438  SCIP_EXPRGRAPHNODE** resultnode, /**< buffer to store node which represents the reformulated monomial */
2439  SCIP_Bool createauxcons, /**< whether to create auxiliary var/cons */
2440  int mindepth, /**< minimal depth of new nodes in expression graph, or -1 */
2441  int* naddcons /**< buffer to increase by number of added cons */
2442  )
2443 {
2444  char name[SCIP_MAXSTRLEN];
2445  SCIP_VAR* auxvar;
2446  SCIP_CONS* auxcons;
2447  SCIP_Real minusone;
2448 
2449  assert(scip != NULL);
2450  assert(exprgraph != NULL);
2451  assert(nfactors > 0);
2452  assert(factors != NULL);
2453  assert(resultnode != NULL);
2454  assert(naddcons != NULL);
2455 
2456  /* factors are just one node */
2457  if( nfactors == 1 && (exponents == NULL || exponents[0] == 1.0) )
2458  {
2459  *resultnode = factors[0];
2460  return SCIP_OKAY;
2461  }
2462 
2463  /* only one factor, but with exponent < 0.0 and factor has mixed sign, e.g., x^(-3)
2464  * reformulate as auxvar * factor^(-exponent) = 1 and return the node for auxvar in resultnode
2465  */
2466  if( nfactors == 1 && exponents[0] < 0.0 && SCIPexprgraphGetNodeBounds(factors[0]).inf < 0.0 && SCIPexprgraphGetNodeBounds(factors[0]).sup > 0.0 ) /*lint !e613*/
2467  {
2468  SCIP_EXPRGRAPHNODE* auxnode;
2469  SCIP_EXPRGRAPHNODE* reformfactors[2];
2470  SCIP_Real reformexp[2];
2471 
2472  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2473  SCIPdebugMsg(scip, "add auxiliary variable and constraint %s\n", name);
2474 
2475  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2477  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2478  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, resultnode) );
2479 
2480 #ifdef WITH_DEBUG_SOLUTION
2481  /* store debug sol value of node as value for auxvar in debug solution and as value for resultnode */
2482  if( SCIPdebugIsMainscip(scip) )
2483  {
2484  SCIP_Real debugval;
2485  debugval = pow(SCIPexprgraphGetNodeVal(factors[0]), exponents[0]);
2486  SCIPexprgraphSetVarNodeValue(*resultnode, debugval);
2487  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
2488  }
2489 #endif
2490 
2491  /* increase naddcons before next call to reformMonomial, to avoid duplicate variable names, which is bad for debugging */
2492  ++*naddcons;
2493 
2494  /* add reformulation for resultnode(=auxvar) * factor^(-exponent) = 1.0
2495  * if exponent != -1.0, then factor^(-exponent) should be moved into extra variable
2496  * finally one should get an EXPR_MUL node */
2497  reformfactors[0] = *resultnode;
2498  reformfactors[1] = factors[0];
2499  reformexp[0] = 1.0;
2500  reformexp[1] = -exponents[0]; /*lint !e613*/
2501  SCIP_CALL( reformMonomial(scip, exprgraph, 2, reformfactors, reformexp, &auxnode, FALSE, mindepth, naddcons) );
2502 
2503  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 0, NULL, NULL, auxnode, 1.0, 1.0,
2504  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
2505  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2506 
2507  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2508  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2509 
2510  return SCIP_OKAY;
2511  }
2512 
2513  /* only one factor, but with exponent != 1.0 */
2514  if( nfactors == 1 )
2515  {
2516  /* create some power expression node, if not existing already */
2517  SCIP_EXPRGRAPHNODE* expnode;
2518  SCIP_EXPRGRAPHNODE* parent;
2519  int p;
2520 
2521  assert(exponents != NULL);
2522 
2523  /* check if there is already a node for factors[0]^exponents[0] */
2524  expnode = NULL;
2525  for( p = 0; p < SCIPexprgraphGetNodeNParents(factors[0]); ++p)
2526  {
2527  parent = SCIPexprgraphGetNodeParents(factors[0])[p];
2528  if( SCIPisIntegral(scip, exponents[0]) &&
2530  SCIPexprgraphGetNodeIntPowerExponent(parent) == (int)SCIPround(scip, exponents[0]) )
2531  {
2532  expnode = parent;
2533  break;
2534  }
2536  SCIPisEQ(scip, SCIPexprgraphGetNodeRealPowerExponent(parent), exponents[0]) )
2537  {
2538  expnode = parent;
2539  }
2540  }
2541  if( expnode == NULL )
2542  {
2543  if( SCIPisIntegral(scip, exponents[0]) )
2544  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &expnode, SCIP_EXPR_INTPOWER, (int)SCIPround(scip, exponents[0])) );
2545  else
2546  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &expnode, SCIP_EXPR_REALPOWER, exponents[0]) );
2547 
2548  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, expnode, mindepth, 1, &factors[0]) );
2551  }
2552 
2553  if( createauxcons )
2554  {
2555  /* @todo if there was already a node for factors[0]^exponents[0], then there may have been also been already an auxiliary variable and constraint (-> ex7_3_4) */
2556  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2557  SCIPdebugMsg(scip, "add auxiliary variable and constraint %s\n", name);
2558 
2559  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2561  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2562  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, resultnode) );
2563 
2564 #ifdef WITH_DEBUG_SOLUTION
2565  if( SCIPdebugIsMainscip(scip) )
2566  {
2568  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(expnode)) );
2569  }
2570 #endif
2571 
2572  /* add new constraint resultnode(=auxvar) = expnode */
2573  minusone = -1.0;
2574  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 1, &auxvar, &minusone, expnode, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
2575  FALSE, FALSE, FALSE, FALSE, FALSE) );
2576  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2577 
2578  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2579  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2580 
2581  ++*naddcons;
2582  }
2583  else
2584  {
2585  *resultnode = expnode;
2586  }
2587 
2588  return SCIP_OKAY;
2589  }
2590 
2591  if( nfactors == 2 && exponents != NULL && exponents[0] != 1.0 && exponents[0] == exponents[1] ) /*lint !e777*/
2592  {
2593  /* factor0^exponent * factor1^exponent with exponent != 1.0, reform as (factor0*factor1)^exponent */
2594  SCIP_EXPRGRAPHNODE* productnode;
2595 
2596  /* create node for factor0*factor1 */
2597  SCIP_CALL( reformMonomial(scip, exprgraph, 2, factors, NULL, &productnode, TRUE, mindepth, naddcons) );
2598 
2599  /* create node for productnode^exponents[0] by just calling this method again */
2600  SCIP_CALL( reformMonomial(scip, exprgraph, 1, &productnode, &exponents[0], resultnode, createauxcons, mindepth, naddcons) );
2601 
2602  return SCIP_OKAY;
2603  }
2604 
2605  if( nfactors == 2 && exponents != NULL && exponents[0] == -exponents[1] ) /*lint !e777*/
2606  {
2607  /* factor0^exponent * factor1^(-exponent), reform as (factor0/factor1)^exponent or (factor1/factor0)^(-exponent) */
2608  SCIP_EXPRGRAPHNODE* auxvarnode;
2609  SCIP_EXPRGRAPHNODE* auxconsnode;
2610  SCIP_EXPRGRAPHNODE* leftright[2];
2611  SCIP_Real absexp;
2612 
2613  /* create variable and constraint for factor0 = auxvar * factor1 (if exponent > 0) or factor1 = auxvar * factor0 (if exponent < 0) */
2614 
2615  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2616  SCIPdebugMsg(scip, "add auxiliary variable and constraint %s\n", name);
2617 
2618  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2620  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2621  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, &auxvarnode) );
2622 
2623 #ifdef WITH_DEBUG_SOLUTION
2624  /* store debug sol value of node as value for auxvar in debug solution and as value for resultnode */
2625  if( SCIPdebugIsMainscip(scip) )
2626  {
2627  SCIP_Real debugval;
2628  if( exponents[0] > 0.0 )
2629  debugval = SCIPexprgraphGetNodeVal(factors[0]) / SCIPexprgraphGetNodeVal(factors[1]);
2630  else
2631  debugval = SCIPexprgraphGetNodeVal(factors[1]) / SCIPexprgraphGetNodeVal(factors[0]);
2632  SCIPexprgraphSetVarNodeValue(auxvarnode, debugval);
2633  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
2634  }
2635 #endif
2636 
2637  /* add new constraint resultnode(= auxvar) * factor1 - factor0 == 0 (exponent > 0) or auxvar * factor0 - factor1 == 0 (exponent < 0) */
2638  leftright[0] = auxvarnode;
2639  leftright[1] = exponents[0] > 0.0 ? factors[1] : factors[0];
2640 
2642  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, auxconsnode, -1, 2, leftright) );
2643 
2644  leftright[0] = auxconsnode;
2645  leftright[1] = exponents[0] > 0.0 ? factors[0] : factors[1];
2646 
2648  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, auxconsnode, -1, 2, leftright) );
2649 
2650  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 0, NULL, NULL, auxconsnode, 0.0, 0.0,
2651  TRUE, TRUE, TRUE, TRUE, TRUE,
2652  FALSE, FALSE, FALSE, FALSE, FALSE) );
2653  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2654 
2655  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2656  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2657 
2658  ++*naddcons;
2659 
2660  /* create node for auxvarnode^abs(exponents[0]) by just calling this method again */
2661  absexp = fabs(exponents[0]);
2662  SCIP_CALL( reformMonomial(scip, exprgraph, 1, &auxvarnode, &absexp, resultnode, createauxcons, mindepth, naddcons) );
2663 
2664  return SCIP_OKAY;
2665  }
2666 
2667  /* @todo if nfactors > 2, assemble groups of factors with same exponent and replace these by a single variable first */
2668 
2669  {
2670  /* at least two factors */
2671  /* create auxvar for left half (recursively) and auxvar for right half (recursively) and maybe new auxvar for product */
2672  /* @todo it may be enough to replace single factors in a monomial to get it convex or concave, see Westerlund et.al. */
2673 
2674  SCIP_EXPRGRAPHNODE* productnode;
2675  SCIP_EXPRGRAPHNODE* leftright[2]; /* {left, right} */
2676  SCIP_EXPRGRAPHNODE* parent;
2677  int half;
2678  int p;
2679 
2680  half = nfactors / 2;
2681  assert(half > 0);
2682  assert(half < nfactors);
2683 
2684  SCIP_CALL( reformMonomial(scip, exprgraph, half, factors, exponents, &leftright[0], TRUE, mindepth, naddcons) );
2685  SCIP_CALL( reformMonomial(scip, exprgraph, nfactors-half, &factors[half], exponents != NULL ? &exponents[half] : NULL, &leftright[1], TRUE, mindepth, naddcons) ); /*lint !e826*/
2686 
2687  /* check if there is already a node for left * right */
2688  productnode = NULL;
2689  for( p = 0; p < SCIPexprgraphGetNodeNParents(leftright[0]); ++p)
2690  {
2691  parent = SCIPexprgraphGetNodeParents(leftright[0])[p];
2693  continue;
2694 
2695  assert(SCIPexprgraphGetNodeNChildren(parent) == 2);
2696  if( (SCIPexprgraphGetNodeChildren(parent)[0] == leftright[0] && SCIPexprgraphGetNodeChildren(parent)[1] == leftright[1]) ||
2697  ( SCIPexprgraphGetNodeChildren(parent)[0] == leftright[1] && SCIPexprgraphGetNodeChildren(parent)[1] == leftright[0]) )
2698  {
2699  productnode = parent;
2700  break;
2701  }
2702  }
2703  if( productnode == NULL )
2704  {
2705  /* create node for left * right */
2706  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &productnode, SCIP_EXPR_MUL, NULL) );
2707  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, productnode, mindepth, 2, leftright) );
2710  }
2711 
2712  if( createauxcons )
2713  {
2714  /* @todo if there was already a node for factors[0]^exponents[0], then there may have been also been already an auxiliary variable and constraint (-> ex7_3_4) */
2715  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
2716  SCIPdebugMsg(scip, "add auxiliary variable and constraint %s\n", name);
2717 
2718  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
2719  SCIP_VARTYPE_CONTINUOUS, TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
2720  SCIP_CALL( SCIPaddVar(scip, auxvar) );
2721  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, resultnode) );
2722 
2723 #ifdef WITH_DEBUG_SOLUTION
2724  if( SCIPdebugIsMainscip(scip) )
2725  {
2726  SCIPexprgraphSetVarNodeValue(*resultnode, SCIPexprgraphGetNodeVal(productnode));
2727  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, SCIPexprgraphGetNodeVal(productnode)) );
2728  }
2729 #endif
2730 
2731  /* add new constraint resultnode(= auxvar) == left * right */
2732  minusone = -1.0;
2733  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 1, &auxvar, &minusone, productnode, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
2734  FALSE, FALSE, FALSE, FALSE, FALSE) );
2735  SCIP_CALL( SCIPaddCons(scip, auxcons) );
2736 
2737  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
2738  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
2739 
2740  ++*naddcons;
2741  }
2742  else
2743  {
2744  *resultnode = productnode;
2745  }
2746  }
2747 
2748  return SCIP_OKAY;
2749 }
2750 
2751 /** reformulates expression graph into a form so that for each node under- and overestimators could be computed
2752  * similar to factorable reformulation in other global solvers, but sometimes does not split up complex operands (like quadratic)
2753  */
2754 static
2756  SCIP* scip, /**< SCIP data structure */
2757  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2758  SCIP_CONS** conss, /**< constraints */
2759  int nconss, /**< number of constraints */
2760  int* naddcons /**< buffer to increase by the number of added constraints */
2761  )
2762 {
2764  SCIP_CONSDATA* consdata;
2765  SCIP_EXPRGRAPH* exprgraph;
2766  SCIP_EXPRGRAPHNODE* node;
2767  SCIP_EXPRGRAPHNODE** children;
2768  SCIP_EXPRGRAPHNODE* reformnode;
2769  SCIP_Bool havenonlinparent;
2770  SCIP_Bool domainerror;
2771  int nchildren;
2772  int c;
2773  int d;
2774  int i;
2775  int u;
2776 #ifndef NDEBUG
2777  int j;
2778 #endif
2779 
2780  assert(scip != NULL);
2781  assert(conshdlr != NULL);
2782  assert(conss != NULL || nconss == 0);
2783  assert(naddcons != NULL);
2784  assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING);
2785  assert(!SCIPinProbing(scip));
2786 
2787  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2788  assert(conshdlrdata != NULL);
2789 
2790  if( conshdlrdata->isreformulated )
2791  {
2792  SCIPdebugMsg(scip, "skip reformulation, already done\n");
2793  return SCIP_OKAY;
2794  }
2795 
2796  exprgraph = conshdlrdata->exprgraph;
2797 
2798  /* make sure current variable bounds are variable nodes of exprgraph */
2799  SCIP_CALL( SCIPexprgraphPropagateVarBounds(exprgraph, INTERVALINFTY, FALSE, &domainerror) );
2800  assert(!domainerror); /* should have been found by domain propagation */
2801 
2802  /* set debug solution in expression graph and evaluate nodes, so we can compute debug solution values for auxiliary variables */
2803 #ifdef WITH_DEBUG_SOLUTION
2804  if( SCIPdebugIsMainscip(scip) )
2805  {
2806  SCIP_Real* varvals;
2807 
2808  SCIP_CALL( SCIPallocBufferArray(scip, &varvals, SCIPexprgraphGetNVars(exprgraph)) );
2809 
2810  for( i = 0; i < SCIPexprgraphGetNVars(exprgraph); ++i )
2811  SCIP_CALL( SCIPdebugGetSolVal(scip, (SCIP_VAR*)SCIPexprgraphGetVars(exprgraph)[i], &varvals[i]) );
2812 
2813  SCIP_CALL( SCIPexprgraphEval(exprgraph, varvals) );
2814 
2815  SCIPfreeBufferArray(scip, &varvals);
2816  }
2817 #endif
2818 
2819  for( d = 1; d < SCIPexprgraphGetDepth(exprgraph); ++d )
2820  {
2821  i = 0;
2822  while( i < SCIPexprgraphGetNNodes(exprgraph)[d] )
2823  {
2824  node = SCIPexprgraphGetNodes(exprgraph)[d][i];
2825  assert(node != NULL);
2826 
2827  /* skip disabled nodes, they should be removed soon */
2828  if( !SCIPexprgraphIsNodeEnabled(node) )
2829  {
2830  ++i;
2831  continue;
2832  }
2833 
2834  /* make sure bounds and curvature of node are uptodate */
2837 
2838  /* try external reformulation methods */
2839  for( u = 0; u < conshdlrdata->nnlconsupgrades; ++u )
2840  {
2841  if( conshdlrdata->nlconsupgrades[u]->nodereform != NULL && conshdlrdata->nlconsupgrades[u]->active )
2842  {
2843  SCIP_CALL( conshdlrdata->nlconsupgrades[u]->nodereform(scip, exprgraph, node, naddcons, &reformnode) );
2844  if( reformnode == NULL )
2845  continue;
2846 
2847  SCIPdebugMsg(scip, "external nodereform reformulated node %p(%d,%d), replace by %p\n",
2848  (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node), (void*)reformnode);
2849 
2850  SCIP_CALL( reformReplaceNode(exprgraph, &node, reformnode, conss, nconss) );
2853 
2854  break;
2855  }
2856  }
2857  /* if node has been reformulated, continue with next node without increasing i */
2858  if( u < conshdlrdata->nnlconsupgrades )
2859  continue;
2860 
2861  /* leave nodes that are known to be convex/concave/linear as they are */
2863  {
2864  SCIPdebugMsg(scip, "skip reformulating node %p(%d,%d) = ", (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
2867  ++i;
2868  continue;
2869  }
2870 
2871  /* get flag whether node has a nonlinear parent
2872  * we want to know whether the current node will be at the top of the tree after the next simplification run
2873  * due to the tricky reformulation of polynomials below, this may not be the case yet
2874  */
2875  havenonlinparent = SCIPexprgraphHasNodeNonlinearAncestor(node);
2876 
2877  /* take action */
2879  SCIPdebugMsg(scip, "think about reformulating %s node %p(%d,%d) = ", SCIPexpropGetName(SCIPexprgraphGetNodeOperator(node)), (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
2881  SCIPdebugMsgPrint(scip, "\n");
2882 
2883  children = SCIPexprgraphGetNodeChildren(node);
2884  nchildren = SCIPexprgraphGetNodeNChildren(node);
2885  assert(children != NULL || nchildren == 0);
2886 
2887 #ifndef NDEBUG
2888  /* at this place, all children nodes should have a known curvature, except if they only appear only linearly in constraints
2889  * the latter for cases where constraints with unknown curvature are upgraded to other constraint handler that can handle these (quadratic, signpower,...)
2890  */
2891  for( j = 0; j < nchildren; ++j )
2892  {
2893  assert(children[j] != NULL); /*lint !e613*/
2894  if( havenonlinparent ||
2899  assert(SCIPexprgraphGetNodeCurvature(children[j]) != SCIP_EXPRCURV_UNKNOWN || SCIPexprgraphGetNodeOperator(children[j]) == SCIP_EXPR_USER); /*lint !e613*/
2900  }
2901 #endif
2902 
2903  switch( SCIPexprgraphGetNodeOperator(node) )
2904  {
2905  case SCIP_EXPR_VARIDX:
2906  case SCIP_EXPR_PARAM:
2907  case SCIP_EXPR_CONST:
2908  SCIPerrorMessage("node with operator %d cannot have unknown curvature\n", SCIPexprgraphGetNodeOperator(node));
2909  SCIPABORT();
2910  break; /*lint !e527*/
2911 
2912  /* linear operands */
2913  case SCIP_EXPR_PLUS:
2914  case SCIP_EXPR_MINUS:
2915  case SCIP_EXPR_SUM:
2916  case SCIP_EXPR_LINEAR:
2917  /* children have conflicting curvature, we can handle such sums in cons_nonlinear
2918  * thus, turn node into variable, if it has nonlinear parents */
2919  if( havenonlinparent )
2920  {
2921  SCIP_CALL( reformNode2Var(scip, exprgraph, node, conss, nconss, naddcons, FALSE) );
2922  assert(node != NULL);
2923  assert(SCIPexprgraphGetNodeNParents(node) == 0); /* node should now be at top of graph */
2924  }
2925  ++i;
2926  break;
2927 
2928  /* quadratic operands */
2929  case SCIP_EXPR_MUL:
2930  case SCIP_EXPR_QUADRATIC:
2931  {
2932  SCIP_EXPRGRAPHNODE* child;
2933  SCIP_Bool needupdate;
2934 
2935  /* ensure all children are linear, so next simplifier run makes sure all children will be variables (by distributing the product)
2936  * however, that will not work for user-expressions, so we should also ensure that they are none (@todo as they are linear, they could actually be replaced by a regular linear expression)
2937  */
2938  SCIPdebugMessage("ensure children are linear\n");
2939  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_LINEAR, conss, nconss, naddcons) );
2940 
2941  needupdate = FALSE; /* whether we need to update curvature of node */
2942  for( c = 0; c < SCIPexprgraphGetNodeNChildren(node); ++c )
2943  {
2944  child = SCIPexprgraphGetNodeChildren(node)[c];
2945  assert(child != NULL);
2946 
2948  {
2949  SCIPdebugMessage("add auxiliary variable for child %p(%d,%d) with curvature %s operator %s\n",
2951 
2952  SCIP_CALL( reformNode2Var(scip, exprgraph, child, conss, nconss, naddcons, FALSE) );
2953  needupdate = TRUE;
2954 
2955  /* c'th child of node should now be a variable */
2956  assert(SCIPexprgraphGetNodeChildren(node)[c] != child);
2958  }
2959  }
2960  if( needupdate )
2961  {
2964  }
2965 
2967  {
2968  /* if curvature is now known then we are done */
2969  ++i;
2970  break;
2971  }
2972 
2973  /* if we have nonlinear parents or a sibling, then add auxiliary variable for this node, so an upgrade to cons_quadratic should take place
2974  * we assume that siblings are non-linear and non-quadratic, which should be the case if simplifier was run, and also if this node was created during reformulating a polynomial
2975  * @todo we could also add auxvars for the sibling nodes, e.g., if there is only one
2976  * @todo if sibling nodes are quadratic (or even linear) due to reformulation, then we do not need to reform here... (-> nvs16)
2977  * maybe this step should not be done here at all if havenonlinparent is FALSE? e.g., move into upgrade from quadratic?
2978  */
2979  if( havenonlinparent || SCIPexprgraphHasNodeSibling(node) )
2980  {
2981  SCIP_CALL( reformNode2Var(scip, exprgraph, node, conss, nconss, naddcons, FALSE) );
2982  assert(node != NULL);
2983  assert(SCIPexprgraphGetNodeNParents(node) == 0); /* node should now be at top of graph, so it can be upgraded by cons_quadratic */
2984  break;
2985  }
2986 
2987  ++i;
2988  break;
2989  }
2990 
2991  case SCIP_EXPR_DIV:
2992  {
2993  /* reformulate as bilinear term
2994  * note that in the reformulation, a zero in the denominator forces the nominator to be zero too, but the auxiliary can be arbitrary
2995  */
2996  SCIP_EXPRGRAPHNODE* auxvarnode;
2997  SCIP_EXPRGRAPHNODE* auxnode;
2998  SCIP_EXPRGRAPHNODE* auxchildren[3];
2999  SCIP_Real lincoefs[3];
3000  SCIP_QUADELEM quadelem;
3001  SCIP_VAR* auxvar;
3002  SCIP_CONS* auxcons;
3003  char name[SCIP_MAXSTRLEN];
3004  SCIP_INTERVAL bounds;
3005 
3006  assert(children != NULL);
3007  assert(nchildren == 2);
3008 
3009  bounds = SCIPexprgraphGetNodeBounds(node);
3010  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "nlreform%d", *naddcons);
3011 
3012  SCIPdebugMsg(scip, "add auxiliary variable %s for division in node %p(%d,%d)\n", name, (void*)node, SCIPexprgraphGetNodeDepth(node), SCIPexprgraphGetNodePosition(node));
3013 
3014  SCIP_CALL( SCIPcreateVar(scip, &auxvar, name, SCIPintervalGetInf(bounds), SCIPintervalGetSup(bounds), 0.0,
3016  SCIP_CALL( SCIPaddVar(scip, auxvar) );
3017  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, (void**)&auxvar, &auxvarnode) );
3018 
3019 #ifdef WITH_DEBUG_SOLUTION
3020  if( SCIPdebugIsMainscip(scip) )
3021  {
3022  SCIP_Real debugval;
3023  debugval = SCIPexprgraphGetNodeVal(children[0]) / SCIPexprgraphGetNodeVal(children[1]);
3024  SCIPexprgraphSetVarNodeValue(auxvarnode, debugval);
3025  SCIP_CALL( SCIPdebugAddSolVal(scip, auxvar, debugval) );
3026  }
3027 #endif
3028 
3029  /* add new constraint auxvar * child[1] - child[0] == 0 */
3030  auxchildren[0] = children[0]; /*lint !e613*/
3031  auxchildren[1] = children[1]; /*lint !e613*/
3032  auxchildren[2] = auxvarnode;
3033 
3034  lincoefs[0] = -1.0;
3035  lincoefs[1] = 0.0;
3036  lincoefs[2] = 0.0;
3037 
3038  quadelem.idx1 = 1;
3039  quadelem.idx2 = 2;
3040  quadelem.coef = 1.0;
3041 
3042  SCIP_CALL( SCIPexprgraphCreateNodeQuadratic(SCIPblkmem(scip), &auxnode, 3, lincoefs, 1, &quadelem, 0.0) );
3043  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, auxnode, -1, 3, auxchildren) );
3044 
3045  SCIP_CALL( SCIPcreateConsNonlinear2(scip, &auxcons, name, 0, NULL, NULL, auxnode, 0.0, 0.0,
3046  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
3047  SCIP_CALL( SCIPaddCons(scip, auxcons) );
3048 
3049  /* replace node by auxvarnode in graph and constraints that use it */
3050  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxvarnode, conss, nconss) );
3051 
3052  SCIP_CALL( SCIPreleaseCons(scip, &auxcons) );
3053  SCIP_CALL( SCIPreleaseVar(scip, &auxvar) );
3054 
3055  ++*naddcons;
3056 
3057  /* do not increase i, since node was removed and not necessarily replaced here */
3058  break;
3059  }
3060 
3061  case SCIP_EXPR_MIN:
3062  {
3063  /* make sure that both children are concave, because min of concave functions is concave */
3064  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_CONCAVE, conss, nconss, naddcons) );
3066  ++i;
3067  break;
3068  }
3069 
3070  case SCIP_EXPR_MAX:
3071  {
3072  /* make sure that both children are convex, because max of convex functions is convex */
3073  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_CONVEX, conss, nconss, naddcons) );
3075  ++i;
3076  break;
3077  }
3078 
3079  case SCIP_EXPR_INTPOWER:
3080  {
3081  assert(nchildren == 1);
3082 
3083  /* for an intpower with mixed sign in the base and negative exponent, we reformulate similar as for EXPR_DIV */
3084  if( SCIPexprgraphGetNodeIntPowerExponent(node) < 0 && SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(children[0])) < 0.0 && SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(children[0])) > 0.0 ) /*lint !e613*/
3085  {
3086  SCIP_EXPRGRAPHNODE* auxvarnode;
3087  SCIP_Real exponent;
3088 
3089  /* if we have something like x^(-3) with mixed sign for x, then add auxvar and reform as auxvar*x^3 = 1 via reformMonomial */
3091  SCIP_CALL( reformMonomial(scip, exprgraph, 1, children, &exponent, &auxvarnode, TRUE, SCIPexprgraphGetNodeDepth(node), naddcons) );
3092  /* replace node by auxvarnode */
3093  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxvarnode, conss, nconss) );
3094  break;
3095  }
3096 
3097  /* otherwise, we continue as for other univariate operands */
3098  } /*lint -fallthrough*/
3099 
3100  /* univariate operands where the child does not have bounds and curvature from which we can deduce curvature of this node,
3101  * but where we can do more if the child is linear
3102  * thus, turn child into auxiliary variable
3103  */
3104  case SCIP_EXPR_SQUARE:
3105  case SCIP_EXPR_SQRT:
3106  case SCIP_EXPR_EXP:
3107  case SCIP_EXPR_LOG:
3108  case SCIP_EXPR_ABS:
3109  case SCIP_EXPR_REALPOWER:
3110  case SCIP_EXPR_SIGNPOWER:
3111  {
3112  assert(nchildren == 1);
3113 
3114  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_LINEAR, conss, nconss, naddcons) );
3115 
3117  {
3118  /* the only case where f(x) for a linear term x is indefinite here is if f is intpower or signpower and x has mixed sign */
3120  assert(SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(children[0])) < 0.0); /*lint !e613*/
3121  assert(SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(children[0])) > 0.0); /*lint !e613*/
3122  }
3123 
3124  /* update curvature of node */
3127 
3129  {
3130  /* if intpower and signpower with positive exponent and a mixed sign in the child bounds still does not give a curvature,
3131  * we can do more if we make this node the root of a nonlinear constraints expression node, so it can be upgraded by cons_signpower
3132  * of course, this is only required if the node is still intermediate
3133  *
3134  * an intpower with negative exponent should have been handled above
3135  * for signpower, we assume the exponent is > 1.0
3136  */
3140  if( havenonlinparent )
3141  {
3142  SCIP_CALL( reformNode2Var(scip, exprgraph, node, conss, nconss, naddcons, FALSE) );
3143  assert(node != NULL); /* it should be used by some auxiliary constraint now */
3144  assert(SCIPexprgraphGetNodeNParents(node) == 0); /* node should now be at top of graph (and used by new auxiliary constraint) */
3145  }
3146  }
3147  ++i;
3148 
3149  break;
3150  }
3151 
3152  case SCIP_EXPR_SIN:
3153  case SCIP_EXPR_COS:
3154  case SCIP_EXPR_TAN:
3155  case SCIP_EXPR_SIGN:
3156  /* case SCIP_EXPR_ERF : */
3157  /* case SCIP_EXPR_ERFI : */
3158  {
3159  SCIPerrorMessage("no support for trigonometric or sign operands yet\n");
3160  return SCIP_ERROR;
3161  }
3162 
3163  case SCIP_EXPR_PRODUCT:
3164  {
3165  /* ensure all children are linear */
3166  SCIP_CALL( reformEnsureChildrenMinCurvature(scip, exprgraph, node, SCIP_EXPRCURV_LINEAR, conss, nconss, naddcons) );
3168  {
3169  ++i;
3170  break;
3171  }
3172 
3173  /* if curvature is still unknown (quite likely), then turn into a cascade of bilinear terms
3174  * if node has parents, then ensure that it has a known curvature, otherwise we are also fine with a node that is a product of two (aux)variables */
3175  SCIP_CALL( reformMonomial(scip, exprgraph, nchildren, children, NULL, &reformnode, havenonlinparent, SCIPexprgraphGetNodeDepth(node), naddcons) );
3176 
3177  /* replace node by reformnode in graph and in all constraints that use it */
3178  SCIP_CALL( reformReplaceNode(exprgraph, &node, reformnode, conss, nconss) );
3179 
3180  /* do not increase i, since node was removed and not necessarily replaced here */
3181  break;
3182  }
3183 
3184  case SCIP_EXPR_POLYNOMIAL:
3185  {
3186  /* if polynomial has several monomials, replace by a sum of nodes each having a single monomial and one that has all linear and quadratic monomials
3187  * if polynomial has only a single monomial, then reformulate that one
3188  */
3189  SCIP_EXPRDATA_MONOMIAL** monomials;
3190  SCIP_EXPRDATA_MONOMIAL* monomial;
3191  int nmonomials;
3192  SCIP_Real* exponents;
3193  SCIP_Real coef;
3194  int* childidxs;
3195  int nfactors;
3196  int f;
3197  SCIP_INTERVAL childbounds;
3198  SCIP_EXPRCURV childcurv;
3199  SCIP_Bool modified;
3200 
3201  monomials = SCIPexprgraphGetNodePolynomialMonomials(node);
3202  nmonomials = SCIPexprgraphGetNodePolynomialNMonomials(node);
3203  assert(nmonomials >= 1); /* constant polynomials should have been simplified away */
3204 
3205  if( nmonomials > 1 )
3206  {
3207  SCIP_EXPRGRAPHNODE* sumnode;
3208  SCIP_Real constant;
3209  int nquadelems;
3210  SCIP_QUADELEM* quadelems;
3211  SCIP_Real* lincoefs;
3212  int nmonomialnodes;
3213  SCIP_EXPRGRAPHNODE** childrennew;
3214  SCIP_EXPRGRAPHNODE** monomialnodes;
3215  SCIP_Bool foundlincoefs;
3216  int m;
3217 
3218  /* @todo if a monomial is a factor of another monomial, then we could (and should?) replace it there by the node we create for it here -> ex7_2_1
3219  * @todo factorizing the polynomial could be beneficial
3220  */
3221 
3222  /* constant part of polynomials, to add to first monomialnode, if any, or quadratic or linear part */
3223  constant = SCIPexprgraphGetNodePolynomialConstant(node);
3224 
3225  /* coefficients from linear monomials */
3226  foundlincoefs = FALSE;
3227 
3228  /* quadratic elements */
3229  nquadelems = 0;
3230 
3231  /* expression graph nodes representing single higher-degree monomials, and single node with linear and/or quadratic monomials */
3232  nmonomialnodes = 0;
3233  SCIP_CALL( SCIPallocBufferArray(scip, &monomialnodes, nmonomials) );
3234 
3235  /* allocate memory */
3236  SCIP_CALL( SCIPallocClearBufferArray(scip, &lincoefs, nchildren) );
3237  SCIP_CALL( SCIPallocBufferArray(scip, &quadelems, nmonomials) );
3238  SCIP_CALL( SCIPallocBufferArray(scip, &childrennew, nchildren) );
3239 
3240  for( m = 0; m < nmonomials; ++m )
3241  {
3242  monomial = monomials[m];
3243  assert(monomial != NULL);
3244 
3245  coef = SCIPexprGetMonomialCoef(monomial);
3246  exponents = SCIPexprGetMonomialExponents(monomial);
3247  childidxs = SCIPexprGetMonomialChildIndices(monomial);
3248  nfactors = SCIPexprGetMonomialNFactors(monomial);
3249  assert(nfactors >= 1); /* constant monomials should have been simplified away */
3250  assert(coef != 0.0); /* zero-monomials should have been simplified away */
3251 
3252  if( nfactors == 1 && exponents[0] == 1.0 )
3253  {
3254  /* linear monomial */
3255  foundlincoefs = TRUE;
3256  assert(0 <= childidxs[0] && childidxs[0] < nchildren);
3257  assert(lincoefs[childidxs[0]] == 0.0); /* monomials should have been merged */
3258  lincoefs[childidxs[0]] = coef;
3259  }
3260  else if( nfactors == 1 && exponents[0] == 2.0 )
3261  {
3262  /* square monomial */
3263  quadelems[nquadelems].idx1 = childidxs[0];
3264  quadelems[nquadelems].idx2 = childidxs[0];
3265  quadelems[nquadelems].coef = coef;
3266  ++nquadelems;
3267  }
3268  else if( nfactors == 2 && exponents[0] == 1.0 && exponents[1] == 1.0 )
3269  {
3270  /* bilinear monomial */
3271  if( childidxs[0] < childidxs[1] )
3272  {
3273  quadelems[nquadelems].idx1 = childidxs[0];
3274  quadelems[nquadelems].idx2 = childidxs[1];
3275  }
3276  else
3277  {
3278  quadelems[nquadelems].idx1 = childidxs[1];
3279  quadelems[nquadelems].idx2 = childidxs[0];
3280  }
3281  quadelems[nquadelems].coef = coef;
3282  ++nquadelems;
3283  }
3284  else
3285  {
3286  /* general monomial -> pass into separate expression graph node */
3287  SCIP_EXPRDATA_MONOMIAL* monomialnew;
3288 
3289  /* create new node for this monomial, children will be those associated with factors */
3290  SCIP_CALL( SCIPexprCreateMonomial(SCIPblkmem(scip), &monomialnew, coef, nfactors, NULL, exponents) );
3291  SCIP_CALL( SCIPexprgraphCreateNodePolynomial(SCIPblkmem(scip), &monomialnodes[nmonomialnodes], 1, &monomialnew, constant, FALSE) );
3292  constant = 0.0;
3293 
3294  assert(nfactors <= nchildren);
3295  for( f = 0; f < nfactors; ++f )
3296  childrennew[f] = children[childidxs[f]]; /*lint !e613*/
3297 
3298  /* add new node to same depth as this node, so we will reformulate it during this run
3299  * no need to refresh bounds/curvature here, since that will be done when we reach this node next */
3300  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, monomialnodes[nmonomialnodes], SCIPexprgraphGetNodeDepth(node), nfactors, childrennew) );
3301 
3302  ++nmonomialnodes;
3303  }
3304  }
3305  /* should have had at least one linear, quadratic, or general monomial */
3306  assert(foundlincoefs || nquadelems > 0 || nmonomialnodes > 0);
3307 
3308  if( nquadelems > 0 )
3309  {
3310  /* create and add additional node for quadratic and linear part, simplifier should take care of removing unused children later */
3311  SCIP_CALL( SCIPexprgraphCreateNodeQuadratic(SCIPblkmem(scip), &monomialnodes[nmonomialnodes], nchildren, foundlincoefs ? lincoefs : NULL, nquadelems, quadelems, constant) );
3312  constant = 0.0;
3313  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, monomialnodes[nmonomialnodes], SCIPexprgraphGetNodeDepth(node), nchildren, children) );
3314  ++nmonomialnodes;
3315  }
3316  else if( foundlincoefs )
3317  {
3318  /* create additional node for linear part, simplifier should take care of removing unused children later */
3319  SCIP_CALL( SCIPexprgraphCreateNodeLinear(SCIPblkmem(scip), &monomialnodes[nmonomialnodes], nchildren, lincoefs, constant) );
3320  constant = 0.0;
3321  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, monomialnodes[nmonomialnodes], SCIPexprgraphGetNodeDepth(node), nchildren, children) );
3322  ++nmonomialnodes;
3323  }
3324  assert(constant == 0.0); /* the constant should have been used somewhere */
3325 
3326  /* release memory */
3327  SCIPfreeBufferArray(scip, &childrennew);
3328  SCIPfreeBufferArray(scip, &quadelems);
3329  SCIPfreeBufferArray(scip, &lincoefs);
3330 
3331  assert(nmonomialnodes > 0);
3332  if( nmonomialnodes > 1 )
3333  {
3334  /* add node for sum of monomials to expression graph */
3335  SCIP_CALL( SCIPexprgraphCreateNode(SCIPblkmem(scip), &sumnode, nmonomialnodes == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM) );
3336  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, sumnode, -1, nmonomialnodes, monomialnodes) );
3337  }
3338  else
3339  {
3340  /* if only one monomial, then because polynomial was linear or quadratic... */
3341  assert(SCIPexprgraphGetNodeOperator(monomialnodes[0]) == SCIP_EXPR_LINEAR || SCIPexprgraphGetNodeOperator(monomialnodes[0]) == SCIP_EXPR_QUADRATIC);
3342  sumnode = monomialnodes[0];
3343  }
3344  SCIPfreeBufferArray(scip, &monomialnodes);
3345 
3346  /* replace node by sumnode, and we are done */
3347  SCIP_CALL( reformReplaceNode(exprgraph, &node, sumnode, conss, nconss) );
3348 
3349  SCIPdebugMsg(scip, "splitup polynomial into sum of %d nodes\n", nmonomialnodes);
3350 
3351  break;
3352  }
3353 
3354  /* reformulate a monomial such that it becomes convex or concave, if necessary */
3355 
3356  monomial = monomials[0];
3357  assert(monomial != NULL);
3358 
3359  coef = SCIPexprGetMonomialCoef(monomial);
3360  exponents = SCIPexprGetMonomialExponents(monomial);
3361  childidxs = SCIPexprGetMonomialChildIndices(monomial);
3362  nfactors = SCIPexprGetMonomialNFactors(monomial);
3363  assert(nfactors >= 1); /* constant monomials should have been simplified away */
3364  assert(coef != 0.0); /* zero-monomials should have been simplified away */
3365  assert(children != NULL);
3366 
3367  /* check if we make monomial convex or concave by making a child linear */
3368  modified = FALSE;
3369  if( nfactors == 1 )
3370  {
3371  /* ensure that the child of an univariate monomial is linear if its current (bounds,curvature) yields an unknown curvature for the monomial
3372  * and with linear child it had a known curvature (rules out x^a, a negative, x not linear) */
3373  childcurv = SCIPexprgraphGetNodeCurvature(children[childidxs[0]]); /*lint !e613*/
3374  childbounds = SCIPexprgraphGetNodeBounds(children[childidxs[0]]); /*lint !e613*/
3375  assert(SCIPexprcurvPower(childbounds, childcurv, exponents[0]) == SCIP_EXPRCURV_UNKNOWN); /* this is exactly the curvature of the node, which is unknown */
3376 
3377  /* if monomial were convex or concave if child were linear, then make child linear */
3378  if( SCIPexprcurvPower(childbounds, SCIP_EXPRCURV_LINEAR, exponents[0]) != SCIP_EXPRCURV_UNKNOWN )
3379  {
3380  assert(childcurv != SCIP_EXPRCURV_LINEAR);
3381  SCIPdebugMsg(scip, "reform child %d (univar. monomial) with curv %s into var\n", childidxs[0], SCIPexprcurvGetName(childcurv));
3382  SCIP_CALL( reformNode2Var(scip, exprgraph, children[childidxs[0]], conss, nconss, naddcons, FALSE) ); /*lint !e613*/
3383  modified = TRUE;
3384  }
3385  }
3386  else
3387  {
3388  /* check if the conditions on the exponents allow for a convex or concave monomial, assuming that the children are linear
3389  * if one of these conditions is fulfilled but a children curvature does not fit, then make these children linear
3390  */
3391  int nnegative;
3392  int npositive;
3393  SCIP_Real sum;
3394  SCIP_Bool expcurvpos;
3395  SCIP_Bool expcurvneg;
3396  SCIP_EXPRCURV desiredcurv;
3397 
3398  nnegative = 0; /* number of negative exponents */
3399  npositive = 0; /* number of positive exponents */
3400  sum = 0.0; /* sum of exponents */
3401  expcurvpos = TRUE; /* whether exp_j * f_j''(x) >= 0 for all factors (assuming f_j >= 0) */
3402  expcurvneg = TRUE; /* whether exp_j * f_j''(x) <= 0 for all factors (assuming f_j >= 0) */
3403 
3404  /* ensure that none of the children have unknown curvature */
3405  for( c = 0; c < SCIPexprgraphGetNodeNChildren(node); ++c )
3406  {
3407  childcurv = SCIPexprgraphGetNodeCurvature(children[c]); /*lint !e613*/
3408  if( childcurv == SCIP_EXPRCURV_UNKNOWN )
3409  {
3410  SCIPdebugMessage("reform child %d with unknown curvature into var\n", c);
3411  SCIP_CALL( reformNode2Var(scip, exprgraph, children[c], conss, nconss, naddcons, FALSE) ); /*lint !e613*/
3412  modified = TRUE;
3413  }
3414  }
3415  if( modified )
3416  {
3417  /* refresh curvature information in node, since we changed children */
3420 
3421  modified = FALSE;
3422  }
3423 
3424  for( f = 0; f < nfactors; ++f )
3425  {
3426  childcurv = SCIPexprgraphGetNodeCurvature(children[childidxs[f]]); /*lint !e613*/
3427  assert(childcurv != SCIP_EXPRCURV_UNKNOWN);
3428  childbounds = SCIPexprgraphGetNodeBounds(children[childidxs[f]]); /*lint !e613*/
3429  if( childbounds.inf < 0.0 && childbounds.sup > 0.0 )
3430  break;
3431 
3432  if( exponents[f] < 0.0 )
3433  ++nnegative;
3434  else
3435  ++npositive;
3436  sum += exponents[f];
3437 
3438  /* negate curvature if factor is negative */
3439  if( childbounds.inf < 0.0 )
3440  childcurv = SCIPexprcurvNegate(childcurv);
3441 
3442  /* check if exp_j * checkcurv is convex (>= 0) and/or concave */
3443  childcurv = SCIPexprcurvMultiply(exponents[f], childcurv);
3444  if( !(childcurv & SCIP_EXPRCURV_CONVEX) )
3445  expcurvpos = FALSE;
3446  if( !(childcurv & SCIP_EXPRCURV_CONCAVE) )
3447  expcurvneg = FALSE;
3448  }
3449 
3450  /* if some child can be both positive and negative, then nothing we can do here to get the monomial convex or concave
3451  * otherwise (i.e., f == nfactors), look further */
3452  desiredcurv = SCIP_EXPRCURV_UNKNOWN;
3453  if( f == nfactors )
3454  {
3455  /* if all factors are linear, then a product f_j^exp_j with f_j >= 0 is convex if
3456  * - all exponents are negative, or
3457  * - all except one exponent j* are negative and exp_j* >= 1 - sum_{j!=j*}exp_j, but the latter is equivalent to sum_j exp_j >= 1
3458  * further, the product is concave if
3459  * - all exponents are positive and the sum of exponents is <= 1.0
3460  *
3461  * if factors are nonlinear, then we require additionally, that for convexity
3462  * - each factor is convex if exp_j >= 0, or concave if exp_j <= 0, i.e., exp_j*f_j'' >= 0
3463  * and for concavity, we require that
3464  * - all factors are concave, i.e., exp_j*f_j'' <= 0
3465  */
3466 
3467  if( nnegative == nfactors || (nnegative == nfactors-1 && SCIPisGE(scip, sum, 1.0)) )
3468  {
3469  /* if exponents are such that we can be convex, but children curvature does not fit, make some children linear */
3470  SCIPdebugMsg(scip, "%d-variate monomial is convex (modulo sign), child curv fits = %u\n", nfactors, expcurvpos);
3471  /* since current node curvature is set to unknown, there must be such a child, since otherwise the node curvature had to be convex */
3472  assert(!expcurvpos);
3473  desiredcurv = SCIP_EXPRCURV_CONVEX;
3474  }
3475  else if( npositive == nfactors && SCIPisLE(scip, sum, 1.0) )
3476  {
3477  /* if exponents are such that we can be concave, but children curvature does not fit, make some children linear */
3478  SCIPdebugMsg(scip, "%d-variate monomial is concave (modulo sign), child curv fits = %u\n", nfactors, expcurvneg);
3479  /* since current node curvature is set to unknown, there must be such a child, since otherwise the node curvature had to be concave */
3480  assert(!expcurvneg);
3481  desiredcurv = SCIP_EXPRCURV_CONCAVE;
3482  }
3483  else
3484  {
3485  /* exponents are such that monomial is neither convex nor concave even if children were linear
3486  * thus, reformulate monomial below
3487  */
3488  }
3489  }
3490 
3491  if( desiredcurv != SCIP_EXPRCURV_UNKNOWN )
3492  {
3493  for( f = 0; f < nfactors; ++f )
3494  {
3495  childcurv = SCIPexprgraphGetNodeCurvature(children[childidxs[f]]); /*lint !e613*/
3496  assert(childcurv != SCIP_EXPRCURV_UNKNOWN);
3497  childbounds = SCIPexprgraphGetNodeBounds(children[childidxs[f]]); /*lint !e613*/
3498  assert(childbounds.inf >= 0.0 || childbounds.sup <= 0.0);
3499 
3500  /* negate curvature if factor is negative */
3501  if( childbounds.inf < 0.0 )
3502  childcurv = SCIPexprcurvNegate(childcurv);
3503 
3504  /* check if exp_j * checkcurv is convex (>= 0) and/or concave */
3505  childcurv = SCIPexprcurvMultiply(SCIPexprGetMonomialExponents(monomial)[f], childcurv);
3506  if( (desiredcurv == SCIP_EXPRCURV_CONVEX && !(childcurv & SCIP_EXPRCURV_CONVEX )) ||
3507  (desiredcurv == SCIP_EXPRCURV_CONCAVE && !(childcurv & SCIP_EXPRCURV_CONCAVE)) )
3508  {
3509  SCIPdebugMsg(scip, "reform child %d (factor %d) with curv %s into var\n",
3510  childidxs[f], f, SCIPexprcurvGetName(SCIPexprgraphGetNodeCurvature(children[childidxs[f]]))); /*lint !e613*/
3511  SCIP_CALL( reformNode2Var(scip, exprgraph, children[childidxs[f]], conss, nconss, naddcons, FALSE) ); /*lint !e613*/
3512  modified = TRUE;
3513  }
3514  }
3515  }
3516  }
3517 
3518  if( modified )
3519  {
3520  /* refresh curvature information in node, since we changed children, it should be convex or concave now */
3524 
3525  /* we are done and can proceed with the next node */
3526  ++i;
3527  break;
3528  }
3529 
3530  /* monomial can only have unknown curvature here, if it has several factors
3531  * or is of form x^a with x both negative and positive and a an odd or negative integer (-> INTPOWER expression)
3532  */
3533  assert(nfactors > 1 ||
3534  (SCIPexprgraphGetNodeBounds(children[childidxs[0]]).inf < 0.0 && SCIPexprgraphGetNodeBounds(children[childidxs[0]]).sup > 0.0 &&
3535  SCIPisIntegral(scip, exponents[0]) && (exponents[0] < 0.0 || ((int)SCIPround(scip, exponents[0]) % 2 != 0)))
3536  ); /*lint !e613*/
3537 
3538  /* bilinear monomials should not come up here, since simplifier should have turned them into quadratic expression nodes */
3539  assert(!(nfactors == 2 && exponents[0] == 1.0 && exponents[1] == 1.0));
3540 
3541  /* reform monomial if it is a product, or we need it to be on the top of the graph, or if it of the form x^a with a < 0.0 (and thus x having mixed sign, see assert above)
3542  * thus, in the case x^a with a an odd positive integer we assume that cons_signpower will do something */
3543  if( nfactors > 1 || havenonlinparent || exponents[0] < 0.0 )
3544  {
3545  SCIP_EXPRGRAPHNODE* auxnode;
3546  SCIP_EXPRGRAPHNODE** factors;
3547 
3548  if( nfactors > 1 )
3549  {
3550  SCIP_CALL( SCIPallocBufferArray(scip, &factors, nfactors) );
3551  for( f = 0; f < nfactors; ++f )
3552  factors[f] = children[childidxs[f]]; /*lint !e613*/
3553  }
3554  else
3555  factors = &children[childidxs[0]]; /*lint !e613*/
3556 
3557  SCIPdebugMsg(scip, "reform monomial node, create auxvar = %u\n", havenonlinparent);
3558  /* get new auxnode for monomial
3559  * if node has parents and monomial is of indefinite form x^a, then also create auxvar for it, since otherwise we create a auxnode with unknown curvature
3560  * note, that the case x^a with positive and odd a will still give an indefinite node (without parents), where we assume that signpower will pick it up at some point
3561  */
3562  SCIP_CALL( reformMonomial(scip, exprgraph, nfactors, factors, exponents, &auxnode, havenonlinparent, SCIPexprgraphGetNodeDepth(node), naddcons) );
3563 
3564  if( nfactors > 1 )
3565  {
3566  SCIPfreeBufferArray(scip, &factors);
3567  }
3568 
3569  /* create node for monomialcoef * auxnode + monomialconstant, if not identical to auxnode */
3570  if( SCIPexprgraphGetNodePolynomialConstant(node) != 0.0 || coef != 1.0 )
3571  {
3572  SCIP_EXPRGRAPHNODE* replnode;
3573 
3575  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, replnode, -1, 1, &auxnode) );
3576  auxnode = replnode;
3577  }
3578 
3579  /* replace node by auxnode and refresh its curvature */
3580  SCIP_CALL( reformReplaceNode(exprgraph, &node, auxnode, conss, nconss) );
3583 
3584  break;
3585  }
3586  else
3587  {
3588  SCIPdebugMsg(scip, "no reformulation of monomial node, assume signpower will take care of it\n");
3589  }
3590 
3591  ++i;
3592  break;
3593  }
3594 
3595  case SCIP_EXPR_USER:
3596  {
3597  /* ensure all children are linear */
3598  SCIP_CALL( reformEnsureChildrenMinCurvature( scip, exprgraph, node, SCIP_EXPRCURV_LINEAR, conss, nconss, naddcons ) );
3599 
3600  /* unknown curvature can be handled by user estimator callback or interval gradient */
3601  /*
3602  if( SCIPexprgraphGetNodeCurvature( node ) == SCIP_EXPRCURV_UNKNOWN )
3603  {
3604  SCIPerrorMessage("user expression with unknown curvature not supported\n");
3605  return SCIP_ERROR;
3606  }
3607  */
3608 
3609  ++i;
3610  break;
3611  }
3612 
3613  case SCIP_EXPR_LAST:
3614  SCIPABORT();
3615  break;
3616  }
3617  }
3618  }
3619 
3620  /* for constraints with concave f(g(x)) with linear g:R^n -> R, n>1, reformulate to get a univariate concave function, since this is easier to underestimate
3621  * @todo this does not work yet for sums of functions other than polynomials
3622  */
3623  for( c = 0; c < nconss; ++c )
3624  {
3625  SCIP_EXPRGRAPHNODE* multivarnode;
3626  SCIP_EXPRCURV curv;
3627 
3628  assert(conss[c] != NULL); /*lint !e613*/
3629 
3630  /* skip constraints that are to be deleted */
3631  if( SCIPconsIsDeleted(conss[c]) ) /*lint !e613*/
3632  continue;
3633 
3634  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
3635  assert(consdata != NULL);
3636 
3637  if( consdata->exprgraphnode == NULL )
3638  continue;
3639 
3640  /* after reformulation, force a round of backpropagation in expression graph for all constraints,
3641  * since new variables (nlreform*) may now be used in existing constraints and we want domain restrictions
3642  * of operators propagated for these variables
3643  */
3644  consdata->forcebackprop = TRUE;
3645 
3646  if( SCIPexprgraphGetNodeOperator(consdata->exprgraphnode) == SCIP_EXPR_POLYNOMIAL )
3647  {
3648  SCIP_EXPRDATA_MONOMIAL* monomial;
3649  int m;
3650  int f;
3651 
3652  for( m = 0; m < SCIPexprgraphGetNodePolynomialNMonomials(consdata->exprgraphnode); ++m )
3653  {
3654  SCIP_CALL( SCIPexprgraphGetNodePolynomialMonomialCurvature(consdata->exprgraphnode, m, INTERVALINFTY, &curv) );
3655 
3656  monomial = SCIPexprgraphGetNodePolynomialMonomials(consdata->exprgraphnode)[m];
3657  assert(monomial != NULL);
3658 
3659  /* if nothing concave, then continue */
3660  if( (SCIPisInfinity(scip, consdata->rhs) || curv != SCIP_EXPRCURV_CONCAVE) &&
3661  ( SCIPisInfinity(scip, -consdata->lhs) || curv != SCIP_EXPRCURV_CONVEX) )
3662  continue;
3663 
3664  for( f = 0; f < SCIPexprGetMonomialNFactors(monomial); ++f )
3665  {
3666  multivarnode = SCIPexprgraphGetNodeChildren(consdata->exprgraphnode)[SCIPexprGetMonomialChildIndices(monomial)[f]];
3667 
3668  /* search for a descendant of node that has > 1 children
3669  * after simplifier run, there should be no constant expressions left
3670  */
3671  while( SCIPexprgraphGetNodeNChildren(multivarnode) == 1 )
3672  multivarnode = SCIPexprgraphGetNodeChildren(multivarnode)[0];
3673 
3674  /* if node expression is obviously univariate, then continue */
3675  if( SCIPexprgraphGetNodeNChildren(multivarnode) == 0 )
3676  {
3678  continue;
3679  }
3680 
3681  /* if multivarnode is a linear expression, then replace this by an auxiliary variable/node
3682  * mark auxiliary variable as not to multiaggregate, so SCIP cannot undo what we just did
3683  */
3685  {
3686  SCIPdebugMsg(scip, "replace linear multivariate node %p(%d,%d) in expression of cons <%s> by auxvar\n",
3687  (void*)multivarnode, SCIPexprgraphGetNodeDepth(multivarnode), SCIPexprgraphGetNodePosition(multivarnode), SCIPconsGetName(conss[c])); /*lint !e613*/
3688  SCIPdebugPrintCons(scip, conss[c], NULL); /*lint !e613*/
3689  SCIP_CALL( reformNode2Var(scip, exprgraph, multivarnode, conss, nconss, naddcons, TRUE) );
3690  }
3691  }
3692  }
3693  }
3694  else
3695  {
3696  curv = SCIPexprgraphGetNodeCurvature(consdata->exprgraphnode);
3697 
3698  /* if nothing concave, then continue */
3699  if( (SCIPisInfinity(scip, consdata->rhs) || curv != SCIP_EXPRCURV_CONCAVE) &&
3700  ( SCIPisInfinity(scip, -consdata->lhs) || curv != SCIP_EXPRCURV_CONVEX) )
3701  continue;
3702 
3703  /* search for a descendant of node that has > 1 children
3704  * after simplifier run, there should be no constant expressions left
3705  */
3706  multivarnode = consdata->exprgraphnode;
3707  while( SCIPexprgraphGetNodeNChildren(multivarnode) == 1 )
3708  multivarnode = SCIPexprgraphGetNodeChildren(multivarnode)[0];
3709 
3710  /* if node expression is obviously univariate, then continue */
3711  if( SCIPexprgraphGetNodeNChildren(multivarnode) == 0 )
3712  {
3714  continue;
3715  }
3716 
3717  /* if node itself is multivariate, then continue */
3718  if( multivarnode == consdata->exprgraphnode )
3719  continue;
3720 
3721  /* if multivarnode is a linear expression, then replace this by an auxiliary variable/node
3722  * mark auxiliary variable as not to multiaggregate, so SCIP cannot undo what we just did
3723  */
3725  {
3726  SCIPdebugMsg(scip, "replace linear multivariate node %p(%d,%d) in expression of cons <%s> by auxvar\n",
3727  (void*)multivarnode, SCIPexprgraphGetNodeDepth(multivarnode), SCIPexprgraphGetNodePosition(multivarnode), SCIPconsGetName(conss[c])); /*lint !e613*/
3728  SCIPdebugPrintCons(scip, conss[c], NULL); /*lint !e613*/
3729  SCIP_CALL( reformNode2Var(scip, exprgraph, multivarnode, conss, nconss, naddcons, TRUE) );
3730  }
3731  }
3732  }
3733 
3734  conshdlrdata->isreformulated = TRUE;
3735 
3736  return SCIP_OKAY;
3737 }
3738 
3739 /** computes activity and violation of a constraint
3740  *
3741  * During presolving and if the constraint is active, it is assumes that SCIPexprgraphEval has been called for sol before.
3742  *
3743  * If a solution is found to violate the variable bounds, then violation calculation is stopped and solviolbounds is set to TRUE.
3744  */
3745 static
3747  SCIP* scip, /**< SCIP data structure */
3748  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3749  SCIP_CONS* cons, /**< nonlinear constraint */
3750  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
3751  SCIP_Bool* solviolbounds /**< buffer to indicate whether solution is found to violate variable bounds by more than feastol */
3752  )
3753 { /*lint --e{666}*/
3755  SCIP_CONSDATA* consdata;
3756  SCIP_VAR* var;
3757  SCIP_Real varval;
3758  int i;
3759 
3760  assert(scip != NULL);
3761  assert(conshdlr != NULL);
3762  assert(cons != NULL);
3763  assert(solviolbounds != NULL);
3764 
3765  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3766  assert(conshdlrdata != NULL);
3767  assert(conshdlrdata->exprinterpreter != NULL);
3768 
3769  consdata = SCIPconsGetData(cons);
3770  assert(consdata != NULL);
3771 
3772  consdata->activity = 0.0;
3773  consdata->lhsviol = 0.0;
3774  consdata->rhsviol = 0.0;
3775  varval = 0.0;
3776  *solviolbounds = FALSE;
3777 
3778  for( i = 0; i < consdata->nlinvars; ++i )
3779  {
3780  SCIP_Real activity;
3781 
3782  var = consdata->linvars[i];
3783  varval = SCIPgetSolVal(scip, sol, var);
3784 
3785  /* project onto local box, in case the LP solution is slightly outside the bounds (which is not our job to enforce) */
3786  if( sol == NULL )
3787  {
3788  /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case */
3789  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
3790  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
3791  {
3792  *solviolbounds = TRUE;
3793  return SCIP_OKAY;
3794  }
3795  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
3796  }
3797  activity = consdata->lincoefs[i] * varval;
3798 
3799  /* the contribution of a variable with |varval| = +inf is +inf when activity > 0.0, -inf when activity < 0.0, and
3800  * 0.0 otherwise
3801  */
3802  if( SCIPisInfinity(scip, REALABS(varval)) )
3803  {
3804  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
3805  {
3806  consdata->activity = SCIPinfinity(scip);
3807  consdata->rhsviol = SCIPinfinity(scip);
3808  return SCIP_OKAY;
3809  }
3810 
3811  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
3812  {
3813  consdata->activity = -SCIPinfinity(scip);
3814  consdata->lhsviol = SCIPinfinity(scip);
3815  return SCIP_OKAY;
3816  }
3817  }
3818 
3819  consdata->activity += activity;
3820  }
3821 
3822  for( i = 0; i < consdata->nexprtrees; ++i )
3823  {
3824  SCIP_Real activity;
3825  SCIP_Real val;
3826  int nvars;
3827 
3828  /* compile expression tree, if not done before */
3829  if( SCIPexprtreeGetInterpreterData(consdata->exprtrees[i]) == NULL )
3830  {
3831  SCIP_CALL( SCIPexprintCompile(conshdlrdata->exprinterpreter, consdata->exprtrees[i]) );
3832  }
3833 
3834  nvars = SCIPexprtreeGetNVars(consdata->exprtrees[i]);
3835 
3836  if( nvars == 1 )
3837  {
3838  /* in the not so unusual case that an expression has only one variable, we do not need to extra allocate memory */
3839  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[0];
3840  varval = SCIPgetSolVal(scip, sol, var);
3841 
3842  /* project onto local box, in case the LP solution is slightly outside the bounds (and then cannot be evaluated) */
3843  if( sol == NULL )
3844  {
3845  /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case */
3846  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
3847  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
3848  {
3849  *solviolbounds = TRUE;
3850  return SCIP_OKAY;
3851  }
3852  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
3853  }
3854 
3855  /* coverity[callee_ptr_arith] */
3856  SCIP_CALL( SCIPexprintEval(conshdlrdata->exprinterpreter, consdata->exprtrees[i], &varval, &val) );
3857  }
3858  else
3859  {
3860  SCIP_Real* x;
3861  int j;
3862 
3863  SCIP_CALL( SCIPallocBufferArray(scip, &x, nvars) );
3864 
3865  for( j = 0; j < nvars; ++j )
3866  {
3867  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[j];
3868  varval = SCIPgetSolVal(scip, sol, var);
3869 
3870  /* project onto local box, in case the LP solution is slightly outside the bounds (and then cannot be evaluated) */
3871  if( sol == NULL )
3872  {
3873  /* with non-initial columns, this might fail because variables can shortly be a column variable before entering the LP and have value 0.0 in this case */
3874  if( (!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) && !SCIPisFeasGE(scip, varval, SCIPvarGetLbLocal(var))) ||
3875  (!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) && !SCIPisFeasLE(scip, varval, SCIPvarGetUbLocal(var))) )
3876  {
3877  *solviolbounds = TRUE;
3878  SCIPfreeBufferArray(scip, &x);
3879  return SCIP_OKAY;
3880  }
3881  varval = MAX(SCIPvarGetLbLocal(var), MIN(SCIPvarGetUbLocal(var), varval));
3882  }
3883 
3884  x[j] = varval;
3885  }
3886 
3887  SCIP_CALL( SCIPexprintEval(conshdlrdata->exprinterpreter, consdata->exprtrees[i], x, &val) );
3888 
3889  SCIPfreeBufferArray(scip, &x);
3890  }
3891 
3892  /* set the activity to infinity if a function evaluation was not valid (e.g., sqrt(-1) ) */
3893  if( !SCIPisFinite(val) )
3894  {
3895  consdata->activity = SCIPinfinity(scip);
3896  if( !SCIPisInfinity(scip, -consdata->lhs) )
3897  consdata->lhsviol = SCIPinfinity(scip);
3898  if( !SCIPisInfinity(scip, consdata->rhs) )
3899  consdata->rhsviol = SCIPinfinity(scip);
3900  return SCIP_OKAY;
3901  }
3902 
3903  /* the contribution of an expression with |val| = +inf is +inf when its coefficient is > 0.0, -inf when its coefficient is < 0.0, and
3904  * 0.0 otherwise
3905  */
3906  activity = consdata->nonlincoefs[i] * val;
3907  if( SCIPisInfinity(scip, REALABS(val)) )
3908  {
3909  if( activity > 0.0 && !SCIPisInfinity(scip, consdata->rhs) )
3910  {
3911  consdata->activity = SCIPinfinity(scip);
3912  consdata->rhsviol = SCIPinfinity(scip);
3913  return SCIP_OKAY;
3914  }
3915 
3916  if( activity < 0.0 && !SCIPisInfinity(scip, -consdata->lhs) )
3917  {
3918  consdata->activity = -SCIPinfinity(scip);
3919  consdata->lhsviol = SCIPinfinity(scip);
3920  return SCIP_OKAY;
3921  }
3922  }
3923 
3924  consdata->activity += activity;
3925  }
3926 
3927  if( consdata->nexprtrees == 0 && consdata->exprgraphnode != NULL )
3928  {
3929  SCIP_Real val;
3930 
3932 
3933  val = SCIPexprgraphGetNodeVal(consdata->exprgraphnode);
3934  assert(val != SCIP_INVALID); /*lint !e777*/
3935 
3936  /* set the activity to infinity if a function evaluation was not valid (e.g., sqrt(-1) ) */
3937  if( !SCIPisFinite(val) )
3938  {
3939  consdata->activity = SCIPinfinity(scip);
3940  if( !SCIPisInfinity(scip, -consdata->lhs) )
3941  consdata->lhsviol = SCIPinfinity(scip);
3942  if( !SCIPisInfinity(scip, consdata->rhs) )
3943  consdata->rhsviol = SCIPinfinity(scip);
3944  return SCIP_OKAY;
3945  }
3946 
3947  if( SCIPisInfinity(scip, val) && !SCIPisInfinity(scip, consdata->rhs) )
3948  {
3949  consdata->activity = SCIPinfinity(scip);
3950  consdata->rhsviol = SCIPinfinity(scip);
3951  return SCIP_OKAY;
3952  }
3953  else if( SCIPisInfinity(scip, -val) && !SCIPisInfinity(scip, -consdata->lhs) )
3954  {
3955  consdata->activity = -SCIPinfinity(scip);
3956  consdata->lhsviol = SCIPinfinity(scip);
3957  return SCIP_OKAY;
3958  }
3959 
3960  consdata->activity += val;
3961  }
3962 
3963  if( !SCIPisInfinity(scip, -consdata->lhs) && SCIPisGT(scip, consdata->lhs - consdata->activity, SCIPfeastol(scip)) )
3964  consdata->lhsviol = consdata->lhs - consdata->activity;
3965  else
3966  consdata->lhsviol = 0.0;
3967 
3968  if( !SCIPisInfinity(scip, consdata->rhs) && SCIPisGT(scip, consdata->activity - consdata->rhs, SCIPfeastol(scip)) )
3969  consdata->rhsviol = consdata->activity - consdata->rhs;
3970  else
3971  consdata->rhsviol = 0.0;
3972 
3973  /* update absolute and relative violation of the solution */
3974  if( sol != NULL )
3975  {
3976  SCIP_Real absviol;
3977  SCIP_Real relviol;
3978  SCIP_Real lhsrelviol;
3979  SCIP_Real rhsrelviol;
3980 
3981  absviol = MAX(consdata->lhsviol, consdata->rhsviol);
3982 
3983  lhsrelviol = SCIPrelDiff(consdata->lhs, consdata->activity);
3984  rhsrelviol = SCIPrelDiff(consdata->activity, consdata->rhs);
3985  relviol = MAX(lhsrelviol, rhsrelviol);
3986 
3987  SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
3988  }
3989 
3990  return SCIP_OKAY;
3991 }
3992 
3993 /** computes violation of a set of constraints
3994  *
3995  * If the solution is found to violate bounds of some variable in some constraint, then violation computation is stopped and solviolbounds is set to TRUE.
3996  */
3997 static
3999  SCIP* scip, /**< SCIP data structure */
4000  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4001  SCIP_CONS** conss, /**< constraints */
4002  int nconss, /**< number of constraints */
4003  SCIP_SOL* sol, /**< solution or NULL if LP solution should be used */
4004  SCIP_Bool* solviolbounds, /**< buffer to indicate whether solution violates bounds of some variable by more than feastol */
4005  SCIP_CONS** maxviolcon /**< buffer to store constraint with largest violation, or NULL if solution is feasible */
4006  )
4007 {
4008  SCIP_CONSDATA* consdata;
4009  SCIP_Real viol;
4010  SCIP_Real maxviol;
4011  int c;
4012 
4013  assert(scip != NULL);
4014  assert(conshdlr != NULL);
4015  assert(conss != NULL || nconss == 0);
4016  assert(maxviolcon != NULL);
4017  assert(solviolbounds != NULL);
4018 
4020  {
4022  SCIP_Real* varvals;
4023 
4024  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4025  assert(conshdlrdata != NULL);
4026  assert(conshdlrdata->exprgraph != NULL);
4027 
4028  SCIP_CALL( SCIPallocBufferArray(scip, &varvals, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
4029  SCIP_CALL( SCIPgetSolVals(scip, sol, SCIPexprgraphGetNVars(conshdlrdata->exprgraph), (SCIP_VAR**)SCIPexprgraphGetVars(conshdlrdata->exprgraph), varvals) );
4030 
4031  SCIP_CALL( SCIPexprgraphEval(conshdlrdata->exprgraph, varvals) );
4032 
4033  SCIPfreeBufferArray(scip, &varvals);
4034  }
4035 
4036  *maxviolcon = NULL;
4037 
4038  maxviol = 0.0;
4039 
4040  for( c = 0; c < nconss; ++c )
4041  {
4042  assert(conss != NULL);
4043  assert(conss[c] != NULL);
4044 
4045  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol, solviolbounds) );
4046 
4047  /* stop if solution violates bounds */
4048  if( *solviolbounds )
4049  break;
4050 
4051  consdata = SCIPconsGetData(conss[c]);
4052  assert(consdata != NULL);
4053 
4054  viol = MAX(consdata->lhsviol, consdata->rhsviol);
4055  if( viol > maxviol && SCIPisGT(scip, viol, SCIPfeastol(scip)) )
4056  {
4057  maxviol = viol;
4058  *maxviolcon = conss[c];
4059  }
4060 
4061  /* SCIPdebugMsg(scip, "constraint <%s> violated by (%g, %g), activity = %g\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->activity); */
4062  }
4063 
4064  return SCIP_OKAY;
4065 }
4066 
4067 /** adds linearization of a constraints expression tree in reference point to a row */
4068 static
4070  SCIP* scip, /**< SCIP data structure */
4071  SCIP_EXPRINT* exprint, /**< expression interpreter */
4072  SCIP_CONS* cons, /**< constraint */
4073  int exprtreeidx, /**< for which tree a linearization should be added */
4074  SCIP_Real* x, /**< value of expression tree variables where to generate cut */
4075  SCIP_Bool newx, /**< whether the last evaluation of the expression with the expression interpreter was not at x */
4076  SCIP_ROWPREP* rowprep, /**< rowprep where to add linearization */
4077  SCIP_Bool* success /**< buffer to store whether a linearization was succefully added to the row */
4078  )
4079 {
4080  SCIP_CONSDATA* consdata;
4081  SCIP_EXPRTREE* exprtree;
4082  SCIP_Real treecoef;
4083  SCIP_Real val;
4084  SCIP_Real* grad;
4085  SCIP_Real constant = 0.0;
4086  SCIP_Bool perturbedx;
4087  int nvars;
4088  int i;
4089 
4090  assert(scip != NULL);
4091  assert(cons != NULL);
4092  assert(x != NULL);
4093  assert(rowprep != NULL);
4094  assert(success != NULL);
4095 
4096  consdata = SCIPconsGetData(cons);
4097  assert(consdata != NULL);
4098  assert(exprtreeidx >= 0);
4099  assert(exprtreeidx < consdata->nexprtrees);
4100  assert(consdata->exprtrees != NULL);
4101 
4102  exprtree = consdata->exprtrees[exprtreeidx];
4103  assert(exprtree != NULL);
4104  assert(newx || SCIPexprtreeGetInterpreterData(exprtree) != NULL);
4105 
4106  treecoef = consdata->nonlincoefs[exprtreeidx];
4107 
4108  *success = FALSE;
4109 
4110  /* compile expression if evaluated the first time; can only happen if newx is FALSE */
4111  if( newx && SCIPexprtreeGetInterpreterData(exprtree) == NULL )
4112  {
4113  SCIP_CALL( SCIPexprintCompile(exprint, exprtree) );
4114  }
4115 
4116  nvars = SCIPexprtreeGetNVars(exprtree);
4117  SCIP_CALL( SCIPallocBufferArray(scip, &grad, nvars) );
4118 
4119  perturbedx = FALSE;
4120  do
4121  {
4122  /* get value and gradient */
4123  SCIP_CALL( SCIPexprintGrad(exprint, exprtree, x, newx, &val, grad) );
4124  if( SCIPisFinite(val) && !SCIPisInfinity(scip, REALABS(val)) )
4125  {
4126  val *= treecoef;
4127  /* check gradient entries and compute constant f(refx) - grad * refx */
4128  constant = val;
4129  for( i = 0; i < nvars; ++i )
4130  {
4131  if( !SCIPisFinite(grad[i]) || SCIPisInfinity(scip, grad[i]) || SCIPisInfinity(scip, -grad[i]) )
4132  break;
4133 
4134  grad[i] *= treecoef;
4135  constant -= grad[i] * x[i];
4136 
4137  /* try to perturb x if the constant is too large */
4138  if( SCIPisInfinity(scip, REALABS(constant)) )
4139  break;
4140 
4141  /* coefficients smaller than epsilon are rounded to 0.0 when added to row, this can be wrong if variable value is very large (bad numerics)
4142  * in this case, set gradient to 0.0 here, but modify constant so that cut is still valid (if possible)
4143  * i.e., estimate grad[i]*x >= grad[i] * bound(x) or grad[i]*x <= grad[i] * bound(x), depending on whether we compute an underestimator (convex) or an overestimator (concave)
4144  * if required bound of x is not finite, then give up
4145  */
4146  if( grad[i] != 0.0 && SCIPisZero(scip, grad[i]) )
4147  {
4148  SCIP_VAR* var;
4149  SCIP_Real xbnd;
4150 
4151  var = SCIPexprtreeGetVars(exprtree)[i];
4152  if( consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONVEX )
4153  {
4154  xbnd = grad[i] > 0.0 ? SCIPvarGetLbGlobal(var) : SCIPvarGetUbGlobal(var);
4155  }
4156  else
4157  {
4158  assert(consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONCAVE);
4159  xbnd = grad[i] > 0.0 ? SCIPvarGetUbGlobal(var) : SCIPvarGetLbGlobal(var);
4160  }
4161  if( !SCIPisInfinity(scip, REALABS(xbnd)) )
4162  {
4163  SCIPdebugMsg(scip, "var <%s> [%g,%g] has tiny gradient %g, replace coefficient by constant %g\n",
4164  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), grad[i], grad[i] * xbnd);
4165  constant += grad[i] * xbnd;
4166  grad[i] = 0.0;
4167  }
4168  else
4169  {
4170  *success = FALSE;
4171  SCIPdebugMsg(scip, "skipping linearization, var <%s> [%g,%g] has tiny gradient %g but no finite bound in this direction\n",
4172  SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var), grad[i]);
4173  SCIPfreeBufferArray(scip, &grad);
4174  return SCIP_OKAY;
4175  }
4176  }
4177  }
4178 
4179  if( i == nvars )
4180  break;
4181  }
4182 
4183  SCIPdebugMsg(scip, "got nonfinite value in evaluation or gradient of <%s>: ", SCIPconsGetName(cons));
4184  if( !perturbedx )
4185  {
4186  SCIP_Real lb;
4187  SCIP_Real ub;
4188 
4189  SCIPdebugMsgPrint(scip, "perturbing reference point and trying again\n");
4190  for( i = 0; i < nvars; ++i )
4191  {
4192  lb = SCIPvarGetLbGlobal(SCIPexprtreeGetVars(exprtree)[i]);
4193  ub = SCIPvarGetUbGlobal(SCIPexprtreeGetVars(exprtree)[i]);
4194  if( SCIPisEQ(scip, x[i], lb) )
4195  x[i] += MIN(0.9*(ub-lb), i*SCIPfeastol(scip)); /*lint !e666*/
4196  else if( SCIPisEQ(scip, x[i], ub) )
4197  x[i] -= MIN(0.9*(ub-lb), i*SCIPfeastol(scip)); /*lint !e666*/
4198  else
4199  x[i] += MIN3(0.9*(ub-x[i]), 0.9*(x[i]-lb), i*SCIPfeastol(scip)) * (i%2 != 0 ? -1.0 : 1.0); /*lint !e666*/
4200  }
4201  newx = TRUE;
4202  perturbedx = TRUE;
4203  }
4204  else
4205  {
4206  SCIPdebugMsgPrint(scip, "skipping linearization\n");
4207  SCIPfreeBufferArray(scip, &grad);
4208  return SCIP_OKAY;
4209  }
4210  }
4211  while( TRUE ); /*lint !e506*/
4212 
4213  /* add linearization to SCIP row */
4214  SCIPaddRowprepConstant(rowprep, constant);
4215  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, nvars, SCIPexprtreeGetVars(exprtree), grad) );
4216 
4217  *success = TRUE;
4218 
4219  SCIPfreeBufferArray(scip, &grad);
4220 
4221  SCIPdebugMsg(scip, "added linearization for tree %d of constraint <%s>\n", exprtreeidx, SCIPconsGetName(cons));
4222  SCIPdebug( SCIPprintRowprep(scip, rowprep, NULL) );
4223 
4224  return SCIP_OKAY;
4225 }
4226 
4227 /** adds secant of a constraints univariate expression tree in reference point to a row */
4228 static
4230  SCIP* scip, /**< SCIP data structure */
4231  SCIP_CONS* cons, /**< constraint */
4232  int exprtreeidx, /**< for which tree a secant should be added */
4233  SCIP_ROWPREP* rowprep, /**< rowprep where to add estimator */
4234  SCIP_Bool* success /**< buffer to store whether a secant was succefully added to the row */
4235  )
4236 {
4237  SCIP_CONSDATA* consdata;
4238  SCIP_EXPRTREE* exprtree;
4239  SCIP_Real treecoef;
4240  SCIP_VAR* var;
4241  SCIP_Real xlb;
4242  SCIP_Real xub;
4243  SCIP_Real vallb;
4244  SCIP_Real valub;
4245  SCIP_Real slope;
4246  SCIP_Real constant;
4247 
4248  assert(scip != NULL);
4249  assert(cons != NULL);
4250  assert(rowprep != NULL);
4251  assert(success != NULL);
4252 
4253  consdata = SCIPconsGetData(cons);
4254  assert(consdata != NULL);
4255  assert(exprtreeidx >= 0);
4256  assert(exprtreeidx < consdata->nexprtrees);
4257  assert(consdata->exprtrees != NULL);
4258 
4259  exprtree = consdata->exprtrees[exprtreeidx];
4260  assert(exprtree != NULL);
4261  assert(SCIPexprtreeGetNVars(exprtree) == 1);
4262 
4263  treecoef = consdata->nonlincoefs[exprtreeidx];
4264 
4265  *success = FALSE;
4266 
4267  var = SCIPexprtreeGetVars(exprtree)[0];
4268  xlb = SCIPvarGetLbLocal(var);
4269  xub = SCIPvarGetUbLocal(var);
4270 
4271  /* if variable is unbounded, then cannot really compute secant */
4272  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) )
4273  {
4274  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since variable is unbounded\n", exprtreeidx, SCIPconsGetName(cons));
4275  return SCIP_OKAY;
4276  }
4277  assert(SCIPisLE(scip, xlb, xub));
4278 
4279  /* coverity[callee_ptr_arith] */
4280  SCIP_CALL( SCIPexprtreeEval(exprtree, &xlb, &vallb) );
4281  if( !SCIPisFinite(vallb) || SCIPisInfinity(scip, REALABS(vallb)) )
4282  {
4283  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated in lower bound\n", exprtreeidx, SCIPconsGetName(cons));
4284  return SCIP_OKAY;
4285  }
4286  vallb *= treecoef;
4287 
4288  /* coverity[callee_ptr_arith] */
4289  SCIP_CALL( SCIPexprtreeEval(exprtree, &xub, &valub) );
4290  if( !SCIPisFinite(valub) || SCIPisInfinity(scip, REALABS(valub)) )
4291  {
4292  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated in upper bound\n", exprtreeidx, SCIPconsGetName(cons));
4293  return SCIP_OKAY;
4294  }
4295  valub *= treecoef;
4296 
4297  if( SCIPisEQ(scip, xlb, xub) )
4298  {
4299  slope = 0.0;
4300  /* choose most conservative value for the cut */
4301  if( rowprep->sidetype == SCIP_SIDETYPE_LEFT )
4302  constant = MAX(vallb, valub);
4303  else
4304  constant = MIN(vallb, valub);
4305  }
4306  else
4307  {
4308  slope = (valub - vallb) / (xub - xlb);
4309  constant = vallb - slope * xlb;
4310  }
4311 
4312  /* add secant to SCIP row */
4313  SCIPaddRowprepConstant(rowprep, constant);
4314  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, var, slope) );
4315 
4316  *success = TRUE;
4317 
4318  SCIPdebugMsg(scip, "added secant for tree %d of constraint <%s>, slope = %g\n", exprtreeidx, SCIPconsGetName(cons), slope);
4319  SCIPdebug( SCIPprintRowprep(scip, rowprep, NULL) );
4320 
4321  return SCIP_OKAY;
4322 }
4323 
4324 /** adds estimator of a constraints bivariate expression tree to a row
4325  * a reference point is given to decide which hyperplane to choose
4326  */
4327 static
4329  SCIP* scip, /**< SCIP data structure */
4330  SCIP_CONS* cons, /**< constraint */
4331  int exprtreeidx, /**< for which tree a secant should be added */
4332  SCIP_Real* ref, /**< reference values of expression tree variables where to generate cut */
4333  SCIP_ROWPREP* rowprep, /**< rowprep where to add estimator */
4334  SCIP_Bool* success /**< buffer to store whether a secant was succefully added to the row */
4335  )
4336 {
4337  SCIP_CONSDATA* consdata;
4338  SCIP_EXPRTREE* exprtree;
4339  SCIP_Real treecoef;
4340  SCIP_VAR* x;
4341  SCIP_VAR* y;
4342  SCIP_Real xlb;
4343  SCIP_Real xub;
4344  SCIP_Real ylb;
4345  SCIP_Real yub;
4346 
4347  SCIP_Real coefx;
4348  SCIP_Real coefy;
4349  SCIP_Real constant;
4350 
4351  SCIP_Real p1[2];
4352  SCIP_Real p2[2];
4353  SCIP_Real p3[2];
4354  SCIP_Real p4[2];
4355  SCIP_Real p1val, p2val, p3val, p4val;
4356 
4357  assert(scip != NULL);
4358  assert(cons != NULL);
4359  assert(ref != NULL);
4360  assert(rowprep != NULL);
4361  assert(success != NULL);
4362 
4363  consdata = SCIPconsGetData(cons);
4364  assert(consdata != NULL);
4365  assert(exprtreeidx >= 0);
4366  assert(exprtreeidx < consdata->nexprtrees);
4367  assert(consdata->exprtrees != NULL);
4368 
4369  exprtree = consdata->exprtrees[exprtreeidx];
4370  assert(exprtree != NULL);
4371  assert(SCIPexprtreeGetNVars(exprtree) == 2);
4372 
4373  treecoef = consdata->nonlincoefs[exprtreeidx];
4374 
4375  *success = FALSE;
4376 
4377  x = SCIPexprtreeGetVars(exprtree)[0];
4378  y = SCIPexprtreeGetVars(exprtree)[1];
4379  xlb = SCIPvarGetLbLocal(x);
4380  xub = SCIPvarGetUbLocal(x);
4381  ylb = SCIPvarGetLbLocal(y);
4382  yub = SCIPvarGetUbLocal(y);
4383 
4384  if( SCIPisInfinity(scip, -xlb) || SCIPisInfinity(scip, xub) || SCIPisInfinity(scip, -ylb) || SCIPisInfinity(scip, yub) )
4385  {
4386  SCIPdebugMsg(scip, "skip bivariate secant since <%s> or <%s> is unbounded\n", SCIPvarGetName(x), SCIPvarGetName(y));
4387  return SCIP_OKAY;
4388  }
4389 
4390  /* reference point should not be outside of bounds */
4391  assert(SCIPisFeasLE(scip, xlb, ref[0]));
4392  assert(SCIPisFeasGE(scip, xub, ref[0]));
4393  ref[0] = MIN(xub, MAX(xlb, ref[0]));
4394  assert(SCIPisFeasLE(scip, ylb, ref[1]));
4395  assert(SCIPisFeasGE(scip, yub, ref[1]));
4396  ref[1] = MIN(yub, MAX(ylb, ref[1]));
4397 
4398  /* lower left */
4399  p1[0] = xlb;
4400  p1[1] = ylb;
4401 
4402  /* lower right */
4403  p2[0] = xub;
4404  p2[1] = ylb;
4405 
4406  /* upper right */
4407  p3[0] = xub;
4408  p3[1] = yub;
4409 
4410  /* upper left */
4411  p4[0] = xlb;
4412  p4[1] = yub;
4413 
4414  if( SCIPisEQ(scip, xlb, xub) && SCIPisEQ(scip, ylb, yub) )
4415  {
4416  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4417 
4418  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) )
4419  {
4420  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4421  return SCIP_OKAY;
4422  }
4423 
4424  p1val *= treecoef;
4425 
4426  coefx = 0.0;
4427  coefy = 0.0;
4428  constant = p1val;
4429  }
4430  else if( SCIPisEQ(scip, xlb, xub) )
4431  {
4432  /* secant between p1 and p4: p1val + [(p4val - p1val) / (yub - ylb)] * (y - ylb) */
4433  assert(!SCIPisEQ(scip, ylb, yub));
4434 
4435  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4436  SCIP_CALL( SCIPexprtreeEval(exprtree, p4, &p4val) );
4437  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p4val) || SCIPisInfinity(scip, REALABS(p4val)) )
4438  {
4439  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4440  return SCIP_OKAY;
4441  }
4442  p1val *= treecoef;
4443  p4val *= treecoef;
4444 
4445  coefx = 0.0;
4446  coefy = (p4val - p1val) / (yub - ylb);
4447  constant = p1val - coefy * ylb;
4448  }
4449  else if( SCIPisEQ(scip, ylb, yub) )
4450  {
4451  /* secant between p1 and p2: p1val + [(p2val - p1val) / (xub - xlb)] * (x - xlb) */
4452  assert(!SCIPisEQ(scip, xlb, xub));
4453 
4454  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4455  SCIP_CALL( SCIPexprtreeEval(exprtree, p2, &p2val) );
4456  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p2val) || SCIPisInfinity(scip, REALABS(p2val)) )
4457  {
4458  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4459  return SCIP_OKAY;
4460  }
4461 
4462  p1val *= treecoef;
4463  p2val *= treecoef;
4464 
4465  coefx = (p2val - p1val) / (xub - xlb);
4466  coefy = 0.0;
4467  constant = p1val - coefx * xlb;
4468  }
4469  else
4470  {
4471  SCIP_Real alpha, beta, gamma_, delta;
4472  SCIP_Bool tryother;
4473  SCIP_Bool doover;
4474 
4475  /* if function is convex, then we want an overestimator, otherwise we want an underestimator */
4476  assert(consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONVEX || consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONCAVE);
4477  doover = (consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONVEX); /*lint !e641*/
4478 
4479  SCIP_CALL( SCIPexprtreeEval(exprtree, p1, &p1val) );
4480  SCIP_CALL( SCIPexprtreeEval(exprtree, p2, &p2val) );
4481  SCIP_CALL( SCIPexprtreeEval(exprtree, p3, &p3val) );
4482  SCIP_CALL( SCIPexprtreeEval(exprtree, p4, &p4val) );
4483  if( !SCIPisFinite(p1val) || SCIPisInfinity(scip, REALABS(p1val)) || !SCIPisFinite(p2val) || SCIPisInfinity(scip, REALABS(p2val)) ||
4484  ! SCIPisFinite(p3val) || SCIPisInfinity(scip, REALABS(p3val)) || !SCIPisFinite(p4val) || SCIPisInfinity(scip, REALABS(p4val)) )
4485  {
4486  SCIPdebugMsg(scip, "skip secant for tree %d of constraint <%s> since function cannot be evaluated\n", exprtreeidx, SCIPconsGetName(cons));
4487  return SCIP_OKAY;
4488  }
4489  p1val *= treecoef;
4490  p2val *= treecoef;
4491  p3val *= treecoef;
4492  p4val *= treecoef;
4493 
4494  /* if we want an underestimator, flip f(x,y), i.e., do as if we compute an overestimator for -f(x,y) */
4495  if( !doover )
4496  {
4497  p1val = -p1val;
4498  p2val = -p2val;
4499  p3val = -p3val;
4500  p4val = -p4val;
4501  }
4502 
4503  SCIPdebugMsg(scip, "p1 = (%g, %g), f(p1) = %g\n", p1[0], p1[1], p1val);
4504  SCIPdebugMsg(scip, "p2 = (%g, %g), f(p2) = %g\n", p2[0], p2[1], p2val);
4505  SCIPdebugMsg(scip, "p3 = (%g, %g), f(p3) = %g\n", p3[0], p3[1], p3val);
4506  SCIPdebugMsg(scip, "p4 = (%g, %g), f(p4) = %g\n", p4[0], p4[1], p4val);
4507 
4508  /* Compute coefficients alpha, beta, gamma (>0), delta such that
4509  * alpha*x + beta*y + gamma*z = delta
4510  * is satisfied by at least three of the corner points (p1,f(p1)), ..., (p4,f(p4)) and
4511  * the fourth corner point lies below this hyperplane.
4512  * Since we assume that f is convex, we then know that all points (x,y,f(x,y)) are below this hyperplane, i.e.,
4513  * alpha*x + beta*y - delta <= -gamma * f(x,y),
4514  * or, equivalently,
4515  * -alpha/gamma*x - beta/gamma*y + delta/gamma >= f(x,y).
4516  */
4517 
4518  tryother = FALSE;
4519  if( ref[1] <= ylb + (yub - ylb)/(xub - xlb) * (ref[0] - xlb) )
4520  {
4521  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1], p3val,
4522  &alpha, &beta, &gamma_, &delta) );
4523 
4524  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] - delta, -gamma_ * p1val));
4525  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] - delta, -gamma_ * p2val));
4526  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] - delta, -gamma_ * p3val));
4527 
4528  /* if hyperplane through p1,p2,p3 does not overestimate f(p4), then it must be the other variant */
4529  if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val > delta )
4530  tryother = TRUE;
4531  else if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4532  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4533  {
4534  /* if numerically bad, take alternative hyperplane */
4535  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1],
4536  p4val, &alpha, &beta, &gamma_, &delta) );
4537 
4538  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] - delta, -gamma_ * p1val));
4539  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] - delta, -gamma_ * p3val));
4540  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] - delta, -gamma_ * p4val));
4541 
4542  /* if hyperplane through p1,p3,p4 does not overestimate f(p2), then it must be the other variant */
4543  if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val > delta )
4544  tryother = TRUE;
4545  }
4546  }
4547  else
4548  {
4549  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p3[0], p3[1], p3val, p4[0], p4[1], p4val,
4550  &alpha, &beta, &gamma_, &delta) );
4551 
4552  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] - delta, -gamma_ * p1val));
4553  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] - delta, -gamma_ * p3val));
4554  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] - delta, -gamma_ * p4val));
4555 
4556  /* if hyperplane through p1,p3,p4 does not overestimate f(p2), then it must be the other variant */
4557  if( alpha * p2[0] + beta * p2[1] + gamma_ * p2val > delta )
4558  tryother = TRUE;
4559  else if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4560  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4561  {
4562  /* if numerically bad, take alternative */
4563  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p3[0], p3[1],
4564  p3val, &alpha, &beta, &gamma_, &delta) );
4565 
4566  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] - delta, -gamma_ * p1val));
4567  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] - delta, -gamma_ * p2val));
4568  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] - delta, -gamma_ * p3val));
4569 
4570  /* if hyperplane through p1,p2,p3 does not overestimate f(p4), then it must be the other variant */
4571  if( alpha * p4[0] + beta * p4[1] + gamma_ * p4val > delta )
4572  tryother = TRUE;
4573  }
4574  }
4575 
4576  if( tryother )
4577  {
4578  if( ref[1] <= yub + (ylb - yub)/(xub - xlb) * (ref[0] - xlb) )
4579  {
4580  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1],
4581  p4val, &alpha, &beta, &gamma_, &delta) );
4582 
4583  /* hyperplane should be above (p3,f(p3)) and other points should lie on hyperplane */
4584  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] - delta, -gamma_ * p1val));
4585  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] - delta, -gamma_ * p2val));
4586  assert(SCIPisRelLE(scip, alpha * p3[0] + beta * p3[1] - delta, -gamma_ * p3val));
4587  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] - delta, -gamma_ * p4val));
4588 
4589  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4590  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4591  {
4592  /* if numerically bad, take alternative */
4593  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1],
4594  p4val, &alpha, &beta, &gamma_, &delta) );
4595 
4596  /* hyperplane should be above (p1,f(p1)) and other points should lie on hyperplane */
4597  assert(SCIPisRelLE(scip, alpha * p1[0] + beta * p1[1] - delta, -gamma_ * p1val));
4598  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] - delta, -gamma_ * p2val));
4599  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] - delta, -gamma_ * p3val));
4600  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] - delta, -gamma_ * p4val));
4601  }
4602  }
4603  else
4604  {
4605  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p2[0], p2[1], p2val, p3[0], p3[1], p3val, p4[0], p4[1],
4606  p4val, &alpha, &beta, &gamma_, &delta) );
4607 
4608  /* hyperplane should be above (p1,f(p1)) and other points should lie on hyperplane */
4609  assert(SCIPisRelLE(scip, alpha * p1[0] + beta * p1[1] - delta, -gamma_ * p1val));
4610  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] - delta, -gamma_ * p2val));
4611  assert(SCIPisRelEQ(scip, alpha * p3[0] + beta * p3[1] - delta, -gamma_ * p3val));
4612  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] - delta, -gamma_ * p4val));
4613 
4614  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, alpha/gamma_)) ||
4615  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, beta /gamma_)) )
4616  {
4617  /* if numerically bad, take alternative */
4618  SCIP_CALL( SCIPcomputeHyperplaneThreePoints(scip, p1[0], p1[1], p1val, p2[0], p2[1], p2val, p4[0], p4[1],
4619  p4val, &alpha, &beta, &gamma_, &delta) );
4620 
4621  /* hyperplane should be above (p3,f(p3)) and other points should lie on hyperplane */
4622  assert(SCIPisRelEQ(scip, alpha * p1[0] + beta * p1[1] - delta, -gamma_ * p1val));
4623  assert(SCIPisRelEQ(scip, alpha * p2[0] + beta * p2[1] - delta, -gamma_ * p2val));
4624  assert(SCIPisRelLE(scip, alpha * p3[0] + beta * p3[1] - delta, -gamma_ * p3val));
4625  assert(SCIPisRelEQ(scip, alpha * p4[0] + beta * p4[1] - delta, -gamma_ * p4val));
4626  }
4627  }
4628  }
4629 
4630  SCIPdebugMsg(scip, "alpha = %g, beta = %g, gamma = %g, delta = %g\n", alpha, beta, gamma_, delta);
4631 
4632  /* check if bad luck: should not happen if xlb != xub and ylb != yub and numerics are fine */
4633  if( SCIPisZero(scip, gamma_) )
4634  return SCIP_OKAY;
4635  assert(!SCIPisNegative(scip, gamma_));
4636 
4637  /* flip hyperplane */
4638  if( !doover )
4639  gamma_ = -gamma_;
4640 
4641  coefx = -alpha / gamma_;
4642  coefy = -beta / gamma_;
4643  constant = delta / gamma_;
4644 
4645  /* if we loose coefficients because division by gamma makes them < SCIPepsilon(scip), then better not generate a cut here */
4646  if( (!SCIPisZero(scip, alpha) && SCIPisZero(scip, coefx)) ||
4647  ( !SCIPisZero(scip, beta) && SCIPisZero(scip, coefy)) )
4648  {
4649  SCIPdebugMsg(scip, "skip bivar secant for <%s> tree %d due to bad numerics\n", SCIPconsGetName(cons), exprtreeidx);
4650  return SCIP_OKAY;
4651  }
4652  }
4653 
4654  /* add hyperplane coefs to SCIP row */
4655  SCIPaddRowprepConstant(rowprep, constant);
4656  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, x, coefx) );
4657  SCIP_CALL( SCIPaddRowprepTerm(scip, rowprep, y, coefy) );
4658 
4659  *success = TRUE;
4660 
4661  SCIPdebugMsg(scip, "added bivariate secant for tree %d of constraint <%s>\n", exprtreeidx, SCIPconsGetName(cons));
4662  SCIPdebug( SCIPprintRowprep(scip, rowprep, NULL) );
4663 
4664  return SCIP_OKAY;
4665 }
4666 
4667 /** internal method using an auxiliary LPI, see addConcaveEstimatorMultivariate() */
4668 static
4669 SCIP_RETCODE _addConcaveEstimatorMultivariate(
4670  SCIP* scip, /**< SCIP data structure */
4671  SCIP_LPI* lpi, /**< auxiliary LPI */
4672  SCIP_CONS* cons, /**< constraint */
4673  int exprtreeidx, /**< for which tree a secant should be added */
4674  SCIP_Real* ref, /**< reference values of expression tree variables where to generate cut */
4675  SCIP_ROWPREP* rowprep, /**< rowprep where to add estimator */
4676  SCIP_VAR** vars, /**< variables of the constraint */
4677  SCIP_EXPRTREE* exprtree, /**< expression tree of constraint */
4678  int nvars, /**< number of variables */
4679  SCIP_Bool doupper, /**< should an upper estimator be computed */
4680  SCIP_Bool* success /**< buffer to store whether a secant was succefully added to the row */
4681  )
4682 {
4683  SCIP_CONSDATA* consdata;
4684  SCIP_Real* val;
4685  SCIP_Real* obj;
4686  SCIP_Real* lb;
4687  SCIP_Real* ub;
4688  SCIP_Real* corner;
4689  SCIP_Real* lhs;
4690  SCIP_Real* rhs;
4691  int* beg;
4692  int* ind;
4693  SCIP_Real lpobj;
4694  int ncols;
4695  int nrows;
4696  int nnonz;
4697  SCIP_Real funcval;
4698  SCIP_Real treecoef;
4699 
4700  int i;
4701  int j;
4702  int idx;
4703 
4704  SCIP_RETCODE lpret;
4705 
4706  assert(lpi != NULL);
4707  assert(nvars <= 10);
4708 
4709  consdata = SCIPconsGetData(cons);
4710  treecoef = consdata->nonlincoefs[exprtreeidx];
4711 
4712  /* columns are cut coefficients plus constant */
4713  ncols = nvars + 1;
4714  SCIP_CALL( SCIPallocBufferArray(scip, &obj, ncols) );
4715  SCIP_CALL( SCIPallocBufferArray(scip, &lb, ncols) );
4716  SCIP_CALL( SCIPallocBufferArray(scip, &ub, ncols) );
4717  corner = lb; /* will not use lb and corner simultaneously, so can share memory */
4718 
4719  /* one row for each corner of domain, i.e., 2^nvars many */
4720  nrows = (int)(1u << nvars);
4721  SCIP_CALL( SCIPallocBufferArray(scip, &lhs, nrows) );
4722  SCIP_CALL( SCIPallocBufferArray(scip, &rhs, nrows) );
4723 
4724  /* the coefficients matrix will have at most ncols * nrows many nonzeros */
4725  nnonz = nrows * ncols;
4726  SCIP_CALL( SCIPallocBufferArray(scip, &beg, nrows+1) );
4727  SCIP_CALL( SCIPallocBufferArray(scip, &ind, nnonz) );
4728  SCIP_CALL( SCIPallocBufferArray(scip, &val, nnonz) );
4729 
4730  /* setup LP data */
4731  idx = 0;
4732  for( i = 0; i < nrows; ++i )
4733  {
4734  /* assemble corner point */
4735  SCIPdebugMsg(scip, "f(");
4736  for( j = 0; j < nvars; ++j )
4737  {
4738  /* if j'th bit of row index i is set, then take upper bound on var j, otherwise lower bound var j
4739  * we check this by shifting i for j positions to the right and checking whether the j'th bit is set */
4740  if( ((unsigned int)i >> j) & 0x1 )
4741  corner[j] = SCIPvarGetUbLocal(vars[j]);
4742  else
4743  corner[j] = SCIPvarGetLbLocal(vars[j]);
4744  SCIPdebugMsgPrint(scip, "%g, ", corner[j]);
4745  assert(!SCIPisInfinity(scip, REALABS(corner[j])));
4746  }
4747 
4748  /* evaluate function in current corner */
4749  SCIP_CALL( SCIPexprtreeEval(exprtree, corner, &funcval) );
4750  SCIPdebugMsgPrint(scip, ") = %g\n", funcval);
4751 
4752  if( !SCIPisFinite(funcval) || SCIPisInfinity(scip, REALABS(funcval)) )
4753  {
4754  SCIPdebugMsg(scip, "cannot compute underestimator for concave because constaint <%s> cannot be evaluated\n", SCIPconsGetName(cons));
4755  goto TERMINATE;
4756  }
4757 
4758  funcval *= treecoef;
4759 
4760  if( !doupper )
4761  {
4762  lhs[i] = -SCIPlpiInfinity(lpi);
4763  rhs[i] = funcval;
4764  }
4765  else
4766  {
4767  lhs[i] = funcval;
4768  rhs[i] = SCIPlpiInfinity(lpi);
4769  }
4770 
4771  /* add nonzeros of corner to matrix */
4772  beg[i] = idx;
4773  for( j = 0; j < nvars; ++j )
4774  {
4775  if( corner[j] != 0.0 )
4776  {
4777  ind[idx] = j;
4778  val[idx] = corner[j];
4779  ++idx;
4780  }
4781  }
4782 
4783  /* coefficient for constant is 1.0 */
4784  val[idx] = 1.0;
4785  ind[idx] = nvars;
4786  ++idx;
4787  }
4788  nnonz = idx;
4789  beg[nrows] = nnonz;
4790 
4791  for( j = 0; j < ncols; ++j )
4792  {
4793  lb[j] = -SCIPlpiInfinity(lpi);
4794  ub[j] = SCIPlpiInfinity(lpi);
4795  }
4796 
4797  /* objective coefficients are reference points, and an additional 1.0 for the constant */
4798  BMScopyMemoryArray(obj, ref, nvars);
4799  obj[nvars] = 1.0;
4800 
4801  /* get function value in reference point, so we can use this as a cutoff */
4802  SCIP_CALL( SCIPexprtreeEval(exprtree, ref, &funcval) );
4803  funcval *= treecoef;
4804 
4805  SCIP_CALL( SCIPlpiAddCols(lpi, ncols, obj, lb, ub, NULL, 0, NULL, NULL, NULL) );
4806  SCIP_CALL( SCIPlpiAddRows(lpi, nrows, lhs, rhs, NULL, nnonz, beg, ind, val) );
4807 
4808  /* make use of this convenient features, since for us nrows >> ncols */
4809  /*SCIP_CALL( SCIPlpiSetRealpar(lpi, SCIP_LPPAR_ROWREPSWITCH, 5.0) ); */
4810  /* get accurate coefficients */
4812  SCIP_CALL( SCIPlpiSetRealpar(lpi, SCIP_LPPAR_OBJLIM, funcval) );
4813  SCIP_CALL( SCIPlpiSetIntpar(lpi, SCIP_LPPAR_LPITLIM, 10 * nvars) );
4816 
4817  /* SCIPdebug( SCIP_CALL( SCIPlpiSetIntpar(lpi, SCIP_LPPAR_LPINFO, 1) ) ); */
4818 
4819  lpret = SCIPlpiSolveDual(lpi);
4820  if( lpret != SCIP_OKAY )
4821  {
4822  SCIPwarningMessage(scip, "solving auxiliary LP for underestimator of concave function returned %d\n", lpret);
4823  goto TERMINATE;
4824  }
4825 
4826  if( !SCIPlpiIsPrimalFeasible(lpi) )
4827  {
4828  SCIPdebugMsg(scip, "failed to find feasible solution for auxiliary LP for underestimator of concave function, iterlimexc = %u, cutoff = %u, unbounded = %u\n", SCIPlpiIsIterlimExc(lpi), SCIPlpiIsObjlimExc(lpi), SCIPlpiIsPrimalUnbounded(lpi));
4829  goto TERMINATE;
4830  }
4831  /* should be either solved to optimality, or the objective or iteration limit be hit */
4832  assert(SCIPlpiIsOptimal(lpi) || SCIPlpiIsObjlimExc(lpi) || SCIPlpiIsIterlimExc(lpi));
4833 
4834  /* setup row coefficient, reuse obj array to store LP sol values */
4835  SCIP_CALL( SCIPlpiGetSol(lpi, &lpobj, obj, NULL, NULL, NULL) );
4836 
4837  /* check that computed hyperplane is on right side of function in refpoint
4838  * if numerics is very bad (e.g., st_e32), then even this can happen */
4839  if( (!doupper && SCIPisFeasGT(scip, lpobj, funcval)) || (doupper && SCIPisFeasGT(scip, funcval, lpobj)) )
4840  {
4841  SCIPwarningMessage(scip, "computed cut does not underestimate concave function in refpoint\n");
4842  goto TERMINATE;
4843  }
4844  assert( doupper || SCIPisFeasLE(scip, lpobj, funcval) );
4845  assert(!doupper || SCIPisFeasLE(scip, funcval, lpobj) );
4846 
4847  /* add estimator to rowprep */
4848  SCIPaddRowprepConstant(rowprep, obj[nvars]);
4849  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, nvars, vars, obj) );
4850 
4851  *success = TRUE;
4852 
4853 TERMINATE:
4854  SCIPfreeBufferArray(scip, &val);
4855  SCIPfreeBufferArray(scip, &ind);
4856  SCIPfreeBufferArray(scip, &beg);
4857  SCIPfreeBufferArray(scip, &rhs);
4858  SCIPfreeBufferArray(scip, &lhs);
4859  SCIPfreeBufferArray(scip, &ub);
4860  SCIPfreeBufferArray(scip, &lb);
4861  SCIPfreeBufferArray(scip, &obj);
4862 
4863  return SCIP_OKAY;
4864 }
4865 
4866 
4867 
4868 /** adds estimator of a constraints multivariate expression tree to a row
4869  * Given concave function f(x) and reference point ref.
4870  * Let (v_i: i=1,...,n) be corner points of current domain of x.
4871  * Find (coef,constant) such that <coef,v_i> + constant <= f(v_i) (cut validity) and
4872  * such that <coef, ref> + constant is maximized (cut efficacy).
4873  * Then <coef, x> + constant <= f(x) for all x in current domain.
4874  *
4875  * Similar to compute an overestimator for a convex function f(x).
4876  * Find (coef,constant) such that <coef,v_i> + constant >= f(v_i) and
4877  * such that <coef, ref> + constant is minimized.
4878  * Then <coef, x> + constant >= f(x) for all x in current domain.
4879  */
4880 static
4882  SCIP* scip, /**< SCIP data structure */
4883  SCIP_CONS* cons, /**< constraint */
4884  int exprtreeidx, /**< for which tree a secant should be added */
4885  SCIP_Real* ref, /**< reference values of expression tree variables where to generate cut */
4886  SCIP_ROWPREP* rowprep, /**< rowprep where to add estimator */
4887  SCIP_Bool* success /**< buffer to store whether a secant was succefully added to the row */
4888  )
4889 {
4890  SCIP_VAR** vars;
4891  SCIP_CONSDATA* consdata;
4892  SCIP_EXPRTREE* exprtree;
4893  SCIP_LPI* lpi;
4894  int nvars;
4895  int j;
4896  SCIP_Bool doupper;
4897 
4898  SCIP_RETCODE retcode;
4899 
4900  static SCIP_Bool warned_highdim_concave = FALSE;
4901 
4902  assert(scip != NULL);
4903  assert(cons != NULL);
4904  assert(ref != NULL);
4905  assert(rowprep != NULL);
4906  assert(success != NULL);
4907 
4908  consdata = SCIPconsGetData(cons);
4909  assert(consdata != NULL);
4910  assert(exprtreeidx >= 0);
4911  assert(exprtreeidx < consdata->nexprtrees);
4912  assert(consdata->exprtrees != NULL);
4913 
4914  exprtree = consdata->exprtrees[exprtreeidx];
4915  assert(exprtree != NULL);
4916 
4917  nvars = SCIPexprtreeGetNVars(exprtree);
4918  assert(nvars >= 2);
4919 
4920  *success = FALSE;
4921 
4922  /* size of LP is exponential in number of variables of tree, so do only for small trees */
4923  if( nvars > 10 )
4924  {
4925  if( !warned_highdim_concave )
4926  {
4927  SCIPwarningMessage(scip, "concave function in constraint <%s> too high-dimensional to compute underestimator\n", SCIPconsGetName(cons));
4928  warned_highdim_concave = TRUE;
4929  }
4930  return SCIP_OKAY;
4931  }
4932 
4933  vars = SCIPexprtreeGetVars(exprtree);
4934 
4935  /* check whether bounds are finite
4936  * make sure reference point is strictly within bounds
4937  * otherwise we can easily get an unbounded LP below, e.g., with instances like ex6_2_* from GlobalLib
4938  */
4939  for( j = 0; j < nvars; ++j )
4940  {
4941  if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(vars[j])) || SCIPisInfinity(scip, SCIPvarGetUbLocal(vars[j])) )
4942  {
4943  SCIPdebugMsg(scip, "cannot compute underestimator for concave because variable <%s> is unbounded\n", SCIPvarGetName(vars[j]));
4944  return SCIP_OKAY;
4945  }
4946  assert(SCIPisFeasLE(scip, SCIPvarGetLbLocal(vars[j]), ref[j]));
4947  assert(SCIPisFeasGE(scip, SCIPvarGetUbLocal(vars[j]), ref[j]));
4948  ref[j] = MIN(SCIPvarGetUbLocal(vars[j]), MAX(SCIPvarGetLbLocal(vars[j]), ref[j])); /*lint !e666*/
4949  }
4950 
4951  /* create empty auxiliary LP and decide its objective sense */
4952  assert(consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONVEX || consdata->curvatures[exprtreeidx] == SCIP_EXPRCURV_CONCAVE);
4953  doupper = (consdata->curvatures[exprtreeidx] & SCIP_EXPRCURV_CONVEX); /*lint !e641*/
4954  SCIP_CALL( SCIPlpiCreate(&lpi, SCIPgetMessagehdlr(scip), "concaveunderest", doupper ? SCIP_OBJSEN_MINIMIZE : SCIP_OBJSEN_MAXIMIZE) );
4955  if( lpi == NULL )
4956  {
4957  SCIPerrorMessage("failed to create auxiliary LP\n");
4958  return SCIP_ERROR;
4959  }
4960 
4961  /* capture the retcode, free the LPI afterwards */
4962  retcode = _addConcaveEstimatorMultivariate(scip, lpi, cons, exprtreeidx, ref, rowprep, vars, exprtree, nvars, doupper, success);
4963 
4964  assert(lpi != NULL);
4965  SCIP_CALL( SCIPlpiFree(&lpi) );
4966 
4967  return retcode;
4968 }
4969 
4970 /** Computes the linear coeffs and the constant in a linear expression
4971  * both scaled by a given scalar value.
4972  * The coeffs of the variables will be stored in the given array at
4973  * their variable index.
4974  * The constant of the given linear expression will be added to the given
4975  * buffer.
4976  */
4977 static
4979  SCIP_EXPR* expr, /**< the linear expression */
4980  SCIP_Real scalar, /**< the scalar value, i.e. the coeff of the given expression */
4981  SCIP_Real* varcoeffs, /**< buffer array to store the computed coefficients */
4982  SCIP_Real* constant /**< buffer to hold the constant value of the given expression */
4983  )
4984 {
4985  switch( SCIPexprGetOperator( expr ) )
4986  {
4987  case SCIP_EXPR_VARIDX: /* set coeff for this variable to current scalar */
4988  {
4989  /* TODO: can a linear expression contain the same variable twice?
4990  * if yes varcoeffs need to be initialized to zero before calling this function
4991  * and coeff must not be overridden but summed up instead. */
4992  varcoeffs[SCIPexprGetOpIndex( expr )] = scalar;
4993  return SCIP_OKAY;
4994  }
4995 
4996  case SCIP_EXPR_CONST:
4997  {
4998  /* constant value increases */
4999  *constant += scalar * SCIPexprGetOpReal( expr );
5000  return SCIP_OKAY;
5001  }
5002 
5003  case SCIP_EXPR_MUL: /* need to find the constant part of the muliplication and then recurse */
5004  {
5005  SCIP_EXPR** children;
5006  children = SCIPexprGetChildren( expr );
5007 
5008  /* first part is constant */
5009  if( SCIPexprGetOperator( children[0] ) == SCIP_EXPR_CONST )
5010  {
5011  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[1], scalar * SCIPexprGetOpReal( children[0] ), varcoeffs, constant ) );
5012  return SCIP_OKAY;
5013  }
5014 
5015  /* second part is constant */
5016  if( SCIPexprGetOperator( children[1] ) == SCIP_EXPR_CONST )
5017  {
5018  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[0], scalar * SCIPexprGetOpReal( children[1] ), varcoeffs, constant ) );
5019  return SCIP_OKAY;
5020  }
5021 
5022  /* nonlinear -> break out to error case */
5023  break;
5024  }
5025 
5026  case SCIP_EXPR_PLUS: /* just recurse */
5027  {
5028  SCIP_EXPR** children;
5029  children = SCIPexprGetChildren( expr );
5030  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[0], scalar, varcoeffs, constant ) );
5031  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[1], scalar, varcoeffs, constant ) );
5032  return SCIP_OKAY;
5033  }
5034 
5035  case SCIP_EXPR_MINUS: /* recursion on second child is called with negated scalar */
5036  {
5037  SCIP_EXPR** children;
5038  children = SCIPexprGetChildren( expr );
5039  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[0], scalar, varcoeffs, constant ) );
5040  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[1], -scalar, varcoeffs, constant ) );
5041  return SCIP_OKAY;
5042  }
5043 
5044  case SCIP_EXPR_SUM: /* just recurse */
5045  {
5046  SCIP_EXPR** children;
5047  int nchildren;
5048  int c;
5049 
5050  children = SCIPexprGetChildren(expr);
5051  nchildren = SCIPexprGetNChildren(expr);
5052 
5053  for( c = 0; c < nchildren; ++c )
5054  {
5055  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[c], scalar, varcoeffs, constant ) );
5056  }
5057 
5058  return SCIP_OKAY;
5059  }
5060 
5061  case SCIP_EXPR_LINEAR: /* add scaled constant and recurse on children with their coeff multiplied into scalar */
5062  {
5063  SCIP_Real* childCoeffs;
5064  SCIP_EXPR** children;
5065  int i;
5066 
5067  *constant += scalar * SCIPexprGetLinearConstant( expr );
5068 
5069  children = SCIPexprGetChildren( expr );
5070  childCoeffs = SCIPexprGetLinearCoefs( expr );
5071 
5072  for( i = 0; i < SCIPexprGetNChildren( expr ); ++i )
5073  {
5074  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[i], scalar * childCoeffs[i], varcoeffs, constant ) );
5075  }
5076 
5077  return SCIP_OKAY;
5078  }
5079 
5080  default:
5081  break;
5082  } /*lint !e788*/
5083 
5084  SCIPerrorMessage( "Cannot extract linear coefficients from expressions with operator %d %s\n", SCIPexprGetOperator( expr ), SCIPexpropGetName(SCIPexprGetOperator( expr )));
5085  SCIPABORT();
5086  return SCIP_ERROR; /*lint !e527*/
5087 }
5088 
5089 /** adds estimator from user callback of a constraints user expression tree to a row
5090  */
5091 static
5093  SCIP* scip, /**< SCIP data structure */
5094  SCIP_CONS* cons, /**< constraint */
5095  int exprtreeidx, /**< for which tree an estimator should be added */
5096  SCIP_Real* x, /**< value of expression tree variables where to generate cut */
5097  SCIP_Bool overestimate, /**< whether to compute an overestimator instead of an underestimator */
5098  SCIP_ROWPREP* rowprep, /**< rowprep where to add estimator */
5099  SCIP_Bool* success /**< buffer to store whether an estimator was succefully added to the rowprep */
5100  )
5101 {
5102  SCIP_CONSDATA* consdata;
5103  SCIP_EXPRTREE* exprtree;
5104  SCIP_EXPR** children;
5105  SCIP_VAR** vars;
5106  SCIP_Real* params;
5107  SCIP_INTERVAL* varbounds;
5108 
5109  SCIP_INTERVAL* childbounds;
5110  SCIP_Real* childvals;
5111  SCIP_Real* childcoeffs;
5112 
5113  SCIP_Real constant;
5114  SCIP_Real treecoef;
5115  int nvars;
5116  int nchildren;
5117  int i;
5118 
5119  consdata = SCIPconsGetData( cons );
5120  assert( consdata != NULL );
5121  assert( exprtreeidx >= 0 );
5122  assert( exprtreeidx < consdata->nexprtrees );
5123  assert( consdata->exprtrees != NULL );
5124  assert( rowprep != NULL );
5125  assert( success != NULL );
5126 
5127  exprtree = consdata->exprtrees[exprtreeidx];
5128  assert( exprtree != NULL );
5129  assert( SCIPexprGetOperator(SCIPexprtreeGetRoot(exprtree)) == SCIP_EXPR_USER );
5130 
5131  /* if user did not implement estimator callback, then we cannot do anything */
5133  {
5134  *success = FALSE;
5135  return SCIP_OKAY;
5136  }
5137 
5138  params = SCIPexprtreeGetParamVals( exprtree );
5139  nvars = SCIPexprtreeGetNVars( exprtree );
5140  vars = SCIPexprtreeGetVars( exprtree );
5141  nchildren = SCIPexprGetNChildren( SCIPexprtreeGetRoot( exprtree ) );
5142  children = SCIPexprGetChildren( SCIPexprtreeGetRoot( exprtree ) );
5143 
5144  /* Get bounds of variables */
5145  SCIP_CALL( SCIPallocBufferArray( scip, &varbounds, nchildren ) );
5146 
5147  for( i = 0; i < nvars; ++i )
5148  {
5149  double lb = SCIPvarGetLbLocal( vars[i] );
5150  double ub = SCIPvarGetUbLocal( vars[i] );
5151  SCIPintervalSetBounds( &varbounds[i],
5152  -infty2infty( SCIPinfinity( scip ), INTERVALINFTY, -MIN( lb, ub ) ),
5153  +infty2infty( SCIPinfinity( scip ), INTERVALINFTY, MAX( lb, ub ) ) );
5154  }
5155 
5156  /* Compute bounds and solution value for the user expressions children */
5157  SCIP_CALL( SCIPallocBufferArray( scip, &childcoeffs, nchildren ) );
5158  SCIP_CALL( SCIPallocBufferArray( scip, &childbounds, nchildren ) );
5159  SCIP_CALL( SCIPallocBufferArray( scip, &childvals, nchildren ) );
5160 
5161  for( i = 0; i < nchildren; ++i )
5162  {
5163  SCIP_CALL( SCIPexprEval( children[i], x, params, &childvals[i] ) );
5164  SCIP_CALL( SCIPexprEvalInt( children[i], INTERVALINFTY, varbounds, params, &childbounds[i] ) );
5165  }
5166 
5167  /* varbounds not needed any longer */
5168  SCIPfreeBufferArray( scip, &varbounds );
5169 
5170  /* call estimator for user expressions to compute coeffs and constant for the user expressions children */
5171  SCIP_CALL( SCIPexprEstimateUser( SCIPexprtreeGetRoot( exprtree ), INTERVALINFTY, childvals, childbounds, overestimate, childcoeffs, &constant, success ) );
5172 
5173  if( *success )
5174  {
5175  SCIP_Real* varcoeffs;
5176  SCIP_CALL( SCIPallocBufferArray( scip, &varcoeffs, nvars ) );
5177 
5178  treecoef = consdata->nonlincoefs[exprtreeidx];
5179  constant *= treecoef;
5180 
5181  for( i = 0; i < nchildren; ++i )
5182  {
5183  SCIP_CALL( getCoeffsAndConstantFromLinearExpr( children[i], childcoeffs[i]*treecoef, varcoeffs, &constant ) );
5184  }
5185 
5186  SCIPaddRowprepConstant(rowprep, constant);
5187  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, nvars, vars, varcoeffs) );
5188 
5189  SCIPfreeBufferArray( scip, &varcoeffs );
5190  }
5191 
5192  SCIPfreeBufferArray( scip, &childcoeffs );
5193  SCIPfreeBufferArray( scip, &childbounds );
5194  SCIPfreeBufferArray( scip, &childvals );
5195 
5196  return SCIP_OKAY;
5197 }
5198 
5199 /** adds estimator from interval gradient of a constraints univariate expression tree to a row
5200  * a reference point is used to decide in which corner to generate the cut
5201  */
5202 static
5204  SCIP* scip, /**< SCIP data structure */
5205  SCIP_EXPRINT* exprint, /**< expression interpreter */
5206  SCIP_CONS* cons, /**< constraint */
5207  int exprtreeidx, /**< for which tree a secant should be added */
5208  SCIP_Real* x, /**< value of expression tree variables where to generate cut */
5209  SCIP_Bool newx, /**< whether the last evaluation of the expression with the expression interpreter was not at x */
5210  SCIP_Bool overestimate, /**< whether to compute an overestimator instead of an underestimator */
5211  SCIP_ROWPREP* rowprep, /**< rowprep where to add estimator */
5212  SCIP_Bool* success /**< buffer to store whether an estimator was succefully added to the rowprep */
5213  )
5214 {
5215  SCIP_CONSDATA* consdata;
5216  SCIP_EXPRTREE* exprtree;
5217  SCIP_Real treecoef;
5218  SCIP_Real* coefs;
5219  SCIP_Real constant;
5220  SCIP_Real val;
5221  SCIP_Real lb;
5222  SCIP_Real ub;
5223  SCIP_INTERVAL* box;
5224  SCIP_INTERVAL* intgrad;
5225  SCIP_INTERVAL intval;
5226  SCIP_VAR** vars;
5227  int nvars;
5228  int i;
5229 
5230  assert(scip != NULL);
5231  assert(cons != NULL);
5232  assert(x != NULL);
5233  assert(rowprep != NULL);
5234  assert(success != NULL);
5235 
5236  consdata = SCIPconsGetData(cons);
5237  assert(consdata != NULL);
5238  assert(exprtreeidx >= 0);
5239  assert(exprtreeidx < consdata->nexprtrees);
5240  assert(consdata->exprtrees != NULL);
5241 
5242  exprtree = consdata->exprtrees[exprtreeidx];
5243  assert(exprtree != NULL);
5244  assert(newx || SCIPexprtreeGetInterpreterData(exprtree) != NULL);
5245 
5246  *success = FALSE;
5247 
5248  /* skip interval gradient if expression interpreter cannot compute interval gradients */
5250  return SCIP_OKAY;
5251 
5252  nvars = SCIPexprtreeGetNVars(exprtree);
5253  vars = SCIPexprtreeGetVars(exprtree);
5254 
5255  box = NULL;
5256  intgrad = NULL;
5257  coefs = NULL;
5258 
5259  SCIP_CALL( SCIPallocBufferArray(scip, &box, nvars) );
5260 
5261  /* move reference point to bounds, setup box */
5262  for( i = 0; i < nvars; ++i )
5263  {
5264  lb = SCIPvarGetLbLocal(vars[i]);
5265  ub = SCIPvarGetUbLocal(vars[i]);
5266  if( SCIPisInfinity(scip, -lb) )
5267  {
5268  if( SCIPisInfinity(scip, ub) )
5269  {
5270  SCIPdebugMsg(scip, "skip interval gradient estimator for constraint <%s> because variable <%s> is still unbounded.\n", SCIPconsGetName(cons), SCIPvarGetName(vars[i]));
5271  goto INTGRADESTIMATOR_CLEANUP;
5272  }
5273  x[i] = ub;
5274  }
5275  else
5276  {
5277  if( SCIPisInfinity(scip, ub) )
5278  x[i] = lb;
5279  else
5280  x[i] = (2.0*x[i] < lb+ub) ? lb : ub;
5281  }
5282  SCIPintervalSetBounds(&box[i],
5283  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -MIN(lb, ub)),
5284  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, MAX(lb, ub)));
5285  }
5286 
5287  /* compile expression if evaluated the first time; can only happen if newx is FALSE */
5288  if( newx && SCIPexprtreeGetInterpreterData(exprtree) == NULL )
5289  {
5290  SCIP_CALL( SCIPexprintCompile(exprint, exprtree) );
5291  }
5292 
5293  /* evaluate in reference point */
5294  SCIP_CALL( SCIPexprintEval(exprint, exprtree, x, &val) );
5295  if( !SCIPisFinite(val) )
5296  {
5297  SCIPdebugMsg(scip, "Got nonfinite function value from evaluation of constraint %s tree %d. skipping interval gradient estimator.\n", SCIPconsGetName(cons), exprtreeidx);
5298  goto INTGRADESTIMATOR_CLEANUP;
5299  }
5300 
5301  treecoef = consdata->nonlincoefs[exprtreeidx];
5302  val *= treecoef;
5303  constant = val;
5304 
5305  /* compute interval gradient */
5306  SCIP_CALL( SCIPallocBufferArray(scip, &intgrad, nvars) );
5307  SCIP_CALL( SCIPexprintGradInt(exprint, exprtree, INTERVALINFTY, box, TRUE, &intval, intgrad) );
5308  SCIPintervalMulScalar(INTERVALINFTY, &intval, intval, treecoef);
5309 
5310  /* printf("nvars %d side %d xref = %g x = [%g,%g] intval = [%g,%g] intgrad = [%g,%g]\n", nvars, side, x[0],
5311  box[0].inf, box[0].sup, intval.inf, intval.sup, intgrad[0].inf, intgrad[0].sup); */
5312 
5313  /* compute coefficients and constant */
5314  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
5315  for( i = 0; i < nvars; ++i )
5316  {
5317  val = x[i];
5318  lb = SCIPintervalGetInf(box[i]);
5319  ub = SCIPintervalGetSup(box[i]);
5320 
5321  SCIPintervalMulScalar(INTERVALINFTY, &intgrad[i], intgrad[i], treecoef);
5322 
5323  if( SCIPisEQ(scip, lb, ub) )
5324  coefs[i] = 0.0;
5325  else if( (overestimate && val == ub) || /*lint !e777*/
5326  (!overestimate && val == lb) ) /*lint !e777*/
5327  coefs[i] = SCIPintervalGetInf(intgrad[i]);
5328  else
5329  coefs[i] = SCIPintervalGetSup(intgrad[i]);
5330 
5331  if( SCIPisZero(scip, coefs[i]) )
5332  continue;
5333 
5334  if( SCIPisInfinity(scip, -coefs[i]) || SCIPisInfinity(scip, coefs[i]) )
5335  {
5336  SCIPdebugMsg(scip, "skip intgrad estimator because of infinite interval bound\n");
5337  goto INTGRADESTIMATOR_CLEANUP;
5338  }
5339 
5340  constant -= coefs[i] * val;
5341  }
5342 
5343  /* add interval gradient estimator to row */
5344  SCIPaddRowprepConstant(rowprep, constant);
5345  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, nvars, vars, coefs) );
5346 
5347  INTGRADESTIMATOR_CLEANUP:
5348  SCIPfreeBufferArrayNull(scip, &coefs);
5349  SCIPfreeBufferArrayNull(scip, &intgrad);
5350  SCIPfreeBufferArrayNull(scip, &box);
5351 
5352  return SCIP_OKAY;
5353 }
5354 
5355 /** generates a cut based on linearization (if convex), secant (if concave), or intervalgradient (if indefinite)
5356  */
5357 static
5359  SCIP* scip, /**< SCIP data structure */
5360  SCIP_EXPRINT* exprint, /**< expression interpreter */
5361  SCIP_CONS* cons, /**< constraint */
5362  SCIP_Real** ref, /**< reference point for each exprtree, or NULL if sol should be used */
5363  SCIP_SOL* sol, /**< reference solution where cut should be generated, or NULL if LP solution should be used */
5364  SCIP_Bool newsol, /**< whether the last evaluation of the expression with the expression interpreter was not at sol */
5365  SCIP_SIDETYPE side, /**< for which side a cut should be generated */
5366  SCIP_ROW** row, /**< storage for cut */
5367  SCIP_Real minviol, /**< minimal absolute violation we try to achieve */
5368  SCIP_Real maxrange, /**< maximal range allowed */
5369  SCIP_Bool expensivecurvchecks,/**< whether also expensive checks should be executed */
5370  SCIP_Bool assumeconvex /**< whether to assume convexity in inequalities */
5371  )
5372 {
5373  SCIP_ROWPREP* rowprep;
5374  SCIP_CONSDATA* consdata;
5375  SCIP_Bool success;
5376  SCIP_Real* x;
5377  int i;
5378 
5379  assert(scip != NULL);
5380  assert(cons != NULL);
5381  assert(row != NULL);
5382 
5383  SCIPdebugMsg(scip, "constructing cut for %s hand side of constraint <%s>\n", side == SCIP_SIDETYPE_LEFT ? "left" : "right", SCIPconsGetName(cons));
5384 
5385  SCIP_CALL( checkCurvature(scip, cons, expensivecurvchecks, assumeconvex) );
5386 
5387  consdata = SCIPconsGetData(cons);
5388  assert(consdata != NULL);
5389 
5390  if( consdata->nexprtrees == 0 )
5391  {
5392  char rowname[SCIP_MAXSTRLEN];
5393  (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%u", SCIPconsGetName(cons), ++(consdata->ncuts));
5394 
5395  /* if we are actually linear, add the constraint as row to the LP */
5396  SCIP_CALL( SCIPcreateEmptyRowCons(scip, row, SCIPconsGetHdlr(cons), rowname, consdata->lhs, consdata->rhs, SCIPconsIsLocal(cons), FALSE , TRUE) );
5397  SCIP_CALL( SCIPaddVarsToRow(scip, *row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
5398  return SCIP_OKAY;
5399  }
5400 
5401  SCIP_CALL( SCIPcreateRowprep(scip, &rowprep, side,
5402  !(side == SCIP_SIDETYPE_LEFT && (consdata->curvature & SCIP_EXPRCURV_CONCAVE)) &&
5403  !(side == SCIP_SIDETYPE_RIGHT && (consdata->curvature & SCIP_EXPRCURV_CONVEX ))) );
5404  SCIPaddRowprepSide(rowprep, side == SCIP_SIDETYPE_LEFT ? consdata->lhs : consdata->rhs);
5405  (void) SCIPsnprintf(rowprep->name, SCIP_MAXSTRLEN, "%s_%u", SCIPconsGetName(cons), ++(consdata->ncuts));
5406 
5407  if( ref == NULL )
5408  {
5409  SCIP_CALL( SCIPallocBufferArray(scip, &x, SCIPexprtreeGetNVars(consdata->exprtrees[0])) );
5410  }
5411 
5412  success = TRUE;
5413  for( i = 0; i < consdata->nexprtrees; ++i )
5414  {
5415  if( ref == NULL )
5416  {
5417  SCIP_CALL( SCIPreallocBufferArray(scip, &x, SCIPexprtreeGetNVars(consdata->exprtrees[i])) ); /*lint !e644*/
5418  SCIP_CALL( SCIPgetSolVals(scip, sol, SCIPexprtreeGetNVars(consdata->exprtrees[i]), SCIPexprtreeGetVars(consdata->exprtrees[i]), x) );
5419  }
5420  else
5421  {
5422  x = ref[i];
5423  }
5424 
5425  if( (side == SCIP_SIDETYPE_LEFT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONCAVE)) ||
5426  (side == SCIP_SIDETYPE_RIGHT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONVEX )) )
5427  {
5428  SCIP_CALL( addLinearization(scip, exprint, cons, i, x, newsol, rowprep, &success) );
5429  }
5430  else if( (side == SCIP_SIDETYPE_LEFT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONVEX)) ||
5431  ( side == SCIP_SIDETYPE_RIGHT && (consdata->curvatures[i] & SCIP_EXPRCURV_CONCAVE)) )
5432  {
5433  switch( SCIPexprtreeGetNVars(consdata->exprtrees[i]) )
5434  {
5435  case 1:
5436  SCIP_CALL( addConcaveEstimatorUnivariate(scip, cons, i, rowprep, &success) );
5437  break;
5438 
5439  case 2:
5440  SCIP_CALL( addConcaveEstimatorBivariate(scip, cons, i, x, rowprep, &success) );
5441  break;
5442 
5443  default:
5444  SCIP_CALL( addConcaveEstimatorMultivariate(scip, cons, i, x, rowprep, &success) );
5445  break;
5446  }
5447  if( !success )
5448  {
5449  SCIPdebugMsg(scip, "failed to generate polyhedral estimator for %d-dim concave function in exprtree %d, fall back to intervalgradient cut\n", SCIPexprtreeGetNVars(consdata->exprtrees[i]), i);
5450  SCIP_CALL( addIntervalGradientEstimator(scip, exprint, cons, i, x, newsol, side == SCIP_SIDETYPE_LEFT, rowprep, &success) );
5451  }
5452  }
5453  else if( SCIPexprGetOperator( SCIPexprtreeGetRoot( consdata->exprtrees[i] ) ) == SCIP_EXPR_USER )
5454  {
5455  SCIP_CALL( addUserEstimator( scip, cons, i, x, side == SCIP_SIDETYPE_LEFT, rowprep, &success ) );
5456  if( !success ) /* the user estimation may not be implemented -> try interval estimator */
5457  {
5458  SCIP_CALL( addIntervalGradientEstimator(scip, exprint, cons, i, x, newsol, side == SCIP_SIDETYPE_LEFT, rowprep, &success) );
5459  }
5460  }
5461  else
5462  {
5463  SCIP_CALL( addIntervalGradientEstimator(scip, exprint, cons, i, x, newsol, side == SCIP_SIDETYPE_LEFT, rowprep, &success) );
5464  }
5465 
5466  if( !success )
5467  break;
5468  }
5469 
5470  if( ref == NULL )
5471  {
5472  SCIPfreeBufferArray(scip, &x);
5473  }
5474 
5475  if( success )
5476  {
5477  SCIP_Real coefrange;
5478 
5479  /* add coefficients for linear variables */
5480  SCIP_CALL( SCIPaddRowprepTerms(scip, rowprep, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
5481 
5482  /* merge terms in same variable */
5483  SCIPmergeRowprepTerms(scip, rowprep);
5484 
5485  /* cleanup row */
5486  SCIP_CALL( SCIPcleanupRowprep(scip, rowprep, sol, maxrange, minviol, &coefrange, NULL) );
5487 
5488  /* check that coefficient range is ok */
5489  success = coefrange <= maxrange;
5490 
5491  /* check that side is finite */ /*lint --e{514} */
5492  success &= !SCIPisInfinity(scip, REALABS(rowprep->side));
5493 
5494  /* check whether maximal coef is finite, if any */
5495  success &= (rowprep->nvars == 0) || !SCIPisInfinity(scip, REALABS(rowprep->coefs[0]));
5496  }
5497 
5498  if( success )
5499  {
5500  SCIP_CALL( SCIPgetRowprepRowCons(scip, row, rowprep, SCIPconsGetHdlr(cons)) );
5501  }
5502  else
5503  *row = NULL;
5504 
5505  SCIPfreeRowprep(scip, &rowprep);
5506 
5507  return SCIP_OKAY;
5508 }
5509 
5510 /** tries to separate solution or LP solution by a linear cut
5511  *
5512  * assumes that constraint violations have been computed
5513  */
5514 static
5516  SCIP* scip, /**< SCIP data structure */
5517  SCIP_CONSHDLR* conshdlr, /**< nonlinear constraints handler */
5518  SCIP_CONS** conss, /**< constraints */
5519  int nconss, /**< number of constraints */
5520  int nusefulconss, /**< number of constraints that seem to be useful */
5521  SCIP_SOL* sol, /**< solution to separate, or NULL if LP solution should be used */
5522  SCIP_Bool newsol, /**< have the constraints just been evaluated at this point? */
5523  SCIP_Real minefficacy, /**< minimal efficacy of a cut if it should be added to the LP */
5524  SCIP_Bool inenforcement, /**< whether we are in constraint enforcement */
5525  SCIP_RESULT* result, /**< result of separation */
5526  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 */
5527  )
5528 {
5530  SCIP_CONSDATA* consdata;
5531  SCIP_Real efficacy;
5532  SCIP_Real feasibility;
5533  SCIP_SIDETYPE violside;
5534  int c;
5535  SCIP_ROW* row;
5536 
5537  assert(scip != NULL);
5538  assert(conshdlr != NULL);
5539  assert(conss != NULL || nconss == 0);
5540  assert(nusefulconss <= nconss);
5541  assert(result != NULL);
5542 
5543  *result = SCIP_FEASIBLE;
5544 
5545  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5546  assert(conshdlrdata != NULL);
5547 
5548  if( bestefficacy != NULL )
5549  *bestefficacy = 0.0;
5550 
5551  for( c = 0, violside = SCIP_SIDETYPE_LEFT; c < nconss; c = (violside == SCIP_SIDETYPE_RIGHT ? c+1 : c), violside = (violside == SCIP_SIDETYPE_LEFT ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT) )
5552  {
5553  assert(conss != NULL);
5554 
5555  /* skip constraints that are not enabled */
5556  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
5557  continue;
5558  assert(SCIPconsIsActive(conss[c]));
5559 
5560  consdata = SCIPconsGetData(conss[c]);
5561  assert(consdata != NULL);
5562 
5563  /* if side violside of cons c not violated, then continue to next side or next cons */
5564  if( !SCIPisGT(scip, violside == SCIP_SIDETYPE_LEFT ? consdata->lhsviol : consdata->rhsviol, SCIPfeastol(scip)) )
5565  continue;
5566 
5567  /* we are not feasible anymore */
5568  if( *result == SCIP_FEASIBLE )
5569  *result = SCIP_DIDNOTFIND;
5570 
5571  /* generate cut
5572  * if function is defined at sol (activity<infinity) and constraint is violated, then expression interpreter should have evaluated at sol to get gradient before
5573  */
5574  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], NULL, sol, newsol || SCIPisInfinity(scip, consdata->activity), violside, &row, minefficacy, conshdlrdata->cutmaxrange, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
5575 
5576  if( row == NULL ) /* failed to generate cut */
5577  continue;
5578 
5579  if( sol == NULL )
5580  feasibility = SCIPgetRowLPFeasibility(scip, row);
5581  else
5582  feasibility = SCIPgetRowSolFeasibility(scip, row, sol);
5583  efficacy = -feasibility;
5584 
5585  if( SCIPisGT(scip, efficacy, minefficacy) && SCIPisCutApplicable(scip, row) )
5586  {
5587  SCIP_Bool infeasible;
5588 
5589  /* cut cuts off solution */
5590  SCIP_CALL( SCIPaddRow(scip, row, FALSE /* forcecut */, &infeasible) );
5591  if ( infeasible )
5592  *result = SCIP_CUTOFF;
5593  else
5594  *result = SCIP_SEPARATED;
5595 
5596  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
5597 
5598  SCIPdebugMsg(scip, "add cut with efficacy %g for constraint <%s> violated by %g\n", efficacy, SCIPconsGetName(conss[c]), MAX(consdata->lhsviol, consdata->rhsviol));
5599  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
5600 
5601  if( bestefficacy != NULL && efficacy > *bestefficacy )
5602  *bestefficacy = efficacy;
5603 
5604  /* mark row as not removable from LP for current node, if in enforcement */
5605  if( inenforcement && !conshdlrdata->enfocutsremovable )
5606  SCIPmarkRowNotRemovableLocal(scip, row);
5607  }
5608  else
5609  {
5610  SCIPdebugMsg(scip, "drop cut since efficacy %g is too small (< %g)\n", efficacy, minefficacy);
5611  }
5612 
5613  SCIP_CALL( SCIPreleaseRow (scip, &row) );
5614 
5615  if ( *result == SCIP_CUTOFF )
5616  break;
5617 
5618  /* enforce only useful constraints
5619  * others are only checked and enforced if we are still feasible or have not found a separating cut yet
5620  */
5621  if( c >= nusefulconss && *result == SCIP_SEPARATED )
5622  break;
5623  }
5624 
5625  return SCIP_OKAY;
5626 }
5627 
5628 /** adds linearizations cuts for convex constraints w.r.t. a given reference point to cutpool and sepastore
5629  * if separatedlpsol is not NULL, then a cut that separates the LP solution is added to the sepastore and is forced to enter the LP
5630  * if separatedlpsol is not NULL, but cut does not separate the LP solution, then it is added to the cutpool only
5631  * if separatedlpsol is NULL, then cut is added to cutpool only
5632  */
5633 static
5635  SCIP* scip, /**< SCIP data structure */
5636  SCIP_CONSHDLR* conshdlr, /**< quadratic constraints handler */
5637  SCIP_CONS** conss, /**< constraints */
5638  int nconss, /**< number of constraints */
5639  SCIP_SOL* ref, /**< reference point where to linearize, or NULL for LP solution */
5640  SCIP_Bool* separatedlpsol, /**< buffer to store whether a cut that separates the current LP solution was found and added to LP, or NULL if adding to cutpool only */
5641  SCIP_Real minefficacy /**< minimal efficacy of a cut when checking for separation of LP solution */
5642  )
5643 {
5645  SCIP_CONSDATA* consdata;
5646  SCIP_Bool addedtolp;
5647  SCIP_ROW* row;
5648  int c;
5649 
5650  assert(scip != NULL);
5651  assert(conshdlr != NULL);
5652  assert(conss != NULL || nconss == 0);
5653 
5654  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5655  assert(conshdlrdata != NULL);
5656 
5657  if( separatedlpsol != NULL )
5658  *separatedlpsol = FALSE;
5659 
5660  for( c = 0; c < nconss; ++c )
5661  {
5662  assert(conss[c] != NULL); /*lint !e613*/
5663 
5664  if( SCIPconsIsLocal(conss[c]) ) /*lint !e613*/
5665  continue;
5666 
5667  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) ); /*lint !e613*/
5668 
5669  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
5670  assert(consdata != NULL);
5671 
5672  /* if we cannot linearize, then skip constraint */
5673  if( (!(consdata->curvature & SCIP_EXPRCURV_CONVEX) || SCIPisInfinity(scip, consdata->rhs)) &&
5674  ( !(consdata->curvature & SCIP_EXPRCURV_CONCAVE) || SCIPisInfinity(scip, -consdata->lhs)) )
5675  continue;
5676 
5677  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], NULL, ref, TRUE,
5678  (consdata->curvature & SCIP_EXPRCURV_CONVEX) ? SCIP_SIDETYPE_RIGHT : SCIP_SIDETYPE_LEFT,
5679  &row, minefficacy, conshdlrdata->cutmaxrange, FALSE, FALSE) ); /*lint !e613*/
5680 
5681  if( row == NULL )
5682  continue;
5683 
5684  addedtolp = FALSE;
5685 
5686  /* if caller wants, then check if cut separates LP solution and add to sepastore if so */
5687  if( separatedlpsol != NULL )
5688  {
5689  if( -SCIPgetRowLPFeasibility(scip, row) >= minefficacy )
5690  {
5691  SCIP_Bool infeasible;
5692 
5693  *separatedlpsol = TRUE;
5694  addedtolp = TRUE;
5695  SCIP_CALL( SCIPaddRow(scip, row, TRUE, &infeasible) );
5696  assert( ! infeasible );
5697  }
5698  }
5699 
5700  if( !SCIProwIsLocal(row) && !addedtolp )
5701  {
5702  SCIP_CALL( SCIPaddPoolCut(scip, row) );
5703  }
5704 
5705  SCIP_CALL( SCIPreleaseRow(scip, &row) );
5706  }
5707 
5708  return SCIP_OKAY;
5709 }
5710 
5711 /** processes the event that a new primal solution has been found */
5712 static
5713 SCIP_DECL_EVENTEXEC(processNewSolutionEvent)
5716  SCIP_CONSHDLR* conshdlr;
5717  SCIP_CONS** conss;
5718  int nconss;
5719  SCIP_SOL* sol;
5720 
5721  assert(scip != NULL);
5722  assert(event != NULL);
5723  assert(eventdata != NULL);
5724  assert(eventhdlr != NULL);
5725 
5726  assert((SCIPeventGetType(event) & SCIP_EVENTTYPE_SOLFOUND) != 0);
5727 
5728  conshdlr = (SCIP_CONSHDLR*)eventdata;
5729 
5730  nconss = SCIPconshdlrGetNConss(conshdlr);
5731 
5732  if( nconss == 0 )
5733  return SCIP_OKAY;
5734 
5735  sol = SCIPeventGetSol(event);
5736  assert(sol != NULL);
5737 
5738  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5739  assert(conshdlrdata != NULL);
5740 
5741  /* we are only interested in solution coming from some heuristic other than trysol, but not from the tree
5742  * the reason for ignoring trysol solutions is that they may come from an NLP solve in sepalp, where we already added linearizations,
5743  * or are from the tree, but postprocessed via proposeFeasibleSolution
5744  */
5745  if( SCIPsolGetHeur(sol) == NULL || SCIPsolGetHeur(sol) == conshdlrdata->trysolheur )
5746  return SCIP_OKAY;
5747 
5748  conss = SCIPconshdlrGetConss(conshdlr);
5749  assert(conss != NULL);
5750 
5751  SCIPdebugMsg(scip, "catched new sol event %" SCIP_EVENTTYPE_FORMAT " from heur <%s>; have %d conss\n", SCIPeventGetType(event), SCIPheurGetName(SCIPsolGetHeur(sol)), nconss);
5752 
5753  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, sol, NULL, 0.0) );
5754 
5755  return SCIP_OKAY;
5756 }
5757 
5758 /** registers unfixed variables in nonlinear terms of violated constraints as external branching candidates */
5759 static
5761  SCIP* scip, /**< SCIP data structure */
5762  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5763  SCIP_CONS** conss, /**< constraints to check */
5764  int nconss, /**< number of constraints to check */
5765  int* nnotify /**< counter for number of notifications performed */
5766  )
5767 {
5768  SCIP_CONSDATA* consdata;
5769  SCIP_VAR* var;
5770  int c;
5771  int i;
5772  int j;
5773 
5774  assert(scip != NULL);
5775  assert(conshdlr != NULL);
5776  assert(conss != NULL || nconss == 0);
5777 
5778  *nnotify = 0;
5779 
5780  for( c = 0; c < nconss; ++c )
5781  {
5782  assert(conss != NULL);
5783  consdata = SCIPconsGetData(conss[c]);
5784  assert(consdata != NULL);
5785 
5786  if( consdata->nexprtrees == 0 )
5787  continue;
5788 
5789  /* do not branch on violation of convex constraint */
5790  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || (consdata->curvature & SCIP_EXPRCURV_CONCAVE)) &&
5791  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || (consdata->curvature & SCIP_EXPRCURV_CONVEX )) )
5792  continue;
5793  SCIPdebugMsg(scip, "cons <%s> violation: %g %g curvature: %s\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, SCIPexprcurvGetName(consdata->curvature));
5794 
5795  for( i = 0; i < consdata->nexprtrees; ++i )
5796  {
5797  /* skip convex summands */
5798  if( (!SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || (consdata->curvatures[i] & SCIP_EXPRCURV_CONCAVE)) &&
5799  ( !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) || (consdata->curvatures[i] & SCIP_EXPRCURV_CONVEX )) )
5800  continue;
5801 
5802  for( j = 0; j < SCIPexprtreeGetNVars(consdata->exprtrees[i]); ++j )
5803  {
5804  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[j];
5805  assert(var != NULL);
5806 
5807  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
5808  {
5809  SCIPdebugMsg(scip, "ignore fixed variable <%s>[%g, %g], width %g\n", SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var));
5810  continue;
5811  }
5812 
5813  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
5814  ++*nnotify;
5815  }
5816  }
5817  }
5818 
5819  SCIPdebugMsg(scip, "registered %d branching candidates\n", *nnotify);
5820 
5821  return SCIP_OKAY;
5822 }
5823 
5824 /** registers a nonlinear variable from a violated constraint as branching candidate that has a large absolute value in the relaxation */
5825 static
5827  SCIP* scip, /**< SCIP data structure */
5828  SCIP_CONS** conss, /**< constraints */
5829  int nconss, /**< number of constraints */
5830  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
5831  SCIP_VAR** brvar /**< buffer to store branching variable */
5832  )
5833 {
5834  SCIP_CONSDATA* consdata;
5835  SCIP_VAR* var;
5836  SCIP_Real val;
5837  SCIP_Real brvarval;
5838  int i;
5839  int j;
5840  int c;
5841 
5842  assert(scip != NULL);
5843  assert(conss != NULL || nconss == 0);
5844 
5845  *brvar = NULL;
5846  brvarval = -1.0;
5847 
5848  for( c = 0; c < nconss; ++c )
5849  {
5850  assert(conss != NULL);
5851  consdata = SCIPconsGetData(conss[c]);
5852  assert(consdata != NULL);
5853 
5854  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5855  continue;
5856 
5857  for( j = 0; j < consdata->nexprtrees; ++j )
5858  {
5859  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]); ++i )
5860  {
5861  var = SCIPexprtreeGetVars(consdata->exprtrees[j])[i];
5862  /* do not propose fixed variables */
5863  if( SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
5864  continue;
5865  val = SCIPgetSolVal(scip, sol, var);
5866  if( REALABS(val) > brvarval )
5867  {
5868  brvarval = ABS(val);
5869  *brvar = var;
5870  }
5871  }
5872  }
5873  }
5874 
5875  if( *brvar != NULL )
5876  {
5877  SCIP_CALL( SCIPaddExternBranchCand(scip, *brvar, brvarval, SCIP_INVALID) );
5878  }
5879 
5880  return SCIP_OKAY;
5881 }
5882 
5883 /** replaces violated nonlinear constraints where all nonlinear variables are almost fixed by linear constraints
5884  * only adds constraint if it is violated in current solution
5885  * first tries to fix almost fixed variables
5886  */
5887 static
5889  SCIP* scip, /**< SCIP data structure */
5890  SCIP_CONS** conss, /**< constraints */
5891  int nconss, /**< number of constraints */
5892  SCIP_Bool* addedcons, /**< buffer to store whether a linear constraint was added */
5893  SCIP_Bool* reduceddom, /**< whether a domain has been reduced */
5894  SCIP_Bool* infeasible /**< whether we detected infeasibility */
5895  )
5896 {
5897  SCIP_CONS* cons;
5898  SCIP_CONSDATA* consdata;
5899  SCIP_Real lhs;
5900  SCIP_Real rhs;
5901  SCIP_Real lb;
5902  SCIP_Real ub;
5903  SCIP_RESULT checkresult;
5904  SCIP_VAR* var;
5905  SCIP_Bool tightened;
5906  int c;
5907  int i;
5908  int v;
5909 
5910  assert(scip != NULL);
5911  assert(conss != NULL || nconss == 0);
5912  assert(addedcons != NULL);
5913  assert(reduceddom != NULL);
5914  assert(infeasible != NULL);
5915 
5916  *addedcons = FALSE;
5917  *reduceddom = FALSE;
5918  *infeasible = FALSE;
5919 
5920  for( c = 0; c < nconss; ++c )
5921  {
5922  assert(conss != NULL);
5923  consdata = SCIPconsGetData(conss[c]);
5924  assert(consdata != NULL);
5925 
5926  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
5927  continue;
5928 
5929  lhs = consdata->lhs;
5930  rhs = consdata->rhs;
5931 
5932  for( i = 0; i < consdata->nexprtrees; ++i )
5933  {
5934  SCIP_INTERVAL nonlinactivity;
5935 
5936  /* check whether there are almost fixed nonlinear variables that can be fixed */
5937  for( v = 0; v < SCIPexprtreeGetNVars(consdata->exprtrees[i]); ++v )
5938  {
5939  var = SCIPexprtreeGetVars(consdata->exprtrees[i])[v];
5940 
5941  lb = SCIPvarGetLbLocal(var);
5942  ub = SCIPvarGetUbLocal(var);
5943  assert(SCIPisRelEQ(scip, lb, ub)); /* variable should be almost fixed */
5944 
5945  assert(!SCIPisInfinity(scip, -lb));
5946  assert(!SCIPisInfinity(scip, ub));
5947 
5948  if( !SCIPisEQ(scip, lb, ub) )
5949  {
5950  /* try to fix variable */
5951  SCIP_CALL( SCIPtightenVarLb(scip, var, (lb+ub)/2.0, TRUE, infeasible, &tightened) );
5952  if( *infeasible )
5953  {
5954  SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(var));
5955  return SCIP_OKAY;
5956  }
5957  if( tightened )
5958  {
5959  SCIPdebugMsg(scip, "Tightened lower bound of almost fixed variable <%s>.\n", SCIPvarGetName(var));
5960  *reduceddom = TRUE;
5961  }
5962 
5963  SCIP_CALL( SCIPtightenVarUb(scip, var, (lb+ub)/2.0, TRUE, infeasible, &tightened) );
5964  if( *infeasible )
5965  {
5966  SCIPdebugMsg(scip, "Fixing almost fixed variable <%s> lead to infeasibility.\n", SCIPvarGetName(var));
5967  return SCIP_OKAY;
5968  }
5969  if( tightened )
5970  {
5971  SCIPdebugMsg(scip, "Tightened upper bound of almost fixed variable <%s>.\n", SCIPvarGetName(var));
5972  *reduceddom = TRUE;
5973  }
5974  }
5975  }
5976 
5977  SCIP_CALL( SCIPevalExprtreeLocalBounds(scip, consdata->exprtrees[i], INTERVALINFTY, &nonlinactivity) );
5978  if( SCIPintervalIsEmpty(INTERVALINFTY, nonlinactivity) )
5979  {
5980  SCIPdebugMsg(scip, "Eval expr via exprtree on local bounds lead to infeasibility due to domain violation.\n");
5981  *infeasible = TRUE;
5982  return SCIP_OKAY;
5983  }
5984 
5985  SCIPintervalMulScalar(INTERVALINFTY, &nonlinactivity, nonlinactivity, consdata->nonlincoefs[i]);
5986 
5987  if( !SCIPisInfinity(scip, -lhs) )
5988  {
5989  if( SCIPintervalGetSup(nonlinactivity) >= INTERVALINFTY )
5990  lhs = -SCIPinfinity(scip);
5991  else if( SCIPintervalGetSup(nonlinactivity) <= -INTERVALINFTY )
5992  {
5993  /* lhs <= [...,-infinity] + ... will never be feasible */
5994  *infeasible = TRUE;
5995  return SCIP_OKAY;
5996  }
5997  else
5998  lhs -= SCIPintervalGetSup(nonlinactivity);
5999  }
6000 
6001  if( !SCIPisInfinity(scip, rhs) )
6002  {
6003  if( SCIPintervalGetInf(nonlinactivity) <= -INTERVALINFTY )
6004  rhs = SCIPinfinity(scip);
6005  else if( SCIPintervalGetInf(nonlinactivity) >= INTERVALINFTY )
6006  {
6007  /* [infinity,...] + ... <= rhs will never be feasible */
6008  *infeasible = TRUE;
6009  return SCIP_OKAY;
6010  }
6011  else
6012  rhs -= SCIPintervalGetInf(nonlinactivity);
6013  }
6014  }
6015 
6016  /* if some nonlinear variable was fixed now, then restart node (next enfo round) */
6017  if( *reduceddom )
6018  return SCIP_OKAY;
6019 
6020  /* check if we have a bound change */
6021  if ( consdata->nlinvars == 0 )
6022  {
6023  assert(SCIPisFeasLE(scip, lhs, rhs));
6024  }
6025  else if ( consdata->nlinvars == 1 )
6026  {
6027  SCIP_Real coef;
6028 
6029  coef = *consdata->lincoefs;
6030  SCIPdebugMsg(scip, "Linear constraint with one variable: %g <= %g <%s> <= %g\n", lhs, coef, SCIPvarGetName(*consdata->linvars), rhs);
6031 
6032  /* possibly correct lhs/rhs */
6033  assert( ! SCIPisZero(scip, coef) );
6034  if ( coef >= 0.0 )
6035  {
6036  if ( ! SCIPisInfinity(scip, -lhs) )
6037  lhs /= coef;
6038  if ( ! SCIPisInfinity(scip, rhs) )
6039  rhs /= coef;
6040  }
6041  else
6042  {
6043  SCIP_Real h;
6044  h = rhs;
6045  if ( ! SCIPisInfinity(scip, -lhs) )
6046  rhs = lhs/coef;
6047  else
6048  rhs = SCIPinfinity(scip);
6049 
6050  if ( ! SCIPisInfinity(scip, h) )
6051  lhs = h/coef;
6052  else
6053  lhs = -SCIPinfinity(scip);
6054  }
6055  SCIPdebugMsg(scip, "Linear constraint is a bound: %g <= <%s> <= %g\n", lhs, SCIPvarGetName(*consdata->linvars), rhs);
6056 
6057  /* cut off the node if SCIP needs to tight the lb/ub to +/-inf */
6058  if( SCIPisInfinity(scip, lhs) || SCIPisInfinity(scip, -rhs) )
6059  {
6060  *infeasible = TRUE;
6061  assert(consdata->linvars[0] != NULL);
6062  SCIPwarningMessage(scip, "Activity of nonlinear part is beyond SCIP's value for infinity. To enforce "
6063  "the constraint %s SCIP needs to tight bounds of %s to a value beyond +/- infinity. Please check if "
6064  "finite bounds can be added.\n", SCIPconsGetName(conss[c]), SCIPvarGetName(consdata->linvars[0]));
6065  return SCIP_OKAY;
6066  }
6067 
6068  if ( ! SCIPisInfinity(scip, -lhs) )
6069  {
6070  SCIP_CALL( SCIPtightenVarLb(scip, *consdata->linvars, lhs, TRUE, infeasible, &tightened) );
6071  if ( *infeasible )
6072  {
6073  SCIPdebugMsg(scip, "Lower bound leads to infeasibility.\n");
6074  return SCIP_OKAY;
6075  }
6076  if ( tightened )
6077  {
6078  SCIPdebugMsg(scip, "Lower bound changed.\n");
6079  *reduceddom = TRUE;
6080  return SCIP_OKAY;
6081  }
6082  }
6083 
6084  if ( ! SCIPisInfinity(scip, rhs) )
6085  {
6086  SCIP_CALL( SCIPtightenVarUb(scip, *consdata->linvars, rhs, TRUE, infeasible, &tightened) );
6087  if ( *infeasible )
6088  {
6089  SCIPdebugMsg(scip, "Upper bound leads to infeasibility.\n");
6090  return SCIP_OKAY;
6091  }
6092  if ( tightened )
6093  {
6094  SCIPdebugMsg(scip, "Upper bound changed.\n");
6095  *reduceddom = TRUE;
6096  return SCIP_OKAY;
6097  }
6098  }
6099  }
6100  else
6101  {
6102  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, SCIPconsGetName(conss[c]),
6103  consdata->nlinvars, consdata->linvars, consdata->lincoefs, lhs, rhs,
6104  SCIPconsIsInitial(conss[c]), SCIPconsIsSeparated(conss[c]), SCIPconsIsEnforced(conss[c]),
6105  SCIPconsIsChecked(conss[c]), SCIPconsIsPropagated(conss[c]), TRUE,
6106  SCIPconsIsModifiable(conss[c]), SCIPconsIsDynamic(conss[c]), SCIPconsIsRemovable(conss[c]),
6107  SCIPconsIsStickingAtNode(conss[c])) );
6108 
6109  SCIPdebugMsg(scip, "replace violated nonlinear constraint <%s> by linear constraint after all nonlinear vars have been fixed\n", SCIPconsGetName(conss[c]) );
6110  SCIPdebugPrintCons(scip, conss[c], NULL);
6111  SCIPdebugPrintCons(scip, cons, NULL);
6112 
6113  SCIP_CALL( SCIPcheckCons(scip, cons, NULL, FALSE, FALSE, FALSE, &checkresult) );
6114 
6115  if( checkresult != SCIP_INFEASIBLE && SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL )
6116  {
6117  SCIPdebugMsg(scip, "linear constraint is feasible, thus do not add\n");
6118  }
6119  else
6120  {
6121  SCIP_CALL( SCIPaddConsLocal(scip, cons, NULL) );
6122  *addedcons = TRUE;
6123  }
6124  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
6125  }
6126  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
6127  }
6128 
6129  return SCIP_OKAY;
6130 }
6131 
6132 /* tightens a lower bound on a variable and checks the result */
6133 static
6135  SCIP* scip, /**< SCIP data structure */
6136  SCIP_CONS* cons, /**< constraint where we currently propagate, or NULL if tightening is from expression graph */
6137  SCIP_VAR* var, /**< variable which domain we might reduce */
6138  SCIP_Real bnd, /**< new lower bound for variable */
6139  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
6140  int* nchgbds /**< counter to increase if a bound was tightened */
6141  )
6142 {
6143  SCIP_Bool infeas;
6144  SCIP_Bool tightened;
6145 
6146  assert(scip != NULL);
6147  assert(bnd > -INTERVALINFTY);
6148  assert(var != NULL);
6149  assert(result != NULL);
6150  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
6151  assert(nchgbds != NULL);
6152 
6153  if( SCIPisInfinity(scip, bnd) )
6154  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
6155  *result = SCIP_CUTOFF;
6156  if( cons != NULL )
6157  {
6158  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6159  }
6160  return SCIP_OKAY;
6161  }
6162 
6163  /* new lower bound is very low (between -INTERVALINFTY and -SCIPinfinity()) */
6164  if( SCIPisInfinity(scip, -bnd) )
6165  return SCIP_OKAY;
6166 
6167  bnd = SCIPadjustedVarLb(scip, var, bnd);
6168  SCIP_CALL( SCIPtightenVarLb(scip, var, bnd, FALSE, &infeas, &tightened) );
6169  if( infeas )
6170  {
6171  SCIPdebugMsg(scip, "%sfound constraint <%s> infeasible due to tightened lower bound %g for variable <%s>\n", SCIPinProbing(scip) ? "in probing " : "", cons != NULL ? SCIPconsGetName(cons) : "??", bnd, SCIPvarGetName(var)); /*lint !e585*/
6172  *result = SCIP_CUTOFF;
6173  if( cons != NULL )
6174  {
6175  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6176  }
6177  return SCIP_OKAY;
6178  }
6179  if( tightened )
6180  {
6181  SCIPdebugMsg(scip, "%stightened lower bound of variable <%s> in constraint <%s> to %.15g\n", SCIPinProbing(scip) ? "in probing " : "", SCIPvarGetName(var), cons != NULL ? SCIPconsGetName(cons) : "??", bnd); /*lint !e585*/
6182  ++*nchgbds;
6183  *result = SCIP_REDUCEDDOM;
6184  if( cons != NULL )
6185  {
6186  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6187  }
6188  }
6189 
6190  return SCIP_OKAY;
6191 }
6192 
6193 /* tightens an upper bound on a variable and checks the result */
6194 static
6196  SCIP* scip, /**< SCIP data structure */
6197  SCIP_CONS* cons, /**< constraint where we currently propagate, or NULL if tightening is from expression graph */
6198  SCIP_VAR* var, /**< variable which domain we might reduce */
6199  SCIP_Real bnd, /**< new upper bound for variable */
6200  SCIP_RESULT* result, /**< result to update if there was a tightening or cutoff */
6201  int* nchgbds /**< counter to increase if a bound was tightened */
6202  )
6203 {
6204  SCIP_Bool infeas;
6205  SCIP_Bool tightened;
6206 
6207  assert(scip != NULL);
6208  assert(bnd < INTERVALINFTY);
6209  assert(var != NULL);
6210  assert(result != NULL);
6211  assert(*result == SCIP_DIDNOTFIND || *result == SCIP_REDUCEDDOM);
6212  assert(nchgbds != NULL);
6213 
6214  if( SCIPisInfinity(scip, -bnd) )
6215  { /* domain will be outside [-infty, +infty] -> declare node infeasible */
6216  *result = SCIP_CUTOFF;
6217  if( cons != NULL )
6218  {
6219  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6220  }
6221  return SCIP_OKAY;
6222  }
6223 
6224  /* new upper bound is very high (between SCIPinfinity() and INTERVALINFTY) */
6225  if( SCIPisInfinity(scip, bnd) )
6226  return SCIP_OKAY;
6227 
6228  bnd = SCIPadjustedVarUb(scip, var, bnd);
6229  SCIP_CALL( SCIPtightenVarUb(scip, var, bnd, FALSE, &infeas, &tightened) );
6230  if( infeas )
6231  {
6232  SCIPdebugMsg(scip, "%sfound constraint <%s> infeasible due to tightened upper bound %g for variable <%s>\n", SCIPinProbing(scip) ? "in probing " : "", cons != NULL ? SCIPconsGetName(cons) : "??", bnd, SCIPvarGetName(var)); /*lint !e585*/
6233  *result = SCIP_CUTOFF;
6234  if( cons != NULL )
6235  {
6236  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6237  }
6238  return SCIP_OKAY;
6239  }
6240  if( tightened )
6241  {
6242  SCIPdebugMsg(scip, "%stightened upper bound of variable <%s> in constraint <%s> to %g\n", SCIPinProbing(scip) ? "in probing " : "", SCIPvarGetName(var), cons != NULL ? SCIPconsGetName(cons) : "??", bnd); /*lint !e585*/
6243  ++*nchgbds;
6244  *result = SCIP_REDUCEDDOM;
6245  if( cons != NULL )
6246  {
6247  SCIP_CALL( SCIPresetConsAge(scip, cons) );
6248  }
6249  }
6250 
6251  return SCIP_OKAY;
6252 }
6253 
6254 /** tightens bounds of linear variables in a single nonlinear constraint */
6255 static
6257  SCIP* scip, /**< SCIP data structure */
6258  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6259  SCIP_CONS* cons, /**< constraint to process */
6260  SCIP_RESULT* result, /**< pointer to store the result of the propagation call */
6261  int* nchgbds, /**< buffer where to add the the number of changed bounds */
6262  SCIP_Bool* redundant /**< buffer where to store whether constraint has been found to be redundant */
6263  )
6264 { /*lint --e{666}*/
6265  SCIP_CONSDATA* consdata;
6266  SCIP_INTERVAL consbounds; /* lower and upper bounds of constraint */
6267  SCIP_INTERVAL consactivity; /* activity of linear plus nonlinear part */
6268  SCIP_VAR* var;
6269  SCIP_INTERVAL rhs; /* right hand side of nonlinear equation */
6270  SCIP_ROUNDMODE roundmode;
6271  SCIP_Real bnd;
6272  int i;
6273  SCIP_INTERVAL nonlinactivity;
6274 
6275  assert(scip != NULL);
6276  assert(conshdlr != NULL);
6277  assert(cons != NULL);
6278  assert(result != NULL);
6279  assert(nchgbds != NULL);
6280 
6281  *result = SCIP_DIDNOTRUN;
6282  *redundant = FALSE;
6283 
6284  if( !SCIPconsIsMarkedPropagate(cons) )
6285  return SCIP_OKAY;
6286 
6287  consdata = SCIPconsGetData(cons);
6288  assert(consdata != NULL);
6289 
6290  *result = SCIP_DIDNOTFIND;
6291 
6292  SCIPdebugMsg(scip, "start linear vars domain propagation for constraint <%s>\n", SCIPconsGetName(cons));
6293 
6294  /* unmark constraint for propagation */
6295  SCIP_CALL( SCIPunmarkConsPropagate(scip, cons) );
6296 
6297  /* make sure we have activity of linear term */
6298  consdataUpdateLinearActivity(scip, consdata);
6299  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777*/
6300  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777*/
6301  assert(consdata->minlinactivityinf >= 0);
6302  assert(consdata->maxlinactivityinf >= 0);
6303  assert(consdata->exprgraphnode != NULL || consdata->nexprtrees == 0);
6304 
6305  /* get activity of nonlinear part, should have been updated in propagateBounds */
6306  if( consdata->exprgraphnode != NULL )
6307  {
6308  nonlinactivity = SCIPexprgraphGetNodeBounds(consdata->exprgraphnode);
6309  }
6310  else
6311  {
6312  SCIPintervalSet(&nonlinactivity, 0.0);
6313  }
6314  assert(!SCIPintervalIsEmpty(INTERVALINFTY, nonlinactivity) );
6315 
6316  /* get activity of constraint function */
6317  SCIPintervalSetBounds(&consactivity, consdata->minlinactivityinf > 0 ? -INTERVALINFTY : consdata->minlinactivity, consdata->maxlinactivityinf > 0 ? INTERVALINFTY : consdata->maxlinactivity);
6318  SCIPintervalAdd(INTERVALINFTY, &consactivity, consactivity, nonlinactivity);
6319 
6320  /* check infeasibility */
6321  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisGT(scip, consdata->lhs-SCIPfeastol(scip), SCIPintervalGetSup(consactivity))) ||
6322  (!SCIPisInfinity(scip, consdata->rhs) && SCIPisLT(scip, consdata->rhs+SCIPfeastol(scip), SCIPintervalGetInf(consactivity))) )
6323  {
6324  SCIPdebugMsg(scip, "found constraint <%s> to be infeasible; sides: [%g, %g], activity: [%g, %g], infeas: %.15g\n",
6325  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity),
6326  MAX(consdata->lhs - SCIPintervalGetSup(consactivity), SCIPintervalGetInf(consactivity) - consdata->rhs));
6327  *result = SCIP_CUTOFF;
6328  return SCIP_OKAY;
6329  }
6330 
6331  SCIPintervalSetBounds(&consbounds,
6332  -infty2infty(SCIPinfinity(scip), INTERVALINFTY, -consdata->lhs + SCIPepsilon(scip)),
6333  +infty2infty(SCIPinfinity(scip), INTERVALINFTY, consdata->rhs + SCIPepsilon(scip)));
6334 
6335  /* check redundancy */
6336  if( SCIPintervalIsSubsetEQ(INTERVALINFTY, consactivity, consbounds) )
6337  {
6338  SCIPdebugMsg(scip, "found constraint <%s> to be redundant: sides: [%g, %g], activity: [%g, %g]\n",
6339  SCIPconsGetName(cons), consdata->lhs, consdata->rhs, SCIPintervalGetInf(consactivity), SCIPintervalGetSup(consactivity));
6340  *redundant = TRUE;
6341  return SCIP_OKAY;
6342  }
6343 
6344  /* propagate linear part in rhs = consbounds - nonlinactivity (use the one from consdata, since that includes infinities) */
6345  SCIPintervalSub(INTERVALINFTY, &rhs, consbounds, nonlinactivity);
6346  if( !SCIPintervalIsEntire(INTERVALINFTY, rhs) )
6347  {
6348  SCIP_Real coef;
6349 
6350  for( i = 0; i < consdata->nlinvars; ++i )
6351  {
6352  coef = consdata->lincoefs[i];
6353  var = consdata->linvars[i];
6354 
6355  /* skip fixed variables
6356  * @todo is that a good or a bad idea?
6357  * we can't expect much more tightening, but may detect infeasiblity, but shouldn't the check on the constraints activity detect that?
6358  */
6359  if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
6360  continue;
6361 
6362  if( coef > 0.0 )
6363  {
6364  if( SCIPintervalGetSup(rhs) < INTERVALINFTY )
6365  {
6366  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777*/
6367  /* try to tighten the upper bound on var x */
6368  if( consdata->minlinactivityinf == 0 )
6369  {
6370  assert(!SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)));
6371  /* tighten upper bound on x to (rhs.sup - (minlinactivity - coef * xlb)) / coef */
6372  roundmode = SCIPintervalGetRoundingMode();
6374  bnd = SCIPintervalGetSup(rhs);
6375  bnd -= consdata->minlinactivity;
6376  bnd += coef * SCIPvarGetLbLocal(var);
6377  bnd /= coef;
6378  SCIPintervalSetRoundingMode(roundmode);
6379  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
6380  if( *result == SCIP_CUTOFF )
6381  break;
6382  }
6383  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
6384  {
6385  /* x was the variable that made the minimal linear activity equal -infinity, so
6386  * we tighten upper bound on x to just (rhs.sup - minlinactivity) / coef */
6387  roundmode = SCIPintervalGetRoundingMode();
6389  bnd = SCIPintervalGetSup(rhs);
6390  bnd -= consdata->minlinactivity;
6391  bnd /= coef;
6392  SCIPintervalSetRoundingMode(roundmode);
6393  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
6394  if( *result == SCIP_CUTOFF )
6395  break;
6396  }
6397  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
6398  }
6399 
6400  if( SCIPintervalGetInf(rhs) > -INTERVALINFTY )
6401  {
6402  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777*/
6403  /* try to tighten the lower bound on var x */
6404  if( consdata->maxlinactivityinf == 0 )
6405  {
6406  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
6407  /* tighten lower bound on x to (rhs.inf - (maxlinactivity - coef * xub)) / coef */
6408  roundmode = SCIPintervalGetRoundingMode();
6410  bnd = SCIPintervalGetInf(rhs);
6411  bnd -= consdata->maxlinactivity;
6412  bnd += coef * SCIPvarGetUbLocal(var);
6413  bnd /= coef;
6414  SCIPintervalSetRoundingMode(roundmode);
6415  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6416  if( *result == SCIP_CUTOFF )
6417  break;
6418  }
6419  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6420  {
6421  /* x was the variable that made the maximal linear activity equal infinity, so
6422  * we tighten upper bound on x to just (rhs.inf - maxlinactivity) / coef */
6423  roundmode = SCIPintervalGetRoundingMode();
6425  bnd = SCIPintervalGetInf(rhs);
6426  bnd -= consdata->maxlinactivity;
6427  bnd /= coef;
6428  SCIPintervalSetRoundingMode(roundmode);
6429  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6430  if( *result == SCIP_CUTOFF )
6431  break;
6432  }
6433  /* otherwise the maximal activity is +infinity and x is not solely responsible for this */
6434  }
6435  }
6436  else
6437  {
6438  assert(coef < 0.0 );
6439  if( SCIPintervalGetInf(rhs) > -INTERVALINFTY )
6440  {
6441  assert(consdata->maxlinactivity != SCIP_INVALID); /*lint !e777*/
6442  /* try to tighten the upper bound on var x */
6443  if( consdata->maxlinactivityinf == 0 )
6444  {
6445  assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
6446  /* compute upper bound on x to (maxlinactivity - coef * xlb) - rhs.inf / (-coef) */
6447  roundmode = SCIPintervalGetRoundingMode();
6449  bnd = consdata->maxlinactivity;
6450  bnd += (-coef) * SCIPvarGetLbLocal(var);
6451  bnd -= SCIPintervalGetInf(rhs);
6452  bnd /= (-coef);
6453  SCIPintervalSetRoundingMode(roundmode);
6454  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
6455  if( *result == SCIP_CUTOFF )
6456  break;
6457  }
6458  else if( consdata->maxlinactivityinf == 1 && SCIPisInfinity(scip, -SCIPvarGetLbLocal(var)) )
6459  {
6460  /* x was the variable that made the maximal linear activity equal infinity, so
6461  * we tighten upper bound on x to just (maxlinactivity - rhs.inf) / (-coef) */
6462  roundmode = SCIPintervalGetRoundingMode();
6464  bnd = consdata->maxlinactivity;
6465  bnd -= SCIPintervalGetInf(rhs);
6466  bnd /= (-coef);
6467  SCIPintervalSetRoundingMode(roundmode);
6468  SCIP_CALL( propagateBoundsTightenVarUb(scip, cons, var, bnd, result, nchgbds) );
6469  if( *result == SCIP_CUTOFF )
6470  break;
6471  }
6472  /* otherwise the maximal activity is infinity and x is not solely responsible for this */
6473  }
6474 
6475  if( SCIPintervalGetSup(rhs) < INTERVALINFTY )
6476  {
6477  assert(consdata->minlinactivity != SCIP_INVALID); /*lint !e777*/
6478  /* try to tighten the lower bound on var x */
6479  if( consdata->minlinactivityinf == 0 )
6480  {
6481  assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
6482  /* compute lower bound on x to (minlinactivity - coef * xub) - rhs.sup / (-coef) */
6483  roundmode = SCIPintervalGetRoundingMode();
6485  bnd = consdata->minlinactivity;
6486  bnd += (-coef) * SCIPvarGetUbLocal(var);
6487  bnd -= SCIPintervalGetSup(rhs);
6488  bnd /= (-coef);
6489  SCIPintervalSetRoundingMode(roundmode);
6490  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6491  if( *result == SCIP_CUTOFF )
6492  break;
6493  }
6494  else if( consdata->minlinactivityinf == 1 && SCIPisInfinity(scip, SCIPvarGetUbLocal(var)) )
6495  {
6496  /* x was the variable that made the maximal linear activity equal -infinity, so
6497  * we tighten lower bound on x to just (minlinactivity - rhs.sup) / (-coef) */
6498  roundmode = SCIPintervalGetRoundingMode();
6500  bnd = consdata->minlinactivity;
6501  bnd -= SCIPintervalGetSup(rhs);
6502  bnd /= (-coef);
6503  SCIPintervalSetRoundingMode(roundmode);
6504  SCIP_CALL( propagateBoundsTightenVarLb(scip, cons, var, bnd, result, nchgbds) );
6505  if( *result == SCIP_CUTOFF )
6506  break;
6507  }
6508  /* otherwise the minimal activity is -infinity and x is not solely responsible for this */
6509  }
6510  }
6511  }
6512  if( *result == SCIP_CUTOFF )
6513  return SCIP_OKAY;
6514  }
6515 
6516  return SCIP_OKAY;
6517 }
6518 
6519 /** propagate constraints sides minus linear activity into nonlinear variables */
6520 static
6522  SCIP* scip, /**< SCIP data structure */
6523  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6524  SCIP_CONS** conss, /**< constraints to process */
6525  int nconss, /**< number of constraints */
6526  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
6527  int* nchgbds /**< buffer where to add the number of changed bounds */
6528  )
6529 {
6531  SCIP_CONSDATA* consdata;
6532  int nvars;
6533  SCIP_VAR** vars;
6534  SCIP_EXPRGRAPHNODE** varnodes;
6535  SCIP_INTERVAL bounds;
6536  SCIP_Bool cutoff;
6537  SCIP_ROUNDMODE roundmode;
6538  int c;
6539  int i;
6540 
6541  assert(scip != NULL);
6542  assert(conshdlr != NULL);
6543  assert(result != NULL);
6544  assert(nchgbds != NULL);
6545 
6546  *result = SCIP_DIDNOTFIND;
6547 
6548  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6549  assert(conshdlrdata != NULL);
6550  assert(conshdlrdata->exprgraph != NULL);
6551 
6552  SCIPdebugMsg(scip, "start backward propagation in expression graph\n");
6553 
6554 #ifdef SCIP_OUTPUT
6555  {
6556  FILE* file;
6557  file = fopen("exprgraph_propconss1.dot", "w");
6558  if( file != NULL )
6559  {
6561  fclose(file);
6562  }
6563  }
6564 #endif
6565 
6566  /* put constraint sides less linear activity into expression graph nodes
6567  * also add a [-feastol,feastol] range around constraint sides to cope with numerics */
6568  for( c = 0; c < nconss; ++c )
6569  {
6570  /* skip (just) deleted or disabled constraints */
6571  if( SCIPconsIsDeleted(conss[c]) || !SCIPconsIsEnabled(conss[c]) )
6572  continue;
6573 
6574  consdata = SCIPconsGetData(conss[c]);
6575  assert(consdata != NULL);
6576 
6577  if( consdata->exprgraphnode == NULL )
6578  continue;
6579 
6580  roundmode = SCIPintervalGetRoundingMode();
6582 
6583  if( !SCIPisInfinity(scip, -consdata->lhs) && consdata->maxlinactivityinf == 0 )
6584  bounds.inf = consdata->lhs - consdata->maxlinactivity - SCIPfeastol(scip);
6585  else
6586  bounds.inf = -INTERVALINFTY;
6587 
6588  if( !SCIPisInfinity(scip, consdata->rhs) && consdata->minlinactivityinf == 0 )
6589  bounds.sup = SCIPintervalNegateReal(consdata->minlinactivity - consdata->rhs - SCIPfeastol(scip));
6590  else
6591  bounds.sup = INTERVALINFTY;
6592 
6593  SCIPintervalSetRoundingMode(roundmode);
6594 
6595  /* if we want the expression graph to propagate the bounds in any case, we set minstrength to a negative value */
6596  SCIPexprgraphTightenNodeBounds(conshdlrdata->exprgraph, consdata->exprgraphnode, bounds,
6597  consdata->forcebackprop ? -1.0 : BOUNDTIGHTENING_MINSTRENGTH, INTERVALINFTY, &cutoff);
6598  consdata->forcebackprop = FALSE; /* do this only once */
6599 
6600  if( cutoff )
6601  {
6602  SCIPdebugMsg(scip, "found constraint <%s> infeasible%s\n", SCIPconsGetName(conss[c]), SCIPinProbing(scip) ? " in probing" : "");
6603  *result = SCIP_CUTOFF;
6604  return SCIP_OKAY;
6605  }
6606  }
6607 
6608  /* compute bound tightenings for nonlinear variables */
6610 
6611 #ifdef SCIP_OUTPUT
6612  {
6613  FILE* file;
6614  file = fopen("exprgraph_propconss2.dot", "w");
6615  if( file != NULL )
6616  {
6618  fclose(file);
6619  }
6620  }
6621 #endif
6622 
6623  if( cutoff )
6624  {
6625  SCIPdebugMsg(scip, "backward propagation found problem infeasible%s\n", SCIPinProbing(scip) ? " in probing" : "");
6626  *result = SCIP_CUTOFF;
6627  return SCIP_OKAY;
6628  }
6629 
6630  /* put tighter bounds into variables */
6631  nvars = SCIPexprgraphGetNVars(conshdlrdata->exprgraph);
6632  vars = (SCIP_VAR**)SCIPexprgraphGetVars(conshdlrdata->exprgraph);
6633  varnodes = SCIPexprgraphGetVarNodes(conshdlrdata->exprgraph);
6634 
6635  /* put back new bounds into SCIP variables */
6636  for( i = 0; i < nvars && *result != SCIP_CUTOFF; ++i )
6637  {
6638  if( !SCIPisInfinity(scip, -SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(varnodes[i]))) )
6639  {
6640  SCIP_CALL( propagateBoundsTightenVarLb(scip, NULL, vars[i], SCIPintervalGetInf(SCIPexprgraphGetNodeBounds(varnodes[i])), result, nchgbds) );
6641  }
6642  if( *result != SCIP_CUTOFF && !SCIPisInfinity(scip, SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(varnodes[i]))) )
6643  {
6644  SCIP_CALL( propagateBoundsTightenVarUb(scip, NULL, vars[i], SCIPintervalGetSup(SCIPexprgraphGetNodeBounds(varnodes[i])), result, nchgbds) );
6645  }
6646  }
6647 
6648  return SCIP_OKAY;
6649 }
6650 
6651 /** calls domain propagation for a set of constraints */
6652 static
6654  SCIP* scip, /**< SCIP data structure */
6655  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6656  SCIP_CONS** conss, /**< constraints to process */
6657  int nconss, /**< number of constraints */
6658  SCIP_Bool needclear, /**< whether we may need to clear remainings from a previous backward propagation */
6659  SCIP_RESULT* result, /**< pointer to store the result of the propagation calls */
6660  int* nchgbds, /**< buffer where to add the the number of changed bounds */
6661  int* ndelconss /**< buffer where to increase if a constraint was deleted (locally) due to redundancy */
6662  )
6663 {
6664 #ifndef NDEBUG
6665  SCIP_CONSDATA* consdata;
6666 #endif
6668  SCIP_RESULT propresult;
6669  SCIP_Bool domainerror;
6670  SCIP_Bool redundant;
6671  int roundnr;
6672  SCIP_Bool success;
6673  int c;
6674 
6675  assert(scip != NULL);
6676  assert(conshdlr != NULL);
6677  assert(conss != NULL || nconss == 0);
6678  assert(result != NULL);
6679  assert(nchgbds != NULL);
6680  assert(ndelconss != NULL);
6681 
6682  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6683  assert(conshdlrdata != NULL);
6684  assert(conshdlrdata->exprgraph != NULL);
6685 
6686  if( nconss == 0 || conshdlrdata->ispropagated )
6687  {
6688  *result = SCIP_DIDNOTRUN;
6689  return SCIP_OKAY;
6690  }
6691 
6692  *result = SCIP_DIDNOTFIND;
6693 
6694  roundnr = 0;
6695  do
6696  {
6697  success = FALSE;
6698 
6699  SCIPdebugMsg(scip, "starting domain propagation round %d for %d constraints\n", roundnr, nconss);
6700 
6701  conshdlrdata->ispropagated = TRUE;
6702 
6703  /* propagate variable bounds through expression graph
6704  * roundnr == 0 clears remainings from a previous backward propagation
6705  * @todo could give FALSE if no linear variable in the constraints had been relaxed since last time
6706  */
6707  SCIP_CALL( SCIPexprgraphPropagateVarBounds(conshdlrdata->exprgraph, INTERVALINFTY, (roundnr == 0) && needclear, &domainerror) );
6708 
6709 #ifdef SCIP_OUTPUT
6710  {
6711  FILE* file;
6712  file = fopen("exprgraph_propvars.dot", "w");
6713  if( file != NULL )
6714  {
6716  fclose(file);
6717  }
6718  }
6719 #endif
6720 
6721  if( domainerror )
6722  {
6723  SCIPdebugMsg(scip, "current bounds out of domain for some expression, do cutoff\n");
6724  *result = SCIP_CUTOFF;
6725  break;
6726  }
6727 
6728  /* check for redundancy and infeasibility of constraints, tighten bounds on linear variables */
6729  for( c = 0; c < nconss && *result != SCIP_CUTOFF; ++c )
6730  {
6731  assert(conss != NULL);
6732  if( !SCIPconsIsEnabled(conss[c]) || SCIPconsIsDeleted(conss[c]) )
6733  continue;
6734  assert(SCIPconsIsActive(conss[c]));
6735 
6736 #ifndef NDEBUG
6737  consdata = SCIPconsGetData(conss[c]);
6738  assert(consdata != NULL);
6739  assert(consdata->exprgraphnode == NULL || !SCIPintervalIsEmpty(INTERVALINFTY, SCIPexprgraphGetNodeBounds(consdata->exprgraphnode)));
6740 #endif
6741 
6742  SCIP_CALL( propagateBoundsCons(scip, conshdlr, conss[c], &propresult, nchgbds, &redundant) );
6743  if( propresult != SCIP_DIDNOTFIND && propresult != SCIP_DIDNOTRUN )
6744  {
6745  *result = propresult;
6746  success = TRUE;
6747  }
6748  if( redundant )
6749  {
6750  SCIPdebugMsg(scip, "delete redundant constraint <%s> locally\n", SCIPconsGetName(conss[c]));
6751  SCIP_CALL( SCIPdelConsLocal(scip, conss[c]) );
6752  ++*ndelconss;
6753  }
6754  }
6755 
6756  /* propagate backward through expression graph */
6757  if( *result != SCIP_CUTOFF )
6758  {
6759  propresult = SCIP_DIDNOTFIND;
6760  SCIP_CALL( propagateConstraintSides(scip, conshdlr, conss, nconss, &propresult, nchgbds) );
6761 
6762  if( propresult != SCIP_DIDNOTFIND )
6763  {
6764  *result = propresult;
6765  success = TRUE;
6766  }
6767  }
6768  }
6769  while( success && *result != SCIP_CUTOFF && ++roundnr < conshdlrdata->maxproprounds );
6770 
6771  return SCIP_OKAY;
6772 }
6773 
6774 /* checks for a linear variable that can be increase or decreased without harming feasibility */
6775 static
6777  SCIP* scip, /**< SCIP data structure */
6778  SCIP_CONSDATA* consdata /**< constraint data */
6779  )
6780 {
6781  int i;
6782  int downlock;
6783  int uplock;
6784 
6785  consdata->linvar_maydecrease = -1;
6786  consdata->linvar_mayincrease = -1;
6787 
6788  /* check for a linear variable that can be increase or decreased without harming feasibility
6789  * setup lincoefsmin, lincoefsmax */
6790  for( i = 0; i < consdata->nlinvars; ++i )
6791  {
6792  /* compute locks of i'th linear variable */
6793  assert(consdata->lincoefs[i] != 0.0);
6794  if( consdata->lincoefs[i] > 0.0 )
6795  {
6796  downlock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0; /* lhs <= x -> downlock on x */
6797  uplock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0; /* x <= rhs -> uplock on x */
6798  }
6799  else
6800  {
6801  downlock = !SCIPisInfinity(scip, consdata->rhs) ? 1 : 0; /* -x <= rhs -> downlock on x */
6802  uplock = !SCIPisInfinity(scip, -consdata->lhs) ? 1 : 0; /* lhs <= -x -> uplock on x */
6803  }
6804 
6805  if( SCIPvarGetNLocksDownType(consdata->linvars[i], SCIP_LOCKTYPE_MODEL) - downlock == 0 )
6806  {
6807  /* for a*x + q(y) \in [lhs, rhs], we can decrease x without harming other constraints */
6808  /* if we have already one candidate, then take the one where the loss in the objective function is less */
6809  if( (consdata->linvar_maydecrease < 0) ||
6810  (SCIPvarGetObj(consdata->linvars[consdata->linvar_maydecrease]) / consdata->lincoefs[consdata->linvar_maydecrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
6811  consdata->linvar_maydecrease = i;
6812  }
6813 
6814  if( SCIPvarGetNLocksUpType(consdata->linvars[i], SCIP_LOCKTYPE_MODEL) - uplock == 0 )
6815  {
6816  /* for a*x + q(y) \in [lhs, rhs], we can increase x without harm */
6817  /* if we have already one candidate, then take the one where the loss in the objective function is less */
6818  if( (consdata->linvar_mayincrease < 0) ||
6819  (SCIPvarGetObj(consdata->linvars[consdata->linvar_mayincrease]) / consdata->lincoefs[consdata->linvar_mayincrease] > SCIPvarGetObj(consdata->linvars[i]) / consdata->lincoefs[i]) )
6820  consdata->linvar_mayincrease = i;
6821  }
6822  }
6823 
6824 #ifdef SCIP_DEBUG
6825  if( consdata->linvar_mayincrease >= 0 )
6826  {
6827  SCIPdebugMsg(scip, "may increase <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_mayincrease]));
6828  }
6829  if( consdata->linvar_maydecrease >= 0 )
6830  {
6831  SCIPdebugMsg(scip, "may decrease <%s> to become feasible\n", SCIPvarGetName(consdata->linvars[consdata->linvar_maydecrease]));
6832  }
6833 #endif
6834 }
6835 
6836 /** Given a solution where every nonlinear constraint is either feasible or can be made feasible by
6837  * moving a linear variable, construct the corresponding feasible solution and pass it to the trysol heuristic.
6838  * The method assumes that this is always possible and that not all constraints are feasible already.
6839  */
6840 static
6842  SCIP* scip, /**< SCIP data structure */
6843  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6844  SCIP_CONS** conss, /**< constraints to process */
6845  int nconss, /**< number of constraints */
6846  SCIP_SOL* sol, /**< solution to process */
6847  SCIP_Bool* success /**< buffer to store whether we succeeded to construct a solution that satisfies all provided constraints */
6848  )
6849 {
6851  SCIP_CONSDATA* consdata;
6852  SCIP_SOL* newsol;
6853  SCIP_VAR* var;
6854  int c;
6855  SCIP_Real viol;
6856  SCIP_Real delta;
6857  SCIP_Real gap;
6858  SCIP_Bool solviolbounds;
6859  SCIP_Bool solchanged;
6860 
6861  assert(scip != NULL);
6862  assert(conshdlr != NULL);
6863  assert(conss != NULL || nconss == 0);
6864  assert(success != NULL);
6865 
6866  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6867  assert(conshdlrdata != NULL);
6868  assert(conshdlrdata->trysolheur != NULL);
6869 
6870  *success = FALSE;
6871 
6872  /* don't propose new solutions if not in presolve or solving */
6874  return SCIP_OKAY;
6875 
6876  if( sol != NULL )
6877  {
6878  SCIP_CALL( SCIPcreateSolCopy(scip, &newsol, sol) );
6879  }
6880  else
6881  {
6882  SCIP_CALL( SCIPcreateLPSol(scip, &newsol, NULL) );
6883  }
6884  SCIP_CALL( SCIPunlinkSol(scip, newsol) );
6885  solchanged = FALSE; /* so far newsol equals sol */
6886 
6887  for( c = 0; c < nconss; ++c )
6888  {
6889  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
6890  assert(consdata != NULL);
6891 
6892  /* recompute violation of constraint in case solution is not original sol anymore */
6893  if( solchanged )
6894  {
6895  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], newsol, &solviolbounds) ); /*lint !e613*/
6896  assert(!solviolbounds);
6897  }
6898 
6899  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
6900  viol = consdata->lhs - consdata->activity;
6901  else if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
6902  viol = consdata->rhs - consdata->activity;
6903  else
6904  continue; /* constraint is satisfied */
6905 
6906  assert(viol != 0.0);
6907  if( consdata->linvar_mayincrease >= 0 &&
6908  (( viol > 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) ||
6909  (viol < 0.0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0)) )
6910  {
6911  /* have variable where increasing makes the constraint less violated */
6912  var = consdata->linvars[consdata->linvar_mayincrease];
6913  /* compute how much we would like to increase var */
6914  delta = viol / consdata->lincoefs[consdata->linvar_mayincrease];
6915  assert(delta > 0.0);
6916  /* if var has an upper bound, may need to reduce delta */
6917  if( !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
6918  {
6919  gap = SCIPvarGetUbGlobal(var) - SCIPgetSolVal(scip, newsol, var);
6920  delta = MIN(MAX(0.0, gap), delta);
6921  }
6922  if( SCIPisPositive(scip, delta) )
6923  {
6924  /* if variable is integral, round delta up so that it will still have an integer value */
6925  if( SCIPvarIsIntegral(var) )
6926  delta = SCIPceil(scip, delta);
6927 
6928  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
6929  SCIPdebugMsg(scip, "increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
6930 
6931  solchanged = TRUE;
6932 
6933  /* adjust constraint violation, if satisfied go on to next constraint */
6934  viol -= consdata->lincoefs[consdata->linvar_mayincrease] * delta;
6935  if( SCIPisZero(scip, viol) )
6936  continue;
6937  }
6938  }
6939 
6940  assert(viol != 0.0);
6941  if( consdata->linvar_maydecrease >= 0 &&
6942  (( viol > 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) ||
6943  (viol < 0.0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0)) )
6944  {
6945  /* have variable where decreasing makes constraint less violated */
6946  var = consdata->linvars[consdata->linvar_maydecrease];
6947  /* compute how much we would like to decrease var */
6948  delta = viol / consdata->lincoefs[consdata->linvar_maydecrease];
6949  assert(delta < 0.0);
6950  /* if var has a lower bound, may need to reduce delta */
6951  if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
6952  {
6953  gap = SCIPgetSolVal(scip, newsol, var) - SCIPvarGetLbGlobal(var);
6954  delta = MAX(MIN(0.0, gap), delta);
6955  }
6956  if( SCIPisNegative(scip, delta) )
6957  {
6958  /* if variable is integral, round delta down so that it will still have an integer value */
6959  if( SCIPvarIsIntegral(var) )
6960  delta = SCIPfloor(scip, delta);
6961  SCIP_CALL( SCIPincSolVal(scip, newsol, var, delta) );
6962  SCIPdebugMsg(scip, "increase <%s> by %g to %g\n", SCIPvarGetName(var), delta, SCIPgetSolVal(scip, newsol, var));
6963 
6964  solchanged = TRUE;
6965 
6966  /* adjust constraint violation, if satisfied go on to next constraint */
6967  viol -= consdata->lincoefs[consdata->linvar_maydecrease] * delta;
6968  if( SCIPisZero(scip, viol) )
6969  continue;
6970  }
6971  }
6972 
6973  /* still here... so probably we could not make constraint feasible due to variable bounds, thus give up */
6974  break;
6975  }
6976 
6977  /* if we have a solution that should satisfy all nonlinear constraints and has a better objective than the current upper bound,
6978  * then pass it to the trysol heuristic */
6979  if( c == nconss && (SCIPisInfinity(scip, SCIPgetUpperbound(scip)) || SCIPisSumLT(scip, SCIPgetSolTransObj(scip, newsol), SCIPgetUpperbound(scip))) )
6980  {
6981  SCIPdebugMsg(scip, "pass solution with objective value %g to trysol heuristic\n", SCIPgetSolTransObj(scip, newsol));
6982  assert(solchanged);
6983 
6984  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, newsol) );
6985  *success = TRUE;
6986  }
6987 
6988  SCIP_CALL( SCIPfreeSol(scip, &newsol) );
6989 
6990  return SCIP_OKAY;
6991 }
6992 
6993 /** helper function to enforce constraints */
6994 static
6996  SCIP* scip, /**< SCIP data structure */
6997  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6998  SCIP_CONS** conss, /**< constraints to process */
6999  int nconss, /**< number of constraints */
7000  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
7001  SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
7002  SCIP_Bool solinfeasible, /**< was the solution already declared infeasible by a constraint handler? */
7003  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
7004  )
7005 {
7007  SCIP_CONSDATA* consdata;
7008  SCIP_CONS* maxviolcons;
7009  SCIP_Real maxviol;
7010  SCIP_RESULT propresult;
7011  SCIP_RESULT separateresult;
7012  int dummy;
7013  int nnotify;
7014  SCIP_Real sepaefficacy;
7015  SCIP_Bool solviolbounds;
7016 
7017  assert(scip != NULL);
7018  assert(conshdlr != NULL);
7019  assert(conss != NULL || nconss == 0);
7020 
7021  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7022  assert(conshdlrdata != NULL);
7023 
7024  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &solviolbounds, &maxviolcons) );
7025 
7026  if( maxviolcons == NULL )
7027  {
7028  *result = SCIP_FEASIBLE;
7029  return SCIP_OKAY;
7030  }
7031 
7032  *result = SCIP_INFEASIBLE;
7033 
7034  if( solviolbounds )
7035  {
7036  /* if LP solution violates variable bounds, then this should be because a row was added that
7037  * introduced this variable newly to the LP, in which case it gets value 0.0; the row should
7038  * have been added to resolve an infeasibility, so solinfeasible should be TRUE
7039  * see also issue #627
7040  */
7041  assert(solinfeasible);
7042  /* however, if solinfeasible is actually not TRUE, then better cut off the node to avoid that SCIP
7043  * stops because infeasible cannot be resolved */ /*lint --e{774} */
7044  if( !solinfeasible )
7045  *result = SCIP_CUTOFF;
7046  return SCIP_OKAY;
7047  }
7048 
7049  consdata = SCIPconsGetData(maxviolcons);
7050  assert(consdata != NULL);
7051 
7052  maxviol = consdata->lhsviol + consdata->rhsviol;
7053  assert(SCIPisGT(scip, maxviol, SCIPfeastol(scip)));
7054 
7055  SCIPdebugMsg(scip, "enforcement with max violation %g in cons <%s> for %s solution\n", maxviol, SCIPconsGetName(maxviolcons),
7056  sol == NULL ? "LP" : "relaxation");
7057 
7058  /* we propagate and separate constraints only if they are active and enforcing by branching only does not seem much effective */
7059  assert(SCIPconsIsActive(maxviolcons));
7060 
7061  /* if we are above the 100'th enforcement round for this node, something is strange
7062  * (maybe the LP does not think that the cuts we add are violated, or we do ECP on a high-dimensional convex function)
7063  * in this case, check if some limit is hit or SCIP should stop for some other reason and terminate enforcement by creating a dummy node
7064  * (in optimized more, returning SCIP_INFEASIBLE in *result would be sufficient, but in debug mode this would give an assert in scip.c)
7065  * the reason to wait for 100 rounds is to avoid calls to SCIPisStopped in normal runs, which may be expensive
7066  * we only increment nenfolprounds until 101 to avoid an overflow
7067  */
7068  if( conshdlrdata->lastenfonode == SCIPgetCurrentNode(scip) )
7069  {
7070  if( conshdlrdata->nenforounds > 100 )
7071  {
7072  if( SCIPisStopped(scip) )
7073  {
7074  SCIP_NODE* child;
7075 
7076  SCIP_CALL( SCIPcreateChild(scip, &child, 1.0, SCIPnodeGetEstimate(SCIPgetCurrentNode(scip))) );
7077  *result = SCIP_BRANCHED;
7078 
7079  return SCIP_OKAY;
7080  }
7081  }
7082  else
7083  ++conshdlrdata->nenforounds;
7084  }
7085  else
7086  {
7087  conshdlrdata->lastenfonode = SCIPgetCurrentNode(scip);
7088  conshdlrdata->nenforounds = 0;
7089  }
7090 
7091  /* run domain propagation */
7092  dummy = 0;
7093  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, TRUE, &propresult, &dummy, &dummy) );
7094  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
7095  {
7096  *result = propresult;
7097  return SCIP_OKAY;
7098  }
7099 
7100  /* we would like a cut that is efficient enough that it is not redundant in the LP (>lpfeastol)
7101  * however, we also don't want very weak cuts, so try to reach at least feastol (=lpfeastol by default, though)
7102  */
7103  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, TRUE /* because computeviolation projects point onto box */, SCIPfeastol(scip), TRUE, &separateresult, &sepaefficacy) );
7104  if( separateresult == SCIP_CUTOFF )
7105  {
7106  SCIPdebugMsg(scip, "separation found cutoff\n");
7107  *result = SCIP_CUTOFF;
7108  return SCIP_OKAY;
7109  }
7110  if( separateresult == SCIP_SEPARATED )
7111  {
7112  SCIPdebugMsg(scip, "separation succeeded (bestefficacy = %g, minefficacy = %g)\n", sepaefficacy, SCIPfeastol(scip));
7113  *result = SCIP_SEPARATED;
7114  return SCIP_OKAY;
7115  }
7116 
7117  /* we are not feasible, the whole node is not infeasible, and we cannot find a good cut
7118  * -> collect variables for branching
7119  */
7120  SCIPdebugMsg(scip, "separation failed (bestefficacy = %g < %g = minefficacy ); max viol: %g\n", sepaefficacy, SCIPfeastol(scip), maxviol);
7121 
7122  /* find branching candidates */
7123  SCIP_CALL( registerBranchingVariables(scip, conshdlr, conss, nconss, &nnotify) );
7124 
7125  if( nnotify == 0 && !solinfeasible && SCIPfeastol(scip) > SCIPlpfeastol(scip) )
7126  {
7127  /* fallback 1: we also have no branching candidates, so try to find a weak cut */
7128  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, FALSE, SCIPlpfeastol(scip), TRUE, &separateresult, &sepaefficacy) );
7129  if( separateresult == SCIP_SEPARATED || separateresult == SCIP_CUTOFF )
7130  {
7131  *result = separateresult;
7132  return SCIP_OKAY;
7133  }
7134  }
7135 
7136  if( nnotify == 0 && !solinfeasible )
7137  {
7138  /* fallback 2: separation probably failed because of numerical difficulties with a convex constraint;
7139  * if noone declared solution infeasible yet and we had not even found a weak cut, try to resolve by branching
7140  */
7141  SCIP_VAR* brvar = NULL;
7142  SCIP_CALL( registerLargeRelaxValueVariableForBranching(scip, conss, nconss, sol, &brvar) );
7143  if( brvar == NULL )
7144  {
7145  /* fallback 3: all nonlinear variables in all violated constraints seem to be fixed -> replace by linear constraints */
7146  SCIP_Bool addedcons;
7147  SCIP_Bool reduceddom;
7148  SCIP_Bool infeasible;
7149 
7150  SCIPdebugMsg(scip, "All nonlinear variables seem to be fixed. Replace remaining violated nonlinear constraints by linear constraints.\n");
7151  SCIP_CALL( replaceViolatedByLinearConstraints(scip, conss, nconss, &addedcons, &reduceddom, &infeasible) );
7152  /* if the linear constraints are actually feasible, then adding them and returning SCIP_CONSADDED confuses SCIP
7153  * when it enforces the new constraints again and nothing resolves the infeasiblity that we declare here thus,
7154  * we only add them if considered violated, and otherwise claim the solution is feasible (but print a
7155  * warning) */
7156  if ( infeasible )
7157  *result = SCIP_CUTOFF;
7158  else if ( addedcons )
7159  *result = SCIP_CONSADDED;
7160  else if ( reduceddom )
7161  *result = SCIP_REDUCEDDOM;
7162  else
7163  {
7164  *result = SCIP_FEASIBLE;
7165  SCIPwarningMessage(scip, "could not enforce feasibility by separating or branching; declaring solution with viol %g as feasible\n", maxviol);
7166  assert(!SCIPisInfinity(scip, maxviol));
7167  }
7168  return SCIP_OKAY;
7169  }
7170  else
7171  {
7172  SCIPdebugMsg(scip, "Could not find any usual branching variable candidate. Proposed variable <%s> with LP value %g for branching.\n",
7173  SCIPvarGetName(brvar), SCIPgetSolVal(scip, sol, brvar));
7174  nnotify = 1;
7175  }
7176  }
7177 
7178  assert(*result == SCIP_INFEASIBLE && (solinfeasible || nnotify > 0));
7179  return SCIP_OKAY;
7180 }
7181 
7182 /*
7183  * Callback methods of constraint handler
7184  */
7185 
7186 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
7187 static
7188 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
7190  assert(scip != NULL);
7191  assert(conshdlr != NULL);
7192  /* assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0); */
7193 
7194  /* call inclusion method of constraint handler */
7196 
7197  *valid = TRUE;
7198 
7199  return SCIP_OKAY;
7200 }
7201 
7202 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
7203 static
7204 SCIP_DECL_CONSFREE(consFreeNonlinear)
7207  int i;
7208 
7209  assert(scip != NULL);
7210  assert(conshdlr != NULL);
7211 
7212  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7213  assert(conshdlrdata != NULL);
7214  assert(conshdlrdata->exprinterpreter != NULL);
7215  assert(conshdlrdata->exprgraph != NULL);
7216  assert(SCIPexprgraphGetNVars(conshdlrdata->exprgraph) == 0);
7217 
7218  /* free expression graph */
7219  SCIP_CALL( SCIPexprgraphFree(&conshdlrdata->exprgraph) );
7220 
7221  /* free upgrade functions */
7222  for( i = 0; i < conshdlrdata->nnlconsupgrades; ++i )
7223  {
7224  assert(conshdlrdata->nlconsupgrades[i] != NULL);
7225  SCIPfreeBlockMemory(scip, &conshdlrdata->nlconsupgrades[i]); /*lint !e866*/
7226  }
7227  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->nlconsupgrades, conshdlrdata->nlconsupgradessize);
7228 
7229  /* free expressions interpreter */
7230  SCIP_CALL( SCIPexprintFree(&conshdlrdata->exprinterpreter) );
7231 
7232  SCIPfreeBlockMemory(scip, &conshdlrdata);
7233 
7234  return SCIP_OKAY;
7235 }
7236 
7237 /** initialization method of constraint handler (called after problem was transformed) */
7238 static
7239 SCIP_DECL_CONSINIT(consInitNonlinear)
7242 
7243  assert(scip != NULL);
7244  assert(conshdlr != NULL);
7245 
7246  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7247  assert(conshdlrdata != NULL);
7248 
7249  conshdlrdata->subnlpheur = SCIPfindHeur(scip, "subnlp");
7250  conshdlrdata->trysolheur = SCIPfindHeur(scip, "trysol");
7251 
7252  /* reset counter, since we have a new problem */
7253  conshdlrdata->naddedreformconss = 0;
7254 
7255 #ifdef SCIP_OUTPUT
7256  {
7257  FILE* file;
7258  file = fopen("exprgraph_init.dot", "w");
7259  if( file != NULL )
7260  {
7261  SCIP_CALL( SCIPexprgraphPrintDot(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), file, NULL) );
7262  fclose(file);
7263  }
7264  }
7265 #endif
7266 
7267  return SCIP_OKAY;
7268 } /*lint !e715*/
7269 
7270 /** deinitialization method of constraint handler (called before transformed problem is freed) */
7271 static
7272 SCIP_DECL_CONSEXIT(consExitNonlinear)
7275 
7276  assert(scip != NULL);
7277  assert(conshdlr != NULL);
7278 
7279  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7280  assert(conshdlrdata != NULL);
7281 
7282  conshdlrdata->subnlpheur = NULL;
7283  conshdlrdata->trysolheur = NULL;
7284 
7285  return SCIP_OKAY;
7286 } /*lint !e715*/
7287 
7288 
7289 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
7290 static
7291 SCIP_DECL_CONSINITPRE(consInitpreNonlinear)
7292 { /*lint --e{715}*/
7293  SCIP_CONSDATA* consdata;
7294  int c;
7295 
7296  assert(scip != NULL);
7297  assert(conshdlr != NULL);
7298  assert(conss != NULL || nconss == 0);
7299 
7300  for( c = 0; c < nconss; ++c )
7301  {
7302  /* skip not yet active constraints */
7303  if( !SCIPconsIsActive(conss[c]) ) /*lint !e613*/
7304  continue;
7305 
7306  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
7307  assert(consdata != NULL);
7308 
7309  /* forget expression trees */
7310  assert(consdata->nexprtrees == 0 || consdata->exprgraphnode != NULL);
7311  SCIP_CALL( consdataSetExprtrees(scip, consdata, 0, NULL, NULL, FALSE) );
7312 
7313  /* mark constraint for propagation */
7314  SCIP_CALL( SCIPmarkConsPropagate(scip, conss[c]) ); /*lint !e613*/
7315  }
7316 
7317  return SCIP_OKAY;
7318 }
7319 
7320 
7321 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
7322 static
7323 SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
7324 { /*lint --e{715}*/
7326  SCIP_CONSDATA* consdata;
7327  SCIP_Bool havegraphchange;
7328  SCIP_Bool havechange;
7329  SCIP_Bool domainerror;
7330 #ifndef NDEBUG
7331  int i;
7332  int j;
7333 #endif
7334  int c;
7335 
7336  assert(scip != NULL);
7337  assert(conshdlr != NULL);
7338  assert(conss != NULL || nconss == 0);
7339 
7340  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7341  assert(conshdlrdata != NULL);
7342 
7343  havegraphchange = FALSE;
7344 
7345  if( !conshdlrdata->isremovedfixings )
7346  {
7347  SCIP_CALL( removeFixedNonlinearVariables(scip, conshdlr) );
7348  assert(conshdlrdata->isremovedfixings);
7349 
7350  havegraphchange = TRUE;
7351  }
7352 
7353  /* if undefined expressions in exprgraph (very unlikely), we will hopefully recognize this during domain propagation later (if it involved an active constraint) */
7354  SCIP_CALL( SCIPexprgraphSimplify(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), SCIPepsilon(scip), conshdlrdata->maxexpansionexponent, &havechange, &domainerror) );
7355  SCIPdebugMsg(scip, "expression graph simplifier found %schange, domain error = %u\n", havechange ? "" : "no ", domainerror);
7356  havegraphchange |= havechange;
7357 
7358  /* some of the methods below will not work if there was a domain error (#1148, point 3) */
7359  if( domainerror )
7360  return SCIP_OKAY;
7361 
7362  for( c = 0; c < nconss; ++c )
7363  {
7364  assert(conss != NULL);
7365 
7366  /* skip inactive constraints */
7367  if( !SCIPconsIsActive(conss[c]) )
7368  continue;
7369  assert(SCIPconsIsAdded(conss[c]));
7370 
7371  consdata = SCIPconsGetData(conss[c]);
7372  assert(consdata != NULL);
7373 
7374  if( !consdata->isremovedfixingslin )
7375  {
7376  SCIP_CALL( removeFixedLinearVariables(scip, conss[c]) );
7377  }
7378 
7379  if( !consdata->ispresolved || havegraphchange )
7380  {
7381  SCIP_Bool infeasible;
7382  SCIP_CALL( splitOffLinearPart(scip, conshdlr, conss[c], &infeasible) );
7383 
7384  /* the infeasibility should have been detected during presolve */
7385  assert(!infeasible);
7386  }
7387 
7388  SCIP_CALL( mergeAndCleanLinearVars(scip, conss[c]) );
7389 
7390  assert(consdata->isremovedfixingslin);
7391  assert(consdata->linvarsmerged);
7392 #ifndef NDEBUG
7393  for( i = 0; i < consdata->nlinvars; ++i )
7394  assert(SCIPvarIsActive(consdata->linvars[i]));
7395 #endif
7396 
7397  if( consdata->exprgraphnode != NULL )
7398  {
7399  /* get expression trees from expression graph */
7400  SCIP_EXPRTREE** exprtrees;
7401  SCIP_Real* coefs;
7402  int nexprtrees;
7403  int exprtreessize;
7404 
7405  exprtreessize = SCIPexprgraphGetSumTreesNSummands(consdata->exprgraphnode);
7406 
7407  SCIP_CALL( SCIPallocBufferArray(scip, &exprtrees, exprtreessize) );
7408  SCIP_CALL( SCIPallocBufferArray(scip, &coefs, exprtreessize) );
7409 
7410  SCIP_CALL( SCIPexprgraphGetSumTrees(conshdlrdata->exprgraph, consdata->exprgraphnode,
7411  exprtreessize, &nexprtrees, exprtrees, coefs) );
7412  assert(nexprtrees > 0);
7413 
7414  SCIP_CALL( consdataSetExprtrees(scip, consdata, nexprtrees, exprtrees, coefs, FALSE) );
7415 
7416  SCIPfreeBufferArray(scip, &coefs);
7417  SCIPfreeBufferArray(scip, &exprtrees);
7418 
7419  assert(consdata->nexprtrees > 0 );
7420 #ifndef NDEBUG
7421  for( j = 0; j < consdata->nexprtrees; ++j )
7422  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]); ++i )
7423  assert(SCIPvarIsActive(SCIPexprtreeGetVars(consdata->exprtrees[j])[i]));
7424 #endif
7425 
7426  /* tell SCIP that we have something nonlinear */
7427  SCIPenableNLP(scip);
7428  }
7429  }
7430 
7431  return SCIP_OKAY;
7432 }
7433 
7434 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
7435 static
7436 SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
7439  SCIP_CONSDATA* consdata;
7440  int c;
7441  int i;
7442 
7443  assert(scip != NULL);
7444  assert(conshdlr != NULL);
7445  assert(conss != NULL || nconss == 0);
7446 
7447  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7448  assert(conshdlrdata != NULL);
7449 
7450  for( c = 0; c < nconss; ++c )
7451  {
7452  assert(conss != NULL);
7453  consdata = SCIPconsGetData(conss[c]);
7454  assert(consdata != NULL);
7455 
7456  /* check for a linear variable that can be increase or decreased without harming feasibility */
7457  consdataFindUnlockedLinearVar(scip, consdata);
7458 
7459  /* setup lincoefsmin, lincoefsmax */
7460  consdata->lincoefsmin = SCIPinfinity(scip);
7461  consdata->lincoefsmax = 0.0;
7462  for( i = 0; i < consdata->nlinvars; ++i )
7463  {
7464  consdata->lincoefsmin = MIN(consdata->lincoefsmin, REALABS(consdata->lincoefs[i])); /*lint !e666*/
7465  consdata->lincoefsmax = MAX(consdata->lincoefsmax, REALABS(consdata->lincoefs[i])); /*lint !e666*/
7466  }
7467 
7468  /* add nlrow respresentation to NLP, if NLP had been constructed */
7469  if( SCIPisNLPConstructed(scip) && SCIPconsIsEnabled(conss[c]) )
7470  {
7471  if( consdata->nlrow == NULL )
7472  {
7473  /* compute curvature for the nonlinear constraint if not done yet */
7474  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
7475 
7476  SCIP_CALL( createNlRow(scip, conss[c]) );
7477  assert(consdata->nlrow != NULL);
7478  }
7479  SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
7480  }
7481  }
7482 
7483  conshdlrdata->newsoleventfilterpos = -1;
7484  if( nconss != 0 )
7485  {
7486  SCIP_EVENTHDLR* eventhdlr;
7487 
7488  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
7489  assert(eventhdlr != NULL);
7490 
7491  SCIP_CALL( SCIPcatchEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, &conshdlrdata->newsoleventfilterpos) );
7492  }
7493 
7494  /* reset flags and counters */
7495  conshdlrdata->sepanlp = FALSE;
7496  conshdlrdata->lastenfonode = NULL;
7497  conshdlrdata->nenforounds = 0;
7498 
7499  return SCIP_OKAY;
7500 }
7501 
7502 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
7503 static
7504 SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
7507  SCIP_CONSDATA* consdata;
7508  int c;
7509 
7510  assert(scip != NULL);
7511  assert(conshdlr != NULL);
7512  assert(conss != NULL || nconss == 0);
7513 
7514  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7515  assert(conshdlrdata != NULL);
7516 
7517  if( conshdlrdata->newsoleventfilterpos >= 0 )
7518  {
7519  SCIP_EVENTHDLR* eventhdlr;
7520 
7521  eventhdlr = SCIPfindEventhdlr(scip, CONSHDLR_NAME"_newsolution");
7522  assert(eventhdlr != NULL);
7523 
7524  SCIP_CALL( SCIPdropEvent(scip, SCIP_EVENTTYPE_SOLFOUND, eventhdlr, (SCIP_EVENTDATA*)conshdlr, conshdlrdata->newsoleventfilterpos) );
7525  conshdlrdata->newsoleventfilterpos = -1;
7526  }
7527 
7528  for( c = 0; c < nconss; ++c )
7529  {
7530  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
7531  assert(consdata != NULL);
7532 
7533  /* free nonlinear row representation */
7534  if( consdata->nlrow != NULL )
7535  {
7536  SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
7537  }
7538  }
7539 
7540  return SCIP_OKAY;
7541 } /*lint !e715*/
7542 
7543 
7544 /** frees specific constraint data */
7545 static
7546 SCIP_DECL_CONSDELETE(consDeleteNonlinear)
7548  assert(scip != NULL);
7549  assert(conshdlr != NULL);
7550  assert(cons != NULL);
7551  assert(!SCIPconsIsActive(cons));
7552  assert(consdata != NULL);
7553  assert(SCIPconsGetData(cons) == *consdata);
7554 
7555  SCIPdebugMsg(scip, "consDelete for cons <%s>\n", SCIPconsGetName(cons));
7556 
7557  /* expression should have been removed from expression graph when constraint was deactivated */
7558  assert((*consdata)->exprgraphnode == NULL);
7559 
7560  SCIP_CALL( consdataFree(scip, consdata) );
7561 
7562  assert(*consdata == NULL);
7563 
7564  return SCIP_OKAY;
7565 }
7566 
7567 /** transforms constraint data into data belonging to the transformed problem */
7568 static
7569 SCIP_DECL_CONSTRANS(consTransNonlinear)
7571  SCIP_CONSDATA* sourcedata;
7572  SCIP_CONSDATA* targetdata;
7573  int i;
7574 
7575  sourcedata = SCIPconsGetData(sourcecons);
7576  assert(sourcedata != NULL);
7577 
7578  SCIP_CALL( consdataCreate(scip, &targetdata,
7579  sourcedata->lhs, sourcedata->rhs,
7580  sourcedata->nlinvars, sourcedata->linvars, sourcedata->lincoefs,
7581  sourcedata->nexprtrees, sourcedata->exprtrees, sourcedata->nonlincoefs,
7582  FALSE) );
7583 
7584  /* copy information on curvature, if known in original constraint */
7585  if( sourcedata->iscurvchecked && sourcedata->nexprtrees > 0 )
7586  {
7587  BMScopyMemoryArray(targetdata->curvatures, sourcedata->curvatures, sourcedata->nexprtrees);
7588  targetdata->curvature = sourcedata->curvature;
7589  targetdata->iscurvchecked = TRUE;
7590  }
7591 
7592  for( i = 0; i < targetdata->nlinvars; ++i )
7593  {
7594  SCIP_CALL( SCIPgetTransformedVar(scip, targetdata->linvars[i], &targetdata->linvars[i]) );
7595  SCIP_CALL( SCIPcaptureVar(scip, targetdata->linvars[i]) );
7596  }
7597 
7598  for( i = 0; i < targetdata->nexprtrees; ++i )
7599  {
7600  SCIP_CALL( SCIPgetExprtreeTransformedVars(scip, targetdata->exprtrees[i]) );
7601  }
7602 
7603  /* create target constraint */
7604  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
7605  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
7606  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
7607  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
7608  SCIPconsIsStickingAtNode(sourcecons)) );
7609 
7610  SCIPdebugMsg(scip, "created transformed nonlinear constraint ");
7611  SCIPdebugPrintCons(scip, *targetcons, NULL);
7612 
7613  return SCIP_OKAY;
7614 }
7615 
7616 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
7617 static
7618 SCIP_DECL_CONSINITLP(consInitlpNonlinear)
7621  SCIP_CONSDATA* consdata;
7622  SCIP_ROW* row;
7623  int c;
7624  SCIP_Real** x;
7625  int nvars;
7626  int i;
7627  int j;
7628  SCIP_VAR* var;
7629  SCIP_Bool haveunboundedvar;
7630 
7631  assert(scip != NULL);
7632  assert(conshdlr != NULL);
7633  assert(conss != NULL || nconss == 0);
7634 
7635  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7636  assert(conshdlrdata != NULL);
7637 
7638  *infeasible = FALSE;
7639 
7640  for( c = 0; c < nconss && !(*infeasible); ++c )
7641  {
7642  assert(conss[c] != NULL); /*lint !e613*/
7643 
7644  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) ); /*lint !e613*/
7645 
7646  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
7647  assert(consdata != NULL);
7648 
7649  row = NULL;
7650 
7651  if( consdata->nexprtrees == 0 )
7652  {
7653  assert(consdata->exprgraphnode == NULL);
7654  /* if we are actually linear, add the constraint as row to the LP */
7655  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(conss[c]), SCIPconsGetName(conss[c]), consdata->lhs, consdata->rhs,
7656  SCIPconsIsLocal(conss[c]), FALSE , TRUE) ); /*lint !e613*/
7657  SCIP_CALL( SCIPaddVarsToRow(scip, row, consdata->nlinvars, consdata->linvars, consdata->lincoefs) );
7658  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
7659  SCIP_CALL( SCIPreleaseRow (scip, &row) );
7660  continue;
7661  }
7662 
7663  /* setup reference points for each exprtree */
7664  SCIP_CALL( SCIPallocBufferArray(scip, &x, consdata->nexprtrees) );
7665  haveunboundedvar = FALSE;
7666  for( j = 0; j < consdata->nexprtrees; ++j )
7667  {
7668  nvars = SCIPexprtreeGetNVars(consdata->exprtrees[j]);
7669 
7670  SCIP_CALL( SCIPallocBufferArray(scip, &x[j], nvars) ); /*lint !e866*/
7671  for( i = 0; i < nvars; ++i )
7672  {
7673  var = SCIPexprtreeGetVars(consdata->exprtrees[j])[i];
7674  assert(var != NULL);
7675  /* use midpoint as reference value, if both bounds are finite
7676  * otherwise use 0.0, projected on bounds
7677  */
7678  if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(var)) )
7679  {
7680  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
7681  {
7682  x[j][i] = 0.0;
7683  haveunboundedvar = TRUE;
7684  }
7685  else
7686  x[j][i] = MIN(0.0, SCIPvarGetUbGlobal(var)); /*lint !e666*/
7687  }
7688  else
7689  {
7690  if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) )
7691  x[j][i] = MAX(0.0, SCIPvarGetLbGlobal(var)); /*lint !e666*/
7692  else
7693  {
7694  x[j][i] = (SCIPvarGetLbGlobal(var) + SCIPvarGetUbGlobal(var)) / 2.0;
7695  /* shift refpoint into [-INITLPMAXVARVAL, INITLPMAXVARVAL], if bounds allow */
7696  if( x[j][i] < -INITLPMAXVARVAL && SCIPvarGetUbGlobal(var) >= -INITLPMAXVARVAL )
7697  x[j][i] = -INITLPMAXVARVAL;
7698  else if( x[j][i] > INITLPMAXVARVAL && SCIPvarGetLbGlobal(var) <= INITLPMAXVARVAL )
7699  x[j][i] = INITLPMAXVARVAL;
7700  }
7701  }
7702  }
7703  }
7704 
7705  /* for inequalities that are convex or that have bounded variables, try to generate a cut */
7706  if( !SCIPisInfinity(scip, consdata->rhs) && ((consdata->curvature & SCIP_EXPRCURV_CONVEX) || !haveunboundedvar) )
7707  {
7708  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], x, NULL, TRUE, SCIP_SIDETYPE_RIGHT, &row,
7709  -SCIPinfinity(scip), conshdlrdata->cutmaxrange, FALSE, FALSE) ); /*lint !e613*/
7710 
7711  if( row != NULL )
7712  {
7713  SCIP_CALL( SCIPaddRow(scip, row, FALSE /* forcecut */, infeasible) );
7714  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
7715  SCIP_CALL( SCIPreleaseRow(scip, &row) );
7716  }
7717  }
7718 
7719  if( !(*infeasible) && !SCIPisInfinity(scip, -consdata->lhs) &&
7720  ((consdata->curvature & SCIP_EXPRCURV_CONCAVE) || !haveunboundedvar) )
7721  {
7722  SCIP_CALL( generateCut(scip, conshdlrdata->exprinterpreter, conss[c], x, NULL, TRUE, SCIP_SIDETYPE_LEFT, &row,
7723  -SCIPinfinity(scip), conshdlrdata->cutmaxrange, FALSE, FALSE) ); /*lint !e613*/
7724 
7725  if( row != NULL )
7726  {
7727  SCIP_CALL( SCIPaddRow(scip, row, FALSE /* forcecut */, infeasible) );
7728  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
7729  SCIP_CALL( SCIPreleaseRow(scip, &row) );
7730  }
7731  }
7732 
7733  /* @todo could add more linearizations for convex or multivariate concave inequ. */
7734 
7735  for( j = consdata->nexprtrees - 1; j >= 0; --j )
7736  {
7737  SCIPfreeBufferArray(scip, &x[j]);
7738  }
7739  SCIPfreeBufferArray(scip, &x);
7740  }
7741 
7742  return SCIP_OKAY;
7743 }
7744 
7745 /** separation method of constraint handler for LP solutions */
7746 static
7747 SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
7750  SCIP_CONS* maxviolcon;
7751  SCIP_Bool solviolbounds;
7752 
7753  assert(scip != NULL);
7754  assert(conshdlr != NULL);
7755  assert(conss != NULL || nconss == 0);
7756  assert(result != NULL);
7757 
7758  *result = SCIP_DIDNOTFIND;
7759 
7760  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7761  assert(conshdlrdata != NULL);
7762 
7763  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &solviolbounds, &maxviolcon) );
7764 
7765  /* it can happen here that the solution violates some bound - we then just don't separate, see also discussion in issue #627 */
7766  if( solviolbounds )
7767  return SCIP_OKAY;
7768 
7769  /* nothing violated -> nothing to separate */
7770  if( maxviolcon == NULL )
7771  return SCIP_OKAY;
7772 
7773  /* at root, check if we want to solve the NLP relaxation and use its solutions as reference point
7774  * if there is something convex, then linearizing in the solution of the NLP relaxation can be very useful
7775  */
7776  if( SCIPgetDepth(scip) == 0 && !conshdlrdata->sepanlp &&
7777  (SCIPgetNContVars(scip) >= conshdlrdata->sepanlpmincont * SCIPgetNVars(scip) || (SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_UNBOUNDEDRAY && conshdlrdata->sepanlpmincont <= 1.0)) &&
7778  SCIPisNLPConstructed(scip) && SCIPgetNNlpis(scip) > 0 )
7779  {
7780  SCIP_CONSDATA* consdata;
7781  SCIP_NLPSOLSTAT solstat;
7782  SCIP_Bool solvednlp; /* whether we invoked an NLP solve here */
7783  int c;
7784 
7785  solstat = SCIPgetNLPSolstat(scip);
7786  solvednlp = FALSE;
7787  if( solstat == SCIP_NLPSOLSTAT_UNKNOWN )
7788  {
7789  /* NLP is not solved yet, so we might want to do this
7790  * but first check whether there is a violated constraint side which corresponds to a convex function
7791  * @todo put this check into initsol and update via consenable/consdisable
7792  */
7793  for( c = 0; c < nconss; ++c )
7794  {
7795  assert(conss[c] != NULL); /*lint !e613*/
7796 
7797  consdata = SCIPconsGetData(conss[c]); /*lint !e613*/
7798  assert(consdata != NULL);
7799 
7800  /* skip feasible constraints */
7801  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
7802  continue;
7803 
7804  /* make sure curvature has been checked */
7805  SCIP_CALL( checkCurvature(scip, conss[c], conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) ); /*lint !e613*/
7806 
7807  if( (SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) && (consdata->curvature & SCIP_EXPRCURV_CONVEX )) ||
7808  ( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && (consdata->curvature & SCIP_EXPRCURV_CONCAVE)) )
7809  break;
7810  }
7811 
7812  if( c < nconss )
7813  {
7814  /* try to solve NLP and update solstat */
7815 
7816  /* ensure linear conss are in NLP */
7817  if( conshdlrdata->subnlpheur != NULL )
7818  {
7819  SCIP_CALL( SCIPaddLinearConsToNlpHeurSubNlp(scip, conshdlrdata->subnlpheur, TRUE, TRUE) );
7820  }
7821 
7822  /* set LP solution as starting values, if available */
7824  {
7826  }
7827 
7828  /* SCIP_CALL( SCIPsetNLPIntPar(scip, SCIP_NLPPAR_VERBLEVEL, 1) ); */
7829  SCIP_CALL( SCIPsolveNLP(scip) );
7830 
7831  solstat = SCIPgetNLPSolstat(scip);
7832  SCIPdebugMsg(scip, "solved NLP relax, solution status: %d\n", solstat);
7833 
7834  solvednlp = TRUE;
7835  }
7836  }
7837 
7838  conshdlrdata->sepanlp = TRUE;
7839 
7840  if( solstat == SCIP_NLPSOLSTAT_GLOBINFEASIBLE )
7841  {
7842  SCIPdebugMsg(scip, "NLP relaxation is globally infeasible, thus can cutoff node\n");
7843  *result = SCIP_CUTOFF;
7844  return SCIP_OKAY;
7845  }
7846 
7847  if( solstat <= SCIP_NLPSOLSTAT_FEASIBLE )
7848  {
7849  /* if we have feasible NLP solution, generate linearization cuts there */
7850  SCIP_Bool lpsolseparated;
7851  SCIP_SOL* nlpsol;
7852 
7853  SCIP_CALL( SCIPcreateNLPSol(scip, &nlpsol, NULL) );
7854  assert(nlpsol != NULL);
7855 
7856  /* if we solved the NLP and solution is integral, then pass it to trysol heuristic */
7857  if( solvednlp && conshdlrdata->trysolheur != NULL )
7858  {
7859  int nfracvars;
7860 
7861  nfracvars = 0;
7862  if( SCIPgetNBinVars(scip) > 0 || SCIPgetNIntVars(scip) > 0 )
7863  {
7864  SCIP_CALL( SCIPgetNLPFracVars(scip, NULL, NULL, NULL, &nfracvars, NULL) );
7865  }
7866 
7867  if( nfracvars == 0 )
7868  {
7869  SCIP_CALL( SCIPheurPassSolTrySol(scip, conshdlrdata->trysolheur, nlpsol) );
7870  }
7871  }
7872 
7873  SCIP_CALL( addLinearizationCuts(scip, conshdlr, conss, nconss, nlpsol, &lpsolseparated, SCIPgetSepaMinEfficacy(scip)) );
7874 
7875  SCIP_CALL( SCIPfreeSol(scip, &nlpsol) );
7876 
7877  /* if a cut that separated the LP solution was added, then return, otherwise continue with usual separation in LP solution */
7878  if( lpsolseparated )
7879  {
7880  SCIPdebugMsg(scip, "linearization cuts separate LP solution\n");
7881 
7882  *result = SCIP_SEPARATED;
7883 
7884  return SCIP_OKAY;
7885  }
7886  }
7887  }
7888  /* if we do not want to try solving the NLP, or have no NLP, or have no NLP solver, or solving the NLP failed,
7889  * or separating with NLP solution as reference point failed, then try (again) with LP solution as reference point
7890  */
7891 
7892  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, NULL, TRUE, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
7893 
7894  return SCIP_OKAY;
7895 }
7896 
7897 /** separation method of constraint handler for arbitrary primal solutions */
7898 static
7899 SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
7901  SCIP_CONS* maxviolcon;
7902  SCIP_Bool solviolbounds;
7903 
7904  assert(scip != NULL);
7905  assert(conshdlr != NULL);
7906  assert(conss != NULL || nconss == 0);
7907  assert(sol != NULL);
7908  assert(result != NULL);
7909 
7910  *result = SCIP_DIDNOTFIND;
7911 
7912  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, sol, &solviolbounds, &maxviolcon) );
7913 
7914  /* odd, if this happens for non-LP solutions, but luckily we can just give up here */
7915  if( solviolbounds )
7916  return SCIP_OKAY;
7917 
7918  /* nothing violated -> nothing to separate */
7919  if( maxviolcon == NULL )
7920  return SCIP_OKAY;
7921 
7922  /* computeViolations already evaluated all constraints, so can pass newsol = FALSE here
7923  * in contrast to Sepalp, a sol != NULL is not projected onto the box in computeViolation
7924  */
7925  SCIP_CALL( separatePoint(scip, conshdlr, conss, nconss, nusefulconss, sol, FALSE, SCIPgetSepaMinEfficacy(scip), FALSE, result, NULL) );
7926 
7927  return SCIP_OKAY;
7928 }
7929 
7930 /** constraint enforcing method of constraint handler for LP solutions */
7931 static
7932 SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
7933 { /*lint --e{715}*/
7934  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, solinfeasible, result) );
7935 
7936  return SCIP_OKAY;
7937 }
7938 
7939 /** constraint enforcing method of constraint handler for relaxation solutions */
7940 static
7941 SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
7942 { /*lint --e{715}*/
7943  SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, solinfeasible, result) );
7944 
7945  return SCIP_OKAY;
7946 }
7947 
7948 /** constraint enforcing method of constraint handler for pseudo solutions */
7949 static
7950 SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
7952  SCIP_CONS* maxviolcons;
7953  SCIP_CONSDATA* consdata;
7954  SCIP_RESULT propresult;
7955  SCIP_VAR* var;
7956  int dummy;
7957  int nnotify;
7958  int c;
7959  int i;
7960  int j;
7961  SCIP_Bool solviolbounds = FALSE;
7962 
7963  assert(scip != NULL);
7964  assert(conss != NULL || nconss == 0);
7965 
7966  SCIP_CALL( computeViolations(scip, conshdlr, conss, nconss, NULL, &solviolbounds, &maxviolcons) );
7967 
7968  /* we enforce a pseudo-solution, which should be within (read: at) bounds by definition */
7969  assert(!solviolbounds);
7970 
7971  if( maxviolcons == NULL )
7972  {
7973  *result = SCIP_FEASIBLE;
7974  return SCIP_OKAY;
7975  }
7976 
7977  *result = SCIP_INFEASIBLE;
7978 
7979  SCIPdebugMsg(scip, "enfops with max violation in cons <%s>\n", SCIPconsGetName(maxviolcons));
7980 
7981  /* we propagate constraints only if they are active and enforcing by branching only does not seem much effective */
7982  assert(SCIPconsIsActive(maxviolcons));
7983 
7984  /* run domain propagation */
7985  dummy = 0;
7986  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, TRUE, &propresult, &dummy, &dummy) );
7987  if( propresult == SCIP_CUTOFF || propresult == SCIP_REDUCEDDOM )
7988  {
7989  *result = propresult;
7990  return SCIP_OKAY;
7991  }
7992 
7993  /* We are not feasible and we cannot prove that the whole node is infeasible -> collect all variables in violated
7994  * constraints for branching. */
7995  nnotify = 0;
7996  for( c = 0; c < nconss; ++c )
7997  {
7998  assert(conss != NULL);
7999  consdata = SCIPconsGetData(conss[c]);
8000  assert(consdata != NULL);
8001 
8002  if( !SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) && !SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
8003  continue;
8004 
8005  for( i = 0; i < consdata->nlinvars; ++i )
8006  {
8007  var = consdata->linvars[i];
8008  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
8009  {
8010  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
8011  ++nnotify;
8012  }
8013  }
8014 
8015  for( j = 0; j < consdata->nexprtrees; ++j )
8016  {
8017  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]); ++i )
8018  {
8019  var = SCIPexprtreeGetVars(consdata->exprtrees[j])[i];
8020  if( !SCIPisRelEQ(scip, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var)) )
8021  {
8022  SCIP_CALL( SCIPaddExternBranchCand(scip, var, MAX(consdata->lhsviol, consdata->rhsviol), SCIP_INVALID) );
8023  ++nnotify;
8024  }
8025  }
8026  }
8027  }
8028 
8029  if( nnotify == 0 )
8030  {
8031  SCIPdebugMsg(scip, "All variables in violated constraints fixed (up to epsilon). Cannot find branching candidate. Forcing solution of LP.\n");
8032  *result = SCIP_SOLVELP;
8033  }
8034 
8035  assert(*result == SCIP_SOLVELP || (*result == SCIP_INFEASIBLE && nnotify > 0));
8036  return SCIP_OKAY;
8037 } /*lint !e715*/
8038 
8039 
8040 /** feasibility check method of constraint handler for integral solutions */
8041 static
8042 SCIP_DECL_CONSCHECK(consCheckNonlinear)
8045  SCIP_CONSDATA* consdata;
8046  SCIP_Real maxviol;
8047  int c;
8048  SCIP_Bool maypropfeasible; /* whether we may be able to propose a feasible solution */
8049  SCIP_Bool solviolbounds;
8050 
8051  assert(scip != NULL);
8052  assert(conss != NULL || nconss == 0);
8053  assert(result != NULL);
8054 
8055  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8056  assert(conshdlrdata != NULL);
8057 
8058  *result = SCIP_FEASIBLE;
8059 
8060  /* during presolve, we do not have exprtrees in the constraints, but we can get values from the expression graph, if we have evaluated it */
8062  {
8063  SCIP_Real* varvals;
8064 
8065  assert(conshdlrdata->exprgraph != NULL);
8066 
8067  SCIP_CALL( SCIPallocBufferArray(scip, &varvals, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
8068  SCIP_CALL( SCIPgetSolVals(scip, sol, SCIPexprgraphGetNVars(conshdlrdata->exprgraph), (SCIP_VAR**)SCIPexprgraphGetVars(conshdlrdata->exprgraph), varvals) );
8069 
8070  SCIP_CALL( SCIPexprgraphEval(conshdlrdata->exprgraph, varvals) );
8071 
8072  SCIPfreeBufferArray(scip, &varvals);
8073  }
8074 
8075  /* @todo adapt proposeFeasibleSolution to function also during presolving */
8076  maxviol = 0.0;
8077  maypropfeasible = conshdlrdata->linfeasshift && (conshdlrdata->trysolheur != NULL) &&
8081 
8082  for( c = 0; c < nconss; ++c )
8083  {
8084  assert(conss != NULL);
8085  SCIP_CALL( computeViolation(scip, conshdlr, conss[c], sol, &solviolbounds) );
8086  assert(!solviolbounds); /* see also issue #627 */
8087 
8088  consdata = SCIPconsGetData(conss[c]);
8089  assert(consdata != NULL);
8090 
8091  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) || SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
8092  {
8093  *result = SCIP_INFEASIBLE;
8094  if( printreason )
8095  {
8096  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
8097  SCIPinfoMessage(scip, NULL, ";\n");
8098  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
8099  {
8100  SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhsviol);
8101  }
8102  if( SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)) )
8103  {
8104  SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", consdata->rhsviol);
8105  }
8106  }
8107 
8108  if( (conshdlrdata->subnlpheur == NULL || sol == NULL) && !maypropfeasible && !completely )
8109  return SCIP_OKAY;
8110 
8111  if( consdata->lhsviol > maxviol || consdata->rhsviol > maxviol )
8112  maxviol = MAX(consdata->lhsviol, consdata->rhsviol);
8113 
8114  /* do not try to shift linear variables if activity is at infinity (leads to setting variable to infinity in solution, which is not allowed) */
8115  if( maypropfeasible && SCIPisInfinity(scip, REALABS(consdata->activity)) )
8116  maypropfeasible = FALSE;
8117 
8118  if( maypropfeasible )
8119  {
8120  /* update information on linear variables that may be in- or decreased */
8121  if( SCIPgetStage(scip) != SCIP_STAGE_SOLVING )
8122  consdataFindUnlockedLinearVar(scip, consdata);
8123 
8124  if( SCIPisGT(scip, consdata->lhsviol, SCIPfeastol(scip)) )
8125  {
8126  /* check if there is a variable which may help to get the left hand side satisfied
8127  * if there is no such var, then we cannot get feasible */
8128  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] > 0.0) &&
8129  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] < 0.0) )
8130  maypropfeasible = FALSE;
8131  }
8132  else
8133  {
8134  assert(SCIPisGT(scip, consdata->rhsviol, SCIPfeastol(scip)));
8135  /* check if there is a variable which may help to get the right hand side satisfied
8136  * if there is no such var, then we cannot get feasible */
8137  if( !(consdata->linvar_mayincrease >= 0 && consdata->lincoefs[consdata->linvar_mayincrease] < 0.0) &&
8138  ! (consdata->linvar_maydecrease >= 0 && consdata->lincoefs[consdata->linvar_maydecrease] > 0.0) )
8139  maypropfeasible = FALSE;
8140  }
8141  }
8142  }
8143  else
8144  {
8145  /* SCIPdebugMsg(scip, "constraint <%s> is feasible (%g, %g) in check, activity = %g, sides = [%g, %g]\n", SCIPconsGetName(conss[c]), consdata->lhsviol, consdata->rhsviol, consdata->activity, consdata->lhs, consdata->rhs); */
8146  }
8147  }
8148 
8149  if( *result == SCIP_INFEASIBLE && maypropfeasible )
8150  {
8151  SCIP_Bool success;
8152 
8153  SCIP_CALL( proposeFeasibleSolution(scip, conshdlr, conss, nconss, sol, &success) );
8154 
8155  /* do not pass solution to NLP heuristic if we made it feasible this way */
8156  if( success )
8157  return SCIP_OKAY;
8158  }
8159 
8160  if( *result == SCIP_INFEASIBLE && conshdlrdata->subnlpheur != NULL && sol != NULL && !SCIPisInfinity(scip, maxviol) )
8161  {
8162  SCIP_CALL( SCIPupdateStartpointHeurSubNlp(scip, conshdlrdata->subnlpheur, sol, maxviol) );
8163  }
8164 
8165  return SCIP_OKAY;
8166 } /*lint !e715*/
8167 
8168 
8169 /** domain propagation method of constraint handler */
8170 static
8171 SCIP_DECL_CONSPROP(consPropNonlinear)
8173  int dummy;
8174 
8175  assert(scip != NULL);
8176  assert(conshdlr != NULL);
8177  assert(conss != NULL || nconss == 0);
8178  assert(result != NULL);
8179 
8180  dummy = 0;
8181  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nmarkedconss, TRUE, result, &dummy, &dummy) );
8182 
8183  return SCIP_OKAY;
8184 } /*lint !e715*/
8185 
8186 /** presolving method of constraint handler */
8187 static
8188 SCIP_DECL_CONSPRESOL(consPresolNonlinear)
8191  SCIP_CONSDATA* consdata;
8192  SCIP_RESULT propresult;
8193  SCIP_Bool havechange;
8194  SCIP_Bool domainerror;
8195  SCIP_Bool havegraphchange;
8196  SCIP_Bool tryupgrades;
8197  int c;
8198 
8199  assert(scip != NULL);
8200  assert(conshdlr != NULL);
8201  assert(conss != NULL || nconss == 0);
8202  assert(result != NULL);
8203 
8204  *result = SCIP_DIDNOTFIND;
8205 
8206  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8207  assert(conshdlrdata != NULL);
8208  assert(conshdlrdata->exprgraph != NULL);
8209 
8210  havegraphchange = FALSE;
8211 
8212  if( !conshdlrdata->isremovedfixings )
8213  {
8214  SCIP_CALL( removeFixedNonlinearVariables(scip, conshdlr) );
8215  assert(conshdlrdata->isremovedfixings);
8216 
8217  havegraphchange = TRUE;
8218  }
8219 
8220  SCIP_CALL( SCIPexprgraphSimplify(conshdlrdata->exprgraph, SCIPgetMessagehdlr(scip), SCIPepsilon(scip), conshdlrdata->maxexpansionexponent, &havechange, &domainerror) );
8221  SCIPdebugMsg(scip, "expression graph simplifier found %schange, domain error = %u\n", havechange ? "" : "no ", domainerror);
8222 
8223  /* if simplifier found some undefined expression, then declare problem as infeasible
8224  * usually, this should be discovered during domain propagation already, but since that is using interval arithmetics,
8225  * it may overestimate in a way that actually undefined expressions still get a value assigned (e.g., 0^(-1) = [-inf,inf])
8226  */
8227  if( domainerror )
8228  *result = SCIP_CUTOFF;
8229 
8230  havegraphchange |= havechange;
8231 
8232  /* if graph has changed, then we will try upgrades, otherwise we only do for changing or not-yet-presolved constraints */
8233  tryupgrades = havegraphchange;
8234 
8235  /* remove fixed vars, do some algebraic manipulation, etc; this loop needs to finish, even if a cutoff is found, because data
8236  * might be inconsistent otherwise (i.e. some asserts might pop later, e.g. exitpresol, etc) */
8237  for( c = 0; c < nconss; ++c )
8238  {
8239  assert(conss != NULL);
8240 
8241  consdata = SCIPconsGetData(conss[c]);
8242  assert(consdata != NULL);
8243 
8244  SCIPdebugMsg(scip, "process constraint <%s>\n", SCIPconsGetName(conss[c]));
8245  SCIPdebugPrintCons(scip, conss[c], NULL);
8246 
8247  havechange = FALSE;
8248 
8249  if( !consdata->isremovedfixingslin )
8250  {
8251  SCIP_CALL( removeFixedLinearVariables(scip, conss[c]) );
8252  assert(consdata->isremovedfixingslin);
8253  havechange = TRUE;
8254  }
8255 
8256  /* the reductions below require the constraint nonlinear function to be in the expression graph, which is only the
8257  * case for active constraints
8258  */
8259  if( !SCIPconsIsActive(conss[c]) )
8260  continue;
8261 
8262  if( !consdata->ispresolved || havegraphchange )
8263  {
8264  SCIP_Bool infeasible;
8265 
8266  SCIP_CALL( splitOffLinearPart(scip, conshdlr, conss[c], &infeasible) );
8267 
8268  if( infeasible )
8269  {
8270  *result = SCIP_CUTOFF;
8271  continue;
8272  }
8273  }
8274 
8275  if( consdata->nlinvars == 0 && consdata->exprgraphnode == NULL )
8276  {
8277  /* all variables fixed or removed, constraint function is 0.0 now */
8278  if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasPositive(scip, consdata->lhs)) ||
8279  ( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasNegative(scip, consdata->rhs)) )
8280  {
8281  /* left hand side positive or right hand side negative */
8282  SCIPdebugMsg(scip, "constraint <%s> is constant and infeasible\n", SCIPconsGetName(conss[c]));
8283  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
8284  *result = SCIP_CUTOFF;
8285  }
8286  else
8287  {
8288  /* left and right hand side are consistent */
8289  SCIPdebugMsg(scip, "constraint <%s> is constant and feasible, deleting\n", SCIPconsGetName(conss[c]));
8290  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
8291  ++*ndelconss;
8292 
8293  if( *result != SCIP_CUTOFF )
8294  *result = SCIP_SUCCESS;
8295  continue;
8296  }
8297  }
8298 
8299  /* remember that we want to call upgrade methods for the current constraint */
8300  if( havechange )
8301  consdata->ispresolved = FALSE;
8302 
8303  /* if a constraint is not finished presolving yet, then we will try upgrade methods */
8304  if( !consdata->ispresolved )
8305  tryupgrades = TRUE;
8306  }
8307 
8308  /* if a cutoff was found, return; data is consistent at this point */
8309  if( *result == SCIP_CUTOFF )
8310  return SCIP_OKAY;
8311 
8312  if( tryupgrades )
8313  {
8314  /* upgrade methods may look at expression graph bounds, which are not present in the first presolving round yet and may be invalid in later rounds (e.g., due to probing) */
8315  SCIP_CALL( SCIPexprgraphPropagateVarBounds(conshdlrdata->exprgraph, INTERVALINFTY, TRUE, &domainerror) );
8316 
8317  if( domainerror )
8318  {
8319  SCIPdebugMsg(scip, "propagating variable bounds through expression graph found that some expressions cannot be evaluated w.r.t. current bounds, thus cutoff\n");
8320  *result = SCIP_CUTOFF;
8321  return SCIP_OKAY;
8322  }
8323 
8324  for( c = 0; c < nconss; ++c )
8325  {
8326  consdata = SCIPconsGetData(conss[c]); /*lint !e794*/
8327  assert(consdata != NULL);
8328 
8329  /* call upgrade methods if constraint was not presolved, has been changed, or the expression graph has changed */
8330  if( !consdata->ispresolved || havegraphchange )
8331  {
8332  SCIP_Bool upgraded;
8333 
8334  SCIP_CALL( presolveUpgrade(scip, conshdlr, conss[c], &upgraded, nupgdconss, naddconss) ); /*lint !e794*/
8335  if( upgraded )
8336  {
8337  *result = SCIP_SUCCESS;
8338  continue;
8339  }
8340  }
8341 
8342  consdata->ispresolved = TRUE;
8343  }
8344  }
8345 
8346  /* run domain propagation (if updated bounds in graph above, then can skip cleanup) */
8347  if( (presoltiming & SCIP_PRESOLTIMING_FAST) != 0 )
8348  {
8349  SCIP_CALL( propagateBounds(scip, conshdlr, conss, nconss, !tryupgrades, &propresult, nchgbds, ndelconss) );
8350  switch( propresult )
8351  {
8352  case SCIP_REDUCEDDOM:
8353  *result = SCIP_SUCCESS;
8354  break;
8355  case SCIP_CUTOFF:
8356  SCIPdebugMsg(scip, "propagation says problem is infeasible in presolve\n");
8357  *result = SCIP_CUTOFF;
8358  return SCIP_OKAY;
8359  default:
8360  assert(propresult == SCIP_DIDNOTFIND || propresult == SCIP_DIDNOTRUN);
8361  } /*lint !e788*/
8362  }
8363 
8364  if( conshdlrdata->reformulate && !conshdlrdata->assumeconvex )
8365  {
8366  /* if other presolvers did not find enough changes for another presolving round,
8367  * then try the reformulations (replacing products with binaries, disaggregation, setting default variable bounds)
8368  * otherwise, we wait with these
8369  */
8370  if( SCIPisPresolveFinished(scip) || (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
8371  {
8372  int naddconssbefore;
8373 
8374  SCIPdebugMsg(scip, "reformulating expression graph\n");
8375 
8376  naddconssbefore = conshdlrdata->naddedreformconss;
8377  SCIP_CALL( reformulate(scip, conshdlr, conss, nconss, &conshdlrdata->naddedreformconss) );
8378 
8379  if( conshdlrdata->naddedreformconss > naddconssbefore )
8380  {
8381  *result = SCIP_SUCCESS;
8382  *naddconss += conshdlrdata->naddedreformconss - naddconssbefore;
8383 
8384  /* if expression graph changed, ensure that we apply all presolving techniques (esp. upgrades) in next round again */
8385  for( c = 0; c < nconss; ++c )
8386  {
8387  assert(conss[c] != NULL); /*lint !e794*/
8388 
8389  consdata = SCIPconsGetData(conss[c]); /*lint !e794*/
8390  assert(consdata != NULL);
8391 
8392  consdata->ispresolved = FALSE;
8393  }
8394  }
8395  }
8396  }
8397 
8398  return SCIP_OKAY;
8399 } /*lint !e715*/
8400 
8401 
8402 /** variable rounding lock method of constraint handler */
8403 static
8404 SCIP_DECL_CONSLOCK(consLockNonlinear)
8406  SCIP_CONSDATA* consdata;
8407  SCIP_Bool havelhs;
8408  SCIP_Bool haverhs;
8409  int i;
8410 
8411  assert(scip != NULL);
8412  assert(cons != NULL);
8413  assert(locktype == SCIP_LOCKTYPE_MODEL);
8414 
8415  /* variable locking for nonlinear part is done w.r.t. variables in the expression graph
8416  * since only active constraints have their nonlinear part in the expression graph, we can lock only active constraints
8417  */
8418  assert(SCIPconsIsActive(cons) || SCIPconsIsDeleted(cons));
8419 
8420  consdata = SCIPconsGetData(cons);
8421  assert(consdata != NULL);
8422 
8423  havelhs = !SCIPisInfinity(scip, -consdata->lhs);
8424  haverhs = !SCIPisInfinity(scip, consdata->rhs);
8425 
8426  for( i = 0; i < consdata->nlinvars; ++i )
8427  {
8428  if( consdata->lincoefs[i] > 0 )
8429  {
8430  if( havelhs )
8431  {
8432  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlockspos, nlocksneg) );
8433  }
8434  if( haverhs )
8435  {
8436  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlocksneg, nlockspos) );
8437  }
8438  }
8439  else
8440  {
8441  if( havelhs )
8442  {
8443  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlocksneg, nlockspos) );
8444  }
8445  if( haverhs )
8446  {
8447  SCIP_CALL( SCIPaddVarLocksType(scip, consdata->linvars[i], locktype, nlockspos, nlocksneg) );
8448  }
8449  }
8450  }
8451 
8452  return SCIP_OKAY;
8453 } /*lint !e715*/
8454 
8455 /** constraint activation notification method of constraint handler */
8456 static
8457 SCIP_DECL_CONSACTIVE(consActiveNonlinear)
8458 { /*lint --e{715}*/
8460  SCIP_CONSDATA* consdata;
8461 
8462  assert(scip != NULL);
8463  assert(conshdlr != NULL);
8464  assert(cons != NULL);
8465  assert(SCIPconsIsTransformed(cons));
8466 
8467  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8468  assert(conshdlrdata != NULL);
8469  assert(conshdlrdata->exprgraph != NULL);
8470 
8471  consdata = SCIPconsGetData(cons);
8472  assert(consdata != NULL);
8473 
8474  SCIPdebugMsg(scip, "activate cons <%s>\n", SCIPconsGetName(cons));
8475 
8476  if( consdata->nexprtrees > 0 )
8477  {
8478  SCIP_Bool exprtreeisnew;
8479 
8480  assert(consdata->exprgraphnode == NULL);
8481 
8482  /* add exprtrees to expression graph */
8483  SCIP_CALL( SCIPexprgraphAddExprtreeSum(conshdlrdata->exprgraph, consdata->nexprtrees, consdata->exprtrees, consdata->nonlincoefs, &consdata->exprgraphnode, &exprtreeisnew) );
8484  assert(consdata->exprgraphnode != NULL);
8485  /* @todo do something with exprtreeisnew? */
8486 
8487  /* if during presolving, then forget expression trees */
8489  {
8490  SCIP_CALL( consdataSetExprtrees(scip, consdata, 0, NULL, NULL, FALSE) );
8491  }
8492 
8493  /* remember that we should run reformulation again */
8494  conshdlrdata->isreformulated = FALSE;
8495 
8496  /* remember that we should force backward propagation on our subgraph propagating the next time,
8497  * so possible domain restrictions are propagated into variable bounds
8498  */
8499  consdata->forcebackprop = TRUE;
8500  }
8501  else if( consdata->exprgraphnode != NULL )
8502  {
8503  /* if constraint already comes with node in expression graph, then also remember that we should run reformulation again */
8504  conshdlrdata->isreformulated = FALSE;
8505 
8506  /* remember that we should force backward propagation on our subgraph propagating the next time,
8507  * so possible domain restrictions are propagated into variable bounds
8508  */
8509  consdata->forcebackprop = TRUE;
8510  }
8511 
8512  return SCIP_OKAY;
8513 }
8514 
8515 /** constraint deactivation notification method of constraint handler */
8516 static
8517 SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
8518 { /*lint --e{715}*/
8520  SCIP_CONSDATA* consdata;
8521 
8522  assert(scip != NULL);
8523  assert(conshdlr != NULL);
8524  assert(cons != NULL);
8525  assert(SCIPconsIsTransformed(cons));
8526 
8527  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8528  assert(conshdlrdata != NULL);
8529  assert(conshdlrdata->exprgraph != NULL);
8530 
8531  consdata = SCIPconsGetData(cons);
8532  assert(consdata != NULL);
8533  assert(consdata->exprgraphnode != NULL || consdata->nexprtrees == 0);
8534 
8535  SCIPdebugMsg(scip, "deactivate cons <%s>\n", SCIPconsGetName(cons));
8536 
8537  if( consdata->exprgraphnode != NULL )
8538  {
8539  if( consdata->nexprtrees == 0 )
8540  {
8541  /* during presolving, the exprtrees in the constraint are removed, so put them back before releasing the exprgraphnode */
8542  SCIP_EXPRTREE* exprtree;
8543 
8544  /* if only presolve is run and problem is found infeasible there, then constraints may not be deactivated there, but in a later call to freeTransform */
8545  /* @todo if infeasible in presolve, will constraints be deactivated still in presolving stage, or in exitpre? */
8547 
8548  SCIP_CALL( SCIPexprgraphGetTree(conshdlrdata->exprgraph, consdata->exprgraphnode, &exprtree) );
8549  SCIP_CALL( consdataSetExprtrees(scip, consdata, 1, &exprtree, NULL, FALSE) );
8550  }
8551 
8552  SCIP_CALL( SCIPexprgraphReleaseNode(conshdlrdata->exprgraph, &consdata->exprgraphnode) );
8553  }
8554 
8555  return SCIP_OKAY;
8556 }
8557 
8558 /** constraint enabling notification method of constraint handler */
8559 static
8560 SCIP_DECL_CONSENABLE(consEnableNonlinear)
8561 { /*lint --e{715}*/
8563  SCIP_CONSDATA* consdata;
8564  int i;
8565 
8566  assert(scip != NULL);
8567  assert(conshdlr != NULL);
8568  assert(cons != NULL);
8569  assert(SCIPconsIsTransformed(cons));
8570  assert(SCIPconsIsActive(cons));
8571 
8572  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8573  assert(conshdlrdata != NULL);
8574  assert(conshdlrdata->exprgraph != NULL);
8575 
8576  consdata = SCIPconsGetData(cons);
8577  assert(consdata != NULL);
8578 
8579  SCIPdebugMsg(scip, "enable cons <%s>\n", SCIPconsGetName(cons));
8580 
8581  if( consdata->exprgraphnode != NULL )
8582  {
8583  /* enable node of expression in expression graph */
8584  SCIPexprgraphEnableNode(conshdlrdata->exprgraph, consdata->exprgraphnode);
8585  }
8586 
8587  /* enable event catching for linear variables */
8588  consdata->isremovedfixingslin = TRUE;
8589  for( i = 0; i < consdata->nlinvars; ++i )
8590  {
8591  SCIP_CALL( catchLinearVarEvents(scip, cons, i) );
8592 
8593  consdata->isremovedfixingslin = consdata->isremovedfixingslin && SCIPvarIsActive(consdata->linvars[i]);
8594  }
8595 
8596  return SCIP_OKAY;
8597 }
8598 
8599 /** constraint disabling notification method of constraint handler */
8600 static
8601 SCIP_DECL_CONSDISABLE(consDisableNonlinear)
8602 { /*lint --e{715}*/
8604  SCIP_CONSDATA* consdata;
8605  int i;
8606 
8607  assert(scip != NULL);
8608  assert(conshdlr != NULL);
8609  assert(cons != NULL);
8610  assert(SCIPconsIsTransformed(cons));
8611 
8612  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8613  assert(conshdlrdata != NULL);
8614  assert(conshdlrdata->exprgraph != NULL);
8615 
8616  consdata = SCIPconsGetData(cons);
8617  assert(consdata != NULL);
8618  assert(consdata->lineventdata != NULL || consdata->nlinvars == 0);
8619 
8620  SCIPdebugMsg(scip, "disable cons <%s>\n", SCIPconsGetName(cons));
8621 
8622  /* disable node of expression in expression graph */
8623  if( consdata->exprgraphnode != NULL )
8624  {
8625  SCIPexprgraphDisableNode(conshdlrdata->exprgraph, consdata->exprgraphnode);
8626  }
8627 
8628  for( i = 0; i < consdata->nlinvars; ++i )
8629  {
8630  SCIP_CALL( dropLinearVarEvents(scip, cons, i) );
8631  }
8632 
8633  return SCIP_OKAY;
8634 }
8635 
8636 
8637 /** constraint display method of constraint handler */
8638 static
8639 SCIP_DECL_CONSPRINT(consPrintNonlinear)
8641  SCIP_CONSDATA* consdata;
8642  int j;
8643 
8644  assert(scip != NULL);
8645  assert(cons != NULL);
8646 
8647  consdata = SCIPconsGetData(cons);
8648  assert(consdata != NULL);
8649 
8650  /* print left hand side for ranged rows */
8651  if( !SCIPisInfinity(scip, -consdata->lhs)
8652  && !SCIPisInfinity(scip, consdata->rhs)
8653  && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
8654  SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
8655 
8656  /* print coefficients and variables */
8657  if( consdata->nlinvars == 0 && consdata->nexprtrees == 0 && consdata->exprgraphnode == 0 )
8658  {
8659  SCIPinfoMessage(scip, file, "0 ");
8660  }
8661  else
8662  {
8663  if( consdata->nexprtrees > 0 )
8664  {
8665  for( j = 0; j < consdata->nexprtrees; ++j )
8666  {
8667  if( j > 0 || consdata->nonlincoefs[j] != 1.0 )
8668  SCIPinfoMessage(scip, file, " %+.15g ", consdata->nonlincoefs[j]);
8669  SCIP_CALL( SCIPexprtreePrintWithNames(consdata->exprtrees[j], SCIPgetMessagehdlr(scip), file) );
8670  }
8671  }
8672  else if( consdata->exprgraphnode != NULL )
8673  {
8675  SCIP_EXPRTREE* tree;
8676 
8677  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8678  assert(conshdlrdata != NULL);
8679  SCIP_CALL( SCIPexprgraphGetTree(conshdlrdata->exprgraph, consdata->exprgraphnode, &tree) );
8680 
8682 
8683  SCIP_CALL( SCIPexprtreeFree(&tree) );
8684  }
8685 
8686  for( j = 0; j < consdata->nlinvars; ++j )
8687  {
8688  SCIPinfoMessage(scip, file, " %+.15g <%s>[%c] ", consdata->lincoefs[j], SCIPvarGetName(consdata->linvars[j]),
8689  SCIPvarGetType(consdata->linvars[j]) == SCIP_VARTYPE_BINARY ? 'B' :
8690  SCIPvarGetType(consdata->linvars[j]) == SCIP_VARTYPE_INTEGER ? 'I' :
8691  SCIPvarGetType(consdata->linvars[j]) == SCIP_VARTYPE_IMPLINT ? 'I' : 'C');
8692  }
8693  }
8694 
8695  /* print right hand side */
8696  if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
8697  {
8698  SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
8699  }
8700  else if( !SCIPisInfinity(scip, consdata->rhs) )
8701  {
8702  SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
8703  }
8704  else if( !SCIPisInfinity(scip, -consdata->lhs) )
8705  {
8706  SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
8707  }
8708  else
8709  {
8710  SCIPinfoMessage(scip, file, " [free]");
8711  }
8712 
8713  return SCIP_OKAY;
8714 }
8715 
8716 /** constraint copying method of constraint handler */
8717 static
8718 SCIP_DECL_CONSCOPY(consCopyNonlinear)
8720  SCIP_CONSDATA* consdata;
8721  SCIP_CONSDATA* targetconsdata;
8722  SCIP_VAR** linvars;
8723  SCIP_Real* nonlincoefs;
8724  SCIP_EXPRTREE** exprtrees;
8725  int nexprtrees;
8726  int i;
8727  int j;
8728 
8729  assert(scip != NULL);
8730  assert(cons != NULL);
8731  assert(sourcescip != NULL);
8732  assert(sourceconshdlr != NULL);
8733  assert(sourcecons != NULL);
8734  assert(varmap != NULL);
8735  assert(valid != NULL);
8736 
8737  consdata = SCIPconsGetData(sourcecons);
8738  assert(consdata != NULL);
8739 
8740  linvars = NULL;
8741  exprtrees = NULL;
8742 
8743  *valid = TRUE;
8744 
8745  if( consdata->nlinvars != 0 )
8746  {
8747  SCIP_CALL( SCIPallocBufferArray(sourcescip, &linvars, consdata->nlinvars) );
8748  for( i = 0; i < consdata->nlinvars && *valid; ++i )
8749  {
8750  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, consdata->linvars[i], &linvars[i], varmap, consmap, global, valid) );
8751  assert(!*valid || linvars[i] != NULL);
8752  }
8753  }
8754 
8755  nexprtrees = 0;
8756  nonlincoefs = NULL;
8757 
8758  if( *valid && consdata->nexprtrees > 0 )
8759  {
8760  SCIP_VAR** nonlinvars;
8761 
8762  nonlincoefs = consdata->nonlincoefs;
8763  nexprtrees = consdata->nexprtrees;
8764 
8765  SCIP_CALL( SCIPallocBufferArray(sourcescip, &exprtrees, nexprtrees) );
8766  BMSclearMemoryArray(exprtrees, nexprtrees);
8767  SCIP_CALL( SCIPallocBufferArray(sourcescip, &nonlinvars, SCIPexprtreeGetNVars(consdata->exprtrees[0])) );
8768 
8769  for( j = 0; j < consdata->nexprtrees; ++j )
8770  {
8771  SCIP_CALL( SCIPreallocBufferArray(sourcescip, &nonlinvars, SCIPexprtreeGetNVars(consdata->exprtrees[j])) );
8772  for( i = 0; i < SCIPexprtreeGetNVars(consdata->exprtrees[j]) && *valid; ++i )
8773  {
8774  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, SCIPexprtreeGetVars(consdata->exprtrees[j])[i], &nonlinvars[i], varmap, consmap, global, valid) );
8775  assert(!*valid || nonlinvars[i] != NULL);
8776  }
8777 
8778  if( *valid )
8779  {
8780  SCIP_CALL( SCIPexprtreeCopy(SCIPblkmem(scip), &exprtrees[j], consdata->exprtrees[j]) );
8781  SCIP_CALL( SCIPexprtreeSetVars(exprtrees[j], SCIPexprtreeGetNVars(consdata->exprtrees[j]), nonlinvars) );
8782  }
8783  else
8784  break;
8785  }
8786 
8787  SCIPfreeBufferArray(sourcescip, &nonlinvars);
8788  }
8789 
8790  if( *valid && consdata->nexprtrees == 0 && consdata->exprgraphnode != NULL )
8791  {
8793  SCIP_VAR** nonlinvars;
8794 
8795  conshdlrdata = SCIPconshdlrGetData(sourceconshdlr);
8796 
8797  nexprtrees = 1;
8798  SCIP_CALL( SCIPallocBufferArray(sourcescip, &exprtrees, 1) );
8799 
8800  SCIP_CALL( SCIPexprgraphGetTree(conshdlrdata->exprgraph, consdata->exprgraphnode, &exprtrees[0]) );
8801 
8802  nonlinvars = SCIPexprtreeGetVars(exprtrees[0]);
8803  for( i = 0; i < SCIPexprtreeGetNVars(exprtrees[0]); ++i )
8804  {
8805  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, nonlinvars[i], &nonlinvars[i], varmap, consmap, global, valid) );
8806  assert(!*valid || nonlinvars[i] != NULL);
8807  }
8808  }
8809 
8810  if( *valid )
8811  {
8812  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name ? name : SCIPconsGetName(sourcecons),
8813  consdata->nlinvars, linvars, consdata->lincoefs,
8814  nexprtrees, exprtrees, nonlincoefs,
8815  consdata->lhs, consdata->rhs,
8816  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
8817 
8818  /* copy information on curvature */
8819  targetconsdata = SCIPconsGetData(*cons);
8820  targetconsdata->curvature = consdata->curvature;
8821  targetconsdata->iscurvchecked = consdata->iscurvchecked && global; /* if the copy is local, then curvature may change (get stronger) */
8822  }
8823 
8824  if( exprtrees != NULL )
8825  {
8826  for( j = 0; j < nexprtrees; ++j )
8827  {
8828  if( exprtrees[j] != NULL )
8829  {
8830  SCIP_CALL( SCIPexprtreeFree(&exprtrees[j]) );
8831  }
8832  }
8833  SCIPfreeBufferArray(sourcescip, &exprtrees);
8834  }
8835  SCIPfreeBufferArrayNull(sourcescip, &linvars);
8836 
8837  return SCIP_OKAY;
8838 }
8839 
8840 /** constraint method of constraint handler which returns the variables (if possible) */
8841 static
8842 SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
8843 { /*lint --e{715}*/
8844  SCIP_CONSDATA* consdata;
8845  int cnt;
8846 
8847  assert(cons != NULL);
8848 
8849  consdata = SCIPconsGetData(cons);
8850  assert(consdata != NULL);
8851 
8852  *success = TRUE;
8853 
8854  if( varssize < consdata->nlinvars )
8855  {
8856  *success = FALSE;
8857  return SCIP_OKAY;
8858  }
8859 
8860  BMScopyMemoryArray(vars, consdata->linvars, consdata->nlinvars);
8861  cnt = consdata->nlinvars;
8862 
8863  if( consdata->exprgraphnode != NULL )
8864  {
8866  int* varsusage;
8867  int i;
8868 
8869  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8870  assert(conshdlrdata != NULL);
8871 
8872  SCIP_CALL( SCIPallocBufferArray(scip, &varsusage, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
8873 
8874  SCIPexprgraphGetSubtreeVarsUsage(conshdlrdata->exprgraph, consdata->exprgraphnode, varsusage);
8875 
8876  for( i = 0; i < SCIPexprgraphGetNVars(conshdlrdata->exprgraph); ++i )
8877  {
8878  if( varsusage[i] == 0 )
8879  continue;
8880 
8881  if( cnt >= varssize )
8882  {
8883  *success = FALSE;
8884  break;
8885  }
8886 
8887  vars[cnt] = (SCIP_VAR*)(SCIPexprgraphGetVars(conshdlrdata->exprgraph)[i]);
8888  ++cnt;
8889  }
8890 
8891  SCIPfreeBufferArray(scip, &varsusage);
8892  }
8893  else
8894  {
8895  SCIP_VAR** exprvars;
8896  int nexprvars;
8897  int e;
8898 
8899  for( e = 0; e < consdata->nexprtrees; ++e )
8900  {
8901  exprvars = SCIPexprtreeGetVars(consdata->exprtrees[e]);
8902  nexprvars = SCIPexprtreeGetNVars(consdata->exprtrees[e]);
8903  assert(exprvars != NULL || nexprvars == 0);
8904 
8905  if( cnt + nexprvars > varssize )
8906  {
8907  *success = FALSE;
8908  break;
8909  }
8910 
8911  BMScopyMemoryArray(&vars[cnt], exprvars, nexprvars); /*lint !e866*/
8912  cnt += nexprvars;
8913  }
8914  }
8915 
8916  return SCIP_OKAY;
8917 }
8918 
8919 /** constraint method of constraint handler which returns the number of variables (if possible) */
8920 static
8921 SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
8922 { /*lint --e{715}*/
8923  SCIP_CONSDATA* consdata;
8924 
8925  consdata = SCIPconsGetData(cons);
8926  assert(consdata != NULL);
8927 
8928  *nvars = consdata->nlinvars;
8929 
8930  if( consdata->exprgraphnode != NULL )
8931  {
8933  int* varsusage;
8934  int i;
8935 
8936  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8937  assert(conshdlrdata != NULL);
8938 
8939  SCIP_CALL( SCIPallocBufferArray(scip, &varsusage, SCIPexprgraphGetNVars(conshdlrdata->exprgraph)) );
8940 
8941  SCIPexprgraphGetSubtreeVarsUsage(conshdlrdata->exprgraph, consdata->exprgraphnode, varsusage);
8942 
8943  for( i = 0; i < SCIPexprgraphGetNVars(conshdlrdata->exprgraph); ++i )
8944  if( varsusage[i] > 0 )
8945  ++*nvars;
8946 
8947  SCIPfreeBufferArray(scip, &varsusage);
8948  }
8949  else
8950  {
8951  int e;
8952 
8953  for( e = 0; e < consdata->nexprtrees; ++e )
8954  *nvars += SCIPexprtreeGetNVars(consdata->exprtrees[e]);
8955  }
8956 
8957  *success = TRUE;
8958 
8959  return SCIP_OKAY;
8960 }
8961 
8962 /** constraint parsing method of constraint handler */
8963 static
8964 SCIP_DECL_CONSPARSE(consParseNonlinear)
8965 { /*lint --e{715}*/
8966  SCIP_EXPRTREE* exprtree;
8967  SCIP_EXPR* expr;
8968  SCIP_VAR** exprvars;
8969  SCIP_RETCODE retcode;
8970  int nvars;
8971  SCIP_Real lhs;
8972  SCIP_Real rhs;
8973  const char* endptr;
8974  char* nonconstendptr;
8975  const char* exprstart;
8976  const char* exprlastchar;
8977  int* varnames;
8978  int* curvarname;
8979  int varnameslength;
8980  int i;
8981 
8982  SCIPdebugMsg(scip, "cons_nonlinear::consparse parsing %s\n",str);
8983 
8984  assert(scip != NULL);
8985  assert(success != NULL);
8986  assert(str != NULL);
8987  assert(name != NULL);
8988  assert(cons != NULL);
8989 
8990  /* return if string empty */
8991  if( !*str )
8992  return SCIP_OKAY;
8993 
8994  endptr = str;
8995 
8996  expr = NULL;
8997  nvars = 0;
8998 
8999  /* set left and right hand side to their default values */
9000  lhs = -SCIPinfinity(scip);
9001  rhs = SCIPinfinity(scip);
9002 
9003  /* parse constraint to get lhs, rhs, and expression in between (from cons_linear.c::consparse, but parsing whole string first, then getting expression) */
9004 
9005  /* check for left hand side */
9006  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
9007  {
9008  /* there is a number coming, maybe it is a left-hand-side */
9009  if( !SCIPstrToRealValue(str, &lhs, &nonconstendptr) )
9010  {
9011  SCIPerrorMessage("error parsing number from <%s>\n", str);
9012  return SCIP_READERROR;
9013  }
9014  endptr = nonconstendptr;
9015 
9016  /* ignore whitespace */
9017  while( isspace((unsigned char)*endptr) )
9018  ++endptr;
9019 
9020  if( endptr[0] != '<' || endptr[1] != '=' )
9021  {
9022  /* no '<=' coming, so it was the first coefficient, but not a left-hand-side */
9023  lhs = -SCIPinfinity(scip);
9024  }
9025  else
9026  {
9027  /* it was indeed a left-hand-side, so continue parsing after it */
9028  str = endptr + 2;
9029 
9030  /* ignore whitespace */
9031  while( isspace((unsigned char)*str) )
9032  ++str;
9033  }
9034  }
9035 
9036  /* Move endptr forward until we find end of expression */
9037  while( !(strncmp(endptr, "[free]", 6) == 0) &&
9038  !(endptr[0] == '<' && endptr[1] == '=') &&
9039  !(endptr[0] == '=' && endptr[1] == '=') &&
9040  !(endptr[0] == '>' && endptr[1] == '=') &&
9041  !(endptr[0] == '\0') )
9042  ++endptr;
9043 
9044  exprstart = str;
9045  exprlastchar = endptr - 1;
9046 
9047  *success = FALSE;
9048  str = endptr;
9049 
9050  /* check for left or right hand side */
9051  while( isspace((unsigned char)*str) )
9052  ++str;
9053 
9054  /* check for free constraint */
9055  if( strncmp(str, "[free]", 6) == 0 )
9056  {
9057  if( !SCIPisInfinity(scip, -lhs) )
9058  {
9059  SCIPerrorMessage("cannot have left hand side and [free] status \n");
9060  return SCIP_OKAY;
9061  }
9062  (*success) = TRUE;
9063  }
9064  else
9065  {
9066  switch( *str )
9067  {
9068  case '<':
9069  *success = SCIPstrToRealValue(str+2, &rhs, &nonconstendptr);
9070  break;
9071  case '=':
9072  if( !SCIPisInfinity(scip, -lhs) )
9073  {
9074  SCIPerrorMessage("cannot have == on rhs if there was a <= on lhs\n");
9075  return SCIP_OKAY;
9076  }
9077  else
9078  {
9079  *success = SCIPstrToRealValue(str+2, &rhs, &nonconstendptr);
9080  lhs = rhs;
9081  }
9082  break;
9083  case '>':
9084  if( !SCIPisInfinity(scip, -lhs) )
9085  {
9086  SCIPerrorMessage("cannot have => on rhs if there was a <= on lhs\n");
9087  return SCIP_OKAY;
9088  }
9089  else
9090  {
9091  *success = SCIPstrToRealValue(str+2, &lhs, &nonconstendptr);
9092  break;
9093  }
9094  case '\0':
9095  *success = TRUE;
9096  break;
9097  default:
9098  SCIPerrorMessage("unexpected character %c\n", *str);
9099  return SCIP_OKAY;
9100  }
9101  }
9102 
9103  /* alloc some space for variable names incl. indices; shouldn't be longer than expression string, and we even give it sizeof(int) times this length (plus 5) */
9104  varnameslength = (int) (exprlastchar - exprstart) + 5;
9105  SCIP_CALL( SCIPallocBufferArray(scip, &varnames, varnameslength) );
9106 
9107  /* parse expression */
9108  retcode = SCIPexprParse(SCIPblkmem(scip), SCIPgetMessagehdlr(scip), &expr, exprstart, exprlastchar, &nvars, varnames, varnameslength);
9109 
9110  if( retcode != SCIP_OKAY )
9111  {
9112  SCIPfreeBufferArray(scip, &varnames);
9113  return retcode;
9114  }
9115 
9116  /* get SCIP variables corresponding to variable names stored in varnames buffer */
9117  SCIP_CALL( SCIPallocBufferArray(scip, &exprvars, nvars) );
9118 
9119  assert( retcode == SCIP_OKAY );
9120  curvarname = varnames;
9121  for( i = 0; i < nvars; ++i )
9122  {
9123  assert(*curvarname == i);
9124  ++curvarname;
9125 
9126  exprvars[i] = SCIPfindVar(scip, (char*)curvarname);
9127  if( exprvars[i] == NULL )
9128  {
9129  SCIPerrorMessage("Unknown SCIP variable <%s> encountered in expression.\n", (char*)curvarname);
9130  retcode = SCIP_READERROR;
9131  goto TERMINATE;
9132  }
9133 
9134  curvarname += (strlen((char*)curvarname) + 1)/sizeof(int) + 1;
9135  }
9136 
9137  /* create expression tree */
9138  SCIP_CALL( SCIPexprtreeCreate(SCIPblkmem(scip), &exprtree, expr, nvars, 0, NULL) );
9139  SCIP_CALL( SCIPexprtreeSetVars(exprtree, nvars, exprvars) );
9140 
9141  /* create constraint */
9142  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name,
9143  0, NULL, NULL,
9144  1, &exprtree, NULL,
9145  lhs, rhs,
9146  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
9147 
9148  SCIPdebugMsg(scip, "created nonlinear constraint:\n");
9149  SCIPdebugPrintCons(scip, *cons, NULL);
9150 
9151  SCIP_CALL( SCIPexprtreeFree(&exprtree) );
9152 
9153  TERMINATE:
9154  SCIPfreeBufferArray(scip, &exprvars);
9155  SCIPfreeBufferArray(scip, &varnames);
9156 
9157  return retcode;
9158 }
9159 
9160 /*
9161  * constraint specific interface methods
9162  */
9163 
9164 /** creates the handler for nonlinear constraints and includes it in SCIP */
9166  SCIP* scip /**< SCIP data structure */
9167  )
9168 {
9170  SCIP_CONSHDLR* conshdlr;
9171 
9172  /* create nonlinear constraint handler data */
9175 
9176  /* include constraint handler */
9179  consEnfolpNonlinear, consEnfopsNonlinear, consCheckNonlinear, consLockNonlinear,
9180  conshdlrdata) );
9181  assert(conshdlr != NULL);
9182 
9183  /* set non-fundamental callbacks via specific setter functions */
9184  SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveNonlinear) );
9185  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyNonlinear, consCopyNonlinear) );
9186  SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveNonlinear) );
9187  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteNonlinear) );
9188  SCIP_CALL( SCIPsetConshdlrDisable(scip, conshdlr, consDisableNonlinear) );
9189  SCIP_CALL( SCIPsetConshdlrEnable(scip, conshdlr, consEnableNonlinear) );
9190  SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitNonlinear) );
9191  SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreNonlinear) );
9192  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolNonlinear) );
9193  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeNonlinear) );
9194  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsNonlinear) );
9195  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsNonlinear) );
9196  SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitNonlinear) );
9197  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreNonlinear) );
9198  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolNonlinear) );
9199  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpNonlinear) );
9200  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolNonlinear, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
9201  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintNonlinear) );
9202  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropNonlinear, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
9204  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpNonlinear, consSepasolNonlinear, CONSHDLR_SEPAFREQ,
9206  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransNonlinear) );
9207  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseNonlinear) );
9208  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxNonlinear) );
9209 
9210  /* add nonlinear constraint handler parameters */
9211  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/cutmaxrange",
9212  "maximal coef range of a cut (maximal coefficient divided by minimal coefficient) in order to be added to LP relaxation",
9213  &conshdlrdata->cutmaxrange, FALSE, 1e+7, 0.0, SCIPinfinity(scip), NULL, NULL) );
9214 
9215  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/linfeasshift",
9216  "whether to try to make solutions in check function feasible by shifting a linear variable (esp. useful if constraint was actually objective function)",
9217  &conshdlrdata->linfeasshift, FALSE, TRUE, NULL, NULL) );
9218 
9219 #if 0 /* don't have any expensive checks yet, so we disable this parameter for now */
9220  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkconvexexpensive",
9221  "whether to apply expensive curvature checking methods",
9222  &conshdlrdata->checkconvexexpensive, FALSE, TRUE, NULL, NULL) );
9223 #endif
9224 
9225  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/assumeconvex",
9226  "whether to assume that nonlinear functions in inequalities (<=) are convex (disables reformulation)",
9227  &conshdlrdata->assumeconvex, TRUE, FALSE, NULL, NULL) );
9228 
9229  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxproprounds",
9230  "limit on number of propagation rounds for a single constraint within one round of SCIP propagation",
9231  &conshdlrdata->maxproprounds, FALSE, 1, 0, INT_MAX, NULL, NULL) );
9232 
9233  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/reformulate",
9234  "whether to reformulate expression graph",
9235  &conshdlrdata->reformulate, FALSE, TRUE, NULL, NULL) );
9236 
9237  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxexpansionexponent",
9238  "maximal exponent where still expanding non-monomial polynomials in expression simplification",
9239  &conshdlrdata->maxexpansionexponent, TRUE, 2, 1, INT_MAX, NULL, NULL) );
9240 
9241  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/sepanlpmincont",
9242  "minimal required fraction of continuous variables in problem to use solution of NLP relaxation in root for separation",
9243  &conshdlrdata->sepanlpmincont, FALSE, 1.0, 0.0, 2.0, NULL, NULL) );
9244 
9245  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/enfocutsremovable",
9246  "are cuts added during enforcement removable from the LP in the same node?",
9247  &conshdlrdata->enfocutsremovable, TRUE, FALSE, NULL, NULL) );
9248 
9249  conshdlrdata->linvareventhdlr = NULL;
9250  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->linvareventhdlr), CONSHDLR_NAME"_boundchange", "signals a bound change to a nonlinear constraint",
9251  processLinearVarEvent, NULL) );
9252  assert(conshdlrdata->linvareventhdlr != NULL);
9253 
9254  conshdlrdata->nonlinvareventhdlr = NULL;
9255  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &(conshdlrdata->nonlinvareventhdlr), CONSHDLR_NAME"_boundchange2", "signals a bound change to a nonlinear constraint handler",
9256  processNonlinearVarEvent, (SCIP_EVENTHDLRDATA*)conshdlrdata) );
9257  assert(conshdlrdata->nonlinvareventhdlr != NULL);
9258 
9259  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, NULL, CONSHDLR_NAME"_newsolution", "handles the event that a new primal solution has been found",
9260  processNewSolutionEvent, NULL) );
9261 
9262  /* create expression interpreter */
9263  SCIP_CALL( SCIPexprintCreate(SCIPblkmem(scip), &conshdlrdata->exprinterpreter) );
9264 
9265  /* create expression graph */
9266  SCIP_CALL( SCIPexprgraphCreate(SCIPblkmem(scip), &conshdlrdata->exprgraph, -1, -1,
9267  exprgraphVarAdded, exprgraphVarRemove, NULL, (void*)conshdlrdata) );
9268  conshdlrdata->isremovedfixings = TRUE;
9269  conshdlrdata->ispropagated = TRUE;
9270 
9271  conshdlrdata->scip = scip;
9272 
9273  return SCIP_OKAY;
9274 }
9275 
9276 /** includes a nonlinear constraint upgrade method into the nonlinear constraint handler */
9278  SCIP* scip, /**< SCIP data structure */
9279  SCIP_DECL_NONLINCONSUPGD((*nonlinconsupgd)),/**< method to call for upgrading nonlinear constraint, or NULL */
9280  SCIP_DECL_EXPRGRAPHNODEREFORM((*nodereform)),/**< method to call for reformulating expression graph node, or NULL */
9281  int priority, /**< priority of upgrading method */
9282  SCIP_Bool active, /**< should the upgrading method by active by default? */
9283  const char* conshdlrname /**< name of the constraint handler */
9284  )
9285 {
9286  SCIP_CONSHDLR* conshdlr;
9288  SCIP_NLCONSUPGRADE* nlconsupgrade;
9289  char paramname[SCIP_MAXSTRLEN];
9290  char paramdesc[SCIP_MAXSTRLEN];
9291  int i;
9292 
9293  assert(conshdlrname != NULL );
9294 
9295  /* ignore empty upgrade functions */
9296  if( nonlinconsupgd == NULL && nodereform == NULL )
9297  return SCIP_OKAY;
9298 
9299  /* find the nonlinear constraint handler */
9300  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9301  if( conshdlr == NULL )
9302  {
9303  SCIPerrorMessage("nonlinear constraint handler not found\n");
9304  return SCIP_PLUGINNOTFOUND;
9305  }
9306 
9307  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9308  assert(conshdlrdata != NULL);
9309 
9310  /* check whether upgrade method exists already */
9311  for( i = conshdlrdata->nnlconsupgrades - 1; i >= 0; --i )
9312  {
9313  if( conshdlrdata->nlconsupgrades[i]->nlconsupgd == nonlinconsupgd && conshdlrdata->nlconsupgrades[i]->nodereform == nodereform)
9314  {
9315 #ifdef SCIP_DEBUG
9316  SCIPwarningMessage(scip, "Try to add already known upgrade method pair (%p,%p) for constraint handler <%s>.\n", nonlinconsupgd, nodereform, conshdlrname); /*lint !e611*/
9317 #endif
9318  return SCIP_OKAY;
9319  }
9320  }
9321 
9322  /* create a nonlinear constraint upgrade data object */
9323  SCIP_CALL( SCIPallocBlockMemory(scip, &nlconsupgrade) );
9324  nlconsupgrade->nlconsupgd = nonlinconsupgd;
9325  nlconsupgrade->nodereform = nodereform;
9326  nlconsupgrade->priority = priority;
9327  nlconsupgrade->active = active;
9328 
9329  /* insert nonlinear constraint upgrade method into constraint handler data */
9330  assert(conshdlrdata->nnlconsupgrades <= conshdlrdata->nlconsupgradessize);
9331  if( conshdlrdata->nnlconsupgrades+1 > conshdlrdata->nlconsupgradessize )
9332  {
9333  int newsize;
9334 
9335  newsize = SCIPcalcMemGrowSize(scip, conshdlrdata->nnlconsupgrades+1);
9336  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->nlconsupgrades, conshdlrdata->nnlconsupgrades, newsize) );
9337  conshdlrdata->nlconsupgradessize = newsize;
9338  }
9339  assert(conshdlrdata->nnlconsupgrades+1 <= conshdlrdata->nlconsupgradessize);
9340 
9341  for( i = conshdlrdata->nnlconsupgrades; i > 0 && conshdlrdata->nlconsupgrades[i-1]->priority < nlconsupgrade->priority; --i )
9342  conshdlrdata->nlconsupgrades[i] = conshdlrdata->nlconsupgrades[i-1];
9343  assert(0 <= i && i <= conshdlrdata->nnlconsupgrades);
9344  conshdlrdata->nlconsupgrades[i] = nlconsupgrade;
9345  conshdlrdata->nnlconsupgrades++;
9346 
9347  /* adds parameter to turn on and off the upgrading step */
9348  (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/" CONSHDLR_NAME "/upgrade/%s", conshdlrname);
9349  (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable nonlinear upgrading for constraint handler <%s>", conshdlrname);
9351  paramname, paramdesc,
9352  &nlconsupgrade->active, FALSE, active, NULL, NULL) );
9353 
9354  return SCIP_OKAY;
9355 }
9356 
9357 /** creates and captures a nonlinear constraint
9358  * this variant takes expression trees as input
9359  *
9360  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9361  */
9363  SCIP* scip, /**< SCIP data structure */
9364  SCIP_CONS** cons, /**< pointer to hold the created constraint */
9365  const char* name, /**< name of constraint */
9366  int nlinvars, /**< number of linear variables in the constraint */
9367  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
9368  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
9369  int nexprtrees, /**< number of expression trees for nonlinear part of constraint */
9370  SCIP_EXPRTREE** exprtrees, /**< expression trees for nonlinear part of constraint */
9371  SCIP_Real* nonlincoefs, /**< coefficients for expression trees for nonlinear part, or NULL if all 1.0 */
9372  SCIP_Real lhs, /**< left hand side of constraint */
9373  SCIP_Real rhs, /**< right hand side of constraint */
9374  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9375  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9376  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9377  * Usually set to TRUE. */
9378  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9379  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9380  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9381  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9382  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9383  * Usually set to TRUE. */
9384  SCIP_Bool local, /**< is constraint only valid locally?
9385  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9386  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9387  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9388  * adds coefficients to this constraint. */
9389  SCIP_Bool dynamic, /**< is constraint subject to aging?
9390  * Usually set to FALSE. Set to TRUE for own cuts which
9391  * are seperated as constraints. */
9392  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9393  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9394  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9395  * if it may be moved to a more global node?
9396  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9397  )
9398 {
9399  SCIP_CONSHDLR* conshdlr;
9400  SCIP_CONSDATA* consdata;
9401  int i;
9402 
9403  assert(linvars != NULL || nlinvars == 0);
9404  assert(lincoefs != NULL || nlinvars == 0);
9405  assert(exprtrees != NULL || nexprtrees == 0);
9406  assert(modifiable == FALSE); /* we do not support column generation */
9407 
9408  /* find the nonlinear constraint handler */
9409  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9410  if( conshdlr == NULL )
9411  {
9412  SCIPerrorMessage("nonlinear constraint handler not found\n");
9413  return SCIP_PLUGINNOTFOUND;
9414  }
9415 
9416  /* create constraint data */
9417  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
9418 
9419  consdata->lhs = lhs;
9420  consdata->rhs = rhs;
9421 
9422  /* create constraint */
9423  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
9424  local, modifiable, dynamic, removable, stickingatnode) );
9425 
9426  /* add linear variables */
9427  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
9428  for( i = 0; i < nlinvars; ++i )
9429  {
9430  if( SCIPisZero(scip, lincoefs[i]) ) /*lint !e613*/
9431  continue;
9432 
9433  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) ); /*lint !e613*/
9434  }
9435 
9436  /* set expression trees */
9437  SCIP_CALL( consdataSetExprtrees(scip, consdata, nexprtrees, exprtrees, nonlincoefs, TRUE) );
9438 
9439  SCIPdebugMsg(scip, "created nonlinear constraint ");
9440  SCIPdebugPrintCons(scip, *cons, NULL);
9441 
9442  return SCIP_OKAY;
9443 }
9444 
9445 /** creates and captures a nonlinear constraint
9446  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
9447  * method SCIPcreateConsNonlinear(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
9448  *
9449  * this variant takes expression trees as input
9450  *
9451  * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration
9452  *
9453  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9454  */
9456  SCIP* scip, /**< SCIP data structure */
9457  SCIP_CONS** cons, /**< pointer to hold the created constraint */
9458  const char* name, /**< name of constraint */
9459  int nlinvars, /**< number of linear variables in the constraint */
9460  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
9461  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
9462  int nexprtrees, /**< number of expression trees for nonlinear part of constraint */
9463  SCIP_EXPRTREE** exprtrees, /**< expression trees for nonlinear part of constraint */
9464  SCIP_Real* nonlincoefs, /**< coefficients for expression trees for nonlinear part, or NULL if all 1.0 */
9465  SCIP_Real lhs, /**< left hand side of constraint */
9466  SCIP_Real rhs /**< right hand side of constraint */
9467  )
9468 {
9469  assert(scip != NULL);
9470 
9471  SCIP_CALL( SCIPcreateConsNonlinear(scip, cons, name, nlinvars, linvars, lincoefs, nexprtrees, exprtrees,
9472  nonlincoefs, lhs, rhs,
9473  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9474 
9475  return SCIP_OKAY;
9476 }
9477 
9478 /** creates and captures a nonlinear constraint
9479  * this variant takes a node of the expression graph as input and can only be used during presolving
9480  * it is assumed that the nonlinear constraint will be added to the transformed problem short after creation
9481  * the given exprgraphnode is captured in this method
9482  *
9483  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9484  */
9486  SCIP* scip, /**< SCIP data structure */
9487  SCIP_CONS** cons, /**< pointer to hold the created constraint */
9488  const char* name, /**< name of constraint */
9489  int nlinvars, /**< number of linear variables in the constraint */
9490  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
9491  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
9492  SCIP_EXPRGRAPHNODE* exprgraphnode, /**< expression graph node associated to nonlinear expression */
9493  SCIP_Real lhs, /**< left hand side of constraint */
9494  SCIP_Real rhs, /**< right hand side of constraint */
9495  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9496  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9497  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9498  * Usually set to TRUE. */
9499  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9500  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9501  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9502  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9503  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9504  * Usually set to TRUE. */
9505  SCIP_Bool local, /**< is constraint only valid locally?
9506  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9507  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9508  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9509  * adds coefficients to this constraint. */
9510  SCIP_Bool dynamic, /**< is constraint subject to aging?
9511  * Usually set to FALSE. Set to TRUE for own cuts which
9512  * are seperated as constraints. */
9513  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9514  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9515  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9516  * if it may be moved to a more global node?
9517  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9518  )
9519 {
9520  SCIP_CONSHDLR* conshdlr;
9521  SCIP_CONSDATA* consdata;
9522  int i;
9523 
9524  assert(modifiable == FALSE); /* we do not support column generation */
9525  assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING);
9526 
9527  /* find the nonlinear constraint handler */
9528  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9529  if( conshdlr == NULL )
9530  {
9531  SCIPerrorMessage("nonlinear constraint handler not found\n");
9532  return SCIP_PLUGINNOTFOUND;
9533  }
9534 
9535  /* create constraint data */
9536  SCIP_CALL( consdataCreateEmpty(scip, &consdata) );
9537 
9538  consdata->lhs = lhs;
9539  consdata->rhs = rhs;
9540 
9541  /* create constraint */
9542  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
9543  local, modifiable, dynamic, removable, stickingatnode) );
9544 
9545  /* add linear variables */
9546  SCIP_CALL( consdataEnsureLinearVarsSize(scip, consdata, nlinvars) );
9547  for( i = 0; i < nlinvars; ++i )
9548  {
9549  if( SCIPisZero(scip, lincoefs[i]) )
9550  continue;
9551 
9552  SCIP_CALL( addLinearCoef(scip, *cons, linvars[i], lincoefs[i]) );
9553  }
9554 
9555  /* set expression graph node */
9556  if( exprgraphnode != NULL )
9557  {
9558  consdata->exprgraphnode = exprgraphnode;
9559  consdata->curvature = SCIP_EXPRCURV_UNKNOWN;
9560  consdata->iscurvchecked = FALSE;
9561  consdata->activity = SCIP_INVALID;
9562  SCIPexprgraphCaptureNode(exprgraphnode);
9563  }
9564 
9565  SCIPdebugMsg(scip, "created nonlinear constraint ");
9566  SCIPdebugPrintCons(scip, *cons, NULL);
9567 
9568  return SCIP_OKAY;
9569 }
9570 
9571 /** creates and captures a nonlinear constraint
9572  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
9573  * method SCIPcreateConsNonlinear(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
9574  *
9575  * this variant takes a node of the expression graph as input and can only be used during presolving
9576  * it is assumed that the nonlinear constraint will be added to the transformed problem short after creation
9577  * the given exprgraphnode is captured in this method
9578  *
9579  * @see SCIPcreateConsNonlinear() for information about the basic constraint flag configuration
9580  *
9581  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9582  */
9584  SCIP* scip, /**< SCIP data structure */
9585  SCIP_CONS** cons, /**< pointer to hold the created constraint */
9586  const char* name, /**< name of constraint */
9587  int nlinvars, /**< number of linear variables in the constraint */
9588  SCIP_VAR** linvars, /**< array with linear variables of constraint entries */
9589  SCIP_Real* lincoefs, /**< array with coefficients of constraint linear entries */
9590  SCIP_EXPRGRAPHNODE* exprgraphnode, /**< expression graph node associated to nonlinear expression */
9591  SCIP_Real lhs, /**< left hand side of constraint */
9592  SCIP_Real rhs /**< right hand side of constraint */
9593  )
9594 {
9595  assert(scip != NULL);
9596 
9597  SCIP_CALL( SCIPcreateConsNonlinear2(scip, cons, name, nlinvars, linvars, lincoefs, exprgraphnode, lhs, rhs,
9598  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9599 
9600  return SCIP_OKAY;
9601 }
9602 
9603 /** adds a linear variable with coefficient to a nonlinear constraint */
9605  SCIP* scip, /**< SCIP data structure */
9606  SCIP_CONS* cons, /**< constraint */
9607  SCIP_VAR* var, /**< variable */
9608  SCIP_Real coef /**< coefficient of variable */
9609  )
9610 {
9611  assert(scip != NULL);
9612  assert(cons != NULL);
9613  assert(var != NULL);
9614  assert(!SCIPisInfinity(scip, REALABS(coef)));
9615 
9616  SCIP_CALL( addLinearCoef(scip, cons, var, coef) );
9617 
9618  return SCIP_OKAY;
9619 }
9620 
9621 /** sets the expression trees in a nonlinear constraint
9622  * constraint must not be active yet
9623  */
9625  SCIP* scip, /**< SCIP data structure */
9626  SCIP_CONS* cons, /**< constraint */
9627  int nexprtrees, /**< number of expression trees */
9628  SCIP_EXPRTREE** exprtrees, /**< new expression trees, or NULL if nexprtrees is 0 */
9629  SCIP_Real* coefs /**< coefficients of expression trees, or NULL if all 1.0 */
9630  )
9631 {
9632  assert(scip != NULL);
9633  assert(cons != NULL);
9634  assert(!SCIPconsIsActive(cons));
9635  assert(SCIPconsGetData(cons) != NULL);
9636  assert(exprtrees != NULL || nexprtrees == 0);
9637 
9638  SCIP_CALL( consdataSetExprtrees(scip, SCIPconsGetData(cons), nexprtrees, exprtrees, coefs, TRUE) );
9639 
9640  return SCIP_OKAY;
9641 }
9642 
9643 /** adds expression trees to a nonlinear constraint
9644  * constraint must not be active yet
9645  */
9647  SCIP* scip, /**< SCIP data structure */
9648  SCIP_CONS* cons, /**< constraint */
9649  int nexprtrees, /**< number of expression trees */
9650  SCIP_EXPRTREE** exprtrees, /**< new expression trees, or NULL if nexprtrees is 0 */
9651  SCIP_Real* coefs /**< coefficients of expression trees, or NULL if all 1.0 */
9652  )
9653 {
9654  assert(scip != NULL);
9655  assert(cons != NULL);
9656  assert(!SCIPconsIsActive(cons));
9657  assert(SCIPconsGetData(cons) != NULL);
9658  assert(exprtrees != NULL || nexprtrees == 0);
9659 
9660  SCIP_CALL( consdataAddExprtrees(scip, SCIPconsGetData(cons), nexprtrees, exprtrees, coefs, TRUE) );
9661 
9662  return SCIP_OKAY;
9663 }
9664 
9665 /** gets the nonlinear constraint as a nonlinear row representation */
9667  SCIP* scip, /**< SCIP data structure */
9668  SCIP_CONS* cons, /**< constraint */
9669  SCIP_NLROW** nlrow /**< pointer to store nonlinear row */
9670  )
9671 {
9672  SCIP_CONSDATA* consdata;
9673 
9674  assert(cons != NULL);
9675  assert(nlrow != NULL);
9676 
9677  consdata = SCIPconsGetData(cons);
9678  assert(consdata != NULL);
9679 
9680  if( consdata->nlrow == NULL )
9681  {
9682  SCIP_CALL( createNlRow(scip, cons) );
9683  }
9684  assert(consdata->nlrow != NULL);
9685  *nlrow = consdata->nlrow;
9686 
9687  return SCIP_OKAY;
9688 }
9689 
9690 /** gets the number of variables in the linear term of a nonlinear constraint */
9692  SCIP* scip, /**< SCIP data structure */
9693  SCIP_CONS* cons /**< constraint */
9694  )
9695 {
9696  assert(cons != NULL);
9697  assert(SCIPconsGetData(cons) != NULL);
9698 
9699  return SCIPconsGetData(cons)->nlinvars;
9700 }
9701 
9702 /** gets the variables in the linear part of a nonlinear constraint */
9704  SCIP* scip, /**< SCIP data structure */
9705  SCIP_CONS* cons /**< constraint */
9706  )
9707 {
9708  assert(cons != NULL);
9709  assert(SCIPconsGetData(cons) != NULL);
9710 
9711  return SCIPconsGetData(cons)->linvars;
9712 }
9713 
9714 /** gets the coefficients in the linear part of a nonlinear constraint */
9716  SCIP* scip, /**< SCIP data structure */
9717  SCIP_CONS* cons /**< constraint */
9718  )
9719 {
9720  assert(cons != NULL);
9721  assert(SCIPconsGetData(cons) != NULL);
9722 
9723  return SCIPconsGetData(cons)->lincoefs;
9724 }
9725 
9726 /** gets the number of expression trees of a nonlinear constraint */
9728  SCIP* scip, /**< SCIP data structure */
9729  SCIP_CONS* cons /**< constraint */
9730  )
9731 {
9732  assert(cons != NULL);
9733  assert(SCIPconsGetData(cons) != NULL);
9735 
9736  return SCIPconsGetData(cons)->nexprtrees;
9737 }
9738 
9739 /** gets the expression trees of a nonlinear constraint */
9741  SCIP* scip, /**< SCIP data structure */
9742  SCIP_CONS* cons /**< constraint */
9743  )
9744 {
9745  assert(cons != NULL);
9746  assert(SCIPconsGetData(cons) != NULL);
9748 
9749  return SCIPconsGetData(cons)->exprtrees;
9750 }
9751 
9752 /** gets the coefficients of the expression trees of a nonlinear constraint */
9754  SCIP* scip, /**< SCIP data structure */
9755  SCIP_CONS* cons /**< constraint */
9756  )
9757 {
9758  assert(cons != NULL);
9759  assert(SCIPconsGetData(cons) != NULL);
9761 
9762  return SCIPconsGetData(cons)->nonlincoefs;
9763 }
9764 
9765 /** gets the expression graph node of a nonlinear constraint */
9767  SCIP* scip, /**< SCIP data structure */
9768  SCIP_CONS* cons /**< constraint */
9769  )
9770 {
9771  assert(cons != NULL);
9772  assert(SCIPconsGetData(cons) != NULL);
9773 
9774  return SCIPconsGetData(cons)->exprgraphnode;
9775 }
9776 
9777 /** gets the left hand side of a nonlinear constraint */
9779  SCIP* scip, /**< SCIP data structure */
9780  SCIP_CONS* cons /**< constraint */
9781  )
9782 {
9783  assert(cons != NULL);
9784  assert(SCIPconsGetData(cons) != NULL);
9785 
9786  return SCIPconsGetData(cons)->lhs;
9787 }
9788 
9789 /** gets the right hand side of a nonlinear constraint */
9791  SCIP* scip, /**< SCIP data structure */
9792  SCIP_CONS* cons /**< constraint */
9793  )
9794 {
9795  assert(cons != NULL);
9796  assert(SCIPconsGetData(cons) != NULL);
9797 
9798  return SCIPconsGetData(cons)->rhs;
9799 }
9800 
9801 /** check the function of a nonlinear constraint for convexity/concavity, if not done yet */
9803  SCIP* scip, /**< SCIP data structure */
9804  SCIP_CONS* cons /**< constraint */
9805  )
9806 {
9807  SCIP_CONSHDLR* conshdlr;
9809 
9810  assert(scip != NULL);
9811  assert(cons != NULL);
9812 
9813  conshdlr = SCIPconsGetHdlr(cons);
9814  assert(conshdlr != NULL);
9815  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9816  assert(conshdlrdata != NULL);
9817 
9818  SCIP_CALL( checkCurvature(scip, cons, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
9819 
9820  return SCIP_OKAY;
9821 }
9822 
9823 /** gets the curvature of the nonlinear function of a nonlinear constraint */
9825  SCIP* scip, /**< SCIP data structure */
9826  SCIP_CONS* cons, /**< constraint */
9827  SCIP_Bool checkcurv, /**< whether to check constraint curvature, if not checked before */
9828  SCIP_EXPRCURV* curvature /**< pointer to store curvature of constraint */
9829  )
9830 {
9831  SCIP_CONSHDLR* conshdlr;
9833  SCIP_CONSDATA* consdata;
9834 
9835  assert(scip != NULL);
9836  assert(cons != NULL);
9837  assert(curvature != NULL);
9838 
9839  consdata = SCIPconsGetData(cons);
9840  assert(consdata != NULL);
9841 
9842  conshdlr = SCIPconsGetHdlr(cons);
9843  assert(conshdlr != NULL);
9844  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9845  assert(conshdlrdata != NULL);
9846 
9847  if( checkcurv && !consdata->iscurvchecked )
9848  {
9849  SCIP_CALL( checkCurvature(scip, cons, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
9850  }
9851 
9852  *curvature = consdata->curvature;
9853 
9854  return SCIP_OKAY;
9855 }
9856 
9857 /** gets the curvature of the expression trees (multiplied by their coefficient) of a nonlinear constraint */
9859  SCIP* scip, /**< SCIP data structure */
9860  SCIP_CONS* cons, /**< constraint */
9861  SCIP_Bool checkcurv, /**< whether to check constraint curvature, if not checked before */
9862  SCIP_EXPRCURV** curvatures /**< buffer to store curvatures of exprtrees */
9863  )
9864 {
9865  SCIP_CONSHDLR* conshdlr;
9867  SCIP_CONSDATA* consdata;
9868 
9869  assert(scip != NULL);
9870  assert(cons != NULL);
9871  assert(curvatures != NULL);
9873 
9874  consdata = SCIPconsGetData(cons);
9875  assert(consdata != NULL);
9876 
9877  conshdlr = SCIPconsGetHdlr(cons);
9878  assert(conshdlr != NULL);
9879  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9880  assert(conshdlrdata != NULL);
9881 
9882  assert(SCIPconsGetData(cons) != NULL);
9883 
9884  if( checkcurv && !consdata->iscurvchecked )
9885  {
9886  SCIP_CALL( checkCurvature(scip, cons, conshdlrdata->checkconvexexpensive, conshdlrdata->assumeconvex) );
9887  }
9888 
9889  *curvatures = consdata->curvatures;
9890 
9891  return SCIP_OKAY;
9892 }
9893 
9894 /** computes the violation of a nonlinear constraint by a solution */
9896  SCIP* scip, /**< SCIP data structure */
9897  SCIP_CONS* cons, /**< constraint */
9898  SCIP_SOL* sol, /**< solution which violation to calculate, or NULL for LP solution */
9899  SCIP_Real* violation /**< pointer to store violation of constraint */
9900  )
9901 {
9902  SCIP_CONSHDLR* conshdlr;
9903  SCIP_CONSDATA* consdata;
9904  SCIP_Bool solviolbounds;
9905 
9906  assert(scip != NULL);
9907  assert(cons != NULL);
9908  assert(violation != NULL);
9909 
9911  {
9912  /* @todo make available */
9913  SCIPwarningMessage(scip, "SCIPgetViolationNonlinear is not available for active constraints during presolve.\n");
9914  *violation = SCIP_INVALID;
9915  return SCIP_OKAY;
9916  }
9917 
9918  conshdlr = SCIPconsGetHdlr(cons);
9919  assert(conshdlr != NULL);
9920 
9921  SCIP_CALL( computeViolation(scip, conshdlr, cons, sol, &solviolbounds) );
9922 
9923  if( solviolbounds )
9924  {
9925  SCIPerrorMessage("Solution passed to SCIPgetViolationNonlinear() does not satisfy variable bounds.\n");
9926  return SCIP_ERROR;
9927  }
9928 
9929  consdata = SCIPconsGetData(cons);
9930  assert(consdata != NULL);
9931 
9932  *violation = MAX(consdata->lhsviol, consdata->rhsviol);
9933 
9934  return SCIP_OKAY;
9935 }
9936 
9937 /** get index of a linear variable of a nonlinear constraint that may be decreased without making any other constraint infeasible, or -1 if none */
9939  SCIP* scip, /**< SCIP data structure */
9940  SCIP_CONS* cons /**< constraint */
9941  )
9942 {
9943  SCIP_CONSDATA* consdata;
9944 
9945  assert(scip != NULL);
9946  assert(cons != NULL);
9947 
9948  consdata = SCIPconsGetData(cons);
9949  assert(consdata != NULL);
9950 
9951  if( consdata->linvar_mayincrease == -1 && consdata->linvar_maydecrease == -1 )
9952  consdataFindUnlockedLinearVar(scip, consdata);
9953 
9954  return consdata->linvar_maydecrease;
9955 }
9956 
9957 /** get index of a linear variable of a nonlinear constraint that may be increased without making any other constraint infeasible, or -1 if none */
9959  SCIP* scip, /**< SCIP data structure */
9960  SCIP_CONS* cons /**< constraint */
9961  )
9962 {
9963  SCIP_CONSDATA* consdata;
9964 
9965  assert(scip != NULL);
9966  assert(cons != NULL);
9967 
9968  consdata = SCIPconsGetData(cons);
9969  assert(consdata != NULL);
9970 
9971  if( consdata->linvar_mayincrease == -1 && consdata->linvar_maydecrease == -1 )
9972  consdataFindUnlockedLinearVar(scip, consdata);
9973 
9974  return consdata->linvar_mayincrease;
9975 }
9976 
9977 /** gets expression graph of nonlinear constraint handler */
9979  SCIP* scip, /**< SCIP data structure */
9980  SCIP_CONSHDLR* conshdlr /**< nonlinear constraint handler */
9981  )
9982 {
9984 
9985  assert(scip != NULL);
9986  assert(conshdlr != NULL);
9987 
9988  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9989  assert(conshdlrdata != NULL);
9990  assert(conshdlrdata->exprgraph != NULL);
9991 
9992  return conshdlrdata->exprgraph;
9993 }
9994 
9995 /** given three points, constructs coefficient of equation for hyperplane generated by these three points
9996  * Three points a, b, and c are given.
9997  * Computes coefficients alpha, beta, gamma, and delta, such that a, b, and c, satisfy
9998  * alpha * x1 + beta * x2 + gamma * x3 = delta and gamma >= 0.0.
9999  */
10001  SCIP* scip, /**< SCIP data structure */
10002  SCIP_Real a1, /**< first coordinate of a */
10003  SCIP_Real a2, /**< second coordinate of a */
10004  SCIP_Real a3, /**< third coordinate of a */
10005  SCIP_Real b1, /**< first coordinate of b */
10006  SCIP_Real b2, /**< second coordinate of b */
10007  SCIP_Real b3, /**< third coordinate of b */
10008  SCIP_Real c1, /**< first coordinate of c */
10009  SCIP_Real c2, /**< second coordinate of c */
10010  SCIP_Real c3, /**< third coordinate of c */
10011  SCIP_Real* alpha, /**< coefficient of first coordinate */
10012  SCIP_Real* beta, /**< coefficient of second coordinate */
10013  SCIP_Real* gamma_, /**< coefficient of third coordinate */
10014  SCIP_Real* delta /**< constant right-hand side */
10015  )
10016 {
10017  assert(scip != NULL);
10018  assert(alpha != NULL);
10019  assert(beta != NULL);
10020  assert(gamma_ != NULL);
10021  assert(delta != NULL);
10022 
10023  *alpha = -b3*c2 + a3*(-b2+c2) + a2*(b3-c3) + b2*c3;
10024  *beta = -(-b3*c1 + a3*(-b1+c1) + a1*(b3-c3) + b1*c3);
10025  *gamma_ = -a2*b1 + a1*b2 + a2*c1 - b2*c1 - a1*c2 + b1*c2;
10026  *delta = -a3*b2*c1 + a2*b3*c1 + a3*b1*c2 - a1*b3*c2 - a2*b1*c3 + a1*b2*c3;
10027 
10028  /* SCIPdebugMsg(scip, "alpha: %g beta: %g gamma: %g delta: %g\n", *alpha, *beta, *gamma_, *delta); */
10029 
10030  if( SCIPisInfinity(scip, REALABS(*gamma_ * a3)) ||
10031  SCIPisInfinity(scip, REALABS(*gamma_ * b3)) ||
10032  SCIPisInfinity(scip, REALABS(*gamma_ * c3)) )
10033  {
10034  SCIPdebugMsg(scip, "activity above SCIP infinity\n");
10035  *delta = 0.0;
10036  *alpha = 0.0;
10037  *beta = 0.0;
10038  *gamma_ = 0.0;
10039  return SCIP_OKAY;
10040  }
10041 
10042  /* check if hyperplane contains all three points (necessary because of numerical troubles) */
10043  if( !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
10044  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
10045  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) )
10046  {
10047  SCIP_Real m[9];
10048  SCIP_Real rhs[3];
10049  SCIP_Real x[3];
10050  SCIP_Bool success;
10051 
10052  /*
10053  SCIPdebugMsg(scip, "a = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", a1, a2, a3, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3, SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3));
10054  SCIPdebugMsg(scip, "b = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", b1, b2, b3, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3, SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3));
10055  SCIPdebugMsg(scip, "c = (%g,%g,%g) hyperplane: %g rhs %g EQdelta: %d\n", c1, c2, c3, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3, SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3));
10056  */
10057 
10058  /* initialize matrix column-wise */
10059  m[0] = a1;
10060  m[1] = b1;
10061  m[2] = c1;
10062  m[3] = a2;
10063  m[4] = b2;
10064  m[5] = c2;
10065  m[6] = a3;
10066  m[7] = b3;
10067  m[8] = c3;
10068 
10069  rhs[0] = 1.0;
10070  rhs[1] = 1.0;
10071  rhs[2] = 1.0;
10072 
10073  SCIPdebugMsg(scip, "numerical troubles - try to solve the linear system via an LU factorization\n");
10074 
10075  /* solve the linear problem */
10076  SCIP_CALL( SCIPsolveLinearProb(3, m, rhs, x, &success) );
10077  assert(success);
10078 
10079  *delta = rhs[0];
10080  *alpha = x[0];
10081  *beta = x[1];
10082  *gamma_ = x[2];
10083 
10084  /* set all coefficients to zero if one of the points is not contained in the hyperplane; this ensures that we do
10085  * not add a cut to SCIP and that all assertions are trivially fulfilled
10086  */
10087  if( !success || !SCIPisRelEQ(scip, *alpha * a1 + *beta * a2 - *delta, -*gamma_ * a3) ||
10088  !SCIPisRelEQ(scip, *alpha * b1 + *beta * b2 - *delta, -*gamma_ * b3) ||
10089  !SCIPisRelEQ(scip, *alpha * c1 + *beta * c2 - *delta, -*gamma_ * c3) ) /*lint !e774*/
10090  {
10091  SCIPdebugMsg(scip, "could not resolve numerical difficulties\n");
10092  *delta = 0.0;
10093  *alpha = 0.0;
10094  *beta = 0.0;
10095  *gamma_ = 0.0;
10096  }
10097  }
10098 
10099  if( *gamma_ < 0.0 )
10100  {
10101  *alpha = -*alpha;
10102  *beta = -*beta;
10103  *gamma_ = -*gamma_;
10104  *delta = -*delta;
10105  }
10106 
10107  return SCIP_OKAY;
10108 }
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:2451
SCIP_EXPORT SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
static SCIP_DECL_CONSENABLE(consEnableNonlinear)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPround(SCIP *scip, SCIP_Real val)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
SCIP_EXPORT SCIP_RETCODE SCIPlpiSetIntpar(SCIP_LPI *lpi, SCIP_LPPARAM type, int ival)
static SCIP_DECL_EXPRGRAPHVARREMOVE(exprgraphVarRemove)
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13338
SCIP_Real SCIPfeastol(SCIP *scip)
static SCIP_RETCODE presolveUpgrade(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *upgraded, int *nupgdconss, int *naddconss)
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15844
SCIP_Bool SCIPisRelEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:86
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, 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)
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2167
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15525
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:976
static void consdataUpdateLinearActivityUbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17075
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_EXPORT SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16880
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip_branch.c:959
SCIP_EXPORT SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
SCIP_Bool SCIPconsIsLockedType(SCIP_CONS *cons, SCIP_LOCKTYPE locktype)
Definition: cons.c:8469
SCIP_RETCODE SCIPcreateConsNonlinear2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPRGRAPHNODE *exprgraphnode, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define NULL
Definition: def.h:253
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:686
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14980
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:242
SCIP_Bool SCIPconsIsEnabled(SCIP_CONS *cons)
Definition: cons.c:8173
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:585
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprgraphAddNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int mindepth, int nchildren, SCIP_EXPRGRAPHNODE **children)
Definition: expr.c:15180
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:80
primal heuristic that tries a given solution
SCIP_RETCODE SCIPaddExternBranchCand(SCIP *scip, SCIP_VAR *var, SCIP_Real score, SCIP_Real solval)
Definition: scip_branch.c:654
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:876
SCIP_RETCODE SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16774
const char * SCIPheurGetName(SCIP_HEUR *heur)
Definition: heur.c:1254
public methods for SCIP parameter handling
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:15264
SCIP_Real * SCIPgetExprtreeCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPgetSepaMinEfficacy(SCIP *scip)
Definition: scip_sepa.c:297
static void consdataFindUnlockedLinearVar(SCIP *scip, SCIP_CONSDATA *consdata)
methods to interpret (evaluate) an expression tree "fast"
SCIP_RETCODE SCIPgetCurvatureNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkcurv, SCIP_EXPRCURV *curvature)
SCIP_RETCODE SCIPcheckCurvatureNonlinear(SCIP *scip, SCIP_CONS *cons)
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:58
public methods for branch and bound tree
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5921
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:452
static SCIP_RETCODE getCoeffsAndConstantFromLinearExpr(SCIP_EXPR *expr, SCIP_Real scalar, SCIP_Real *varcoeffs, SCIP_Real *constant)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:14769
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5121
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:933
static SCIP_RETCODE addLinearizationCuts(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *ref, SCIP_Bool *separatedlpsol, SCIP_Real minefficacy)
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8315
SCIP_EXPORT int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3241
public methods for memory management
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:307
static SCIP_DECL_CONSEXIT(consExitNonlinear)
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12974
SCIP_CONS * cons
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:113
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
static SCIP_DECL_CONSDISABLE(consDisableNonlinear)
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5694
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8275
SCIP_EXPORT SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
SCIP_RETCODE SCIPmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1950
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:165
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4200
static SCIP_RETCODE unlockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14950
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSACTIVE((*consactive)))
Definition: scip_cons.c:654
static SCIP_RETCODE addUserEstimator(SCIP *scip, SCIP_CONS *cons, int exprtreeidx, SCIP_Real *x, SCIP_Bool overestimate, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
#define SCIP_MAXSTRLEN
Definition: def.h:274
SCIP_EVENTHDLR * SCIPfindEventhdlr(SCIP *scip, const char *name)
Definition: scip_event.c:224
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:1167
SCIP_RETCODE SCIPaddRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep, int nvars, SCIP_VAR **vars, SCIP_Real *coefs)
static SCIP_RETCODE consdataAddExprtrees(SCIP *scip, SCIP_CONSDATA *consdata, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_Bool copytrees)
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:122
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
static SCIP_DECL_EXPRGRAPHVARADDED(exprgraphVarAdded)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:815
int SCIPexprgraphGetDepth(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14920
SCIP_RETCODE SCIPcleanupRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_SOL *sol, SCIP_Real maxcoefrange, SCIP_Real minviol, SCIP_Real *coefrange, SCIP_Real *viol)
const char * SCIPexpropGetName(SCIP_EXPROP op)
Definition: expr.c:3264
int SCIPgetNExprtreesNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1217
type definitions for expression interpreter
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1352
SCIP_RETCODE SCIPaddRowprepTerm(SCIP *scip, SCIP_ROWPREP *rowprep, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5237
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2031
static SCIP_RETCODE checkCurvature(SCIP *scip, SCIP_CONS *cons, SCIP_Bool expensivechecks, SCIP_Bool assumeconvex)
SCIP_Real * SCIPexprtreeGetParamVals(SCIP_EXPRTREE *tree)
Definition: expr.c:8633
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
SCIP_RETCODE SCIPexprCreateMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial, SCIP_Real coef, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:7036
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:15024
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:769
static SCIP_RETCODE reformEnsureChildrenMinCurvature(SCIP *scip, SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRCURV mincurv, SCIP_CONS **conss, int nconss, int *naddcons)
void SCIPexprgraphCaptureNode(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12952
static SCIP_RETCODE splitOffLinearPart(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool *infeasible)
SCIP_EXPRTREE ** SCIPgetExprtreesNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:8505
interface methods for specific LP solvers
struct SCIP_EventhdlrData SCIP_EVENTHDLRDATA
Definition: type_event.h:138
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4593
#define SCIP_EXPRINTCAPABILITY_INTGRADIENT
SCIP_EXPORT SCIP_RETCODE SCIPlpiAddRows(SCIP_LPI *lpi, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
SCIP_RETCODE SCIPexprgraphCreateNodeQuadratic(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nchildren, SCIP_Real *lincoefs, int nquadelems, SCIP_QUADELEM *quadelems, SCIP_Real constant)
Definition: expr.c:13467
static SCIP_RETCODE consdataCreateEmpty(SCIP *scip, SCIP_CONSDATA **consdata)
int SCIPexprGetOpIndex(SCIP_EXPR *expr)
Definition: expr.c:5724
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:80
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1987
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8137
#define NLOCKTYPES
Definition: type_var.h:81
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
SCIP_SIDETYPE sidetype
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:215
void SCIPexprgraphPropagateNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:15898
#define FALSE
Definition: def.h:73
static SCIP_DECL_CONSINITPRE(consInitpreNonlinear)
static SCIP_DECL_CONSENFOLP(consEnfolpNonlinear)
SCIP_EXPORT SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17200
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14970
SCIP_EXPORT SCIP_HEUR * SCIPsolGetHeur(SCIP_SOL *sol)
Definition: sol.c:2553
SCIP_EXPORT SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16903
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13103
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:72
#define SCIPdebug(x)
Definition: pub_message.h:74
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static SCIP_RETCODE addLinearization(SCIP *scip, SCIP_EXPRINT *exprint, SCIP_CONS *cons, int exprtreeidx, SCIP_Real *x, SCIP_Bool newx, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_Bool SCIPisRelLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:45
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3470
SCIP_EXPORT SCIP_RETCODE SCIPexprintGrad(SCIP_EXPRINT *exprint, SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Bool new_varvals, SCIP_Real *val, SCIP_Real *gradient)
static SCIP_RETCODE consdataSetExprtrees(SCIP *scip, SCIP_CONSDATA *consdata, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_Bool copytrees)
SCIP_RETCODE SCIPexprtreeCopy(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **targettree, SCIP_EXPRTREE *sourcetree)
Definition: expr.c:8813
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12994
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8245
SCIP_Real SCIPgetRhsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_INTERVAL SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13328
static SCIP_RETCODE addConcaveEstimatorUnivariate(SCIP *scip, SCIP_CONS *cons, int exprtreeidx, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15823
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:562
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int * SCIPexprgraphGetNNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14930
SCIP_EXPORT SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17025
public methods for problem variables
SCIP_RETCODE SCIPexprEvalInt(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7928
SCIP_EXPORT SCIP_Bool SCIPlpiIsObjlimExc(SCIP_LPI *lpi)
static GRAPHNODE ** active
SCIP_Real SCIPadjustedVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real ub)
Definition: scip_var.c:4583
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:47
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:95
#define CONSHDLR_SEPAFREQ
static SCIP_DECL_CONSSEPALP(consSepalpNonlinear)
SCIP_EXPORT void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_EXPORT SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16857
SCIP_Real SCIPgetUpperbound(SCIP *scip)
static void consdataUpdateLinearActivityLbChange(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_Real coef, SCIP_Real oldbnd, SCIP_Real newbnd)
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15384
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:524
static SCIP_DECL_CONSACTIVE(consActiveNonlinear)
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8772
static SCIP_DECL_CONSSEPASOL(consSepasolNonlinear)
#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:380
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:838
static SCIP_RETCODE reformReplaceNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, SCIP_EXPRGRAPHNODE *replacement, SCIP_CONS **conss, int nconss)
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:78
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:83
public methods for SCIP variables
#define CONSHDLR_NAME
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:500
SCIP_RETCODE SCIPunlinkSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1181
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:108
#define SCIPdebugMsgPrint
Definition: scip_message.h:70
#define SCIPdebugMsg
Definition: scip_message.h:69
SCIP_RETCODE SCIPcreateNLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:389
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2005
public methods for separator plugins
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:15131
SCIP_VAR ** x
Definition: circlepacking.c:54
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool solinfeasible, SCIP_RESULT *result)
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4291
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:158
#define SCIP_DECL_EXPRGRAPHNODEREFORM(x)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13197
#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:356
static SCIP_RETCODE removeFixedNonlinearVariables(SCIP *scip, SCIP_CONSHDLR *conshdlr)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPgetNLPFracVars(SCIP *scip, SCIP_VAR ***fracvars, SCIP_Real **fracvarssol, SCIP_Real **fracvarsfrac, int *nfracvars, int *npriofracvars)
Definition: scip_nlp.c:712
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2077
SCIP_RETCODE SCIPsolveNLP(SCIP *scip)
Definition: scip_nlp.c:569
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:14403
public methods for numerical tolerances
SCIP_EXPORT SCIP_Bool SCIPlpiIsIterlimExc(SCIP_LPI *lpi)
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:248
SCIP_EXPORT SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17144
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:264
public methods for expressions, expression trees, expression graphs, and related stuff ...
#define SCIP_EVENTTYPE_LBCHANGED
Definition: type_event.h:104
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2838
SCIP_EXPRCURV SCIPexprcurvMultiply(SCIP_Real factor, SCIP_EXPRCURV curvature)
Definition: expr.c:240
#define MIN3(x, y, z)
Definition: def.h:228
int SCIPexprGetMonomialNFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5911
public methods for querying solving statistics
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
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:672
SCIP_EVENTHDLRDATA * SCIPeventhdlrGetData(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:324
SCIP_RETCODE SCIPexprtreeCheckCurvature(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:9011
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13034
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13185
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:15092
static SCIP_DECL_CONSGETVARS(consGetVarsNonlinear)
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition: scip_sol.c:609
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip_nlp.c:1275
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:92
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8542
SCIP_Real coef
Definition: type_expr.h:104
public methods for managing constraints
#define SCIP_EVENTTYPE_SOLFOUND
Definition: type_event.h:127
SCIP_RETCODE SCIPgetExprtreeCurvaturesNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkcurv, SCIP_EXPRCURV **curvatures)
void SCIPfreeRowprep(SCIP *scip, SCIP_ROWPREP **rowprep)
SCIP_Real inf
Definition: intervalarith.h:39
SCIP_RETCODE SCIPcheckCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_RESULT *result)
Definition: scip_cons.c:2071
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10571
const char * SCIPexprcurvGetName(SCIP_EXPRCURV curv)
Definition: expr.c:474
static SCIP_DECL_CONSCHECK(consCheckNonlinear)
static SCIP_RETCODE addConcaveEstimatorMultivariate(SCIP *scip, SCIP_CONS *cons, int exprtreeidx, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize, SCIP_Bool mergemultiples)
Definition: scip_var.c:1740
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13209
SCIP_RETCODE SCIPsetConshdlrExit(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXIT((*consexit)))
Definition: scip_cons.c:404
SCIP_RETCODE SCIPcreateConsBasicNonlinear(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)
static SCIP_RETCODE registerBranchingVariables(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *nnotify)
SCIP_Bool SCIPexprgraphHasNodeNonlinearAncestor(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14654
SCIP_EXPORT const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16738
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13348
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprEval(SCIP_EXPR *expr, SCIP_Real *varvals, SCIP_Real *param, SCIP_Real *val)
Definition: expr.c:7867
static SCIP_DECL_EVENTEXEC(processLinearVarEvent)
enum SCIP_LockType SCIP_LOCKTYPE
Definition: type_var.h:87
SCIP_EXPORT SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16929
#define SCIPerrorMessage
Definition: pub_message.h:45
static SCIP_RETCODE consdataEnsureLinearVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
#define CONSHDLR_ENFOPRIORITY
static SCIP_DECL_CONSINITLP(consInitlpNonlinear)
static SCIP_RETCODE propagateBoundsTightenVarLb(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10364
interval arithmetics for provable bounds
static SCIP_RETCODE computeViolation(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *solviolbounds)
SCIP_RETCODE SCIPincSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real incval)
Definition: scip_sol.c:1309
enum SCIP_NlpSolStat SCIP_NLPSOLSTAT
Definition: type_nlpi.h:69
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1406
SCIP_EXPRGRAPHNODE *** SCIPexprgraphGetNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14940
#define SCIP_DECL_NONLINCONSUPGD(x)
public methods for event handler plugins and event handlers
SCIP_Real SCIPintervalGetInf(SCIP_INTERVAL interval)
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16738
#define CONSHDLR_PROP_TIMING
SCIP_RETCODE SCIPcatchEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:276
SCIP_RETCODE SCIPexprtreePrintWithNames(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: nlp.c:173
static SCIP_RETCODE lockLinearVariable(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:595
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:428
SCIP_RETCODE SCIPsetConshdlrDisable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDISABLE((*consdisable)))
Definition: scip_cons.c:723
SCIP_RETCODE SCIPaddExprtreesNonlinear(SCIP *scip, SCIP_CONS *cons, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs)
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:1442
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:124
SCIP_RETCODE SCIPgetNlRowNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_NLROW **nlrow)
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:47
public methods for expression handlers
SCIP_RETCODE SCIPcreateConsBasicNonlinear2(SCIP *scip, SCIP_CONS **cons, const char *name, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPRGRAPHNODE *exprgraphnode, SCIP_Real lhs, SCIP_Real rhs)
static SCIP_DECL_CONSDEACTIVE(consDeactiveNonlinear)
static SCIP_RETCODE mergeAndCleanLinearVars(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPRCURV SCIPexprcurvPower(SCIP_INTERVAL basebounds, SCIP_EXPRCURV basecurv, SCIP_Real exponent)
Definition: expr.c:253
void SCIPaddRowprepSide(SCIP_ROWPREP *rowprep, SCIP_Real side)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:155
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:87
constraint handler for quadratic constraints
#define BOUNDTIGHTENING_MINSTRENGTH
static SCIP_RETCODE propagateBoundsTightenVarUb(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real bnd, SCIP_RESULT *result, int *nchgbds)
type definitions for specific LP solvers interface
static SCIP_RETCODE propagateBounds(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_Bool needclear, SCIP_RESULT *result, int *nchgbds, int *ndelconss)
SCIP_EXPORT SCIP_RETCODE SCIPexprintFree(SCIP_EXPRINT **exprint)
SCIP_RETCODE SCIPcreateRowprep(SCIP *scip, SCIP_ROWPREP **rowprep, SCIP_SIDETYPE sidetype, SCIP_Bool local)
SCIPInterval fabs(const SCIPInterval &x)
#define REALABS(x)
Definition: def.h:188
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:8613
int SCIPgetLinvarMayDecreaseNonlinear(SCIP *scip, SCIP_CONS *cons)
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 SCIPexprgraphCreateNodeLinear(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int ncoefs, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:13441
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:476
static SCIP_RETCODE reformNode2Var(SCIP *scip, SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_CONS **conss, int nconss, int *naddcons, SCIP_Bool donotmultaggr)
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8106
#define SCIP_CALL(x)
Definition: def.h:365
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12964
static SCIP_RETCODE chgLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos, SCIP_Real newcoef)
#define INITLPMAXVARVAL
static SCIP_RETCODE addConcaveEstimatorBivariate(SCIP *scip, SCIP_CONS *cons, int exprtreeidx, SCIP_Real *ref, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
SCIP_EXPORT SCIP_RETCODE SCIPlpiAddCols(SCIP_LPI *lpi, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:995
SCIP_VAR * h
Definition: circlepacking.c:59
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1198
SCIP_Real sup
Definition: intervalarith.h:40
SCIP_RETCODE SCIPsetExprtreesNonlinear(SCIP *scip, SCIP_CONS *cons, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs)
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:14707
SCIP_RETCODE SCIPexprEstimateUser(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_Real *argvals, SCIP_INTERVAL *argbounds, SCIP_Bool overestimate, SCIP_Real *coeffs, SCIP_Real *constant, SCIP_Bool *success)
Definition: expr.c:8108
SCIP_RETCODE SCIPgetViolationNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Real *violation)
#define SCIPdebugGetSolVal(scip, var, val)
Definition: debug.h:257
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:51
SCIP_EXPORT SCIP_RETCODE SCIPexprintCreate(BMS_BLKMEM *blkmem, SCIP_EXPRINT **exprint)
#define SCIP_EVENTTYPE_BOUNDTIGHTENED
Definition: type_event.h:106
SCIP_EXPR * SCIPexprtreeGetRoot(SCIP_EXPRTREE *tree)
Definition: expr.c:8603
SCIP_Bool SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14619
public methods for primal heuristic plugins and divesets
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:13224
#define SCIP_EVENTTYPE_UBCHANGED
Definition: type_event.h:105
public methods for constraint handler plugins and constraints
public methods for NLP management
static SCIP_RETCODE delLinearCoefPos(SCIP *scip, SCIP_CONS *cons, int pos)
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1748
static SCIP_RETCODE dropLinearVarEvents(SCIP *scip, SCIP_CONS *cons, int linvarpos)
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8345
static void consdataSortLinearVars(SCIP_CONSDATA *consdata)
int SCIPgetNLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE reformMonomial(SCIP *scip, SCIP_EXPRGRAPH *exprgraph, int nfactors, SCIP_EXPRGRAPHNODE **factors, SCIP_Real *exponents, SCIP_EXPRGRAPHNODE **resultnode, SCIP_Bool createauxcons, int mindepth, int *naddcons)
Ipopt NLP interface.
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:111
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:129
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:219
#define CONSHDLR_CHECKPRIORITY
public data structures and miscellaneous methods
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1174
static SCIP_RETCODE catchLinearVarEvents(SCIP *scip, SCIP_CONS *cons, int linvarpos)
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:5714
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4376
SCIP_EXPORT SCIP_RETCODE SCIPexprintEval(SCIP_EXPRINT *exprint, SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
SCIP_Real side
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:637
#define SCIP_Bool
Definition: def.h:70
#define infty2infty(infty1, infty2, val)
static SCIP_DECL_CONSENFORELAX(consEnforelaxNonlinear)
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:390
static SCIP_RETCODE createNlRow(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPORT SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17156
static SCIP_RETCODE reformulate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int *naddcons)
SCIP_Bool SCIPisSumLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE propagateConstraintSides(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_RESULT *result, int *nchgbds)
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:15044
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:331
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:209
int SCIPgetNNlpis(SCIP *scip)
Definition: scip_nlp.c:131
static void consdataUpdateLinearActivity(SCIP *scip, SCIP_CONSDATA *consdata)
SCIP_RETCODE SCIPexprtreeSetVars(SCIP_EXPRTREE *tree, int nvars, SCIP_VAR **vars)
Definition: nlp.c:112
SCIP_EXPORT SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17362
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2472
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8658
constraint handler for nonlinear constraints
SCIP_NLPSOLSTAT SCIPgetNLPSolstat(SCIP *scip)
Definition: scip_nlp.c:592
SCIP_RETCODE SCIPgetExprtreeTransformedVars(SCIP *scip, SCIP_EXPRTREE *tree)
Definition: scip_expr.c:74
void SCIPmergeRowprepTerms(SCIP *scip, SCIP_ROWPREP *rowprep)
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:90
SCIP_Bool SCIPexprHasUserEstimator(SCIP_EXPR *expr)
Definition: expr.c:5952
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4211
SCIP_EXPORT SCIP_RETCODE SCIPlpiSetRealpar(SCIP_LPI *lpi, SCIP_LPPARAM type, SCIP_Real dval)
SCIP_RETCODE SCIPcreateLPSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:361
SCIP_Bool SCIPisCutApplicable(SCIP *scip, SCIP_ROW *cut)
Definition: scip_cut.c:177
SCIP_EXPORT SCIP_EXPRINTCAPABILITY SCIPexprintGetCapability(void)
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition: scip_var.c:104
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:5704
#define MIN(x, y)
Definition: def.h:223
methods for debugging
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1268
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:16722
public methods for LP management
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:15064
#define CONSHDLR_PROPFREQ
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define CONSHDLR_NEEDSCONS
SCIP_RETCODE SCIPexprgraphNodeSplitOffLinear(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, int linvarssize, int *nlinvars, void **linvars, SCIP_Real *lincoefs, SCIP_Real *constant)
Definition: expr.c:13591
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8385
public methods for cuts and aggregation rows
SCIP_RETCODE SCIPexprtreeFree(SCIP_EXPRTREE **tree)
Definition: expr.c:8853
static SCIP_RETCODE proposeFeasibleSolution(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *success)
#define CONSHDLR_DELAYSEPA
int SCIPgetLinvarMayIncreaseNonlinear(SCIP *scip, SCIP_CONS *cons)
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_VAR ** SCIPexprtreeGetVars(SCIP_EXPRTREE *tree)
Definition: nlp.c:102
static SCIP_RETCODE registerLargeRelaxValueVariableForBranching(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_VAR **brvar)
SCIP_Real SCIPgetLhsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPORT SCIP_Real SCIPnodeGetEstimate(SCIP_NODE *node)
Definition: tree.c:7377
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14581
SCIP_Real SCIPintervalGetSup(SCIP_INTERVAL interval)
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:124
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8255
Constraint handler for linear constraints in their most general form, .
SCIP_Real * SCIPgetLinearCoefsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_prob.c:1667
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyNonlinear)
static SCIP_DECL_CONSPROP(consPropNonlinear)
SCIP_Bool SCIPisFeasGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define BMSclearMemory(ptr)
Definition: memory.h:119
SCIP_Real SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5901
SCIP_RETCODE SCIPgetRowprepRowCons(SCIP *scip, SCIP_ROW **row, SCIP_ROWPREP *rowprep, SCIP_CONSHDLR *conshdlr)
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8335
char name[SCIP_MAXSTRLEN]
SCIP_EXPORT SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17408
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:94
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:129
SCIP_RETCODE SCIPunmarkConsPropagate(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1978
SCIP_VAR * SCIPfindVar(SCIP *scip, const char *name)
Definition: scip_prob.c:2680
public methods for the LP relaxation, rows and columns
#define INTERVALINFTY
SCIP_RETCODE SCIPaddLinearConsToNlpHeurSubNlp(SCIP *scip, SCIP_HEUR *heur, SCIP_Bool addcombconss, SCIP_Bool addcontconss)
Definition: heur_subnlp.c:2417
SCIP_EXPORT int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:3184
#define CONSHDLR_SEPAPRIORITY
int SCIPexprgraphGetNodeIntPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13092
public methods for nonlinear relaxations
static SCIP_DECL_CONSDELETE(consDeleteNonlinear)
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13004
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
static SCIP_RETCODE addLinearCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
static SCIP_DECL_CONSTRANS(consTransNonlinear)
SCIP_EXPORT SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17418
methods for sorting joint arrays of various types
static SCIP_RETCODE removeFixedLinearVariables(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1389
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:95
public methods for branching rule plugins and branching
#define CONSHDLR_PRESOLTIMING
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:220
SCIP_EXPORT SCIP_Bool SCIPlpiIsPrimalUnbounded(SCIP_LPI *lpi)
public methods for managing events
general public methods
#define MAX(x, y)
Definition: def.h:222
SCIP_EXPORT SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
static SCIP_RETCODE generateCut(SCIP *scip, SCIP_EXPRINT *exprint, SCIP_CONS *cons, SCIP_Real **ref, SCIP_SOL *sol, SCIP_Bool newsol, SCIP_SIDETYPE side, SCIP_ROW **row, SCIP_Real minviol, SCIP_Real maxrange, SCIP_Bool expensivecurvchecks, SCIP_Bool assumeconvex)
SCIP_EXPORT SCIP_Bool SCIPlpiIsPrimalFeasible(SCIP_LPI *lpi)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_DECL_CONSGETNVARS(consGetNVarsNonlinear)
SCIP_Real * SCIPexprGetLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5790
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
#define CONSHDLR_DELAYPROP
SCIP_Real SCIPexprGetOpReal(SCIP_EXPR *expr)
Definition: expr.c:5735
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13024
SCIP_EXPORT SCIP_Bool SCIPlpiIsOptimal(SCIP_LPI *lpi)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8265
SCIP_RETCODE SCIPdropEvent(SCIP *scip, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:310
SCIP_EXPORT SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
#define SCIP_EVENTTYPE_FORMAT
Definition: type_event.h:135
SCIP_EXPORT SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17352
public methods for the probing mode
SCIP_EXPRGRAPH * SCIPgetExprgraphNonlinear(SCIP *scip, SCIP_CONSHDLR *conshdlr)
static SCIP_RETCODE propagateBoundsCons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_RESULT *result, int *nchgbds, SCIP_Bool *redundant)
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDEACTIVE((*consdeactive)))
Definition: scip_cons.c:677
void SCIPenableNLP(SCIP *scip)
Definition: scip_nlp.c:194
SCIP_EXPORT int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17120
void SCIPintervalSetRoundingModeUpwards(void)
SCIP_RETCODE SCIPsolveLinearProb(int N, SCIP_Real *A, SCIP_Real *b, SCIP_Real *x, SCIP_Bool *success)
SCIP_RETCODE SCIPexprgraphCreateNodePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:13493
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4563
SCIP_CONSHDLRDATA * conshdlrdata
public methods for message output
static SCIP_RETCODE computeViolations(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool *solviolbounds, SCIP_CONS **maxviolcon)
SCIP_RETCODE SCIPexprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op,...)
Definition: expr.c:13358
NLP local search primal heuristic using sub-SCIPs.
SCIP_Real SCIPgetSolTransObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1482
SCIP_RETCODE SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14435
static SCIP_RETCODE separatePoint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_Bool newsol, SCIP_Real minefficacy, SCIP_Bool inenforcement, SCIP_RESULT *result, SCIP_Real *bestefficacy)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10263
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:73
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8076
struct SCIP_LPi SCIP_LPI
Definition: type_lpi.h:96
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1251
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8205
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:16235
#define SCIP_Real
Definition: def.h:164
#define CONSHDLR_EAGERFREQ
static SCIP_DECL_CONSFREE(consFreeNonlinear)
static void consdataMoveLinearVar(SCIP_CONSDATA *consdata, int oldpos, int newpos)
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:8096
SCIP_EXPORT SCIP_RETCODE SCIPexprintGradInt(SCIP_EXPRINT *exprint, SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Bool new_varvals, SCIP_INTERVAL *val, SCIP_INTERVAL *gradient)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_DECL_CONSENFOPS(consEnfopsNonlinear)
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:12984
#define SCIP_INVALID
Definition: def.h:184
SCIP_Real SCIPgetRowLPFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1848
SCIP_EXPRGRAPHNODE * SCIPgetExprgraphNodeNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5931
void SCIPexprgraphPrintNode(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: expr.c:14691
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:460
static SCIP_DECL_CONSINITSOL(consInitsolNonlinear)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8355
SCIP_RETCODE SCIPexprParse(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR **expr, const char *str, const char *lastchar, int *nvars, int *varnames, int varnameslength)
Definition: expr.c:8539
#define SCIPdebugAddSolVal(scip, var, val)
Definition: debug.h:256
static SCIP_DECL_CONSEXITPRE(consExitpreNonlinear)
#define SCIPisFinite(x)
Definition: pub_misc.h:1826
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2032
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1796
SCIP_Real SCIPlpfeastol(SCIP *scip)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:344
SCIP_RETCODE SCIPexprgraphSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange, SCIP_Bool *domainerror)
Definition: expr.c:15973
#define CONSHDLR_MAXPREROUNDS
static SCIP_DECL_CONSPRINT(consPrintNonlinear)
SCIP_RETCODE SCIPevalExprtreeLocalBounds(SCIP *scip, SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *val)
Definition: scip_expr.c:233
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
static SCIP_DECL_CONSINIT(consInitNonlinear)
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1018
SCIP_EXPORT SCIP_RETCODE SCIPlpiSolveDual(SCIP_LPI *lpi)
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2765
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:331
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:50
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:98
SCIP_EXPORT void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13081
SCIP_Real * coefs
SCIP_RETCODE SCIPaddConsLocal(SCIP *scip, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip_prob.c:3389
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:120
SCIP_Bool SCIPconsIsMarkedPropagate(SCIP_CONS *cons)
Definition: cons.c:8285
static SCIP_RETCODE addIntervalGradientEstimator(SCIP *scip, SCIP_EXPRINT *exprint, SCIP_CONS *cons, int exprtreeidx, SCIP_Real *x, SCIP_Bool newx, SCIP_Bool overestimate, SCIP_ROWPREP *rowprep, SCIP_Bool *success)
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:1565
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:198
#define CONSHDLR_DESC
static SCIP_DECL_CONSLOCK(consLockNonlinear)
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1109
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14960
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:355
void SCIPprintRowprep(SCIP *scip, SCIP_ROWPREP *rowprep, FILE *file)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:792
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:265
static SCIP_DECL_CONSPRESOL(consPresolNonlinear)
#define SCIPABORT()
Definition: def.h:337
static SCIP_DECL_CONSPARSE(consParseNonlinear)
SCIP_Real SCIPexprGetLinearConstant(SCIP_EXPR *expr)
Definition: expr.c:5803
public methods for global and local (sub)problems
void SCIPmarkRowNotRemovableLocal(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1706
SCIP_EXPRCURV SCIPexprcurvAdd(SCIP_EXPRCURV curv1, SCIP_EXPRCURV curv2)
Definition: expr.c:205
SCIP_Real SCIPadjustedVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real lb)
Definition: scip_var.c:4551
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
SCIP_RETCODE SCIPsetConshdlrEnable(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENABLE((*consenable)))
Definition: scip_cons.c:700
SCIP_VAR ** SCIPgetLinearVarsNonlinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8295
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_Real lhs, SCIP_Real rhs, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *nonlincoefs, SCIP_Bool capturevars)
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15774
SCIP_RETCODE SCIPaddLinearVarNonlinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real coef)
SCIP_RETCODE SCIPincludeConshdlrNonlinear(SCIP *scip)
void SCIPintervalSetRoundingModeDownwards(void)
SCIP_RETCODE SCIPsetNLPInitialGuessSol(SCIP *scip, SCIP_SOL *sol)
Definition: scip_nlp.c:537
#define ABS(x)
Definition: def.h:218
SCIP_EXPORT SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17132
SCIP_SOL * SCIPeventGetSol(SCIP_EVENT *event)
Definition: event.c:1259
int SCIPexprgraphGetNodeDepth(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13014
static SCIP_DECL_CONSCOPY(consCopyNonlinear)
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:608
SCIP_EXPRCURV SCIPexprcurvNegate(SCIP_EXPRCURV curvature)
Definition: expr.c:214
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:8724
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8325
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
type definitions for specific NLP solver interfaces
SCIP_EXPORT int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11436
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:134
void SCIPaddRowprepConstant(SCIP_ROWPREP *rowprep, SCIP_Real constant)
static SCIP_RETCODE replaceViolatedByLinearConstraints(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_Bool *addedcons, SCIP_Bool *reduceddom, SCIP_Bool *infeasible)
static SCIP_DECL_CONSEXITSOL(consExitsolNonlinear)
void SCIPexprgraphEnableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14554
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)