Scippy

SCIP

Solving Constraint Integer Programs

expr.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2017 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file nlpi/expr.c
17  * @brief methods for expressions, expression trees, expression graphs, and related
18  * @author Stefan Vigerske
19  * @author Thorsten Gellermann
20  * @author Ingmar Vierhaus (exprparse)
21  */
22 
23 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24 
25 #include <stdarg.h>
26 #include <string.h>
27 #include <math.h>
28 #include <ctype.h>
29 
30 #include "nlpi/pub_expr.h"
31 #include "nlpi/struct_expr.h"
32 #include "nlpi/exprinterpret.h"
33 
34 #include "scip/intervalarith.h"
35 #include "scip/pub_misc.h"
36 #include "scip/pub_message.h"
37 
38 
39 #define SCIP_EXPRESSION_MAXCHILDEST 16 /**< estimate on maximal number of children */
40 #define DEFAULT_RANDSEED 73 /**< initial random seed */
41 
42 /** sign of a value (-1 or +1)
43  *
44  * 0.0 has sign +1
45  */
46 #define SIGN(x) ((x) >= 0.0 ? 1.0 : -1.0)
47 
48 /** ensures that a block memory array has at least a given size
49  *
50  * if cursize is 0, then *array1 can be NULL
51  */
52 #define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize) \
53  do { \
54  int __newsize; \
55  assert((blkmem) != NULL); \
56  if( *(cursize) >= (minsize) ) \
57  break; \
58  __newsize = calcGrowSize(minsize); \
59  assert(__newsize >= (minsize)); \
60  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
61  *(cursize) = __newsize; \
62  } while( FALSE )
63 
64 #ifdef SCIP_DISABLED_CODE /* this macro is currently not used, which offends lint, so disable it */
65 /** ensures that two block memory arrays have at least a given size
66  *
67  * if cursize is 0, then arrays can be NULL
68  */
69 #define ensureBlockMemoryArraySize2(blkmem, array1, array2, cursize, minsize) \
70  do { \
71  int __newsize; \
72  assert((blkmem) != NULL); \
73  if( *(cursize) >= (minsize) ) \
74  break; \
75  __newsize = calcGrowSize(minsize); \
76  assert(__newsize >= (minsize)); \
77  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
78  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
79  *(cursize) = __newsize; \
80  } while( FALSE )
81 #endif
82 
83 /** ensures that three block memory arrays have at least a given size
84  *
85  * if cursize is 0, then arrays can be NULL
86  */
87 #define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize) \
88  do { \
89  int __newsize; \
90  assert((blkmem) != NULL); \
91  if( *(cursize) >= (minsize) ) \
92  break; \
93  __newsize = calcGrowSize(minsize); \
94  assert(__newsize >= (minsize)); \
95  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
96  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
97  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array3, *(cursize), __newsize) ); \
98  *(cursize) = __newsize; \
99  } while( FALSE )
100 
101 /**@name Miscellaneous private methods */
102 /**@{ */
103 
104 /** calculate memory size for dynamically allocated arrays (copied from scip/set.c) */
105 static
107  int num /**< minimum number of entries to store */
108  )
109 {
110  int size;
111 
112  /* calculate the size with this loop, such that the resulting numbers are always the same (-> block memory) */
113  size = 4;
114  while( size < num )
115  size = (int)(1.2 * size + 4);
116 
117  return size;
118 }
119 
120 /** pointer comparison to use in sorting methods */
121 static
123 {
124  if( elem1 > elem2 )
125  return 1;
126  if( elem1 < elem2 )
127  return -1;
128  return 0;
129 }
130 
131 /** checks if a given new lower bound is tighter (w.r.t. given bound strengthening epsilon) than the old one (copied from scip/set.c) */
132 static
134  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
135  SCIP_Real newlb, /**< new lower bound */
136  SCIP_Real oldlb, /**< old lower bound */
137  SCIP_Real oldub /**< old upper bound */
138  )
139 {
140  SCIP_Real eps;
141 
142  /* nothing can be tighter than an empty interval */
143  if( oldlb > oldub )
144  return FALSE;
145 
146  eps = REALABS(oldlb);
147  eps = MIN(oldub - oldlb, eps);
148  return EPSGT(newlb, oldlb, minstrength * MAX(eps, 1e-3));
149 }
150 
151 /** checks if a given new upper bound is tighter (w.r.t. given bound strengthening epsilon) than the old one (copied from scip/set.c) */
152 static
154  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
155  SCIP_Real newub, /**< new upper bound */
156  SCIP_Real oldlb, /**< old lower bound */
157  SCIP_Real oldub /**< old upper bound */
158  )
159 {
160  SCIP_Real eps;
161 
162  /* nothing can be tighter than an empty interval */
163  if( oldlb > oldub )
164  return FALSE;
165 
166  eps = REALABS(oldub);
167  eps = MIN(oldub - oldlb, eps);
168  return EPSLT(newub, oldub, minstrength * MAX(eps, 1e-3));
169 }
170 
171 /**@} */
172 
173 /**@name Expression curvature methods */
174 /**@{ */
175 
176 /** curvature names as strings */
177 static
178 const char* curvnames[4] =
179  {
180  "unknown",
181  "convex",
182  "concave",
183  "linear"
184  };
185 
186 #undef SCIPexprcurvAdd
187 
188 /** gives curvature for a sum of two functions with given curvature */
190  SCIP_EXPRCURV curv1, /**< curvature of first summand */
191  SCIP_EXPRCURV curv2 /**< curvature of second summand */
192  )
193 {
194  return (SCIP_EXPRCURV) (curv1 & curv2);
195 }
196 
197 /** gives the curvature for the negation of a function with given curvature */
199  SCIP_EXPRCURV curvature /**< curvature of function */
200  )
201 {
202  switch( curvature )
203  {
205  return SCIP_EXPRCURV_CONVEX;
206 
208  return SCIP_EXPRCURV_CONCAVE;
209 
212  /* can return curvature, do this below */
213  break;
214 
215  default:
216  SCIPerrorMessage("unknown curvature status.\n");
217  SCIPABORT();
218  }
219 
220  return curvature;
221 }
222 
223 /** gives curvature for a functions with given curvature multiplied by a constant factor */
225  SCIP_Real factor, /**< constant factor */
226  SCIP_EXPRCURV curvature /**< curvature of other factor */
227  )
228 {
229  if( factor == 0.0 )
230  return SCIP_EXPRCURV_LINEAR;
231  if( factor > 0.0 )
232  return curvature;
233  return SCIPexprcurvNegate(curvature);
234 }
235 
236 /** gives curvature for base^exponent for given bounds and curvature of base-function and constant exponent */
238  SCIP_INTERVAL basebounds, /**< bounds on base function */
239  SCIP_EXPRCURV basecurv, /**< curvature of base function */
240  SCIP_Real exponent /**< exponent */
241  )
242 {
243  SCIP_Bool expisint;
244 
245  assert(basebounds.inf <= basebounds.sup);
246 
247  if( exponent == 0.0 )
248  return SCIP_EXPRCURV_LINEAR;
249 
250  if( exponent == 1.0 )
251  return basecurv;
252 
253  expisint = EPSISINT(exponent, 0.0); /*lint !e835*/
254 
255  /* if exponent is fractional, then power is not defined for a negative base
256  * thus, consider only positive part of basebounds
257  */
258  if( !expisint && basebounds.inf < 0.0 )
259  {
260  basebounds.inf = 0.0;
261  if( basebounds.sup < 0.0 )
262  return SCIP_EXPRCURV_LINEAR;
263  }
264 
265  /* if basebounds contains 0.0, consider negative and positive interval separately, if possible */
266  if( basebounds.inf < 0.0 && basebounds.sup > 0.0 )
267  {
268  SCIP_INTERVAL leftbounds;
269  SCIP_INTERVAL rightbounds;
270 
271  /* something like x^(-2) may look convex on each side of zero, but is not convex on the whole interval due to the singularity at 0.0 */
272  if( exponent < 0.0 )
273  return SCIP_EXPRCURV_UNKNOWN;
274 
275  SCIPintervalSetBounds(&leftbounds, basebounds.inf, 0.0);
276  SCIPintervalSetBounds(&rightbounds, 0.0, basebounds.sup);
277 
278  return (SCIP_EXPRCURV) (SCIPexprcurvPower(leftbounds, basecurv, exponent) & SCIPexprcurvPower(rightbounds, basecurv, exponent));
279  }
280  assert(basebounds.inf >= 0.0 || basebounds.sup <= 0.0);
281 
282  /* (base^exponent)'' = exponent * ( (exponent-1) base^(exponent-2) (base')^2 + base^(exponent-1) base'' )
283  *
284  * if base'' is positive, i.e., base is convex, then
285  * - for base > 0.0 and exponent > 1.0, the second deriv. is positive -> convex
286  * - for base < 0.0 and exponent > 1.0, we can't say (first and second summand opposite signs)
287  * - for base > 0.0 and 0.0 < exponent < 1.0, we can't say (first sommand negative, second summand positive)
288  * - for base > 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
289  * - for base < 0.0 and exponent < 0.0 and even, the second deriv. is positive -> convex
290  * - for base < 0.0 and exponent < 0.0 and odd, the second deriv. is negative -> concave
291  *
292  * if base'' is negative, i.e., base is concave, then
293  * - for base > 0.0 and exponent > 1.0, we can't say (first summand positive, second summand negative)
294  * - for base < 0.0 and exponent > 1.0 and even, the second deriv. is positive -> convex
295  * - for base < 0.0 and exponent > 1.0 and odd, the second deriv. is negative -> concave
296  * - for base > 0.0 and 0.0 < exponent < 1.0, the second deriv. is negative -> concave
297  * - for base > 0.0 and exponent < 0.0, the second deriv. is positive -> convex
298  * - for base < 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
299  *
300  * if base'' is zero, i.e., base is linear, then
301  * (base^exponent)'' = exponent * (exponent-1) base^(exponent-2) (base')^2
302  * - just multiply signs
303  */
304 
305  if( basecurv == SCIP_EXPRCURV_LINEAR )
306  {
307  SCIP_Real sign;
308 
309  /* base^(exponent-2) is negative, if base < 0.0 and exponent is odd */
310  sign = exponent * (exponent - 1.0);
311  assert(basebounds.inf >= 0.0 || expisint);
312  if( basebounds.inf < 0.0 && ((int)exponent)%2 != 0 )
313  sign *= -1.0;
314  assert(sign != 0.0);
315 
316  return sign > 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
317  }
318 
319  if( basecurv == SCIP_EXPRCURV_CONVEX )
320  {
321  if( basebounds.sup <= 0.0 && exponent < 0.0 && expisint )
322  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
323  if( basebounds.inf >= 0.0 && exponent > 1.0 )
324  return SCIP_EXPRCURV_CONVEX ;
325  return SCIP_EXPRCURV_UNKNOWN;
326  }
327 
328  if( basecurv == SCIP_EXPRCURV_CONCAVE )
329  {
330  if( basebounds.sup <= 0.0 && exponent > 1.0 && expisint )
331  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
332  if( basebounds.inf >= 0.0 && exponent < 1.0 )
333  return exponent < 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
334  return SCIP_EXPRCURV_UNKNOWN;
335  }
336 
337  return SCIP_EXPRCURV_UNKNOWN;
338 }
339 
340 /** gives curvature for a monomial with given curvatures and bounds for each factor
341  *
342  * See Maranas and Floudas, Finding All Solutions of Nonlinearly Constrained Systems of Equations, JOGO 7, 1995
343  * for the categorization in the case that all factors are linear.
344  */
346  int nfactors, /**< number of factors in monomial */
347  SCIP_Real* exponents, /**< exponents in monomial, or NULL if all 1.0 */
348  int* factoridxs, /**< indices of factors (but not exponents), or NULL if identity mapping */
349  SCIP_EXPRCURV* factorcurv, /**< curvature of each factor */
350  SCIP_INTERVAL* factorbounds /**< bounds of each factor */
351  )
352 {
353  SCIP_Real mult;
354  SCIP_Real e;
355  SCIP_EXPRCURV curv;
356  SCIP_EXPRCURV fcurv;
357  int nnegative;
358  int npositive;
359  SCIP_Real sum;
360  SCIP_Bool expcurvpos;
361  SCIP_Bool expcurvneg;
362  int j;
363  int f;
364 
365  assert(nfactors >= 0);
366  assert(factorcurv != NULL || nfactors == 0);
367  assert(factorbounds != NULL || nfactors == 0);
368 
369  if( nfactors == 0 )
370  return SCIP_EXPRCURV_LINEAR;
371 
372  if( nfactors == 1 )
373  {
374  f = factoridxs != NULL ? factoridxs[0] : 0;
375  e = exponents != NULL ? exponents[0] : 1.0;
376  /* SCIPdebugMessage("monomial [%g,%g]^%g is %s\n",
377  factorbounds[f].inf, factorbounds[f].sup, e,
378  SCIPexprcurvGetName(SCIPexprcurvPower(factorbounds[f], factorcurv[f], e))); */
379  return SCIPexprcurvPower(factorbounds[f], factorcurv[f], e); /*lint !e613*/
380  }
381 
382  mult = 1.0;
383 
384  nnegative = 0; /* number of negative exponents */
385  npositive = 0; /* number of positive exponents */
386  sum = 0.0; /* sum of exponents */
387  expcurvpos = TRUE; /* whether exp_j * f_j''(x) >= 0 for all factors (assuming f_j >= 0) */
388  expcurvneg = TRUE; /* whether exp_j * f_j''(x) <= 0 for all factors (assuming f_j >= 0) */
389 
390  for( j = 0; j < nfactors; ++j )
391  {
392  f = factoridxs != NULL ? factoridxs[j] : j;
393  if( factorcurv[f] == SCIP_EXPRCURV_UNKNOWN ) /*lint !e613*/
394  return SCIP_EXPRCURV_UNKNOWN;
395  if( factorbounds[f].inf < 0.0 && factorbounds[f].sup > 0.0 ) /*lint !e613*/
396  return SCIP_EXPRCURV_UNKNOWN;
397 
398  e = exponents != NULL ? exponents[j] : 1.0;
399  if( e < 0.0 )
400  ++nnegative;
401  else
402  ++npositive;
403  sum += e;
404 
405  if( factorbounds[f].inf < 0.0 ) /*lint !e613*/
406  {
407  /* if argument is negative, then exponent should be integer */
408  assert(EPSISINT(e, 0.0)); /*lint !e835*/
409 
410  /* flip j'th argument: (f_j)^(exp_j) = (-1)^(exp_j) (-f_j)^(exp_j) */
411 
412  /* -f_j has negated curvature of f_j */
413  fcurv = SCIPexprcurvNegate(factorcurv[f]); /*lint !e613*/
414 
415  /* negate monomial, if exponent is odd, i.e., (-1)^(exp_j) = -1 */
416  if( (int)e % 2 != 0 )
417  mult *= -1.0;
418  }
419  else
420  {
421  fcurv = factorcurv[f]; /*lint !e613*/
422  }
423 
424  /* check if exp_j * fcurv is convex (>= 0) and/or concave */
425  fcurv = SCIPexprcurvMultiply(e, fcurv);
426  if( !(fcurv & SCIP_EXPRCURV_CONVEX) )
427  expcurvpos = FALSE;
428  if( !(fcurv & SCIP_EXPRCURV_CONCAVE) )
429  expcurvneg = FALSE;
430  }
431 
432  /* if all factors are linear, then a product f_j^exp_j with f_j >= 0 is convex if
433  * - all exponents are negative, or
434  * - 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
435  * further, the product is concave if
436  * - all exponents are positive and the sum of exponents is <= 1.0
437  *
438  * if factors are nonlinear, then we require additionally, that for convexity
439  * - each factor is convex if exp_j >= 0, or concave if exp_j <= 0, i.e., exp_j*f_j'' >= 0
440  * and for concavity, we require that
441  * - all factors are concave, i.e., exp_j*f_j'' <= 0
442  */
443 
444  if( nnegative == nfactors && expcurvpos )
445  curv = SCIP_EXPRCURV_CONVEX;
446  else if( nnegative == nfactors-1 && EPSGE(sum, 1.0, 1e-9) && expcurvpos )
447  curv = SCIP_EXPRCURV_CONVEX;
448  else if( npositive == nfactors && EPSLE(sum, 1.0, 1e-9) && expcurvneg )
449  curv = SCIP_EXPRCURV_CONCAVE;
450  else
451  curv = SCIP_EXPRCURV_UNKNOWN;
452  curv = SCIPexprcurvMultiply(mult, curv);
453 
454  return curv;
455 }
456 
457 /** gives name as string for a curvature */
459  SCIP_EXPRCURV curv /**< curvature */
460  )
461 {
462  assert(curv <= SCIP_EXPRCURV_LINEAR); /*lint !e685*/
463 
464  return curvnames[curv];
465 }
466 
467 /**@} */
468 
469 /**@name Quadratic expression data private methods */
470 /**@{ */
471 
472 /** creates SCIP_EXPRDATA_QUADRATIC data structure from given quadratic elements */
473 static
475  BMS_BLKMEM* blkmem, /**< block memory data structure */
476  SCIP_EXPRDATA_QUADRATIC** quadraticdata, /**< buffer to store pointer to quadratic data */
477  SCIP_Real constant, /**< constant */
478  int nchildren, /**< number of children */
479  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
480  int nquadelems, /**< number of quadratic elements */
481  SCIP_QUADELEM* quadelems /**< quadratic elements */
482  )
483 {
484  assert(blkmem != NULL);
485  assert(quadraticdata != NULL);
486  assert(quadelems != NULL || nquadelems == 0);
487  assert(nchildren >= 0);
488 
489  SCIP_ALLOC( BMSallocBlockMemory(blkmem, quadraticdata) );
490 
491  (*quadraticdata)->constant = constant;
492  (*quadraticdata)->lincoefs = NULL;
493  (*quadraticdata)->nquadelems = nquadelems;
494  (*quadraticdata)->quadelems = NULL;
495  (*quadraticdata)->sorted = (nquadelems <= 1);
496 
497  if( lincoefs != NULL )
498  {
499  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->lincoefs, lincoefs, nchildren) );
500  }
501 
502  if( nquadelems > 0 )
503  {
504  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->quadelems, quadelems, nquadelems) );
505  }
506 
507  return SCIP_OKAY;
508 }
509 
510 /** sorts quadratic elements in a SCIP_EXPRDATA_QUADRATIC data structure */
511 static
513  SCIP_EXPRDATA_QUADRATIC* quadraticdata /**< quadratic data */
514  )
515 {
516  assert(quadraticdata != NULL);
517 
518  if( quadraticdata->sorted )
519  {
520 #ifndef NDEBUG
521  int i;
522  for( i = 1; i < quadraticdata->nquadelems; ++i )
523  {
524  assert(quadraticdata->quadelems[i].idx1 <= quadraticdata->quadelems[i].idx2);
525  assert(quadraticdata->quadelems[i-1].idx1 <= quadraticdata->quadelems[i].idx1);
526  assert(quadraticdata->quadelems[i-1].idx1 < quadraticdata->quadelems[i].idx1 ||
527  quadraticdata->quadelems[i-1].idx2 <= quadraticdata->quadelems[i].idx2);
528  }
529 #endif
530  return;
531  }
532 
533  if( quadraticdata->nquadelems > 0 )
534  SCIPquadelemSort(quadraticdata->quadelems, quadraticdata->nquadelems);
535 
536  quadraticdata->sorted = TRUE;
537 }
538 
539 /**@} */
540 
541 /**@name Polynomial expression data private methods */
542 /**@{ */
543 
544 /** compares two monomials
545  *
546  * gives 0 if monomials are equal */
547 static
548 SCIP_DECL_SORTPTRCOMP(monomialdataCompare)
549 {
550  SCIP_EXPRDATA_MONOMIAL* monomial1;
551  SCIP_EXPRDATA_MONOMIAL* monomial2;
552 
553  int i;
554 
555  assert(elem1 != NULL);
556  assert(elem2 != NULL);
557 
558  monomial1 = (SCIP_EXPRDATA_MONOMIAL*)elem1;
559  monomial2 = (SCIP_EXPRDATA_MONOMIAL*)elem2;
560 
561  /* make sure, both monomials are equal */
562  SCIPexprSortMonomialFactors(monomial1);
563  SCIPexprSortMonomialFactors(monomial2);
564 
565  /* for the first factor where both monomials differ,
566  * we return either the difference in the child indices, if children are different
567  * or the sign of the difference in the exponents
568  */
569  for( i = 0; i < monomial1->nfactors && i < monomial2->nfactors; ++i )
570  {
571  if( monomial1->childidxs[i] != monomial2->childidxs[i] )
572  return monomial1->childidxs[i] - monomial2->childidxs[i];
573  if( monomial1->exponents[i] > monomial2->exponents[i] )
574  return 1;
575  else if( monomial1->exponents[i] < monomial2->exponents[i] )
576  return -1;
577  }
578 
579  /* if the factors of one monomial are a proper subset of the factors of the other monomial,
580  * we return the difference in the number of monomials
581  */
582  return monomial1->nfactors - monomial2->nfactors;
583 }
584 
585 /** ensures that the factors arrays of a monomial have at least a given size */
586 static
588  BMS_BLKMEM* blkmem, /**< block memory data structure */
589  SCIP_EXPRDATA_MONOMIAL* monomialdata, /**< monomial data */
590  int minsize /**< minimal size of factors arrays */
591  )
592 {
593  assert(blkmem != NULL);
594  assert(monomialdata != NULL);
595 
596  if( minsize > monomialdata->factorssize )
597  {
598  int newsize;
599 
600  newsize = calcGrowSize(minsize);
601  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->childidxs, monomialdata->factorssize, newsize) );
602  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->exponents, monomialdata->factorssize, newsize) );
603  monomialdata->factorssize = newsize;
604  }
605  assert(minsize <= monomialdata->factorssize);
606 
607  return SCIP_OKAY;
608 }
609 
610 /** creates SCIP_EXPRDATA_POLYNOMIAL data structure from given monomials */
611 static
613  BMS_BLKMEM* blkmem, /**< block memory data structure */
614  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
615  int nmonomials, /**< number of monomials */
616  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
617  SCIP_Real constant, /**< constant part */
618  SCIP_Bool copymonomials /**< whether to copy monomials, or copy only given pointers, in which case polynomialdata assumes ownership of monomial structure */
619  )
620 {
621  assert(blkmem != NULL);
622  assert(polynomialdata != NULL);
623  assert(monomials != NULL || nmonomials == 0);
624 
625  SCIP_ALLOC( BMSallocBlockMemory(blkmem, polynomialdata) );
626 
627  (*polynomialdata)->constant = constant;
628  (*polynomialdata)->nmonomials = nmonomials;
629  (*polynomialdata)->monomialssize = nmonomials;
630  (*polynomialdata)->monomials = NULL;
631  (*polynomialdata)->sorted = (nmonomials <= 1);
632 
633  if( nmonomials > 0 )
634  {
635  int i;
636 
637  if( copymonomials )
638  {
639  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, nmonomials) );
640 
641  for( i = 0; i < nmonomials; ++i )
642  {
643  assert(monomials[i] != NULL); /*lint !e613*/
644  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i],
645  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
646  }
647  }
648  else
649  {
650  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, monomials, nmonomials) );
651  }
652  }
653 
654  return SCIP_OKAY;
655 }
656 
657 /** creates a copy of a SCIP_EXPRDATA_POLYNOMIAL data structure */
658 static
660  BMS_BLKMEM* blkmem, /**< block memory data structure */
661  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
662  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata /**< polynomial data to copy */
663  )
664 {
665  assert(blkmem != NULL);
666  assert(polynomialdata != NULL);
667  assert(sourcepolynomialdata != NULL);
668 
669  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, polynomialdata, sourcepolynomialdata) );
670 
671  (*polynomialdata)->monomialssize = sourcepolynomialdata->nmonomials;
672  if( sourcepolynomialdata->nmonomials > 0 )
673  {
674  int i;
675 
676  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize) );
677 
678  for( i = 0; i < sourcepolynomialdata->nmonomials; ++i )
679  {
680  assert(sourcepolynomialdata->monomials[i] != NULL); /*lint !e613*/
681  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i], sourcepolynomialdata->monomials[i]->coef,
682  sourcepolynomialdata->monomials[i]->nfactors, sourcepolynomialdata->monomials[i]->childidxs, sourcepolynomialdata->monomials[i]->exponents) );
683  (*polynomialdata)->monomials[i]->sorted = sourcepolynomialdata->monomials[i]->sorted;
684  }
685  }
686  else
687  {
688  (*polynomialdata)->monomials = NULL;
689  }
690 
691  return SCIP_OKAY;
692 }
693 
694 /** frees a SCIP_EXPRDATA_POLYNOMIAL data structure */
695 static
697  BMS_BLKMEM* blkmem, /**< block memory data structure */
698  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata /**< pointer to polynomial data to free */
699  )
700 {
701  assert(blkmem != NULL);
702  assert(polynomialdata != NULL);
703  assert(*polynomialdata != NULL);
704 
705  if( (*polynomialdata)->monomialssize > 0 )
706  {
707  int i;
708 
709  for( i = 0; i < (*polynomialdata)->nmonomials; ++i )
710  {
711  assert((*polynomialdata)->monomials[i] != NULL);
712  SCIPexprFreeMonomial(blkmem, &(*polynomialdata)->monomials[i]);
713  assert((*polynomialdata)->monomials[i] == NULL);
714  }
715 
716  BMSfreeBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize);
717  }
718  assert((*polynomialdata)->monomials == NULL);
719 
720  BMSfreeBlockMemory(blkmem, polynomialdata);
721 }
722 
723 /** ensures that the monomials array of a polynomial has at least a given size */
724 static
726  BMS_BLKMEM* blkmem, /**< block memory data structure */
727  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
728  int minsize /**< minimal size of monomials array */
729  )
730 {
731  assert(blkmem != NULL);
732  assert(polynomialdata != NULL);
733 
734  ensureBlockMemoryArraySize(blkmem, &polynomialdata->monomials, &polynomialdata->monomialssize, minsize);
735  assert(minsize <= polynomialdata->monomialssize);
736 
737  return SCIP_OKAY;
738 }
739 
740 /** adds an array of monomials to a polynomial */
741 static
743  BMS_BLKMEM* blkmem, /**< block memory of expression */
744  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
745  int nmonomials, /**< number of monomials to add */
746  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
747  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
748  )
749 {
750  int i;
751 
752  assert(blkmem != NULL);
753  assert(polynomialdata != NULL);
754  assert(monomials != NULL || nmonomials == 0);
755 
756  if( nmonomials == 0 )
757  return SCIP_OKAY;
758 
759  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials + nmonomials) );
760  assert(polynomialdata->monomialssize >= polynomialdata->nmonomials + nmonomials);
761 
762  if( copymonomials )
763  {
764  for( i = 0; i < nmonomials; ++i )
765  {
766  assert(monomials[i] != NULL); /*lint !e613*/
767  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials + i],
768  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
769  }
770  }
771  else
772  {
773  BMScopyMemoryArray(&polynomialdata->monomials[polynomialdata->nmonomials], monomials, nmonomials); /*lint !e866*/
774  }
775  polynomialdata->nmonomials += nmonomials;
776 
777  polynomialdata->sorted = (polynomialdata->nmonomials <= 1);
778 
779  return SCIP_OKAY;
780 }
781 
782 /** ensures that monomials of a polynomial are sorted */
783 static
785  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata /**< polynomial expression */
786  )
787 {
788  assert(polynomialdata != NULL);
789 
790  if( polynomialdata->sorted )
791  {
792 #ifndef NDEBUG
793  int i;
794 
795  /* a polynom with more than one monoms can only be sorted if its monoms are sorted */
796  for( i = 1; i < polynomialdata->nmonomials; ++i )
797  {
798  assert(polynomialdata->monomials[i-1]->sorted);
799  assert(polynomialdata->monomials[i]->sorted);
800  assert(monomialdataCompare(polynomialdata->monomials[i-1], polynomialdata->monomials[i]) <= 0);
801  }
802 #endif
803  return;
804  }
805 
806  if( polynomialdata->nmonomials > 0 )
807  SCIPsortPtr((void**)polynomialdata->monomials, monomialdataCompare, polynomialdata->nmonomials);
808 
809  polynomialdata->sorted = TRUE;
810 }
811 
812 /** merges monomials that differ only in coefficient into a single monomial
813  *
814  * Eliminates monomials with coefficient between -eps and eps.
815  */
816 static
818  BMS_BLKMEM* blkmem, /**< block memory */
819  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
820  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
821  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
822  )
823 {
824  int i;
825  int offset;
826  int oldnfactors;
827 
828  assert(polynomialdata != NULL);
829  assert(eps >= 0.0);
830 
831  polynomialdataSortMonomials(polynomialdata);
832 
833  /* merge monomials by adding their coefficients, eliminate monomials with no factors or zero coefficient*/
834  offset = 0;
835  i = 0;
836  while( i + offset < polynomialdata->nmonomials )
837  {
838  if( offset > 0 )
839  {
840  assert(polynomialdata->monomials[i] == NULL);
841  assert(polynomialdata->monomials[i+offset] != NULL);
842  polynomialdata->monomials[i] = polynomialdata->monomials[i+offset];
843 #ifndef NDEBUG
844  polynomialdata->monomials[i+offset] = NULL;
845 #endif
846  }
847 
848  if( mergefactors )
849  {
850  oldnfactors = polynomialdata->monomials[i]->nfactors;
851  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i], eps);
852 
853  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
854  if( oldnfactors != polynomialdata->monomials[i]->nfactors )
855  polynomialdata->sorted = FALSE;
856  }
857 
858  while( i+offset+1 < polynomialdata->nmonomials )
859  {
860  assert(polynomialdata->monomials[i+offset+1] != NULL);
861  if( mergefactors )
862  {
863  oldnfactors = polynomialdata->monomials[i+offset+1]->nfactors;
864  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i+offset+1], eps);
865 
866  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
867  if( oldnfactors != polynomialdata->monomials[i+offset+1]->nfactors )
868  polynomialdata->sorted = FALSE;
869  }
870  if( monomialdataCompare((void*)polynomialdata->monomials[i], (void*)polynomialdata->monomials[i+offset+1]) != 0 )
871  break;
872  polynomialdata->monomials[i]->coef += polynomialdata->monomials[i+offset+1]->coef;
873  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i+offset+1]);
874  ++offset;
875  }
876 
877  if( polynomialdata->monomials[i]->nfactors == 0 )
878  {
879  /* constant monomial */
880  polynomialdata->constant += polynomialdata->monomials[i]->coef;
881  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
882  ++offset;
883  continue;
884  }
885 
886  if( EPSZ(polynomialdata->monomials[i]->coef, eps) )
887  {
888  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
889  ++offset;
890  continue;
891  }
892 
893  ++i;
894  }
895 
896 #ifndef NDEBUG
897  for( ; i < polynomialdata->nmonomials; ++i )
898  assert(polynomialdata->monomials[i] == NULL);
899 #endif
900 
901  polynomialdata->nmonomials -= offset;
902 
903  if( EPSZ(polynomialdata->constant, eps) )
904  polynomialdata->constant = 0.0;
905 }
906 
907 /** multiplies each summand of a polynomial by a given constant */
908 static
910  BMS_BLKMEM* blkmem, /**< block memory */
911  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
912  SCIP_Real factor /**< constant factor */
913  )
914 {
915  int i;
916 
917  assert(polynomialdata != NULL);
918 
919  if( factor == 1.0 )
920  return;
921 
922  if( factor == 0.0 )
923  {
924  for( i = 0; i < polynomialdata->nmonomials; ++i )
925  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
926  polynomialdata->nmonomials = 0;
927  }
928  else
929  {
930  for( i = 0; i < polynomialdata->nmonomials; ++i )
931  SCIPexprChgMonomialCoef(polynomialdata->monomials[i], polynomialdata->monomials[i]->coef * factor);
932  }
933 
934  polynomialdata->constant *= factor;
935 }
936 
937 /** multiplies each summand of a polynomial by a given monomial */
938 static
940  BMS_BLKMEM* blkmem, /**< block memory */
941  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
942  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
943  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
944  )
945 {
946  int i;
947 
948  assert(blkmem != NULL);
949  assert(factor != NULL);
950  assert(polynomialdata != NULL);
951 
952  if( factor->nfactors == 0 )
953  {
954  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factor->coef);
955  return SCIP_OKAY;
956  }
957 
958  /* multiply each monomial by factor */
959  for( i = 0; i < polynomialdata->nmonomials; ++i )
960  {
961  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i], factor, childmap) );
962  }
963 
964  /* add new monomial for constant multiplied by factor */
965  if( polynomialdata->constant != 0.0 )
966  {
967  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
968  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
969  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[polynomialdata->nmonomials], factor, childmap) );
970  ++polynomialdata->nmonomials;
971  polynomialdata->sorted = FALSE;
972  polynomialdata->constant = 0.0;
973  }
974 
975  return SCIP_OKAY;
976 }
977 
978 /** multiplies a polynomial by a polynomial
979  *
980  * Factors need to be different.
981  */
982 static
984  BMS_BLKMEM* blkmem, /**< block memory */
985  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
986  SCIP_EXPRDATA_POLYNOMIAL* factordata, /**< polynomial factor data */
987  int* childmap /**< map children in factor to children in polynomialdata, or NULL for 1:1 */
988  )
989 {
990  int i1;
991  int i2;
992  int orignmonomials;
993 
994  assert(blkmem != NULL);
995  assert(polynomialdata != NULL);
996  assert(factordata != NULL);
997  assert(polynomialdata != factordata);
998 
999  if( factordata->nmonomials == 0 )
1000  {
1001  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factordata->constant);
1002  return SCIP_OKAY;
1003  }
1004 
1005  if( factordata->nmonomials == 1 && factordata->constant == 0.0 )
1006  {
1007  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, polynomialdata, factordata->monomials[0], childmap) );
1008  return SCIP_OKAY;
1009  }
1010 
1011  /* turn constant into a monomial, so we can assume below that constant is 0.0 */
1012  if( polynomialdata->constant != 0.0 )
1013  {
1014  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
1015  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
1016  ++polynomialdata->nmonomials;
1017  polynomialdata->sorted = FALSE;
1018  polynomialdata->constant = 0.0;
1019  }
1020 
1021  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials * (factordata->nmonomials + (factordata->constant == 0.0 ? 0 : 1))) );
1022 
1023  /* for each monomial in factordata (except the last, if factordata->constant is 0),
1024  * duplicate monomials from polynomialdata and multiply them by the monomial for factordata */
1025  orignmonomials = polynomialdata->nmonomials;
1026  for( i2 = 0; i2 < factordata->nmonomials; ++i2 )
1027  {
1028  /* add a copy of original monomials to end of polynomialdata's monomials array */
1029  assert(polynomialdata->nmonomials + orignmonomials <= polynomialdata->monomialssize); /* reallocating in polynomialdataAddMonomials would make the polynomialdata->monomials invalid, so assert that above the monomials array was made large enough */
1030  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, orignmonomials, polynomialdata->monomials, TRUE) );
1031  assert(polynomialdata->nmonomials == (i2+2) * orignmonomials);
1032 
1033  /* multiply each copied monomial by current monomial from factordata */
1034  for( i1 = (i2+1) * orignmonomials; i1 < (i2+2) * orignmonomials; ++i1 )
1035  {
1036  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1037  }
1038 
1039  if( factordata->constant == 0.0 && i2 == factordata->nmonomials - 2 )
1040  {
1041  ++i2;
1042  break;
1043  }
1044  }
1045 
1046  if( factordata->constant != 0.0 )
1047  {
1048  assert(i2 == factordata->nmonomials);
1049  /* multiply original monomials in polynomialdata by constant in factordata */
1050  for( i1 = 0; i1 < orignmonomials; ++i1 )
1051  SCIPexprChgMonomialCoef(polynomialdata->monomials[i1], polynomialdata->monomials[i1]->coef * factordata->constant);
1052  }
1053  else
1054  {
1055  assert(i2 == factordata->nmonomials - 1);
1056  /* multiply original monomials in polynomialdata by last monomial in factordata */
1057  for( i1 = 0; i1 < orignmonomials; ++i1 )
1058  {
1059  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1060  }
1061  }
1062 
1063  return SCIP_OKAY;
1064 }
1065 
1066 /** takes a power of a polynomial
1067  *
1068  * Exponent needs to be an integer,
1069  * polynomial needs to be a monomial, if exponent is negative.
1070  */
1071 static
1073  BMS_BLKMEM* blkmem, /**< block memory */
1074  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1075  int exponent /**< exponent of power operation */
1076  )
1077 {
1078  SCIP_EXPRDATA_POLYNOMIAL* factor;
1079  int i;
1080 
1081  assert(blkmem != NULL);
1082  assert(polynomialdata != NULL);
1083 
1084  if( exponent == 0 )
1085  {
1086  /* x^0 = 1, except if x = 0 */
1087  if( polynomialdata->nmonomials == 0 && polynomialdata->constant == 0.0 )
1088  {
1089  polynomialdata->constant = 0.0;
1090  }
1091  else
1092  {
1093  polynomialdata->constant = 1.0;
1094 
1095  for( i = 0; i < polynomialdata->nmonomials; ++i )
1096  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
1097  polynomialdata->nmonomials = 0;
1098  }
1099 
1100  return SCIP_OKAY;
1101  }
1102 
1103  if( exponent == 1 )
1104  return SCIP_OKAY;
1105 
1106  if( polynomialdata->nmonomials == 1 && polynomialdata->constant == 0.0 )
1107  {
1108  /* polynomial is a single monomial */
1109  SCIPexprMonomialPower(polynomialdata->monomials[0], exponent);
1110  return SCIP_OKAY;
1111  }
1112 
1113  if( polynomialdata->nmonomials == 0 )
1114  {
1115  /* polynomial is a constant */
1116  polynomialdata->constant = pow(polynomialdata->constant, (SCIP_Real)exponent);
1117  return SCIP_OKAY;
1118  }
1119 
1120  assert(exponent >= 2); /* negative exponents not allowed if more than one monom */
1121 
1122  /* todo improve, look how SCIPintervalPowerScalar in intervalarith.c does it */
1123 
1124  /* get copy of our polynomial */
1125  SCIP_CALL( polynomialdataCopy(blkmem, &factor, polynomialdata) );
1126 
1127  /* do repeated multiplication */
1128  for( i = 2; i <= exponent; ++i )
1129  {
1130  SCIP_CALL( polynomialdataMultiplyByPolynomial(blkmem, polynomialdata, factor, NULL) );
1131  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
1132  }
1133 
1134  /* free copy again */
1135  polynomialdataFree(blkmem, &factor);
1136 
1137  return SCIP_OKAY;
1138 }
1139 
1140 /** applies a mapping of child indices to the indices used in polynomial monomials */
1141 static
1143  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1144  int* childmap /**< mapping of child indices */
1145  )
1146 {
1147  SCIP_EXPRDATA_MONOMIAL* monomial;
1148  int i;
1149  int j;
1150 
1151  assert(polynomialdata != NULL);
1152 
1153  for( i = 0; i < polynomialdata->nmonomials; ++i )
1154  {
1155  monomial = polynomialdata->monomials[i];
1156  assert(monomial != NULL);
1157 
1158  for( j = 0; j < monomial->nfactors; ++j )
1159  {
1160  monomial->childidxs[j] = childmap[monomial->childidxs[j]];
1161  assert(monomial->childidxs[j] >= 0);
1162  }
1163  monomial->sorted = FALSE;
1164  }
1165 
1166  polynomialdata->sorted = FALSE;
1167 }
1168 
1169 /** replaces a factor in a monomial by a polynomial and expands the result */
1170 static
1172  BMS_BLKMEM* blkmem, /**< block memory data structure */
1173  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1174  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data where to expand a monomial */
1175  int monomialpos, /**< position of monomial which factor to expand */
1176  int factorpos, /**< position of factor in monomial to expand */
1177  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomial,/**< polynomial that should replace factor */
1178  int* childmap, /**< map of child indices in factorpolynomial to children of polynomial */
1179  int maxexpansionexponent,/**< maximal exponent for which polynomials (with > 1 summands) are expanded */
1180  SCIP_Bool* success /**< buffer to store whether expansion has been done */
1181  )
1182 {
1183  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomialcopy;
1184  SCIP_EXPRDATA_MONOMIAL* monomial;
1185  int i;
1186 
1187  assert(blkmem != NULL);
1188  assert(polynomialdata != NULL);
1189  assert(factorpolynomial != NULL);
1190  assert(childmap != NULL || factorpolynomial->nmonomials == 0);
1191  assert(success != NULL);
1192  assert(monomialpos >= 0);
1193  assert(monomialpos < polynomialdata->nmonomials);
1194  assert(factorpos >= 0);
1195 
1196  monomial = polynomialdata->monomials[monomialpos];
1197  assert(monomial != NULL);
1198  assert(factorpos < monomial->nfactors);
1199 
1200  *success = TRUE;
1201 
1202  if( factorpolynomial->nmonomials == 0 )
1203  {
1204  /* factorpolynomial is a constant */
1205 
1206  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && factorpolynomial->constant < 0.0 ) /*lint !e835*/
1207  {
1208  /* if polynomial is a negative constant and our exponent is not integer, then cannot do expansion */
1209  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", factorpolynomial->constant, monomial->exponents[factorpos]);
1210  *success = FALSE;
1211  return SCIP_OKAY;
1212  }
1213  monomial->coef *= pow(factorpolynomial->constant, monomial->exponents[factorpos]);
1214 
1215  /* move last factor to position factorpos */
1216  if( factorpos < monomial->nfactors-1 )
1217  {
1218  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1219  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1220  }
1221  --monomial->nfactors;
1222  monomial->sorted = FALSE;
1223  polynomialdata->sorted = FALSE;
1224 
1225  return SCIP_OKAY;
1226  }
1227 
1228  if( factorpolynomial->constant == 0.0 && factorpolynomial->nmonomials == 1 )
1229  {
1230  /* factorpolynomial is a single monomial */
1231  SCIP_EXPRDATA_MONOMIAL* factormonomial;
1232  int childidx;
1233  SCIP_Real exponent;
1234 
1235  factormonomial = factorpolynomial->monomials[0];
1236  assert(factormonomial != NULL);
1237 
1238  if( !EPSISINT(monomial->exponents[factorpos], 0.0) ) /*lint !e835*/
1239  {
1240  if( factormonomial->coef < 0.0 )
1241  {
1242  /* if coefficient of monomial is negative and our exponent is not integer, then do not do expansion
1243  * @todo the only case where this could make sense is if the factors can be negative, i.e., when we have negative arguments with an odd exponent: (-x^a)^b = (-x)^(ab) for a odd
1244  */
1245  *success = FALSE;
1246  return SCIP_OKAY;
1247  }
1248  if( factormonomial->nfactors > 1 )
1249  {
1250  /* @todo if there is an even number of factors in factormonomial that are negative, then they always multiply to something positive
1251  * however, we cannot expand them as below, since we cannot compute the single powers
1252  * since we do not have the bounds on the factors here, we skip expansion in this case
1253  * MINLPLib instances tls2,4,6 are examples where we are loosing here (do not recognize convexity)
1254  */
1255  *success = FALSE;
1256  return SCIP_OKAY;
1257  }
1258  }
1259 
1260  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + factormonomial->nfactors) );
1261 
1262  for( i = 0; i < factormonomial->nfactors; ++i )
1263  {
1264  childidx = childmap[factormonomial->childidxs[i]]; /*lint !e613*/
1265  /* can do this because monomial->exponents[factorpos] is assumed to be integer or factormonomial has positive coefficient and only one factor
1266  * thus, if factormonomial->exponents[i] is fractional, then we can assume that it's argument is positive
1267  */
1268  exponent = factormonomial->exponents[i] * monomial->exponents[factorpos];
1269  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
1270  }
1271 
1272  monomial->coef *= pow(factormonomial->coef, monomial->exponents[factorpos]);
1273 
1274  /* move last factor to position factorpos */
1275  if( factorpos < monomial->nfactors-1 )
1276  {
1277  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1278  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1279  }
1280  --monomial->nfactors;
1281  monomial->sorted = FALSE;
1282  polynomialdata->sorted = FALSE;
1283 
1284  return SCIP_OKAY;
1285  }
1286 
1287  /* if exponent is negative or fractional and the polynomial is not just a monomial, then we cannot do expansion */
1288  if( !EPSISINT(monomial->exponents[factorpos], 0.0) || monomial->exponents[factorpos] < 0.0 ) /*lint !e835*/
1289  {
1290  *success = FALSE;
1291  return SCIP_OKAY;
1292  }
1293 
1294  /* if exponent is too large, skip expansion */
1295  if( monomial->exponents[factorpos] > maxexpansionexponent )
1296  {
1297  *success = FALSE;
1298  return SCIP_OKAY;
1299  }
1300 
1301  /* check whether maximal degree of expansion would exceed maxexpansionexponent
1302  * that is, assume monomial is f1^a1 f2^a2 ... and we want to expand f1 = (g11^beta11 g12^beta12... + g21^beta21 g22^beta22 ... + ...)
1303  * then we do this only if all ai and all beta are > 0.0 and a1 max(beta11+beta12+..., beta21+beta22+..., ...) + a2 + ... < maxexpansionexponent
1304  * exception (there need to be one) is if monomial is just f1
1305  */
1306  if( maxexpansionexponent < INT_MAX && (monomial->nfactors > 1 || monomial->exponents[factorpos] != 1.0) )
1307  {
1308  SCIP_Real restdegree;
1309  SCIP_Real degree;
1310  int j;
1311 
1312  restdegree = -monomial->exponents[factorpos];
1313  for( i = 0; i < monomial->nfactors; ++i )
1314  {
1315  if( monomial->exponents[i] < 0.0 )
1316  {
1317  /* ai < 0.0 */
1318  SCIPdebugMessage("skip expansion because factor %d in monomial has negative exponent\n", i);
1319  *success = FALSE;
1320  return SCIP_OKAY;
1321  }
1322  restdegree += monomial->exponents[i];
1323  }
1324 
1325  for( i = 0; i < factorpolynomial->nmonomials; ++i )
1326  {
1327  degree = 0.0;
1328  for( j = 0; j < factorpolynomial->monomials[i]->nfactors; ++j )
1329  {
1330  if( factorpolynomial->monomials[i]->exponents[j] < 0.0 )
1331  {
1332  /* beta_ij < 0.0 */
1333  SCIPdebugMessage("skip expansion because %d'th factor in %d'th monomial of factorpolynomial is negative\n", i, j);
1334  *success = FALSE;
1335  return SCIP_OKAY;
1336  }
1337  degree += factorpolynomial->monomials[i]->exponents[j];
1338  }
1339  if( degree * monomial->exponents[factorpos] + restdegree > maxexpansionexponent )
1340  {
1341  /* (beta_i1+beta_i2+...)*monomial->exponents[factorpos] + rest > maxexpansion */
1342  SCIPdebugMessage("skip expansion because degree of %d'th monomial would yield degree %g > max = %d in expansion\n",
1343  i, degree * monomial->exponents[factorpos] + restdegree, maxexpansionexponent);
1344  *success = FALSE;
1345  return SCIP_OKAY;
1346  }
1347  }
1348  }
1349 
1350  /* create a copy of factor */
1351  SCIP_CALL( polynomialdataCopy(blkmem, &factorpolynomialcopy, factorpolynomial) );
1352  /* apply childmap to copy */
1353  polynomialdataApplyChildmap(factorpolynomialcopy, childmap);
1354  /* create power of factor */
1355  SCIP_CALL( polynomialdataPower(blkmem, factorpolynomialcopy, (int)EPSFLOOR(monomial->exponents[factorpos], 0.0)) ); /*lint !e835*/
1356 
1357  /* remove factor from monomial by moving last factor to position factorpos */
1358  if( factorpos < monomial->nfactors-1 )
1359  {
1360  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1361  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1362  }
1363  --monomial->nfactors;
1364  monomial->sorted = FALSE;
1365 
1366  /* multiply factor with this reduced monomial */
1367  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, factorpolynomialcopy, monomial, NULL) );
1368 
1369  /* remove monomial from polynomial and move last monomial to monomialpos */
1370  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[monomialpos]);
1371  if( monomialpos < polynomialdata->nmonomials-1 )
1372  polynomialdata->monomials[monomialpos] = polynomialdata->monomials[polynomialdata->nmonomials-1];
1373  --polynomialdata->nmonomials;
1374  polynomialdata->sorted = FALSE;
1375 
1376  /* add factorpolynomialcopy to polynomial */
1377  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, factorpolynomialcopy->nmonomials, factorpolynomialcopy->monomials, FALSE) );
1378  polynomialdata->constant += factorpolynomialcopy->constant;
1379 
1380  factorpolynomialcopy->nmonomials = 0;
1381  polynomialdataFree(blkmem, &factorpolynomialcopy);
1382 
1383  return SCIP_OKAY;
1384 }
1385 
1386 /**@} */
1387 
1388 /**@name Expression operand private methods */
1389 /**@{ */
1390 
1391 /** a default implementation of expression interval evaluation that always gives a correct result */
1392 static
1393 SCIP_DECL_EXPRINTEVAL( exprevalIntDefault )
1394 { /*lint --e{715}*/
1396 
1397  return SCIP_OKAY;
1398 }
1399 
1400 /** a default implementation of expression curvature check that always gives a correct result */
1401 static
1402 SCIP_DECL_EXPRCURV( exprcurvDefault )
1403 { /*lint --e{715}*/
1404  *result = SCIP_EXPRCURV_UNKNOWN;
1405 
1406  return SCIP_OKAY;
1407 }
1408 
1409 /** point evaluation for EXPR_VAR */
1410 static
1411 SCIP_DECL_EXPREVAL( exprevalVar )
1412 { /*lint --e{715}*/
1413  assert(result != NULL);
1414  assert(varvals != NULL);
1415 
1416  *result = varvals[opdata.intval];
1417 
1418  return SCIP_OKAY;
1419 }
1420 
1421 /** interval evaluation for EXPR_VAR */
1422 static
1423 SCIP_DECL_EXPRINTEVAL( exprevalIntVar )
1424 { /*lint --e{715}*/
1425  assert(result != NULL);
1426  assert(varvals != NULL);
1427 
1428  *result = varvals[opdata.intval];
1429 
1430  return SCIP_OKAY;
1431 }
1432 
1433 /** curvature for EXPR_VAR */
1434 static
1435 SCIP_DECL_EXPRCURV( exprcurvVar )
1436 { /*lint --e{715}*/
1437  assert(result != NULL);
1438 
1439  *result = SCIP_EXPRCURV_LINEAR;
1440 
1441  return SCIP_OKAY;
1442 }
1443 
1444 /** point evaluation for EXPR_CONST */
1445 static
1446 SCIP_DECL_EXPREVAL( exprevalConst )
1447 { /*lint --e{715}*/
1448  assert(result != NULL);
1449 
1450  *result = opdata.dbl;
1451 
1452  return SCIP_OKAY;
1453 }
1454 
1455 /** interval evaluation for EXPR_CONST */
1456 static
1457 SCIP_DECL_EXPRINTEVAL( exprevalIntConst )
1458 { /*lint --e{715}*/
1459  assert(result != NULL);
1460 
1461  SCIPintervalSet(result, opdata.dbl);
1462 
1463  return SCIP_OKAY;
1464 }
1465 
1466 /** curvature for EXPR_CONST */
1467 static
1468 SCIP_DECL_EXPRCURV( exprcurvConst )
1469 { /*lint --e{715}*/
1470  assert(result != NULL);
1471 
1472  *result = SCIP_EXPRCURV_LINEAR;
1473 
1474  return SCIP_OKAY;
1475 }
1476 
1477 /** point evaluation for EXPR_PARAM */
1478 static
1479 SCIP_DECL_EXPREVAL( exprevalParam )
1480 { /*lint --e{715}*/
1481  assert(result != NULL);
1482  assert(paramvals != NULL );
1483 
1484  *result = paramvals[opdata.intval];
1485 
1486  return SCIP_OKAY;
1487 }
1488 
1489 /** interval evaluation for EXPR_PARAM */
1490 static
1491 SCIP_DECL_EXPRINTEVAL( exprevalIntParam )
1492 { /*lint --e{715}*/
1493  assert(result != NULL);
1494  assert(paramvals != NULL );
1495 
1496  SCIPintervalSet(result, paramvals[opdata.intval]);
1497 
1498  return SCIP_OKAY;
1499 }
1500 
1501 /** curvature for EXPR_PARAM */
1502 static
1503 SCIP_DECL_EXPRCURV( exprcurvParam )
1504 { /*lint --e{715}*/
1505  assert(result != NULL);
1506 
1507  *result = SCIP_EXPRCURV_LINEAR;
1508 
1509  return SCIP_OKAY;
1510 }
1511 
1512 /** point evaluation for EXPR_PLUS */
1513 static
1514 SCIP_DECL_EXPREVAL( exprevalPlus )
1515 { /*lint --e{715}*/
1516  assert(result != NULL);
1517  assert(argvals != NULL);
1518 
1519  *result = argvals[0] + argvals[1];
1520 
1521  return SCIP_OKAY;
1522 }
1523 
1524 /** interval evaluation for EXPR_PLUS */
1525 static
1526 SCIP_DECL_EXPRINTEVAL( exprevalIntPlus )
1527 { /*lint --e{715}*/
1528  assert(result != NULL);
1529  assert(argvals != NULL);
1530 
1531  SCIPintervalAdd(infinity, result, argvals[0], argvals[1]);
1532 
1533  return SCIP_OKAY;
1534 }
1535 
1536 /** curvature for EXPR_PLUS */
1537 static
1538 SCIP_DECL_EXPRCURV( exprcurvPlus )
1539 { /*lint --e{715}*/
1540  assert(result != NULL);
1541  assert(argcurv != NULL);
1542 
1543  *result = SCIPexprcurvAdd(argcurv[0], argcurv[1]);
1544 
1545  return SCIP_OKAY;
1546 }
1547 
1548 /** point evaluation for EXPR_MINUS */
1549 static
1550 SCIP_DECL_EXPREVAL( exprevalMinus )
1551 { /*lint --e{715}*/
1552  assert(result != NULL);
1553  assert(argvals != NULL);
1554 
1555  *result = argvals[0] - argvals[1];
1556 
1557  return SCIP_OKAY;
1558 }
1559 
1560 /** interval evaluation for EXPR_MINUS */
1561 static
1562 SCIP_DECL_EXPRINTEVAL( exprevalIntMinus )
1563 { /*lint --e{715}*/
1564  assert(result != NULL);
1565  assert(argvals != NULL);
1566 
1567  SCIPintervalSub(infinity, result, argvals[0], argvals[1]);
1568 
1569  return SCIP_OKAY;
1570 }
1571 
1572 /** curvature for EXPR_MINUS */
1573 static
1574 SCIP_DECL_EXPRCURV( exprcurvMinus )
1575 { /*lint --e{715}*/
1576  assert(result != NULL);
1577  assert(argcurv != NULL);
1578 
1579  *result = SCIPexprcurvAdd(argcurv[0], SCIPexprcurvNegate(argcurv[1]));
1580 
1581  return SCIP_OKAY;
1582 }
1583 
1584 /** point evaluation for EXPR_MUL */
1585 static
1586 SCIP_DECL_EXPREVAL( exprevalMult )
1587 { /*lint --e{715}*/
1588  assert(result != NULL);
1589  assert(argvals != NULL);
1590 
1591  *result = argvals[0] * argvals[1];
1592 
1593  return SCIP_OKAY;
1594 }
1595 
1596 /** interval evaluation for EXPR_MUL */
1597 static
1598 SCIP_DECL_EXPRINTEVAL( exprevalIntMult )
1599 { /*lint --e{715}*/
1600  assert(result != NULL);
1601  assert(argvals != NULL);
1602 
1603  SCIPintervalMul(infinity, result, argvals[0], argvals[1]);
1604 
1605  return SCIP_OKAY;
1606 }
1607 
1608 /** curvature for EXPR_MUL */
1609 static
1610 SCIP_DECL_EXPRCURV( exprcurvMult )
1611 { /*lint --e{715}*/
1612  assert(result != NULL);
1613  assert(argcurv != NULL);
1614  assert(argbounds != NULL);
1615 
1616  /* if one factor is constant, then product is
1617  * - linear, if constant is 0.0
1618  * - same curvature as other factor, if constant is positive
1619  * - negated curvature of other factor, if constant is negative
1620  *
1621  * if both factors are not constant, then product may not be convex nor concave
1622  */
1623  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1624  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1625  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1626  *result = SCIPexprcurvMultiply(argbounds[0].inf, argcurv[1]);
1627  else
1628  *result = SCIP_EXPRCURV_UNKNOWN;
1629 
1630  return SCIP_OKAY;
1631 }
1632 
1633 /** point evaluation for EXPR_DIV */
1634 static
1635 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1636 __attribute__((no_sanitize_undefined))
1637 #endif
1638 SCIP_DECL_EXPREVAL( exprevalDiv )
1639 { /*lint --e{715}*/
1640  assert(result != NULL);
1641  assert(argvals != NULL);
1642 
1643  *result = argvals[0] / argvals[1];
1644 
1645  return SCIP_OKAY;
1646 }
1647 
1648 /** interval evaluation for EXPR_DIV */
1649 static
1650 SCIP_DECL_EXPRINTEVAL( exprevalIntDiv )
1651 { /*lint --e{715}*/
1652  assert(result != NULL);
1653  assert(argvals != NULL);
1654 
1655  SCIPintervalDiv(infinity, result, argvals[0], argvals[1]);
1656 
1657  return SCIP_OKAY;
1658 }
1659 
1660 /** curvature for EXPR_DIV */
1661 static
1662 SCIP_DECL_EXPRCURV( exprcurvDiv )
1663 { /*lint --e{715}*/
1664  assert(result != NULL);
1665  assert(argcurv != NULL);
1666  assert(argbounds != NULL);
1667 
1668  /* if denominator is constant, then quotient has curvature sign(denominator) * curv(nominator)
1669  *
1670  * if nominator is a constant, then quotient is
1671  * - sign(nominator) * convex, if denominator is concave and positive
1672  * - sign(nominator) * concave, if denominator is convex and negative
1673  *
1674  * if denominator is positive but convex, then we don't know, e.g.,
1675  * - 1/x^2 is convex for x>=0
1676  * - 1/(1+(x-1)^2) is neither convex nor concave for x >= 0
1677  *
1678  * if both nominator and denominator are not constant, then quotient may not be convex nor concave
1679  */
1680  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1681  {
1682  /* denominator is constant */
1683  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1684  }
1685  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1686  {
1687  /* nominator is constant */
1688  if( argbounds[1].inf >= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
1689  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONVEX);
1690  else if( argbounds[1].sup <= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
1691  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONCAVE);
1692  else
1693  *result = SCIP_EXPRCURV_UNKNOWN;
1694  }
1695  else
1696  {
1697  /* denominator and nominator not constant */
1698  *result = SCIP_EXPRCURV_UNKNOWN;
1699  }
1700 
1701  return SCIP_OKAY;
1702 }
1703 
1704 /** point evaluation for EXPR_SQUARE */
1705 static
1706 SCIP_DECL_EXPREVAL( exprevalSquare )
1707 { /*lint --e{715}*/
1708  assert(result != NULL);
1709  assert(argvals != NULL);
1710 
1711  *result = argvals[0] * argvals[0];
1712 
1713  return SCIP_OKAY;
1714 }
1715 
1716 /** interval evaluation for EXPR_SQUARE */
1717 static
1718 SCIP_DECL_EXPRINTEVAL( exprevalIntSquare )
1719 { /*lint --e{715}*/
1720  assert(result != NULL);
1721  assert(argvals != NULL);
1722 
1723  SCIPintervalSquare(infinity, result, argvals[0]);
1724 
1725  return SCIP_OKAY;
1726 }
1727 
1728 /** curvature for EXPR_SQUARE */
1729 static
1730 SCIP_DECL_EXPRCURV( exprcurvSquare )
1731 { /*lint --e{715}*/
1732  assert(result != NULL);
1733  assert(argcurv != NULL);
1734  assert(argbounds != NULL);
1735 
1736  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], 2.0);
1737 
1738  return SCIP_OKAY;
1739 }
1740 
1741 /** point evaluation for EXPR_SQRT */
1742 static
1743 SCIP_DECL_EXPREVAL( exprevalSquareRoot )
1744 { /*lint --e{715}*/
1745  assert(result != NULL);
1746  assert(argvals != NULL);
1747 
1748  *result = sqrt(argvals[0]);
1749 
1750  return SCIP_OKAY;
1751 }
1752 
1753 /** interval evaluation for EXPR_SQRT */
1754 static
1755 SCIP_DECL_EXPRINTEVAL( exprevalIntSquareRoot )
1756 { /*lint --e{715}*/
1757  assert(result != NULL);
1758  assert(argvals != NULL);
1759 
1760  SCIPintervalSquareRoot(infinity, result, argvals[0]);
1761 
1762  return SCIP_OKAY;
1763 }
1764 
1765 /** curvature for EXPR_SQRT */
1766 static
1767 SCIP_DECL_EXPRCURV( exprcurvSquareRoot )
1768 { /*lint --e{715}*/
1769  assert(result != NULL);
1770  assert(argcurv != NULL);
1771 
1772  /* square-root is concave, if child is concave
1773  * otherwise, we don't know
1774  */
1775 
1776  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
1777  *result = SCIP_EXPRCURV_CONCAVE;
1778  else
1779  *result = SCIP_EXPRCURV_UNKNOWN;
1780 
1781  return SCIP_OKAY;
1782 }
1783 
1784 /** point evaluation for EXPR_REALPOWER */
1785 static
1786 SCIP_DECL_EXPREVAL( exprevalRealPower )
1787 { /*lint --e{715}*/
1788  assert(result != NULL);
1789  assert(argvals != NULL);
1790 
1791  *result = pow(argvals[0], opdata.dbl);
1792 
1793  return SCIP_OKAY;
1794 }
1795 
1796 /** interval evaluation for EXPR_REALPOWER */
1797 static
1798 SCIP_DECL_EXPRINTEVAL( exprevalIntRealPower )
1799 { /*lint --e{715}*/
1800  assert(result != NULL);
1801  assert(argvals != NULL);
1802 
1803  SCIPintervalPowerScalar(infinity, result, argvals[0], opdata.dbl);
1804 
1805  return SCIP_OKAY;
1806 }
1807 
1808 /** curvature for EXPR_REALPOWER */
1809 static
1810 SCIP_DECL_EXPRCURV( exprcurvRealPower )
1811 { /*lint --e{715}*/
1812  assert(result != NULL);
1813  assert(argcurv != NULL);
1814  assert(argbounds != NULL);
1815 
1816  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], opdata.dbl);
1817 
1818  return SCIP_OKAY;
1819 }
1820 
1821 /** point evaluation for EXPR_INTPOWER */
1822 static
1823 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1824 __attribute__((no_sanitize_undefined))
1825 #endif
1826 SCIP_DECL_EXPREVAL( exprevalIntPower )
1827 { /*lint --e{715}*/
1828  assert(result != NULL);
1829  assert(argvals != NULL);
1830 
1831  switch( opdata.intval )
1832  {
1833  case -1:
1834  *result = 1.0 / argvals[0];
1835  return SCIP_OKAY;
1836 
1837  case 0:
1838  *result = 1.0;
1839  return SCIP_OKAY;
1840 
1841  case 1:
1842  *result = argvals[0];
1843  return SCIP_OKAY;
1844 
1845  case 2:
1846  *result = argvals[0] * argvals[0];
1847  return SCIP_OKAY;
1848 
1849  default:
1850  *result = pow(argvals[0], (SCIP_Real)opdata.intval);
1851  }
1852 
1853  return SCIP_OKAY;
1854 }
1855 
1856 /** interval evaluation for EXPR_INTPOWER */
1857 static
1858 SCIP_DECL_EXPRINTEVAL( exprevalIntIntPower )
1859 { /*lint --e{715}*/
1860  assert(result != NULL);
1861  assert(argvals != NULL);
1862 
1863  SCIPintervalPowerScalar(infinity, result, argvals[0], (SCIP_Real)opdata.intval);
1864 
1865  return SCIP_OKAY;
1866 }
1867 
1868 /** curvature for EXPR_INTPOWER */
1869 static
1870 SCIP_DECL_EXPRCURV( exprcurvIntPower )
1871 { /*lint --e{715}*/
1872  assert(result != NULL);
1873  assert(argcurv != NULL);
1874  assert(argbounds != NULL);
1875 
1876  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], (SCIP_Real)opdata.intval);
1877 
1878  return SCIP_OKAY;
1879 }
1880 
1881 /** point evaluation for EXPR_SIGNPOWER */
1882 static
1883 SCIP_DECL_EXPREVAL( exprevalSignPower )
1884 { /*lint --e{715}*/
1885  assert(result != NULL);
1886  assert(argvals != NULL);
1887 
1888  if( argvals[0] > 0 )
1889  *result = pow( argvals[0], opdata.dbl);
1890  else
1891  *result = -pow(-argvals[0], opdata.dbl);
1892 
1893  return SCIP_OKAY;
1894 }
1895 
1896 /** interval evaluation for EXPR_SIGNPOWER */
1897 static
1898 SCIP_DECL_EXPRINTEVAL( exprevalIntSignPower )
1899 { /*lint --e{715}*/
1900  assert(result != NULL);
1901  assert(argvals != NULL);
1902 
1903  SCIPintervalSignPowerScalar(infinity, result, argvals[0], opdata.dbl);
1904 
1905  return SCIP_OKAY;
1906 }
1907 
1908 /** curvature for EXPR_SIGNPOWER */
1909 static
1910 SCIP_DECL_EXPRCURV( exprcurvSignPower )
1911 { /*lint --e{715}*/
1912  SCIP_INTERVAL tmp;
1913  SCIP_EXPRCURV left;
1914  SCIP_EXPRCURV right;
1915 
1916  assert(result != NULL);
1917  assert(argcurv != NULL);
1918  assert(argbounds != NULL);
1919 
1920  /* for x <= 0, signpower(x,c) = -(-x)^c
1921  * for x >= 0, signpower(x,c) = ( x)^c
1922  *
1923  * thus, get curvatures for both parts and "intersect" them
1924  */
1925 
1926  if( argbounds[0].inf < 0 )
1927  {
1928  SCIPintervalSetBounds(&tmp, 0.0, -argbounds[0].inf);
1929  left = SCIPexprcurvNegate(SCIPexprcurvPower(tmp, SCIPexprcurvNegate(argcurv[0]), opdata.dbl));
1930  }
1931  else
1932  {
1933  left = SCIP_EXPRCURV_LINEAR;
1934  }
1935 
1936  if( argbounds[0].sup > 0 )
1937  {
1938  SCIPintervalSetBounds(&tmp, 0.0, argbounds[0].sup);
1939  right = SCIPexprcurvPower(tmp, argcurv[0], opdata.dbl);
1940  }
1941  else
1942  {
1943  right = SCIP_EXPRCURV_LINEAR;
1944  }
1945 
1946  *result = (SCIP_EXPRCURV) (left & right);
1947 
1948  return SCIP_OKAY;
1949 }
1950 
1951 /** point evaluation for EXPR_EXP */
1952 static
1953 SCIP_DECL_EXPREVAL( exprevalExp )
1954 { /*lint --e{715}*/
1955  assert(result != NULL);
1956  assert(argvals != NULL);
1957 
1958  *result = exp(argvals[0]);
1959 
1960  return SCIP_OKAY;
1961 }
1962 
1963 /** interval evaluation for EXPR_EXP */
1964 static
1965 SCIP_DECL_EXPRINTEVAL( exprevalIntExp )
1966 { /*lint --e{715}*/
1967  assert(result != NULL);
1968  assert(argvals != NULL);
1969 
1970  SCIPintervalExp(infinity, result, argvals[0]);
1971 
1972  return SCIP_OKAY;
1973 }
1974 
1975 /** curvature for EXPR_EXP */
1976 static
1977 SCIP_DECL_EXPRCURV( exprcurvExp )
1978 { /*lint --e{715}*/
1979  assert(result != NULL);
1980  assert(argcurv != NULL);
1981 
1982  /* expression is convex if child is convex
1983  * otherwise, we don't know
1984  */
1985  if( argcurv[0] & SCIP_EXPRCURV_CONVEX )
1986  *result = SCIP_EXPRCURV_CONVEX;
1987  else
1988  *result = SCIP_EXPRCURV_UNKNOWN;
1989 
1990  return SCIP_OKAY;
1991 }
1992 
1993 /** point evaluation for EXPR_LOG */
1994 static
1995 SCIP_DECL_EXPREVAL( exprevalLog )
1996 { /*lint --e{715}*/
1997  assert(result != NULL);
1998  assert(argvals != NULL);
1999 
2000  *result = log(argvals[0]);
2001 
2002  return SCIP_OKAY;
2003 }
2004 
2005 /** interval evaluation for EXPR_LOG */
2006 static
2007 SCIP_DECL_EXPRINTEVAL( exprevalIntLog )
2008 { /*lint --e{715}*/
2009  assert(result != NULL);
2010  assert(argvals != NULL);
2011 
2012  SCIPintervalLog(infinity, result, argvals[0]);
2013 
2014  return SCIP_OKAY;
2015 }
2016 
2017 /** curvature for EXPR_LOG */
2018 static
2019 SCIP_DECL_EXPRCURV( exprcurvLog )
2020 { /*lint --e{715}*/
2021  assert(result != NULL);
2022  assert(argcurv != NULL);
2023 
2024  /* expression is concave if child is concave
2025  * otherwise, we don't know
2026  */
2027  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
2028  *result = SCIP_EXPRCURV_CONCAVE;
2029  else
2030  *result = SCIP_EXPRCURV_UNKNOWN;
2031 
2032  return SCIP_OKAY;
2033 }
2034 
2035 /** point evaluation for EXPR_SIN */
2036 static
2037 SCIP_DECL_EXPREVAL( exprevalSin )
2038 { /*lint --e{715}*/
2039  assert(result != NULL);
2040  assert(argvals != NULL);
2041 
2042  *result = sin(argvals[0]);
2043 
2044  return SCIP_OKAY;
2045 }
2046 
2047 /** interval evaluation for EXPR_SIN */
2048 static
2049 SCIP_DECL_EXPRINTEVAL( exprevalIntSin )
2050 { /*lint --e{715}*/
2051  assert(result != NULL);
2052  assert(argvals != NULL);
2053  assert(nargs == 1);
2054 
2055  SCIPintervalSin(infinity, result, *argvals);
2056 
2057  return SCIP_OKAY;
2058 }
2059 
2060 /* @todo implement exprcurvSin */
2061 #define exprcurvSin exprcurvDefault
2062 
2063 /** point evaluation for EXPR_COS */
2064 static
2065 SCIP_DECL_EXPREVAL( exprevalCos )
2066 { /*lint --e{715}*/
2067  assert(result != NULL);
2068  assert(argvals != NULL);
2069 
2070  *result = cos(argvals[0]);
2071 
2072  return SCIP_OKAY;
2073 }
2074 
2075 /** interval evaluation for EXPR_COS */
2076 static
2077 SCIP_DECL_EXPRINTEVAL( exprevalIntCos )
2078 { /*lint --e{715}*/
2079  assert(result != NULL);
2080  assert(argvals != NULL);
2081  assert(nargs == 1);
2082 
2083  SCIPintervalCos(infinity, result, *argvals);
2084 
2085  return SCIP_OKAY;
2086 }
2087 
2088 /* @todo implement exprcurvCos */
2089 #define exprcurvCos exprcurvDefault
2090 
2091 /** point evaluation for EXPR_TAN */
2092 static
2093 SCIP_DECL_EXPREVAL( exprevalTan )
2094 { /*lint --e{715}*/
2095  assert(result != NULL);
2096  assert(argvals != NULL);
2097 
2098  *result = tan(argvals[0]);
2099 
2100  return SCIP_OKAY;
2101 }
2102 
2103 /* @todo implement SCIPintervalTan */
2104 #define exprevalIntTan exprevalIntDefault
2105 
2106 /* @todo implement exprcurvTan */
2107 #define exprcurvTan exprcurvDefault
2108 
2109 /* erf and erfi do not seem to exist on every system, and we cannot really handle them anyway, so they are currently disabled */
2110 #ifdef SCIP_DISABLED_CODE
2111 static
2112 SCIP_DECL_EXPREVAL( exprevalErf )
2113 { /*lint --e{715}*/
2114  assert(result != NULL);
2115  assert(argvals != NULL);
2116 
2117  *result = erf(argvals[0]);
2118 
2119  return SCIP_OKAY;
2120 }
2121 
2122 /* @todo implement SCIPintervalErf */
2123 #define exprevalIntErf exprevalIntDefault
2124 
2125 /* @todo implement SCIPintervalErf */
2126 #define exprcurvErf exprcurvDefault
2127 
2128 static
2129 SCIP_DECL_EXPREVAL( exprevalErfi )
2130 { /*lint --e{715}*/
2131  assert(result != NULL);
2132  assert(argvals != NULL);
2133 
2134  /* @TODO implement erfi evaluation */
2135  SCIPerrorMessage("erfi not implemented");
2136 
2137  return SCIP_ERROR;
2138 }
2139 
2140 /* @todo implement SCIPintervalErfi */
2141 #define exprevalIntErfi NULL
2142 
2143 #define exprcurvErfi exprcurvDefault
2144 #endif
2145 
2146 /** point evaluation for EXPR_MIN */
2147 static
2148 SCIP_DECL_EXPREVAL( exprevalMin )
2149 { /*lint --e{715}*/
2150  assert(result != NULL);
2151  assert(argvals != NULL);
2152 
2153  *result = MIN(argvals[0], argvals[1]);
2154 
2155  return SCIP_OKAY;
2156 }
2157 
2158 /** interval evaluation for EXPR_MIN */
2159 static
2160 SCIP_DECL_EXPRINTEVAL( exprevalIntMin )
2161 { /*lint --e{715}*/
2162  assert(result != NULL);
2163  assert(argvals != NULL);
2164 
2165  SCIPintervalMin(infinity, result, argvals[0], argvals[1]);
2166 
2167  return SCIP_OKAY;
2168 }
2169 
2170 /** curvature for EXPR_MIN */
2171 static
2172 SCIP_DECL_EXPRCURV( exprcurvMin )
2173 { /*lint --e{715}*/
2174  assert(result != NULL);
2175  assert(argcurv != NULL);
2176 
2177  /* the minimum of two concave functions is concave
2178  * otherwise, we don't know
2179  */
2180 
2181  if( (argcurv[0] & SCIP_EXPRCURV_CONCAVE) && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
2182  *result = SCIP_EXPRCURV_CONCAVE;
2183  else
2184  *result = SCIP_EXPRCURV_UNKNOWN;
2185 
2186  return SCIP_OKAY;
2187 }
2188 
2189 /** point evaluation for EXPR_MAX */
2190 static
2191 SCIP_DECL_EXPREVAL( exprevalMax )
2192 { /*lint --e{715}*/
2193  assert(result != NULL);
2194  assert(argvals != NULL);
2195 
2196  *result = MAX(argvals[0], argvals[1]);
2197 
2198  return SCIP_OKAY;
2199 }
2200 
2201 /** interval evaluation for EXPR_MAX */
2202 static
2203 SCIP_DECL_EXPRINTEVAL( exprevalIntMax )
2204 { /*lint --e{715}*/
2205  assert(result != NULL);
2206  assert(argvals != NULL);
2207 
2208  SCIPintervalMax(infinity, result, argvals[0], argvals[1]);
2209 
2210  return SCIP_OKAY;
2211 }
2212 
2213 /** curvature for EXPR_MAX */
2214 static
2215 SCIP_DECL_EXPRCURV( exprcurvMax )
2216 { /*lint --e{715}*/
2217  assert(result != NULL);
2218  assert(argcurv != NULL);
2219 
2220  /* the maximum of two convex functions is convex
2221  * otherwise, we don't know
2222  */
2223  if( (argcurv[0] & SCIP_EXPRCURV_CONVEX) && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
2224  *result = SCIP_EXPRCURV_CONVEX;
2225  else
2226  *result = SCIP_EXPRCURV_UNKNOWN;
2227 
2228  return SCIP_OKAY;
2229 }
2230 
2231 /** point evaluation for EXPR_ABS */
2232 static
2233 SCIP_DECL_EXPREVAL( exprevalAbs )
2234 { /*lint --e{715}*/
2235  assert(result != NULL);
2236  assert(argvals != NULL);
2237 
2238  *result = ABS(argvals[0]);
2239 
2240  return SCIP_OKAY;
2241 }
2242 
2243 /** interval evaluation for EXPR_ABS */
2244 static
2245 SCIP_DECL_EXPRINTEVAL( exprevalIntAbs )
2246 { /*lint --e{715}*/
2247  assert(result != NULL);
2248  assert(argvals != NULL);
2249 
2250  SCIPintervalAbs(infinity, result, argvals[0]);
2251 
2252  return SCIP_OKAY;
2253 }
2254 
2255 /** curvature for EXPR_ABS */
2256 static
2257 SCIP_DECL_EXPRCURV( exprcurvAbs )
2258 { /*lint --e{715}*/
2259  assert(result != NULL);
2260  assert(argcurv != NULL);
2261  assert(argbounds != NULL);
2262 
2263  /* if child is only negative, then abs(child) = -child
2264  * if child is only positive, then abs(child) = child
2265  * if child is both positive and negative, but also linear, then abs(child) is convex
2266  * otherwise, we don't know
2267  */
2268  if( argbounds[0].sup <= 0.0 )
2269  *result = SCIPexprcurvMultiply(-1.0, argcurv[0]);
2270  else if( argbounds[0].inf >= 0.0 )
2271  *result = argcurv[0];
2272  else if( argcurv[0] == SCIP_EXPRCURV_LINEAR )
2273  *result = SCIP_EXPRCURV_CONVEX;
2274  else
2275  *result = SCIP_EXPRCURV_UNKNOWN;
2276 
2277  return SCIP_OKAY;
2278 }
2279 
2280 /** point evaluation for EXPR_SIGN */
2281 static
2282 SCIP_DECL_EXPREVAL( exprevalSign )
2283 { /*lint --e{715}*/
2284  assert(result != NULL);
2285  assert(argvals != NULL);
2286 
2287  *result = SIGN(argvals[0]);
2288 
2289  return SCIP_OKAY;
2290 }
2291 
2292 /** interval evaluation for EXPR_SIGN */
2293 static
2294 SCIP_DECL_EXPRINTEVAL( exprevalIntSign )
2295 { /*lint --e{715}*/
2296  assert(result != NULL);
2297  assert(argvals != NULL);
2298 
2299  SCIPintervalSign(infinity, result, argvals[0]);
2300 
2301  return SCIP_OKAY;
2302 }
2303 
2304 /** curvature for EXPR_SIGN */
2305 static
2306 SCIP_DECL_EXPRCURV( exprcurvSign )
2307 { /*lint --e{715}*/
2308  assert(result != NULL);
2309  assert(argbounds != NULL);
2310 
2311  /* if sign of child is clear, then sign is linear otherwise, we don't know */
2312  if( argbounds[0].sup <= 0.0 || argbounds[0].inf >= 0.0 )
2313  *result = SCIP_EXPRCURV_LINEAR;
2314  else
2315  *result = SCIP_EXPRCURV_UNKNOWN;
2316 
2317  return SCIP_OKAY;
2318 }
2319 
2320 /** point evaluation for EXPR_SUM */
2321 static
2322 SCIP_DECL_EXPREVAL( exprevalSum )
2323 { /*lint --e{715}*/
2324  int i;
2325 
2326  assert(result != NULL);
2327  assert(argvals != NULL);
2328 
2329  *result = 0.0;
2330  for( i = 0; i < nargs; ++i )
2331  *result += argvals[i];
2332 
2333  return SCIP_OKAY;
2334 }
2335 
2336 /** interval evaluation for EXPR_SUM */
2337 static
2338 SCIP_DECL_EXPRINTEVAL( exprevalIntSum )
2339 { /*lint --e{715}*/
2340  int i;
2341 
2342  assert(result != NULL);
2343  assert(argvals != NULL);
2344 
2345  SCIPintervalSet(result, 0.0);
2346 
2347  for( i = 0; i < nargs; ++i )
2348  SCIPintervalAdd(infinity, result, *result, argvals[i]);
2349 
2350  return SCIP_OKAY;
2351 }
2352 
2353 /** curvature for EXPR_SUM */
2354 static
2355 SCIP_DECL_EXPRCURV( exprcurvSum )
2356 { /*lint --e{715}*/
2357  int i;
2358 
2359  assert(result != NULL);
2360  assert(argcurv != NULL);
2361 
2362  *result = SCIP_EXPRCURV_LINEAR;
2363 
2364  for( i = 0; i < nargs; ++i )
2365  *result = SCIPexprcurvAdd(*result, argcurv[i]);
2366 
2367  return SCIP_OKAY;
2368 }
2369 
2370 /** point evaluation for EXPR_PRODUCT */
2371 static
2372 SCIP_DECL_EXPREVAL( exprevalProduct )
2373 { /*lint --e{715}*/
2374  int i;
2375 
2376  assert(result != NULL);
2377  assert(argvals != NULL);
2378 
2379  *result = 1.0;
2380  for( i = 0; i < nargs; ++i )
2381  *result *= argvals[i];
2382 
2383  return SCIP_OKAY;
2384 }
2385 
2386 /** interval evaluation for EXPR_PRODUCT */
2387 static
2388 SCIP_DECL_EXPRINTEVAL( exprevalIntProduct )
2389 { /*lint --e{715}*/
2390  int i;
2391 
2392  assert(result != NULL);
2393  assert(argvals != NULL);
2394 
2395  SCIPintervalSet(result, 1.0);
2396 
2397  for( i = 0; i < nargs; ++i )
2398  SCIPintervalMul(infinity, result, *result, argvals[i]);
2399 
2400  return SCIP_OKAY;
2401 }
2402 
2403 /** curvature for EXPR_PRODUCT */
2404 static
2405 SCIP_DECL_EXPRCURV( exprcurvProduct )
2406 { /*lint --e{715}*/
2407  SCIP_Bool hadnonconst;
2408  SCIP_Real constants;
2409  int i;
2410 
2411  assert(result != NULL);
2412  assert(argcurv != NULL);
2413  assert(argbounds != NULL);
2414 
2415  /* if all factors are constant, then product is linear (even constant)
2416  * if only one factor is not constant, then product is curvature of this factor, multiplied by sign of product of remaining factors
2417  */
2418  *result = SCIP_EXPRCURV_LINEAR;
2419  hadnonconst = FALSE;
2420  constants = 1.0;
2421 
2422  for( i = 0; i < nargs; ++i )
2423  {
2424  if( argbounds[i].inf == argbounds[i].sup ) /*lint !e777*/
2425  {
2426  constants *= argbounds[i].inf;
2427  }
2428  else if( !hadnonconst )
2429  {
2430  /* first non-constant child */
2431  *result = argcurv[i];
2432  hadnonconst = TRUE;
2433  }
2434  else
2435  {
2436  /* more than one non-constant child, thus don't know curvature */
2437  *result = SCIP_EXPRCURV_UNKNOWN;
2438  break;
2439  }
2440  }
2441 
2442  *result = SCIPexprcurvMultiply(constants, *result);
2443 
2444  return SCIP_OKAY;
2445 }
2446 
2447 /** point evaluation for EXPR_LINEAR */
2448 static
2449 SCIP_DECL_EXPREVAL( exprevalLinear )
2450 { /*lint --e{715}*/
2451  SCIP_Real* coef;
2452  int i;
2453 
2454  assert(result != NULL);
2455  assert(argvals != NULL || nargs == 0);
2456  assert(opdata.data != NULL);
2457 
2458  coef = &((SCIP_Real*)opdata.data)[nargs];
2459 
2460  *result = *coef;
2461  for( i = nargs-1, --coef; i >= 0; --i, --coef )
2462  *result += *coef * argvals[i]; /*lint !e613*/
2463 
2464  assert(++coef == (SCIP_Real*)opdata.data);
2465 
2466  return SCIP_OKAY;
2467 }
2468 
2469 /** interval evaluation for EXPR_LINEAR */
2470 static
2471 SCIP_DECL_EXPRINTEVAL( exprevalIntLinear )
2472 { /*lint --e{715}*/
2473  assert(result != NULL);
2474  assert(argvals != NULL || nargs == 0);
2475  assert(opdata.data != NULL);
2476 
2477  SCIPintervalScalprodScalars(infinity, result, nargs, argvals, (SCIP_Real*)opdata.data);
2478  SCIPintervalAddScalar(infinity, result, *result, ((SCIP_Real*)opdata.data)[nargs]);
2479 
2480  return SCIP_OKAY;
2481 }
2482 
2483 /** curvature for EXPR_LINEAR */
2484 static
2485 SCIP_DECL_EXPRCURV( exprcurvLinear )
2486 { /*lint --e{715}*/
2487  SCIP_Real* data;
2488  int i;
2489 
2490  assert(result != NULL);
2491  assert(argcurv != NULL);
2492 
2493  data = (SCIP_Real*)opdata.data;
2494  assert(data != NULL);
2495 
2496  *result = SCIP_EXPRCURV_LINEAR;
2497 
2498  for( i = 0; i < nargs; ++i )
2499  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(data[i], argcurv[i]));
2500 
2501  return SCIP_OKAY;
2502 }
2503 
2504 /** expression data copy for EXPR_LINEAR */
2505 static
2506 SCIP_DECL_EXPRCOPYDATA( exprCopyDataLinear )
2507 { /*lint --e{715}*/
2508  SCIP_Real* targetdata;
2509 
2510  assert(blkmem != NULL);
2511  assert(nchildren >= 0);
2512  assert(opdatatarget != NULL);
2513 
2514  /* for a linear expression, we need to copy the array that holds the coefficients and constant term */
2515  assert(opdatasource.data != NULL);
2516  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &targetdata, (SCIP_Real*)opdatasource.data, nchildren + 1) ); /*lint !e866*/
2517  opdatatarget->data = targetdata;
2518 
2519  return SCIP_OKAY;
2520 }
2521 
2522 /** expression data free for EXPR_LINEAR */
2523 static
2524 SCIP_DECL_EXPRFREEDATA( exprFreeDataLinear )
2525 { /*lint --e{715}*/
2526  SCIP_Real* freedata;
2527 
2528  assert(blkmem != NULL);
2529  assert(nchildren >= 0);
2530 
2531  freedata = (SCIP_Real*)opdata.data;
2532  assert(freedata != NULL);
2533 
2534  BMSfreeBlockMemoryArray(blkmem, &freedata, nchildren + 1); /*lint !e866*/
2535 }
2536 
2537 /** point evaluation for EXPR_QUADRATIC */
2538 static
2539 SCIP_DECL_EXPREVAL( exprevalQuadratic )
2540 { /*lint --e{715}*/
2541  SCIP_EXPRDATA_QUADRATIC* quaddata;
2542  SCIP_Real* lincoefs;
2543  SCIP_QUADELEM* quadelems;
2544  int nquadelems;
2545  int i;
2546 
2547  assert(result != NULL);
2548  assert(argvals != NULL || nargs == 0);
2549 
2550  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2551  assert(quaddata != NULL);
2552 
2553  lincoefs = quaddata->lincoefs;
2554  nquadelems = quaddata->nquadelems;
2555  quadelems = quaddata->quadelems;
2556 
2557  assert(quadelems != NULL || nquadelems == 0);
2558  assert(argvals != NULL || nquadelems == 0);
2559 
2560  *result = quaddata->constant;
2561 
2562  if( lincoefs != NULL )
2563  {
2564  for( i = nargs-1; i >= 0; --i )
2565  *result += lincoefs[i] * argvals[i]; /*lint !e613*/
2566  }
2567 
2568  for( i = 0; i < nquadelems; ++i, ++quadelems ) /*lint !e613*/
2569  *result += quadelems->coef * argvals[quadelems->idx1] * argvals[quadelems->idx2]; /*lint !e613*/
2570 
2571  return SCIP_OKAY;
2572 }
2573 
2574 /** interval evaluation for EXPR_QUADRATIC */
2575 static
2576 SCIP_DECL_EXPRINTEVAL( exprevalIntQuadratic )
2577 { /*lint --e{715}*/
2578  SCIP_EXPRDATA_QUADRATIC* quaddata;
2579  SCIP_Real* lincoefs;
2580  SCIP_QUADELEM* quadelems;
2581  int nquadelems;
2582  int i;
2583  int argidx;
2584  SCIP_Real sqrcoef;
2585  SCIP_INTERVAL lincoef;
2586  SCIP_INTERVAL tmp;
2587 
2588  assert(result != NULL);
2589  assert(argvals != NULL || nargs == 0);
2590 
2591  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2592  assert(quaddata != NULL);
2593 
2594  lincoefs = quaddata->lincoefs;
2595  nquadelems = quaddata->nquadelems;
2596  quadelems = quaddata->quadelems;
2597 
2598  assert(quadelems != NULL || nquadelems == 0);
2599  assert(argvals != NULL || nargs == 0);
2600 
2601  /* something fast for case of only one child */
2602  if( nargs == 1 )
2603  {
2604  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[0] : 0.0);
2605 
2606  sqrcoef = 0.0;
2607  for( i = 0; i < nquadelems; ++i )
2608  {
2609  assert(quadelems[i].idx1 == 0); /*lint !e613*/
2610  assert(quadelems[i].idx2 == 0); /*lint !e613*/
2611  sqrcoef += quadelems[i].coef; /*lint !e613*/
2612  }
2613 
2614  SCIPintervalQuad(infinity, result, sqrcoef, lincoef, argvals[0]); /*lint !e613*/
2615  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2616 
2617  return SCIP_OKAY;
2618  }
2619 
2620  if( nargs == 2 && nquadelems > 0 )
2621  {
2622  /* if it's a bivariate quadratic expression with bilinear term, do something special */
2623  SCIP_Real ax; /* square coefficient of first child */
2624  SCIP_Real ay; /* square coefficient of second child */
2625  SCIP_Real axy; /* bilinear coefficient */
2626 
2627  ax = 0.0;
2628  ay = 0.0;
2629  axy = 0.0;
2630  for( i = 0; i < nquadelems; ++i )
2631  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 ) /*lint !e613*/
2632  ax += quadelems[i].coef; /*lint !e613*/
2633  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 ) /*lint !e613*/
2634  ay += quadelems[i].coef; /*lint !e613*/
2635  else
2636  axy += quadelems[i].coef; /*lint !e613*/
2637 
2638  SCIPintervalQuadBivar(infinity, result, ax, ay, axy,
2639  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2640  argvals[0], argvals[1]); /*lint !e613*/
2641  SCIPdebugMessage("%g x^2 + %g y^2 + %g x y + %g x + %g y = [%g,%g] for x = [%g,%g], y = [%g,%g]\n",
2642  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2643  result->inf, result->sup, argvals[0].inf, argvals[0].sup, argvals[1].inf, argvals[1].sup); /*lint !e613*/
2644 
2645  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2646 
2647  return SCIP_OKAY;
2648  }
2649 
2650  /* make sure coefficients are sorted */
2651  quadraticdataSort(quaddata);
2652 
2653  SCIPintervalSet(result, quaddata->constant);
2654 
2655  /* for each argument, we collect it's linear index from lincoefs, it's square coefficients and all factors from bilinear terms
2656  * then we compute the interval sqrcoef*x^2 + lincoef*x and add it to result
2657  * @todo split quadratic expression into bivariate quadratic terms and apply the above method
2658  */
2659  i = 0;
2660  for( argidx = 0; argidx < nargs; ++argidx )
2661  {
2662  if( i == nquadelems || quadelems[i].idx1 > argidx ) /*lint !e613*/
2663  {
2664  /* there are no quadratic terms with argidx in its first argument, that should be easy to handle */
2665  if( lincoefs != NULL )
2666  {
2667  SCIPintervalMulScalar(infinity, &tmp, argvals[argidx], lincoefs[argidx]); /*lint !e613*/
2668  SCIPintervalAdd(infinity, result, *result, tmp);
2669  }
2670  continue;
2671  }
2672 
2673  sqrcoef = 0.0;
2674  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[argidx] : 0.0);
2675 
2676  assert(i < nquadelems && quadelems[i].idx1 == argidx); /*lint !e613*/
2677  do
2678  {
2679  if( quadelems[i].idx2 == argidx ) /*lint !e613*/
2680  {
2681  sqrcoef += quadelems[i].coef; /*lint !e613*/
2682  }
2683  else
2684  {
2685  SCIPintervalMulScalar(infinity, &tmp, argvals[quadelems[i].idx2], quadelems[i].coef); /*lint !e613*/
2686  SCIPintervalAdd(infinity, &lincoef, lincoef, tmp);
2687  }
2688  ++i;
2689  }
2690  while( i < nquadelems && quadelems[i].idx1 == argidx ); /*lint !e613*/
2691  assert(i == nquadelems || quadelems[i].idx1 > argidx); /*lint !e613*/
2692 
2693  SCIPintervalQuad(infinity, &tmp, sqrcoef, lincoef, argvals[argidx]); /*lint !e613*/
2694  SCIPintervalAdd(infinity, result, *result, tmp);
2695  }
2696  assert(i == nquadelems);
2697 
2698  return SCIP_OKAY;
2699 }
2700 
2701 /** curvature for EXPR_QUADRATIC */
2702 static
2703 SCIP_DECL_EXPRCURV( exprcurvQuadratic )
2704 { /*lint --e{715}*/
2706  SCIP_QUADELEM* quadelems;
2707  int nquadelems;
2708  SCIP_Real* lincoefs;
2709  int i;
2710 
2711  assert(result != NULL);
2712  assert(argcurv != NULL);
2713  assert(argbounds != NULL);
2714 
2715  data = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2716  assert(data != NULL);
2717 
2718  lincoefs = data->lincoefs;
2719  quadelems = data->quadelems;
2720  nquadelems = data->nquadelems;
2721 
2722  *result = SCIP_EXPRCURV_LINEAR;
2723 
2724  if( lincoefs != NULL )
2725  for( i = 0; i < nargs; ++i )
2726  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(lincoefs[i], argcurv[i]));
2727 
2728  /* @todo could try cholesky factorization if all children linear...
2729  * @todo should then cache the result
2730  */
2731  for( i = 0; i < nquadelems && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
2732  {
2733  if( quadelems[i].coef == 0.0 )
2734  continue;
2735 
2736  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup && /*lint !e777*/
2737  +argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup
2738  ) /*lint !e777*/
2739  {
2740  /* both factors are constants -> curvature does not change */
2741  continue;
2742  }
2743 
2744  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup ) /*lint !e777*/
2745  {
2746  /* first factor is constant, second is not -> add curvature of second */
2747  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx1].inf, argcurv[quadelems[i].idx2]));
2748  }
2749  else if( argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup ) /*lint !e777*/
2750  {
2751  /* first factor is not constant, second is -> add curvature of first */
2752  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx2].inf, argcurv[quadelems[i].idx1]));
2753  }
2754  else if( quadelems[i].idx1 == quadelems[i].idx2 )
2755  {
2756  /* both factors not constant, but the same (square term) */
2757  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef, SCIPexprcurvPower(argbounds[quadelems[i].idx1], argcurv[quadelems[i].idx1], 2.0)));
2758  }
2759  else
2760  {
2761  /* two different non-constant factors -> can't tell about curvature */
2762  *result = SCIP_EXPRCURV_UNKNOWN;
2763  }
2764  }
2765 
2766  return SCIP_OKAY;
2767 }
2768 
2769 /** expression data copy for EXPR_QUADRATIC */
2770 static
2771 SCIP_DECL_EXPRCOPYDATA( exprCopyDataQuadratic )
2772 { /*lint --e{715}*/
2773  SCIP_EXPRDATA_QUADRATIC* sourcedata;
2774 
2775  assert(blkmem != NULL);
2776  assert(opdatatarget != NULL);
2777 
2778  sourcedata = (SCIP_EXPRDATA_QUADRATIC*)opdatasource.data;
2779  assert(sourcedata != NULL);
2780 
2781  SCIP_CALL( quadraticdataCreate(blkmem, (SCIP_EXPRDATA_QUADRATIC**)&opdatatarget->data,
2782  sourcedata->constant, nchildren, sourcedata->lincoefs, sourcedata->nquadelems, sourcedata->quadelems) );
2783 
2784  return SCIP_OKAY;
2785 }
2786 
2787 /** expression data free for EXPR_QUADRATIC */
2788 static
2789 SCIP_DECL_EXPRFREEDATA( exprFreeDataQuadratic )
2790 { /*lint --e{715}*/
2791  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
2792 
2793  assert(blkmem != NULL);
2794  assert(nchildren >= 0);
2795 
2796  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2797  assert(quadraticdata != NULL);
2798 
2799  if( quadraticdata->lincoefs != NULL )
2800  {
2801  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->lincoefs, nchildren);
2802  }
2803 
2804  if( quadraticdata->nquadelems > 0 )
2805  {
2806  assert(quadraticdata->quadelems != NULL);
2807  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->quadelems, quadraticdata->nquadelems);
2808  }
2809 
2810  BMSfreeBlockMemory(blkmem, &quadraticdata);
2811 }
2812 
2813 /** point evaluation for EXPR_POLYNOMIAL */
2814 static
2815 SCIP_DECL_EXPREVAL( exprevalPolynomial )
2816 { /*lint --e{715}*/
2817  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2818  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2819  SCIP_Real childval;
2820  SCIP_Real exponent;
2821  SCIP_Real monomialval;
2822  int i;
2823  int j;
2824 
2825  assert(result != NULL);
2826  assert(argvals != NULL || nargs == 0);
2827  assert(opdata.data != NULL);
2828 
2829  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2830  assert(polynomialdata != NULL);
2831 
2832  *result = polynomialdata->constant;
2833 
2834  for( i = 0; i < polynomialdata->nmonomials; ++i )
2835  {
2836  monomialdata = polynomialdata->monomials[i];
2837  assert(monomialdata != NULL);
2838 
2839  monomialval = monomialdata->coef;
2840  for( j = 0; j < monomialdata->nfactors; ++j )
2841  {
2842  assert(monomialdata->childidxs[j] >= 0);
2843  assert(monomialdata->childidxs[j] < nargs);
2844 
2845  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2846  if( childval == 1.0 ) /* 1^anything == 1 */
2847  continue;
2848 
2849  exponent = monomialdata->exponents[j];
2850 
2851  if( childval == 0.0 )
2852  {
2853  if( exponent > 0.0 )
2854  {
2855  /* 0^positive == 0 */
2856  monomialval = 0.0;
2857  break;
2858  }
2859  else if( exponent < 0.0 )
2860  {
2861  /* 0^negative = nan (or should it be +inf?, doesn't really matter) */
2862 #ifdef NAN
2863  *result = NAN;
2864 #else
2865  /* cppcheck-suppress wrongmathcall */
2866  *result = pow(0.0, -1.0);
2867 #endif
2868  return SCIP_OKAY;
2869  }
2870  /* 0^0 == 1 */
2871  continue;
2872  }
2873 
2874  /* cover some special exponents separately to avoid calling expensive pow function */
2875  if( exponent == 0.0 )
2876  continue;
2877  if( exponent == 1.0 )
2878  {
2879  monomialval *= childval;
2880  continue;
2881  }
2882  if( exponent == 2.0 )
2883  {
2884  monomialval *= childval * childval;
2885  continue;
2886  }
2887  if( exponent == 0.5 )
2888  {
2889  monomialval *= sqrt(childval);
2890  continue;
2891  }
2892  if( exponent == -1.0 )
2893  {
2894  monomialval /= childval;
2895  continue;
2896  }
2897  if( exponent == -2.0 )
2898  {
2899  monomialval /= childval * childval;
2900  continue;
2901  }
2902  monomialval *= pow(childval, exponent);
2903  }
2904 
2905  *result += monomialval;
2906  }
2907 
2908  return SCIP_OKAY;
2909 }
2910 
2911 /** interval evaluation for EXPR_POLYNOMIAL */
2912 static
2913 SCIP_DECL_EXPRINTEVAL( exprevalIntPolynomial )
2914 { /*lint --e{715}*/
2915  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2916  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2917  SCIP_INTERVAL childval;
2918  SCIP_INTERVAL monomialval;
2919  SCIP_Real exponent;
2920  int i;
2921  int j;
2922 
2923  assert(result != NULL);
2924  assert(argvals != NULL || nargs == 0);
2925  assert(opdata.data != NULL);
2926 
2927  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2928  assert(polynomialdata != NULL);
2929 
2930  SCIPintervalSet(result, polynomialdata->constant);
2931 
2932  for( i = 0; i < polynomialdata->nmonomials; ++i )
2933  {
2934  monomialdata = polynomialdata->monomials[i];
2935  assert(monomialdata != NULL);
2936 
2937  SCIPintervalSet(&monomialval, monomialdata->coef);
2938  for( j = 0; j < monomialdata->nfactors && !SCIPintervalIsEntire(infinity, monomialval); ++j )
2939  {
2940  assert(monomialdata->childidxs[j] >= 0);
2941  assert(monomialdata->childidxs[j] < nargs);
2942 
2943  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2944 
2945  exponent = monomialdata->exponents[j];
2946 
2947  /* cover some special exponents separately to avoid calling expensive pow function */
2948  if( exponent == 0.0 )
2949  continue;
2950 
2951  if( exponent == 1.0 )
2952  {
2953  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2954  continue;
2955  }
2956 
2957  if( exponent == 2.0 )
2958  {
2959  SCIPintervalSquare(infinity, &childval, childval);
2960  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2961  continue;
2962  }
2963 
2964  if( exponent == 0.5 )
2965  {
2966  SCIPintervalSquareRoot(infinity, &childval, childval);
2967  if( SCIPintervalIsEmpty(infinity, childval) )
2968  {
2969  SCIPintervalSetEmpty(result);
2970  break;
2971  }
2972  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2973  continue;
2974  }
2975  else if( exponent == -1.0 )
2976  {
2977  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2978  }
2979  else if( exponent == -2.0 )
2980  {
2981  SCIPintervalSquare(infinity, &childval, childval);
2982  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2983  }
2984  else
2985  {
2986  SCIPintervalPowerScalar(infinity, &childval, childval, exponent);
2987  if( SCIPintervalIsEmpty(infinity, childval) )
2988  {
2989  SCIPintervalSetEmpty(result);
2990  return SCIP_OKAY;
2991  }
2992  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2993  }
2994 
2995  /* the cases in which monomialval gets empty should have been catched */
2996  assert(!SCIPintervalIsEmpty(infinity, monomialval));
2997  }
2998 
2999  SCIPintervalAdd(infinity, result, *result, monomialval);
3000  }
3001 
3002  return SCIP_OKAY;
3003 }
3004 
3005 /** curvature for EXPR_POLYNOMIAL */
3006 static
3007 SCIP_DECL_EXPRCURV( exprcurvPolynomial )
3008 { /*lint --e{715}*/
3010  SCIP_EXPRDATA_MONOMIAL** monomials;
3011  SCIP_EXPRDATA_MONOMIAL* monomial;
3012  int nmonomials;
3013  int i;
3014 
3015  assert(result != NULL);
3016  assert(argcurv != NULL);
3017  assert(argbounds != NULL);
3018 
3019  data = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3020  assert(data != NULL);
3021 
3022  monomials = data->monomials;
3023  nmonomials = data->nmonomials;
3024 
3025  *result = SCIP_EXPRCURV_LINEAR;
3026 
3027  for( i = 0; i < nmonomials && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
3028  {
3029  /* we assume that some simplifier was running, so that monomials do not have constants in their factors and such that all factors are different
3030  * (result would still be correct)
3031  */
3032  monomial = monomials[i];
3033  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(monomial->coef, SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, monomial->childidxs, argcurv, argbounds)));
3034  }
3035 
3036  return SCIP_OKAY;
3037 }
3038 
3039 /** expression data copy for EXPR_POLYNOMIAL */
3040 static
3041 SCIP_DECL_EXPRCOPYDATA( exprCopyDataPolynomial )
3042 { /*lint --e{715}*/
3043  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata;
3044  SCIP_EXPRDATA_POLYNOMIAL* targetpolynomialdata;
3045 
3046  assert(blkmem != NULL);
3047  assert(opdatatarget != NULL);
3048 
3049  sourcepolynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdatasource.data;
3050  assert(sourcepolynomialdata != NULL);
3051 
3052  SCIP_CALL( polynomialdataCopy(blkmem, &targetpolynomialdata, sourcepolynomialdata) );
3053 
3054  opdatatarget->data = (void*)targetpolynomialdata;
3055 
3056  return SCIP_OKAY;
3057 }
3058 
3059 /** expression data free for EXPR_POLYNOMIAL */
3060 static
3061 SCIP_DECL_EXPRFREEDATA( exprFreeDataPolynomial )
3062 { /*lint --e{715}*/
3063  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3064 
3065  assert(blkmem != NULL);
3066 
3067  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3068  assert(polynomialdata != NULL);
3069 
3070  polynomialdataFree(blkmem, &polynomialdata);
3071 }
3072 
3073 /** point evaluation for user expression */
3074 static
3075 SCIP_DECL_EXPREVAL( exprevalUser )
3076 { /*lint --e{715}*/
3077  SCIP_EXPRDATA_USER* exprdata;
3078 
3079  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3080 
3081  SCIP_CALL( exprdata->eval(exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3082 
3083  return SCIP_OKAY;
3084 }
3085 
3086 /** interval evaluation for user expression */
3087 static
3088 SCIP_DECL_EXPRINTEVAL( exprevalIntUser )
3089 { /*lint --e{715}*/
3090  SCIP_EXPRDATA_USER* exprdata;
3091 
3092  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3093 
3094  if( exprdata->inteval != NULL )
3095  {
3096  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3097  }
3098  else
3099  {
3100  /* if user does not provide interval evaluation, then return a result that is always correct */
3102  }
3103 
3104  return SCIP_OKAY;
3105 }
3106 
3107 /** curvature check for user expression */
3108 static
3109 SCIP_DECL_EXPRCURV( exprcurvUser )
3110 {
3111  SCIP_EXPRDATA_USER* exprdata;
3112 
3113  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3114 
3115  if( exprdata->curv != NULL )
3116  {
3117  SCIP_CALL( exprdata->curv(infinity, exprdata->userdata, nargs, argbounds, argcurv, result) );
3118  }
3119  else
3120  {
3121  /* if user does not provide curvature check, then return unknown (which is handled like indefinite) */
3122  *result = SCIP_EXPRCURV_UNKNOWN;
3123  }
3124 
3125  return SCIP_OKAY;
3126 }
3127 
3128 /** data copy for user expression */
3129 static
3130 SCIP_DECL_EXPRCOPYDATA( exprCopyDataUser )
3131 {
3132  SCIP_EXPRDATA_USER* exprdatasource;
3133  SCIP_EXPRDATA_USER* exprdatatarget;
3134 
3135  assert(blkmem != NULL);
3136  assert(opdatatarget != NULL);
3137 
3138  exprdatasource = (SCIP_EXPRDATA_USER*)opdatasource.data;
3139  assert(exprdatasource != NULL);
3140 
3141  /* duplicate expression data */
3142  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, &exprdatatarget, exprdatasource) );
3143 
3144  /* duplicate user expression data, if any */
3145  if( exprdatasource->copydata != NULL )
3146  {
3147  SCIP_CALL( exprdatasource->copydata(blkmem, nchildren, exprdatasource->userdata, &exprdatatarget->userdata) );
3148  }
3149  else
3150  {
3151  /* if no copy function for data, then there has to be no data */
3152  assert(exprdatatarget->userdata == NULL);
3153  }
3154 
3155  opdatatarget->data = (void*)exprdatatarget;
3156 
3157  return SCIP_OKAY;
3158 }
3159 
3160 /** data free for user expression */
3161 static
3162 SCIP_DECL_EXPRFREEDATA( exprFreeDataUser )
3163 {
3164  SCIP_EXPRDATA_USER* exprdata;
3165 
3166  assert(blkmem != NULL);
3167 
3168  exprdata = (SCIP_EXPRDATA_USER*)opdata.data;
3169 
3170  /* free user expression data, if any */
3171  if( exprdata->freedata != NULL )
3172  {
3173  exprdata->freedata(blkmem, nchildren, exprdata->userdata);
3174  }
3175  else
3176  {
3177  assert(exprdata->userdata == NULL);
3178  }
3179 
3180  /* free expression data */
3181  BMSfreeBlockMemory(blkmem, &exprdata);
3182 }
3183 
3184 /** element in table of expression operands */
3185 struct exprOpTableElement
3186 {
3187  const char* name; /**< name of operand (used for printing) */
3188  int nargs; /**< number of arguments (negative if not fixed) */
3189  SCIP_DECL_EXPREVAL ((*eval)); /**< evaluation function */
3190  SCIP_DECL_EXPRINTEVAL ((*inteval)); /**< interval evaluation function */
3191  SCIP_DECL_EXPRCURV ((*curv)); /**< curvature check function */
3192  SCIP_DECL_EXPRCOPYDATA ((*copydata)); /**< expression data copy function, or NULL to only opdata union */
3193  SCIP_DECL_EXPRFREEDATA ((*freedata)); /**< expression data free function, or NULL if nothing to free */
3194 };
3195 
3196 #define EXPROPEMPTY {NULL, -1, NULL, NULL, NULL, NULL, NULL}
3197 
3198 /** table containing for each operand the name, the number of children, and some evaluation functions */
3199 static
3200 struct exprOpTableElement exprOpTable[] =
3201  {
3202  EXPROPEMPTY,
3203  { "variable", 0, exprevalVar, exprevalIntVar, exprcurvVar, NULL, NULL },
3204  { "constant", 0, exprevalConst, exprevalIntConst, exprcurvConst, NULL, NULL },
3205  { "parameter", 0, exprevalParam, exprevalIntParam, exprcurvParam, NULL, NULL },
3207  { "plus", 2, exprevalPlus, exprevalIntPlus, exprcurvPlus, NULL, NULL },
3208  { "minus", 2, exprevalMinus, exprevalIntMinus, exprcurvMinus, NULL, NULL },
3209  { "mul", 2, exprevalMult, exprevalIntMult, exprcurvMult, NULL, NULL },
3210  { "div", 2, exprevalDiv, exprevalIntDiv, exprcurvDiv, NULL, NULL },
3211  { "sqr", 1, exprevalSquare, exprevalIntSquare, exprcurvSquare, NULL, NULL },
3212  { "sqrt", 1, exprevalSquareRoot, exprevalIntSquareRoot, exprcurvSquareRoot, NULL, NULL },
3213  { "realpower", 1, exprevalRealPower, exprevalIntRealPower, exprcurvRealPower, NULL, NULL },
3214  { "intpower", 1, exprevalIntPower, exprevalIntIntPower, exprcurvIntPower, NULL, NULL },
3215  { "signpower", 1, exprevalSignPower, exprevalIntSignPower, exprcurvSignPower, NULL, NULL },
3216  { "exp", 1, exprevalExp, exprevalIntExp, exprcurvExp, NULL, NULL },
3217  { "log", 1, exprevalLog, exprevalIntLog, exprcurvLog, NULL, NULL },
3218  { "sin", 1, exprevalSin, exprevalIntSin, exprcurvSin, NULL, NULL },
3219  { "cos", 1, exprevalCos, exprevalIntCos, exprcurvCos, NULL, NULL },
3220  { "tan", 1, exprevalTan, exprevalIntTan, exprcurvTan, NULL, NULL },
3221  /* { "erf", 1, exprevalErf, exprevalIntErf, exprcurvErf, NULL, NULL }, */
3222  /* { "erfi", 1, exprevalErfi, exprevalIntErfi exprcurvErfi, NULL, NULL }, */
3224  { "min", 2, exprevalMin, exprevalIntMin, exprcurvMin, NULL, NULL },
3225  { "max", 2, exprevalMax, exprevalIntMax, exprcurvMax, NULL, NULL },
3226  { "abs", 1, exprevalAbs, exprevalIntAbs, exprcurvAbs, NULL, NULL },
3227  { "sign", 1, exprevalSign, exprevalIntSign, exprcurvSign, NULL, NULL },
3233  { "sum", -2, exprevalSum, exprevalIntSum, exprcurvSum, NULL, NULL },
3234  { "prod", -2, exprevalProduct, exprevalIntProduct, exprcurvProduct, NULL, NULL },
3235  { "linear", -2, exprevalLinear, exprevalIntLinear, exprcurvLinear, exprCopyDataLinear, exprFreeDataLinear },
3236  { "quadratic", -2, exprevalQuadratic, exprevalIntQuadratic, exprcurvQuadratic, exprCopyDataQuadratic, exprFreeDataQuadratic },
3237  { "polynomial", -2, exprevalPolynomial, exprevalIntPolynomial, exprcurvPolynomial, exprCopyDataPolynomial, exprFreeDataPolynomial },
3238  { "user", -2, exprevalUser, exprevalIntUser, exprcurvUser, exprCopyDataUser, exprFreeDataUser }
3239  };
3240 
3241 /**@} */
3242 
3243 /**@name Expression operand methods */
3244 /**@{ */
3245 
3246 /** gives the name of an operand as string */
3247 const char* SCIPexpropGetName(
3248  SCIP_EXPROP op /**< expression operand */
3249  )
3250 {
3251  assert(op < SCIP_EXPR_LAST);
3252 
3253  return exprOpTable[op].name;
3254 }
3255 
3256 /** gives the number of children of a simple operand */
3258  SCIP_EXPROP op /**< expression operand */
3259  )
3260 {
3261  assert(op < SCIP_EXPR_LAST);
3262 
3263  return exprOpTable[op].nargs;
3264 }
3265 
3266 /**@} */
3267 
3268 /**@name Expressions private methods */
3269 /**@{ */
3270 
3271 /** creates an expression
3272  *
3273  * Note, that the expression is allocated but for the children only the pointer is copied.
3274  */
3275 static
3277  BMS_BLKMEM* blkmem, /**< block memory data structure */
3278  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
3279  SCIP_EXPROP op, /**< operand of expression */
3280  int nchildren, /**< number of children */
3281  SCIP_EXPR** children, /**< children */
3282  SCIP_EXPROPDATA opdata /**< operand data */
3283  )
3284 {
3285  assert(blkmem != NULL);
3286  assert(expr != NULL);
3287  assert(children != NULL || nchildren == 0);
3288  assert(children == NULL || nchildren > 0);
3289 
3290  SCIP_ALLOC( BMSallocBlockMemory(blkmem, expr) );
3291 
3292  (*expr)->op = op;
3293  (*expr)->nchildren = nchildren;
3294  (*expr)->children = children;
3295  (*expr)->data = opdata;
3296 
3297  return SCIP_OKAY;
3298 }
3299 
3300 /** tries to convert a given (operator,operatordata) pair into a polynomial operator with corresponding data
3301  *
3302  * Does not do this for constants.
3303  * If conversion is not possible or operator is already polynomial, *op and *data are
3304  * left untouched.
3305  */
3306 static
3308  BMS_BLKMEM* blkmem, /**< block memory */
3309  SCIP_EXPROP* op, /**< pointer to expression operator */
3310  SCIP_EXPROPDATA* data, /**< pointer to expression data */
3311  int nchildren /**< number of children of operator */
3312  )
3313 {
3314  assert(blkmem != NULL);
3315  assert(op != NULL);
3316  assert(data != NULL);
3317 
3318  switch( *op )
3319  {
3320  case SCIP_EXPR_VARIDX:
3321  case SCIP_EXPR_PARAM:
3322  case SCIP_EXPR_CONST:
3323  break;
3324 
3325  case SCIP_EXPR_PLUS:
3326  {
3327  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3328  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3329  int childidx;
3330  SCIP_Real exponent;
3331 
3332  assert(nchildren == 2);
3333 
3334  /* create monomial for first child */
3335  childidx = 0;
3336  exponent = 1.0;
3337  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3338 
3339  /* create monomial for second child */
3340  childidx = 1;
3341  exponent = 1.0;
3342  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], 1.0, 1, &childidx, &exponent) );
3343 
3344  /* create polynomial for sum of children */
3345  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3346 
3347  *op = SCIP_EXPR_POLYNOMIAL;
3348  data->data = (void*)polynomialdata;
3349 
3350  break;
3351  }
3352 
3353  case SCIP_EXPR_MINUS:
3354  {
3355  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3356  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3357  int childidx;
3358  SCIP_Real exponent;
3359 
3360  assert(nchildren == 2);
3361 
3362  /* create monomial for first child */
3363  childidx = 0;
3364  exponent = 1.0;
3365  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3366 
3367  /* create monomial for second child */
3368  childidx = 1;
3369  exponent = 1.0;
3370  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], -1.0, 1, &childidx, &exponent) );
3371 
3372  /* create polynomial for difference of children */
3373  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3374 
3375  *op = SCIP_EXPR_POLYNOMIAL;
3376  data->data = (void*)polynomialdata;
3377 
3378  break;
3379  }
3380 
3381  case SCIP_EXPR_MUL:
3382  {
3383  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3384  SCIP_EXPRDATA_MONOMIAL* monomial;
3385  int childidx[2];
3386  SCIP_Real exponent[2];
3387 
3388  assert(nchildren == 2);
3389 
3390  /* create monomial for product of children */
3391  childidx[0] = 0;
3392  childidx[1] = 1;
3393  exponent[0] = 1.0;
3394  exponent[1] = 1.0;
3395  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3396 
3397  /* create polynomial */
3398  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3399 
3400  *op = SCIP_EXPR_POLYNOMIAL;
3401  data->data = (void*)polynomialdata;
3402 
3403  break;
3404  }
3405 
3406  case SCIP_EXPR_DIV:
3407  {
3408  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3409  SCIP_EXPRDATA_MONOMIAL* monomial;
3410  int childidx[2];
3411  SCIP_Real exponent[2];
3412 
3413  assert(nchildren == 2);
3414 
3415  /* create monomial for division of children */
3416  childidx[0] = 0;
3417  childidx[1] = 1;
3418  exponent[0] = 1.0;
3419  exponent[1] = -1.0;
3420  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3421 
3422  /* create polynomial */
3423  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3424 
3425  *op = SCIP_EXPR_POLYNOMIAL;
3426  data->data = (void*)polynomialdata;
3427 
3428  break;
3429  }
3430 
3431  case SCIP_EXPR_SQUARE:
3432  {
3433  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3434  SCIP_EXPRDATA_MONOMIAL* monomial;
3435  int childidx;
3436  SCIP_Real exponent;
3437 
3438  assert(nchildren == 1);
3439 
3440  /* create monomial for square of child */
3441  childidx = 0;
3442  exponent = 2.0;
3443  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3444 
3445  /* create polynomial */
3446  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3447 
3448  *op = SCIP_EXPR_POLYNOMIAL;
3449  data->data = (void*)polynomialdata;
3450 
3451  break;
3452  }
3453 
3454  case SCIP_EXPR_SQRT:
3455  {
3456  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3457  SCIP_EXPRDATA_MONOMIAL* monomial;
3458  int childidx;
3459  SCIP_Real exponent;
3460 
3461  assert(nchildren == 1);
3462 
3463  /* create monomial for square root of child */
3464  childidx = 0;
3465  exponent = 0.5;
3466  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3467 
3468  /* create polynomial */
3469  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3470 
3471  *op = SCIP_EXPR_POLYNOMIAL;
3472  data->data = (void*)polynomialdata;
3473 
3474  break;
3475  }
3476 
3477  case SCIP_EXPR_REALPOWER:
3478  {
3479  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3480  SCIP_EXPRDATA_MONOMIAL* monomial;
3481  int childidx;
3482 
3483  assert(nchildren == 1);
3484 
3485  /* convert to child0 to the power of exponent */
3486 
3487  /* create monomial for power of first child */
3488  childidx = 0;
3489  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &data->dbl) );
3490 
3491  /* create polynomial */
3492  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3493 
3494  *op = SCIP_EXPR_POLYNOMIAL;
3495  data->data = (void*)polynomialdata;
3496 
3497  break;
3498  }
3499 
3500  case SCIP_EXPR_SIGNPOWER:
3501  {
3502  SCIP_Real exponent;
3503 
3504  assert(nchildren == 1);
3505 
3506  /* check if exponent is an odd integer */
3507  exponent = data->dbl;
3508  if( EPSISINT(exponent, 0.0) && (int)exponent % 2 != 0 ) /*lint !e835*/
3509  {
3510  /* convert to child0 to the power of exponent, since sign is kept by taking power */
3511  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3512  SCIP_EXPRDATA_MONOMIAL* monomial;
3513  int childidx;
3514 
3515  /* create monomial for power of first child */
3516  childidx = 0;
3517  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3518 
3519  /* create polynomial */
3520  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3521 
3522  *op = SCIP_EXPR_POLYNOMIAL;
3523  data->data = (void*)polynomialdata;
3524  }
3525  /* if exponent is not an odd integer constant, then keep it as signpower expression */
3526  break;
3527  }
3528 
3529  case SCIP_EXPR_INTPOWER:
3530  {
3531  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3532  SCIP_EXPRDATA_MONOMIAL* monomial;
3533  int childidx;
3534  SCIP_Real exponent;
3535 
3536  assert(nchildren == 1);
3537 
3538  /* create monomial for power of child */
3539  childidx = 0;
3540  exponent = data->intval;
3541  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3542 
3543  /* create polynomial */
3544  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3545 
3546  *op = SCIP_EXPR_POLYNOMIAL;
3547  data->data = (void*)polynomialdata;
3548 
3549  break;
3550  }
3551 
3552  case SCIP_EXPR_EXP:
3553  case SCIP_EXPR_LOG:
3554  case SCIP_EXPR_SIN:
3555  case SCIP_EXPR_COS:
3556  case SCIP_EXPR_TAN:
3557  /* case SCIP_EXPR_ERF: */
3558  /* case SCIP_EXPR_ERFI: */
3559  case SCIP_EXPR_MIN:
3560  case SCIP_EXPR_MAX:
3561  case SCIP_EXPR_ABS:
3562  case SCIP_EXPR_SIGN:
3563  case SCIP_EXPR_USER:
3564  break;
3565 
3566  case SCIP_EXPR_SUM:
3567  {
3568  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3569  SCIP_EXPRDATA_MONOMIAL* monomial;
3570  int childidx;
3571  int i;
3572  SCIP_Real exponent;
3573 
3574  /* create empty polynomial */
3575  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, 0.0, FALSE) );
3576  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3577  assert(polynomialdata->monomialssize >= nchildren);
3578 
3579  /* add summands as monomials */
3580  childidx = 0;
3581  exponent = 1.0;
3582  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3583  for( i = 0; i < nchildren; ++i )
3584  {
3585  monomial->childidxs[0] = i;
3586  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3587  }
3588  SCIPexprFreeMonomial(blkmem, &monomial);
3589 
3590  *op = SCIP_EXPR_POLYNOMIAL;
3591  data->data = (void*)polynomialdata;
3592 
3593  break;
3594  }
3595 
3596  case SCIP_EXPR_PRODUCT:
3597  {
3598  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3599  SCIP_EXPRDATA_MONOMIAL* monomial;
3600  int childidx;
3601  int i;
3602  SCIP_Real exponent;
3603 
3604  /* create monomial */
3605  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 0, NULL, NULL) );
3606  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, nchildren) );
3607  exponent = 1.0;
3608  for( i = 0; i < nchildren; ++i )
3609  {
3610  childidx = i;
3611  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
3612  }
3613 
3614  /* create polynomial */
3615  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3616 
3617  *op = SCIP_EXPR_POLYNOMIAL;
3618  data->data = (void*)polynomialdata;
3619 
3620  break;
3621  }
3622 
3623  case SCIP_EXPR_LINEAR:
3624  {
3625  SCIP_Real* lineardata;
3626  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3627  SCIP_EXPRDATA_MONOMIAL* monomial;
3628  int childidx;
3629  int i;
3630  SCIP_Real exponent;
3631 
3632  /* get coefficients of linear term */
3633  lineardata = (SCIP_Real*)data->data;
3634  assert(lineardata != NULL);
3635 
3636  /* create polynomial consisting of constant from linear term */
3637  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, lineardata[nchildren], FALSE) );
3638  /* ensure space for linear coefficients */
3639  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3640  assert(polynomialdata->monomialssize >= nchildren);
3641 
3642  /* add summands as monomials */
3643  childidx = 0;
3644  exponent = 1.0;
3645  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3646  for( i = 0; i < nchildren; ++i )
3647  {
3648  monomial->coef = lineardata[i];
3649  monomial->childidxs[0] = i;
3650  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3651  }
3652  SCIPexprFreeMonomial(blkmem, &monomial);
3653 
3654  /* free linear expression data */
3655  exprFreeDataLinear(blkmem, nchildren, *data);
3656 
3657  *op = SCIP_EXPR_POLYNOMIAL;
3658  data->data = (void*)polynomialdata;
3659 
3660  break;
3661  }
3662 
3663  case SCIP_EXPR_QUADRATIC:
3664  {
3665  SCIP_EXPRDATA_QUADRATIC* quaddata;
3666  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3667  SCIP_EXPRDATA_MONOMIAL* squaremonomial;
3668  SCIP_EXPRDATA_MONOMIAL* bilinmonomial;
3669  SCIP_EXPRDATA_MONOMIAL* linmonomial;
3670  int childidx[2];
3671  SCIP_Real exponent[2];
3672  int i;
3673 
3674  /* get data of quadratic expression */
3675  quaddata = (SCIP_EXPRDATA_QUADRATIC*)data->data;
3676  assert(quaddata != NULL);
3677 
3678  /* create empty polynomial */
3679  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, quaddata->constant, FALSE) );
3680  /* ensure space for linear and quadratic terms */
3681  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, (quaddata->lincoefs != NULL ? nchildren : 0) + quaddata->nquadelems) );
3682  assert(polynomialdata->monomialssize >= quaddata->nquadelems);
3683 
3684  childidx[0] = 0;
3685  childidx[1] = 0;
3686 
3687  /* create monomial templates */
3688  exponent[0] = 2.0;
3689  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &squaremonomial, 1.0, 1, childidx, exponent) );
3690  exponent[0] = 1.0;
3691  exponent[1] = 1.0;
3692  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &bilinmonomial, 1.0, 2, childidx, exponent) );
3693  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &linmonomial, 1.0, 1, childidx, exponent) );
3694 
3695  /* add linear terms as monomials */
3696  if( quaddata->lincoefs != NULL )
3697  for( i = 0; i < nchildren; ++i )
3698  if( quaddata->lincoefs[i] != 0.0 )
3699  {
3700  linmonomial->childidxs[0] = i;
3701  linmonomial->coef = quaddata->lincoefs[i];
3702  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &linmonomial, TRUE) );
3703  }
3704 
3705  /* add quadratic terms as monomials */
3706  for( i = 0; i < quaddata->nquadelems; ++i )
3707  {
3708  if( quaddata->quadelems[i].idx1 == quaddata->quadelems[i].idx2 )
3709  {
3710  squaremonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3711  squaremonomial->coef = quaddata->quadelems[i].coef;
3712  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &squaremonomial, TRUE) );
3713  }
3714  else
3715  {
3716  bilinmonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3717  bilinmonomial->childidxs[1] = quaddata->quadelems[i].idx2;
3718  bilinmonomial->coef = quaddata->quadelems[i].coef;
3719  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &bilinmonomial, TRUE) );
3720  }
3721  }
3722  SCIPexprFreeMonomial(blkmem, &squaremonomial);
3723  SCIPexprFreeMonomial(blkmem, &bilinmonomial);
3724  SCIPexprFreeMonomial(blkmem, &linmonomial);
3725 
3726  /* free quadratic expression data */
3727  exprFreeDataQuadratic(blkmem, nchildren, *data);
3728 
3729  *op = SCIP_EXPR_POLYNOMIAL;
3730  data->data = (void*)polynomialdata;
3731 
3732  break;
3733  }
3734 
3735  case SCIP_EXPR_POLYNOMIAL:
3736  case SCIP_EXPR_LAST:
3737  break;
3738  } /*lint !e788*/
3739 
3740  return SCIP_OKAY;
3741 }
3742 
3743 /** converts polynomial expression back into simpler expression, if possible */
3744 static
3746  BMS_BLKMEM* blkmem, /**< block memory data structure */
3747  SCIP_EXPROP* op, /**< pointer to expression operator */
3748  SCIP_EXPROPDATA* data, /**< pointer to expression data holding polynomial data */
3749  int nchildren, /**< number of children of operator */
3750  void** children /**< children array */
3751  )
3752 {
3753  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3754  SCIP_EXPRDATA_MONOMIAL* monomial;
3755  int maxdegree;
3756  int nlinmonomials;
3757  int i;
3758  int j;
3759 
3760  assert(blkmem != NULL);
3761  assert(op != NULL);
3762  assert(*op == SCIP_EXPR_POLYNOMIAL);
3763  assert(data != NULL);
3764  assert(children != NULL || nchildren == 0);
3765 
3766  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)data->data;
3767  assert(polynomialdata != NULL);
3768 
3769  /* make sure monomials are sorted and merged */
3770  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
3771 
3772  /* if no monomials, then leave as it is */
3773  if( polynomialdata->nmonomials == 0 )
3774  return SCIP_OKAY;
3775 
3776  /* check maximal degree of polynomial only - not considering children expressions
3777  * check number of linear monomials */
3778  maxdegree = 0;
3779  nlinmonomials = 0;
3780  for( i = 0; i < polynomialdata->nmonomials; ++i )
3781  {
3782  int monomialdegree;
3783 
3784  monomial = polynomialdata->monomials[i];
3785  assert(monomial != NULL);
3786 
3787  monomialdegree = 0;
3788  for(j = 0; j < monomial->nfactors; ++j )
3789  {
3790  if( !EPSISINT(monomial->exponents[j], 0.0) || monomial->exponents[j] < 0.0 ) /*lint !e835*/
3791  {
3792  monomialdegree = SCIP_EXPR_DEGREEINFINITY;
3793  break;
3794  }
3795 
3796  monomialdegree += (int)EPSROUND(monomial->exponents[j], 0.0); /*lint !e835*/
3797  }
3798 
3799  if( monomialdegree == SCIP_EXPR_DEGREEINFINITY )
3800  {
3801  maxdegree = SCIP_EXPR_DEGREEINFINITY;
3802  break;
3803  }
3804 
3805  if( monomialdegree == 1 )
3806  ++nlinmonomials;
3807 
3808  if( monomialdegree > maxdegree )
3809  maxdegree = monomialdegree;
3810  }
3811  assert(maxdegree > 0 );
3812 
3813  if( maxdegree == 1 )
3814  {
3815  /* polynomial is a linear expression in children */
3816 
3817  /* polynomial simplification and monomial merging should ensure that monomial i corresponds to child i and that there are not unused children */
3818  assert(polynomialdata->nmonomials == nchildren);
3819  assert(polynomialdata->nmonomials == nlinmonomials);
3820 
3821  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3822  {
3823  /* polynomial is addition of two expressions, so turn into SCIP_EXPR_PLUS */
3824  assert(polynomialdata->monomials[0]->nfactors == 1);
3825  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3826  assert(polynomialdata->monomials[1]->nfactors == 1);
3827  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3828 
3829  polynomialdataFree(blkmem, &polynomialdata);
3830  data->data = NULL;
3831 
3832  /* change operator type to PLUS */
3833  *op = SCIP_EXPR_PLUS;
3834 
3835  return SCIP_OKAY;
3836  }
3837 
3838  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == -1.0 )
3839  {
3840  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3841  assert(polynomialdata->monomials[0]->nfactors == 1);
3842  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3843  assert(polynomialdata->monomials[1]->nfactors == 1);
3844  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3845 
3846  polynomialdataFree(blkmem, &polynomialdata);
3847  data->data = NULL;
3848 
3849  /* change operator type to MINUS */
3850  *op = SCIP_EXPR_MINUS;
3851 
3852  return SCIP_OKAY;
3853  }
3854 
3855  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == -1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3856  {
3857  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3858  void* tmp;
3859 
3860  assert(polynomialdata->monomials[0]->nfactors == 1);
3861  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3862  assert(polynomialdata->monomials[1]->nfactors == 1);
3863  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3864 
3865  polynomialdataFree(blkmem, &polynomialdata);
3866  data->data = NULL;
3867 
3868  /* swap children */
3869  tmp = children[1]; /*lint !e613*/
3870  children[1] = children[0]; /*lint !e613*/
3871  children[0] = tmp; /*lint !e613*/
3872 
3873  /* change operator type to MINUS */
3874  *op = SCIP_EXPR_MINUS;
3875 
3876  return SCIP_OKAY;
3877  }
3878 
3879  if( polynomialdata->constant == 0.0 )
3880  {
3881  /* check if all monomials have coefficient 1.0 */
3882  for( i = 0; i < polynomialdata->nmonomials; ++i )
3883  if( polynomialdata->monomials[i]->coef != 1.0 )
3884  break;
3885 
3886  if( i == polynomialdata->nmonomials )
3887  {
3888  /* polynomial is sum of children, so turn into SCIP_EXPR_SUM */
3889 
3890  polynomialdataFree(blkmem, &polynomialdata);
3891  data->data = NULL;
3892 
3893  /* change operator type to MINUS */
3894  *op = SCIP_EXPR_SUM;
3895 
3896  return SCIP_OKAY;
3897  }
3898  }
3899 
3900  /* turn polynomial into linear expression */
3901  {
3902  SCIP_Real* lindata;
3903 
3904  /* monomial merging should ensure that each child appears in at most one monomial,
3905  * that monomials are ordered according to the child index, and that constant monomials have been removed
3906  */
3907 
3908  /* setup data of linear expression */
3909  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &lindata, polynomialdata->nmonomials + 1) );
3910 
3911  for( i = 0; i < polynomialdata->nmonomials; ++i )
3912  {
3913  assert(polynomialdata->monomials[i]->childidxs[0] == i);
3914  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3915  lindata[i] = polynomialdata->monomials[i]->coef; /*lint !e644*/
3916  }
3917  lindata[i] = polynomialdata->constant;
3918 
3919  polynomialdataFree(blkmem, &polynomialdata);
3920  *op = SCIP_EXPR_LINEAR;
3921  data->data = (void*)lindata;
3922 
3923  return SCIP_OKAY;
3924  }
3925  }
3926 
3927  if( maxdegree == 2 && (polynomialdata->nmonomials > 1 || polynomialdata->constant != 0.0 || polynomialdata->monomials[0]->coef != 1.0) )
3928  {
3929  /* polynomial is quadratic expression with more than one summand or with a constant or a square or bilinear term with coefficient != 1.0, so turn into SCIP_EXPR_QUADRATIC */
3930  SCIP_EXPRDATA_QUADRATIC* quaddata;
3931  int quadelemidx;
3932 
3933  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &quaddata) );
3934  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->quadelems, polynomialdata->nmonomials - nlinmonomials) );
3935  quaddata->nquadelems = polynomialdata->nmonomials - nlinmonomials;
3936  quaddata->constant = polynomialdata->constant;
3937  quaddata->sorted = FALSE; /* quadratic data is sorted different than polynomials */
3938 
3939  if( nlinmonomials > 0 )
3940  {
3941  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->lincoefs, nchildren) );
3942  BMSclearMemoryArray(quaddata->lincoefs, nchildren);
3943  }
3944  else
3945  quaddata->lincoefs = NULL;
3946 
3947  quadelemidx = 0;
3948  for( i = 0; i < polynomialdata->nmonomials; ++i )
3949  {
3950  assert(polynomialdata->monomials[i]->nfactors == 1 || polynomialdata->monomials[i]->nfactors == 2);
3951  if( polynomialdata->monomials[i]->nfactors == 1 )
3952  {
3953  if( polynomialdata->monomials[i]->exponents[0] == 1.0 )
3954  {
3955  /* monomial is a linear term */
3956  assert(quaddata->lincoefs != NULL);
3957  quaddata->lincoefs[polynomialdata->monomials[i]->childidxs[0]] += polynomialdata->monomials[i]->coef;
3958  }
3959  else
3960  {
3961  /* monomial should be a square term */
3962  assert(polynomialdata->monomials[i]->exponents[0] == 2.0);
3963  assert(quadelemidx < quaddata->nquadelems);
3964  quaddata->quadelems[quadelemidx].idx1 = polynomialdata->monomials[i]->childidxs[0];
3965  quaddata->quadelems[quadelemidx].idx2 = polynomialdata->monomials[i]->childidxs[0];
3966  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3967  ++quadelemidx;
3968  }
3969  }
3970  else
3971  {
3972  /* monomial should be a bilinear term */
3973  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3974  assert(polynomialdata->monomials[i]->exponents[1] == 1.0);
3975  assert(quadelemidx < quaddata->nquadelems);
3976  quaddata->quadelems[quadelemidx].idx1 = MIN(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3977  quaddata->quadelems[quadelemidx].idx2 = MAX(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3978  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3979  ++quadelemidx;
3980  }
3981  }
3982  assert(quadelemidx == quaddata->nquadelems);
3983 
3984  polynomialdataFree(blkmem, &polynomialdata);
3985 
3986  *op = SCIP_EXPR_QUADRATIC;
3987  data->data = (void*)quaddata;
3988 
3989  return SCIP_OKAY;
3990  }
3991 
3992  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 1 && polynomialdata->monomials[0]->coef == 1.0 )
3993  {
3994  /* polynomial is product of children */
3995  monomial = polynomialdata->monomials[0];
3996  assert(monomial->nfactors == nchildren);
3997 
3998  if( monomial->nfactors == 1 )
3999  {
4000  /* polynomial is x^k for some k */
4001  assert(monomial->exponents[0] != 1.0); /* should have been handled before */
4002  assert(monomial->childidxs[0] == 0);
4003 
4004  if( monomial->exponents[0] == 2.0 )
4005  {
4006  /* polynomial is x^2, so turn into SCIP_EXPR_SQUARE */
4007 
4008  polynomialdataFree(blkmem, &polynomialdata);
4009  data->data = NULL;
4010 
4011  *op = SCIP_EXPR_SQUARE;
4012 
4013  return SCIP_OKAY;
4014  }
4015 
4016  if( EPSISINT(monomial->exponents[0], 0.0) ) /*lint !e835*/
4017  {
4018  /* k is an integer, so turn into SCIP_EXPR_INTPOWER */
4019  int exponent;
4020 
4021  exponent = (int)EPSROUND(monomial->exponents[0], 0.0); /*lint !e835*/
4022 
4023  polynomialdataFree(blkmem, &polynomialdata);
4024 
4025  *op = SCIP_EXPR_INTPOWER;
4026  data->intval = exponent;
4027 
4028  return SCIP_OKAY;
4029  }
4030 
4031  if( monomial->exponents[0] == 0.5 )
4032  {
4033  /* polynomial is sqrt(x), so turn into SCIP_EXPR_SQRT */
4034 
4035  polynomialdataFree(blkmem, &polynomialdata);
4036  data->data = NULL;
4037 
4038  *op = SCIP_EXPR_SQRT;
4039 
4040  return SCIP_OKAY;
4041  }
4042 
4043  {
4044  /* polynomial is x^a with a some real number, so turn into SCIP_EXPR_REALPOWER */
4045  SCIP_Real exponent;
4046 
4047  exponent = monomial->exponents[0];
4048 
4049  polynomialdataFree(blkmem, &polynomialdata);
4050 
4051  *op = SCIP_EXPR_REALPOWER;
4052  data->dbl = exponent;
4053 
4054  return SCIP_OKAY;
4055  }
4056  }
4057 
4058  if( maxdegree == 2 && monomial->nfactors == 2 )
4059  {
4060  /* polynomial is product of two children, so turn into SCIP_EXPR_MUL */
4061  assert(monomial->exponents[0] == 1.0);
4062  assert(monomial->exponents[1] == 1.0);
4063 
4064  polynomialdataFree(blkmem, &polynomialdata);
4065  data->data = NULL;
4066 
4067  *op = SCIP_EXPR_MUL;
4068 
4069  return SCIP_OKAY;
4070  }
4071 
4072  if( maxdegree == monomial->nfactors )
4073  {
4074  /* polynomial is a product of n children, so turn into SCIP_EXPR_PRODUCT */
4075 
4076  polynomialdataFree(blkmem, &polynomialdata);
4077  data->data = NULL;
4078 
4079  *op = SCIP_EXPR_PRODUCT;
4080 
4081  return SCIP_OKAY;
4082  }
4083 
4084  if( monomial->nfactors == 2 && monomial->exponents[0] == 1.0 && monomial->exponents[1] == -1.0 )
4085  {
4086  /* polynomial is x/y, so turn into SCIP_EXPR_DIV */
4087  assert(monomial->childidxs[0] == 0);
4088  assert(monomial->childidxs[1] == 1);
4089 
4090  polynomialdataFree(blkmem, &polynomialdata);
4091  data->data = NULL;
4092 
4093  *op = SCIP_EXPR_DIV;
4094 
4095  return SCIP_OKAY;
4096  }
4097 
4098  if( monomial->nfactors == 2 && monomial->exponents[0] == -1.0 && monomial->exponents[1] == 1.0 )
4099  {
4100  /* polynomial is y/x, so turn into SCIP_EXPR_DIV */
4101  void* tmp;
4102 
4103  assert(monomial->childidxs[0] == 0);
4104  assert(monomial->childidxs[1] == 1);
4105 
4106  polynomialdataFree(blkmem, &polynomialdata);
4107  data->data = NULL;
4108 
4109  /* swap children */
4110  tmp = children[1]; /*lint !e613*/
4111  children[1] = children[0]; /*lint !e613*/
4112  children[0] = tmp; /*lint !e613*/
4113 
4114  *op = SCIP_EXPR_DIV;
4115 
4116  return SCIP_OKAY;
4117  }
4118  }
4119 
4120  return SCIP_OKAY;
4121 }
4122 
4123 /** adds copies of expressions to the array of children of a sum, product, linear, quadratic, or polynomial expression
4124  *
4125  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
4126  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
4127  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
4128  */
4129 static
4131  BMS_BLKMEM* blkmem, /**< block memory */
4132  SCIP_EXPR* expr, /**< quadratic or polynomial expression */
4133  int nexprs, /**< number of expressions to add */
4134  SCIP_EXPR** exprs, /**< expressions to add */
4135  SCIP_Bool comparechildren, /**< whether to compare expressions with already existing children (no effect for sum and product) */
4136  SCIP_Real eps, /**< which epsilon to use when comparing expressions */
4137  int* childmap /**< array where to store mapping of indices from exprs to children array in expr, or NULL if not of interest */
4138  )
4139 {
4140  int i;
4141 
4142  assert(blkmem != NULL);
4143  assert(expr != NULL);
4144  assert(expr->op == SCIP_EXPR_SUM || expr->op == SCIP_EXPR_PRODUCT || expr->op == SCIP_EXPR_LINEAR || expr->op == SCIP_EXPR_QUADRATIC || expr->op == SCIP_EXPR_POLYNOMIAL);
4145  assert(exprs != NULL || nexprs == 0);
4146 
4147  if( nexprs == 0 )
4148  return SCIP_OKAY;
4149 
4150  switch( expr->op )
4151  {
4152  case SCIP_EXPR_SUM:
4153  case SCIP_EXPR_PRODUCT:
4154  {
4155  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4156  for( i = 0; i < nexprs; ++i )
4157  {
4158  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren + i], exprs[i]) ); /*lint !e613*/
4159  if( childmap != NULL )
4160  childmap[i] = expr->nchildren + i;
4161  }
4162  expr->nchildren += nexprs;
4163 
4164  break;
4165  }
4166 
4167  case SCIP_EXPR_LINEAR:
4168  case SCIP_EXPR_QUADRATIC:
4169  case SCIP_EXPR_POLYNOMIAL:
4170  {
4171  int j;
4172  int orignchildren;
4173  SCIP_Bool existsalready;
4174 
4175  orignchildren = expr->nchildren;
4176  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4177 
4178  for( i = 0; i < nexprs; ++i )
4179  {
4180  existsalready = FALSE;
4181  if( comparechildren )
4182  for( j = 0; j < orignchildren; ++j )
4183  /* during simplification of polynomials, their may be NULL's in children array */
4184  if( expr->children[j] != NULL && SCIPexprAreEqual(expr->children[j], exprs[i], eps) ) /*lint !e613*/
4185  {
4186  existsalready = TRUE;
4187  break;
4188  }
4189 
4190  if( !existsalready )
4191  {
4192  /* add copy of exprs[j] to children array */
4193  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren], exprs[i]) ); /*lint !e613*/
4194  if( childmap != NULL )
4195  childmap[i] = expr->nchildren;
4196  ++expr->nchildren;
4197  }
4198  else
4199  {
4200  if( childmap != NULL )
4201  childmap[i] = j; /*lint !e644*/
4202  if( expr->op == SCIP_EXPR_LINEAR )
4203  {
4204  /* if linear expression, increase coefficient by 1.0 */
4205  ((SCIP_Real*)expr->data.data)[j] += 1.0;
4206  }
4207  }
4208  }
4209 
4210  /* shrink children array to actually used size */
4211  assert(comparechildren || expr->nchildren == orignchildren + nexprs);
4212  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, orignchildren + nexprs, expr->nchildren) );
4213 
4214  if( expr->op == SCIP_EXPR_LINEAR && expr->nchildren > orignchildren )
4215  {
4216  /* if linear expression, then add 1.0 coefficients for new expressions */
4217  SCIP_Real* data;
4218 
4219  data = (SCIP_Real*)expr->data.data;
4220  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, expr->nchildren + 1) );
4221  data[expr->nchildren] = data[orignchildren]; /* move constant from old end to new end */
4222  for( i = orignchildren; i < expr->nchildren; ++i )
4223  data[i] = 1.0;
4224  expr->data.data = (void*)data;
4225  }
4226  else if( expr->op == SCIP_EXPR_QUADRATIC && expr->nchildren > orignchildren )
4227  {
4228  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
4230 
4231  data = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
4232  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, expr->nchildren) );
4233  BMSclearMemoryArray(&data->lincoefs[orignchildren], expr->nchildren - orignchildren); /*lint !e866*/
4234  }
4235 
4236  break;
4237  }
4238 
4239  default:
4240  SCIPerrorMessage("exprsimplifyAddChildren cannot be called for operand %d\n", expr->op);
4241  return SCIP_INVALIDDATA;
4242  } /*lint !e788*/
4243 
4244  return SCIP_OKAY;
4245 }
4246 
4247 /** converts expressions into polynomials, where possible and obvious */
4248 static
4250  BMS_BLKMEM* blkmem, /**< block memory data structure */
4251  SCIP_EXPR* expr /**< expression to convert */
4252  )
4253 {
4254  int i;
4255 
4256  assert(expr != NULL);
4257 
4258  for( i = 0; i < expr->nchildren; ++i )
4259  {
4261  }
4262 
4263  SCIP_CALL( exprConvertToPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren) );
4264 
4265  return SCIP_OKAY;
4266 }
4267 
4268 /** removes duplicate children in a polynomial expression
4269  *
4270  * Leaves NULL's in children array.
4271  */
4272 static
4274  BMS_BLKMEM* blkmem, /**< block memory data structure */
4275  SCIP_EXPR* expr, /**< expression */
4276  SCIP_Real eps /**< threshold for zero */
4277  )
4278 {
4279  SCIP_Bool foundduplicates;
4280  int* childmap;
4281  int i;
4282  int j;
4283 
4284  assert(blkmem != NULL);
4285  assert(expr != NULL);
4286  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4287 
4288  if( expr->nchildren == 0 )
4289  return SCIP_OKAY;
4290 
4291  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4292 
4293  foundduplicates = FALSE;
4294  for( i = 0; i < expr->nchildren; ++i )
4295  {
4296  if( expr->children[i] == NULL )
4297  continue;
4298  childmap[i] = i; /*lint !e644*/
4299 
4300  for( j = i+1; j < expr->nchildren; ++j )
4301  {
4302  if( expr->children[j] == NULL )
4303  continue;
4304 
4305  if( SCIPexprAreEqual(expr->children[i], expr->children[j], eps) )
4306  {
4307  /* forget about expr j and remember that is to be replaced by i */
4308  SCIPexprFreeDeep(blkmem, &expr->children[j]);
4309  childmap[j] = i;
4310  foundduplicates = TRUE;
4311  }
4312  }
4313  }
4314 
4315  /* apply childmap to monomials */
4316  if( foundduplicates )
4318 
4319  /* free childmap */
4320  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4321 
4322  return SCIP_OKAY;
4323 }
4324 
4325 /** eliminates NULL's in children array and shrinks it to actual size */
4326 static
4328  BMS_BLKMEM* blkmem, /**< block memory data structure */
4329  SCIP_EXPR* expr /**< expression */
4330  )
4331 {
4332  int* childmap;
4333  int lastnonnull;
4334  int i;
4335 
4336  assert(blkmem != NULL);
4337  assert(expr != NULL);
4338  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4339 
4340  if( expr->nchildren == 0 )
4341  return SCIP_OKAY;
4342 
4343  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4344 
4345  /* close gaps in children array */
4346  lastnonnull = expr->nchildren-1;
4347  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4348  --lastnonnull;
4349  for( i = 0; i <= lastnonnull; ++i )
4350  {
4351  if( expr->children[i] != NULL )
4352  {
4353  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
4354  continue;
4355  }
4356  assert(expr->children[lastnonnull] != NULL);
4357 
4358  /* move child at lastnonnull to position i */
4359  expr->children[i] = expr->children[lastnonnull];
4360  expr->children[lastnonnull] = NULL;
4361  childmap[lastnonnull] = i;
4362 
4363  /* update lastnonnull */
4364  --lastnonnull;
4365  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4366  --lastnonnull;
4367  }
4368  assert(i > lastnonnull);
4369 
4370  /* apply childmap to monomials */
4371  if( lastnonnull < expr->nchildren-1 )
4373 
4374  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4375 
4376  /* shrink children array */
4377  if( lastnonnull >= 0 )
4378  {
4379  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, lastnonnull+1) );
4380  expr->nchildren = lastnonnull+1;
4381  }
4382  else
4383  {
4384  BMSfreeBlockMemoryArray(blkmem, &expr->children, expr->nchildren);
4385  expr->nchildren = 0;
4386  }
4387 
4388  return SCIP_OKAY;
4389 }
4390 
4391 /** checks which children are still in use and frees those which are not */
4392 static
4394  BMS_BLKMEM* blkmem, /**< block memory data structure */
4395  SCIP_EXPR* expr /**< polynomial expression */
4396  )
4397 {
4398  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4399  SCIP_EXPRDATA_MONOMIAL* monomial;
4400  SCIP_Bool* childinuse;
4401  int i;
4402  int j;
4403 
4404  assert(blkmem != NULL);
4405  assert(expr != NULL);
4406 
4407  if( expr->nchildren == 0 )
4408  return SCIP_OKAY;
4409 
4410  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4411  assert(polynomialdata != NULL);
4412 
4413  /* check which children are still in use */
4414  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, expr->nchildren) );
4415  BMSclearMemoryArray(childinuse, expr->nchildren); /*lint !e644*/
4416  for( i = 0; i < polynomialdata->nmonomials; ++i )
4417  {
4418  monomial = polynomialdata->monomials[i];
4419  assert(monomial != NULL);
4420 
4421  for( j = 0; j < monomial->nfactors; ++j )
4422  {
4423  assert(monomial->childidxs[j] >= 0);
4424  assert(monomial->childidxs[j] < expr->nchildren);
4425  childinuse[monomial->childidxs[j]] = TRUE;
4426  }
4427  }
4428 
4429  /* free children that are not used in any monomial */
4430  for( i = 0; i < expr->nchildren; ++i )
4431  if( expr->children[i] != NULL && !childinuse[i] )
4432  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4433 
4434  BMSfreeBlockMemoryArray(blkmem, &childinuse, expr->nchildren);
4435 
4436  return SCIP_OKAY;
4437 }
4438 
4439 /** flattens polynomials in polynomials, check for constants in non-polynomials expressions
4440  *
4441  * exprsimplifyConvertToPolynomials should have been called before to eliminate simple polynomial operands.
4442  */
4443 static
4445  BMS_BLKMEM* blkmem, /**< block memory data structure */
4446  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4447  SCIP_EXPR* expr, /**< expression */
4448  SCIP_Real eps, /**< threshold, under which values are treat as 0 */
4449  int maxexpansionexponent/**< maximal exponent for which we still expand non-monomial polynomials */
4450  )
4451 {
4452  int i;
4453 
4454  assert(expr != NULL);
4455 
4456  for( i = 0; i < expr->nchildren; ++i )
4457  {
4458  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr->children[i], eps, maxexpansionexponent) );
4459  }
4460 
4461  switch( SCIPexprGetOperator(expr) )
4462  {
4463  case SCIP_EXPR_VARIDX:
4464  case SCIP_EXPR_CONST:
4465  case SCIP_EXPR_PARAM:
4466  case SCIP_EXPR_PLUS:
4467  case SCIP_EXPR_MINUS:
4468  case SCIP_EXPR_MUL:
4469  case SCIP_EXPR_DIV:
4470  case SCIP_EXPR_SQUARE:
4471  case SCIP_EXPR_SQRT:
4472  case SCIP_EXPR_INTPOWER:
4473  case SCIP_EXPR_REALPOWER:
4474  case SCIP_EXPR_SIGNPOWER:
4475  break;
4476 
4477  case SCIP_EXPR_EXP:
4478  case SCIP_EXPR_LOG:
4479  case SCIP_EXPR_SIN:
4480  case SCIP_EXPR_COS:
4481  case SCIP_EXPR_TAN:
4482  /* case SCIP_EXPR_ERF: */
4483  /* case SCIP_EXPR_ERFI: */
4484  case SCIP_EXPR_ABS:
4485  case SCIP_EXPR_SIGN:
4486  {
4487  /* check if argument is a constant */
4488  if( (expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) ||
4489  expr->children[0]->op == SCIP_EXPR_CONST )
4490  {
4491  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4492  SCIP_Real exprval;
4493 
4494  /* since child0 has no children and it's polynomial was flattened, it should have no monomials */
4495  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4496 
4497  /* evaluate expression in constant polynomial */
4498  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4499 
4500  /* create polynomial */
4501  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4502 
4503  expr->op = SCIP_EXPR_POLYNOMIAL;
4504  expr->data.data = (void*)polynomialdata;
4505 
4506  /* forget child */
4507  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4508  BMSfreeBlockMemoryArray(blkmem, &expr->children, 1);
4509  expr->nchildren = 0;
4510  }
4511 
4512  break;
4513  }
4514 
4515  case SCIP_EXPR_MIN:
4516  case SCIP_EXPR_MAX:
4517  {
4518  /* check if both arguments are constants */
4519  if( ((expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) || expr->children[0]->op == SCIP_EXPR_CONST) &&
4520  ((expr->children[1]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[1]) == 0) || expr->children[1]->op == SCIP_EXPR_CONST) )
4521  {
4522  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4523  SCIP_Real exprval;
4524 
4525  /* since children have no children and it's polynomial was flattened, it should have no monomials */
4526  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4527  assert(expr->children[1]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[1]) == 0);
4528 
4529  /* evaluate expression in constants */
4530  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4531 
4532  /* create polynomial */
4533  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4534 
4535  expr->op = SCIP_EXPR_POLYNOMIAL;
4536  expr->data.data = (void*)polynomialdata;
4537 
4538  /* forget children */
4539  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4540  SCIPexprFreeDeep(blkmem, &expr->children[1]);
4541  BMSfreeBlockMemoryArray(blkmem, &expr->children, 2);
4542  expr->nchildren = 0;
4543  }
4544 
4545  break;
4546  }
4547 
4548  case SCIP_EXPR_SUM:
4549  case SCIP_EXPR_PRODUCT:
4550  case SCIP_EXPR_LINEAR:
4551  case SCIP_EXPR_QUADRATIC:
4552  case SCIP_EXPR_USER:
4553  break;
4554 
4555  case SCIP_EXPR_POLYNOMIAL:
4556  {
4557  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4558  SCIP_EXPRDATA_MONOMIAL* monomial;
4559  SCIP_Bool removechild;
4560  int* childmap;
4561  int childmapsize;
4562  int j;
4563 
4564  /* simplify current polynomial */
4566  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4567 
4568  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4569  assert(polynomialdata != NULL);
4570 
4571  SCIPdebugMessage("expand factors in expression ");
4572  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4573  SCIPdebugPrintf("\n");
4574 
4575  childmap = NULL;
4576  childmapsize = 0;
4577 
4578  /* resolve children that are constants
4579  * we do this first, because it reduces the degree and number of factors in the monomials,
4580  * thereby allowing some expansions of polynomials that may not be possible otherwise, e.g., turning c0*c1 with c0=quadratic and c1=constant into a single monomial
4581  */
4582  for( i = 0; i < expr->nchildren; ++i )
4583  {
4584  if( expr->children[i] == NULL )
4585  continue;
4586 
4587  if( SCIPexprGetOperator(expr->children[i]) != SCIP_EXPR_CONST )
4588  continue;
4589 
4590  removechild = TRUE; /* we intend to delete children[i] */
4591 
4592  if( childmapsize < expr->children[i]->nchildren )
4593  {
4594  int newsize;
4595 
4596  newsize = calcGrowSize(expr->children[i]->nchildren);
4597  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4598  childmapsize = newsize;
4599  }
4600 
4601  /* put constant of child i into every monomial where child i is used */
4602  for( j = 0; j < polynomialdata->nmonomials; ++j )
4603  {
4604  int factorpos;
4605  SCIP_Bool success;
4606 
4607  monomial = polynomialdata->monomials[j];
4608  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4609  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4610 
4611  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4612  {
4613  assert(factorpos >= 0);
4614  assert(factorpos < monomial->nfactors);
4615  /* assert that factors have been merged */
4616  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4617  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4618 
4619  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4620  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4621  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4622 
4623  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && SCIPexprGetOpReal(expr->children[i]) < 0.0 ) /*lint !e835*/
4624  {
4625  /* if constant is negative and our exponent is not integer, then cannot do expansion */
4626  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n",
4627  SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4628  success = FALSE;
4629  }
4630  else
4631  {
4632  monomial->coef *= pow(SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4633 
4634  /* move last factor to position factorpos */
4635  if( factorpos < monomial->nfactors-1 )
4636  {
4637  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
4638  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
4639  }
4640  --monomial->nfactors;
4641  monomial->sorted = FALSE;
4642  polynomialdata->sorted = FALSE;
4643 
4644  success = TRUE;
4645  }
4646 
4647  if( !success )
4648  removechild = FALSE;
4649  }
4650  }
4651 
4652  /* forget about child i, if it is not used anymore */
4653  if( removechild )
4654  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4655 
4656  /* simplify current polynomial again */
4657  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4658  }
4659 
4660  /* try to resolve children that are polynomials itself */
4661  for( i = 0; i < expr->nchildren; ++i )
4662  {
4663  if( expr->children[i] == NULL )
4664  continue;
4665 
4667  continue;
4668 
4669  removechild = TRUE; /* we intend to delete children[i] */
4670 
4671  if( childmapsize < expr->children[i]->nchildren )
4672  {
4673  int newsize;
4674 
4675  newsize = calcGrowSize(expr->children[i]->nchildren);
4676  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4677  childmapsize = newsize;
4678  }
4679 
4680  /* add children of child i */
4681  SCIP_CALL( exprsimplifyAddChildren(blkmem, expr, expr->children[i]->nchildren, expr->children[i]->children, TRUE, eps, childmap) );
4682 
4683  /* put polynomial of child i into every monomial where child i is used */
4684  j = 0;
4685  while( j < polynomialdata->nmonomials )
4686  {
4687  int factorpos;
4688  SCIP_Bool success;
4689 
4690  monomial = polynomialdata->monomials[j];
4691  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4692  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4693 
4694  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4695  {
4696  assert(factorpos >= 0);
4697  assert(factorpos < monomial->nfactors);
4698  /* assert that factors have been merged */
4699  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4700  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4701 
4702  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4703  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4704  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4705 
4706  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
4707  (SCIP_EXPRDATA_POLYNOMIAL*)expr->children[i]->data.data, childmap, maxexpansionexponent, &success) );
4708 
4709  if( !success )
4710  {
4711  removechild = FALSE;
4712  ++j;
4713  }
4714  }
4715  else
4716  ++j;
4717 
4718  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
4719  * we thus repeat with index j, if a factor was successfully expanded
4720  */
4721  }
4722 
4723  /* forget about child i, if it is not used anymore */
4724  if( removechild )
4725  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4726 
4727  /* simplify current polynomial again */
4728  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4729  }
4730 
4731  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
4732 
4733  /* free children that are not in use anymore */
4735 
4736  /* remove NULLs from children array */
4738 
4739  /* if no children left, then it's a constant polynomial -> change into EXPR_CONST */
4740  if( expr->nchildren == 0 )
4741  {
4742  SCIP_Real val;
4743 
4744  /* if no children, then it should also have no monomials */
4745  assert(polynomialdata->nmonomials == 0);
4746 
4747  val = polynomialdata->constant;
4748  polynomialdataFree(blkmem, &polynomialdata);
4749 
4750  expr->op = SCIP_EXPR_CONST;
4751  expr->data.dbl = val;
4752  }
4753 
4754  SCIPdebugMessage("-> ");
4755  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4756  SCIPdebugPrintf("\n");
4757 
4758  break;
4759  }
4760 
4761  case SCIP_EXPR_LAST:
4762  break;
4763  } /*lint !e788*/
4764 
4765  return SCIP_OKAY;
4766 }
4767 
4768 /** separates linear monomials from an expression, if it is a polynomial expression
4769  *
4770  * Separates only those linear terms whose variable is not used otherwise in the expression.
4771  */
4772 static
4774  BMS_BLKMEM* blkmem, /**< block memory data structure */
4775  SCIP_EXPR* expr, /**< expression */
4776  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
4777  int nvars, /**< number of variables in expression */
4778  int* nlinvars, /**< buffer to store number of linear variables in linear part */
4779  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part */
4780  SCIP_Real* lincoefs /**< array to store coefficients of linear part */
4781  )
4782 {
4783  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4784  SCIP_EXPRDATA_MONOMIAL* monomial;
4785  int* varsusage;
4786  int* childusage;
4787  int childidx;
4788  int i;
4789  int j;
4790 
4791  assert(blkmem != NULL);
4792  assert(expr != NULL);
4793  assert(nlinvars != NULL);
4794  assert(linidxs != NULL);
4795  assert(lincoefs != NULL);
4796 
4797  *nlinvars = 0;
4798 
4800  return SCIP_OKAY;
4801 
4802  if( SCIPexprGetNChildren(expr) == 0 )
4803  return SCIP_OKAY;
4804 
4805  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4806  assert(polynomialdata != NULL);
4807 
4808  /* get variable usage */
4809  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &varsusage, nvars) );
4810  BMSclearMemoryArray(varsusage, nvars); /*lint !e644*/
4811  SCIPexprGetVarsUsage(expr, varsusage);
4812 
4813  /* get child usage: how often each child is used in the polynomial */
4814  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childusage, expr->nchildren) );
4815  BMSclearMemoryArray(childusage, expr->nchildren); /*lint !e644*/
4816  for( i = 0; i < polynomialdata->nmonomials; ++i )
4817  {
4818  monomial = polynomialdata->monomials[i];
4819  assert(monomial != NULL);
4820  for( j = 0; j < monomial->nfactors; ++j )
4821  {
4822  assert(monomial->childidxs[j] >= 0);
4823  assert(monomial->childidxs[j] < expr->nchildren);
4824  ++childusage[monomial->childidxs[j]];
4825  }
4826  }
4827 
4828  /* move linear monomials out of polynomial */
4829  for( i = 0; i < polynomialdata->nmonomials; ++i )
4830  {
4831  monomial = polynomialdata->monomials[i];
4832  assert(monomial != NULL);
4833  if( monomial->nfactors != 1 )
4834  continue;
4835  if( monomial->exponents[0] != 1.0 )
4836  continue;
4837  childidx = monomial->childidxs[0];
4838  if( SCIPexprGetOperator(expr->children[childidx]) != SCIP_EXPR_VARIDX )
4839  continue;
4840 
4841  /* we are at a linear monomial in a variable */
4842  assert(SCIPexprGetOpIndex(expr->children[childidx]) < nvars);
4843  if( childusage[childidx] == 1 && varsusage[SCIPexprGetOpIndex(expr->children[childidx])] == 1 )
4844  {
4845  /* if the child expression is not used in another monomial (which would due to merging be not linear)
4846  * and if the variable is not used somewhere else in the tree,
4847  * then move this monomial into linear part and free child
4848  */
4849  linidxs[*nlinvars] = SCIPexprGetOpIndex(expr->children[childidx]);
4850  lincoefs[*nlinvars] = monomial->coef;
4851  ++*nlinvars;
4852 
4853  SCIPexprFreeDeep(blkmem, &expr->children[childidx]);
4854  monomial->coef = 0.0;
4855  monomial->nfactors = 0;
4856  }
4857  }
4858 
4859  BMSfreeBlockMemoryArray(blkmem, &varsusage, nvars);
4860  BMSfreeBlockMemoryArray(blkmem, &childusage, expr->nchildren);
4861 
4862  if( *nlinvars > 0 )
4863  {
4864  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
4865  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, FALSE);
4867  }
4868 
4869  return SCIP_OKAY;
4870 }
4871 
4872 /** converts polynomial expressions back into simpler expressions, where possible */
4873 static
4875  BMS_BLKMEM* blkmem, /**< block memory data structure */
4876  SCIP_EXPR* expr /**< expression to convert back */
4877  )
4878 {
4879  int i;
4880 
4881  assert(blkmem != NULL);
4882  assert(expr != NULL);
4883 
4884  for( i = 0; i < expr->nchildren; ++i )
4885  {
4887  }
4888 
4889  if( expr->op != SCIP_EXPR_POLYNOMIAL )
4890  return SCIP_OKAY;
4891 
4892  SCIP_CALL( exprUnconvertPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren, (void**)expr->children) );
4893 
4894  return SCIP_OKAY;
4895 }
4896 
4897 static
4898 SCIP_DECL_HASHGETKEY( exprparseVarTableGetKey )
4899 { /*lint --e{715}*/
4900  return (void*)((char*)elem + sizeof(int));
4901 }
4902 
4903 /** parses a variable name from a string and creates corresponding expression
4904  *
4905  * Creates a new variable index if variable not seen before, updates varnames and vartable structures.
4906  */
4907 static
4909  BMS_BLKMEM* blkmem, /**< block memory data structure */
4910  const char** str, /**< pointer to the string to be parsed */
4911  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
4912  int* nvars, /**< running number of encountered variables so far */
4913  int** varnames, /**< pointer to buffer to store new variable names */
4914  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
4915  SCIP_Real coefficient, /**< coefficient to be used when creating the expression */
4916  const char* varnameendptr /**< if a <varname> should be parsed, set this to NULL. Then, str points to the '<'
4917  else, str should point to the first letter of the varname, and varnameendptr should
4918  point one char behind the last char of the variable name */
4919  )
4920 {
4921  int namelength;
4922  int varidx;
4923  char varname[SCIP_MAXSTRLEN];
4924  void* element;
4925 
4926  assert(blkmem != NULL);
4927  assert(str != NULL);
4928  assert(expr != NULL);
4929  assert(nvars != NULL);
4930  assert(varnames != NULL);
4931  assert(vartable != NULL);
4932 
4933  if( varnameendptr == NULL )
4934  {
4935  ++*str;
4936  varnameendptr = *str;
4937  while( varnameendptr[0] != '>' )
4938  ++varnameendptr;
4939  }
4940 
4941  namelength = varnameendptr - *str; /*lint !e712*/
4942  if( namelength >= SCIP_MAXSTRLEN )
4943  {
4944  SCIPerrorMessage("Variable name %.*s is too long for buffer in exprparseReadVariable.\n", namelength, str);
4945  return SCIP_READERROR;
4946  }
4947 
4948  memcpy(varname, *str, namelength * sizeof(char));
4949  varname[namelength] = '\0';
4950 
4951  element = SCIPhashtableRetrieve(vartable, varname);
4952  if( element != NULL )
4953  {
4954  /* variable is old friend */
4955  assert(strcmp((char*)element + sizeof(int), varname) == 0);
4956 
4957  varidx = *(int*)element;
4958  }
4959  else
4960  {
4961  /* variable is new */
4962  varidx = *nvars;
4963 
4964  /* store index of variable and variable name in varnames buffer */
4965  **varnames = varidx;
4966  strcpy((char*)(*varnames + 1), varname);
4967 
4968  /* insert variable into hashtable */
4969  SCIP_CALL( SCIPhashtableInsert(vartable, (void*)*varnames) );
4970 
4971  ++*nvars;
4972  *varnames += 1 + (strlen(varname) + 1) / sizeof(int) + 1;
4973  }
4974 
4975  /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
4976  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_VARIDX, varidx) ); /*lint !e613*/
4977  if( coefficient != 1.0 )
4978  {
4979  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, expr, &coefficient, 0.0) );
4980  }
4981 
4982  /* Move pointer to char behind end of variable */
4983  *str = varnameendptr + 1;
4984 
4985  /* consprint sometimes prints a variable type identifier which we don't need */
4986  if( (*str)[0] == '[' && (*str)[2] == ']' &&
4987  ((*str)[1] == SCIP_VARTYPE_BINARY_CHAR ||
4988  (*str)[1] == SCIP_VARTYPE_INTEGER_CHAR ||
4989  (*str)[1] == SCIP_VARTYPE_IMPLINT_CHAR ||
4990  (*str)[1] == SCIP_VARTYPE_CONTINUOUS_CHAR ) )
4991  *str += 3;
4992 
4993  return SCIP_OKAY;
4994 }
4995 
4996 /** if str[0] points to an opening parenthesis, this function sets endptr to point to the matching closing bracket in str
4997  *
4998  * Searches for at most length characters.
4999  */
5000 static
5002  const char* str, /**< pointer to the string to be parsed */
5003  const char** endptr, /**< pointer to point to the closing parenthesis */
5004  int length /**< length of the string to be parsed */
5005  )
5006 {
5007  int nopenbrackets;
5008 
5009  assert(str[0] == '(');
5010 
5011  *endptr = str;
5012 
5013  /* find the end of this expression */
5014  nopenbrackets = 0;
5015  while( (*endptr - str ) < length && !(nopenbrackets == 1 && *endptr[0] == ')') )
5016  {
5017  if( *endptr[0] == '(')
5018  ++nopenbrackets;
5019  if( *endptr[0] == ')')
5020  --nopenbrackets;
5021  ++*endptr;
5022  }
5023 
5024  if( *endptr[0] != ')' )
5025  {
5026  SCIPerrorMessage("unable to find closing parenthesis in unbalanced expression %.*s\n", length, str);
5027  return SCIP_READERROR;
5028  }
5029 
5030  return SCIP_OKAY;
5031 }
5032 
5033 /** this function sets endptr to point to the next separating comma in str
5034  *
5035  * That is, for a given string like "x+f(x,y),z", endptr will point to the comma before "z"
5036  *
5037  * Searches for at most length characters.
5038  */
5039 static
5041  const char* str, /**< pointer to the string to be parsed */
5042  const char** endptr, /**< pointer to point to the comma */
5043  int length /**< length of the string to be parsed */
5044  )
5045 {
5046  int nopenbrackets;
5047 
5048  *endptr = str;
5049 
5050  /* find a comma without open brackets */
5051  nopenbrackets = 0;
5052  while( (*endptr - str ) < length && !(nopenbrackets == 0 && *endptr[0] == ',') )
5053  {
5054  if( *endptr[0] == '(')
5055  ++nopenbrackets;
5056  if( *endptr[0] == ')')
5057  --nopenbrackets;
5058  ++*endptr;
5059  }
5060 
5061  if( *endptr[0] != ',' )
5062  {
5063  SCIPerrorMessage("unable to find separating comma in unbalanced expression %.*s\n", length, str);
5064  return SCIP_READERROR;
5065  }
5066 
5067  return SCIP_OKAY;
5068 }
5069 
5070 /** parses an expression from a string */
5071 static
5073  BMS_BLKMEM* blkmem, /**< block memory data structure */
5074  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
5075  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
5076  const char* str, /**< pointer to the string to be parsed */
5077  int length, /**< length of the string to be parsed */
5078  const char* lastchar, /**< pointer to the last char of str that should be parsed */
5079  int* nvars, /**< running number of encountered variables so far */
5080  int** varnames, /**< pointer to buffer to store new variable names */
5081  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
5082  int recursiondepth /**< current recursion depth */
5083  )
5084 { /*lint --e{712,747}*/
5085  SCIP_EXPR* arg1;
5086  SCIP_EXPR* arg2;
5087  const char* subexpptr;
5088  const char* subexpendptr;
5089  const char* strstart;
5090  const char* endptr;
5091  char* nonconstendptr;
5092  SCIP_Real number;
5093  int subexplength;
5094  int nopenbrackets;
5095 
5096  assert(blkmem != NULL);
5097  assert(expr != NULL);
5098  assert(str != NULL);
5099  assert(lastchar >= str);
5100  assert(nvars != NULL);
5101  assert(varnames != NULL);
5102  assert(vartable != NULL);
5103 
5104  assert(recursiondepth < 100);
5105 
5106  strstart = str; /* might be needed for error message... */
5107 
5108  SCIPdebugMessage("exprParse (%i): parsing %.*s\n", recursiondepth, (int) (lastchar-str + 1), str);
5109 
5110  /* ignore whitespace */
5111  while( isspace((unsigned char)*str) )
5112  ++str;
5113 
5114  /* look for a sum or difference not contained in brackets */
5115  subexpptr = str;
5116  nopenbrackets = 0;
5117 
5118  /* find the end of this expression
5119  * a '+' right at the beginning indicates a coefficient, not treated here, or a summation
5120  */
5121  while( subexpptr != lastchar && !(nopenbrackets == 0 && (subexpptr[0] == '+' || subexpptr[0] == '-') && subexpptr != str) )
5122  {
5123  if( subexpptr[0] == '(')
5124  ++nopenbrackets;
5125  if( subexpptr[0] == ')')
5126  --nopenbrackets;
5127  ++subexpptr;
5128  }
5129 
5130  if( subexpptr != lastchar )
5131  {
5132  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str, (int) ((subexpptr - 1) - str + 1), subexpptr - 1, nvars, varnames, vartable, recursiondepth + 1) );
5133 
5134  if( subexpptr[0] == '+' )
5135  ++subexpptr;
5136  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, subexpptr , (int) (lastchar - (subexpptr ) + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5137 
5138  /* make new expression from two arguments
5139  * we always use add, because we leave the operator between the found expressions in the second argument
5140  * this way, we do not have to worry about ''minus brackets'' in the case of more then two summands:
5141  * a - b - c = a + (-b -c)
5142  */
5143  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5144 
5145  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5146  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5147  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5148 
5149  return SCIP_OKAY;
5150  }
5151 
5152  /* check for a bracketed subexpression */
5153  if( str[0] == '(' )
5154  {
5155  nopenbrackets = 0;
5156 
5157  subexplength = -1; /* we do not want the closing bracket in the string */
5158  subexpptr = str + 1; /* leave out opening bracket */
5159 
5160  /* find the end of this expression */
5161  while( subexplength < length && !(nopenbrackets == 1 && str[0] == ')') )
5162  {
5163  if( str[0] == '(' )
5164  ++nopenbrackets;
5165  if( str[0] == ')' )
5166  --nopenbrackets;
5167  ++str;
5168  ++subexplength;
5169  }
5170  subexpendptr = str - 1; /* leave out closing bracket */
5171 
5172  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, subexpptr, subexplength, subexpendptr, nvars, varnames, vartable, recursiondepth + 1) );
5173  ++str;
5174  }
5175  else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+')
5176  && (isdigit((unsigned char)str[1]) || str[1] == ' ')) )
5177  {
5178  /* check if there is a lonely minus coming, indicating a -1.0 */
5179  if( str[0] == '-' && str[1] == ' ' )
5180  {
5181  number = -1.0;
5182  nonconstendptr = (char*) str + 1;
5183  }
5184  /* check if there is a number coming */
5185  else if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5186  {
5187  SCIPerrorMessage("error parsing number from <%s>\n", str);
5188  return SCIP_READERROR;
5189  }
5190  str = nonconstendptr;
5191 
5192  /* ignore whitespace */
5193  while( isspace((unsigned char)*str) && str != lastchar )
5194  ++str;
5195 
5196  if( str[0] != '*' && str[0] != '/' && str[0] != '+' && str[0] != '-' && str[0] != '^' )
5197  {
5198  if( str < lastchar )
5199  {
5200  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, str, (int)(lastchar - str) + 1, lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5201  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, *expr, number) );
5202  }
5203  else
5204  {
5205  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5206  }
5207  str = lastchar + 1;
5208  }
5209  else
5210  {
5211  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5212  }
5213  }
5214  else if( str[0] == '<' )
5215  {
5216  /* check if expressions begins with a variable */
5217  SCIP_CALL( exprparseReadVariable(blkmem, &str, expr, nvars, varnames, vartable, 1.0, NULL) );
5218  }
5219  /* four character operators */
5220  else if( strncmp(str, "sqrt", 4) == 0 )
5221  {
5222  str += 4;
5223  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5224  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5225  str = endptr + 1;
5226 
5227  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQRT, arg1) );
5228  }
5229  /* three character operators with 1 argument */
5230  else if(
5231  strncmp(str, "abs", 3) == 0 ||
5232  strncmp(str, "cos", 3) == 0 ||
5233  strncmp(str, "exp", 3) == 0 ||
5234  strncmp(str, "log", 3) == 0 ||
5235  strncmp(str, "sin", 3) == 0 ||
5236  strncmp(str, "sqr", 3) == 0 ||
5237  strncmp(str, "tan", 3) == 0 )
5238  {
5239  const char* opname = str;
5240 
5241  str += 3;
5242  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5243  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5244  str = endptr + 1;
5245 
5246  if( strncmp(opname, "abs", 3) == 0 )
5247  {
5248  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_ABS, arg1) );
5249  }
5250  else if( strncmp(opname, "cos", 3) == 0 )
5251  {
5252  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_COS, arg1) );
5253  }
5254  else if( strncmp(opname, "exp", 3) == 0 )
5255  {
5256  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, arg1) );
5257  }
5258  else if( strncmp(opname, "log", 3) == 0 )
5259  {
5260  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5261  }
5262  else if( strncmp(opname, "sin", 3) == 0 )
5263  {
5264  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIN, arg1) );
5265  }
5266  else if( strncmp(opname, "sqr", 3) == 0 )
5267  {
5268  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQUARE, arg1) );
5269  }
5270  else
5271  {
5272  assert(strncmp(opname, "tan", 3) == 0);
5273  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_TAN, arg1) );
5274  }
5275  }
5276  /* three character operators with 2 arguments */
5277  else if(
5278  strncmp(str, "max", 3) == 0 ||
5279  strncmp(str, "min", 3) == 0 )
5280  {
5281  /* we have a string of the form "min(...,...)" or "max(...,...)"
5282  * first find the closing parenthesis, then the comma
5283  */
5284  const char* comma;
5285  SCIP_EXPROP op;
5286 
5287  op = (str[1] == 'a' ? SCIP_EXPR_MAX : SCIP_EXPR_MIN);
5288 
5289  str += 3;
5290  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5291 
5292  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5293 
5294  /* parse first argument [str+1..comma-1] */
5295  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames, vartable, recursiondepth + 1) );
5296 
5297  /* parse second argument [comma+1..endptr] */
5298  ++comma;
5299  while( comma < endptr && *comma == ' ' )
5300  ++comma;
5301 
5302  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, comma, endptr - comma, endptr - 1, nvars, varnames, vartable, recursiondepth + 1) );
5303 
5304  SCIP_CALL( SCIPexprCreate(blkmem, expr, op, arg1, arg2) );
5305 
5306  str = endptr + 1;
5307  }
5308  else if( strncmp(str, "power", 5) == 0 )
5309  {
5310  /* we have a string of the form "power(...,integer)" (thus, intpower)
5311  * first find the closing parenthesis, then the comma
5312  */
5313  const char* comma;
5314  int exponent;
5315 
5316  str += 5;
5317  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5318 
5319  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5320 
5321  /* parse first argument [str+1..comma-1] */
5322  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames, vartable, recursiondepth + 1) );
5323 
5324  ++comma;
5325  /* parse second argument [comma, endptr-1]: it needs to be an integer */
5326  while( comma < endptr && *comma == ' ' )
5327  ++comma;
5328  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5329  {
5330  SCIPerrorMessage("error parsing integer exponent from <%s>\n", comma);
5331  }
5332  if( !SCIPstrToIntValue(comma, &exponent, &nonconstendptr) )
5333  {
5334  SCIPerrorMessage("error parsing integer from <%s>\n", comma);
5335  return SCIP_READERROR;
5336  }
5337 
5338  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, exponent) );
5339 
5340  str = endptr + 1;
5341  }
5342  else if( strncmp(str, "realpower", 9) == 0 || strncmp(str, "signpower", 9) == 0 )
5343  {
5344  /* we have a string of the form "realpower(...,double)" or "signpower(...,double)"
5345  * first find the closing parenthesis, then the comma
5346  */
5347  const char* opname = str;
5348  const char* comma;
5349 
5350  str += 9;
5351  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5352 
5353  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5354 
5355  /* parse first argument [str+1..comma-1] */
5356  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames, vartable, recursiondepth + 1) );
5357 
5358  ++comma;
5359  /* parse second argument [comma, endptr-1]: it needs to be an number */
5360  while( comma < endptr && *comma == ' ' )
5361  ++comma;
5362  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5363  {
5364  SCIPerrorMessage("error parsing number exponent from <%s>\n", comma);
5365  }
5366  if( !SCIPstrToRealValue(comma, &number, &nonconstendptr) )
5367  {
5368  SCIPerrorMessage("error parsing number from <%s>\n", comma);
5369  return SCIP_READERROR;
5370  }
5371 
5372  if( strncmp(opname, "realpower", 9) == 0 )
5373  {
5374  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, number) );
5375  }
5376  else
5377  {
5378  assert(strncmp(opname, "signpower", 9) == 0);
5379  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIGNPOWER, arg1, number) );
5380  }
5381 
5382  str = endptr + 1;
5383  }
5384  else if( isalpha(*str) || *str == '_' || *str == '#' )
5385  {
5386  /* check for a variable, that was not recognized earlier because somebody omitted the '<' and '>' we need for
5387  * SCIPparseVarName, making everyones life harder;
5388  * we allow only variable names starting with a character or underscore here
5389  */
5390  const char* varnamestartptr = str;
5391 
5392  /* allow only variable names containing characters, digits, hash marks, and underscores here */
5393  while( isalnum(str[0]) || str[0] == '_' || str[0] == '#' )
5394  ++str;
5395 
5396  SCIP_CALL( exprparseReadVariable(blkmem, &varnamestartptr, expr, nvars, varnames, vartable, 1.0, str) );
5397  }
5398  else
5399  {
5400  SCIPerrorMessage("parsing of invalid expression %.*s.\n", (int) (lastchar - str + 1), str);
5401  return SCIP_READERROR;
5402  }
5403 
5404  /* if we are one char behind lastchar, we are done */
5405  if( str == lastchar + 1)
5406  {
5407  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5408  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5409  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5410 
5411  return SCIP_OKAY;
5412  }
5413 
5414  /* check if we are still in bounds */
5415  if( str > lastchar + 1)
5416  {
5417  SCIPerrorMessage("error finding first expression in \"%.*s\" took us outside of given subexpression length\n", length, strstart);
5418  return SCIP_READERROR;
5419  }
5420 
5421  /* ignore whitespace */
5422  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5423  ++str;
5424 
5425  /* maybe now we're done? */
5426  if( str >= lastchar + 1)
5427  {
5428  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5429  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5430  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5431 
5432  return SCIP_OKAY;
5433  }
5434 
5435  if( str[0] == '^' )
5436  {
5437  /* a '^' behind the found expression indicates a power */
5438  SCIP_Real constant;
5439 
5440  arg1 = *expr;
5441  ++str;
5442  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5443  ++str;
5444 
5445  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5446  {
5447  /* there is a number coming */
5448  if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5449  {
5450  SCIPerrorMessage("error parsing number from <%s>\n", str);
5451  return SCIP_READERROR;
5452  }
5453 
5454  SCIP_CALL( SCIPexprCreate(blkmem, &arg2, SCIP_EXPR_CONST, number) );
5455  str = nonconstendptr;
5456 
5457  constant = SCIPexprGetOpReal(arg2);
5458  SCIPexprFreeDeep(blkmem, &arg2);
5459 
5460  /* expr^number is intpower or realpower */
5461  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5462  {
5463  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5464  }
5465  else
5466  {
5467  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5468  }
5469  }
5470  else if( str[0] == '(' )
5471  {
5472  /* we use exprParse to evaluate the exponent */
5473 
5474  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5475  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5476 
5477  if( SCIPexprGetOperator(arg2) != SCIP_EXPR_CONST )
5478  {
5479  /* reformulate arg1^arg2 as exp(arg2 * log(arg1)) */
5480  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5481  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, *expr, arg2) );
5482  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, *expr) );
5483  }
5484  else
5485  {
5486  /* expr^number is intpower or realpower */
5487  constant = SCIPexprGetOpReal(arg2);
5488  SCIPexprFreeDeep(blkmem, &arg2);
5489  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5490  {
5491  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5492  }
5493  else
5494  {
5495  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5496  }
5497  }
5498  str = endptr + 1;
5499  }
5500  else
5501  {
5502  SCIPerrorMessage("unexpected string following ^ in %.*s\n", length, str);
5503  return SCIP_READERROR;
5504  }
5505 
5506  /* ignore whitespace */
5507  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5508  ++str;
5509  }
5510 
5511  /* check for a two argument operator that is not a multiplication */
5512  if( str <= lastchar && (str[0] == '+' || str[0] == '-' || str[0] == '/') )
5513  {
5514  char op;
5515 
5516  op = str[0];
5517  arg1 = *expr;
5518 
5519  /* step forward over the operator to go to the beginning of the second argument */
5520  ++str;
5521 
5522  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5523  str = lastchar + 1;
5524 
5525  /* make new expression from two arguments */
5526  if( op == '+')
5527  {
5528  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5529  }
5530  else if( op == '-')
5531  {
5532  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, -1.0, arg2, 0.0) );
5533  }
5534  else if( op == '*' )
5535  {
5536  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5537  {
5538  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5539  }
5540  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5541  {
5542  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5543  }
5544  else
5545  {
5546  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5547  }
5548  }
5549  else
5550  {
5551  assert(op == '/');
5552 
5553  if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5554  {
5555  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, 1.0 / SCIPexprGetOpReal(arg2)) );
5556  SCIPexprFreeShallow(blkmem, &arg2);
5557  }
5558  else
5559  {
5560  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_DIV, arg1, arg2) );
5561  }
5562  }
5563  }
5564 
5565  /* ignore whitespace */
5566  while( isspace((unsigned char)*str) )
5567  ++str;
5568 
5569  /* we are either done or we have a multiplication? */
5570  if( str >= lastchar + 1 )
5571  {
5572  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5573  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5574  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5575 
5576  return SCIP_OKAY;
5577  }
5578 
5579  /* if there is a part of the string left to be parsed, we assume that this as a multiplication */
5580  arg1 = *expr;
5581 
5582  /* stepping over multiplication operator if needed */
5583  if( str[0] == '*' )
5584  {
5585  ++str;
5586  }
5587  else if( str[0] != '(' )
5588  {
5589  SCIPdebugMessage("No operator found, assuming a multiplication before %.*s\n", (int) (lastchar - str + 1), str);
5590  }
5591 
5592  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5593 
5594  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5595  {
5596  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5597  SCIPexprFreeDeep(blkmem, &arg1);
5598  }
5599  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5600  {
5601  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5602  SCIPexprFreeDeep(blkmem, &arg2);
5603  }
5604  else
5605  {
5606  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5607  }
5608 
5609  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5610  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5611  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5612 
5613  return SCIP_OKAY;
5614 }
5615 
5616 /**@} */
5617 
5618 /**@name Expression methods */
5619 /**@{ */
5620 
5621 /* In debug mode, the following methods are implemented as function calls to ensure
5622  * type validity.
5623  * In optimized mode, the methods are implemented as defines to improve performance.
5624  * However, we want to have them in the library anyways, so we have to undef the defines.
5625  */
5626 
5627 #undef SCIPexprGetOperator
5628 #undef SCIPexprGetNChildren
5629 #undef SCIPexprGetChildren
5630 #undef SCIPexprGetOpIndex
5631 #undef SCIPexprGetOpReal
5632 #undef SCIPexprGetOpData
5633 #undef SCIPexprGetRealPowerExponent
5634 #undef SCIPexprGetIntPowerExponent
5635 #undef SCIPexprGetSignPowerExponent
5636 #undef SCIPexprGetLinearCoefs
5637 #undef SCIPexprGetLinearConstant
5638 #undef SCIPexprGetQuadElements
5639 #undef SCIPexprGetQuadConstant
5640 #undef SCIPexprGetQuadLinearCoefs
5641 #undef SCIPexprGetNQuadElements
5642 #undef SCIPexprGetMonomials
5643 #undef SCIPexprGetNMonomials
5644 #undef SCIPexprGetPolynomialConstant
5645 #undef SCIPexprGetMonomialCoef
5646 #undef SCIPexprGetMonomialNFactors
5647 #undef SCIPexprGetMonomialChildIndices
5648 #undef SCIPexprGetMonomialExponents
5649 #undef SCIPexprGetUserData
5650 #undef SCIPexprHasUserEstimator
5651 #undef SCIPexprGetUserEvalCapability
5652 
5653 /** gives operator of expression */
5655  SCIP_EXPR* expr /**< expression */
5656  )
5657 {
5658  assert(expr != NULL);
5659 
5660  return expr->op;
5661 }
5662 
5663 /** gives number of children of an expression */
5665  SCIP_EXPR* expr /**< expression */
5666  )
5667 {
5668  assert(expr != NULL);
5669 
5670  return expr->nchildren;
5671 }
5672 
5673 /** gives pointer to array with children of an expression */
5675  SCIP_EXPR* expr /**< expression */
5676  )
5677 {
5678  assert(expr != NULL);
5679 
5680  return expr->children;
5681 }
5682 
5683 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
5685  SCIP_EXPR* expr /**< expression */
5686  )
5687 {
5688  assert(expr != NULL);
5689  assert(expr->op == SCIP_EXPR_VARIDX || expr->op == SCIP_EXPR_PARAM);
5690 
5691  return expr->data.intval;
5692 }
5693 
5694 /** gives real belonging to a SCIP_EXPR_CONST operand */
5696  SCIP_EXPR* expr /**< expression */
5697  )
5698 {
5699  assert(expr != NULL);
5700  assert(expr->op == SCIP_EXPR_CONST);
5701 
5702  return expr->data.dbl;
5703 }
5704 
5705 /** gives void* belonging to a complex operand */
5707  SCIP_EXPR* expr /**< expression */
5708  )
5709 {
5710  assert(expr != NULL);
5711  assert(expr->op >= SCIP_EXPR_SUM); /* only complex operands store their data as void* */
5712 
5713  return expr->data.data;
5714 }
5715 
5716 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
5718  SCIP_EXPR* expr /**< expression */
5719  )
5720 {
5721  assert(expr != NULL);
5722  assert(expr->op == SCIP_EXPR_REALPOWER);
5723 
5724  return expr->data.dbl;
5725 }
5726 
5727 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
5729  SCIP_EXPR* expr /**< expression */
5730  )
5731 {
5732  assert(expr != NULL);
5733  assert(expr->op == SCIP_EXPR_INTPOWER);
5734 
5735  return expr->data.intval;
5736 }
5737 
5738 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
5740  SCIP_EXPR* expr /**< expression */
5741  )
5742 {
5743  assert(expr != NULL);
5744  assert(expr->op == SCIP_EXPR_SIGNPOWER);
5745 
5746  return expr->data.dbl;
5747 }
5748 
5749 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
5751  SCIP_EXPR* expr /**< expression */
5752  )
5753 {
5754  assert(expr != NULL);
5755  assert(expr->op == SCIP_EXPR_LINEAR);
5756  assert(expr->data.data != NULL);
5757 
5758  /* the coefficients are stored in the first nchildren elements of the array stored as expression data */
5759  return (SCIP_Real*)expr->data.data;
5760 }
5761 
5762 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
5764  SCIP_EXPR* expr /**< expression */
5765  )
5766 {
5767  assert(expr != NULL);
5768  assert(expr->op == SCIP_EXPR_LINEAR);
5769  assert(expr->data.data != NULL);
5770 
5771  /* the constant is stored in the nchildren's element of the array stored as expression data */
5772  return ((SCIP_Real*)expr->data.data)[expr->nchildren];
5773 }
5774 
5775 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5777  SCIP_EXPR* expr /**< quadratic expression */
5778  )
5779 {
5780  assert(expr != NULL);
5781  assert(expr->op == SCIP_EXPR_QUADRATIC);
5782  assert(expr->data.data != NULL);
5783 
5784  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->quadelems;
5785 }
5786 
5787 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
5789  SCIP_EXPR* expr /**< quadratic expression */
5790  )
5791 {
5792  assert(expr != NULL);
5793  assert(expr->op == SCIP_EXPR_QUADRATIC);
5794  assert(expr->data.data != NULL);
5795 
5796  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->constant;
5797 }
5798 
5799 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression
5800  * can be NULL if all coefficients are 0.0 */
5802  SCIP_EXPR* expr /**< quadratic expression */
5803  )
5804 {
5805  assert(expr != NULL);
5806  assert(expr->op == SCIP_EXPR_QUADRATIC);
5807  assert(expr->data.data != NULL);
5808 
5809  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->lincoefs;
5810 }
5811 
5812 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5814  SCIP_EXPR* expr /**< quadratic expression */
5815  )
5816 {
5817  assert(expr != NULL);
5818  assert(expr->op == SCIP_EXPR_QUADRATIC);
5819  assert(expr->data.data != NULL);
5820 
5821  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->nquadelems;
5822 }
5823 
5824 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5826  SCIP_EXPR* expr /**< expression */
5827  )
5828 {
5829  assert(expr != NULL);
5830  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5831  assert(expr->data.data != NULL);
5832 
5833  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->monomials;
5834 }
5835 
5836 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5838  SCIP_EXPR* expr /**< expression */
5839  )
5840 {
5841  assert(expr != NULL);
5842  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5843  assert(expr->data.data != NULL);
5844 
5845  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->nmonomials;
5846 }
5847 
5848 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
5850  SCIP_EXPR* expr /**< expression */
5851  )
5852 {
5853  assert(expr != NULL);
5854  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5855  assert(expr->data.data != NULL);
5856 
5857  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant;
5858 }
5859 
5860 /** gets coefficient of a monomial */
5862  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5863  )
5864 {
5865  assert(monomial != NULL);
5866 
5867  return monomial->coef;
5868 }
5869 
5870 /** gets number of factors of a monomial */
5872  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5873  )
5874 {
5875  assert(monomial != NULL);
5876 
5877  return monomial->nfactors;
5878 }
5879 
5880 /** gets indices of children corresponding to factors of a monomial */
5882  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5883  )
5884 {
5885  assert(monomial != NULL);
5886 
5887  return monomial->childidxs;
5888 }
5889 
5890 /** gets exponents in factors of a monomial */
5892  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5893  )
5894 {
5895  assert(monomial != NULL);
5896 
5897  return monomial->exponents;
5898 }
5899 
5900 /** gets user data of a user expression */
5902  SCIP_EXPR* expr
5903  )
5904 {
5905  assert(expr != NULL);
5906  assert(expr->data.data != NULL);
5907 
5908  return ((SCIP_EXPRDATA_USER*)expr->data.data)->userdata;
5909 }
5910 
5911 /** indicates whether a user expression has the estimator callback defined */
5913  SCIP_EXPR* expr
5914  )
5915 {
5916  assert(expr != NULL);
5917  assert(expr->data.data != NULL);
5918 
5919  return ((SCIP_EXPRDATA_USER*)expr->data.data)->estimate != NULL;
5920 }
5921 
5922 /** gives the evaluation capability of a user expression */
5924  SCIP_EXPR* expr
5925  )
5926 {
5927  assert(expr != NULL);
5928  assert(expr->data.data != NULL);
5929 
5930  return ((SCIP_EXPRDATA_USER*)expr->data.data)->evalcapability;
5931 }
5932 
5933 /** creates a simple expression */
5935  BMS_BLKMEM* blkmem, /**< block memory data structure */
5936  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
5937  SCIP_EXPROP op, /**< operand of expression */
5938  ... /**< arguments of operand */
5939  )
5940 {
5941  va_list ap;
5942  SCIP_EXPR** children;
5943  SCIP_EXPROPDATA opdata;
5944 
5945  assert(blkmem != NULL);
5946  assert(expr != NULL);
5947 
5948  switch( op )
5949  {
5950  case SCIP_EXPR_VARIDX:
5951  case SCIP_EXPR_PARAM:
5952  {
5953  va_start( ap, op ); /*lint !e838*/
5954  opdata.intval = va_arg( ap, int ); /*lint !e416 !e826*/
5955  va_end( ap ); /*lint !e826*/
5956 
5957  assert( opdata.intval >= 0 );
5958 
5959  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5960  break;
5961  }
5962 
5963  case SCIP_EXPR_CONST:
5964  {
5965  va_start(ap, op ); /*lint !e838*/
5966  opdata.dbl = va_arg( ap, SCIP_Real ); /*lint !e416 !e826*/
5967  va_end( ap ); /*lint !e826*/
5968 
5969  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5970  break;
5971  }
5972 
5973  /* operands with two children */
5974  case SCIP_EXPR_PLUS :
5975  case SCIP_EXPR_MINUS :
5976  case SCIP_EXPR_MUL :
5977  case SCIP_EXPR_DIV :
5978  case SCIP_EXPR_MIN :
5979  case SCIP_EXPR_MAX :
5980  {
5981  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 2) ); /*lint !e506*/
5982 
5983  va_start(ap, op ); /*lint !e838*/
5984  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5985  children[1] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5986  assert(children[0] != NULL);
5987  assert(children[1] != NULL);
5988  va_end( ap ); /*lint !e826*/
5989  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
5990 
5991  SCIP_CALL( exprCreate( blkmem, expr, op, 2, children, opdata ) );
5992  break;
5993  }
5994 
5995  /* operands with one child */
5996  case SCIP_EXPR_SQUARE:
5997  case SCIP_EXPR_SQRT :
5998  case SCIP_EXPR_EXP :
5999  case SCIP_EXPR_LOG :
6000  case SCIP_EXPR_SIN :
6001  case SCIP_EXPR_COS :
6002  case SCIP_EXPR_TAN :
6003  /* case SCIP_EXPR_ERF : */
6004  /* case SCIP_EXPR_ERFI : */
6005  case SCIP_EXPR_ABS :
6006  case SCIP_EXPR_SIGN :
6007  {
6008  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6009 
6010  va_start(ap, op ); /*lint !e838*/
6011  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6012  assert(children[0] != NULL);
6013  va_end( ap ); /*lint !e826*/
6014  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6015 
6016  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6017  break;
6018  }
6019 
6020  case SCIP_EXPR_REALPOWER:
6021  case SCIP_EXPR_SIGNPOWER:
6022  {
6023  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6024 
6025  va_start(ap, op ); /*lint !e838*/
6026  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6027  assert(children[0] != NULL);
6028  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
6029  va_end( ap ); /*lint !e826*/
6030 
6031  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6032  break;
6033  }
6034 
6035  case SCIP_EXPR_INTPOWER:
6036  {
6037  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6038 
6039  va_start(ap, op ); /*lint !e838*/
6040  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6041  assert(children[0] != NULL);
6042  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
6043  va_end( ap ); /*lint !e826*/
6044 
6045  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6046  break;
6047  }
6048 
6049  /* complex operands */
6050  case SCIP_EXPR_SUM :
6051  case SCIP_EXPR_PRODUCT:
6052  {
6053  int nchildren;
6054  SCIP_EXPR** childrenarg;
6055 
6056  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6057 
6058  va_start(ap, op ); /*lint !e838*/
6059  /* first argument should be number of children */
6060  nchildren = va_arg( ap, int ); /*lint !e416 !e826*/
6061  assert(nchildren >= 0);
6062 
6063  /* for a sum or product of 0 terms we can finish here */
6064  if( nchildren == 0 )
6065  {
6066  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata) );
6067  va_end( ap ); /*lint !e826*/
6068  break;
6069  }
6070 
6071  /* next argument should be array of children expressions */
6072  childrenarg = va_arg( ap, SCIP_EXPR** ); /*lint !e416 !e826*/
6073  assert(childrenarg != NULL);
6074  va_end( ap ); /*lint !e826*/
6075 
6076  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &children, childrenarg, nchildren) );
6077 
6078  SCIP_CALL( exprCreate( blkmem, expr, op, nchildren, children, opdata) );
6079  break;
6080  }
6081 
6082  case SCIP_EXPR_LINEAR :
6083  case SCIP_EXPR_QUADRATIC:
6084  case SCIP_EXPR_POLYNOMIAL:
6085  case SCIP_EXPR_USER:
6086  {
6087  SCIPerrorMessage("cannot create complex expression linear, quadratic, polynomial, or user with SCIPexprCreate\n");
6088  return SCIP_INVALIDDATA;
6089  }
6090 
6091  case SCIP_EXPR_LAST:
6092  SCIPABORT();
6093  break;
6094  }
6095 
6096  return SCIP_OKAY;
6097 }
6098 
6099 /** copies an expression including its children */
6101  BMS_BLKMEM* blkmem, /**< block memory data structure */
6102  SCIP_EXPR** targetexpr, /**< buffer to store pointer to copied expression */
6103  SCIP_EXPR* sourceexpr /**< expression to copy */
6104  )
6105 {
6106  assert(blkmem != NULL);
6107  assert(targetexpr != NULL);
6108  assert(sourceexpr != NULL);
6109 
6110  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targetexpr, sourceexpr) );
6111 
6112  if( sourceexpr->nchildren )
6113  {
6114  int i;
6115 
6116  /* alloc memory for children expressions */
6117  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetexpr)->children, sourceexpr->nchildren) );
6118 
6119  /* copy children expressions */
6120  for( i = 0; i < sourceexpr->nchildren; ++i )
6121  {
6122  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targetexpr)->children[i], sourceexpr->children[i]) );
6123  }
6124  }
6125  else
6126  {
6127  assert((*targetexpr)->children == NULL); /* otherwise, sourceexpr->children was not NULL, which is wrong */
6128  }
6129 
6130  /* call operands data copy callback for complex operands
6131  * for simple operands BMSduplicate above should have done the job
6132  */
6133  if( exprOpTable[sourceexpr->op].copydata != NULL )
6134  {
6135  SCIP_CALL( exprOpTable[sourceexpr->op].copydata(blkmem, sourceexpr->nchildren, sourceexpr->data, &(*targetexpr)->data) );
6136  }
6137 
6138  return SCIP_OKAY;
6139 }
6140 
6141 /** frees an expression including its children */
6143  BMS_BLKMEM* blkmem, /**< block memory data structure */
6144  SCIP_EXPR** expr /**< pointer to expression to free */
6145  )
6146 {
6147  assert(blkmem != NULL);
6148  assert(expr != NULL);
6149  assert(*expr != NULL);
6150 
6151  /* call operands data free callback, if given */
6152  if( exprOpTable[(*expr)->op].freedata != NULL )
6153  {
6154  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6155  }
6156 
6157  if( (*expr)->nchildren )
6158  {
6159  int i;
6160 
6161  assert( (*expr)->children != NULL );
6162 
6163  for( i = 0; i < (*expr)->nchildren; ++i )
6164  {
6165  SCIPexprFreeDeep(blkmem, &(*expr)->children[i]);
6166  assert((*expr)->children[i] == NULL);
6167  }
6168 
6169  BMSfreeBlockMemoryArray(blkmem, &(*expr)->children, (*expr)->nchildren);
6170  }
6171  else
6172  {
6173  assert( (*expr)->children == NULL );
6174  }
6175 
6176  BMSfreeBlockMemory(blkmem, expr);
6177 }
6178 
6179 /** frees an expression but not its children */
6181  BMS_BLKMEM* blkmem, /**< block memory data structure */
6182  SCIP_EXPR** expr /**< pointer to expression to free */
6183  )
6184 {
6185  assert(blkmem != NULL);
6186  assert(expr != NULL);
6187  assert(*expr != NULL);
6188 
6189  /* call operands data free callback, if given */
6190  if( exprOpTable[(*expr)->op].freedata != NULL )
6191  {
6192  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6193  }
6194 
6195  BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->nchildren);
6196 
6197  BMSfreeBlockMemory(blkmem, expr);
6198 }
6199 
6200 /** creates an expression from the addition of two given expression, with coefficients, and a constant
6201  *
6202  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6203  * Favors creation and maintaining of SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6204  */
6206  BMS_BLKMEM* blkmem, /**< block memory data structure */
6207  SCIP_EXPR** expr, /**< pointer to store pointer to created expression */
6208  SCIP_Real coef1, /**< coefficient of first term */
6209  SCIP_EXPR* term1, /**< expression of first term, or NULL */
6210  SCIP_Real coef2, /**< coefficient of second term */
6211  SCIP_EXPR* term2, /**< expression of second term, or NULL */
6212  SCIP_Real constant /**< constant term to add */
6213  )
6214 {
6215  assert(blkmem != NULL);
6216  assert(expr != NULL);
6217 
6218  /* @todo could do something special with quadratic and polynomial expressions */
6219 
6220  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_CONST )
6221  {
6222  constant += coef1 * SCIPexprGetOpReal(term1);
6223  SCIPexprFreeDeep(blkmem, &term1);
6224  }
6225 
6226  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_CONST )
6227  {
6228  constant += coef2 * SCIPexprGetOpReal(term2);
6229  SCIPexprFreeDeep(blkmem, &term2);
6230  }
6231 
6232  if( term1 == NULL && term2 == NULL )
6233  {
6234  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, constant) );
6235  return SCIP_OKAY;
6236  }
6237 
6238  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && coef1 != 1.0 )
6239  {
6240  /* multiply coefficients and constant of linear expression term1 by coef1 */
6241  SCIP_Real* data;
6242  int i;
6243 
6244  data = (SCIP_Real*)term1->data.data;
6245  assert(data != NULL);
6246 
6247  /* loop one more index to multiply also constant of linear expression */
6248  for( i = 0; i <= term1->nchildren; ++i )
6249  data[i] *= coef1;
6250 
6251  coef1 = 1.0;
6252  }
6253 
6254  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR && coef2 != 1.0 )
6255  {
6256  /* multiply coefficients and constant of linear expression term2 by coef2 */
6257  SCIP_Real* data;
6258  int i;
6259 
6260  data = (SCIP_Real*)term2->data.data;
6261  assert(data != NULL);
6262 
6263  /* loop one more index to multiply also constant of linear expression */
6264  for( i = 0; i <= term2->nchildren; ++i )
6265  data[i] *= coef2;
6266 
6267  coef2 = 1.0;
6268  }
6269 
6270  if( term1 == NULL || term2 == NULL )
6271  {
6272  if( term1 == NULL )
6273  {
6274  term1 = term2;
6275  coef1 = coef2;
6276  }
6277  if( constant != 0.0 || coef1 != 1.0 )
6278  {
6279  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6280  {
6281  assert(coef1 == 1.0);
6282 
6283  /* add constant to existing linear expression */
6284  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 0, NULL, NULL, constant) );
6285  *expr = term1;
6286  }
6287  else
6288  {
6289  /* create new linear expression for coef1 * term1 + constant */
6290  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term1, &coef1, constant) );
6291  }
6292  }
6293  else
6294  {
6295  assert(constant == 0.0);
6296  assert(coef1 == 1.0);
6297  *expr = term1;
6298  }
6299 
6300  return SCIP_OKAY;
6301  }
6302 
6304  {
6305  /* add 2nd linear expression to first one */
6306  assert(coef1 == 1.0);
6307  assert(coef2 == 1.0);
6308 
6310  SCIPexprFreeShallow(blkmem, &term2);
6311 
6312  *expr = term1;
6313 
6314  return SCIP_OKAY;
6315  }
6316 
6317  if( SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
6318  {
6319  /* if only term2 is linear, then swap */
6320  SCIP_EXPR* tmp;
6321 
6322  tmp = term2;
6323  assert(coef2 == 1.0);
6324 
6325  term2 = term1;
6326  coef2 = coef1;
6327  term1 = tmp;
6328  coef1 = 1.0;
6329  }
6330 
6331  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6332  {
6333  /* add coef2*term2 as extra child to linear expression term1 */
6334  assert(coef1 == 1.0);
6335 
6336  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 1, &coef2, &term2, constant) );
6337  *expr = term1;
6338 
6339  return SCIP_OKAY;
6340  }
6341 
6342  /* both terms are not linear, then create new linear term for sum */
6343  {
6344  SCIP_Real coefs[2];
6345  SCIP_EXPR* children[2];
6346 
6347  coefs[0] = coef1;
6348  coefs[1] = coef2;
6349  children[0] = term1;
6350  children[1] = term2;
6351 
6352  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 2, children, coefs, constant) );
6353  }
6354 
6355  return SCIP_OKAY;
6356 }
6357 
6358 /** creates an expression from the multiplication of an expression with a constant
6359  *
6360  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6361  * Favors creation and maintaining SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6362  */
6364  BMS_BLKMEM* blkmem, /**< block memory data structure */
6365  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
6366  SCIP_EXPR* term, /**< term to multiply by factor */
6367  SCIP_Real factor /**< factor */
6368  )
6369 {
6370  assert(blkmem != NULL);
6371  assert(expr != NULL);
6372  assert(term != NULL);
6373 
6374  if( factor == 0.0 )
6375  {
6376  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, 0.0) );
6377 
6378  SCIPexprFreeDeep(blkmem, &term);
6379 
6380  return SCIP_OKAY;
6381  }
6382  if( factor == 1.0 )
6383  {
6384  *expr = term;
6385  return SCIP_OKAY;
6386  }
6387 
6388  switch( SCIPexprGetOperator(term) )
6389  {
6390  case SCIP_EXPR_CONST :
6391  {
6392  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, factor * SCIPexprGetOpReal(term)) );
6393  SCIPexprFreeDeep(blkmem, &term);
6394  break;
6395  }
6396 
6397  case SCIP_EXPR_LINEAR :
6398  {
6399  SCIP_Real* data;
6400  int i;
6401 
6402  data = (SCIP_Real*)term->data.data;
6403  assert(data != NULL);
6404 
6405  /* loop one more index to multiply also constant of linear expression */
6406  for( i = 0; i <= SCIPexprGetNChildren(term); ++i )
6407  data[i] *= factor;
6408 
6409  *expr = term;
6410  break;
6411  }
6412 
6413  case SCIP_EXPR_QUADRATIC :
6414  {
6416  int i;
6417 
6418  data = (SCIP_EXPRDATA_QUADRATIC*)term->data.data;
6419 
6420  data->constant *= factor;
6421 
6422  if( data->lincoefs != NULL )
6423  for( i = 0; i < term->nchildren; ++i )
6424  data->lincoefs[i] *= factor;
6425 
6426  for( i = 0; i < data->nquadelems; ++i )
6427  data->quadelems[i].coef *= factor;
6428 
6429  *expr = term;
6430  break;
6431  }
6432 
6433  case SCIP_EXPR_POLYNOMIAL :
6434  {
6436  int i;
6437 
6438  data = (SCIP_EXPRDATA_POLYNOMIAL*)term->data.data;
6439 
6440  data->constant *= factor;
6441 
6442  for( i = 0; i < data->nmonomials; ++i )
6443  data->monomials[i]->coef *= factor;
6444 
6445  *expr = term;
6446  break;
6447  }
6448 
6449  default:
6450  {
6451  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term, &factor, 0.0) );
6452  break;
6453  }
6454 
6455  } /*lint !e788 */
6456 
6457  return SCIP_OKAY;
6458 }
6459 
6460 /** creates a SCIP_EXPR_LINEAR expression that is (affine) linear in its children: constant + sum_i coef_i child_i */
6462  BMS_BLKMEM* blkmem, /**< block memory data structure */
6463  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6464  int nchildren, /**< number of children */
6465  SCIP_EXPR** children, /**< children of expression */
6466  SCIP_Real* coefs, /**< coefficients of children */
6467  SCIP_Real constant /**< constant part */
6468  )
6469 {
6470  SCIP_EXPROPDATA opdata;
6471  SCIP_EXPR** childrencopy;
6472  SCIP_Real* data;
6473 
6474  assert(nchildren >= 0);
6475  assert(children != NULL || nchildren == 0);
6476  assert(coefs != NULL || nchildren == 0);
6477 
6478  if( nchildren > 0 )
6479  {
6480  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6481  }
6482  else
6483  childrencopy = NULL;
6484 
6485  /* we store the coefficients and the constant in a single array and make this our operand data */
6486  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, nchildren + 1) );
6487  BMScopyMemoryArray(data, coefs, nchildren); /*lint !e644*/
6488  data[nchildren] = constant;
6489 
6490  opdata.data = (void*)data;
6491 
6492  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_LINEAR, nchildren, childrencopy, opdata) );
6493 
6494  return SCIP_OKAY;
6495 }
6496 
6497 /** adds new terms to a linear expression */
6499  BMS_BLKMEM* blkmem, /**< block memory */
6500  SCIP_EXPR* expr, /**< linear expression */
6501  int nchildren, /**< number of children to add */
6502  SCIP_Real* coefs, /**< coefficients of additional children */
6503  SCIP_EXPR** children, /**< additional children expressions */
6504  SCIP_Real constant /**< constant to add */
6505  )
6506 {
6507  SCIP_Real* data;
6508 
6509  assert(blkmem != NULL);
6510  assert(expr != NULL);
6511  assert(expr->op == SCIP_EXPR_LINEAR);
6512  assert(nchildren >= 0);
6513  assert(coefs != NULL || nchildren == 0);
6514  assert(children != NULL || nchildren == 0);
6515 
6516  data = (SCIP_Real*)expr->data.data;
6517  assert(data != NULL);
6518 
6519  /* handle simple case of adding a constant */
6520  if( nchildren == 0 )
6521  {
6522  data[expr->nchildren] += constant;
6523 
6524  return SCIP_OKAY;
6525  }
6526 
6527  /* add new children to expr's children array */
6528  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nchildren) );
6529  BMScopyMemoryArray(&expr->children[expr->nchildren], children, nchildren); /*lint !e866*/
6530 
6531  /* add constant and new coefs to expr's data array */
6532  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, expr->nchildren + 1, expr->nchildren + nchildren + 1) );
6533  data[expr->nchildren + nchildren] = data[expr->nchildren] + constant;
6534  BMScopyMemoryArray(&data[expr->nchildren], coefs, nchildren); /*lint !e866*/
6535  expr->data.data = (void*)data;
6536 
6537  expr->nchildren += nchildren;
6538 
6539  return SCIP_OKAY;
6540 }
6541 
6542 /** creates a SCIP_EXPR_QUADRATIC expression: constant + sum_i coef_i child_i + sum_i coef_i child1_i child2_i */
6544  BMS_BLKMEM* blkmem, /**< block memory data structure */
6545  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6546  int nchildren, /**< number of children */
6547  SCIP_EXPR** children, /**< children of expression */
6548  SCIP_Real constant, /**< constant */
6549  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
6550  int nquadelems, /**< number of quadratic elements */
6551  SCIP_QUADELEM* quadelems /**< quadratic elements specifying coefficients and child indices */
6552  )
6553 {
6554  SCIP_EXPROPDATA opdata;
6555  SCIP_EXPR** childrencopy;
6557 
6558  assert(nchildren >= 0);
6559  assert(children != NULL || nchildren == 0);
6560  assert(quadelems != NULL || nquadelems == 0);
6561 
6562  if( nchildren > 0 )
6563  {
6564  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6565  }
6566  else
6567  childrencopy = NULL;
6568 
6569  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
6570 
6571  opdata.data = (void*)data;
6572 
6573  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_QUADRATIC, nchildren, childrencopy, opdata) );
6574 
6575  return SCIP_OKAY;
6576 }
6577 
6578 /** ensures that quadratic elements of a quadratic expression are sorted */
6580  SCIP_EXPR* expr /**< quadratic expression */
6581  )
6582 {
6583  assert(expr != NULL);
6584  assert(expr->op == SCIP_EXPR_QUADRATIC);
6585  assert(expr->data.data != NULL);
6586 
6588 }
6589 
6590 /** creates a SCIP_EXPR_POLYNOMIAL expression from an array of monomials: constant + sum_i monomial_i */
6592  BMS_BLKMEM* blkmem, /**< block memory data structure */
6593  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6594  int nchildren, /**< number of children */
6595  SCIP_EXPR** children, /**< children of expression */
6596  int nmonomials, /**< number of monomials */
6597  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
6598  SCIP_Real constant, /**< constant part */
6599  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6600  )
6601 {
6602  SCIP_EXPROPDATA opdata;
6603  SCIP_EXPR** childrencopy;
6605 
6606  assert(nchildren >= 0);
6607  assert(children != NULL || nchildren == 0);
6608  assert(monomials != NULL || nmonomials == 0);
6609 
6610  if( nchildren > 0 )
6611  {
6612  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6613  }
6614  else
6615  childrencopy = NULL;
6616 
6617  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
6618  opdata.data = (void*)data;
6619 
6620  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_POLYNOMIAL, nchildren, childrencopy, opdata) );
6621 
6622  return SCIP_OKAY;
6623 }
6624 
6625 /** adds an array of monomials to a SCIP_EXPR_POLYNOMIAL expression */
6627  BMS_BLKMEM* blkmem, /**< block memory of expression */
6628  SCIP_EXPR* expr, /**< expression */
6629  int nmonomials, /**< number of monomials to add */
6630  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
6631  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6632  )
6633 {
6634  assert(blkmem != NULL);
6635  assert(expr != NULL);
6636  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6637  assert(monomials != NULL || nmonomials == 0);
6638 
6639  if( nmonomials == 0 )
6640  return SCIP_OKAY;
6641 
6642  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, nmonomials, monomials, copymonomials) );
6643 
6644  return SCIP_OKAY;
6645 }
6646 
6647 /** changes the constant in a SCIP_EXPR_POLYNOMIAL expression */
6649  SCIP_EXPR* expr, /**< expression */
6650  SCIP_Real constant /**< new value for constant */
6651  )
6652 {
6653  assert(expr != NULL);
6654  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6655  assert(expr->data.data != NULL);
6656 
6657  ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant = constant;
6658 }
6659 
6660 /** multiplies each summand of a polynomial by a given constant */
6662  BMS_BLKMEM* blkmem, /**< block memory */
6663  SCIP_EXPR* expr, /**< polynomial expression */
6664  SCIP_Real factor /**< constant factor */
6665  )
6666 {
6667  assert(expr != NULL);
6668  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6669  assert(expr->data.data != NULL);
6670 
6671  polynomialdataMultiplyByConstant(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor);
6672 }
6673 
6674 /** multiplies each summand of a polynomial by a given monomial */
6676  BMS_BLKMEM* blkmem, /**< block memory */
6677  SCIP_EXPR* expr, /**< polynomial expression */
6678  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
6679  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6680  )
6681 {
6682  assert(blkmem != NULL);
6683  assert(factor != NULL);
6684  assert(expr != NULL);
6685  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6686  assert(expr->data.data != NULL);
6687 
6688  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor, childmap) );
6689 
6690  return SCIP_OKAY;
6691 }
6692 
6693 /** multiplies this polynomial by a polynomial
6694  *
6695  * Factor needs to be different from expr.
6696  * Children of factor need to be children of expr already, w.r.t. an optional mapping of child indices.
6697  */
6699  BMS_BLKMEM* blkmem, /**< block memory */
6700  SCIP_EXPR* expr, /**< polynomial expression */
6701  SCIP_EXPR* factor, /**< polynomial factor */
6702  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6703  )
6704 {
6705  assert(blkmem != NULL);
6706  assert(expr != NULL);
6707  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6708  assert(expr->data.data != NULL);
6709  assert(factor != NULL);
6710  assert(factor->op == SCIP_EXPR_POLYNOMIAL);
6711  assert(factor->data.data != NULL);
6712  assert(expr != factor);
6713 
6714 #ifndef NDEBUG
6715  if( childmap == NULL )
6716  {
6717  int i;
6718  assert(factor->nchildren == expr->nchildren);
6719  for( i = 0; i < factor->nchildren; ++i )
6720  assert(SCIPexprAreEqual(expr->children[i], factor->children[i], 0.0));
6721  }
6722  else
6723  {
6724  int i;
6725  for( i = 0; i < factor->nchildren; ++i )
6726  {
6727  assert(childmap[i] >= 0);
6728  assert(childmap[i] < expr->nchildren);
6729  assert(SCIPexprAreEqual(expr->children[childmap[i]], factor->children[i], 0.0));
6730  }
6731  }
6732 #endif
6733 
6735 
6736  return SCIP_OKAY;
6737 }
6738 
6739 /** takes a power of the polynomial
6740  *
6741  * Exponent need to be an integer.
6742  * Polynomial needs to be a monomial, if exponent is negative.
6743  */
6745  BMS_BLKMEM* blkmem, /**< block memory */
6746  SCIP_EXPR* expr, /**< polynomial expression */
6747  int exponent /**< exponent of power operation */
6748  )
6749 {
6750  assert(blkmem != NULL);
6751  assert(expr != NULL);
6752  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6753  assert(expr->data.data != NULL);
6754 
6755  SCIP_CALL( polynomialdataPower(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, exponent) );
6756 
6757  return SCIP_OKAY;
6758 }
6759 
6760 /** merges monomials in a polynomial expression that differ only in coefficient into a single monomial
6761  *
6762  * Eliminates monomials with coefficient between -eps and eps.
6763  */
6765  BMS_BLKMEM* blkmem, /**< block memory */
6766  SCIP_EXPR* expr, /**< polynomial expression */
6767  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
6768  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
6769  )
6770 {
6771  assert(expr != NULL);
6772  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6773  assert(expr->data.data != NULL);
6774 
6775  polynomialdataMergeMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, eps, mergefactors);
6776 }
6777 
6778 /** checks if two monomials are equal */
6780  SCIP_EXPRDATA_MONOMIAL* monomial1, /**< first monomial */
6781  SCIP_EXPRDATA_MONOMIAL* monomial2, /**< second monomial */
6782  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6783  )
6784 {
6785  int i;
6786 
6787  assert(monomial1 != NULL);
6788  assert(monomial2 != NULL);
6789 
6790  if( monomial1->nfactors != monomial2->nfactors )
6791  return FALSE;
6792 
6793  if( !EPSEQ(monomial1->coef, monomial2->coef, eps) )
6794  return FALSE;
6795 
6796  SCIPexprSortMonomialFactors(monomial1);
6797  SCIPexprSortMonomialFactors(monomial2);
6798 
6799  for( i = 0; i < monomial1->nfactors; ++i )
6800  {
6801  if( monomial1->childidxs[i] != monomial2->childidxs[i] ||
6802  !EPSEQ(monomial1->exponents[i], monomial2->exponents[i], eps) )
6803  return FALSE;
6804  }
6805 
6806  return TRUE;
6807 }
6808 
6809 /** changes coefficient of monomial */
6811  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6812  SCIP_Real newcoef /**< new coefficient */
6813  )
6814 {
6815  assert(monomial != NULL);
6816 
6817  monomial->coef = newcoef;
6818 }
6819 
6820 /** adds factors to a monomial */
6822  BMS_BLKMEM* blkmem, /**< block memory */
6823  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6824  int nfactors, /**< number of factors to add */
6825  int* childidxs, /**< indices of children corresponding to factors */
6826  SCIP_Real* exponents /**< exponent in each factor */
6827  )
6828 {
6829  assert(monomial != NULL);
6830  assert(nfactors >= 0);
6831  assert(childidxs != NULL || nfactors == 0);
6832  assert(exponents != NULL || nfactors == 0);
6833 
6834  if( nfactors == 0 )
6835  return SCIP_OKAY;
6836 
6837  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + nfactors) );
6838  assert(monomial->nfactors + nfactors <= monomial->factorssize);
6839 
6840  BMScopyMemoryArray(&monomial->childidxs[monomial->nfactors], childidxs, nfactors); /*lint !e866*/
6841  BMScopyMemoryArray(&monomial->exponents[monomial->nfactors], exponents, nfactors); /*lint !e866*/
6842 
6843  monomial->nfactors += nfactors;
6844  monomial->sorted = (monomial->nfactors <= 1);
6845 
6846  return SCIP_OKAY;
6847 }
6848 
6849 /** multiplies a monomial with a monomial */
6851  BMS_BLKMEM* blkmem, /**< block memory */
6852  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6853  SCIP_EXPRDATA_MONOMIAL* factor, /**< factor monomial */
6854  int* childmap /**< map to apply to children in factor, or NULL for 1:1 */
6855  )
6856 {
6857  assert(monomial != NULL);
6858  assert(factor != NULL);
6859 
6860  if( factor->coef == 0.0 )
6861  {
6862  monomial->nfactors = 0;
6863  monomial->coef = 0.0;
6864  return SCIP_OKAY;
6865  }
6866 
6867  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, factor->nfactors, factor->childidxs, factor->exponents) );
6868 
6869  if( childmap != NULL )
6870  {
6871  int i;
6872  for( i = monomial->nfactors - factor->nfactors; i < monomial->nfactors; ++i )
6873  monomial->childidxs[i] = childmap[monomial->childidxs[i]];
6874  }
6875 
6876  monomial->coef *= factor->coef;
6877 
6878  return SCIP_OKAY;
6879 }
6880 
6881 /** replaces the monomial by a power of the monomial
6882  *
6883  * Allows only integers as exponent.
6884  */
6886  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6887  int exponent /**< integer exponent of power operation */
6888  )
6889 {
6890  int i;
6891 
6892  assert(monomial != NULL);
6893 
6894  if( exponent == 1 )
6895  return;
6896 
6897  if( exponent == 0 )
6898  {
6899  /* x^0 = 1, unless x = 0; 0^0 = 0 */
6900  if( monomial->coef != 0.0 )
6901  monomial->coef = 1.0;
6902  monomial->nfactors = 0;
6903  return;
6904  }
6905 
6906  monomial->coef = pow(monomial->coef, (SCIP_Real)exponent);
6907  for( i = 0; i < monomial->nfactors; ++i )
6908  monomial->exponents[i] *= exponent;
6909 }
6910 
6911 /** merges factors that correspond to the same child by adding exponents
6912  *
6913  * Eliminates factors with exponent between -eps and eps.
6914  */
6916  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6917  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6918  )
6919 {
6920  int i;
6921  int offset;
6922 
6923  assert(monomial != NULL);
6924  assert(eps >= 0.0);
6925 
6926  SCIPexprSortMonomialFactors(monomial);
6927 
6928  /* merge factors with same child index by adding up their exponents
6929  * delete factors with exponent 0.0 */
6930  offset = 0;
6931  i = 0;
6932  while( i + offset < monomial->nfactors )
6933  {
6934  if( offset > 0 )
6935  {
6936  assert(monomial->childidxs[i] == -1);
6937  assert(monomial->childidxs[i+offset] >= 0);
6938  monomial->childidxs[i] = monomial->childidxs[i+offset];
6939  monomial->exponents[i] = monomial->exponents[i+offset];
6940 #ifndef NDEBUG
6941  monomial->childidxs[i+offset] = -1;
6942 #endif
6943  }
6944 
6945  while( i+offset+1 < monomial->nfactors && monomial->childidxs[i] == monomial->childidxs[i+offset+1] )
6946  {
6947  monomial->exponents[i] += monomial->exponents[i+offset+1];
6948 #ifndef NDEBUG
6949  monomial->childidxs[i+offset+1] = -1;
6950 #endif
6951  ++offset;
6952  }
6953 
6954  if( EPSZ(monomial->exponents[i], eps) )
6955  {
6956 #ifndef NDEBUG
6957  monomial->childidxs[i] = -1;
6958 #endif
6959  ++offset;
6960  continue;
6961  }
6962  else if( EPSISINT(monomial->exponents[i], eps) )
6963  monomial->exponents[i] = EPSROUND(monomial->exponents[i], eps);
6964 
6965  ++i;
6966  }
6967 
6968 #ifndef NDEBUG
6969  for( ; i < monomial->nfactors; ++i )
6970  assert(monomial->childidxs[i] == -1);
6971 #endif
6972 
6973  monomial->nfactors -= offset;
6974 
6975  if( EPSEQ(monomial->coef, 1.0, eps) )
6976  monomial->coef = 1.0;
6977  else if( EPSEQ(monomial->coef, -1.0, eps) )
6978  monomial->coef = -1.0;
6979 }
6980 
6981 /** ensures that monomials of a polynomial are sorted */
6983  SCIP_EXPR* expr /**< polynomial expression */
6984  )
6985 {
6986  assert(expr != NULL);
6987  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6988  assert(expr->data.data != NULL);
6989 
6991 }
6992 
6993 /** creates a monomial */
6995  BMS_BLKMEM* blkmem, /**< block memory */
6996  SCIP_EXPRDATA_MONOMIAL** monomial, /**< buffer where to store pointer to new monomial */
6997  SCIP_Real coef, /**< coefficient of monomial */
6998  int nfactors, /**< number of factors in monomial */
6999  int* childidxs, /**< indices of children corresponding to factors, or NULL if identity */
7000  SCIP_Real* exponents /**< exponent in each factor, or NULL if all 1.0 */
7001  )
7002 {
7003  assert(blkmem != NULL);
7004  assert(monomial != NULL);
7005 
7006  SCIP_ALLOC( BMSallocBlockMemory(blkmem, monomial) );
7007 
7008  (*monomial)->coef = coef;
7009  (*monomial)->nfactors = nfactors;
7010  (*monomial)->factorssize = nfactors;
7011  (*monomial)->sorted = (nfactors <= 1);
7012 
7013  if( nfactors > 0 )
7014  {
7015  if( childidxs != NULL )
7016  {
7017  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->childidxs, childidxs, nfactors) );
7018  }
7019  else
7020  {
7021  int i;
7022 
7023  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->childidxs, nfactors) );
7024  for( i = 0; i < nfactors; ++i )
7025  (*monomial)->childidxs[i] = i;
7026  }
7027 
7028  if( exponents != NULL )
7029  {
7030  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->exponents, exponents, nfactors) );
7031  }
7032  else
7033  {
7034  int i;
7035 
7036  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->exponents, nfactors) );
7037  for( i = 0; i < nfactors; ++i )
7038  (*monomial)->exponents[i] = 1.0;
7039  }
7040  }
7041  else
7042  {
7043  (*monomial)->childidxs = NULL;
7044  (*monomial)->exponents = NULL;
7045  }
7046 
7047  return SCIP_OKAY;
7048 }
7049 
7050 /** frees a monomial */
7052  BMS_BLKMEM* blkmem, /**< block memory */
7053  SCIP_EXPRDATA_MONOMIAL** monomial /**< pointer to monomial that should be freed */
7054  )
7055 {
7056  assert(blkmem != NULL);
7057  assert( monomial != NULL);
7058  assert(*monomial != NULL);
7059 
7060  if( (*monomial)->factorssize > 0 )
7061  {
7062  assert((*monomial)->childidxs != NULL);
7063  assert((*monomial)->exponents != NULL);
7064 
7065  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->childidxs, (*monomial)->factorssize);
7066  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->exponents, (*monomial)->factorssize);
7067  }
7068  assert((*monomial)->childidxs == NULL);
7069  assert((*monomial)->exponents == NULL);
7070 
7071  BMSfreeBlockMemory(blkmem, monomial);
7072 }
7073 
7074 /** ensures that factors in a monomial are sorted */
7076  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
7077  )
7078 {
7079  assert(monomial != NULL);
7080 
7081  if( monomial->sorted )
7082  return;
7083 
7084  if( monomial->nfactors > 0 )
7085  SCIPsortIntReal(monomial->childidxs, monomial->exponents, monomial->nfactors);
7086 
7087  monomial->sorted = TRUE;
7088 }
7089 
7090 /** finds a factor corresponding to a given child index in a monomial
7091  *
7092  * Note that if the factors have not been merged, the position of some factor corresponding to a given child is given.
7093  * Returns TRUE if a factor is found, FALSE if not.
7094  */
7096  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
7097  int childidx, /**< index of the child which factor to search for */
7098  int* pos /**< buffer to store position of factor */
7099  )
7100 {
7101  assert(monomial != NULL);
7102 
7103  if( monomial->nfactors == 0 )
7104  return FALSE;
7105 
7106  SCIPexprSortMonomialFactors(monomial);
7107 
7108  return SCIPsortedvecFindInt(monomial->childidxs, childidx, monomial->nfactors, pos);
7109 }
7110 
7111 /** creates a user expression */
7113  BMS_BLKMEM* blkmem, /**< block memory data structure */
7114  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
7115  int nchildren, /**< number of children */
7116  SCIP_EXPR** children, /**< children of expression */
7117  SCIP_USEREXPRDATA* data, /**< user data for expression, expression assumes ownership */
7118  SCIP_EXPRINTCAPABILITY evalcapability, /**< capability of evaluation functions (partially redundant, currently) */
7119  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
7120  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function, or NULL if not implemented */
7121  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
7122  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function, or NULL if not implemented */
7123  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
7124  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
7125  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
7126  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
7127  )
7128 {
7129  SCIP_EXPROPDATA opdata;
7130  SCIP_EXPRDATA_USER* userexprdata;
7131  SCIP_EXPR** childrencopy;
7132 
7133  assert(blkmem != NULL);
7134  assert(expr != NULL);
7135  assert(eval != NULL);
7136  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
7137  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
7138  assert(curv != NULL);
7139  assert(copydata != NULL || data == NULL);
7140  assert(freedata != NULL || data == NULL);
7141 
7142  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &userexprdata) );
7143 
7144  userexprdata->userdata = data;
7145  userexprdata->evalcapability = evalcapability;
7146  userexprdata->eval = eval;
7147  userexprdata->inteval = inteval;
7148  userexprdata->curv = curv;
7149  userexprdata->prop = prop;
7150  userexprdata->estimate = estimate;
7151  userexprdata->copydata = copydata;
7152  userexprdata->freedata = freedata;
7153  userexprdata->print = print;
7154 
7155  opdata.data = (void*) userexprdata;
7156 
7157  if( nchildren == 0 )
7158  {
7159  SCIP_CALL( exprCreate(blkmem, expr, SCIP_EXPR_USER, 0, NULL, opdata) );
7160  return SCIP_OKAY;
7161  }
7162  assert(children != NULL);
7163 
7164  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
7165 
7166  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_USER, nchildren, childrencopy, opdata) );
7167 
7168  return SCIP_OKAY;
7169 }
7170 
7171 /** indicates whether the expression contains a SCIP_EXPR_PARAM */
7173  SCIP_EXPR* expr /**< expression */
7174  )
7175 {
7176  int i;
7177 
7178  assert(expr != NULL);
7179 
7180  if( expr->op == SCIP_EXPR_PARAM )
7181  return TRUE;
7182 
7183  for( i = 0; i < expr->nchildren; ++i )
7184  if( SCIPexprHasParam(expr->children[i]) )
7185  return TRUE;
7186 
7187  return FALSE;
7188 }
7189 
7190 /** gets maximal degree of expression, or SCIP_EXPR_DEGREEINFINITY if not a polynomial */
7192  SCIP_EXPR* expr, /**< expression */
7193  int* maxdegree /**< buffer to store maximal degree */
7194  )
7195 {
7196  int child1;
7197  int child2;
7198 
7199  assert(expr != NULL);
7200  assert(maxdegree != NULL);
7201 
7202  switch( expr->op )
7203  {
7204  case SCIP_EXPR_VARIDX:
7205  *maxdegree = 1;
7206  break;
7207 
7208  case SCIP_EXPR_CONST:
7209  case SCIP_EXPR_PARAM:
7210  *maxdegree = 0;
7211  break;
7212 
7213  case SCIP_EXPR_PLUS:
7214  case SCIP_EXPR_MINUS:
7215  {
7216  assert(expr->children[0] != NULL);
7217  assert(expr->children[1] != NULL);
7218 
7219  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7220  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7221 
7222  *maxdegree = MAX(child1, child2);
7223  break;
7224  }
7225 
7226  case SCIP_EXPR_MUL:
7227  {
7228  assert(expr->children[0] != NULL);
7229  assert(expr->children[1] != NULL);
7230 
7231  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7232  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7233 
7234  *maxdegree = child1 + child2;
7235  break;
7236  }
7237 
7238  case SCIP_EXPR_DIV:
7239  {
7240  assert(expr->children[0] != NULL);
7241  assert(expr->children[1] != NULL);
7242 
7243  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7244  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7245 
7246  /* if not division by constant, then it is not a polynomial */
7247  *maxdegree = (child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : child1;
7248  break;
7249  }
7250 
7251  case SCIP_EXPR_SQUARE:
7252  {
7253  assert(expr->children[0] != NULL);
7254 
7255  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7256 
7257  *maxdegree = 2 * child1;
7258  break;
7259  }
7260 
7261  case SCIP_EXPR_SQRT:
7262  {
7263  assert(expr->children[0] != NULL);
7264 
7265  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7266 
7267  /* if not squareroot of constant, then no polynomial */
7268  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7269  break;
7270  }
7271 
7272  case SCIP_EXPR_REALPOWER:
7273  {
7274  assert(expr->children[0] != NULL);
7275 
7276  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7277 
7278  /* constant ^ constant has degree 0 */
7279  if( child1 == 0 )
7280  {
7281  *maxdegree = 0;
7282  break;
7283  }
7284 
7285  /* non-polynomial ^ constant is not a polynomial */
7286  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7287  {
7288  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7289  break;
7290  }
7291 
7292  /* so it is polynomial ^ constant
7293  * let's see whether the constant is integral */
7294 
7295  if( expr->data.dbl == 0.0 ) /* polynomial ^ 0 == 0 */
7296  *maxdegree = 0;
7297  else if( expr->data.dbl > 0.0 && (int)expr->data.dbl == expr->data.dbl ) /* natural exponent gives polynomial again */ /*lint !e777*/
7298  *maxdegree = child1 * (int)expr->data.dbl;
7299  else /* negative or nonintegral exponent does not give polynomial */
7300  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7301 
7302  break;
7303  }
7304 
7305  case SCIP_EXPR_INTPOWER:
7306  {
7307  assert(expr->children[0] != NULL);
7308 
7309  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7310 
7311  /* constant ^ integer or something ^ 0 has degree 0 */
7312  if( child1 == 0 || expr->data.intval == 0 )
7313  {
7314  *maxdegree = 0;
7315  break;
7316  }
7317 
7318  /* non-polynomial ^ integer or something ^ negative is not a polynomial */
7319  if( child1 >= SCIP_EXPR_DEGREEINFINITY || expr->data.intval < 0 )
7320  {
7321  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7322  break;
7323  }
7324 
7325  /* so it is polynomial ^ natural, which gives a polynomial again */
7326  *maxdegree = child1 * expr->data.intval;
7327 
7328  break;
7329  }
7330 
7331  case SCIP_EXPR_SIGNPOWER:
7332  {
7333  assert(expr->children[0] != NULL);
7334 
7335  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7336 
7337  /* if child is not constant, then it is no polynomial */
7338  *maxdegree = child1 != 0 ? SCIP_EXPR_DEGREEINFINITY : 0;
7339  break;
7340  }
7341 
7342  case SCIP_EXPR_EXP:
7343  case SCIP_EXPR_LOG:
7344  case SCIP_EXPR_SIN:
7345  case SCIP_EXPR_COS:
7346  case SCIP_EXPR_TAN:
7347  /* case SCIP_EXPR_ERF: */
7348  /* case SCIP_EXPR_ERFI: */
7349  case SCIP_EXPR_ABS:
7350  case SCIP_EXPR_SIGN:
7351  case SCIP_EXPR_USER:
7352  {
7353  assert(expr->children[0] != NULL);
7354 
7355  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7356 
7357  /* if argument is not a constant, then no polynomial, otherwise it is a constant */
7358  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7359  break;
7360  }
7361 
7362  case SCIP_EXPR_MIN:
7363  case SCIP_EXPR_MAX:
7364  {
7365  assert(expr->children[0] != NULL);
7366  assert(expr->children[1] != NULL);
7367 
7368  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7369  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7370 
7371  /* if any of the operands is not constant, then it is no polynomial */
7372  *maxdegree = (child1 != 0 || child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7373  break;
7374  }
7375 
7376  case SCIP_EXPR_SUM:
7377  case SCIP_EXPR_LINEAR:
7378  {
7379  int i;
7380 
7381  *maxdegree = 0;
7382  for( i = 0; i < expr->nchildren && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7383  {
7384  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7385  if( child1 > *maxdegree )
7386  *maxdegree = child1;
7387  }
7388 
7389  break;
7390  }
7391 
7392  case SCIP_EXPR_PRODUCT:
7393  {
7394  int i;
7395 
7396  *maxdegree = 0;
7397  for( i = 0; i < expr->nchildren; ++i )
7398  {
7399  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7400  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7401  {
7402  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7403  break;
7404  }
7405  *maxdegree += child1;
7406  }
7407 
7408  break;
7409  }
7410 
7411  case SCIP_EXPR_QUADRATIC:
7412  {
7413  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7414  int childidx;
7415  int quadidx;
7416 
7417  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7418 
7419  /* make sure quadratic elements are sorted */
7420  quadraticdataSort(quadraticdata);
7421 
7422  *maxdegree = 0;
7423  quadidx = 0;
7424  for( childidx = 0; childidx < expr->nchildren; ++childidx )
7425  {
7426  /* if no linear or no quadratic coefficient with current child on first position, then nothing to do */
7427  if( (quadraticdata->lincoefs == NULL || quadraticdata->lincoefs[childidx] == 0.0) &&
7428  (quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 > childidx) )
7429  continue;
7430 
7431  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[childidx], &child1) );
7432  if( child1 == SCIP_EXPR_DEGREEINFINITY )
7433  {
7434  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7435  break;
7436  }
7437 
7438  while( quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 == childidx )
7439  {
7440  if( quadraticdata->quadelems[quadidx].idx2 == childidx )
7441  {
7442  /* square term */
7443  if( 2*child1 > *maxdegree )
7444  *maxdegree = 2*child1;
7445  }
7446  else
7447  {
7448  /* bilinear term */
7449  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[quadraticdata->quadelems[quadidx].idx2], &child2) );
7450  if( child2 == SCIP_EXPR_DEGREEINFINITY )
7451  {
7452  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7453  break;
7454  }
7455  if( child1 + child2 > *maxdegree )
7456  *maxdegree = child1 + child2;
7457  }
7458  ++quadidx;
7459  }
7460  if( *maxdegree == SCIP_EXPR_DEGREEINFINITY )
7461  break;
7462  }
7463 
7464  break;
7465  }
7466 
7467  case SCIP_EXPR_POLYNOMIAL:
7468  {
7469  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7470  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7471  int monomialdegree;
7472  int i;
7473  int j;
7474 
7475  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7476 
7477  *maxdegree = 0;
7478  for( i = 0; i < polynomialdata->nmonomials && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7479  {
7480  monomialdata = polynomialdata->monomials[i];
7481  assert(monomialdata != NULL);
7482 
7483  /* compute degree of monomial = sum of degree of factors */
7484  monomialdegree = 0;
7485  for( j = 0; j < monomialdata->nfactors; ++j )
7486  {
7487  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[monomialdata->childidxs[j]], &child1) );
7488 
7489  /* if the exponent of the factor is not a natural number and the child is not constant (degree 0),
7490  * then we report that we are not really a polynomial */
7491  if( child1 != 0 && (monomialdata->exponents[j] < 0.0 || (int)monomialdata->exponents[j] != monomialdata->exponents[j]) )
7492  {
7493  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7494  break;
7495  }
7496 
7497  monomialdegree += child1 * (int)monomialdata->exponents[j];
7498  }
7499 
7500  if( monomialdegree > *maxdegree )
7501  *maxdegree = monomialdegree;
7502  }
7503 
7504  break;
7505  }
7506 
7507  case SCIP_EXPR_LAST:
7508  SCIPABORT();
7509  break;
7510  }
7511 
7512  return SCIP_OKAY;
7513 }
7514 
7515 /** counts usage of variables in expression */
7517  SCIP_EXPR* expr, /**< expression to update */
7518  int* varsusage /**< array with counters of variable usage */
7519  )
7520 {
7521  int i;
7522 
7523  assert(expr != NULL);
7524  assert(varsusage != NULL);
7525 
7526  if( expr->op == SCIP_EXPR_VARIDX )
7527  {
7528  ++varsusage[expr->data.intval];
7529  }
7530 
7531  for( i = 0; i < expr->nchildren; ++i )
7532  SCIPexprGetVarsUsage(expr->children[i], varsusage);
7533 }
7534 
7535 /** compares whether two expressions are the same
7536  *
7537  * Inconclusive, i.e., may give FALSE even if expressions are equivalent (x*y != y*x).
7538  */
7540  SCIP_EXPR* expr1, /**< first expression */
7541  SCIP_EXPR* expr2, /**< second expression */
7542  SCIP_Real eps /**< threshold under which numbers are assumed to be zero */
7543  )
7544 {
7545  assert(expr1 != NULL);
7546  assert(expr2 != NULL);
7547 
7548  if( expr1 == expr2 )
7549  return TRUE;
7550 
7551  if( expr1->op != expr2->op )
7552  return FALSE;
7553 
7554  switch( expr1->op )
7555  {
7556  case SCIP_EXPR_VARIDX:
7557  case SCIP_EXPR_PARAM:
7558  return expr1->data.intval == expr2->data.intval;
7559 
7560  case SCIP_EXPR_CONST:
7561  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps);
7562 
7563  /* operands with two children */
7564  case SCIP_EXPR_PLUS :
7565  case SCIP_EXPR_MINUS :
7566  case SCIP_EXPR_MUL :
7567  case SCIP_EXPR_DIV :
7568  case SCIP_EXPR_MIN :
7569  case SCIP_EXPR_MAX :
7570  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps) && SCIPexprAreEqual(expr1->children[1], expr2->children[1], eps);
7571 
7572  /* operands with one child */
7573  case SCIP_EXPR_SQUARE:
7574  case SCIP_EXPR_SQRT :
7575  case SCIP_EXPR_EXP :
7576  case SCIP_EXPR_LOG :
7577  case SCIP_EXPR_SIN :
7578  case SCIP_EXPR_COS :
7579  case SCIP_EXPR_TAN :
7580  /* case SCIP_EXPR_ERF : */
7581  /* case SCIP_EXPR_ERFI : */
7582  case SCIP_EXPR_ABS :
7583  case SCIP_EXPR_SIGN :
7584  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7585 
7586  case SCIP_EXPR_REALPOWER:
7587  case SCIP_EXPR_SIGNPOWER:
7588  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps) && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7589 
7590  case SCIP_EXPR_INTPOWER:
7591  return expr1->data.intval == expr2->data.intval && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7592 
7593  /* complex operands */
7594  case SCIP_EXPR_SUM :
7595  case SCIP_EXPR_PRODUCT:
7596  {
7597  int i;
7598 
7599  /* @todo sort children and have sorted flag in data? */
7600 
7601  if( expr1->nchildren != expr2->nchildren )
7602  return FALSE;
7603 
7604  for( i = 0; i < expr1->nchildren; ++i )
7605  {
7606  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7607  return FALSE;
7608  }
7609 
7610  return TRUE;
7611  }
7612 
7613  case SCIP_EXPR_LINEAR :
7614  {
7615  SCIP_Real* data1;
7616  SCIP_Real* data2;
7617  int i;
7618 
7619  /* @todo sort children and have sorted flag in data? */
7620 
7621  if( expr1->nchildren != expr2->nchildren )
7622  return FALSE;
7623 
7624  data1 = (SCIP_Real*)expr1->data.data;
7625  data2 = (SCIP_Real*)expr2->data.data;
7626 
7627  /* check if constant and coefficients are equal */
7628  for( i = 0; i < expr1->nchildren + 1; ++i )
7629  if( !EPSEQ(data1[i], data2[i], eps) )
7630  return FALSE;
7631 
7632  /* check if children are equal */
7633  for( i = 0; i < expr1->nchildren; ++i )
7634  {
7635  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7636  return FALSE;
7637  }
7638 
7639  return TRUE;
7640  }
7641 
7642  case SCIP_EXPR_QUADRATIC:
7643  {
7644  SCIP_EXPRDATA_QUADRATIC* data1;
7645  SCIP_EXPRDATA_QUADRATIC* data2;
7646  int i;
7647 
7648  if( expr1->nchildren != expr2->nchildren )
7649  return FALSE;
7650 
7651  data1 = (SCIP_EXPRDATA_QUADRATIC*)expr1->data.data;
7652  data2 = (SCIP_EXPRDATA_QUADRATIC*)expr2->data.data;
7653 
7654  if( data1->nquadelems != data2->nquadelems )
7655  return FALSE;
7656 
7657  if( !EPSEQ(data1->constant, data2->constant, eps) )
7658  return FALSE;
7659 
7660  /* check if linear part is equal */
7661  if( data1->lincoefs != NULL || data2->lincoefs != NULL )
7662  for( i = 0; i < expr1->nchildren; ++i )
7663  {
7664  if( data1->lincoefs == NULL )
7665  {
7666  if( !EPSZ(data2->lincoefs[i], eps) )
7667  return FALSE;
7668  }
7669  else if( data2->lincoefs == NULL )
7670  {
7671  if( !EPSZ(data1->lincoefs[i], eps) )
7672  return FALSE;
7673  }
7674  else if( !EPSEQ(data1->lincoefs[i], data2->lincoefs[i], eps) )
7675  return FALSE;
7676  }
7677 
7678  SCIPexprSortQuadElems(expr1);
7679  SCIPexprSortQuadElems(expr2);
7680 
7681  /* check if quadratic elements are equal */
7682  for( i = 0; i < data1->nquadelems; ++i )
7683  if( data1->quadelems[i].idx1 != data2->quadelems[i].idx1 ||
7684  data1->quadelems[i].idx2 != data2->quadelems[i].idx2 ||
7685  !EPSEQ(data1->quadelems[i].coef, data2->quadelems[i].coef, eps) )
7686  return FALSE;
7687 
7688  /* check if children are equal */
7689  for( i = 0; i < expr1->nchildren; ++i )
7690  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7691  return FALSE;
7692 
7693  return TRUE;
7694  }
7695 
7696  case SCIP_EXPR_POLYNOMIAL:
7697  {
7698  SCIP_EXPRDATA_POLYNOMIAL* data1;
7699  SCIP_EXPRDATA_POLYNOMIAL* data2;
7700  int i;
7701 
7702  if( expr1->nchildren != expr2->nchildren )
7703  return FALSE;
7704 
7705  data1 = (SCIP_EXPRDATA_POLYNOMIAL*)expr1->data.data;
7706  data2 = (SCIP_EXPRDATA_POLYNOMIAL*)expr2->data.data;
7707 
7708  if( data1->nmonomials != data2->nmonomials )
7709  return FALSE;
7710 
7711  if( !EPSEQ(data1->constant, data2->constant, eps) )
7712  return FALSE;
7713 
7714  /* make sure polynomials are sorted */
7715  SCIPexprSortMonomials(expr1);
7716  SCIPexprSortMonomials(expr2);
7717 
7718  /* check if monomials are equal */
7719  for( i = 0; i < data1->nmonomials; ++i )
7720  {
7721  if( !SCIPexprAreMonomialsEqual(data1->monomials[i], data2->monomials[i], eps) )
7722  return FALSE;
7723  }
7724 
7725  /* check if children are equal */
7726  for( i = 0; i < expr1->nchildren; ++i )
7727  {
7728  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7729  return FALSE;
7730  }
7731 
7732  return TRUE;
7733  }
7734 
7735  case SCIP_EXPR_USER:
7736  {
7737  /* @todo could implement this via another user callback */
7738  return FALSE;
7739  }
7740 
7741  case SCIP_EXPR_LAST:
7742  break;
7743  }
7744 
7745  SCIPerrorMessage("this should never happen\n");
7746  SCIPABORT();
7747  return FALSE; /*lint !e527*/
7748 }
7749 
7750 /** aims at simplifying an expression and splitting of a linear expression
7751  *
7752  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
7753  */
7755  BMS_BLKMEM* blkmem, /**< block memory data structure */
7756  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7757  SCIP_EXPR* expr, /**< expression */
7758  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
7759  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
7760  int nvars, /**< number of variables in expression */
7761  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
7762  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
7763  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
7764  )
7765 {
7766  assert(blkmem != NULL);
7767  assert(expr != NULL);
7768  assert(eps >= 0.0);
7769 
7770  SCIPdebugMessage("simplify expression: ");
7771  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7772  SCIPdebugPrintf("\n");
7773 
7775 
7776  SCIPdebugMessage("converted to polynomials: ");
7777  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7778  SCIPdebugPrintf("\n");
7779 
7780  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr, eps, maxexpansionexponent) );
7781 
7782  SCIPdebugMessage("polynomials flattened: ");
7783  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7784  SCIPdebugPrintf("\n");
7785 
7786  if( nlinvars != NULL )
7787  {
7788  /* separate linear part from root polynomial */
7789  SCIP_CALL( exprsimplifySeparateLinearFromPolynomial(blkmem, expr, eps, nvars, nlinvars, linidxs, lincoefs) );
7790 
7791  SCIPdebugMessage("separated linear part: ");
7792  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7793  SCIPdebugPrintf("\n");
7794  }
7795 
7797 
7798  SCIPdebugMessage("converted back from polynomials: ");
7799  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7800  SCIPdebugPrintf("\n");
7801 
7802  return SCIP_OKAY;
7803 }
7804 
7805 /** evaluates an expression w.r.t. given values for children expressions */
7807  SCIP_EXPR* expr, /**< expression */
7808  SCIP_Real* argvals, /**< values for children, can be NULL if the expression has no children */
7809  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression operand is not a variable */
7810  SCIP_Real* param, /**< values for parameters, can be NULL if the expression operand is not a parameter */
7811  SCIP_Real* val /**< buffer to store value */
7812  )
7813 {
7814  assert(expr != NULL);
7815  assert(argvals != NULL || expr->nchildren == 0);
7816 
7817  /* evaluate this expression */
7818  assert( exprOpTable[expr->op].eval != NULL );
7819  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, argvals, varvals, param, val) );
7820 
7821  return SCIP_OKAY;
7822 }
7823 
7824 /** evaluates an expression w.r.t. a point */
7826  SCIP_EXPR* expr, /**< expression */
7827  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression is constant */
7828  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7829  SCIP_Real* val /**< buffer to store value */
7830  )
7831 {
7832  int i;
7834  SCIP_Real* buf;
7835 
7836  /* if many children, get large enough memory to store argument values */
7838  {
7839  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7840  }
7841  else
7842  {
7843  buf = staticbuf;
7844  }
7845 
7846  /* evaluate children */
7847  for( i = 0; i < expr->nchildren; ++i )
7848  {
7849  SCIP_CALL( SCIPexprEval(expr->children[i], varvals, param, &buf[i]) ); /*lint !e644*/
7850  }
7851 
7852  /* evaluate this expression */
7853  assert( exprOpTable[expr->op].eval != NULL );
7854  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, buf, varvals, param, val) );
7855 
7856  /* free memory, if allocated before */
7857  if( staticbuf != buf )
7858  {
7859  BMSfreeMemoryArray(&buf);
7860  }
7861 
7862  return SCIP_OKAY;
7863 }
7864 
7865 /** evaluates an expression w.r.t. given interval values for children expressions */
7867  SCIP_EXPR* expr, /**< expression */
7868  SCIP_Real infinity, /**< value to use for infinity */
7869  SCIP_INTERVAL* argvals, /**< interval values for children, can be NULL if the expression has no children */
7870  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7871  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7872  SCIP_INTERVAL* val /**< buffer to store value */
7873  )
7874 {
7875  assert(expr != NULL);
7876  assert(argvals != NULL || expr->nchildren == 0);
7877 
7878  /* evaluate this expression */
7879  assert( exprOpTable[expr->op].inteval != NULL );
7880  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, argvals, varvals, param, val) );
7881 
7882  return SCIP_OKAY;
7883 }
7884 
7885 /** evaluates an expression w.r.t. an interval */
7887  SCIP_EXPR* expr, /**< expression */
7888  SCIP_Real infinity, /**< value to use for infinity */
7889  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7890  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7891  SCIP_INTERVAL* val /**< buffer to store value */
7892  )
7893 {
7894  int i;
7896  SCIP_INTERVAL* buf;
7897 
7898  /* if many children, get large enough memory to store argument values */
7900  {
7901  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7902  }
7903  else
7904  {
7905  buf = staticbuf;
7906  }
7907 
7908  /* evaluate children */
7909  for( i = 0; i < expr->nchildren; ++i )
7910  {
7911  SCIP_CALL( SCIPexprEvalInt(expr->children[i], infinity, varvals, param, &buf[i]) ); /*lint !e644*/
7912  }
7913 
7914  /* evaluate this expression */
7915  assert( exprOpTable[expr->op].inteval != NULL );
7916  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, buf, varvals, param, val) );
7917 
7918  /* free memory, if allocated before */
7919  if( staticbuf != buf )
7920  {
7921  BMSfreeMemoryArray(&buf);
7922  }
7923 
7924  return SCIP_OKAY;
7925 }
7926 
7927 /** evaluates a user expression w.r.t. given values for children expressions */
7929  SCIP_EXPR* expr, /**< expression */
7930  SCIP_Real* argvals, /**< values for children */
7931  SCIP_Real* val, /**< buffer to store function value */
7932  SCIP_Real* gradient, /**< buffer to store gradient values, or NULL if not requested */
7933  SCIP_Real* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7934  )
7935 {
7936  SCIP_EXPRDATA_USER* exprdata;
7937 
7938  assert(expr != NULL);
7939  assert(expr->op == SCIP_EXPR_USER);
7940  assert(argvals != NULL || expr->nchildren == 0);
7941 
7942  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7943  assert(exprdata->eval != NULL);
7944 
7945  SCIP_CALL( exprdata->eval(exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7946 
7947  return SCIP_OKAY;
7948 }
7949 
7950 /** evaluates a user expression w.r.t. an interval */
7952  SCIP_EXPR* expr, /**< expression */
7953  SCIP_Real infinity, /**< value to use for infinity */
7954  SCIP_INTERVAL* argvals, /**< values for children */
7955  SCIP_INTERVAL* val, /**< buffer to store value */
7956  SCIP_INTERVAL* gradient, /**< buffer to store gradient values, or NULL if not requested */
7957  SCIP_INTERVAL* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7958  )
7959 {
7960  SCIP_EXPRDATA_USER* exprdata;
7961 
7962  assert(expr != NULL);
7963  assert(expr->op == SCIP_EXPR_USER);
7964  assert(argvals != NULL || expr->nchildren == 0);
7965 
7966  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7967 
7968  if( exprdata->inteval == NULL )
7969  {
7970  int i;
7971 
7972  for( i = 0; i < expr->nchildren; ++i )
7973  SCIPintervalSetEntire(infinity, &argvals[i]); /*lint !e613*/
7974  }
7975  else
7976  {
7977  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7978  }
7979 
7980  return SCIP_OKAY;
7981 }
7982 
7983 /** tries to determine the curvature type of an expression w.r.t. given variable domains */
7985  SCIP_EXPR* expr, /**< expression to check */
7986  SCIP_Real infinity, /**< value to use for infinity */
7987  SCIP_INTERVAL* varbounds, /**< domains of variables */
7988  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7989  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
7990  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
7991  )
7992 {
7994  SCIP_INTERVAL* childbounds;
7996  SCIP_EXPRCURV* childcurv;
7997  int i;
7998 
7999  assert(expr != NULL);
8000  assert(curv != NULL);
8001  assert(bounds != NULL);
8002 
8003  /* if many children, get large enough memory to store argument values */
8005  {
8006  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, expr->nchildren) );
8007  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, expr->nchildren) );
8008  }
8009  else
8010  {
8011  childbounds = childboundsbuf;
8012  childcurv = childcurvbuf;
8013  }
8014 
8015  /* check curvature and compute bounds of children
8016  * constant children can be considered as always linear */
8017  for( i = 0; i < expr->nchildren; ++i )
8018  {
8019  SCIP_CALL( SCIPexprCheckCurvature(expr->children[i], infinity, varbounds, param, &childcurv[i], &childbounds[i]) ); /*lint !e644*/
8020  if( childbounds[i].inf == childbounds[i].sup ) /*lint !e777*/
8021  childcurv[i] = SCIP_EXPRCURV_LINEAR;
8022  }
8023 
8024  /* get curvature and bounds of expr */
8025  assert(exprOpTable[expr->op].curv != NULL);
8026  assert(exprOpTable[expr->op].inteval != NULL);
8027 
8028  SCIP_CALL( exprOpTable[expr->op].curv(infinity, expr->data, expr->nchildren, childbounds, childcurv, curv) );
8029  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, childbounds, varbounds, param, bounds) );
8030 
8031  /* free memory, if allocated before */
8032  if( childboundsbuf != childbounds )
8033  {
8034  BMSfreeMemoryArray(&childcurv);
8035  BMSfreeMemoryArray(&childbounds);
8036  }
8037 
8038  return SCIP_OKAY;
8039 }
8040 
8041 /** under-/overestimates a user expression w.r.t. to given values and bounds for children expressions */
8043  SCIP_EXPR* expr, /**< expression */
8044  SCIP_Real infinity, /**< value to use for infinity */
8045  SCIP_Real* argvals, /**< values for children */
8046  SCIP_INTERVAL* argbounds, /**< bounds for children */
8047  SCIP_Bool overestimate, /**< whether to overestimate the expression */
8048  SCIP_Real* coeffs, /**< buffer to store the linear coefficients for each child expression that gives a valid under-/overestimator */
8049  SCIP_Real* constant, /**< buffer to store the constant value of the linear under-/overestimator */
8050  SCIP_Bool* success /**< buffer to store whether an estimator was successfully computed */
8051  )
8052 {
8053  SCIP_EXPRDATA_USER* exprdata;
8054 
8055  assert(expr != NULL);
8056  assert(expr->op == SCIP_EXPR_USER);
8057  assert(argvals != NULL || expr->nchildren == 0);
8058  assert(argbounds != NULL || expr->nchildren == 0);
8059 
8060  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8061 
8062  if( exprdata->estimate != NULL )
8063  {
8064  SCIP_CALL( exprdata->estimate(infinity, exprdata->userdata, expr->nchildren, argvals, argbounds, overestimate, coeffs, constant, success ) );
8065  }
8066  else
8067  {
8068  *success = FALSE;
8069  }
8070 
8071  return SCIP_OKAY;
8072 }
8073 
8074 /** substitutes variables (SCIP_EXPR_VARIDX) by expressions
8075  *
8076  * Note that only the children of the given expr are checked!
8077  * A variable with index i is replaced by a copy of substexprs[i], if the latter is not NULL.
8078  * If substexprs[i] == NULL, then the variable expression i is not touched.
8079  */
8081  BMS_BLKMEM* blkmem, /**< block memory data structure */
8082  SCIP_EXPR* expr, /**< expression, which of the children may be replaced */
8083  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8084  )
8085 {
8086  int i;
8087 
8088  assert(blkmem != NULL);
8089  assert(expr != NULL);
8090  assert(substexprs != NULL);
8091 
8092  for( i = 0; i < expr->nchildren; ++i )
8093  {
8094  if( expr->children[i]->op == SCIP_EXPR_VARIDX )
8095  {
8096  int varidx;
8097  varidx = expr->children[i]->data.intval;
8098 
8099  assert(varidx >= 0);
8100  if( substexprs[varidx] != NULL )
8101  {
8102  /* replace child i by copy of substexprs[expr->children[i]->opdata.intval] */
8103  SCIPexprFreeDeep(blkmem, &expr->children[i]);
8104  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[i], substexprs[varidx]) );
8105  }
8106  }
8107  else
8108  {
8109  /* call recursively */
8110  SCIP_CALL( SCIPexprSubstituteVars(blkmem, expr->children[i], substexprs) );
8111  }
8112  }
8113 
8114  return SCIP_OKAY;
8115 }
8116 
8117 /** updates variable indices in expression tree */
8119  SCIP_EXPR* expr, /**< expression to update */
8120  int* newindices /**< new indices of variables */
8121  )
8122 {
8123  int i;
8124 
8125  assert(expr != NULL);
8126  assert(newindices != NULL);
8127 
8128  if( expr->op == SCIP_EXPR_VARIDX )
8129  {
8130  expr->data.intval = newindices[expr->data.intval];
8131  assert(expr->data.intval >= 0);
8132  }
8133 
8134  for( i = 0; i < expr->nchildren; ++i )
8135  SCIPexprReindexVars(expr->children[i], newindices);
8136 }
8137 
8138 /** updates parameter indices in expression tree */
8140  SCIP_EXPR* expr, /**< expression to update */
8141  int* newindices /**< new indices of variables */
8142  )
8143 {
8144  int i;
8145 
8146  assert(expr != NULL);
8147  assert(newindices != NULL);
8148 
8149  if( expr->op == SCIP_EXPR_PARAM )
8150  {
8151  expr->data.intval = newindices[expr->data.intval];
8152  assert(expr->data.intval >= 0);
8153  }
8154 
8155  for( i = 0; i < expr->nchildren; ++i )
8156  SCIPexprReindexParams(expr->children[i], newindices);
8157 }
8158 
8159 /** prints an expression */
8161  SCIP_EXPR* expr, /**< expression */
8162  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8163  FILE* file, /**< file for printing, or NULL for stdout */
8164  const char** varnames, /**< names of variables, or NULL for default names */
8165  const char** paramnames, /**< names of parameters, or NULL for default names */
8166  SCIP_Real* paramvals /**< values of parameters, or NULL for not printing */
8167  )
8168 {
8169  assert( expr != NULL );
8170 
8171  switch( expr->op )
8172  {
8173  /* @Note: 'expr->data.intval' is either between 0 and number of variables-1, if it uses the varnames array, or
8174  * between 0 and number of params in the expression tree, if it uses the paramnames array
8175  * because, here, we cannot get the values above we cannot assert them
8176  */
8177  case SCIP_EXPR_VARIDX:
8178  if( varnames != NULL )
8179  {
8180  assert(varnames[expr->data.intval] != NULL);
8181  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", varnames[expr->data.intval]);
8182  }
8183  else
8184  {
8185  SCIPmessageFPrintInfo(messagehdlr, file, "var%d", expr->data.intval);
8186  }
8187  break;
8188 
8189  case SCIP_EXPR_PARAM:
8190  if( paramnames != NULL )
8191  {
8192  assert(paramnames[expr->data.intval] != NULL);
8193  SCIPmessageFPrintInfo(messagehdlr, file, "%s", paramnames[expr->data.intval]);
8194  }
8195  else
8196  {
8197  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", expr->data.intval );
8198  }
8199  if( paramvals != NULL )
8200  {
8201  SCIPmessageFPrintInfo(messagehdlr, file, "[%g]", paramvals[expr->data.intval] );
8202  }
8203  break;
8204 
8205  case SCIP_EXPR_CONST:
8206  if (expr->data.dbl < 0.0 )
8207  SCIPmessageFPrintInfo(messagehdlr, file, "(%g)", expr->data.dbl );
8208  else
8209  SCIPmessageFPrintInfo(messagehdlr, file, "%g", expr->data.dbl );
8210  break;
8211 
8212  case SCIP_EXPR_PLUS:
8213  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8214  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8215  SCIPmessageFPrintInfo(messagehdlr, file, " + ");
8216  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8217  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8218  break;
8219 
8220  case SCIP_EXPR_MINUS:
8221  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8222  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8223  SCIPmessageFPrintInfo(messagehdlr, file, " - ");
8224  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8225  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8226  break;
8227 
8228  case SCIP_EXPR_MUL:
8229  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8230  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8231  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8232  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8233  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8234  break;
8235 
8236  case SCIP_EXPR_DIV:
8237  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8238  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8239  SCIPmessageFPrintInfo(messagehdlr, file, " / ");
8240  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8241  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8242  break;
8243 
8244  case SCIP_EXPR_REALPOWER:
8245  case SCIP_EXPR_SIGNPOWER:
8246  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8247  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8248  SCIPmessageFPrintInfo(messagehdlr, file, ", %g)", expr->data.dbl);
8249  break;
8250 
8251  case SCIP_EXPR_INTPOWER:
8252  SCIPmessageFPrintInfo(messagehdlr, file, "power(");
8253  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8254  SCIPmessageFPrintInfo(messagehdlr, file, ", %d)", expr->data.intval);
8255  break;
8256 
8257  case SCIP_EXPR_SQUARE:
8258  case SCIP_EXPR_SQRT:
8259  case SCIP_EXPR_EXP:
8260  case SCIP_EXPR_LOG:
8261  case SCIP_EXPR_SIN:
8262  case SCIP_EXPR_COS:
8263  case SCIP_EXPR_TAN:
8264  /* case SCIP_EXPR_ERF: */
8265  /* case SCIP_EXPR_ERFI: */
8266  case SCIP_EXPR_MIN:
8267  case SCIP_EXPR_MAX:
8268  case SCIP_EXPR_ABS:
8269  case SCIP_EXPR_SIGN:
8270  {
8271  int i;
8272 
8273  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8274 
8275  for( i = 0; i < expr->nchildren; ++i )
8276  {
8277  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8278  if( i + 1 < expr->nchildren )
8279  {
8280  SCIPmessageFPrintInfo(messagehdlr, file, ", ");
8281  }
8282  }
8283 
8284  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8285  break;
8286  }
8287 
8288  case SCIP_EXPR_SUM:
8289  case SCIP_EXPR_PRODUCT:
8290  {
8291  switch( expr->nchildren )
8292  {
8293  case 0:
8294  SCIPmessageFPrintInfo(messagehdlr, file, expr->op == SCIP_EXPR_SUM ? "0" : "1");
8295  break;
8296  case 1:
8297  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8298  break;
8299  default:
8300  {
8301  int i;
8302  const char* opstr = expr->op == SCIP_EXPR_SUM ? " + " : " * ";
8303 
8304  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8305  for( i = 0; i < expr->nchildren; ++i )
8306  {
8307  if( i > 0 )
8308  {
8309  SCIPmessageFPrintInfo(messagehdlr, file, opstr);
8310  }
8311  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8312  }
8313  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8314  }
8315  }
8316  break;
8317  }
8318 
8319  case SCIP_EXPR_LINEAR:
8320  {
8321  SCIP_Real constant;
8322  int i;
8323 
8324  constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
8325 
8326  if( expr->nchildren == 0 )
8327  {
8328  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
8329  break;
8330  }
8331 
8332  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8333 
8334  if( constant != 0.0 )
8335  {
8336  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
8337  }
8338 
8339  for( i = 0; i < expr->nchildren; ++i )
8340  {
8341  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", ((SCIP_Real*)expr->data.data)[i]);
8342  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8343  }
8344 
8345  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8346  break;
8347  }
8348 
8349  case SCIP_EXPR_QUADRATIC:
8350  {
8351  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
8352  int i;
8353 
8354  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
8355  assert(quadraticdata != NULL);
8356 
8357  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8358 
8359  if( quadraticdata->constant != 0.0 )
8360  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->constant);
8361 
8362  if( quadraticdata->lincoefs != NULL )
8363  for( i = 0; i < expr->nchildren; ++i )
8364  {
8365  if( quadraticdata->lincoefs[i] == 0.0 )
8366  continue;
8367  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->lincoefs[i]);
8368  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8369  }
8370 
8371  for( i = 0; i < quadraticdata->nquadelems; ++i )
8372  {
8373  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->quadelems[i].coef);
8374  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
8375  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
8376  {
8377  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
8378  }
8379  else
8380  {
8381  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8382  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
8383  }
8384  }
8385 
8386  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8387  break;
8388  }
8389 
8390  case SCIP_EXPR_POLYNOMIAL:
8391  {
8392  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
8393  SCIP_EXPRDATA_MONOMIAL* monomialdata;
8394  int i;
8395  int j;
8396 
8397  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8398 
8399  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
8400  assert(polynomialdata != NULL);
8401 
8402  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
8403  {
8404  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", polynomialdata->constant);
8405  }
8406 
8407  for( i = 0; i < polynomialdata->nmonomials; ++i )
8408  {
8409  monomialdata = polynomialdata->monomials[i];
8410  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g", monomialdata->coef);
8411 
8412  for( j = 0; j < monomialdata->nfactors; ++j )
8413  {
8414  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8415 
8416  SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
8417  if( monomialdata->exponents[j] < 0.0 )
8418  {
8419  SCIPmessageFPrintInfo(messagehdlr, file, "^(%.20g)", monomialdata->exponents[j]);
8420  }
8421  else if( monomialdata->exponents[j] != 1.0 )
8422  {
8423  SCIPmessageFPrintInfo(messagehdlr, file, "^%.20g", monomialdata->exponents[j]);
8424  }
8425  }
8426  }
8427 
8428  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8429  break;
8430  }
8431 
8432  case SCIP_EXPR_USER:
8433  {
8434  SCIP_EXPRDATA_USER* exprdata;
8435  int i;
8436 
8437  exprdata = (SCIP_EXPRDATA_USER*)expr->data.data;
8438  assert(exprdata != NULL);
8439 
8440  if( exprdata->print != NULL )
8441  {
8442  exprdata->print(exprdata->userdata, messagehdlr, file);
8443  }
8444  else
8445  {
8446  SCIPmessageFPrintInfo(messagehdlr, file, "user");
8447  }
8448 
8449  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8450  for( i = 0; i < expr->nchildren; ++i )
8451  {
8452  if( i > 0 )
8453  {
8454  SCIPmessageFPrintInfo(messagehdlr, file, ",");
8455  }
8456  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8457  }
8458  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8459 
8460  break;
8461  }
8462 
8463  case SCIP_EXPR_LAST:
8464  {
8465  SCIPerrorMessage("invalid expression\n");
8466  SCIPABORT();
8467  }
8468  }
8469 }
8470 
8471 /** parses an expression from a string */
8473  BMS_BLKMEM* blkmem, /**< block memory data structure */
8474  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8475  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
8476  const char* str, /**< pointer to the string to be parsed */
8477  const char* lastchar, /**< pointer to the last char of str that should be parsed */
8478  int* nvars, /**< buffer to store number of variables */
8479  int* varnames /**< buffer to store variable names, prefixed by index (as int) */
8480  )
8481 {
8482  SCIP_HASHTABLE* vartable;
8483  SCIP_RETCODE retcode;
8484 
8485  assert(blkmem != NULL);
8486  assert(expr != NULL);
8487  assert(str != NULL);
8488  assert(lastchar != NULL);
8489  assert(nvars != NULL);
8490  assert(varnames != NULL);
8491 
8492  *nvars = 0;
8493 
8494  /* create a hash table for variable names and corresponding expression index
8495  * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
8496  */
8497  SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) );
8498 
8499  retcode = exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames, vartable, 0);
8500 
8501  SCIPhashtableFree(&vartable);
8502 
8503  return retcode;
8504 }
8505 
8506 
8507 /**@} */
8508 
8509 /**@name Expression tree methods */
8510 /**@{ */
8511 
8512 /* In debug mode, the following methods are implemented as function calls to ensure
8513  * type validity.
8514  * In optimized mode, the methods are implemented as defines to improve performance.
8515  * However, we want to have them in the library anyways, so we have to undef the defines.
8516  */
8517 
8518 #undef SCIPexprtreeGetRoot
8519 #undef SCIPexprtreeGetNVars
8520 #undef SCIPexprtreeGetNParams
8521 #undef SCIPexprtreeGetParamVals
8522 #undef SCIPexprtreeSetParamVal
8523 #undef SCIPexprtreeGetInterpreterData
8524 #undef SCIPexprtreeSetInterpreterData
8525 #undef SCIPexprtreeFreeInterpreterData
8526 #undef SCIPexprtreeHasParam
8527 #undef SCIPexprtreeGetMaxDegree
8528 #undef SCIPexprtreeEval
8529 #undef SCIPexprtreeEvalInt
8530 #undef SCIPexprtreePrint
8531 
8532 /** returns root expression of an expression tree */
8534  SCIP_EXPRTREE* tree /**< expression tree */
8535  )
8536 {
8537  assert(tree != NULL);
8538 
8539  return tree->root;
8540 }
8541 
8542 /** returns number of variables in expression tree */
8544  SCIP_EXPRTREE* tree /**< expression tree */
8545  )
8546 {
8547  assert(tree != NULL);
8548 
8549  return tree->nvars;
8550 }
8551 
8552 /** returns number of parameters in expression tree */
8554  SCIP_EXPRTREE* tree /**< expression tree */
8555  )
8556 {
8557  assert(tree != NULL);
8558 
8559  return tree->nparams;
8560 }
8561 
8562 /** returns values of parameters or NULL if none */
8564  SCIP_EXPRTREE* tree /**< expression tree */
8565  )
8566 {
8567  assert(tree != NULL);
8568 
8569  return tree->params;
8570 }
8571 
8572 /** sets value of a single parameter in expression tree */
8574  SCIP_EXPRTREE* tree, /**< expression tree */
8575  int paramidx, /**< index of parameter */
8576  SCIP_Real paramval /**< new value of parameter */
8577  )
8578 {
8579  assert(tree != NULL);
8580  assert(paramidx >= 0);
8581  assert(paramidx < tree->nparams);
8582  assert(tree->params != NULL);
8583 
8584  tree->params[paramidx] = paramval;
8585 }
8586 
8587 /** gets data of expression tree interpreter, or NULL if not set */
8589  SCIP_EXPRTREE* tree /**< expression tree */
8590  )
8591 {
8592  assert(tree != NULL);
8593 
8594  return tree->interpreterdata;
8595 }
8596 
8597 /** sets data of expression tree interpreter */
8599  SCIP_EXPRTREE* tree, /**< expression tree */
8600  SCIP_EXPRINTDATA* interpreterdata /**< expression interpreter data */
8601  )
8602 {
8603  assert(tree != NULL);
8604  assert(interpreterdata != NULL);
8605  assert(tree->interpreterdata == NULL);
8606 
8607  tree->interpreterdata = interpreterdata;
8608 }
8609 
8610 /** frees data of expression tree interpreter, if any */
8612  SCIP_EXPRTREE* tree /**< expression tree */
8613  )
8614 {
8615  if( tree->interpreterdata != NULL )
8616  {
8618  assert(tree->interpreterdata == NULL);
8619  }
8620 
8621  return SCIP_OKAY;
8622 }
8623 
8624 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
8626  SCIP_EXPRTREE* tree /**< expression tree */
8627  )
8628 {
8629  assert(tree != NULL);
8630 
8631  return SCIPexprHasParam(tree->root);
8632 }
8633 
8634 /** Gives maximal degree of expression in expression tree.
8635  *
8636  * If constant expression, gives 0,
8637  * if linear expression, gives 1,
8638  * if polynomial expression, gives its maximal degree,
8639  * otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8640  */
8642  SCIP_EXPRTREE* tree, /**< expression tree */
8643  int* maxdegree /**< buffer to store maximal degree */
8644  )
8645 {
8646  assert(tree != NULL);
8647 
8648  SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8649 
8650  return SCIP_OKAY;
8651 }
8652 
8653 /** evaluates an expression tree w.r.t. a point */
8655  SCIP_EXPRTREE* tree, /**< expression tree */
8656  SCIP_Real* varvals, /**< values for variables */
8657  SCIP_Real* val /**< buffer to store expression tree value */
8658  )
8659 {
8660  assert(tree != NULL);
8661  assert(varvals != NULL || tree->nvars == 0);
8662  assert(val != NULL);
8663 
8664  SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8665 
8666  return SCIP_OKAY;
8667 }
8668 
8669 /** evaluates an expression tree w.r.t. an interval */
8671  SCIP_EXPRTREE* tree, /**< expression tree */
8672  SCIP_Real infinity, /**< value for infinity */
8673  SCIP_INTERVAL* varvals, /**< intervals for variables */
8674  SCIP_INTERVAL* val /**< buffer to store expression tree value */
8675  )
8676 {
8677  assert(tree != NULL);
8678  assert(varvals != NULL || tree->nvars == 0);
8679  assert(val != NULL);
8680 
8681  SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8682 
8683  return SCIP_OKAY;
8684 }
8685 
8686 /** prints an expression tree */
8688  SCIP_EXPRTREE* tree, /**< expression tree */
8689  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8690  FILE* file, /**< file for printing, or NULL for stdout */
8691  const char** varnames, /**< names of variables, or NULL for default names */
8692  const char** paramnames /**< names of parameters, or NULL for default names */
8693  )
8694 {
8695  assert(tree != NULL);
8696 
8697  SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8698 }
8699 
8700 
8701 /** creates an expression tree */
8703  BMS_BLKMEM* blkmem, /**< block memory data structure */
8704  SCIP_EXPRTREE** tree, /**< buffer to store address of created expression tree */
8705  SCIP_EXPR* root, /**< pointer to root expression, not copied deep !, can be NULL */
8706  int nvars, /**< number of variables in variable mapping */
8707  int nparams, /**< number of parameters in expression */
8708  SCIP_Real* params /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8709  )
8710 {
8711  assert(blkmem != NULL);
8712  assert(tree != NULL);
8713 
8714  SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8715 
8716  (*tree)->blkmem = blkmem;
8717  (*tree)->root = root;
8718  (*tree)->nvars = nvars;
8719  (*tree)->vars = NULL;
8720  (*tree)->nparams = nparams;
8721  (*tree)->interpreterdata = NULL;
8722 
8723  if( params != NULL )
8724  {
8725  assert(nparams > 0);
8726  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8727  }
8728  else if( nparams > 0 )
8729  {
8730  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8731  BMSclearMemoryArray((*tree)->params, nparams);
8732  }
8733  else
8734  {
8735  assert(nparams == 0);
8736  (*tree)->params = NULL;
8737  }
8738 
8739  return SCIP_OKAY;
8740 }
8741 
8742 /** copies an expression tree */
8744  BMS_BLKMEM* blkmem, /**< block memory that should be used in new expression tree */
8745  SCIP_EXPRTREE** targettree, /**< buffer to store address of copied expression tree */
8746  SCIP_EXPRTREE* sourcetree /**< expression tree to copy */
8747  )
8748 {
8749  assert(blkmem != NULL);
8750  assert(targettree != NULL);
8751  assert(sourcetree != NULL);
8752 
8753  /* copy expression tree "header" */
8754  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8755 
8756  /* we may have a new block memory; and we do not want to keep the others interpreter data */
8757  (*targettree)->blkmem = blkmem;
8758  (*targettree)->interpreterdata = NULL;
8759 
8760  /* copy variables, if any */
8761  if( sourcetree->vars != NULL )
8762  {
8763  assert(sourcetree->nvars > 0);
8764 
8765  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8766  }
8767 
8768  /* copy parameters, if any */
8769  if( sourcetree->params != NULL )
8770  {
8771  assert(sourcetree->nparams > 0);
8772 
8773  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8774  }
8775 
8776  /* copy expression */
8777  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8778 
8779  return SCIP_OKAY;
8780 }
8781 
8782 /** frees an expression tree */
8784  SCIP_EXPRTREE** tree /**< pointer to expression tree that is freed */
8785  )
8786 {
8787  assert( tree != NULL);
8788  assert(*tree != NULL);
8789 
8791 
8792  if( (*tree)->root != NULL )
8793  {
8794  SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8795  assert((*tree)->root == NULL);
8796  }
8797 
8798  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars, (*tree)->nvars );
8799  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8800 
8801  BMSfreeBlockMemory((*tree)->blkmem, tree);
8802 
8803  return SCIP_OKAY;
8804 }
8805 
8806 /** sets number and values of all parameters in expression tree */
8808  SCIP_EXPRTREE* tree, /**< expression tree */
8809  int nparams, /**< number of parameters */
8810  SCIP_Real* paramvals /**< values of parameters, can be NULL if nparams == 0 */
8811  )
8812 {
8813  assert(tree != NULL);
8814  assert(paramvals != NULL || nparams == 0);
8815 
8816  if( nparams == 0 )
8817  {
8818  BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8819  }
8820  else if( tree->params != NULL )
8821  {
8822  SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8823  BMScopyMemoryArray(tree->params, paramvals, nparams);
8824  }
8825  else
8826  {
8827  SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8828  }
8829 
8830  tree->nparams = nparams;
8831  assert(tree->params != NULL || tree->nparams == 0);
8832 
8833  return SCIP_OKAY;
8834 }
8835 
8836 
8837 /** gives the number of usages for each variable in the expression tree */
8839  SCIP_EXPRTREE* tree, /**< expression tree */
8840  int* varsusage /**< array where to store for each variable how often it is used in the tree */
8841  )
8842 {
8843  assert(tree != NULL);
8844  assert(varsusage != NULL);
8845 
8846  if( tree->nvars == 0 )
8847  return;
8848 
8849  BMSclearMemoryArray(varsusage, tree->nvars);
8850  SCIPexprGetVarsUsage(tree->root, varsusage);
8851 }
8852 
8853 /** aims at simplifying an expression and splitting of a linear expression
8854  *
8855  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
8856  */
8858  SCIP_EXPRTREE* tree, /**< expression tree */
8859  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8860  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
8861  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8862  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8863  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8864  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
8865  )
8866 {
8867 #ifndef NDEBUG
8868  SCIP_RANDNUMGEN* randnumgen;
8869  SCIP_Real* testx;
8870  SCIP_Real testval_before;
8871  SCIP_Real testval_after;
8872  int i;
8873 #endif
8874 
8875  assert(tree != NULL);
8876 
8877 #ifndef NDEBUG
8878  SCIP_CALL( SCIPrandomCreate(&randnumgen, tree->blkmem, 42) );
8879 
8880  SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) ); /*lint !e666*/
8881  for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8882  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
8883  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8884 
8885  SCIPrandomFree(&randnumgen);
8886 #endif
8887 
8888  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8889  SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8890 
8891 #ifndef NDEBUG
8892  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8893  if( nlinvars != NULL && testval_before == testval_before ) /*lint !e777*/
8894  for( i = 0; i < *nlinvars; ++i )
8895  testval_after += lincoefs[i] * testx[linidxs[i]];
8896  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
8897  BMSfreeMemoryArray(&testx);
8898 #endif
8899 
8900  /* removing something from the the tree may invalidate the interpreter data */
8901  if( nlinvars != NULL && *nlinvars > 0 )
8903 
8904  return SCIP_OKAY;
8905 }
8906 
8907 /** adds an expression to the root expression of the tree
8908  *
8909  * The root is replaced with an SCIP_EXPR_PLUS expression which has the previous root and the given expression (or a copy of it) as children.
8910  */
8912  SCIP_EXPRTREE* tree, /**< expression tree */
8913  SCIP_EXPR* expr, /**< expression to add to tree */
8914  SCIP_Bool copyexpr /**< whether expression should be copied */
8915  )
8916 {
8917  assert(tree != NULL);
8918  assert(tree->root != NULL);
8919 
8920  /* adding something to the tree may invalidate the interpreter data */
8922 
8923  if( copyexpr )
8924  {
8925  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &expr, expr) );
8926  }
8927 
8928  SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
8929 
8930  return SCIP_OKAY;
8931 }
8932 
8933 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
8935  SCIP_EXPRTREE* tree, /**< expression tree */
8936  SCIP_Real infinity, /**< value for infinity */
8937  SCIP_INTERVAL* varbounds, /**< domains of variables */
8938  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8939  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression, or NULL if not needed */
8940  )
8941 {
8942  SCIP_INTERVAL exprbounds;
8943 
8944  assert(tree != NULL);
8945  assert(tree->root != NULL);
8946 
8947  SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
8948 
8949  if( bounds != NULL )
8950  *bounds = exprbounds;
8951 
8952  return SCIP_OKAY;
8953 }
8954 
8955 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
8956  *
8957  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL.
8958  * If substexprs[i] == NULL, then the variable expression i is not touched.
8959  */
8961  SCIP_EXPRTREE* tree, /**< expression tree */
8962  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8963  )
8964 {
8965  assert(tree != NULL);
8966  assert(tree->root != NULL);
8967 
8968  if( tree->root->op == SCIP_EXPR_VARIDX )
8969  {
8970  int varidx;
8971 
8972  varidx = tree->root->data.intval;
8973  assert(varidx >= 0);
8974  if( substexprs[varidx] != NULL )
8975  {
8976  /* substitute root expression */
8977  SCIPexprFreeDeep(tree->blkmem, &tree->root);
8978  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
8979  }
8980  }
8981  else
8982  {
8983  /* check children (and grandchildren and so on...) of root expression */
8984  SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
8985  }
8986 
8987  /* substitution of variables should invalidate interpreter data */
8989 
8990  return SCIP_OKAY;
8991 }
8992 
8993 /**@} */
8994 
8995 /**@name Quadratic element methods */
8996 /**@{ */
8997 
8998 /** comparing two quadratic elements
8999  *
9000  * a is better than b if index1 of a is smaller than index1 of b or index1 of both is equal but index2 of a is smaller than index2 of b
9001  */
9002 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
9003 
9004 /** swaps two quadratic elements */
9005 #define QUADELEMS_SWAP(x,y) \
9006  { \
9007  SCIP_QUADELEM temp = x; \
9008  x = y; \
9009  y = temp; \
9010  }
9011 
9012 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
9013 static
9015  SCIP_QUADELEM* elems, /**< array to be sorted */
9016  int start, /**< starting index */
9017  int end /**< ending index */
9018  )
9019 {
9020  assert(start <= end);
9021 
9022  /* use quick sort for long lists */
9023  while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
9024  {
9025  SCIP_QUADELEM pivotkey;
9026  int lo;
9027  int hi;
9028  int mid;
9029 
9030  /* select pivot element */
9031  mid = (start+end)/2;
9032  pivotkey = elems[mid];
9033 
9034  /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
9035  lo = start;
9036  hi = end;
9037  for( ;; )
9038  {
9039  while( lo < end && QUADELEMS_ISBETTER(elems[lo], pivotkey) )
9040  lo++;
9041  while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
9042  hi--;
9043 
9044  if( lo >= hi )
9045  break;
9046 
9047  QUADELEMS_SWAP(elems[lo], elems[hi]);
9048 
9049  lo++;
9050  hi--;
9051  }
9052  assert(hi == lo-1 || hi == start);
9053 
9054  /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
9055  while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
9056  lo++;
9057 
9058  /* make sure that we have at least one element in the smaller partition */
9059  if( lo == start )
9060  {
9061  /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
9062  assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
9063  assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
9064  QUADELEMS_SWAP(elems[lo], elems[mid]);
9065  lo++;
9066  }
9067 
9068  /* sort the smaller partition by a recursive call, sort the larger part without recursion */
9069  if( hi - start <= end - lo )
9070  {
9071  /* sort [start,hi] with a recursive call */
9072  if( start < hi )
9073  quadelemsQuickSort(elems, start, hi);
9074 
9075  /* now focus on the larger part [lo,end] */
9076  start = lo;
9077  }
9078  else
9079  {
9080  /* sort [lo,end] with a recursive call */
9081  if( lo < end )
9082  quadelemsQuickSort(elems, lo, end);
9083 
9084  /* now focus on the larger part [start,hi] */
9085  end = hi;
9086  }
9087  }
9088 
9089  /* use shell sort on the remaining small list */
9090  if( end - start >= 1 )
9091  {
9092  static const int incs[3] = {1, 5, 19}; /* sequence of increments */
9093  int k;
9094 
9095  for( k = 2; k >= 0; --k )
9096  {
9097  int h;
9098  int i;
9099 
9100  for( h = incs[k], i = h + start; i <= end; ++i )
9101  {
9102  int j;
9103  SCIP_QUADELEM tempkey = elems[i];
9104 
9105  j = i;
9106  while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
9107  {
9108  elems[j] = elems[j-h];
9109  j -= h;
9110  }
9111 
9112  elems[j] = tempkey;
9113  }
9114  }
9115  }
9116 }
9117 
9118 /** sorts an array of quadratic elements
9119  *
9120  * The elements are sorted such that the first index is increasing and
9121  * such that among elements with the same first index, the second index is increasing.
9122  * For elements with same first and second index, the order is not defined.
9123  */
9125  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9126  int nquadelems /**< number of quadratic elements */
9127  )
9128 {
9129  if( nquadelems == 0 )
9130  return;
9131 
9132 #ifndef NDEBUG
9133  {
9134  int i;
9135  for( i = 0; i < nquadelems; ++i )
9136  assert(quadelems[i].idx1 <= quadelems[i].idx2);
9137  }
9138 #endif
9139 
9140  quadelemsQuickSort(quadelems, 0, nquadelems-1);
9141 }
9142 
9143 /** Finds an index pair in a sorted array of quadratic elements.
9144  *
9145  * If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
9146  * If (idx1,idx2) is not found in quadelems, then returns FALSE and stores position where a quadratic element with these indices would be inserted in *pos.
9147  * Assumes that idx1 <= idx2.
9148  */
9150  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9151  int idx1, /**< index of first variable in element to search for */
9152  int idx2, /**< index of second variable in element to search for */
9153  int nquadelems, /**< number of quadratic elements in array */
9154  int* pos /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
9155  )
9156 {
9157  int left;
9158  int right;
9159 
9160  assert(quadelems != NULL || nquadelems == 0);
9161  assert(idx1 <= idx2);
9162 
9163  if( nquadelems == 0 )
9164  {
9165  if( pos != NULL )
9166  *pos = 0;
9167  return FALSE;
9168  }
9169 
9170  left = 0;
9171  right = nquadelems - 1;
9172  while( left <= right )
9173  {
9174  int middle;
9175 
9176  middle = (left+right)/2;
9177  assert(0 <= middle && middle < nquadelems);
9178 
9179  if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) ) /*lint !e613*/
9180  right = middle - 1;
9181  else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) ) /*lint !e613*/
9182  left = middle + 1;
9183  else
9184  {
9185  if( pos != NULL )
9186  *pos = middle;
9187  return TRUE;
9188  }
9189  }
9190  assert(left == right+1);
9191 
9192  if( pos != NULL )
9193  *pos = left;
9194  return FALSE;
9195 }
9196 
9197 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
9198  *
9199  * Assumes that elements have been sorted before.
9200  */
9202  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9203  int nquadelems, /**< number of quadratic elements */
9204  int* nquadelemsnew /**< pointer to store new (reduced) number of quadratic elements */
9205  )
9206 {
9207  int i;
9208  int next;
9209 
9210  assert(quadelems != NULL);
9211  assert(nquadelemsnew != NULL);
9212  assert(nquadelems >= 0);
9213 
9214  i = 0;
9215  next = 0;
9216  while( next < nquadelems )
9217  {
9218  /* assert that array is sorted */
9219  assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
9220  (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
9221 
9222  /* skip elements with coefficient 0.0 */
9223  if( quadelems[next].coef == 0.0 )
9224  {
9225  ++next;
9226  continue;
9227  }
9228 
9229  /* if next element has same index as previous one, add it to the previous one */
9230  if( i >= 1 &&
9231  quadelems[i-1].idx1 == quadelems[next].idx1 &&
9232  quadelems[i-1].idx2 == quadelems[next].idx2 )
9233  {
9234  quadelems[i-1].coef += quadelems[next].coef;
9235  ++next;
9236  continue;
9237  }
9238 
9239  /* otherwise, move next element to current position */
9240  quadelems[i] = quadelems[next];
9241  ++i;
9242  ++next;
9243  }
9244  assert(next == nquadelems);
9245 
9246  /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
9247  *nquadelemsnew = i;
9248 }
9249 
9250 /**@} */
9251 
9252 /**@name Expression graph node private methods */
9253 /**@{ */
9254 
9255 /** adds a parent to an expression graph node */
9256 static
9258  BMS_BLKMEM* blkmem, /**< block memory */
9259  SCIP_EXPRGRAPHNODE* node, /**< expression graph node where to add a parent */
9260  SCIP_EXPRGRAPHNODE* parent /**< parent node */
9261  )
9262 {
9263  assert(blkmem != NULL);
9264  assert(node != NULL);
9265  assert(node->depth >= 0);
9266  assert(node->pos >= 0);
9267  assert(parent != NULL);
9268  assert(parent->depth >= 0);
9269  assert(parent->pos >= 0);
9270  assert(parent->depth > node->depth); /* a parent node need to have larger depth */
9271 
9272  ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
9273  assert(node->nparents < node->parentssize);
9274 
9275  node->parents[node->nparents] = parent;
9276  ++node->nparents;
9277 
9278  /* update sorted flag */
9279  node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (node->parents[node->nparents-2] <= parent));
9280 
9281  return SCIP_OKAY;
9282 }
9283 
9284 /** ensures that array of parents in a node is sorted */
9285 static
9287  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
9288  )
9289 {
9290  assert(node != NULL);
9291 
9292  if( node->parentssorted )
9293  {
9294 #ifndef NDEBUG
9295  int i;
9296  for( i = 1; i < node->nparents; ++i )
9297  assert(ptrcomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
9298 #endif
9299  return;
9300  }
9301 
9302  SCIPsortPtr((void**)node->parents, ptrcomp, node->nparents);
9303 
9304  node->parentssorted = TRUE;
9305 }
9306 
9307 /** removes a parent from an expression graph node
9308  *
9309  * If the node is not used and has no other parents, then it is freed.
9310  */
9311 static
9313  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9314  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to remove a parent, *node will be set to NULL */
9315  SCIP_EXPRGRAPHNODE* parent /**< parent node to remove */
9316  )
9317 {
9318  SCIP_EXPRGRAPHNODE* node_;
9319  int pos;
9320 
9321  assert(exprgraph != NULL);
9322  assert(node != NULL);
9323  assert(*node != NULL);
9324  assert((*node)->depth >= 0);
9325  assert((*node)->pos >= 0);
9326  assert((*node)->nparents > 0);
9327  assert(parent != NULL);
9328  assert(parent->depth >= 0);
9329  assert(parent->pos >= 0);
9330  assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
9331 
9332  /* find parent */
9333  exprgraphNodeSortParents(*node);
9334  (void) SCIPsortedvecFindPtr((void**)(*node)->parents, ptrcomp, (void*)parent, (*node)->nparents, &pos);
9335  assert(pos >= 0);
9336  assert(pos < (*node)->nparents);
9337  assert((*node)->parents[pos] == parent);
9338 
9339  /* move last parent to pos, if pos is before last
9340  * update sorted flag */
9341  if( pos < (*node)->nparents-1 )
9342  {
9343  (*node)->parents[pos] = (*node)->parents[(*node)->nparents-1];
9344  (*node)->parentssorted = ((*node)->nparents <= 2);
9345  }
9346  --(*node)->nparents;
9347 
9348  /* keep pointer to *node in case it is still used */
9349  node_ = (*node)->nuses > 0 ? *node : NULL;
9350 
9351  /* capture and release node so it is freed if possible */
9352  SCIPexprgraphCaptureNode(*node);
9353  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
9354 
9355  /* restore pointer, if node still exists */
9356  *node = node_;
9357 
9358  return SCIP_OKAY;
9359 }
9360 
9361 /** checks if a node is parent of a node */
9362 static
9364  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9365  SCIP_EXPRGRAPHNODE* parent /**< parent to look for */
9366  )
9367 {
9368  int pos;
9369 
9370  assert(node != NULL);
9371  assert(parent != NULL);
9372 
9373  /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
9374  if( node->depth >= parent->depth || node->nparents == 0 )
9375  return FALSE;
9376  assert(node->parents != NULL);
9377 
9378  /* ensure parents array is sorted */
9380 
9381  return SCIPsortedvecFindPtr((void**)node->parents, ptrcomp, (void*)parent, node->nparents, &pos);
9382 }
9383 
9384 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
9385  *
9386  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
9387  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
9388  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
9389  *
9390  * It is assumed that node and all exprs are in the expression graph already.
9391  * It is assumed that all expressions that are added have lower depth than node.
9392  */
9393 static
9395  BMS_BLKMEM* blkmem, /**< block memory */
9396  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9397  int nexprs, /**< number of children to add */
9398  SCIP_EXPRGRAPHNODE** exprs, /**< children nodes to add */
9399  int* childmap /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
9400  )
9401 {
9402  int i;
9403  int j;
9404  int orignchildren;
9405  SCIP_Bool existsalready;
9406 
9407  assert(blkmem != NULL);
9408  assert(node != NULL);
9409  assert(node->depth > 0);
9410  assert(node->pos >= 0);
9411  assert(node->op == SCIP_EXPR_SUM || node->op == SCIP_EXPR_PRODUCT || node->op == SCIP_EXPR_LINEAR || node->op == SCIP_EXPR_QUADRATIC || node->op == SCIP_EXPR_POLYNOMIAL);
9412  assert(exprs != NULL || nexprs == 0);
9413 
9414  if( nexprs == 0 )
9415  return SCIP_OKAY;
9416 
9417  orignchildren = node->nchildren;
9418  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
9419 
9420  for( i = 0; i < nexprs; ++i )
9421  {
9422  assert(exprs[i]->depth >= 0); /*lint !e613*/
9423  assert(exprs[i]->pos >= 0); /*lint !e613*/
9424  assert(exprs[i]->depth < node->depth); /*lint !e613*/
9425 
9426  /* check if exprs[i] is a child already, if not SUM or PRODUCT */
9427  existsalready = FALSE;
9428  if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
9429  for( j = 0; j < orignchildren; ++j )
9430  /* during simplification of polynomials, their may be NULL's in children array */
9431  if( node->children[j] != NULL && node->children[j] == exprs[i] ) /*lint !e613*/
9432  {
9433  existsalready = TRUE;
9434  break;
9435  }
9436 
9437  if( !existsalready )
9438  {
9439  /* add exprs[i] to children array */
9440  node->children[node->nchildren] = exprs[i]; /*lint !e613*/
9441  SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) ); /*lint !e613*/
9442  if( childmap != NULL )
9443  childmap[i] = node->nchildren;
9444  ++node->nchildren;
9445  }
9446  else
9447  {
9448  if( childmap != NULL )
9449  childmap[i] = j; /*lint !e644*/
9450  if( node->op == SCIP_EXPR_LINEAR )
9451  {
9452  /* if linear expression, increase coefficient by 1.0 */
9453  ((SCIP_Real*)node->data.data)[j] += 1.0;
9454  }
9455  }
9456  }
9457 
9458  /* shrink children array to actually used size */
9459  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
9460 
9461  if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
9462  {
9463  /* if linear expression, then add 1.0 coefficients for new expressions */
9464  SCIP_Real* data;
9465 
9466  data = (SCIP_Real*)node->data.data;
9467  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
9468  data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
9469  for( i = orignchildren; i < node->nchildren; ++i )
9470  data[i] = 1.0;
9471  node->data.data = (void*)data;
9472  }
9473  else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
9474  {
9475  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
9477 
9478  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9479  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
9480  BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren); /*lint !e866*/
9481  }
9482 
9483  node->simplified = FALSE;
9484 
9485  return SCIP_OKAY;
9486 }
9487 
9488 /** replaces a child node by another node
9489  *
9490  * Assumes that both nodes represent the same expression.
9491  * If this node was the last parent of oldchild and oldchild is not in use, then it is freed.
9492  * newchild must have deeper depth than node.
9493  */
9494 static
9496  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9497  SCIP_EXPRGRAPHNODE* node, /**< pointer to expression graph node */
9498  SCIP_EXPRGRAPHNODE** oldchild, /**< child node that should be replaced, it may be freed */
9499  SCIP_EXPRGRAPHNODE* newchild /**< node that should take position of oldchild */
9500  )
9501 {
9502  int i;
9503 
9504  assert(exprgraph != NULL);
9505  assert(node != NULL);
9506  assert(oldchild != NULL);
9507  assert(*oldchild != NULL);
9508  assert(newchild != NULL);
9509 
9510  if( *oldchild == newchild )
9511  return SCIP_OKAY;
9512 
9513  SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
9514 
9515  /* search for oldchild in children array */
9516  for( i = 0; i < node->nchildren; ++i )
9517  {
9518  if( node->children[i] == *oldchild )
9519  {
9520  /* add as parent to newchild */
9521  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
9522 
9523  /* remove as parent from oldchild */
9524  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
9525 
9526  /* set newchild as child i */
9527  node->children[i] = newchild;
9528 
9529  /* we're done */
9530  break;
9531  }
9532  }
9533  assert(i < node->nchildren); /* assert that oldchild has been found in children array */
9534 
9535  node->simplified = FALSE;
9536 
9537  return SCIP_OKAY;
9538 }
9539 
9540 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
9541  *
9542  * A node is larger than another node, if their corresponding constants are related that way.
9543  */
9544 static
9545 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
9546 {
9547  assert(elem1 != NULL);
9548  assert(elem2 != NULL);
9549  assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
9550  assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
9551  assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9552  assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9553 
9554  if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9555  return 1;
9556  else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9557  return -1;
9558  else
9559  return 0;
9560 }
9561 
9562 /** sort array of nodes that holds constants */
9563 static
9565  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
9566  )
9567 {
9568  assert(exprgraph != NULL);
9569 
9570  if( exprgraph->constssorted )
9571  return;
9572 
9573  SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
9574 
9575  exprgraph->constssorted = TRUE;
9576 }
9577 
9578 /** finds position of expression graph node corresponding to a constant in constnodes array */
9579 static
9581  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9582  SCIP_EXPRGRAPHNODE* node, /**< node to search for */
9583  int* pos /**< buffer to store position of node, if found */
9584  )
9585 {
9586  int left;
9587  int right;
9588  int middle;
9589 
9590  assert(exprgraph != NULL);
9591  assert(node != NULL);
9592  assert(node->op == SCIP_EXPR_CONST);
9593  assert(node->depth == 0);
9594  assert(node->pos >= 0);
9595  assert(pos != NULL);
9596 
9597  exprgraphSortConstNodes(exprgraph);
9598  assert(exprgraph->constssorted);
9599 
9600  /* find a node with constant node->data.dbl using binary search */
9601  left = 0;
9602  right = exprgraph->nconsts-1;
9603  *pos = -1;
9604  while( left <= right )
9605  {
9606  middle = (left+right)/2;
9607  assert(0 <= middle && middle < exprgraph->nconsts);
9608 
9609  if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9610  right = middle - 1;
9611  else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9612  left = middle + 1;
9613  else
9614  {
9615  *pos = middle;
9616  break;
9617  }
9618  }
9619  assert(left == right+1 || *pos >= 0);
9620  if( left == right+1 )
9621  return FALSE;
9622 
9623  /* search left of *pos to find node */
9624  while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl ) /*lint !e777*/
9625  --*pos;
9626  /* search right of *pos to find node */
9627  while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl ) /*lint !e777*/
9628  ++*pos;
9629 
9630  return exprgraph->constnodes[*pos] == node;
9631 }
9632 
9633 /** creates an expression graph node */
9634 static
9636  BMS_BLKMEM* blkmem, /**< block memory */
9637  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
9638  SCIP_EXPROP op, /**< operator type of expression */
9639  SCIP_EXPROPDATA opdata /**< operator data of expression */
9640  )
9641 {
9642  assert(blkmem != NULL);
9643  assert(node != NULL);
9644 
9645  SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9646  BMSclearMemory(*node);
9647 
9648  (*node)->op = op;
9649  (*node)->data = opdata;
9650 
9651  /* mark graph position as not in graph yet */
9652  (*node)->depth = -1;
9653  (*node)->pos = -1;
9654 
9655  /* arrays of length 0 are trivially sorted */
9656  (*node)->parentssorted = TRUE;
9657 
9658  /* set bounds interval to entire */
9659  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9660  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9661 
9662  /* set initial value to invalid */
9663  (*node)->value = SCIP_INVALID;
9664 
9665  /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9666  if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9667  (*node)->curv = SCIP_EXPRCURV_LINEAR;
9668  else
9669  (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9670 
9671  /* per default, a node is enabled */
9672  (*node)->enabled = TRUE;
9673 
9674  return SCIP_OKAY;
9675 }
9676 
9677 /** prints the expression corresponding to a node (not recursively) */
9678 static
9680  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9681  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9682  FILE* file, /**< file to print to, or NULL for stdout */
9683  const char** varnames, /**< variable names, or NULL for generic names */
9684  SCIP_Bool printchildrenbounds /**< whether to print bounds of children */
9685  )
9686 {
9687  int i;
9688 
9689  assert(node != NULL);
9690 
9691  switch( node->op )
9692  {
9693  case SCIP_EXPR_VARIDX:
9694  if( varnames != NULL )
9695  {
9696  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9697  }
9698  else
9699  SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9700  break;
9701 
9702  case SCIP_EXPR_CONST:
9703  SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9704  break;
9705 
9706  case SCIP_EXPR_PARAM:
9707  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9708  break;
9709 
9710  case SCIP_EXPR_PLUS:
9711  if( printchildrenbounds )
9712  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9713  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9714  if( printchildrenbounds )
9715  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9716  break;
9717 
9718  case SCIP_EXPR_MINUS:
9719  if( printchildrenbounds )
9720  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9721  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9722  if( printchildrenbounds )
9723  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9724  break;
9725 
9726  case SCIP_EXPR_MUL:
9727  if( printchildrenbounds )
9728  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9729  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9730  if( printchildrenbounds )
9731  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9732  break;
9733 
9734  case SCIP_EXPR_DIV:
9735  if( printchildrenbounds )
9736  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9737  SCIPmessageFPrintInfo(messagehdlr, file, "/");
9738  if( printchildrenbounds )
9739  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9740  break;
9741 
9742  case SCIP_EXPR_SQUARE:
9743  if( printchildrenbounds )
9744  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9745  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9746  break;
9747 
9748  case SCIP_EXPR_REALPOWER:
9749  if( printchildrenbounds )
9750  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9751  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9752  break;
9753 
9754  case SCIP_EXPR_SIGNPOWER:
9755  if( printchildrenbounds )
9756  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9757  node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9758  else
9759  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9760  break;
9761 
9762  case SCIP_EXPR_INTPOWER:
9763  SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9764  if( printchildrenbounds )
9765  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9766  SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9767  break;
9768 
9769  case SCIP_EXPR_SQRT:
9770  case SCIP_EXPR_EXP:
9771  case SCIP_EXPR_LOG:
9772  case SCIP_EXPR_SIN:
9773  case SCIP_EXPR_COS:
9774  case SCIP_EXPR_TAN:
9775  /* SCIP_EXPR_ERF = 20, */ /**< gaussian error function (1 operand) */
9776  /* SCIP_EXPR_ERFI = 21, */ /**< imaginary part of gaussian error function (1 operand) */
9777  case SCIP_EXPR_MIN:
9778  case SCIP_EXPR_MAX:
9779  case SCIP_EXPR_ABS:
9780  case SCIP_EXPR_SIGN:
9781  SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9782  if( printchildrenbounds )
9783  {
9784  SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9785  if( node->nchildren == 2 )
9786  SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9787  SCIPmessageFPrintInfo(messagehdlr, file, ")");
9788  }
9789  break;
9790 
9791  case SCIP_EXPR_SUM:
9792  if( printchildrenbounds )
9793  for( i = 0; i < node->nchildren; ++i )
9794  {
9795  if( i > 0 )
9796  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9797  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9798  }
9799  else
9800  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9801  break;
9802 
9803  case SCIP_EXPR_PRODUCT:
9804  if( printchildrenbounds )
9805  for( i = 0; i < node->nchildren; ++i )
9806  {
9807  if( i > 0 )
9808  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9809  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9810  }
9811  else
9812  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9813  break;
9814 
9815  case SCIP_EXPR_LINEAR:
9816  {
9817  SCIP_Real constant;
9818 
9819  constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9820 
9821  if( constant != 0.0 || node->nchildren == 0 )
9822  SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9823 
9824  for( i = 0; i < node->nchildren; ++i )
9825  {
9826  if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9827  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9828  else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9829  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9830  else
9831  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9832  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9833  if( printchildrenbounds )
9834  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9835  }
9836 
9837  break;
9838  }
9839 
9840  case SCIP_EXPR_QUADRATIC:
9841  {
9842  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9843 
9844  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9845  assert(quadraticdata != NULL);
9846 
9847  if( quadraticdata->constant != 0.0 )
9848  SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9849 
9850  if( quadraticdata->lincoefs != NULL )
9851  for( i = 0; i < node->nchildren; ++i )
9852  {
9853  if( quadraticdata->lincoefs[i] == 0.0 )
9854  continue;
9855  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9856  if( printchildrenbounds )
9857  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9858  }
9859 
9860  for( i = 0; i < quadraticdata->nquadelems; ++i )
9861  {
9862  if( quadraticdata->quadelems[i].coef == 1.0 )
9863  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9864  else if( quadraticdata->quadelems[i].coef == -1.0 )
9865  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9866  else
9867  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9868  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9869  if( printchildrenbounds )
9870  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9871  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9872  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9873  else
9874  {
9875  SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9876  if( printchildrenbounds )
9877  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9878  }
9879  }
9880 
9881  break;
9882  }
9883 
9884  case SCIP_EXPR_POLYNOMIAL:
9885  {
9886  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9887  SCIP_EXPRDATA_MONOMIAL* monomialdata;
9888  int j;
9889 
9890  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9891  assert(polynomialdata != NULL);
9892 
9893  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
9894  {
9895  SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
9896  }
9897 
9898  for( i = 0; i < polynomialdata->nmonomials; ++i )
9899  {
9900  monomialdata = polynomialdata->monomials[i];
9901  if( monomialdata->coef == 1.0 )
9902  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9903  else if( monomialdata->coef == -1.0 )
9904  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9905  else
9906  SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
9907 
9908  for( j = 0; j < monomialdata->nfactors; ++j )
9909  {
9910  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
9911  if( printchildrenbounds )
9912  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
9913  if( monomialdata->exponents[j] < 0.0 )
9914  SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
9915  else if( monomialdata->exponents[j] != 1.0 )
9916  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
9917  }
9918  }
9919 
9920  break;
9921  }
9922 
9923  case SCIP_EXPR_LAST:
9924  SCIPABORT();
9925  break;
9926 
9927  default:
9928  SCIPmessageFPrintInfo(messagehdlr, file, SCIPexpropGetName(node->op));
9929  break;
9930  } /*lint !e788*/
9931 }
9932 
9933 /** prints a node of an expression graph */
9934 static
9936  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9937  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9938  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9939  FILE* file, /**< file to print to, or NULL for stdout */
9940  const char** varnames /**< variable names, or NULL for generic names */
9941  )
9942 {
9943  SCIP_Real color;
9944  int i;
9945 
9946  assert(exprgraph != NULL);
9947  assert(node != NULL);
9948  assert(file != NULL);
9949 
9950  color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
9951  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
9952 
9953  exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
9954 
9955  SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
9957  SCIPmessageFPrintInfo(messagehdlr, file, "!");
9959  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9961  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9962 
9963  SCIPmessageFPrintInfo(messagehdlr, file, "\"");
9964 
9965  if( !node->enabled )
9966  SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
9967 
9968  SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
9969 
9970  /* add edges from node to children */
9971  for( i = 0; i < node->nchildren; ++i )
9972  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d -> n%d_%d [label=\"c%d\"]\n", node->depth, node->pos, node->children[i]->depth, node->children[i]->pos, i);
9973 }
9974 
9975 /** evaluate node of expression graph w.r.t. values stored in children */
9976 static
9978  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9979  SCIP_Real* varvals /**< values for variables */
9980  )
9981 {
9982  int i;
9984  SCIP_Real* buf;
9985 
9986  assert(node != NULL);
9987 
9988  /* if many children, get large enough memory to store argument values */
9990  {
9991  SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
9992  }
9993  else
9994  {
9995  buf = staticbuf;
9996  }
9997 
9998  /* get values of children */
9999  for( i = 0; i < node->nchildren; ++i )
10000  {
10001  assert(node->children[i]->value != SCIP_INVALID); /*lint !e777*/
10002  buf[i] = node->children[i]->value; /*lint !e644*/
10003  }
10004 
10005  /* evaluate this expression */
10006  assert(exprOpTable[node->op].eval != NULL);
10007  SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
10008  assert(node->value != SCIP_INVALID); /*lint !e777*/
10009 
10010  /* free memory, if allocated before */
10011  if( staticbuf != buf )
10012  {
10013  BMSfreeMemoryArray(&buf);
10014  }
10015 
10016  return SCIP_OKAY;
10017 }
10018 
10019 /** evaluates node including subtree */
10020 static
10022  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10023  SCIP_Real* varvals /**< values for variables */
10024  )
10025 {
10026  int i;
10027 
10028  assert(node != NULL);
10029 
10030  for( i = 0; i < node->nchildren; ++i )
10031  {
10032  SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
10033  }
10034 
10035  SCIP_CALL( exprgraphNodeEval(node, varvals) );
10036 
10037  return SCIP_OKAY;
10038 }
10039 
10040 /** updates bounds of a node if a children has changed its bounds */
10041 static
10043  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10044  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10045  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
10046  SCIP_Bool parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
10047  )
10048 {
10049  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
10050  SCIP_INTERVAL* childbounds;
10051  SCIP_INTERVAL newbounds;
10052  int i;
10053 
10054  assert(node != NULL);
10055  assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
10056  assert(node->pos >= 0); /* node should be in graph */
10057  assert(node->op != SCIP_EXPR_VARIDX);
10058  assert(node->op != SCIP_EXPR_PARAM);
10059 
10060  /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
10061  * if node is disabled, then also do nothing */
10062  if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
10063  return SCIP_OKAY;
10064 
10065  /* if many children, get large enough memory to store children bounds */
10067  {
10068  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
10069  }
10070  else
10071  {
10072  childbounds = childboundsstatic;
10073  }
10074 
10075  /* assemble bounds of children */
10076  for( i = 0; i < node->nchildren; ++i )
10077  {
10078  /* child should have valid and non-empty bounds */
10080  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10081 
10082  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
10083  }
10084 
10085  /* call interval evaluation function for this operand */
10086  assert( exprOpTable[node->op].inteval != NULL );
10087  SCIPintervalSet(&newbounds, 0.0);
10088  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
10089 
10090  /* free memory, if allocated before */
10091  if( childbounds != childboundsstatic )
10092  {
10093  BMSfreeMemoryArray(&childbounds);
10094  }
10095 
10096  /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
10097 
10098  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
10099  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
10100  *
10101  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
10102  *
10103  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
10104  */
10105  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
10106  ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
10107  {
10108  for( i = 0; i < node->nparents; ++i )
10110 
10111  node->bounds = newbounds;
10112  }
10113  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
10114  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
10115  {
10116  for( i = 0; i < node->nparents; ++i )
10118 
10119  node->bounds = newbounds;
10120  }
10121  else
10122  {
10123  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
10124  }
10125 
10126  SCIPdebugMessage("updated bounds of node %p (%d,%d) op %s to [%g,%g]\n", (void*)node, node->depth, node->pos, SCIPexpropGetName(node->op), node->bounds.inf, node->bounds.sup);
10127 
10128  /* node now has valid bounds */
10129  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
10130 
10131  return SCIP_OKAY;
10132 }
10133 
10134 /** propagate bounds of a node into children by reverting the nodes expression */
10135 static
10137  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10138  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
10139  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10140  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
10141  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
10142  )
10143 {
10144  SCIP_INTERVAL childbounds;
10145  int i;
10146 
10147  assert(exprgraph != NULL);
10148  assert(node != NULL);
10149  assert(node->depth >= 0); /* node should be in graph */
10150  assert(node->pos >= 0); /* node should be in graph */
10151  assert(minstrength >= 0.0);
10152  assert(cutoff != NULL);
10153  assert(!SCIPintervalIsEmpty(infinity, node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
10154  assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
10155 
10156  /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
10158  return;
10159 
10160  /* if node is not enabled, then do nothing */
10161  if( !node->enabled )
10162  return;
10163 
10164  /* tell children that they should propagate their bounds even if not tightened */
10166  minstrength = -1.0;
10167 
10168  /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
10170 
10171  /* SCIPdebugMessage("propagating node %p (%d,%d) op %s: [%10g,%10g] = ", (void*)node, node->depth, node->pos, SCIPexpropGetName(node->op), node->bounds.inf, node->bounds.sup);
10172  * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10173  * SCIPdebugPrintf("\n");
10174  */
10175 
10176  /* @todo add callback to exprOpTable for this */
10177 
10178  switch( node->op )
10179  {
10180  case SCIP_EXPR_VARIDX:
10181  case SCIP_EXPR_CONST:
10182  case SCIP_EXPR_PARAM:
10183  /* cannot propagate bound changes further */
10184  break;
10185 
10186  case SCIP_EXPR_PLUS:
10187  {
10188  assert(node->nchildren == 2);
10189  /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
10190 
10191  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10192  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10193 
10194  if( *cutoff )
10195  break;
10196 
10197  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10198  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10199 
10200  break;
10201  }
10202 
10203  case SCIP_EXPR_MINUS:
10204  {
10205  assert(node->nchildren == 2);
10206  /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
10207 
10208  SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10209  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10210 
10211  if( *cutoff )
10212  break;
10213 
10214  SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10215  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10216 
10217  break;
10218  }
10219 
10220  case SCIP_EXPR_MUL:
10221  {
10222  assert(node->nchildren == 2);
10223  /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
10224 
10225  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10226  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10227 
10228  if( *cutoff )
10229  break;
10230 
10231  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10232  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10233 
10234  break;
10235  }
10236 
10237  case SCIP_EXPR_DIV:
10238  {
10239  assert(node->nchildren == 2);
10240  /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
10241 
10242  SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10243  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10244 
10245  if( *cutoff )
10246  break;
10247 
10248  SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10249  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10250 
10251  break;
10252  }
10253 
10254  case SCIP_EXPR_SQUARE:
10255  {
10256  assert(node->nchildren == 1);
10257  /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
10258 
10259  if( node->bounds.sup < 0.0 )
10260  {
10261  *cutoff = TRUE;
10262  break;
10263  }
10264 
10265  SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
10266  if( node->children[0]->bounds.inf <= -childbounds.inf )
10267  SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
10268  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10269 
10270  break;
10271  }
10272 
10273  case SCIP_EXPR_SQRT:
10274  {
10275  assert(node->nchildren == 1);
10276  /* f = sqrt(c0) -> c0 = f^2 */
10277 
10278  SCIPintervalSquare(infinity, &childbounds, node->bounds);
10279  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10280 
10281  break;
10282  }
10283 
10284  case SCIP_EXPR_REALPOWER:
10285  {
10286  assert(node->nchildren == 1);
10287 
10288  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
10289 
10290  if( SCIPintervalIsEmpty(infinity, childbounds) )
10291  {
10292  *cutoff = TRUE;
10293  break;
10294  }
10295  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10296 
10297  break;
10298  }
10299 
10300  case SCIP_EXPR_SIGNPOWER:
10301  {
10302  assert(node->nchildren == 1);
10303 
10304  if( node->data.dbl != 0.0 )
10305  {
10306  SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
10307  }
10308  else
10309  {
10310  /* behaves like SCIP_EXPR_SIGN */
10311  SCIPintervalSetBounds(&childbounds,
10312  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10313  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10314  }
10315 
10316  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10317 
10318  break;
10319  }
10320 
10321  case SCIP_EXPR_INTPOWER:
10322  {
10323  assert(node->nchildren == 1);
10324 
10325  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
10326 
10327  if( SCIPintervalIsEmpty(infinity, childbounds) )
10328  {
10329  *cutoff = TRUE;
10330  break;
10331  }
10332  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10333 
10334  break;
10335  }
10336 
10337  case SCIP_EXPR_EXP:
10338  {
10339  assert(node->nchildren == 1);
10340  /* f = exp(c0) -> c0 = log(f) */
10341 
10342  if( node->bounds.sup < 0.0 )
10343  {
10344  *cutoff = TRUE;
10345  break;
10346  }
10347 
10348  SCIPintervalLog(infinity, &childbounds, node->bounds);
10349  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10350 
10351  break;
10352  }
10353 
10354  case SCIP_EXPR_LOG:
10355  {
10356  assert(node->nchildren == 1);
10357  /* f = log(c0) -> c0 = exp(f) */
10358 
10359  SCIPintervalExp(infinity, &childbounds, node->bounds);
10360  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10361 
10362  break;
10363  }
10364 
10365  case SCIP_EXPR_SIN:
10366  case SCIP_EXPR_COS:
10367  case SCIP_EXPR_TAN:
10368  /* case SCIP_EXPR_ERF: */
10369  /* case SCIP_EXPR_ERFI: */
10370  {
10371  assert(node->nchildren == 1);
10372 
10373  /* @todo implement */
10374 
10375  break;
10376  }
10377 
10378  case SCIP_EXPR_ABS:
10379  {
10380  assert(node->nchildren == 1);
10381 
10382  /* use identity if child bounds are non-negative */
10383  if( node->children[0]->bounds.inf >= 0 )
10384  {
10385  SCIPintervalSetBounds(&childbounds, node->bounds.inf, node->bounds.sup);
10386  }
10387  /* use -identity if child bounds are non-positive */
10388  else if( node->children[0]->bounds.sup <= 0 )
10389  {
10390  assert(node->bounds.inf <= node->bounds.sup);
10391  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, -node->bounds.inf);
10392  }
10393  /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
10394  else
10395  {
10396  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
10397  }
10398 
10399  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10400 
10401  break;
10402  }
10403 
10404  case SCIP_EXPR_SIGN:
10405  {
10406  assert(node->nchildren == 1);
10407  /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
10408 
10409  SCIPintervalSetBounds(&childbounds,
10410  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10411  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10412  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10413 
10414  break;
10415  }
10416 
10417  case SCIP_EXPR_MIN:
10418  {
10419  assert(node->nchildren == 2);
10420  /* f = min(c0,c1) -> f <= c0, f <= c1
10421  * if c1 > f -> c0 = f
10422  * if c0 > f -> c1 = f
10423  */
10424 
10425  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10426  node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10427  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10428 
10429  if( *cutoff )
10430  break;
10431 
10432  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10433  node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10434  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10435 
10436  break;
10437  }
10438 
10439  case SCIP_EXPR_MAX:
10440  {
10441  assert(node->nchildren == 2);
10442  /* f = max(c0, c1) -> f >= c0, f >= c1
10443  * if c1 < f -> c0 = f
10444  * if c0 < f -> c1 = f
10445  */
10446 
10447  SCIPintervalSetBounds(&childbounds,
10448  node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10449  node->bounds.sup);
10450  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10451 
10452  SCIPintervalSetBounds(&childbounds,
10453  node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10454  node->bounds.sup);
10455  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10456 
10457  break;
10458  }
10459 
10460  case SCIP_EXPR_SUM:
10461  {
10462  SCIP_ROUNDMODE prevroundmode;
10463 
10464  /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
10465 
10466  SCIP_Real minlinactivity;
10467  SCIP_Real maxlinactivity;
10468  int minlinactivityinf;
10469  int maxlinactivityinf;
10470 
10471  if( node->nchildren == 0 )
10472  break;
10473 
10474  if( SCIPintervalIsEntire(infinity, node->bounds) )
10475  break;
10476 
10477  minlinactivity = 0.0;
10478  maxlinactivity = 0.0;
10479  minlinactivityinf = 0;
10480  maxlinactivityinf = 0;
10481 
10482  prevroundmode = SCIPintervalGetRoundingMode();
10484 
10485  for( i = 0; i < node->nchildren; ++i )
10486  {
10487  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10488 
10489  /* minimal activity is only useful if node has a finite upper bound */
10490  if( node->bounds.sup < infinity )
10491  {
10492  if( node->children[i]->bounds.inf <= -infinity )
10493  {
10494  ++minlinactivityinf;
10495  }
10496  else
10497  {
10498  assert(node->children[i]->bounds.inf < infinity);
10499  minlinactivity += node->children[i]->bounds.inf;
10500  }
10501  }
10502 
10503  /* maximal activity is only useful if node has a finite lower bound
10504  * we compute negated maximal activity here so we can keep downward rounding
10505  */
10506  if( node->bounds.inf > -infinity )
10507  {
10508  if( node->children[i]->bounds.sup >= infinity )
10509  {
10510  ++maxlinactivityinf;
10511  }
10512  else
10513  {
10514  assert(node->children[i]->bounds.sup > -infinity);
10515  maxlinactivity -= node->children[i]->bounds.sup;
10516  }
10517  }
10518  }
10519  maxlinactivity = -maxlinactivity; /* correct sign */
10520 
10521  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10522  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10523  ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10524  )
10525  {
10526  SCIPintervalSetRoundingMode(prevroundmode);
10527  break;
10528  }
10529 
10530  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10531  {
10532  /* upper bounds of c_i is
10533  * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
10534  * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
10535  */
10536  SCIPintervalSetEntire(infinity, &childbounds);
10537  if( node->bounds.sup < infinity )
10538  {
10539  /* we are still in downward rounding mode, so negate and negate to get upward rounding */
10540  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10541  {
10542  assert(minlinactivityinf == 1);
10543  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
10544  }
10545  else if( minlinactivityinf == 0 )
10546  {
10547  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
10548  }
10549  }
10550 
10551  /* lower bounds of c_i is
10552  * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
10553  * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
10554  */
10555  if( node->bounds.inf > -infinity )
10556  {
10557  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10558  {
10559  assert(maxlinactivityinf == 1);
10560  childbounds.inf = node->bounds.inf - maxlinactivity;
10561  }
10562  else if( maxlinactivityinf == 0 )
10563  {
10564  childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
10565  }
10566  }
10567 
10568  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10569  }
10570 
10571  SCIPintervalSetRoundingMode(prevroundmode);
10572 
10573  break;
10574  }
10575 
10576  case SCIP_EXPR_PRODUCT:
10577  {
10578  int j;
10579  /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
10580 
10581  /* too expensive (runtime here is quadratic in number of children) */
10582  if( node->nchildren > 10 )
10583  break;
10584 
10585  /* useless */
10586  if( SCIPintervalIsEntire(infinity, node->bounds) )
10587  break;
10588 
10589  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10590  {
10591  /* compute prod_{j:j!=i} c_j */
10592  SCIPintervalSet(&childbounds, 1.0);
10593  for( j = 0; j < node->nchildren; ++j )
10594  {
10595  if( i == j )
10596  continue;
10597  SCIPintervalMul(infinity, &childbounds, childbounds, node->children[j]->bounds);
10598 
10599  /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
10600  if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
10601  break;
10602  }
10603 
10604  if( j == node->nchildren )
10605  {
10606  SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
10607  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10608  }
10609  }
10610 
10611  break;
10612  }
10613 
10614  case SCIP_EXPR_LINEAR:
10615  {
10616  SCIP_ROUNDMODE prevroundmode;
10617  SCIP_Real* coefs;
10618 
10619  /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10620 
10621  SCIP_Real minlinactivity;
10622  SCIP_Real maxlinactivity;
10623  int minlinactivityinf;
10624  int maxlinactivityinf;
10625 
10626  if( node->nchildren == 0 )
10627  break;
10628 
10629  if( SCIPintervalIsEntire(infinity, node->bounds) )
10630  break;
10631 
10632  coefs = (SCIP_Real*)node->data.data;
10633 
10634  minlinactivity = coefs[node->nchildren];
10635  maxlinactivity = -coefs[node->nchildren];
10636  minlinactivityinf = 0;
10637  maxlinactivityinf = 0;
10638 
10639  prevroundmode = SCIPintervalGetRoundingMode();
10641 
10642  for( i = 0; i < node->nchildren; ++i )
10643  {
10644  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10645 
10646  /* minimal activity is only useful if node has a finite upper bound */
10647  if( node->bounds.sup < infinity )
10648  {
10649  if( coefs[i] >= 0.0 )
10650  {
10651  if( node->children[i]->bounds.inf <= -infinity )
10652  {
10653  ++minlinactivityinf;
10654  }
10655  else
10656  {
10657  assert(node->children[i]->bounds.inf < infinity);
10658  minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10659  }
10660  }
10661  else
10662  {
10663  if( node->children[i]->bounds.sup >= infinity )
10664  {
10665  ++minlinactivityinf;
10666  }
10667  else
10668  {
10669  assert(node->children[i]->bounds.sup > -infinity);
10670  minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10671  }
10672  }
10673  }
10674 
10675  /* maximal activity is only useful if node has a finite lower bound
10676  * we compute negated maximal activity here so we can keep downward rounding
10677  */
10678  if( node->bounds.inf > -infinity )
10679  {
10680  if( coefs[i] >= 0.0 )
10681  {
10682  if( node->children[i]->bounds.sup >= infinity )
10683  {
10684  ++maxlinactivityinf;
10685  }
10686  else
10687  {
10688  assert(node->children[i]->bounds.sup > -infinity);
10689  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.sup;
10690  }
10691  }
10692  else
10693  {
10694  if( node->children[i]->bounds.inf <= -infinity )
10695  {
10696  ++maxlinactivityinf;
10697  }
10698  else
10699  {
10700  assert(node->children[i]->bounds.inf < infinity);
10701  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.inf;
10702  }
10703  }
10704  }
10705  }
10706  maxlinactivity = SCIPintervalNegateReal(maxlinactivity); /* correct sign */
10707 
10708  /* SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]; bounds = [%10g,%10g]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf, node->bounds.inf, node->bounds.sup); */
10709 
10710  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10711  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10712  (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10713  )
10714  {
10715  SCIPintervalSetRoundingMode(prevroundmode);
10716  break;
10717  }
10718 
10719  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10720  {
10721  SCIP_INTERVAL ac;
10722 
10723  if( coefs[i] == 0.0 )
10724  continue;
10725 
10726  /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10727  SCIPintervalSet(&ac, 0.0);
10728  if( coefs[i] >= 0.0 )
10729  {
10730  if( node->children[i]->bounds.inf > -infinity )
10731  ac.inf = coefs[i] * node->children[i]->bounds.inf;
10732  if( node->children[i]->bounds.sup < infinity )
10734  }
10735  else
10736  {
10737  if( node->children[i]->bounds.sup < infinity )
10738  ac.inf = coefs[i] * node->children[i]->bounds.sup;
10739  if( node->children[i]->bounds.inf > -infinity )
10740  ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10741  }
10742 
10743  SCIPintervalSetEntire(infinity, &childbounds);
10744  if( coefs[i] > 0.0 )
10745  {
10746  /* upper bounds of c_i is
10747  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10748  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10749  */
10750  if( node->bounds.sup < infinity )
10751  {
10752  /* we are still in downward rounding mode, so negate to get upward rounding */
10753  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10754  {
10755  assert(minlinactivityinf == 1);
10756  childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10757  }
10758  else if( minlinactivityinf == 0 )
10759  {
10760  childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10761  }
10762  }
10763 
10764  /* lower bounds of c_i is
10765  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10766  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10767  */
10768  if( node->bounds.inf > -infinity )
10769  {
10770  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10771  {
10772  assert(maxlinactivityinf == 1);
10773  childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10774  }
10775  else if( maxlinactivityinf == 0 )
10776  {
10777  childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10778  }
10779  }
10780  }
10781  else
10782  {
10783  /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10784  * thus, we do (b-a)/(-c) in downward rounding
10785  */
10786  /* lower bounds of c_i is
10787  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10788  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10789  */
10790  if( node->bounds.sup < infinity )
10791  {
10792  if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10793  {
10794  assert(minlinactivityinf == 1);
10795  childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10796  }
10797  else if( minlinactivityinf == 0 )
10798  {
10799  childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10800  }
10801  }
10802 
10803  /* upper bounds of c_i is
10804  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10805  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10806  */
10807  if( node->bounds.inf > -infinity )
10808  {
10809  /* we are still in downward rounding mode, so negate to get upward rounding */
10810  if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10811  {
10812  assert(maxlinactivityinf == 1);
10813  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10814  }
10815  else if( maxlinactivityinf == 0 )
10816  {
10817  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10818  }
10819  }
10820  }
10821 
10822  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10823  }
10824 
10825  SCIPintervalSetRoundingMode(prevroundmode);
10826 
10827  break;
10828  }
10829 
10830  case SCIP_EXPR_QUADRATIC:
10831  {
10832  SCIP_EXPRDATA_QUADRATIC* quaddata;
10833  SCIP_INTERVAL tmp;
10834  SCIP_INTERVAL a;
10835  SCIP_INTERVAL b;
10836  SCIP_INTERVAL c;
10837  SCIP_QUADELEM* quadelems;
10838  int nquadelems;
10839  SCIP_Real* lincoefs;
10840  int k;
10841 
10842  /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10843  * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10844  */
10845 
10846  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10847  quadelems = quaddata->quadelems;
10848  nquadelems = quaddata->nquadelems;
10849  lincoefs = quaddata->lincoefs;
10850 
10851  /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10852  if( nquadelems > 10 )
10853  break;
10854 
10855  if( SCIPintervalIsEntire(infinity, node->bounds) )
10856  break;
10857 
10858  if( node->nchildren == 2 && nquadelems > 0 )
10859  {
10860  /* if it's a bivariate quadratic expression with bilinear term, do something special */
10861  SCIP_Real ax; /* square coefficient of first child */
10862  SCIP_Real ay; /* square coefficient of second child */
10863  SCIP_Real axy; /* bilinear coefficient */
10864 
10865  ax = 0.0;
10866  ay = 0.0;
10867  axy = 0.0;
10868  for( i = 0; i < nquadelems; ++i )
10869  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10870  ax += quadelems[i].coef;
10871  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10872  ay += quadelems[i].coef;
10873  else
10874  axy += quadelems[i].coef;
10875 
10876  c = node->bounds;
10877  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10878 
10879  /* compute bounds for x */
10881  infinity, &childbounds, ax, ay, axy,
10882  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10883  c, node->children[0]->bounds, node->children[1]->bounds
10884  );
10885  if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10886  {
10887  SCIPdebugMessage("%g x^2 + %g y^2 + %g xy + %g x + %g y in [%g,%g], x = [%g,%g], y = [%g,%g] -> x in [%g,%g], cutoff = %d\n",
10888  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10889  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10890  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10891  );
10892  }
10893 
10894  if( SCIPintervalIsEmpty(infinity, childbounds) )
10895  *cutoff = TRUE;
10896  else
10897  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10898  if( *cutoff )
10899  break;
10900 
10901  /* compute bounds for y */
10903  infinity, &childbounds, ay, ax, axy,
10904  lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
10905  c, node->children[1]->bounds, node->children[0]->bounds
10906  );
10907 
10908  if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
10909  {
10910  SCIPdebugMessage("%g x^2 + %g y^2 + %g xy + %g x + %g y in [%g,%g], x = [%g,%g], y = [%g,%g] -> y in [%g,%g], cutoff = %d\n",
10911  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10912  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10913  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10914  );
10915  }
10916 
10917  if( SCIPintervalIsEmpty(infinity, childbounds) )
10918  *cutoff = TRUE;
10919  else
10920  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10921  if( *cutoff )
10922  break;
10923 
10924  break;
10925  }
10926 
10927  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10928  {
10929  SCIPintervalSet(&a, 0.0);
10930  SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
10931  c = node->bounds;
10932  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10933 
10934  /* move linear terms not corresponding to i into c
10935  * @todo do this faster, see EXPR_LINEAR
10936  */
10937  if( lincoefs != NULL )
10938  for( k = 0; k < node->nchildren; ++k )
10939  if( i != k && lincoefs[k] != 0.0 )
10940  {
10941  SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
10942  SCIPintervalSub(infinity, &c, c, tmp);
10943  }
10944 
10945  for( k = 0; k < nquadelems; ++k )
10946  {
10947  if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
10948  {
10949  SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
10950  }
10951  else if( quadelems[k].idx1 == i )
10952  {
10953  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
10954  SCIPintervalAdd(infinity, &b, b, tmp);
10955  }
10956  else if( quadelems[k].idx2 == i )
10957  {
10958  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
10959  SCIPintervalAdd(infinity, &b, b, tmp);
10960  }
10961  else if( quadelems[k].idx1 == quadelems[k].idx2 )
10962  {
10963  SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
10964  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
10965  SCIPintervalSub(infinity, &c, c, tmp);
10966  }
10967  else
10968  {
10969  SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
10970  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
10971  SCIPintervalSub(infinity, &c, c, tmp);
10972  }
10973  }
10974 
10975  SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
10976  a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
10977  SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c);
10978  if( SCIPintervalIsEmpty(infinity, childbounds) )
10979  *cutoff = TRUE;
10980  else
10981  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10982  }
10983 
10984  break;
10985  }
10986 
10987  case SCIP_EXPR_POLYNOMIAL:
10988  {
10989  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
10990  SCIP_EXPRDATA_MONOMIAL** monomials;
10991  SCIP_EXPRDATA_MONOMIAL* monomial;
10992  int nmonomials;
10993  int j;
10994  int k;
10995  SCIP_Real n;
10996  int nexpisdoublen;
10997  int nexpishalfn;
10998  char abc_flag;
10999 
11000  SCIP_INTERVAL monomialcoef;
11001  SCIP_INTERVAL tmp;
11002  SCIP_INTERVAL a;
11003  SCIP_INTERVAL b;
11004  SCIP_INTERVAL c;
11005 
11006  /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
11007  * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
11008  *
11009  * we determine n by setting n to the first exponent of x that we see
11010  * then we count how often we see x^(2n) and x^(n/2)
11011  * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
11012  */
11013 
11014  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11015  monomials = polynomialdata->monomials;
11016  nmonomials = polynomialdata->nmonomials;
11017 
11018  if( SCIPintervalIsEntire(infinity, node->bounds) )
11019  break;
11020 
11021  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11022  {
11023  n = 0.0;
11024  nexpisdoublen = 0;
11025  nexpishalfn = 0;
11026  for( j = 0; j < nmonomials; ++j )
11027  {
11028  monomial = monomials[j];
11029  for( k = 0; k < monomial->nfactors; ++k )
11030  {
11031  if( monomial->childidxs[k] == i )
11032  {
11033  if( n == 0.0 )
11034  n = monomial->exponents[k];
11035  else if( n == 2*monomial->exponents[k] ) /*lint !e777*/
11036  ++nexpishalfn;
11037  else if( 2*n == monomial->exponents[k] ) /*lint !e777*/
11038  ++nexpisdoublen;
11039  }
11040  }
11041  }
11042 
11043  if( n == 0.0 )
11044  {
11045  /* child does not appear in polynomial -> cannot deduce bound */
11046  continue;
11047  }
11048 
11049  /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
11050  if( nexpishalfn > nexpisdoublen )
11051  n /= 2.0;
11052 
11053  SCIPintervalSet(&a, 0.0);
11054  SCIPintervalSet(&b, 0.0);
11055  SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
11056 
11057  for( j = 0; j < nmonomials; ++j )
11058  {
11059  monomial = monomials[j];
11060  SCIPintervalSet(&monomialcoef, monomial->coef);
11061  abc_flag = 'c';
11062  for( k = 0; k < monomial->nfactors; ++k )
11063  {
11064  if( monomial->childidxs[k] == i )
11065  {
11066  assert(abc_flag == 'c'); /* child should appear only once per monom */
11067  if( n > 0.0 )
11068  {
11069  if( monomial->exponents[k] > 2.0*n )
11070  {
11071  abc_flag = 'a';
11072  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11073  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11074  }
11075  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11076  {
11077  abc_flag = 'a';
11078  }
11079  else if( monomial->exponents[k] > n )
11080  {
11081  abc_flag = 'b';
11082  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11083  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11084  }
11085  else if( monomial->exponents[k] == n ) /*lint !e777*/
11086  {
11087  abc_flag = 'b';
11088  }
11089  else
11090  {
11091  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11092  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11093  }
11094  }
11095  else
11096  {
11097  assert(n < 0.0);
11098  if( monomial->exponents[k] < 2.0*n )
11099  {
11100  abc_flag = 'a';
11101  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11102  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11103  }
11104  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11105  {
11106  abc_flag = 'a';
11107  }
11108  else if( monomial->exponents[k] < n )
11109  {
11110  abc_flag = 'b';
11111  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11112  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11113  }
11114  else if( monomial->exponents[k] == n ) /*lint !e777*/
11115  {
11116  abc_flag = 'b';
11117  }
11118  else
11119  {
11120  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11121  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11122  }
11123  }
11124  }
11125  else
11126  {
11127  SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
11128  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11129  }
11130  }
11131 
11132  if( abc_flag == 'a' )
11133  {
11134  SCIPintervalAdd(infinity, &a, a, monomialcoef);
11135  /* if monomialcoef is such that a exceeds value for infinity, then stop */
11136  if( a.inf >= infinity || a.sup <= -infinity )
11137  break;
11138  }
11139  else if( abc_flag == 'b' )
11140  {
11141  SCIPintervalAdd(infinity, &b, b, monomialcoef);
11142  /* if monomialcoef is such that b exceeds value for infinity, then stop */
11143  if( b.inf >= infinity || b.sup <= -infinity )
11144  break;
11145  }
11146  else
11147  {
11148  SCIPintervalSub(infinity, &c, c, monomialcoef);
11149  /* if monomialcoef is such that c exceeds value for infinity, then stop */
11150  if( c.inf >= infinity || c.sup <= -infinity )
11151  break;
11152  }
11153  }
11154 
11155  /* if we run out of numbers (within -infinity,infinity) above, then stop */
11156  if( j < nmonomials )
11157  continue;
11158 
11159  /* now have equation a*child^(2n) + b*child^n = c
11160  * solve a*y^2 + b*y = c, then child^n = y
11161  */
11162  SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g]",
11163  a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup);
11164  SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c);
11165  SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
11166 
11167  if( SCIPintervalIsEmpty(infinity, tmp) )
11168  {
11169  *cutoff = TRUE;
11170  break;
11171  }
11172 
11173  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
11174  SCIPdebugPrintf(" -> c%d = [%10g, %10g]\n", i, childbounds.inf, childbounds.sup);
11175  if( SCIPintervalIsEmpty(infinity, childbounds) )
11176  {
11177  SCIPdebugMessage(" -> cutoff\n");
11178  *cutoff = TRUE;
11179  break;
11180  }
11181 
11182  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11183 
11184  /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
11185  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11186  SCIPdebugPrintf("\n"); */
11187  }
11188 
11189  break;
11190  }
11191 
11192  case SCIP_EXPR_USER:
11193  {
11194  SCIP_INTERVAL* childrenbounds;
11195  SCIP_EXPRDATA_USER* exprdata;
11196  int c;
11197 
11198  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11199 
11200  /* do nothing if callback not implemented */
11201  if( exprdata->prop == NULL )
11202  break;
11203 
11204  /* if only one child, do faster */
11205  if( node->nchildren == 1 )
11206  {
11207  childbounds = node->children[0]->bounds;
11208  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, 1, &childbounds, node->bounds, cutoff) );
11209 
11210  if( !*cutoff )
11211  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11212 
11213  break;
11214  }
11215 
11216  SCIP_ALLOC_ABORT( BMSallocBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren) );
11217  for( c = 0; c < node->nchildren; ++c )
11218  childrenbounds[c] = node->children[c]->bounds;
11219 
11220  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, node->nchildren, childrenbounds, node->bounds, cutoff) );
11221 
11222  for( c = 0; !*cutoff && c < node->nchildren; ++c )
11223  {
11224  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[c], childrenbounds[c], minstrength, infinity, cutoff);
11225  }
11226 
11227  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren);
11228 
11229  break;
11230  }
11231 
11232  case SCIP_EXPR_LAST:
11233  SCIPABORT();
11234  break;
11235  }
11236 }
11237 
11238 /** removes duplicate children in a polynomial expression node
11239  *
11240  * Leaves NULL's in children array.
11241  */
11242 static
11244  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11245  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11246  )
11247 {
11248  SCIP_Bool foundduplicates;
11249  int* childmap;
11250  int i;
11251  int j;
11252 
11253  assert(exprgraph != NULL);
11254  assert(node != NULL);
11255  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11256 
11257  if( node->nchildren == 0 )
11258  return SCIP_OKAY;
11259 
11260  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
11261 
11262  foundduplicates = FALSE;
11263  for( i = 0; i < node->nchildren; ++i )
11264  {
11265  if( node->children[i] == NULL )
11266  continue;
11267  childmap[i] = i; /*lint !e644*/
11268 
11269  for( j = i+1; j < node->nchildren; ++j )
11270  {
11271  if( node->children[j] == NULL )
11272  continue;
11273 
11274  if( node->children[i] == node->children[j] )
11275  {
11276  /* node should be parent of children[j] at least twice,
11277  * so we remove it once
11278  */
11279  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
11280  node->children[j] = NULL;
11281  assert(exprgraphNodeIsParent(node->children[i], node));
11282 
11283  childmap[j] = i;
11284  foundduplicates = TRUE;
11285  }
11286  }
11287  }
11288 
11289  /* apply childmap to monomials */
11290  if( foundduplicates )
11292 
11293  /* free childmap */
11294  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
11295 
11296  return SCIP_OKAY;
11297 }
11298 
11299 /** eliminates NULL's in children array and shrinks it to actual size */
11300 static
11302  BMS_BLKMEM* blkmem, /**< block memory */
11303  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11304  )
11305 {
11306  int* childmap;
11307  int lastnonnull;
11308  int i;
11309 
11310  assert(blkmem != NULL);
11311  assert(node != NULL);
11312  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11313 
11314  if( node->nchildren == 0 )
11315  return SCIP_OKAY;
11316 
11317  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
11318 
11319  /* close gaps in children array */
11320  lastnonnull = node->nchildren-1;
11321  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11322  --lastnonnull;
11323  for( i = 0; i <= lastnonnull; ++i )
11324  {
11325  if( node->children[i] != NULL )
11326  {
11327  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
11328  continue;
11329  }
11330  assert(node->children[lastnonnull] != NULL);
11331 
11332  /* move child at lastnonnull to position i */
11333  node->children[i] = node->children[lastnonnull];
11334  node->children[lastnonnull] = NULL;
11335  childmap[lastnonnull] = i;
11336 
11337  /* update lastnonnull */
11338  --lastnonnull;
11339  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11340  --lastnonnull;
11341  }
11342  assert(i > lastnonnull);
11343 
11344  /* apply childmap to monomials */
11345  if( lastnonnull < node->nchildren-1 )
11347 
11348  BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
11349 
11350  /* shrink children array */
11351  if( lastnonnull >= 0 )
11352  {
11353  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
11354  node->nchildren = lastnonnull+1;
11355  }
11356  else
11357  {
11358  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11359  node->nchildren = 0;
11360  }
11361 
11362  return SCIP_OKAY;
11363 }
11364 
11365 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
11366  *
11367  * Converts node into polynomial, if possible and not constant.
11368  */
11369 static
11371  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11372  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
11373  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
11374  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
11375  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
11376  SCIP_Bool* havechange /**< flag to set if the node has been changed */
11377  )
11378 {
11379  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11380  SCIP_EXPRDATA_MONOMIAL* monomial;
11381  BMS_BLKMEM* blkmem;
11382  SCIP_Bool removechild;
11383  SCIP_Bool* childinuse;
11384  int* childmap;
11385  int childmapsize;
11386  int i;
11387  int j;
11388  int orignchildren;
11389 
11390  assert(exprgraph != NULL);
11391  assert(node != NULL);
11392  assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
11393  assert(havechange != NULL);
11394 
11395  blkmem = exprgraph->blkmem;
11396  assert(blkmem != NULL);
11397 
11398  SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
11399 
11400  /* if all children are constants, then turn this node into constant */
11401  for( i = 0; i < node->nchildren; ++i )
11402  if( node->children[i]->op != SCIP_EXPR_CONST )
11403  break;
11404  if( node->nchildren > 0 && i == node->nchildren )
11405  {
11406  /* get value of node */
11408  assert(node->value != SCIP_INVALID); /*lint !e777*/
11409 
11410  SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
11411  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11412  SCIPdebugPrintf("\n");
11413 
11414  /* free expression data */
11415  if( exprOpTable[node->op].freedata != NULL )
11416  exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
11417 
11418  /* disconnect from children */
11419  for( i = 0; i < node->nchildren; ++i )
11420  {
11421  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11422  }
11423  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11424  node->nchildren = 0;
11425 
11426  /* turn into constant expression */
11427  node->op = SCIP_EXPR_CONST;
11428  node->data.dbl = node->value;
11429 
11430  *havechange = TRUE;
11431  node->simplified = TRUE;
11432 
11433  return SCIP_OKAY;
11434  }
11435 
11436  /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
11437  * @todo log(product) -> sum(log)
11438  * @todo product(exp) -> exp(sum)
11439  * @todo exp(x)^p -> exp(p*x)
11440  * @todo exp(const*log(x)) -> x^const
11441  */
11442 
11443  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
11444 
11445  if( node->op != SCIP_EXPR_POLYNOMIAL )
11446  {
11447  node->simplified = TRUE;
11448  return SCIP_OKAY;
11449  }
11450 
11451  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11452  assert(polynomialdata != NULL);
11453 
11454  orignchildren = node->nchildren;
11455 
11456  /* check if we have duplicate children and merge */
11458  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11459 
11460  SCIPdebugMessage("expand factors in expression node ");
11461  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11462  SCIPdebugPrintf("\n");
11463 
11464  childmap = NULL;
11465  childmapsize = 0;
11466 
11467  /* resolve children that are constants
11468  * we do this first, because it reduces the degree and number of factors in the monomials,
11469  * thereby allowing some expansions of polynomials that may not be possible otherwise, e.g., turning c0*c1 with c0=quadratic and c1=constant into a single monomial
11470  */
11471  for( i = 0; i < node->nchildren; ++i )
11472  {
11473  if( node->children[i] == NULL )
11474  continue;
11475 
11476  /* convert children to polynomial, if not constant or polynomial
11477  * if child was simplified in this round, it may have already been converted, and then nothing happens
11478  * but if child was already simplified, then it was not converted, and thus we try it here
11479  */
11480  if( node->children[i]->op != SCIP_EXPR_CONST )
11481  continue;
11482 
11483  SCIPdebugMessage("expand child %d in expression node ", i);
11484  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11485  SCIPdebugPrintf("\n\tchild = ");
11486  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11487  SCIPdebugPrintf("\n");
11488 
11489  removechild = TRUE; /* we intend to release children[i] */
11490 
11491  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11492 
11493  /* put constant of child i into every monomial where child i is used */
11494  for( j = 0; j < polynomialdata->nmonomials; ++j )
11495  {
11496  int factorpos;
11497 
11498  monomial = polynomialdata->monomials[j];
11499  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11500  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11501 
11502  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11503  {
11504  assert(factorpos >= 0);
11505  assert(factorpos < monomial->nfactors);
11506  /* assert that factors have been merged */
11507  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11508  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11509 
11510  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11511 
11512  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 ) /*lint !e835*/
11513  {
11514  /* if constant is negative and our exponent is not integer, then cannot do expansion */
11515  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
11516  removechild = FALSE;
11517  }
11518  else
11519  {
11520  monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
11521 
11522  /* move last factor to position factorpos */
11523  if( factorpos < monomial->nfactors-1 )
11524  {
11525  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
11526  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
11527  }
11528  --monomial->nfactors;
11529  monomial->sorted = FALSE;
11530  polynomialdata->sorted = FALSE;
11531 
11532  *havechange = TRUE;
11533  }
11534  }
11535  }
11536 
11537  /* forget about child i, if it is not used anymore */
11538  if( removechild )
11539  {
11540  /* remove node from list of parents of child i */
11541  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11542  node->children[i] = NULL;
11543  }
11544 
11545  /* simplify current polynomial again */
11546  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11547  }
11548 
11549  /* resolve children that are polynomials itself */
11550  for( i = 0; i < node->nchildren; ++i )
11551  {
11552  if( node->children[i] == NULL )
11553  continue;
11554 
11555  /* convert children to polynomial, if not constant or polynomial
11556  * if child was simplified in this round, it may have already been converted, and then nothing happens
11557  * but if child was already simplified, then it was not converted, and thus we try it here
11558  */
11559  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
11560 
11561  if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
11562  continue;
11563 
11564  SCIPdebugMessage("expand child %d in expression node ", i);
11565  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11566  SCIPdebugPrintf("\n\tchild = ");
11567  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11568  SCIPdebugPrintf("\n");
11569 
11570  removechild = TRUE; /* we intend to release children[i] */
11571 
11572  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11573 
11574  /* add children of child i to node */
11575  SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
11576 
11577  /* put polynomial of child i into every monomial where child i is used */
11578  j = 0;
11579  while( j < polynomialdata->nmonomials )
11580  {
11581  int factorpos;
11582  SCIP_Bool success;
11583 
11584  monomial = polynomialdata->monomials[j];
11585  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11586  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11587 
11588  if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11589  {
11590  ++j;
11591  continue;
11592  }
11593 
11594  assert(factorpos >= 0);
11595  assert(factorpos < monomial->nfactors);
11596  /* assert that factors have been merged */
11597  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11598  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11599 
11600  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11601 
11602  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
11603  (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
11604 
11605  if( !success )
11606  {
11607  removechild = FALSE;
11608  ++j;
11609  }
11610  else
11611  *havechange = TRUE;
11612 
11613  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
11614  * we thus repeat with index j, if a factor was successfully expanded
11615  */
11616  }
11617 
11618  /* forget about child i, if it is not used anymore */
11619  if( removechild )
11620  {
11621  /* remove node from list of parents of child i */
11622  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11623  node->children[i] = NULL;
11624  }
11625 
11626  /* simplify current polynomial again */
11627  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11628  }
11629 
11630  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
11631 
11632  /* check which children are still in use */
11633  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
11634  BMSclearMemoryArray(childinuse, node->nchildren); /*lint !e644*/
11635  for( i = 0; i < polynomialdata->nmonomials; ++i )
11636  {
11637  monomial = polynomialdata->monomials[i];
11638  assert(monomial != NULL);
11639 
11640  for( j = 0; j < monomial->nfactors; ++j )
11641  {
11642  assert(monomial->childidxs[j] >= 0);
11643  assert(monomial->childidxs[j] < node->nchildren);
11644  childinuse[monomial->childidxs[j]] = TRUE;
11645  }
11646  }
11647 
11648  /* free children that are not used in any monomial */
11649  for( i = 0; i < node->nchildren; ++i )
11650  if( node->children[i] != NULL && !childinuse[i] )
11651  {
11652  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11653  node->children[i] = NULL;
11654  }
11655 
11656  BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
11657 
11658  /* remove NULLs from children array */
11660 
11661  /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
11662  if( node->nchildren == 0 )
11663  {
11664  SCIP_Real val;
11665 
11666  /* if no children, then it should also have no monomials */
11667  assert(polynomialdata->nmonomials == 0);
11668 
11669  val = polynomialdata->constant;
11670  polynomialdataFree(blkmem, &polynomialdata);
11671 
11672  node->op = SCIP_EXPR_CONST;
11673  node->data.dbl = val;
11674  node->value = val;
11675  }
11676 
11677  /* if no factor in a monomial was replaced, the number of children should not have changed
11678  * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11679  */
11680  *havechange |= (node->nchildren < orignchildren); /*lint !e514*/
11681 
11682  node->simplified = TRUE;
11683 
11684  SCIPdebugMessage("-> %p = ", (void*)node);
11685  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11686  SCIPdebugPrintf("\n");
11687 
11688  return SCIP_OKAY;
11689 }
11690 
11691 /** creates an expression from a given node in an expression graph
11692  *
11693  * Assembles mapping of variables from graph to tree.
11694  */
11695 static
11697  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11698  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which expression should be created */
11699  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
11700  int* nexprvars, /**< current number of variables in expression */
11701  int* varidx /**< current mapping of variable indices from graph to expression */
11702  )
11703 {
11704  SCIP_EXPR** childexprs;
11705  int i;
11706 
11707  assert(exprgraph != NULL);
11708  assert(node != NULL);
11709  assert(expr != NULL);
11710  assert(nexprvars != NULL);
11711  assert(*nexprvars >= 0);
11712  assert(varidx != NULL);
11713 
11714  childexprs = NULL;
11715  if( node->nchildren > 0 )
11716  {
11717  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11718  for( i = 0; i < node->nchildren; ++i )
11719  {
11720  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) ); /*lint !e613*/
11721  }
11722  }
11723 
11724  switch( node->op )
11725  {
11726  case SCIP_EXPR_VARIDX:
11727  {
11728  /* check if the variable already has an index assigned in the expression tree
11729  * if not, create one and increase nexprvars
11730  */
11731  assert(node->data.intval >= 0);
11732  assert(node->data.intval < exprgraph->nvars);
11733  assert(varidx[node->data.intval] >= -1);
11734  assert(varidx[node->data.intval] < *nexprvars);
11735  if( varidx[node->data.intval] == -1 )
11736  {
11737  varidx[node->data.intval] = *nexprvars;
11738  ++*nexprvars;
11739  }
11740 
11741  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11742  break;
11743  }
11744 
11745  case SCIP_EXPR_CONST:
11746  {
11747  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11748  break;
11749  }
11750 
11751  case SCIP_EXPR_REALPOWER:
11752  case SCIP_EXPR_SIGNPOWER:
11753  {
11754  assert(node->nchildren == 1);
11755  assert(childexprs != NULL);
11756  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11757  break;
11758  }
11759 
11760  case SCIP_EXPR_INTPOWER:
11761  {
11762  assert(node->nchildren == 1);
11763  assert(childexprs != NULL);
11764  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11765  break;
11766  }
11767 
11768  case SCIP_EXPR_PLUS:
11769  case SCIP_EXPR_MINUS:
11770  case SCIP_EXPR_MUL:
11771  case SCIP_EXPR_DIV:
11772  case SCIP_EXPR_MIN:
11773  case SCIP_EXPR_MAX:
11774  {
11775  assert(node->nchildren == 2);
11776  assert(childexprs != NULL);
11777  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11778  break;
11779  }
11780 
11781  case SCIP_EXPR_SQUARE:
11782  case SCIP_EXPR_SQRT:
11783  case SCIP_EXPR_EXP:
11784  case SCIP_EXPR_LOG:
11785  case SCIP_EXPR_SIN:
11786  case SCIP_EXPR_COS:
11787  case SCIP_EXPR_TAN:
11788  /* case SCIP_EXPR_ERF: */
11789  /* case SCIP_EXPR_ERFI: */
11790  case SCIP_EXPR_ABS:
11791  case SCIP_EXPR_SIGN:
11792  {
11793  assert(node->nchildren == 1);
11794  assert(childexprs != NULL);
11795  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11796  break;
11797  }
11798 
11799  case SCIP_EXPR_SUM:
11800  case SCIP_EXPR_PRODUCT:
11801  {
11802  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11803  break;
11804  }
11805 
11806  case SCIP_EXPR_LINEAR:
11807  {
11808  assert(node->data.data != NULL);
11809 
11810  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11811  break;
11812  }
11813 
11814  case SCIP_EXPR_QUADRATIC:
11815  {
11816  SCIP_EXPRDATA_QUADRATIC* quaddata;
11817 
11818  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11819  assert(quaddata != NULL);
11820 
11821  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11822  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11823  break;
11824  }
11825 
11826  case SCIP_EXPR_POLYNOMIAL:
11827  {
11828  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11829 
11830  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11831  assert(polynomialdata != NULL);
11832 
11833  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11834  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11835 
11836  break;
11837  }
11838 
11839  case SCIP_EXPR_USER:
11840  {
11841  SCIP_EXPRDATA_USER* exprdata;
11842  SCIP_USEREXPRDATA* userdata;
11843 
11844  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11845  assert(exprdata != NULL);
11846 
11847  if( exprdata->copydata != NULL )
11848  {
11849  SCIP_CALL( exprdata->copydata(exprgraph->blkmem, node->nchildren, exprdata->userdata, &userdata) );
11850  }
11851  else
11852  userdata = exprdata->userdata;
11853 
11854  SCIP_CALL( SCIPexprCreateUser(exprgraph->blkmem, expr, node->nchildren, childexprs,
11855  userdata, exprdata->evalcapability, exprdata->eval, exprdata->inteval, exprdata->curv, exprdata->prop, exprdata->estimate, exprdata->copydata, exprdata->freedata, exprdata->print) );
11856 
11857  break;
11858  }
11859 
11860  case SCIP_EXPR_LAST:
11861  case SCIP_EXPR_PARAM:
11862  {
11863  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11864  return SCIP_ERROR;
11865  }
11866  }
11867 
11868  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11869 
11870  return SCIP_OKAY;
11871 }
11872 
11873 /** counts how often expression graph variables are used in a subtree of the expression graph
11874  *
11875  * @note The function does not clear the array first, but only increases already existing counts.
11876  */
11877 static
11879  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11880  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11881  )
11882 {
11883  int i;
11884 
11885  assert(node != NULL);
11886  assert(varsusage != NULL);
11887 
11888  if( node->op == SCIP_EXPR_VARIDX )
11889  {
11890  ++varsusage[node->data.intval];
11891  return;
11892  }
11893 
11894  for( i = 0; i < node->nchildren; ++i )
11895  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
11896 }
11897 
11898 /** checks whether a node can be put into a component when checking block separability of an expression
11899  *
11900  * If a variable used by node is already in another component, components are merged and component number is updated.
11901  */
11902 static
11904  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
11905  int* compnr, /**< component number to assign, may be reduced if variables overlap */
11906  int nchildcomps, /**< number of entries for which childcomps have been set already */
11907  int* childcomps, /**< component numbers of children */
11908  int nvars, /**< number of variables */
11909  int* varcomps /**< component numbers of variables */
11910  )
11911 {
11912  int varidx;
11913  int i;
11914 
11915  assert(node != NULL);
11916  assert(compnr != NULL);
11917  assert(*compnr >= 0);
11918  assert(childcomps != NULL);
11919  assert(varcomps != NULL);
11920 
11921  if( node->op != SCIP_EXPR_VARIDX )
11922  {
11923  for( i = 0; i < node->nchildren; ++i )
11924  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
11925  return;
11926  }
11927 
11928  varidx = node->data.intval;
11929  assert(varidx >= 0);
11930  assert(varidx < nvars);
11931 
11932  if( varcomps[varidx] == -1 )
11933  {
11934  /* first time we get to this variable, so set it's component to compnr and we are done */
11935  varcomps[varidx] = *compnr;
11936  return;
11937  }
11938 
11939  if( varcomps[varidx] == *compnr )
11940  {
11941  /* variable is already in current component, that's also good and we are done */
11942  return;
11943  }
11944 
11945  /* variable is already in another component, so have to merge component compnr into that component
11946  * do this by updating varcomps and childcomps */
11947  for( i = 0; i < nvars; ++i )
11948  if( varcomps[i] == *compnr )
11949  varcomps[i] = varcomps[varidx];
11950  for( i = 0; i < nchildcomps; ++i )
11951  if( childcomps[i] == *compnr )
11952  childcomps[i] = varcomps[varidx];
11953  *compnr = varcomps[varidx];
11954 }
11955 
11956 /**@} */
11957 
11958 /**@name Expression graph private methods */
11959 /**@{ */
11960 
11961 /** assert that expression tree has at least a given depth */
11962 static
11964  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
11965  int mindepth /**< minimal depth that should be ensured */
11966  )
11967 {
11968  int olddepth;
11969 
11970  assert(exprgraph != NULL);
11971  assert(exprgraph->blkmem != NULL);
11972 
11973  if( mindepth <= exprgraph->depth )
11974  return SCIP_OKAY;
11975 
11976  olddepth = exprgraph->depth;
11977  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
11978  assert(exprgraph->depth >= mindepth);
11979 
11980  /* initialize new array entries to 0 and NULL, resp. */
11981  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11982  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11983  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11984 
11985  return SCIP_OKAY;
11986 }
11987 
11988 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
11989 static
11991  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11992  int varidx /**< variable index */
11993  )
11994 {
11995  SCIP_EXPRGRAPHNODE* varnode;
11996  void* var;
11997 
11998  assert(exprgraph != NULL);
11999  assert(varidx >= 0);
12000  assert(varidx < exprgraph->nvars);
12001 
12002  varnode = exprgraph->varnodes[varidx];
12003  assert(varnode->data.intval == varidx);
12004 
12005  var = exprgraph->vars[varidx];
12006 
12007  /* call varremove callback method, if set */
12008  if( exprgraph->exprgraphvarremove != NULL )
12009  {
12010  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
12011  }
12012 
12013  /* remove variable from hashmap */
12014  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
12015 
12016  /* move last variable to position varidx and give it the new index */
12017  if( varidx < exprgraph->nvars-1 )
12018  {
12019  /* call callback method, if set */
12020  if( exprgraph->exprgraphvarchgidx != NULL )
12021  {
12022  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
12023  }
12024 
12025  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
12026  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
12027  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
12028  exprgraph->varnodes[varidx]->data.intval = varidx;
12029  SCIP_CALL( SCIPhashmapSetImage(exprgraph->varidxs, exprgraph->vars[varidx], (void*)(size_t)(varidx)) );
12030  }
12031  --exprgraph->nvars;
12032 
12033  return SCIP_OKAY;
12034 }
12035 
12036 /** moves a node in an expression graph to a different depth
12037  *
12038  * New depth must be larger than children depth.
12039  * Moves parent nodes to higher depth, if needed.
12040  * Variable nodes cannot be moved.
12041  */
12042 static
12044  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12045  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
12046  int newdepth /**< new depth to which to move node */
12047  )
12048 {
12049  int olddepth;
12050  int oldpos;
12051  int i;
12052 
12053  assert(exprgraph != NULL);
12054  assert(node != NULL);
12055  assert(node->depth >= 0); /* node should be in graph */
12056  assert(newdepth >= 0);
12057 
12058  /* if already on aimed depth, then don't need to move */
12059  if( node->depth == newdepth )
12060  return SCIP_OKAY;
12061 
12062  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
12063 
12064 #ifndef NDEBUG
12065  /* assert that children are at lower depth than new depth */
12066  for( i = 0; i < node->nchildren; ++i )
12067  assert(node->children[i]->depth < newdepth);
12068 #endif
12069 
12070  /* move parents to higher depth, if needed */
12071  for( i = 0; i < node->nparents; ++i )
12072  {
12073  if( node->parents[i]->depth <= newdepth )
12074  {
12075  /* move parent to depth+1 */
12076  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
12077  assert(node->parents[i]->depth > newdepth);
12078  }
12079  }
12080 
12081  /* ensure that graph is deep enough */
12082  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
12083  assert(exprgraph->depth > newdepth);
12084 
12085  olddepth = node->depth;
12086  oldpos = node->pos;
12087 
12088  /* add node to new depth */
12089  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
12090  node->depth = newdepth;
12091  node->pos = exprgraph->nnodes[newdepth];
12092  exprgraph->nodes[newdepth][node->pos] = node;
12093  ++exprgraph->nnodes[newdepth];
12094 
12095  /* move last node at previous depth to previous position, if it wasn't last */
12096  if( oldpos < exprgraph->nnodes[olddepth]-1 )
12097  {
12098  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
12099  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
12100  }
12101  --exprgraph->nnodes[olddepth];
12102 
12103  if( node->depth == 0 )
12104  {
12105  /* if at depth 0, then it need to be a node for either a constant or a variable */
12106  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
12107  if( node->op == SCIP_EXPR_CONST )
12108  {
12109  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
12110  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
12111  exprgraph->constnodes[exprgraph->nconsts] = node;
12112  ++exprgraph->nconsts;
12113  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
12114  }
12115  else
12116  {
12117  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
12118  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
12119  return SCIP_ERROR;
12120  }
12121 
12122  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
12123  node->curv = SCIP_EXPRCURV_LINEAR;
12124  }
12125 
12126  return SCIP_OKAY;
12127 }
12128 
12129 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
12130 static
12132  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12133  int nchildren, /**< number of children */
12134  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
12135  SCIP_EXPROP op, /**< operator */
12136  SCIP_EXPROPDATA opdata, /**< operator data */
12137  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
12138  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
12139  )
12140 {
12141  SCIP_EXPRGRAPHNODE** parentcands;
12142  int nparentcands;
12143  int parentcandssize;
12144  int i;
12145  int p;
12146 
12147  assert(exprgraph != NULL);
12148  assert(nchildren > 0);
12149  assert(children != NULL);
12150  assert(parent != NULL);
12151 
12152  *parent = NULL;
12153 
12154  /* create initial set of parent candidates as
12155  * all parents of first child that have the same operator type and the same number of children
12156  * additionally, some easy conditions for complex expression types:
12157  * if expression type is int/real/signpower, then compare also exponent,
12158  * if expression type is linear, then compare also constant part,
12159  * if expression type is quadratic, then compare also number of quadratic elements,
12160  * if expression type is polynomial, then compare also number of monmials and constant part
12161  */
12162  parentcandssize = children[0]->nparents;
12163  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
12164  nparentcands = 0;
12165  for( p = 0; p < children[0]->nparents; ++p )
12166  if( children[0]->parents[p]->op == op &&
12167  children[0]->parents[p]->nchildren == nchildren &&
12168  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
12169  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12170  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12171  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
12172  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
12173  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
12174  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
12175  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
12176  )
12177  {
12178  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
12179  }
12180 
12181  /* for all remaining children, remove parent candidates, that are not in their list of parents */
12182  for( i = 1; i < nchildren && nparentcands > 0; ++i )
12183  {
12184  p = 0;
12185  while( p < nparentcands )
12186  {
12187  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
12188  * otherwise keep candidate and check next one
12189  */
12190  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
12191  {
12192  parentcands[p] = parentcands[nparentcands-1];
12193  --nparentcands;
12194  }
12195  else
12196  ++p;
12197  }
12198  }
12199 
12200  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
12201 
12202  if( nparentcands == 0 )
12203  {
12204  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
12205  return SCIP_OKAY;
12206  }
12207 
12208  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
12209  * check if there is also one which corresponds to same expression and store that one in *parent
12210  */
12211  switch( op )
12212  {
12213  /* commutative operands with no data */
12214  case SCIP_EXPR_PLUS :
12215  case SCIP_EXPR_MUL :
12216  case SCIP_EXPR_MIN :
12217  case SCIP_EXPR_MAX :
12218  case SCIP_EXPR_SUM :
12219  case SCIP_EXPR_PRODUCT:
12220  case SCIP_EXPR_SQUARE :
12221  case SCIP_EXPR_SQRT :
12222  case SCIP_EXPR_EXP :
12223  case SCIP_EXPR_LOG :
12224  case SCIP_EXPR_SIN :
12225  case SCIP_EXPR_COS :
12226  case SCIP_EXPR_TAN :
12227  /* case SCIP_EXPR_ERF : */
12228  /* case SCIP_EXPR_ERFI : */
12229  case SCIP_EXPR_ABS :
12230  case SCIP_EXPR_SIGN :
12231  {
12232  /* sort childnodes, if needed for later */
12233  if( nchildren > 2 )
12234  SCIPsortPtr((void**)children, ptrcomp, nchildren);
12235  for( p = 0; p < nparentcands; ++p )
12236  {
12237  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12238  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12239 
12240  if( nchildren == 1 )
12241  {
12242  assert(parentcands[p]->children[0] == children[0]);
12243  /* same operand, same child, so same expression */
12244  *parent = parentcands[p];
12245  break;
12246  }
12247  else if( nchildren == 2 )
12248  {
12249  /* We know that every node in children is also a child of parentcands[p].
12250  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
12251  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
12252  */
12253  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
12254  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
12255  {
12256  *parent = parentcands[p];
12257  break;
12258  }
12259  }
12260  else
12261  {
12262  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
12263 
12264  /* sort children of parent candidate */
12265  SCIPsortPtr((void**)parentcands[p]->children, ptrcomp, nchildren);
12266 
12267  /* check if childnodes and parentcands[p]->children are the same */
12268  for( i = 0; i < nchildren; ++i )
12269  if( children[i] != parentcands[p]->children[i] )
12270  break;
12271  if( i == nchildren )
12272  {
12273  /* yeah, found an exact match */
12274  *parent = parentcands[p];
12275  break;
12276  }
12277  }
12278  }
12279 
12280  break;
12281  }
12282 
12283  /* non-commutative operands with two children */
12284  case SCIP_EXPR_MINUS :
12285  case SCIP_EXPR_DIV :
12286  {
12287  for( p = 0; p < nparentcands; ++p )
12288  {
12289  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12290  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
12291  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
12292  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
12293  {
12294  /* yeah, found one */
12295  *parent = parentcands[p];
12296  break;
12297  }
12298  }
12299 
12300  break;
12301  }
12302 
12303  /* operands with one child and data */
12304  case SCIP_EXPR_INTPOWER:
12305  {
12306  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12307  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12308  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12309  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
12310 
12311  /* yeah, have one with same exponent */
12312  *parent = parentcands[0];
12313 
12314  break;
12315  }
12316 
12317  case SCIP_EXPR_REALPOWER:
12318  case SCIP_EXPR_SIGNPOWER:
12319  {
12320  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12321  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12322  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12323  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
12324 
12325  /* yeah, have one with same exponent */
12326  *parent = parentcands[0];
12327 
12328  break;
12329  }
12330 
12331  /* commutative operands with n children and data */
12332  case SCIP_EXPR_LINEAR:
12333  {
12334  SCIP_Real* exprcoef;
12335  SCIP_Real* candcoef;
12336 
12337  exprcoef = (SCIP_Real*)opdata.data;
12338  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
12339  if( exprchildren != NULL )
12340  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, ptrcomp, nchildren);
12341  else
12342  SCIPsortPtrReal((void**)children, exprcoef, ptrcomp, nchildren);
12343  for( p = 0; p < nparentcands; ++p )
12344  {
12345  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12346  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12347 
12348  candcoef = (SCIP_Real*)parentcands[p]->data.data;
12349  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12350 
12351  /* sort children of parent candidate */
12352  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, ptrcomp, nchildren);
12353 
12354  /* check if children and coefficients in parent candidate and expression are the same */
12355  for( i = 0; i < nchildren; ++i )
12356  {
12357  if( children[i] != parentcands[p]->children[i] )
12358  break;
12359  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
12360  break;
12361  }
12362  if( i < nchildren )
12363  continue;
12364 
12365  /* yeah, found an exact match */
12366  *parent = parentcands[p];
12367  break;
12368  }
12369 
12370  break;
12371  }
12372 
12373  case SCIP_EXPR_QUADRATIC:
12374  {
12375  SCIP_EXPRDATA_QUADRATIC* exprdata;
12376  SCIP_Real* exprlincoef;
12377  SCIP_Real* candlincoef;
12378  SCIP_EXPRDATA_QUADRATIC* canddata;
12379  int* perm;
12380  int* invperm;
12381 
12382  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
12383  exprlincoef = exprdata->lincoefs;
12384 
12385  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
12386 
12387  /* sort expr->children and childnodes and store inverse permutation in invperm */
12388  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12389  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12390  for( i = 0; i < nchildren; ++i )
12391  invperm[i] = i; /*lint !e644*/
12392 
12393  if( exprlincoef != NULL )
12394  if( exprchildren != NULL )
12395  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, ptrcomp, nchildren);
12396  else
12397  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, ptrcomp, nchildren);
12398  else
12399  if( exprchildren != NULL )
12400  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, ptrcomp, nchildren);
12401  else
12402  SCIPsortPtrInt((void**)children, invperm, ptrcomp, nchildren);
12403 
12404  /* compute permutation from its inverse */
12405  for( i = 0; i < nchildren; ++i )
12406  perm[invperm[i]] = i; /*lint !e644*/
12407 
12408  /* apply permuation to exprdata->quadelems and sort again */
12409  for( i = 0; i < exprdata->nquadelems; ++i )
12410  {
12411  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
12412  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
12413  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
12414  {
12415  int tmp;
12416  tmp = exprdata->quadelems[i].idx1;
12417  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
12418  exprdata->quadelems[i].idx2 = tmp;
12419  }
12420  }
12421  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
12422  exprdata->sorted = TRUE;
12423 
12424  for( p = 0; p < nparentcands; ++p )
12425  {
12426  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12427  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12428 
12429  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
12430  candlincoef = canddata->lincoefs;
12431  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
12432  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12433 
12434  /* sort parentcands[p]->children and store inverse permutation in invperm */
12435  for( i = 0; i < nchildren; ++i )
12436  invperm[i] = i;
12437 
12438  if( candlincoef != NULL )
12439  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, ptrcomp, parentcands[p]->nchildren);
12440  else
12441  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, ptrcomp, nchildren);
12442 
12443  /* compute permutation from its inverse */
12444  for( i = 0; i < nchildren; ++i )
12445  perm[invperm[i]] = i;
12446 
12447  /* apply permutation to canddata->quadelems */
12448  for( i = 0; i < canddata->nquadelems; ++i )
12449  {
12450  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
12451  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
12452  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
12453  {
12454  int tmp;
12455  tmp = canddata->quadelems[i].idx1;
12456  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
12457  canddata->quadelems[i].idx2 = tmp;
12458  }
12459  }
12460  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
12461  canddata->sorted = TRUE;
12462 
12463  /* check if children and linear coefficients in parent candidate and expression are the same */
12464  for( i = 0; i < nchildren; ++i )
12465  {
12466  if( children[i] != parentcands[p]->children[i] )
12467  break;
12468  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
12469  break;
12470  }
12471  if( i < nchildren )
12472  continue;
12473 
12474  assert(exprdata->nquadelems == canddata->nquadelems);
12475  for( i = 0; i < exprdata->nquadelems; ++i )
12476  {
12477  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
12478  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
12479  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
12480  break;
12481  }
12482  if( i == exprdata->nquadelems )
12483  {
12484  /* yeah, parentcands[p] is same quadratic expression as expr */
12485  *parent = parentcands[p];
12486  break;
12487  }
12488  }
12489 
12490  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12491  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12492 
12493  break;
12494  }
12495 
12496  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
12497  case SCIP_EXPR_POLYNOMIAL:
12498  {
12499  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
12500  SCIP_EXPRDATA_POLYNOMIAL* canddata;
12501  int* perm;
12502  int* invperm;
12503 
12504  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
12505 
12506  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
12507 
12508  /* sort exprchildren and childnodes and store inverse permutation in invperm */
12509  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12510  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12511  for( i = 0; i < nchildren; ++i )
12512  invperm[i] = i; /*lint !e644*/
12513 
12514  if( exprchildren != NULL )
12515  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, ptrcomp, nchildren);
12516  else
12517  SCIPsortPtrInt((void**)children, invperm, ptrcomp, nchildren);
12518 
12519  /* compute permutation from its inverse */
12520  for( i = 0; i < nchildren; ++i )
12521  perm[invperm[i]] = i; /*lint !e644*/
12522 
12523  /* apply permutation to exprdata and sort again */
12524  polynomialdataApplyChildmap(exprdata, perm);
12525  polynomialdataSortMonomials(exprdata);
12526 
12527  for( p = 0; p < nparentcands; ++p )
12528  {
12529  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12530  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12531 
12532  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
12533  assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
12534  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12535 
12536  /* sort parentcands[p]->children and store inverse permutation in invperm */
12537  for( i = 0; i < nchildren; ++i )
12538  invperm[i] = i;
12539 
12540  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, ptrcomp, nchildren);
12541 
12542  /* compute permutation from its inverse */
12543  for( i = 0; i < nchildren; ++i )
12544  perm[invperm[i]] = i;
12545 
12546  /* apply permutation to canddata and sort again */
12547  polynomialdataApplyChildmap(canddata, perm);
12548  polynomialdataSortMonomials(canddata);
12549 
12550  /* check if children are equal */
12551  for( i = 0; i < nchildren; ++i )
12552  if( children[i] != parentcands[p]->children[i] )
12553  break;
12554  if( i < nchildren )
12555  continue;
12556 
12557  /* check if monomials are equal */
12558  for( i = 0; i < exprdata->nmonomials; ++i )
12559  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
12560  break;
12561  if( i == exprdata->nmonomials )
12562  {
12563  /* yeah, parentcands[p] is same polynomial expression as expr */
12564  *parent = parentcands[p];
12565  break;
12566  }
12567  }
12568 
12569  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12570  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12571 
12572  break;
12573  }
12574 
12575  case SCIP_EXPR_USER:
12576  {
12577  /* @todo need comparison function on user data to decide whether a parent candidate fits */
12578  break;
12579  }
12580 
12581  case SCIP_EXPR_VARIDX:
12582  case SCIP_EXPR_PARAM:
12583  case SCIP_EXPR_CONST:
12584  case SCIP_EXPR_LAST:
12585  SCIPerrorMessage("expression operand %d unexpected here\n", op);
12586  return SCIP_ERROR;
12587  }
12588 
12589  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
12590 
12591  return SCIP_OKAY;
12592 }
12593 
12594 /** adds an expression into an expression graph
12595  *
12596  * Enables corresponding nodes.
12597  */
12598 static
12600  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12601  SCIP_EXPR* expr, /**< expression to add */
12602  void** vars, /**< variables corresponding to VARIDX expressions */
12603  SCIP_Real* params, /**< parameter values */
12604  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
12605  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12606  )
12607 {
12608  SCIP_EXPRGRAPHNODE** childnodes;
12609  SCIP_Bool childisnew;
12610  SCIP_Bool nochildisnew;
12611  SCIP_EXPROPDATA opdata;
12612  int i;
12613 
12614  assert(exprgraph != NULL);
12615  assert(expr != NULL);
12616  assert(exprnode != NULL);
12617  assert(exprnodeisnew != NULL);
12618 
12619  if( expr->op == SCIP_EXPR_VARIDX )
12620  {
12621  /* find node corresponding to variable and add if not existing yet */
12622  assert(expr->nchildren == 0);
12623 
12624  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12625  assert(*exprnode != NULL);
12626  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12627  assert((*exprnode)->data.intval >= 0);
12628  assert((*exprnode)->data.intval < exprgraph->nvars);
12629  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12630 
12631  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12632 
12633  return SCIP_OKAY;
12634  }
12635 
12636  if( expr->op == SCIP_EXPR_CONST )
12637  {
12638  /* find node corresponding to constant and add if not existing yet */
12639  assert(expr->nchildren == 0);
12640 
12641  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12642  assert(*exprnode != NULL);
12643  assert((*exprnode)->op == SCIP_EXPR_CONST);
12644  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
12645 
12646  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12647 
12648  return SCIP_OKAY;
12649  }
12650 
12651  if( expr->op == SCIP_EXPR_PARAM )
12652  {
12653  /* find node corresponding to constant corresponding to parameter and add if not existing yet */
12654  assert(expr->nchildren == 0);
12655  assert(params != NULL);
12656 
12657  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, params[expr->data.intval], exprnode) );
12658  assert(*exprnode != NULL);
12659  assert((*exprnode)->op == SCIP_EXPR_CONST);
12660  assert((*exprnode)->data.dbl == params[expr->data.intval]); /*lint !e777*/
12661 
12662  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12663 
12664  return SCIP_OKAY;
12665  }
12666 
12667  /* expression should be variable or constant or have children */
12668  assert(expr->nchildren > 0);
12669 
12670  /* add children expressions into expression graph
12671  * check if we can find a common parent
12672  */
12673  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12674  nochildisnew = TRUE;
12675  for( i = 0; i < expr->nchildren; ++i )
12676  {
12677  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, params, &childnodes[i], &childisnew) ); /*lint !e644*/
12678  assert(childnodes[i] != NULL);
12679  nochildisnew &= !childisnew; /*lint !e514*/
12680  }
12681 
12682  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12683  if( nochildisnew )
12684  {
12685  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12686 
12687  if( *exprnode != NULL )
12688  {
12689  /* node already existing, make sure it is enabled */
12690  (*exprnode)->enabled = TRUE;
12691  *exprnodeisnew = FALSE;
12692 
12693  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12694  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12695  * SCIPdebugPrintf("\n");
12696  */
12697 
12698  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12699  return SCIP_OKAY;
12700  }
12701  }
12702 
12703  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12704 
12705  /* copy expression data */
12706  if( exprOpTable[expr->op].copydata != NULL )
12707  {
12708  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12709  }
12710  else
12711  {
12712  opdata = expr->data;
12713  }
12714 
12715  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12716  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12717  *exprnodeisnew = TRUE;
12718 
12719  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12720 
12721  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12722  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12723  * SCIPdebugPrintf("\n");
12724  */
12725 
12726  return SCIP_OKAY;
12727 }
12728 
12729 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12730 static
12732  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12733  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12734  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12735  )
12736 {
12737  SCIP_EXPRGRAPHNODE* node;
12738  int i;
12739  int p;
12740 
12741  assert(exprgraph != NULL);
12742  assert(clearreverseprop != NULL);
12743  assert(boundchanged != NULL);
12744 
12745  *boundchanged = FALSE;
12746  for( i = 0; i < exprgraph->nvars; ++i )
12747  {
12748  node = exprgraph->varnodes[i];
12749 
12750  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12751  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12752  {
12754  continue;
12755  }
12756 
12757  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12758  {
12759  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12760  SCIP_Real tmp;
12761 
12762  tmp = exprgraph->varbounds[i].inf;
12763  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12764  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12765  }
12766 
12767  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12768  +exprgraph->varbounds[i].sup > node->bounds.sup )
12769  {
12770  for( p = 0; p < node->nparents; ++p )
12772 
12773  node->bounds = exprgraph->varbounds[i];
12774  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12775 
12776  *boundchanged = TRUE;
12777 
12778  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12779  *clearreverseprop = TRUE;
12780  }
12781  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12782  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12783  {
12784  for( p = 0; p < node->nparents; ++p )
12786 
12787  node->bounds = exprgraph->varbounds[i];
12788  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12789 
12790  *boundchanged = TRUE;
12791  }
12792  else
12793  {
12794  node->bounds = exprgraph->varbounds[i];
12795  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12796  }
12797 
12799  }
12800 }
12801 
12802 /**@} */
12803 
12804 /**@name Expression graph node methods */
12805 /**@{ */
12806 
12807 /* In debug mode, the following methods are implemented as function calls to ensure
12808  * type validity.
12809  * In optimized mode, the methods are implemented as defines to improve performance.
12810  * However, we want to have them in the library anyways, so we have to undef the defines.
12811  */
12812 
12813 #undef SCIPexprgraphCaptureNode
12814 #undef SCIPexprgraphIsNodeEnabled
12815 #undef SCIPexprgraphGetNodeNChildren
12816 #undef SCIPexprgraphGetNodeChildren
12817 #undef SCIPexprgraphGetNodeNParents
12818 #undef SCIPexprgraphGetNodeParents
12819 #undef SCIPexprgraphGetNodeDepth
12820 #undef SCIPexprgraphGetNodePosition
12821 #undef SCIPexprgraphGetNodeOperator
12822 #undef SCIPexprgraphGetNodeOperatorIndex
12823 #undef SCIPexprgraphGetNodeOperatorReal
12824 #undef SCIPexprgraphGetNodeVar
12825 #undef SCIPexprgraphGetNodeRealPowerExponent
12826 #undef SCIPexprgraphGetNodeIntPowerExponent
12827 #undef SCIPexprgraphGetNodeSignPowerExponent
12828 #undef SCIPexprgraphGetNodeLinearCoefs
12829 #undef SCIPexprgraphGetNodeLinearConstant
12830 #undef SCIPexprgraphGetNodeQuadraticConstant
12831 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12832 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12833 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12834 #undef SCIPexprgraphGetNodePolynomialMonomials
12835 #undef SCIPexprgraphGetNodePolynomialNMonomials
12836 #undef SCIPexprgraphGetNodePolynomialConstant
12837 #undef SCIPexprgraphGetNodeUserData
12838 #undef SCIPexprgraphHasNodeUserEstimator
12839 #undef SCIPexprgraphGetNodeBounds
12840 #undef SCIPexprgraphGetNodeVal
12841 #undef SCIPexprgraphGetNodeCurvature
12842 
12843 /** captures node, i.e., increases number of uses */
12845  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12846  )
12847 {
12848  assert(node->nuses >= 0);
12849 
12850  SCIPdebugMessage("capture node %p\n", (void*)node);
12851 
12852  ++node->nuses;
12853 }
12854 
12855 /** returns whether a node is currently enabled */
12857  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12858  )
12859 {
12860  assert(node != NULL);
12861 
12862  return node->enabled;
12863 }
12864 
12865 /** gets number of children of a node in an expression graph */
12867  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12868  )
12869 {
12870  assert(node != NULL);
12871 
12872  return node->nchildren;
12873 }
12874 
12875 /** gets children of a node in an expression graph */
12877  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12878  )
12879 {
12880  assert(node != NULL);
12881 
12882  return node->children;
12883 }
12884 
12885 /** gets number of parents of a node in an expression graph */
12887  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12888  )
12889 {
12890  assert(node != NULL);
12891 
12892  return node->nparents;
12893 }
12894 
12895 /** gets parents of a node in an expression graph */
12897  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12898  )
12899 {
12900  assert(node != NULL);
12901 
12902  return node->parents;
12903 }
12904 
12905 /** gets depth of node in expression graph */
12907  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12908  )
12909 {
12910  assert(node != NULL);
12911 
12912  return node->depth;
12913 }
12914 
12915 /** gets position of node in expression graph at its depth level */
12917  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12918  )
12919 {
12920  assert(node != NULL);
12921 
12922  return node->pos;
12923 }
12924 
12925 /** gets operator of a node in an expression graph */
12927  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12928  )
12929 {
12930  assert(node != NULL);
12931 
12932  return node->op;
12933 }
12934 
12935 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
12937  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12938  )
12939 {
12940  assert(node != NULL);
12941  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
12942 
12943  return node->data.intval;
12944 }
12945 
12946 /** gives real belonging to a SCIP_EXPR_CONST operand */
12948  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12949  )
12950 {
12951  assert(node != NULL);
12952  assert(node->op == SCIP_EXPR_CONST);
12953 
12954  return node->data.dbl;
12955 }
12956 
12957 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
12959  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12960  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12961  )
12962 {
12963  assert(exprgraph != NULL);
12964  assert(node != NULL);
12965  assert(node->op == SCIP_EXPR_VARIDX);
12966  assert(node->data.intval >= 0);
12967  assert(node->data.intval < exprgraph->nvars);
12968 
12969  return exprgraph->vars[node->data.intval];
12970 }
12971 
12972 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
12974  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12975  )
12976 {
12977  assert(node != NULL);
12978  assert(node->op == SCIP_EXPR_REALPOWER);
12979 
12980  return node->data.dbl;
12981 }
12982 
12983 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
12985  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12986  )
12987 {
12988  assert(node != NULL);
12989  assert(node->op == SCIP_EXPR_INTPOWER);
12990 
12991  return node->data.intval;
12992 }
12993 
12994 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
12996  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12997  )
12998 {
12999  assert(node != NULL);
13000  assert(node->op == SCIP_EXPR_SIGNPOWER);
13001 
13002  return node->data.dbl;
13003 }
13004 
13005 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
13007  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13008  )
13009 {
13010  assert(node != NULL);
13011  assert(node->op == SCIP_EXPR_LINEAR);
13012 
13013  return (SCIP_Real*)node->data.data;
13014 }
13015 
13016 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
13018  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13019  )
13020 {
13021  assert(node != NULL);
13022  assert(node->op == SCIP_EXPR_LINEAR);
13023  assert(node->data.data != NULL);
13024 
13025  return ((SCIP_Real*)node->data.data)[node->nchildren];
13026 }
13027 
13028 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
13030  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13031  )
13032 {
13033  assert(node != NULL);
13034  assert(node->op == SCIP_EXPR_QUADRATIC);
13035  assert(node->data.data != NULL);
13036 
13037  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
13038 }
13039 
13040 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
13042  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13043  )
13044 {
13045  assert(node != NULL);
13046  assert(node->op == SCIP_EXPR_QUADRATIC);
13047  assert(node->data.data != NULL);
13048 
13049  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
13050 }
13051 
13052 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13054  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13055  )
13056 {
13057  assert(node != NULL);
13058  assert(node->op == SCIP_EXPR_QUADRATIC);
13059  assert(node->data.data != NULL);
13060 
13061  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
13062 }
13063 
13064 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13066  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13067  )
13068 {
13069  assert(node != NULL);
13070  assert(node->op == SCIP_EXPR_QUADRATIC);
13071  assert(node->data.data != NULL);
13072 
13073  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
13074 }
13075 
13076 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13078  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13079  )
13080 {
13081  assert(node != NULL);
13082  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13083  assert(node->data.data != NULL);
13084 
13085  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
13086 }
13087 
13088 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13090  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13091  )
13092 {
13093  assert(node != NULL);
13094  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13095  assert(node->data.data != NULL);
13096 
13097  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
13098 }
13099 
13100 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
13102  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13103  )
13104 {
13105  assert(node != NULL);
13106  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13107  assert(node->data.data != NULL);
13108 
13109  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
13110 }
13111 
13112 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
13113  *
13114  * Assumes that curvature of children and bounds of children and node itself are valid.
13115  */
13117  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13118  int monomialidx, /**< index of monomial */
13119  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
13120  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
13121  )
13122 {
13123  SCIP_EXPRDATA_MONOMIAL* monomial;
13124  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13125  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13126  SCIP_INTERVAL* childbounds;
13127  SCIP_EXPRCURV* childcurv;
13128  SCIP_EXPRGRAPHNODE* child;
13129  int i;
13130 
13131  assert(node != NULL);
13132  assert(node->depth >= 0); /* node should be in graph */
13133  assert(node->pos >= 0); /* node should be in graph */
13134  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13135  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
13136  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13137  assert(node->data.data != NULL);
13138  assert(monomialidx >= 0);
13139  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
13140  assert(curv != NULL);
13141 
13142  if( SCIPintervalIsEmpty(infinity, node->bounds) )
13143  {
13144  *curv = SCIP_EXPRCURV_LINEAR;
13145  return SCIP_OKAY;
13146  }
13147 
13148  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
13149  assert(monomial != NULL);
13150 
13151  /* if many children, get large enough memory to store children bounds */
13152  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13153  {
13154  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13155  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, monomial->nfactors) );
13156  }
13157  else
13158  {
13159  childbounds = childboundsstatic;
13160  childcurv = childcurvstatic;
13161  }
13162 
13163  /* assemble bounds and curvature of children */
13164  for( i = 0; i < monomial->nfactors; ++i )
13165  {
13166  child = node->children[monomial->childidxs[i]];
13167  assert(child != NULL);
13168 
13169  /* child should have valid and non-empty bounds */
13170  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13171  assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13172  /* nodes at depth 0 are always linear */
13173  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13174 
13175  childbounds[i] = child->bounds; /*lint !e644*/
13176  childcurv[i] = child->curv; /*lint !e644*/
13177  }
13178 
13179  /* check curvature */
13180  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13181  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13182 
13183  /* free memory, if allocated before */
13184  if( childbounds != childboundsstatic )
13185  {
13186  BMSfreeMemoryArray(&childbounds);
13187  BMSfreeMemoryArray(&childcurv);
13188  }
13189 
13190  return SCIP_OKAY;
13191 }
13192 
13193 /** gives the user data belonging to a SCIP_EXPR_USER expression */
13195  SCIP_EXPRGRAPHNODE* node
13196  )
13197 {
13198  assert(node != NULL);
13199  assert(node->op == SCIP_EXPR_USER);
13200  assert(node->data.data != NULL);
13201 
13202  return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13203 }
13204 
13205 /** indicates whether a user expression has the estimator callback defined */
13207  SCIP_EXPRGRAPHNODE* node
13208  )
13209 {
13210  assert(node != NULL);
13211  assert(node->op == SCIP_EXPR_USER);
13212  assert(node->data.data != NULL);
13213 
13214  return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13215 }
13216 
13217 /** gets bounds of a node in an expression graph */
13219  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13220  )
13221 {
13222  assert(node != NULL);
13223 
13224  return node->bounds;
13225 }
13226 
13227 /** gets value of expression associated to node from last evaluation call */
13229  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13230  )
13231 {
13232  assert(node != NULL);
13233 
13234  return node->value;
13235 }
13236 
13237 /** gets curvature of expression associated to node from last curvature check call */
13239  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13240  )
13241 {
13242  assert(node != NULL);
13243 
13244  return node->curv;
13245 }
13246 
13247 /** creates an expression graph node */
13249  BMS_BLKMEM* blkmem, /**< block memory */
13250  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13251  SCIP_EXPROP op, /**< operator type of expression */
13252  ...
13253  )
13254 {
13255  va_list ap;
13256  SCIP_EXPROPDATA opdata;
13257 
13258  assert(blkmem != NULL);
13259  assert(node != NULL);
13260 
13261  *node = NULL;
13262 
13263  switch( op )
13264  {
13265  case SCIP_EXPR_VARIDX :
13266  case SCIP_EXPR_PARAM :
13267  case SCIP_EXPR_CONST :
13268  case SCIP_EXPR_LINEAR :
13269  case SCIP_EXPR_QUADRATIC :
13270  case SCIP_EXPR_POLYNOMIAL:
13271  case SCIP_EXPR_USER :
13272  {
13273  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
13274  SCIPABORT();
13275  return SCIP_ERROR; /*lint !e527*/
13276  }
13277 
13278  /* operands without data */
13279  case SCIP_EXPR_PLUS :
13280  case SCIP_EXPR_MINUS :
13281  case SCIP_EXPR_MUL :
13282  case SCIP_EXPR_DIV :
13283  case SCIP_EXPR_MIN :
13284  case SCIP_EXPR_MAX :
13285  case SCIP_EXPR_SQUARE :
13286  case SCIP_EXPR_SQRT :
13287  case SCIP_EXPR_EXP :
13288  case SCIP_EXPR_LOG :
13289  case SCIP_EXPR_SIN :
13290  case SCIP_EXPR_COS :
13291  case SCIP_EXPR_TAN :
13292  /* case SCIP_EXPR_ERF : */
13293  /* case SCIP_EXPR_ERFI: */
13294  case SCIP_EXPR_ABS :
13295  case SCIP_EXPR_SIGN :
13296  case SCIP_EXPR_SUM :
13297  case SCIP_EXPR_PRODUCT:
13298  opdata.data = NULL;
13299  break;
13300 
13301  case SCIP_EXPR_REALPOWER:
13302  case SCIP_EXPR_SIGNPOWER:
13303  {
13304  va_start(ap, op ); /*lint !e838*/
13305  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
13306  va_end( ap ); /*lint !e826*/
13307 
13308  break;
13309  }
13310 
13311  case SCIP_EXPR_INTPOWER:
13312  {
13313  va_start(ap, op ); /*lint !e838*/
13314  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
13315  va_end( ap ); /*lint !e826*/
13316 
13317  break;
13318  }
13319 
13320  case SCIP_EXPR_LAST:
13321  SCIPABORT();
13322  return SCIP_INVALIDDATA; /*lint !e527*/
13323  }
13324 
13325  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13326 
13327  return SCIP_OKAY;
13328 }
13329 
13330 /** creates an expression graph node for a linear expression */
13332  BMS_BLKMEM* blkmem, /**< block memory */
13333  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13334  int ncoefs, /**< number of coefficients */
13335  SCIP_Real* coefs, /**< coefficients of linear expression */
13336  SCIP_Real constant /**< constant of linear expression */
13337  )
13338 {
13339  SCIP_EXPROPDATA opdata;
13340  SCIP_Real* data;
13341 
13342  assert(blkmem != NULL);
13343  assert(node != NULL);
13344 
13345  /* we store the coefficients and the constant in a single array and make this our operand data */
13346  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13347  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
13348  data[ncoefs] = constant;
13349 
13350  opdata.data = data;
13351  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13352 
13353  return SCIP_OKAY;
13354 }
13355 
13356 /** creates an expression graph node for a quadratic expression */
13358  BMS_BLKMEM* blkmem, /**< block memory */
13359  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13360  int nchildren, /**< number of children */
13361  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
13362  int nquadelems, /**< number of quadratic elements */
13363  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
13364  SCIP_Real constant /**< constant */
13365  )
13366 {
13367  SCIP_EXPROPDATA opdata;
13369 
13370  assert(blkmem != NULL);
13371  assert(node != NULL);
13372  assert(quadelems != NULL || nquadelems == 0);
13373 
13374  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13375 
13376  opdata.data = data;
13377  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13378 
13379  return SCIP_OKAY;
13380 }
13381 
13382 /** creates an expression graph node for a polynomial expression */
13384  BMS_BLKMEM* blkmem, /**< block memory */
13385  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13386  int nmonomials, /**< number of monomials */
13387  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13388  SCIP_Real constant, /**< constant of polynomial */
13389  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13390  )
13391 {
13392  SCIP_EXPROPDATA opdata;
13394 
13395  assert(blkmem != NULL);
13396  assert(node != NULL);
13397  assert(monomials != NULL || nmonomials == 0);
13398 
13399  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13400 
13401  opdata.data = data;
13402  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13403 
13404  return SCIP_OKAY;
13405 }
13406 
13407 /** adds monomials to an expression graph node that is a polynomial expression */
13409  BMS_BLKMEM* blkmem, /**< block memory */
13410  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
13411  int nmonomials, /**< number of monomials */
13412  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13413  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13414  )
13415 {
13416  assert(blkmem != NULL);
13417  assert(node != NULL);
13419  assert(monomials != NULL || nmonomials == 0);
13420 
13421  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13422 
13423  return SCIP_OKAY;
13424 }
13425 
13426 /** creates an expression graph node for a user expression */
13428  BMS_BLKMEM* blkmem, /**< block memory */
13429  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13430  SCIP_USEREXPRDATA* data, /**< user data for expression, node assumes ownership */
13431  SCIP_EXPRINTCAPABILITY evalcapability, /**< evaluation capability */
13432  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
13433  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function */
13434  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
13435  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function */
13436  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13437  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13438  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
13439  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
13440  )
13441 {
13442  SCIP_EXPROPDATA opdata;
13443  SCIP_EXPRDATA_USER* exprdata;
13444 
13445  assert(blkmem != NULL);
13446  assert(node != NULL);
13447  assert(eval != NULL);
13448  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
13449  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13450  assert(copydata != NULL || data == NULL);
13451  assert(freedata != NULL || data == NULL);
13452 
13453  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13454 
13455  exprdata->userdata = data;
13456  exprdata->evalcapability = evalcapability;
13457  exprdata->eval = eval;
13458  exprdata->estimate = estimate;
13459  exprdata->inteval = inteval;
13460  exprdata->curv = curv;
13461  exprdata->prop = prop;
13462  exprdata->copydata = copydata;
13463  exprdata->freedata = freedata;
13464  exprdata->print = print;
13465 
13466  opdata.data = (void*) exprdata;
13467 
13468  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13469 
13470  return SCIP_OKAY;
13471 }
13472 
13473 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13474  *
13475  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13476  * If the node is a linear expression, it may be freed.
13477  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13478  * It is assumed that the user had captured the node.
13479  * It is assumed that the expression graph has been simplified before.
13480  */
13482  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13483  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
13484  int linvarssize, /**< length of linvars and lincoefs arrays */
13485  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
13486  void** linvars, /**< buffer to store variables of linear part */
13487  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
13488  SCIP_Real* constant /**< buffer to store constant part */
13489  )
13490 {
13491  int orignvars;
13492  int* varsusage;
13493  SCIP_EXPRGRAPHNODE* orignode;
13494  SCIP_Bool havechange;
13495  int i;
13496 
13497  assert(exprgraph != NULL);
13498  assert(node != NULL);
13499  assert(*node != NULL);
13500  assert((*node)->nuses > 0);
13501  assert(nlinvars != NULL);
13502  assert(linvars != NULL || linvarssize == 0);
13503  assert(lincoefs != NULL || linvarssize == 0);
13504  assert(constant != NULL);
13505 
13506  *constant = 0.0;
13507  *nlinvars = 0;
13508 
13509  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13510 
13511  /* do some obvious and easy cases */
13512  switch( (*node)->op )
13513  {
13514  case SCIP_EXPR_VARIDX:
13515  {
13516  if( linvarssize >= 1 )
13517  {
13518  *nlinvars = 1;
13519  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
13520  lincoefs[0] = 1.0; /*lint !e613*/
13521 
13522  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13523  }
13524  return SCIP_OKAY;
13525  }
13526 
13527  case SCIP_EXPR_CONST:
13528  {
13529  *constant = (*node)->data.dbl;
13530  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13531 
13532  return SCIP_OKAY;
13533  }
13534 
13535  case SCIP_EXPR_REALPOWER:
13536  case SCIP_EXPR_SIGNPOWER:
13537  {
13538  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13539  {
13540  *nlinvars = 1;
13541  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13542  lincoefs[0] = 1.0; /*lint !e613*/
13543 
13544  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13545  }
13546  return SCIP_OKAY;
13547  }
13548 
13549  case SCIP_EXPR_INTPOWER:
13550  {
13551  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13552  {
13553  *nlinvars = 1;
13554  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13555  lincoefs[0] = 1.0; /*lint !e613*/
13556 
13557  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13558  }
13559  return SCIP_OKAY;
13560  }
13561 
13562  case SCIP_EXPR_PLUS:
13563  {
13564  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13565  {
13566  *constant = (*node)->children[0]->data.dbl;
13567  *nlinvars = 1;
13568  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13569  lincoefs[0] = 1.0; /*lint !e613*/
13570 
13571  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13572 
13573  return SCIP_OKAY;
13574  }
13575  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13576  {
13577  *constant = (*node)->children[1]->data.dbl;
13578  *nlinvars = 1;
13579  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13580  lincoefs[0] = 1.0; /*lint !e613*/
13581 
13582  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13583 
13584  return SCIP_OKAY;
13585  }
13586  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13587  {
13588  *nlinvars = 2;
13589  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13590  lincoefs[0] = 1.0; /*lint !e613*/
13591  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13592  lincoefs[1] = 1.0; /*lint !e613*/
13593 
13594  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13595 
13596  return SCIP_OKAY;
13597  }
13598  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13599  {
13600  /* handle this one later */
13601  break;
13602  }
13603  return SCIP_OKAY;
13604  }
13605 
13606  case SCIP_EXPR_MINUS:
13607  {
13608  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13609  {
13610  *constant = (*node)->children[0]->data.dbl;
13611  *nlinvars = 1;
13612  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13613  lincoefs[0] = -1.0; /*lint !e613*/
13614 
13615  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13616 
13617  return SCIP_OKAY;
13618  }
13619  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13620  {
13621  *constant = -(*node)->children[1]->data.dbl;
13622  *nlinvars = 1;
13623  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13624  lincoefs[0] = 1.0; /*lint !e613*/
13625 
13626  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13627 
13628  return SCIP_OKAY;
13629  }
13630  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13631  {
13632  *nlinvars = 2;
13633  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13634  lincoefs[0] = 1.0; /*lint !e613*/
13635  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13636  lincoefs[1] = -1.0; /*lint !e613*/
13637 
13638  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13639 
13640  return SCIP_OKAY;
13641  }
13642  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13643  {
13644  /* handle this one later */
13645  break;
13646  }
13647  return SCIP_OKAY;
13648  }
13649 
13650  case SCIP_EXPR_MUL:
13651  {
13652  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13653  {
13654  *nlinvars = 1;
13655  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13656  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
13657 
13658  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13659  }
13660  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13661  {
13662  *nlinvars = 1;
13663  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13664  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
13665 
13666  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13667  }
13668  return SCIP_OKAY;
13669  }
13670 
13671  case SCIP_EXPR_DIV:
13672  {
13673  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13674  return SCIP_OKAY;
13675 
13676  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13677  {
13678  *nlinvars = 1;
13679  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13680  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
13681 
13682  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13683  }
13684  return SCIP_OKAY;
13685  }
13686 
13687  case SCIP_EXPR_SQUARE:
13688  case SCIP_EXPR_SQRT:
13689  case SCIP_EXPR_EXP:
13690  case SCIP_EXPR_LOG:
13691  case SCIP_EXPR_SIN:
13692  case SCIP_EXPR_COS:
13693  case SCIP_EXPR_TAN:
13694  /* case SCIP_EXPR_ERF: */
13695  /* case SCIP_EXPR_ERFI: */
13696  case SCIP_EXPR_ABS:
13697  case SCIP_EXPR_SIGN:
13698  case SCIP_EXPR_MIN:
13699  case SCIP_EXPR_MAX:
13700  return SCIP_OKAY;
13701 
13702  case SCIP_EXPR_PRODUCT:
13703  case SCIP_EXPR_USER:
13704  return SCIP_OKAY;
13705 
13706  case SCIP_EXPR_SUM:
13707  case SCIP_EXPR_LINEAR:
13708  case SCIP_EXPR_QUADRATIC:
13709  case SCIP_EXPR_POLYNOMIAL:
13710  default:
13711  {
13712  /* check if there is a child that is a variable */
13713  for( i = 0; i < (*node)->nchildren; ++i )
13714  {
13715  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13716  break;
13717  }
13718 
13719  if( i == (*node)->nchildren )
13720  return SCIP_OKAY;
13721 
13722  break;
13723  }
13724  } /*lint !e788*/
13725 
13726  /* count how often variables are used in this expression */
13727  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13728  orignvars = exprgraph->nvars;
13729  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13730  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
13731 
13732  exprgraphNodeGetVarsUsage(*node, varsusage);
13733 
13734  /* duplicate node if it has parents or more than one user */
13735  orignode = NULL;
13736  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13737  {
13738  SCIP_EXPROPDATA data;
13739 
13740  orignode = *node;
13741 
13742  if( exprOpTable[orignode->op].copydata != NULL )
13743  {
13744  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13745  }
13746  else
13747  data = orignode->data;
13748 
13749  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13750  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13751  SCIPexprgraphCaptureNode(*node);
13752  }
13753 
13754  havechange = FALSE;
13755  /* split up constant and linear part */
13756  switch( (*node)->op )
13757  {
13758  case SCIP_EXPR_PLUS:
13759  case SCIP_EXPR_MINUS:
13760  {
13761  SCIP_EXPRGRAPHNODE* varchild;
13762  SCIP_EXPRGRAPHNODE* otherchild;
13763  int varidx;
13764 
13765  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13766  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13767  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13768  assert(linvarssize >= 1);
13769 
13770  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13771  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13772  varidx = varchild->data.intval;
13773  /* if variable is used in other child (which should be nonlinear), we don't take it */
13774  if( varsusage[varidx] > 1 )
13775  break;
13776 
13777  /* add to linear variables */
13778  *nlinvars = 1;
13779  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13780  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13781  lincoefs[0] = -1.0; /*lint !e613*/
13782  else
13783  lincoefs[0] = 1.0; /*lint !e613*/
13784 
13785  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13786  {
13787  /* replace *node by otherchild */
13788  SCIPexprgraphCaptureNode(otherchild);
13789  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13790  *node = otherchild;
13791  }
13792  else
13793  {
13794  SCIP_Real* lindata;
13795 
13796  /* turn *node into linear expression -1.0 * otherchild */
13797 
13798  /* reduce to one child */
13799  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13800  (*node)->children[0] = otherchild;
13801  (*node)->nchildren = 1;
13802  (*node)->op = SCIP_EXPR_LINEAR;
13803 
13804  /* setup linear data -1.0 * child0 + 0.0 */
13805  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13806  lindata[0] = -1.0;
13807  lindata[1] = 0.0;
13808  (*node)->data.data = (void*)lindata;
13809 
13810  /* remove *node as parent of varchild */
13811  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13812  }
13813 
13814  havechange = TRUE;
13815 
13816  break;
13817  }
13818 
13819  case SCIP_EXPR_SUM:
13820  {
13821  int nchildren;
13822 
13823  i = 0;
13824  nchildren = (*node)->nchildren;
13825  while( i < nchildren )
13826  {
13827  /* sort out constants */
13828  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13829  {
13830  *constant += (*node)->children[i]->data.dbl;
13831  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13832 
13833  if( i < nchildren-1 )
13834  {
13835  (*node)->children[i] = (*node)->children[nchildren-1];
13836  (*node)->children[nchildren-1] = NULL;
13837  }
13838  --nchildren;
13839 
13840  continue;
13841  }
13842 
13843  /* keep every child that is not a constant or variable */
13844  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13845  {
13846  ++i;
13847  continue;
13848  }
13849 
13850  /* skip variables that are used in other parts of the expression */
13851  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13852  {
13853  ++i;
13854  continue;
13855  }
13856 
13857  /* move variable into linear part, if still space */
13858  if( *nlinvars < linvarssize )
13859  {
13860  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13861  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13862  ++*nlinvars;
13863 
13864  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13865  if( i < nchildren-1 )
13866  {
13867  (*node)->children[i] = (*node)->children[nchildren-1];
13868  (*node)->children[nchildren-1] = NULL;
13869  }
13870  --nchildren;
13871 
13872  continue;
13873  }
13874  }
13875  assert(i == nchildren);
13876 
13877  if( nchildren == 0 )
13878  {
13879  /* all children were removed */
13880  havechange = TRUE;
13881  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13882  (*node)->nchildren = 0;
13883  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13884  break;
13885  }
13886 
13887  if( nchildren < (*node)->nchildren )
13888  {
13889  /* some children were removed */
13890  havechange = TRUE;
13891  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13892  (*node)->nchildren = nchildren;
13893  }
13894 
13895  if( havechange && (*node)->nchildren == 1 )
13896  {
13897  /* replace node by its child */
13898  SCIP_EXPRGRAPHNODE* child;
13899 
13900  child = (*node)->children[0];
13901  SCIPexprgraphCaptureNode(child);
13902  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13903  *node = child;
13904 
13905  break;
13906  }
13907 
13908  break;
13909  }
13910 
13911  case SCIP_EXPR_LINEAR:
13912  {
13913  int nchildren;
13914  SCIP_Real* coefs;
13915 
13916  coefs = (SCIP_Real*)(*node)->data.data;
13917  assert(coefs != NULL);
13918 
13919  /* remove constant, if nonzero */
13920  if( coefs[(*node)->nchildren] != 0.0 )
13921  {
13922  *constant = coefs[(*node)->nchildren];
13923  coefs[(*node)->nchildren] = 0.0;
13924  havechange = TRUE;
13925  }
13926 
13927  i = 0;
13928  nchildren = (*node)->nchildren;
13929  while( i < nchildren )
13930  {
13931  /* sort out constants */
13932  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13933  {
13934  *constant += coefs[i] * (*node)->children[i]->data.dbl;
13935  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13936 
13937  if( i < nchildren-1 )
13938  {
13939  (*node)->children[i] = (*node)->children[nchildren-1];
13940  (*node)->children[nchildren-1] = NULL;
13941  coefs[i] = coefs[nchildren-1];
13942  coefs[nchildren-1] = 0.0;
13943  }
13944  --nchildren;
13945 
13946  continue;
13947  }
13948 
13949  /* keep everything that is not a constant or variable */
13950  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13951  {
13952  ++i;
13953  continue;
13954  }
13955 
13956  /* skip variables that are used in other parts of the expression */
13957  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13958  {
13959  ++i;
13960  continue;
13961  }
13962 
13963  /* move variable into linear part, if still space */
13964  if( *nlinvars < linvarssize )
13965  {
13966  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13967  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
13968  ++*nlinvars;
13969 
13970  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13971  if( i < nchildren-1 )
13972  {
13973  (*node)->children[i] = (*node)->children[nchildren-1];
13974  (*node)->children[nchildren-1] = NULL;
13975  coefs[i] = coefs[nchildren-1];
13976  coefs[nchildren-1] = 0.0;
13977  }
13978  --nchildren;
13979 
13980  continue;
13981  }
13982  }
13983  assert(i == nchildren);
13984 
13985  if( nchildren == 0 )
13986  {
13987  /* all children were removed */
13988  havechange = TRUE;
13989  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13990  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
13991  (*node)->data.data = NULL;
13992  (*node)->nchildren = 0;
13993  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
13994  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13995  break;
13996  }
13997 
13998  if( nchildren < (*node)->nchildren )
13999  {
14000  /* some children were removed */
14001  havechange = TRUE;
14002  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14003  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
14004  coefs[nchildren] = 0.0;
14005  (*node)->data.data = (void*)coefs;
14006  (*node)->nchildren = nchildren;
14007  }
14008 
14009  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
14010  {
14011  /* replace node by its child */
14012  SCIP_EXPRGRAPHNODE* child;
14013 
14014  child = (*node)->children[0];
14015  SCIPexprgraphCaptureNode(child);
14016  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14017  *node = child;
14018 
14019  break;
14020  }
14021 
14022  break;
14023  }
14024 
14025  case SCIP_EXPR_QUADRATIC:
14026  {
14027  SCIP_EXPRDATA_QUADRATIC* quaddata;
14028  SCIP_Bool* childused;
14029  int* childmap;
14030  int nchildren;
14031 
14032  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
14033  assert(quaddata != NULL);
14034 
14035  /* remove constant, if nonzero */
14036  if( quaddata->constant != 0.0 )
14037  {
14038  *constant = quaddata->constant;
14039  quaddata->constant = 0.0;
14040  havechange = TRUE;
14041  }
14042 
14043  /* if there is no linear part or no space left for linear variables, then stop */
14044  if( quaddata->lincoefs != NULL || linvarssize == 0 )
14045  break;
14046 
14047  /* check which childs are used in quadratic terms */
14048  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14049  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14050 
14051  for( i = 0; i < quaddata->nquadelems; ++i )
14052  {
14053  childused[quaddata->quadelems[i].idx1] = TRUE;
14054  childused[quaddata->quadelems[i].idx2] = TRUE;
14055  }
14056 
14057  /* alloc space for mapping of children indices */
14058  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
14059 
14060  nchildren = (*node)->nchildren;
14061  for( i = 0; i < nchildren; ++i )
14062  {
14063  childmap[i] = i; /*lint !e644*/
14064  if( *nlinvars >= linvarssize )
14065  continue;
14066  /* skip child if not variable or also used in quadratic part or other parts of expression */
14067  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14068  continue;
14069  if( childused[i] )
14070  continue;
14071  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14072  continue;
14073 
14074  /* put variable into linear part */
14075  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14076  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
14077  quaddata->lincoefs[i] = 0.0;
14078  ++*nlinvars;
14079 
14080  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14081 
14082  /* move last child to position i */
14083  if( i < nchildren-1 )
14084  {
14085  (*node)->children[i] = (*node)->children[nchildren-1];
14086  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
14087  childused[i] = childused[nchildren-1];
14088  childmap[nchildren-1] = i;
14089  }
14090  --nchildren;
14091  childmap[i] = -1;
14092 
14093  havechange = TRUE;
14094  --i; /* look at i again */
14095  }
14096 
14097  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
14098 
14099  if( nchildren < (*node)->nchildren )
14100  {
14101  /* apply childmap to quadratic term */
14102  for( i = 0; i < quaddata->nquadelems; ++i )
14103  {
14104  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
14105  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
14106  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
14107  {
14108  int tmp;
14109  tmp = quaddata->quadelems[i].idx1;
14110  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
14111  quaddata->quadelems[i].idx2 = tmp;
14112  }
14113  }
14114  quaddata->sorted = FALSE;
14115  }
14116  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
14117 
14118  if( nchildren == 0 )
14119  {
14120  /* all children were removed (so it was actually a linear expression) */
14121  havechange = TRUE;
14122  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14123  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
14124  (*node)->data.data = NULL;
14125  (*node)->nchildren = 0;
14126  (*node)->op = SCIP_EXPR_SUM;
14127  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14128  break;
14129  }
14130 
14131  if( nchildren < (*node)->nchildren )
14132  {
14133  /* reduce number of children */
14134  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14135  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
14136  (*node)->nchildren = nchildren;
14137  }
14138 
14139  break;
14140  }
14141 
14142  case SCIP_EXPR_POLYNOMIAL:
14143  {
14144  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
14145  SCIP_EXPRDATA_MONOMIAL* monomial;
14146  SCIP_Bool* childused;
14147  int childidx;
14148  int j;
14149 
14150  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
14151  assert(polynomialdata != NULL);
14152 
14153  /* make sure linear monomials are merged */
14154  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14155 
14156  /* remove constant, if nonzero */
14157  if( polynomialdata->constant != 0.0 )
14158  {
14159  *constant = polynomialdata->constant;
14160  polynomialdata->constant = 0.0;
14161  havechange = TRUE;
14162  }
14163 
14164  /* if there is no space for linear variables, then stop */
14165  if( linvarssize == 0 )
14166  break;
14167 
14168  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14169  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14170  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14171  for( i = 0; i < polynomialdata->nmonomials; ++i )
14172  {
14173  monomial = polynomialdata->monomials[i];
14174  assert(monomial != NULL);
14175  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14176  continue;
14177  for( j = 0; j < monomial->nfactors; ++j )
14178  {
14179  assert(monomial->childidxs[j] >= 0);
14180  assert(monomial->childidxs[j] < (*node)->nchildren);
14181  childused[monomial->childidxs[j]] = TRUE;
14182  }
14183  }
14184 
14185  /* move linear monomials out of polynomial */
14186  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14187  {
14188  monomial = polynomialdata->monomials[i];
14189  assert(monomial != NULL);
14190 
14191  /* sort out constants */
14192  if( monomial->nfactors == 0 )
14193  {
14194  if( monomial->coef != 0.0 )
14195  {
14196  *constant += monomial->coef;
14197  havechange = TRUE;
14198  }
14199  continue;
14200  }
14201 
14202  if( monomial->nfactors != 1 )
14203  continue;
14204  if( monomial->exponents[0] != 1.0 )
14205  continue;
14206  childidx = monomial->childidxs[0];
14207  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14208  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14209  continue;
14210  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14211  continue;
14212 
14213  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14214 
14215  /* put variable into linear part */
14216  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
14217  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
14218  ++*nlinvars;
14219 
14220  monomial->coef = 0.0;
14221  monomial->nfactors = 0;
14222  polynomialdata->sorted = FALSE;
14223 
14224  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14225  (*node)->children[childidx] = NULL;
14226 
14227  havechange = TRUE;
14228  }
14229 
14230  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14231 
14232  if( *nlinvars > 0 )
14233  {
14234  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14235  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14237  }
14238 
14239  if( (*node)->nchildren == 0 )
14240  {
14241  assert(polynomialdata->nmonomials == 0);
14242  assert(polynomialdata->constant == 0.0);
14243  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14244  havechange = TRUE;
14245  break;
14246  }
14247 
14248  break;
14249  }
14250 
14251  default: ;
14252  } /*lint !e788*/
14253 
14254  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14255 
14256  if( orignode != NULL )
14257  {
14258  /* if node was duplicated, we need to forget about original or duplicate */
14259  if( !havechange )
14260  {
14261  /* if nothing has changed, then forget about duplicate */
14262  assert(*constant == 0.0);
14263  assert(*nlinvars == 0);
14264  assert(*node != NULL);
14265  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14266  *node = orignode;
14267  }
14268  else
14269  {
14270  /* if something changed, then release original node */
14271  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14272  }
14273  }
14274  else if( havechange && *node != NULL )
14275  {
14276  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14277  (*node)->value = SCIP_INVALID;
14278  (*node)->simplified = FALSE;
14279  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14280  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14281  exprgraph->needvarboundprop = TRUE;
14282  }
14283 
14284  return SCIP_OKAY;
14285 }
14286 
14287 /** moves parents from a one node to another node
14288  *
14289  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14290  * srcnode may be freed, if not captured.
14291  * It is assumed that targetnode represents the same expression as srcnode.
14292  */
14294  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14295  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
14296  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
14297  )
14298 {
14299  assert(exprgraph != NULL);
14300  assert(srcnode != NULL);
14301  assert(*srcnode != NULL);
14302  assert(targetnode != NULL);
14303 
14304  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14305  {
14306  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14307  {
14308  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14309  }
14310  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14311  }
14312  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14313 
14314  return SCIP_OKAY;
14315 }
14316 
14317 /** releases node, i.e., decreases number of uses
14318  *
14319  * node is freed if no parents and no other uses.
14320  * Children are recursively released if they have no other parents.
14321  * Nodes that are removed are also freed.
14322  * If node correspond to a variable, then the variable is removed from the expression graph;
14323  * similarly for constants.
14324  */
14326  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14327  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
14328  )
14329 {
14330  int i;
14331 
14332  assert(exprgraph != NULL);
14333  assert(node != NULL);
14334  assert(*node != NULL);
14335  assert((*node)->depth >= 0); /* node should be in graph */
14336  assert((*node)->pos >= 0); /* node should be in graph */
14337  assert((*node)->depth < exprgraph->depth);
14338  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14339  assert((*node)->nuses >= 1);
14340  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14341 
14342  SCIPdebugMessage("release node %p\n", (void*)*node);
14343 
14344  --(*node)->nuses;
14345 
14346  /* do nothing if node still has parents or is still in use */
14347  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14348  {
14349  SCIPdebugMessage("skip removing node %p (%d, %d) with %d parents and %d uses from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, (*node)->nparents, (*node)->nuses);
14350  *node = NULL;
14351  return SCIP_OKAY;
14352  }
14353 
14354  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14355 
14356  /* notify children about removal of its parent
14357  * they are also freed, if possible */
14358  for( i = 0; i < (*node)->nchildren; ++i )
14359  {
14360  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14361  (*node)->children[i] = NULL;
14362  }
14363 
14364  if( (*node)->op == SCIP_EXPR_VARIDX )
14365  {
14366  assert((*node)->depth == 0);
14367  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14368  }
14369  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14370  {
14371  int constidx;
14372 
14373  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14374  assert(constidx >= 0);
14375  assert(constidx < exprgraph->nconsts);
14376  assert(exprgraph->constnodes[constidx] == *node);
14377 
14378  /* move last constant to position constidx */
14379  if( constidx < exprgraph->nconsts-1 )
14380  {
14381  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14382  exprgraph->constssorted = (exprgraph->nconsts <= 2);
14383  }
14384  --exprgraph->nconsts;
14385  }
14386  else
14387  {
14388  /* only variables and constants are allowed at depth 0 */
14389  assert((*node)->depth > 0);
14390  }
14391 
14392  /* remove node from nodes array in expression graph */
14393  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14394  {
14395  /* move last node at depth of *node to position of *node */
14396  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14397  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14398  }
14399  --exprgraph->nnodes[(*node)->depth];
14400 
14401  /* node is now not in graph anymore */
14402  (*node)->depth = -1;
14403  (*node)->pos = -1;
14404 
14405  /* free node */
14406  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14407 
14408  *node = NULL;
14409 
14410  return SCIP_OKAY;
14411 }
14412 
14413 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14414 /** frees a node of an expression graph */
14416  BMS_BLKMEM* blkmem, /**< block memory */
14417  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
14418  )
14419 {
14420  assert(blkmem != NULL);
14421  assert( node != NULL);
14422  assert(*node != NULL);
14423  assert((*node)->depth == -1); /* node should not be in graph anymore */
14424  assert((*node)->pos == -1); /* node should not be in graph anymore */
14425  assert((*node)->nuses == 0); /* node should not be in use */
14426 
14427  /* free operator data, if needed */
14428  if( exprOpTable[(*node)->op].freedata != NULL )
14429  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14430 
14431  /* free arrays of children and parent nodes */
14432  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14433  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
14434 
14435  /* free node struct */
14436  BMSfreeBlockMemory(blkmem, node);
14437 }
14438 
14439 /** enables a node and recursively all its children in an expression graph */
14441  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14442  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14443  )
14444 {
14445  int i;
14446 
14447  assert(exprgraph != NULL);
14448  assert(node != NULL);
14449  assert(node->depth >= 0);
14450  assert(node->pos >= 0);
14451 
14452  if( node->enabled )
14453  return;
14454 
14455  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14456 
14457  node->enabled = TRUE;
14458  for( i = 0; i < node->nchildren; ++i )
14459  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14460 
14461  /* make sure bounds are updated in next bound propagation round */
14462  SCIPintervalSetEntire(SCIP_REAL_MAX, &node->bounds);
14463  exprgraph->needvarboundprop = TRUE;
14464 }
14465 
14466 /** disables a node and recursively all children which have no enabled parents in an expression graph */
14468  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14469  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14470  )
14471 {
14472  int i;
14473 
14474  assert(exprgraph != NULL);
14475  assert(node != NULL);
14476  assert(node->depth >= 0);
14477  assert(node->pos >= 0);
14478 
14479  if( !node->enabled )
14480  return;
14481 
14482  /* workaround: don't disable nodes if there could be more users than the one who is disabling the node
14483  * otherwise, if there are several nonlinear constraints using the same expression graph node as root node,
14484  * we might get enabled constraints with disabled node
14485  */
14486  if( node->nuses > 1 )
14487  return;
14488 
14489  /* if all parents of node are disabled, then also node can be disabled */
14490  node->enabled = FALSE;
14491  for( i = 0; i < node->nparents; ++i )
14492  if( node->parents[i]->enabled )
14493  {
14494  node->enabled = TRUE;
14495  return;
14496  }
14497 
14498  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14499 
14500  for( i = 0; i < node->nchildren; ++i )
14501  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14502 }
14503 
14504 /** returns whether the node has siblings in the expression graph */
14506  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14507  )
14508 {
14509  int p;
14510 
14511  assert(node != NULL);
14512 
14513  for( p = 0; p < node->nparents; ++p )
14514  if( node->parents[p]->nchildren > 1 )
14515  return TRUE;
14516 
14517  return FALSE;
14518 }
14519 
14520 /** returns whether all children of an expression graph node are variable nodes
14521  *
14522  * Returns TRUE for nodes without children.
14523  */
14525  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14526  )
14527 {
14528  int i;
14529 
14530  assert(node != NULL);
14531 
14532  for( i = 0; i < node->nchildren; ++i )
14533  if( node->children[i]->op != SCIP_EXPR_VARIDX )
14534  return FALSE;
14535 
14536  return TRUE;
14537 }
14538 
14539 /** returns whether the node has an ancestor which has a nonlinear expression operand */
14541  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14542  )
14543 {
14544  int p;
14545 
14546  for( p = 0; p < node->nparents; ++p )
14547  {
14548  assert(node->parents[p]->depth > node->depth);
14549  switch( node->parents[p]->op )
14550  {
14551  case SCIP_EXPR_PLUS:
14552  case SCIP_EXPR_MINUS:
14553  case SCIP_EXPR_SUM:
14554  case SCIP_EXPR_LINEAR:
14556  return TRUE;
14557  break;
14558 
14559 #ifndef NDEBUG
14560  case SCIP_EXPR_VARIDX:
14561  case SCIP_EXPR_CONST:
14562  case SCIP_EXPR_PARAM:
14563  assert(0); /* these expressions cannot have children */
14564  break;
14565 #endif
14566 
14567  default:
14568  /* parent has nonlinear expression operand */
14569  return TRUE;
14570  }/*lint !e788*/
14571  }
14572 
14573  return FALSE;
14574 }
14575 
14576 /** prints an expression graph node */
14578  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14579  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14580  FILE* file /**< file to print to, or NULL for stdout */
14581  )
14582 {
14583  assert(node != NULL);
14584 
14585  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14586 }
14587 
14588 /** tightens the bounds in a node of the graph
14589  *
14590  * Preparation for reverse propagation.
14591  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14592  */
14594  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14595  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
14596  SCIP_INTERVAL nodebounds, /**< new bounds for node */
14597  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes (set to negative value if propagation should always be triggered) */
14598  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14599  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14600  )
14601 {
14602  assert(exprgraph != NULL);
14603  assert(node != NULL);
14604  assert(node->depth >= 0);
14605  assert(node->pos >= 0);
14606  assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14607  assert(cutoff != NULL);
14608 
14609  *cutoff = FALSE;
14610 
14611  /* if node is disabled, then ignore new bounds */
14612  if( !node->enabled )
14613  {
14614  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14615  return;
14616  }
14617 
14618  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14619  (void*)node, node->depth, node->pos,
14620  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14621 
14622  /* bounds in node should be valid */
14623  assert(!(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
14624 
14625  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14626  {
14627  *cutoff = TRUE;
14628  SCIPdebugPrintf(" -> cutoff\n");
14629  return;
14630  }
14631 
14632  /* if minstrength is negative, always mark that node has recently tightened bounds,
14633  * if bounds are considerably improved or tightening leads to an empty interval,
14634  * mark that node has recently tightened bounds
14635  * if bounds are only slightly improved, set the status to tightened by parent,
14636  * so next propagateVarBound round will reset the bounds
14637  */
14638  if( minstrength < 0.0 )
14639  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE;
14640  else if(
14641  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14642  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14643  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT;
14644  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14645  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT;
14646 
14647  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14648  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14649 }
14650 
14651 /** ensures that bounds and curvature information in a node is uptodate
14652  *
14653  * Assumes that bounds and curvature in children are uptodate.
14654  */
14656  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14657  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14658  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14659  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14660  )
14661 {
14662  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14663  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14664  SCIP_INTERVAL* childbounds;
14665  SCIP_EXPRCURV* childcurv;
14666  int i;
14667 
14668  assert(node != NULL);
14669  assert(node->depth >= 0); /* node should be in graph */
14670  assert(node->pos >= 0); /* node should be in graph */
14671  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14672 
14673  if( node->depth == 0 )
14674  {
14675  /* we cannot update bound tightenings in variable nodes here */
14676  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14677  return SCIP_OKAY;
14678  }
14679 
14680  assert(node->op != SCIP_EXPR_VARIDX);
14681  assert(node->op != SCIP_EXPR_PARAM);
14682 
14683  /* if many children, get large enough memory to store children bounds */
14685  {
14686  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14687  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, node->nchildren) );
14688  }
14689  else
14690  {
14691  childbounds = childboundsstatic;
14692  childcurv = childcurvstatic;
14693  }
14694 
14695  /* assemble bounds and curvature of children */
14696  for( i = 0; i < node->nchildren; ++i )
14697  {
14698  /* child should have valid and non-empty bounds */
14700  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14701  /* nodes at depth 0 are always linear */
14702  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14703 
14704  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
14705  childcurv[i] = node->children[i]->curv; /*lint !e644*/
14706  }
14707 
14708  /* if we do not have valid bounds, then update
14709  * code below is copied from exprgraphNodeUpdateBounds */
14711  {
14712  SCIP_INTERVAL newbounds;
14713 
14714  /* calling interval evaluation function for this operand */
14715  assert( exprOpTable[node->op].inteval != NULL );
14716  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
14717 
14718  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14719  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14720  *
14721  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14722  *
14723  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14724  */
14725  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14727  {
14728  for( i = 0; i < node->nparents; ++i )
14730 
14731  node->bounds = newbounds;
14732  }
14733  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14734  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14735  {
14736  for( i = 0; i < node->nparents; ++i )
14738 
14739  node->bounds = newbounds;
14740  }
14741  else
14742  {
14743  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14744  }
14745 
14746  SCIPdebugMessage("updated bounds of node %p (%d,%d) op %s to [%g,%g]\n", (void*)node, node->depth, node->pos, SCIPexpropGetName(node->op), node->bounds.inf, node->bounds.sup);
14747 
14748  /* node now has valid bounds */
14749  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
14750  }
14751 
14752  /* update curvature */
14753  if( SCIPintervalIsEmpty(infinity, node->bounds) )
14754  {
14755  node->curv = SCIP_EXPRCURV_LINEAR;
14756 
14757  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14758  }
14759  else
14760  {
14761  SCIP_CALL( exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv) );
14762 
14763  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14764  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14765  * SCIPdebugPrintf("\n");
14766  */
14767  }
14768 
14769  /* free memory, if allocated before */
14770  if( childbounds != childboundsstatic )
14771  {
14772  BMSfreeMemoryArray(&childbounds);
14773  BMSfreeMemoryArray(&childcurv);
14774  }
14775 
14776  return SCIP_OKAY;
14777 }
14778 
14779 /**@} */
14780 
14781 /**@name Expression graph methods */
14782 /**@{ */
14783 
14784 /* In debug mode, the following methods are implemented as function calls to ensure
14785  * type validity.
14786  * In optimized mode, the methods are implemented as defines to improve performance.
14787  * However, we want to have them in the library anyways, so we have to undef the defines.
14788  */
14789 
14790 #undef SCIPexprgraphGetDepth
14791 #undef SCIPexprgraphGetNNodes
14792 #undef SCIPexprgraphGetNodes
14793 #undef SCIPexprgraphGetNVars
14794 #undef SCIPexprgraphGetVars
14795 #undef SCIPexprgraphGetVarNodes
14796 #undef SCIPexprgraphSetVarNodeValue
14797 #undef SCIPexprgraphSetVarsBounds
14798 #undef SCIPexprgraphSetVarBounds
14799 #undef SCIPexprgraphSetVarNodeBounds
14800 #undef SCIPexprgraphSetVarNodeLb
14801 #undef SCIPexprgraphSetVarNodeUb
14802 #undef SCIPexprgraphGetVarsBounds
14803 
14804 /** get current maximal depth of expression graph */
14806  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14807  )
14808 {
14809  assert(exprgraph != NULL);
14810 
14811  return exprgraph->depth;
14812 }
14813 
14814 /** gets array with number of nodes at each depth of expression graph */
14816  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14817  )
14818 {
14819  assert(exprgraph != NULL);
14820 
14821  return exprgraph->nnodes;
14822 }
14823 
14824 /** gets nodes of expression graph, one array per depth */
14826  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14827  )
14828 {
14829  assert(exprgraph != NULL);
14830 
14831  return exprgraph->nodes;
14832 }
14833 
14834 /** gets number of variables in expression graph */
14836  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14837  )
14838 {
14839  assert(exprgraph != NULL);
14840 
14841  return exprgraph->nvars;
14842 }
14843 
14844 /** gets array of variables in expression graph */
14846  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14847  )
14848 {
14849  assert(exprgraph != NULL);
14850 
14851  return exprgraph->vars;
14852 }
14853 
14854 /** gets array of expression graph nodes corresponding to variables */
14856  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14857  )
14858 {
14859  assert(exprgraph != NULL);
14860 
14861  return exprgraph->varnodes;
14862 }
14863 
14864 /** sets value for a single variable given as expression graph node */
14866  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14867  SCIP_Real value /**< new value for variable */
14868  )
14869 {
14870  assert(varnode != NULL);
14871  assert(varnode->op == SCIP_EXPR_VARIDX);
14872 
14873  varnode->value = value;
14874 }
14875 
14876 /** sets bounds for variables */
14878  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14879  SCIP_INTERVAL* varbounds /**< new bounds for variables */
14880  )
14881 {
14882  assert(exprgraph != NULL);
14883  assert(varbounds != NULL || exprgraph->nvars == 0);
14884 
14885  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
14886 }
14887 
14888 /** sets bounds for a single variable */
14890  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14891  void* var, /**< variable */
14892  SCIP_INTERVAL varbounds /**< new bounds of variable */
14893  )
14894 {
14895  int pos;
14896 
14897  assert(exprgraph != NULL);
14898  assert(var != NULL);
14899  assert(SCIPhashmapExists(exprgraph->varidxs, var));
14900 
14901  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
14902  assert(pos < exprgraph->nvars);
14903  assert(exprgraph->vars[pos] == var);
14904 
14905  exprgraph->varbounds[pos] = varbounds;
14906 }
14907 
14908 /** sets bounds for a single variable given as expression graph node */
14910  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14911  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14912  SCIP_INTERVAL varbounds /**< new bounds of variable */
14913  )
14914 {
14915  int pos;
14916 
14917  assert(exprgraph != NULL);
14918  assert(varnode != NULL);
14919 
14920  pos = varnode->data.intval;
14921  assert(pos >= 0);
14922  assert(pos < exprgraph->nvars);
14923  assert(exprgraph->varnodes[pos] == varnode);
14924 
14925  exprgraph->varbounds[pos] = varbounds;
14926 }
14927 
14928 /** sets lower bound for a single variable given as expression graph node */
14930  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14931  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14932  SCIP_Real lb /**< new lower bound for variable */
14933  )
14934 {
14935  int pos;
14936 
14937  assert(exprgraph != NULL);
14938  assert(varnode != NULL);
14939 
14940  pos = varnode->data.intval;
14941  assert(pos >= 0);
14942  assert(pos < exprgraph->nvars);
14943  assert(exprgraph->varnodes[pos] == varnode);
14944 
14945  exprgraph->varbounds[pos].inf = lb;
14946 }
14947 
14948 /** sets upper bound for a single variable given as expression graph node */
14950  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14951  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14952  SCIP_Real ub /**< new upper bound for variable */
14953  )
14954 {
14955  int pos;
14956 
14957  assert(exprgraph != NULL);
14958  assert(varnode != NULL);
14959 
14960  pos = varnode->data.intval;
14961  assert(pos >= 0);
14962  assert(pos < exprgraph->nvars);
14963  assert(exprgraph->varnodes[pos] == varnode);
14964 
14965  exprgraph->varbounds[pos].sup = ub;
14966 }
14967 
14968 /** gets bounds that are stored for all variables */
14970  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14971  )
14972 {
14973  return exprgraph->varbounds;
14974 }
14975 
14976 /** creates an empty expression graph */
14978  BMS_BLKMEM* blkmem, /**< block memory */
14979  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
14980  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
14981  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
14982  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /**< callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
14983  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /**< callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
14984  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /**< callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
14985  void* userdata /**< user data to pass to callback functions */
14986  )
14987 {
14988  assert(blkmem != NULL);
14989  assert(exprgraph != NULL);
14990 
14991  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
14992  BMSclearMemory(*exprgraph);
14993  (*exprgraph)->blkmem = blkmem;
14994 
14995  /* create nodes's arrays */
14996  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
14997  assert((*exprgraph)->depth >= 1);
14998 
14999  /* create var's arrays and hashmap */
15000  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
15001  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, (*exprgraph)->varssize) );
15002 
15003  /* empty array of constants is sorted */
15004  (*exprgraph)->constssorted = TRUE;
15005 
15006  /* store callback functions and user data */
15007  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
15008  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
15009  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
15010  (*exprgraph)->userdata = userdata;
15011 
15012  return SCIP_OKAY;
15013 }
15014 
15015 /** frees an expression graph */
15017  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
15018  )
15019 {
15020  BMS_BLKMEM* blkmem;
15021  int d;
15022 
15023  assert( exprgraph != NULL);
15024  assert(*exprgraph != NULL);
15025  assert((*exprgraph)->nvars == 0);
15026  assert((*exprgraph)->nconsts == 0);
15027 
15028  blkmem = (*exprgraph)->blkmem;
15029  assert(blkmem != NULL);
15030 
15031  /* free nodes arrays */
15032  for( d = 0; d < (*exprgraph)->depth; ++d )
15033  {
15034  assert((*exprgraph)->nnodes[d] == 0);
15035  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
15036  }
15037  assert((*exprgraph)->nodes != NULL);
15038  assert((*exprgraph)->nnodes != NULL);
15039  assert((*exprgraph)->nodessize != NULL);
15040  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
15041  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
15042  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
15043 
15044  /* free variables arrays and hashmap */
15045  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
15046  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
15047  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
15048  SCIPhashmapFree(&(*exprgraph)->varidxs);
15049 
15050  /* free constants array */
15051  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
15052 
15053  /* free graph struct */
15054  BMSfreeBlockMemory(blkmem, exprgraph);
15055 
15056  return SCIP_OKAY;
15057 }
15058 
15059 /** adds an expression graph node to an expression graph
15060  *
15061  * Expression graph assumes ownership of node.
15062  * Children are notified about new parent.
15063  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
15064  */
15066  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15067  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
15068  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
15069  int nchildren, /**< number of children */
15070  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
15071  )
15072 {
15073  SCIP_Bool childvalsvalid;
15074  int depth;
15075  int i;
15076 
15077  assert(exprgraph != NULL);
15078  assert(node != NULL);
15079  assert(node->pos < 0); /* node should have no position in graph yet */
15080  assert(node->depth < 0); /* node should have no position in graph yet */
15081  assert(node->nchildren == 0); /* node should not have stored children yet */
15082  assert(node->children == NULL); /* node should not have stored children yet */
15083  assert(node->nparents == 0); /* node should not have parents stored yet */
15084  assert(children != NULL || nchildren == 0);
15085 
15086  /* choose depth as maximal depth of children + 1, and at least mindepth */
15087  depth = MAX(0, mindepth);
15088  for( i = 0; i < nchildren; ++i )
15089  {
15090  if( children[i]->depth >= depth ) /*lint !e613*/
15091  depth = children[i]->depth + 1; /*lint !e613*/
15092  }
15093 
15094  /* ensure that expression graph is deep enough */
15095  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
15096  assert(exprgraph->depth > depth);
15097 
15098  /* ensure enough space for nodes at depth depth */
15099  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
15100 
15101  /* add node to graph */
15102  node->depth = depth;
15103  node->pos = exprgraph->nnodes[depth];
15104  exprgraph->nodes[depth][node->pos] = node;
15105  ++exprgraph->nnodes[depth];
15106 
15107  /* add as parent to children
15108  * and check if children has valid values */
15109  childvalsvalid = TRUE;
15110  for( i = 0; i < nchildren; ++i )
15111  {
15112  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
15113  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
15114  }
15115  /* store children */
15116  if( nchildren > 0 )
15117  {
15118  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
15119  node->nchildren = nchildren;
15120  }
15121 
15122  if( node->op == SCIP_EXPR_CONST )
15123  {
15124  /* set bounds to constant value of node */
15126  SCIPintervalSet(&node->bounds, node->data.dbl);
15127  }
15128  else
15129  {
15130  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
15133  exprgraph->needvarboundprop = TRUE;
15134  }
15135 
15136  /* if not a variable, set value of node according to values of children (if all have valid values) */
15137  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
15138  {
15139  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15140  }
15141 
15142  return SCIP_OKAY;
15143 }
15144 
15145 /** adds variables to an expression graph, if not existing yet
15146  *
15147  * Also already existing nodes are enabled.
15148  */
15150  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15151  int nvars, /**< number of variables to add */
15152  void** vars, /**< variables to add */
15153  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
15154  )
15155 {
15156  SCIP_EXPRGRAPHNODE* node;
15157  SCIP_EXPROPDATA opdata;
15158  int i;
15159 
15160  assert(exprgraph != NULL);
15161  assert(exprgraph->depth >= 1);
15162  assert(vars != NULL || nvars == 0);
15163 
15164  /* if there are no variables yet, then it's quite likely that we will create new nodes for all vars, so can easily estimate how much space we will need in variables array and nodes at depth 0 arrays */
15165  if( exprgraph->nvars == 0 )
15166  {
15167  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15168  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15169  }
15170 
15171  for( i = 0; i < nvars; ++i )
15172  {
15173  /* skip variables that exist already */
15174  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15175  {
15176  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
15177  assert(node != NULL);
15178 
15179  /* enable node */
15180  node->enabled = TRUE;
15181 
15182  if( varnodes != NULL )
15183  varnodes[i] = node;
15184 
15185  continue;
15186  }
15187 
15188  /* create new variable expression */
15189  opdata.intval = exprgraph->nvars;
15190  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15191 
15192  /* add expression node to expression graph at depth 0 */
15193  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15194 
15195  /* add variable node to vars arrays and hashmap */
15196  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15197  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
15198  exprgraph->varnodes[exprgraph->nvars] = node;
15199  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15200  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[i], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15201  ++exprgraph->nvars;
15202 
15203  if( varnodes != NULL )
15204  varnodes[i] = node;
15205 
15206  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15207 
15208  /* call callback method, if set */
15209  if( exprgraph->exprgraphvaradded != NULL )
15210  {
15211  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
15212  }
15213  }
15214 
15215  return SCIP_OKAY;
15216 }
15217 
15218 /** adds a constant to an expression graph, if not existing yet
15219  *
15220  * Also already existing nodes are enabled.
15221  */
15223  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15224  SCIP_Real constant, /**< constant to add */
15225  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
15226  )
15227 {
15228  SCIP_EXPROPDATA opdata;
15229 
15230  assert(exprgraph != NULL);
15231  assert(constnode != NULL);
15232 
15233  /* check if there is already an expression for this constant */
15234  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15235  {
15236  assert(*constnode != NULL);
15237  assert((*constnode)->op == SCIP_EXPR_CONST);
15238  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15239  (*constnode)->enabled = TRUE;
15240  return SCIP_OKAY;
15241  }
15242 
15243  /* create new node for constant */
15244  opdata.dbl = constant;
15245  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15246 
15247  /* add node to expression graph at depth 0 */
15248  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15249  assert((*constnode)->depth == 0);
15250  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
15251 
15252  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15253  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15254  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15255  ++exprgraph->nconsts;
15256  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15257 
15258  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15259 
15260  return SCIP_OKAY;
15261 }
15262 
15263 /** adds sum of expression trees into expression graph
15264  *
15265  * node will also be captured.
15266  *
15267  * @note Parameters will be converted into constants
15268  */
15270  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15271  int nexprtrees, /**< number of expression trees to add */
15272  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
15273  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
15274  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
15275  SCIP_Bool* rootnodeisnew /**< buffer to indicate whether the node in *rootnode has been newly created for this expression tree (otherwise, expression tree was already in graph) */
15276  )
15277 {
15278  SCIP_Bool allone;
15279 
15280  assert(exprgraph != NULL);
15281  assert(nexprtrees > 0);
15282  assert(exprtrees != NULL);
15283  assert(rootnode != NULL);
15284  assert(rootnodeisnew != NULL);
15285 
15286  *rootnode = NULL;
15287 
15288  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15289  {
15290  assert(exprtrees[0] != NULL);
15291  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15292 
15293  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, exprtrees[0]->params, rootnode, rootnodeisnew) );
15294  }
15295  else
15296  {
15297  SCIP_EXPROP op;
15298  SCIP_EXPRGRAPHNODE** rootnodes;
15299  SCIP_Bool rootnodeisnew_;
15300  int i;
15301 
15302  *rootnodeisnew = TRUE;
15303  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15304 
15305  allone = TRUE;
15306  for( i = 0; i < nexprtrees; ++i )
15307  {
15308  assert(exprtrees[i] != NULL);
15309  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15310 
15311  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, exprtrees[i]->params, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
15312  assert(rootnodes[i] != NULL);
15313  *rootnodeisnew &= rootnodeisnew_;
15314 
15315  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
15316  }
15317 
15318  /* decide which operand we want to use for the root node */
15319  if( coefs == NULL || allone )
15320  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15321  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15322  op = SCIP_EXPR_MINUS;
15323  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15324  {
15325  SCIP_EXPRGRAPHNODE* tmp;
15326 
15327  tmp = rootnodes[0];
15328  rootnodes[0] = rootnodes[1];
15329  rootnodes[1] = tmp;
15330  op = SCIP_EXPR_MINUS;
15331  }
15332  else
15333  op = SCIP_EXPR_LINEAR;
15334 
15335  if( op != SCIP_EXPR_LINEAR )
15336  {
15337  SCIP_EXPROPDATA data;
15338  data.data = NULL;
15339 
15340  if( !*rootnodeisnew )
15341  {
15342  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15343  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15344  }
15345 
15346  if( *rootnode == NULL )
15347  {
15348  /* create new node for sum of rootnodes and add to exprgraph */
15349  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15350  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15351  *rootnodeisnew = TRUE;
15352  }
15353  else
15354  {
15355  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15356  *rootnodeisnew = FALSE;
15357  }
15358  }
15359  else
15360  {
15361  SCIP_EXPROPDATA data;
15362  SCIP_Real* lindata;
15363 
15364  assert(op == SCIP_EXPR_LINEAR);
15365 
15366  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15367  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15368  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
15369  lindata[nexprtrees] = 0.0;
15370  data.data = lindata;
15371 
15372  if( !*rootnodeisnew )
15373  {
15374  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15375  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15376  }
15377 
15378  if( *rootnode == NULL )
15379  {
15380  /* create new node for linear combination of rootnodes and add to exprgraph */
15381  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15382  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15383  *rootnodeisnew = TRUE;
15384  }
15385  else
15386  {
15387  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15388  *rootnodeisnew = FALSE;
15389  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15390  }
15391  }
15392 
15393  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15394  }
15395  assert(*rootnode != NULL);
15396 
15397  SCIPexprgraphCaptureNode(*rootnode);
15398 
15399  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15400  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15401 
15402  return SCIP_OKAY;
15403 }
15404 
15405 /** replaces variable in expression graph by a linear sum of variables
15406  *
15407  * Variables will be added if not in the graph yet.
15408  */
15410  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15411  void* var, /**< variable to replace */
15412  int ncoefs, /**< number of coefficients in linear term */
15413  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
15414  void** vars, /**< variables in linear term */
15415  SCIP_Real constant /**< constant offset */
15416  )
15417 {
15418  SCIP_EXPRGRAPHNODE* varnode;
15419  SCIP_Real* lindata;
15420  int varidx;
15421  int i;
15422 
15423  assert(exprgraph != NULL);
15424  assert(var != NULL);
15425  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15426  assert(coefs != NULL || ncoefs == 0);
15427  assert(vars != NULL || ncoefs == 0);
15428 
15429  varidx = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15430  assert(varidx < exprgraph->nvars);
15431  assert(exprgraph->vars[varidx] == var);
15432  varnode = exprgraph->varnodes[varidx];
15433  assert(varnode != NULL);
15434  assert(varnode->data.intval == varidx);
15435 
15436  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
15437  {
15438  /* variable is replaced by constant or variable */
15439  SCIP_EXPRGRAPHNODE* node;
15440 
15441  /* check if there is already a node for this constant or variable */
15442  node = NULL;
15443  if( ncoefs == 0 )
15444  {
15445  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15446  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
15447  }
15448  else
15449  {
15450  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
15451  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
15452  }
15453 
15454  if( node != NULL )
15455  {
15456  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15457 
15458  /* tell parents of varnode to replace child varnode by node, this may free varnode */
15459  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15460 
15461  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15462  if( varnode != NULL )
15463  {
15464  assert(varnode->nuses > 0);
15465  assert(varnode->nparents == 0);
15466 
15467  /* remove variable (but don't free it's node) from graph */
15468  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15469 
15470  /* move varnode up to depth 1 */
15471  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15472 
15473  /* turn into EXPR_SUM expression */
15474  varnode->op = SCIP_EXPR_SUM;
15475  varnode->data.data = NULL;
15476  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
15477  varnode->children[0] = node;
15478  varnode->nchildren = 1;
15479  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15480 
15481  varnode->value = node->value;
15482  varnode->bounds = node->bounds;
15483  varnode->boundstatus = (node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID) ? SCIP_EXPRBOUNDSTATUS_VALID : SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
15484  }
15485  }
15486  else if( ncoefs == 0 )
15487  {
15488  /* turn node into EXPR_CONST node */
15489 
15490  /* remove variable (but don't free it's node) from graph */
15491  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15492 
15493  /* convert into EXPR_CONST node */
15494  varnode->op = SCIP_EXPR_CONST;
15495  varnode->data.dbl = constant;
15496 
15497  varnode->value = constant;
15498  SCIPintervalSet(&varnode->bounds, constant);
15500 
15501  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15502  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15503  exprgraph->constnodes[exprgraph->nconsts] = varnode;
15504  ++exprgraph->nconsts;
15505  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15506  }
15507  else
15508  {
15509  /* turn node into EXPR_VARIDX node for new variable */
15510 
15511  /* remove variable (but don't free it's node) from graph */
15512  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15513 
15514  varnode->data.intval = exprgraph->nvars;
15515 
15516  /* add variable node to vars arrays and hashmap */
15517  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15518  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
15519  exprgraph->varnodes[exprgraph->nvars] = varnode;
15520  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15521  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[0], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15522  ++exprgraph->nvars;
15523 
15524  /* call callback method, if set */
15525  if( exprgraph->exprgraphvaradded != NULL )
15526  {
15527  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
15528  }
15529  }
15530 
15531  /* mark varnode and its parents as not simplified */
15532  if( varnode != NULL )
15533  {
15534  varnode->simplified = FALSE;
15535  for( i = 0; i < varnode->nparents; ++i )
15536  varnode->parents[i]->simplified = FALSE;
15537  }
15538 
15539  return SCIP_OKAY;
15540  }
15541 
15542  /* turn varnode into EXPR_LINEAR */
15543 
15544  /* remove variable (but don't free it's node) from graph */
15545  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15546 
15547  /* move varnode up to depth 1 */
15548  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15549 
15550  /* convert into EXPR_LINEAR node */
15551  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15552  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
15553  lindata[ncoefs] = constant;
15554  varnode->data.data = (void*)lindata;
15555  varnode->op = SCIP_EXPR_LINEAR;
15556 
15557  /* add nodes corresponding to vars to expression graph, if not existing yet */
15558  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15559  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15560  varnode->nchildren = ncoefs;
15561 
15562  /* notify vars about new parent varnode */
15563  for( i = 0; i < ncoefs; ++i )
15564  {
15565  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15566  }
15567 
15568  /* set value and bounds to invalid, curvature can remain (still linear) */
15569  varnode->value = SCIP_INVALID;
15571 
15572  /* mark varnode and its parents as not simplified */
15573  varnode->simplified = FALSE;
15574  for( i = 0; i < varnode->nparents; ++i )
15575  varnode->parents[i]->simplified = FALSE;
15576 
15577  return SCIP_OKAY;
15578 }
15579 
15580 /** finds expression graph node corresponding to a variable */
15582  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15583  void* var, /**< variable to search for */
15584  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15585  )
15586 {
15587  int pos;
15588 
15589  assert(exprgraph != NULL);
15590  assert(var != NULL);
15591  assert(varnode != NULL);
15592 
15593  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15594  {
15595  *varnode = NULL;
15596  return FALSE;
15597  }
15598 
15599  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15600  assert(pos < exprgraph->nvars);
15601 
15602  *varnode = exprgraph->varnodes[pos];
15603  assert(*varnode != NULL);
15604  assert((*varnode)->op == SCIP_EXPR_VARIDX);
15605 
15606  return TRUE;
15607 }
15608 
15609 /** finds expression graph node corresponding to a constant */
15611  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15612  SCIP_Real constant, /**< constant to search for */
15613  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15614  )
15615 {
15616  int left;
15617  int right;
15618  int middle;
15619 
15620  assert(exprgraph != NULL);
15621  assert(constnode != NULL);
15622  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
15623 
15624  exprgraphSortConstNodes(exprgraph);
15625  assert(exprgraph->constssorted);
15626 
15627  /* find node using binary search */
15628  left = 0;
15629  right = exprgraph->nconsts-1;
15630  *constnode = NULL;
15631 
15632  while( left <= right )
15633  {
15634  middle = (left+right)/2;
15635  assert(0 <= middle && middle < exprgraph->nconsts);
15636 
15637  if( constant < exprgraph->constnodes[middle]->data.dbl )
15638  right = middle - 1;
15639  else if( constant > exprgraph->constnodes[middle]->data.dbl )
15640  left = middle + 1;
15641  else
15642  {
15643  *constnode = exprgraph->constnodes[middle];
15644  break;
15645  }
15646  }
15647  if( left == right+1 )
15648  return FALSE;
15649 
15650  assert(*constnode != NULL);
15651  assert((*constnode)->op == SCIP_EXPR_CONST);
15652  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15653 
15654  return TRUE;
15655 }
15656 
15657 /** prints an expression graph in dot format */
15659  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15660  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15661  FILE* file, /**< file to print to, or NULL for stdout */
15662  const char** varnames /**< variable names, or NULL for generic names */
15663  )
15664 {
15665  int d;
15666  int i;
15667 
15668  assert(exprgraph != NULL);
15669 
15670  if( file == NULL )
15671  file = stdout;
15672 
15673  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15674  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15675 
15676  for( d = 0; d < exprgraph->depth; ++d )
15677  {
15678  if( exprgraph->nnodes[d] == 0 )
15679  continue;
15680 
15681  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15682  {
15683  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15684  }
15685  }
15686 
15687  /* tell dot that all nodes of depth 0 have the same rank */
15688  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15689  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15690  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15691  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15692 
15693  /* tell dot that all nodes without parent have the same rank */
15694  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15695  for( d = 0; d < exprgraph->depth; ++d )
15696  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15697  if( exprgraph->nodes[d][i]->nparents == 0 )
15698  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15699  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15700 
15701  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15702 
15703  return SCIP_OKAY;
15704 }
15705 
15706 /** evaluates nodes of expression graph for given values of variables */
15708  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15709  SCIP_Real* varvals /**< values for variables */
15710  )
15711 {
15712  int d;
15713  int i;
15714 
15715  assert(exprgraph != NULL);
15716  assert(varvals != NULL || exprgraph->nvars == 0);
15717 
15718  for( d = 0; d < exprgraph->depth; ++d )
15719  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15720  {
15721  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15722  }
15723 
15724  return SCIP_OKAY;
15725 }
15726 
15727 /** propagates bound changes in variables forward through the expression graph */
15729  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15730  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15731  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
15732  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15733  )
15734 {
15735  SCIP_EXPRGRAPHNODE* node;
15736  SCIP_Bool boundchanged;
15737  int d;
15738  int i;
15739 
15740  assert(exprgraph != NULL);
15741  assert(domainerror != NULL);
15742 
15743  *domainerror = FALSE;
15744 
15745  /* update bounds in varnodes of expression graph */
15746  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15747 
15748  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15749  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15750  {
15751  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15752  return SCIP_OKAY;
15753  }
15754 
15755  /* propagate bound changes, interrupt if we get to a node with empty bounds */
15756  for( d = 1; d < exprgraph->depth; ++d )
15757  {
15758  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15759  {
15760  node = exprgraph->nodes[d][i];
15761  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15762  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15763  {
15764  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15765  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15766  *domainerror = TRUE;
15767  return SCIP_OKAY;
15768  }
15769  }
15770  }
15771 
15772  exprgraph->needvarboundprop = FALSE;
15773 
15774  return SCIP_OKAY;
15775 }
15776 
15777 /** propagates bound changes in nodes backward through the graph
15778  *
15779  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15780  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15781  */
15783  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15784  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15785  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15786  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15787  )
15788 {
15789  SCIP_EXPRGRAPHNODE* node;
15790  int d;
15791  int i;
15792 
15793  assert(exprgraph != NULL);
15794  assert(cutoff != NULL);
15795 
15796  *cutoff = FALSE;
15797 
15798  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15799  {
15800  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15801  {
15802  node = exprgraph->nodes[d][i];
15803  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15804  }
15805  }
15806  if( *cutoff )
15807  return;
15808 }
15809 
15810 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15811  *
15812  * Implies update of bounds in expression graph.
15813  */
15815  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15816  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15817  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15818  )
15819 {
15820  SCIP_EXPRGRAPHNODE* node;
15821  SCIP_Bool boundchanged;
15822  int d;
15823  int i;
15824 
15825  assert(exprgraph != NULL);
15826 
15827  /* update bounds in varnodes of expression graph */
15828  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15829 
15830 #ifndef NDEBUG
15831  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15832  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15833 #endif
15834 
15835  for( d = 1; d < exprgraph->depth; ++d )
15836  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15837  {
15838  node = exprgraph->nodes[d][i];
15839  assert(node != NULL);
15840 
15841  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15842 
15843  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15844  {
15845  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15846  return SCIP_OKAY;
15847  }
15848  }
15849 
15850  return SCIP_OKAY;
15851 }
15852 
15853 /** aims at simplifying an expression graph
15854  *
15855  * A domain error can occur when variables were fixed to values for which a parent expression is not defined (e.g., 0^(-1) or log(-1)).
15856  */
15858  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15859  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15860  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15861  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15862  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15863  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15864  )
15865 {
15866  SCIP_EXPRGRAPHNODE* node;
15867  SCIP_Bool havechangenode;
15868  SCIP_Bool allsimplified;
15869  int d;
15870  int i;
15871  int j;
15872 
15873 #ifndef NDEBUG
15874  SCIP_Real* testx;
15875  SCIP_HASHMAP* testvalidx;
15876  SCIP_Real* testvals;
15877  SCIP_RANDNUMGEN* randnumgen;
15878  int testvalssize;
15879  int ntestvals;
15880 #endif
15881 
15882  assert(exprgraph != NULL);
15883  assert(eps >= 0.0);
15884  assert(havechange != NULL);
15885  assert(domainerror != NULL);
15886 
15887 #ifndef NDEBUG
15888  SCIP_CALL( SCIPrandomCreate(&randnumgen, exprgraph->blkmem, DEFAULT_RANDSEED) );
15889  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
15890  testvals = NULL;
15891  ntestvals = 0;
15892  testvalssize = 0;
15893 
15894  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
15895  for( i = 0; i < exprgraph->nvars; ++i )
15896  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
15897  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
15898  for( d = 1; d < exprgraph->depth; ++d )
15899  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15900  {
15901  node = exprgraph->nodes[d][i];
15902  assert(node != NULL);
15903 
15904  /* nodes that are in use should not be removed by simplifier, so for those we store their value and check if it remains the same after simplifier was run */
15905  if( node->nuses > 0 )
15906  {
15907  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
15908  SCIP_CALL( SCIPhashmapInsert(testvalidx, (void*)node, (void*)(size_t)ntestvals) );
15909  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
15910  ++ntestvals;
15911  }
15912  }
15913 
15914  SCIPrandomFree(&randnumgen);
15915 #endif
15916 
15917 #ifdef SCIP_OUTPUT
15918  {
15919  FILE* file;
15920  file = fopen("exprgraph_beforesimplify.dot", "w");
15921  if( file != NULL )
15922  {
15923  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
15924  fclose(file);
15925  }
15926  }
15927 #endif
15928 
15929  *havechange = FALSE; /* we have not changed any node yet */
15930  *domainerror = FALSE; /* no domain errors encountered so far */
15931  allsimplified = TRUE; /* all nodes we looked at are simplified */
15932 
15933  /* call node simplifier from bottom up
15934  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
15935  */
15936  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
15937  {
15938  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15939  {
15940  node = exprgraph->nodes[d][i];
15941  assert(node != NULL);
15942 
15943  havechangenode = FALSE; /* node did not change yet */
15944 
15945  if( node->op != SCIP_EXPR_CONST )
15946  {
15947  /* skip nodes that are already simplified */
15948  if( node->simplified )
15949  continue;
15950 
15951  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
15952 
15953  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
15954  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
15955  assert(node->simplified == TRUE);
15956  *havechange |= havechangenode;
15957  }
15958 
15959  /* if node was or has been converted into constant, may move to depth 0 */
15960  if( node->op == SCIP_EXPR_CONST )
15961  {
15962  SCIP_EXPRGRAPHNODE* constnode;
15963 
15964  if( !SCIPisFinite(node->value) ) /*lint !e777*/
15965  {
15966  SCIPdebugMessage("Expression graph simplify turned node into NaN or inf.\n");
15967  *domainerror = TRUE;
15968  break;
15969  }
15970 
15971  /* check if there is already a node for this constant */
15972  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
15973  {
15974  assert(constnode->op == SCIP_EXPR_CONST);
15975  assert(constnode->data.dbl == node->value); /*lint !e777*/
15976 
15977  if( node->nparents > 0 )
15978  {
15979  /* move parents of this node to constnode, node may be freed if not in use */
15980  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
15981  /* node should have no parents anymore, so it should have been freed if not in use */
15982  assert(node == NULL || node->nuses > 0);
15983  havechangenode = TRUE;
15984 
15985  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
15986  if( node == NULL )
15987  {
15988  --i;
15989  continue;
15990  }
15991  }
15992  assert(node != NULL);
15993  assert(node->nuses > 0);
15994 
15995  if( constnode->nuses == 0 )
15996  {
15997  /* move node to depth 0, adding it to constnodes */
15998  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
15999 
16000  /* move parents of constnode to node, so constnode is freed */
16001  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
16002  assert(constnode == NULL);
16003  havechangenode = TRUE;
16004 
16005  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16006  --i;
16007  continue;
16008  }
16009  }
16010  else
16011  {
16012  /* move to depth 0, adding it to constnodes */
16013  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16014 
16015  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16016  --i;
16017  }
16018  }
16019 
16020  /* if there was a change, mark parents as not simplified */
16021  if( havechangenode )
16022  for( j = 0; j < node->nparents; ++j )
16023  node->parents[j]->simplified = FALSE;
16024  }
16025  } /*lint !e850*/
16026 
16027  /* if we did nothing, clean up and escape from here */
16028  if( allsimplified || *domainerror )
16029  goto EXPRGRAPHSIMPLIFY_CLEANUP;
16030 
16031  /* @todo find duplicate subexpressions in expression graph */
16032 
16033  /* unconvert polynomials into simpler expressions, where possible */
16034  for( d = 1; d < exprgraph->depth; ++d )
16035  {
16036  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16037  {
16038  node = exprgraph->nodes[d][i];
16039  assert(node != NULL);
16040 
16041  if( node->op != SCIP_EXPR_POLYNOMIAL )
16042  continue;
16043 
16044  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
16045 
16046  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
16047  {
16048  /* node is identity w.r.t only child
16049  * replace node as child of parents by child of node
16050  */
16051 
16052  for( j = 0; node != NULL && j < node->nparents; ++j )
16053  {
16054  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
16055  }
16056  /* node should have no parents anymore, so it should have been freed if not in use */
16057  assert(node == NULL || node->nuses > 0);
16058 
16059  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
16060  if( node == NULL )
16061  --i;
16062  }
16063  }
16064  } /*lint !e850*/
16065 
16066 #ifdef SCIP_OUTPUT
16067  {
16068  FILE* file;
16069  file = fopen("exprgraph_aftersimplify.dot", "w");
16070  if( file != NULL )
16071  {
16072  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16073  fclose(file);
16074  }
16075  }
16076 #endif
16077 
16078 #ifndef NDEBUG
16079  for( d = 1; d < exprgraph->depth; ++d )
16080  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16081  {
16082  int idx;
16083  SCIP_Real testval_before;
16084  SCIP_Real testval_after;
16085 
16086  node = exprgraph->nodes[d][i];
16087  assert(node != NULL);
16088 
16089  SCIP_CALL( exprgraphNodeEval(node, NULL) );
16090 
16091  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
16092  if( node->nuses > 0 )
16093  {
16094  assert(SCIPhashmapExists(testvalidx, (void*)node));
16095 
16096  idx = (int)(size_t)(void*)SCIPhashmapGetImage(testvalidx, (void*)node);
16097  assert(idx < ntestvals);
16098 
16099  testval_before = testvals[idx]; /*lint !e613*/
16100  testval_after = SCIPexprgraphGetNodeVal(node);
16101 
16102  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
16103  }
16104  }
16105 #endif
16106 
16107  EXPRGRAPHSIMPLIFY_CLEANUP:
16108 #ifndef NDEBUG
16109  BMSfreeMemoryArray(&testx);
16110  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
16111  SCIPhashmapFree(&testvalidx);
16112 #endif
16113 
16114  return SCIP_OKAY;
16115 }
16116 
16117 /** creates an expression tree from a given node in an expression graph */
16119  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16120  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
16121  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
16122  )
16123 {
16124  SCIP_EXPR* root;
16125  int nexprvars;
16126  int* varidx;
16127  int i;
16128 
16129  assert(exprgraph != NULL);
16130  assert(rootnode != NULL);
16131  assert(rootnode->depth >= 0);
16132  assert(rootnode->pos >= 0);
16133  assert(exprtree != NULL);
16134 
16135  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16136  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16137 
16138  /* initially, no variable appears in the expression tree */
16139  for( i = 0; i < exprgraph->nvars; ++i )
16140  varidx[i] = -1; /*lint !e644*/
16141  nexprvars = 0;
16142 
16143  /* create expression from the subgraph that has rootnode as root */
16144  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
16145 
16146  /* create expression tree for this expression */
16147  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
16148 
16149  /* copy variables into expression tree */
16150  if( nexprvars > 0 )
16151  {
16152  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
16153  for( i = 0; i < exprgraph->nvars; ++i )
16154  {
16155  assert(varidx[i] >= -1);
16156  assert(varidx[i] < nexprvars);
16157  if( varidx[i] >= 0 )
16158  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
16159  }
16160  }
16161 
16162  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16163 
16164  return SCIP_OKAY;
16165 }
16166 
16167 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16168  *
16169  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16170  */
16172  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16173  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16174  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16175  int* nexprtrees, /**< buffer to store number of expression trees */
16176  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16177  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16178  )
16179 {
16180  int ncomponents;
16181  int* childcomp;
16182  int* varcomp;
16183  int compnr;
16184  SCIP_Bool haveoverlap;
16185  int i;
16186  int j;
16187  int k;
16188 
16189  SCIP_EXPR** exprs;
16190  int nexprs;
16191  int* childmap;
16192  int* childmapinv;
16193  int* varidx;
16194  int nexprvars;
16195 
16196  assert(exprgraph != NULL);
16197  assert(node != NULL);
16198  assert(node->depth >= 0);
16199  assert(node->pos >= 0);
16200  assert(exprtreessize > 0);
16201  assert(nexprtrees != NULL);
16202  assert(exprtrees != NULL);
16203  assert(exprtreecoefs != NULL);
16204 
16205  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16206  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16207  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16208  ( node->op != SCIP_EXPR_PLUS &&
16209  node->op != SCIP_EXPR_MINUS &&
16210  node->op != SCIP_EXPR_SUM &&
16211  node->op != SCIP_EXPR_LINEAR &&
16212  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16213  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16214  {
16215  *nexprtrees = 1;
16216  exprtreecoefs[0] = 1.0;
16217  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16218 
16219  return SCIP_OKAY;
16220  }
16221 
16222  /* find components in node->children <-> variables graph */
16223  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16224  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16225  for( i = 0; i < exprgraph->nvars; ++i )
16226  varcomp[i] = -1; /*lint !e644*/
16227 
16228  haveoverlap = FALSE;
16229  for( i = 0; i < node->nchildren; ++i )
16230  {
16231  compnr = i;
16232  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
16233  assert(compnr >= 0);
16234  assert(compnr < node->nchildren);
16235  childcomp[i] = compnr;
16236 
16237  /* remember if component number was changed by CheckComponent */
16238  if( compnr != i )
16239  haveoverlap = TRUE;
16240  }
16241 
16242  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16243 
16244  if( node->op == SCIP_EXPR_QUADRATIC )
16245  {
16246  /* merge components for products of children from different components */
16248 
16249  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16250  assert(data != NULL);
16251 
16252  for( i = 0; i < data->nquadelems; ++i )
16253  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16254  {
16255  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16256  compnr = childcomp[data->quadelems[i].idx2];
16257  for( j = 0; j < node->nchildren; ++j )
16258  if( childcomp[j] == compnr )
16259  childcomp[j] = childcomp[data->quadelems[i].idx1];
16260  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16261  haveoverlap = TRUE;
16262  }
16263  }
16264  else if( node->op == SCIP_EXPR_POLYNOMIAL )
16265  {
16266  /* merge components for monomials of children from different components */
16268 
16269  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16270  assert(data != NULL);
16271 
16272  for( i = 0; i < data->nmonomials; ++i )
16273  for( j = 1; j < data->monomials[i]->nfactors; ++j )
16274  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16275  {
16276  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16277  compnr = childcomp[data->monomials[i]->childidxs[j]];
16278  for( k = 0; k < node->nchildren; ++k )
16279  if( childcomp[k] == compnr )
16280  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16281  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16282  haveoverlap = TRUE;
16283  }
16284  }
16285 
16286  if( haveoverlap )
16287  {
16288  /* some component numbers are unused, thus relabel and count final number of components */
16289  int* compmap;
16290 
16291  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16292  for( i = 0; i < node->nchildren; ++i )
16293  compmap[i] = -1; /*lint !e644*/
16294 
16295  ncomponents = 0;
16296  for( i = 0; i < node->nchildren; ++i )
16297  {
16298  if( compmap[childcomp[i]] == -1 )
16299  compmap[childcomp[i]] = ncomponents++;
16300  childcomp[i] = compmap[childcomp[i]];
16301  }
16302 
16303  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16304  }
16305  else
16306  {
16307  ncomponents = node->nchildren;
16308  }
16309 
16310  if( ncomponents == 1 )
16311  {
16312  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16313  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16314 
16315  *nexprtrees = 1;
16316  exprtreecoefs[0] = 1.0;
16317  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16318 
16319  return SCIP_OKAY;
16320  }
16321 
16322  if( ncomponents > exprtreessize )
16323  {
16324  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16325  for( i = 0; i < node->nchildren; ++i )
16326  if( childcomp[i] >= exprtreessize )
16327  childcomp[i] = exprtreessize-1;
16328  ncomponents = exprtreessize;
16329  }
16330 
16331  assert(ncomponents >= 2);
16332 
16333  /* setup expression trees for each component */
16334  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16335  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16336  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16337  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16338  for( i = 0; i < ncomponents; ++i )
16339  {
16340  /* initially, no variable appears in the expression tree */
16341  for( j = 0; j < exprgraph->nvars; ++j )
16342  varidx[j] = -1; /*lint !e644*/
16343  nexprvars = 0;
16344 
16345  /* collect expressions from children belonging to component i */
16346  nexprs = 0;
16347  for( j = 0; j < node->nchildren; ++j )
16348  {
16349  assert(childcomp[j] >= 0);
16350  assert(childcomp[j] < ncomponents);
16351  if( childcomp[j] != i )
16352  continue;
16353 
16354  /* create expression from the subgraph that has child j as root */
16355  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
16356  childmap[j] = nexprs; /*lint !e644*/
16357  childmapinv[nexprs] = j; /*lint !e644*/
16358  ++nexprs;
16359  }
16360 
16361  /* setup expression tree for component i */
16362  switch( node->op )
16363  {
16364  case SCIP_EXPR_PLUS:
16365  {
16366  assert(ncomponents == 2);
16367  assert(nexprs == 1);
16368 
16369  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16370  exprtreecoefs[i] = 1.0;
16371 
16372  break;
16373  }
16374 
16375  case SCIP_EXPR_MINUS:
16376  {
16377  assert(ncomponents == 2);
16378  assert(nexprs == 1);
16379 
16380  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16381  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16382  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16383  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16384 
16385  break;
16386  }
16387 
16388  case SCIP_EXPR_SUM:
16389  {
16390  if( nexprs == 1 )
16391  {
16392  /* component corresponds to exactly one child of node */
16393  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16394  }
16395  else
16396  {
16397  /* component corresponds to a sum of children of node */
16398  SCIP_EXPR* sumexpr;
16399 
16400  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16401  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16402  }
16403  exprtreecoefs[i] = 1.0;
16404 
16405  break;
16406  }
16407 
16408  case SCIP_EXPR_LINEAR:
16409  {
16410  SCIP_Real* nodecoefs;
16411  SCIP_EXPR* sumexpr;
16412 
16413  nodecoefs = (SCIP_Real*)node->data.data;
16414 
16415  /* if there is a constant, then we put it into the expression of the first component */
16416  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16417  {
16418  /* component corresponds to exactly one child of node */
16419  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16420  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16421  }
16422  else if( nexprs == 1 )
16423  {
16424  /* component corresponds to a sum of one child and a constant */
16425  assert(i == 0);
16426  assert(nodecoefs[node->nchildren] != 0.0);
16427  assert(nodecoefs[childmapinv[0]] != 0.0);
16428  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16429  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16430  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16431  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16432  }
16433  else
16434  {
16435  /* component corresponds to a linear combination of children of node */
16436 
16437  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16438  {
16439  /* if two expressions with equal sign, then create PLUS expression */
16440  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16441  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16442  }
16443  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16444  {
16445  /* if two expressions with opposite sign, then create MINUS expression */
16446  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16447  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16448  }
16449  else
16450  {
16451  /* assemble coefficents and create SUM or LINEAR expression */
16452  SCIP_Real* coefs;
16453  SCIP_Bool allcoefsequal;
16454 
16455  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16456  allcoefsequal = TRUE;
16457  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
16458  for( j = 0; j < nexprs; ++j )
16459  {
16460  coefs[j] = nodecoefs[childmapinv[j]];
16461  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
16462  }
16463 
16464  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16465  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16466  {
16467  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16468  exprtreecoefs[i] = coefs[0];
16469  }
16470  else
16471  {
16472  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16473  exprtreecoefs[i] = 1.0;
16474  }
16475 
16476  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16477  }
16478 
16479  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16480  }
16481 
16482  break;
16483  }
16484 
16485  case SCIP_EXPR_QUADRATIC:
16486  {
16487  SCIP_EXPR* quadexpr;
16489  SCIP_Real* lincoefs;
16490  SCIP_QUADELEM* quadelems;
16491  int nquadelems;
16492 
16493  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16494 
16495  exprtreecoefs[i] = 1.0;
16496 
16497  /* assemble coefficients corresponding to component i */
16498  if( nodedata->lincoefs != NULL )
16499  {
16500  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16501  for( j = 0; j < nexprs; ++j )
16502  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
16503  }
16504  else
16505  lincoefs = NULL;
16506 
16507  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16508  nquadelems = 0;
16509  for( j = 0; j < nodedata->nquadelems; ++j )
16510  {
16511  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16512  if( childcomp[nodedata->quadelems[j].idx1] != i )
16513  continue;
16514  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
16515  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16516  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16517  ++nquadelems;
16518  }
16519 
16520  /* put constant into first component */
16521  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16522  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16523 
16524  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16525  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16526 
16527  break;
16528  }
16529 
16530  case SCIP_EXPR_POLYNOMIAL:
16531  {
16532  SCIP_EXPR* polyexpr;
16534  SCIP_EXPRDATA_MONOMIAL** monomials;
16535  SCIP_Real constant;
16536  int nmonomials;
16537 
16538  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16539 
16540  constant = nodedata->constant;
16541  exprtreecoefs[i] = 1.0;
16542 
16543  /* collect monomials belonging to component i */
16544  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16545  nmonomials = 0;
16546  for( j = 0; j < nodedata->nmonomials; ++j )
16547  {
16548  if( nodedata->monomials[j]->nfactors == 0 )
16549  {
16550  constant += nodedata->monomials[j]->coef;
16551  continue;
16552  }
16553  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16554  continue;
16555 
16556  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16557  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
16558  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16559  {
16560  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16561  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16562  }
16563  ++nmonomials;
16564  }
16565 
16566  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16567  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16568 
16569  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16570 
16571  break;
16572  }
16573 
16574  default:
16575  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16576  return SCIP_ERROR;
16577  } /*lint !e788*/
16578 
16579  /* copy variables into expression tree */
16580  if( nexprvars > 0 )
16581  {
16582  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16583  for( j = 0; j < exprgraph->nvars; ++j )
16584  {
16585  assert(varidx[j] >= -1);
16586  assert(varidx[j] < nexprvars);
16587  if( varidx[j] >= 0 )
16588  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16589  }
16590  }
16591  }
16592 
16593  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16594  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16595  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16596  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16597  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16598 
16599  *nexprtrees = ncomponents;
16600 
16601  return SCIP_OKAY;
16602 }
16603 
16604 /** returns how often expression graph variables are used in a subtree of the expression graph */
16606  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16607  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
16608  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16609  )
16610 {
16611  assert(exprgraph != NULL);
16612  assert(node != NULL);
16613  assert(varsusage != NULL);
16614 
16615  BMSclearMemoryArray(varsusage, exprgraph->nvars);
16616 
16617  exprgraphNodeGetVarsUsage(node, varsusage);
16618 }
16619 
16620 /** gives the number of summands which the expression of an expression graph node consists of */
16622  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
16623  )
16624 {
16625  switch( node->op )
16626  {
16627  case SCIP_EXPR_PLUS:
16628  case SCIP_EXPR_MINUS:
16629  return 2;
16630 
16631  case SCIP_EXPR_SUM:
16632  case SCIP_EXPR_LINEAR:
16633  return node->nchildren;
16634 
16635  case SCIP_EXPR_QUADRATIC:
16636  {
16638 
16639  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16640  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16641  }
16642 
16643  case SCIP_EXPR_POLYNOMIAL:
16644  {
16646 
16647  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16648  return nodedata->nmonomials;
16649  }
16650 
16651  default:
16652  return 1;
16653  } /*lint !e788*/
16654 }
16655 
16656 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
16658  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16659  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16660  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16661  int* nexprtrees, /**< buffer to store number of expression trees */
16662  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16663  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16664  )
16665 {
16666  int* varidx;
16667  int nexprvars;
16668  int i;
16669 
16670  assert(exprgraph != NULL);
16671  assert(node != NULL);
16672  assert(node->depth >= 0);
16673  assert(node->pos >= 0);
16674  assert(exprtreessize > 0);
16675  assert(nexprtrees != NULL);
16676  assert(exprtrees != NULL);
16677  assert(exprtreecoefs != NULL);
16678 
16679  /* if node is not separable, fallback to SCIPexprgraphGetTree */
16680  if( node->op != SCIP_EXPR_PLUS &&
16681  node->op != SCIP_EXPR_MINUS &&
16682  node->op != SCIP_EXPR_SUM &&
16683  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16684  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16685  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16686  {
16687  *nexprtrees = 1;
16688  exprtreecoefs[0] = 1.0;
16689  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16690 
16691  return SCIP_OKAY;
16692  }
16693 
16694  switch( node->op )
16695  {
16696  case SCIP_EXPR_PLUS:
16697  {
16698  assert(exprtreessize >= 2);
16699 
16700  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16701  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16702 
16703  exprtreecoefs[0] = 1.0;
16704  exprtreecoefs[1] = 1.0;
16705 
16706  *nexprtrees = 2;
16707  break;
16708  }
16709 
16710  case SCIP_EXPR_MINUS:
16711  {
16712  assert(exprtreessize >= 2);
16713 
16714  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16715  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16716 
16717  exprtreecoefs[0] = 1.0;
16718  exprtreecoefs[1] = -1.0;
16719 
16720  *nexprtrees = 2;
16721  break;
16722  }
16723 
16724  case SCIP_EXPR_SUM:
16725  {
16726  assert(exprtreessize >= node->nchildren);
16727 
16728  for( i = 0; i < node->nchildren; ++i )
16729  {
16730  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16731  exprtreecoefs[i] = 1.0;
16732  }
16733 
16734  *nexprtrees = node->nchildren;
16735  break;
16736  }
16737 
16738  case SCIP_EXPR_LINEAR:
16739  {
16740  SCIP_Real* nodecoefs;
16741 
16742  assert(exprtreessize >= node->nchildren);
16743  assert(node->nchildren > 0);
16744 
16745  nodecoefs = (SCIP_Real*)node->data.data;
16746  assert(nodecoefs != NULL);
16747 
16748  for( i = 0; i < node->nchildren; ++i )
16749  {
16750  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16751  exprtreecoefs[i] = nodecoefs[i];
16752  }
16753 
16754  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16755  if( nodecoefs[node->nchildren] != 0.0 )
16756  {
16757  SCIP_EXPR* constexpr_;
16758 
16759  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16760  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16761  }
16762 
16763  *nexprtrees = node->nchildren;
16764  break;
16765  }
16766 
16767  case SCIP_EXPR_QUADRATIC:
16768  {
16770  SCIP_Real* lincoefs;
16771  SCIP_QUADELEM* quadelems;
16772  int nquadelems;
16773  SCIP_EXPR* expr;
16774  int j;
16775 
16776  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16777  lincoefs = nodedata->lincoefs;
16778  quadelems = nodedata->quadelems;
16779  nquadelems = nodedata->nquadelems;
16780 
16781  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16782  assert(node->nchildren > 0);
16783 
16784  *nexprtrees = 0;
16785  if( lincoefs != NULL )
16786  {
16787  for( i = 0; i < node->nchildren; ++i )
16788  {
16789  if( lincoefs[i] == 0.0 )
16790  continue;
16791  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16792  exprtreecoefs[*nexprtrees] = lincoefs[i];
16793  ++*nexprtrees;
16794  }
16795  }
16796 
16797  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16798  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16799 
16800  for( i = 0; i < nquadelems; ++i )
16801  {
16802  /* initially, no variable appears in the expression tree */
16803  for( j = 0; j < exprgraph->nvars; ++j )
16804  varidx[j] = -1; /*lint !e644*/
16805  nexprvars = 0;
16806 
16807  /* create expression from the subgraph at quadelems[i].idx1 */
16808  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16809 
16810  if( quadelems[i].idx1 == quadelems[i].idx2 )
16811  {
16812  /* create expression for square of expr */
16813  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16814  }
16815  else
16816  {
16817  SCIP_EXPR* expr2;
16818 
16819  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16820  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16821  /* create expression for product */
16822  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16823  }
16824 
16825  /* create expression tree for expr */
16826  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16827 
16828  /* copy variables into expression tree */
16829  if( nexprvars > 0 )
16830  {
16831  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16832  for( j = 0; j < exprgraph->nvars; ++j )
16833  {
16834  assert(varidx[j] >= -1);
16835  assert(varidx[j] < nexprvars);
16836  if( varidx[j] >= 0 )
16837  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16838  }
16839  }
16840 
16841  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16842 
16843  ++*nexprtrees;
16844  }
16845 
16846  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16847  if( nodedata->constant != 0.0 )
16848  {
16849  SCIP_EXPR* constexpr_;
16850 
16851  assert(*nexprtrees > 0);
16852  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16853  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16854  }
16855 
16856  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16857 
16858  break;
16859  }
16860 
16861  case SCIP_EXPR_POLYNOMIAL:
16862  {
16864  SCIP_EXPRDATA_MONOMIAL** monomials;
16865  SCIP_Real constant;
16866  int nmonomials;
16867  SCIP_EXPR* expr;
16868  int* childidxs;
16869  int j;
16870 
16871  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16872  monomials = nodedata->monomials;
16873  nmonomials = nodedata->nmonomials;
16874  constant = nodedata->constant;
16875 
16876  assert(exprtreessize >= nmonomials);
16877  assert(node->nchildren > 0);
16878 
16879  *nexprtrees = 0;
16880 
16881  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16882  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16883 
16884  for( i = 0; i < nmonomials; ++i )
16885  {
16886  /* initially, no variable appears in the expression tree */
16887  for( j = 0; j < exprgraph->nvars; ++j )
16888  varidx[j] = -1;
16889  nexprvars = 0;
16890 
16891  if( monomials[i]->nfactors == 1 )
16892  {
16893  /* create expression from the subgraph at only factor */
16894  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16895 
16896  /* put exponent in, if not 1.0 */
16897  if( monomials[i]->exponents[0] == 1.0 )
16898  ;
16899  else if( monomials[i]->exponents[0] == 2.0 )
16900  {
16901  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16902  }
16903  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
16904  {
16905  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
16906  }
16907  else
16908  {
16909  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
16910  }
16911  }
16912  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
16913  {
16914  SCIP_EXPR* expr2;
16915 
16916  /* create expressions for both factors */
16917  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16918  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
16919 
16920  /* create expression for product of factors */
16921  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16922  }
16923  else
16924  {
16925  SCIP_EXPRDATA_MONOMIAL* monomial;
16926  SCIP_EXPR** exprs;
16927  int f;
16928 
16929  /* create expression for each factor, assemble varidx and nexprvars
16930  * create child indices (= identity) */
16931  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
16932  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
16933  for( f = 0; f < monomials[i]->nfactors; ++f )
16934  {
16935  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
16936  childidxs[f] = f; /*lint !e644*/
16937  }
16938 
16939  /* create monomial and polynomial expression for this monomial
16940  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
16941  */
16942  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
16943  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
16944  constant = 0.0;
16945 
16946  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
16947  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
16948  }
16949 
16950  /* create expression tree for expr */
16951  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16952 
16953  /* copy variables into expression tree */
16954  if( nexprvars > 0 )
16955  {
16956  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16957  for( j = 0; j < exprgraph->nvars; ++j )
16958  {
16959  assert(varidx[j] >= -1);
16960  assert(varidx[j] < nexprvars);
16961  if( varidx[j] >= 0 )
16962  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16963  }
16964  }
16965 
16966  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
16967 
16968  ++*nexprtrees;
16969  }
16970 
16971  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
16972  if( constant != 0.0 )
16973  {
16974  SCIP_EXPR* constexpr_;
16975 
16976  assert(*nexprtrees > 0);
16977  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
16978  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16979  }
16980 
16981  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16982 
16983  break;
16984  }
16985 
16986  default:
16987  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16988  return SCIP_ERROR;
16989  } /*lint !e788*/
16990 
16991  return SCIP_OKAY;
16992 }
16993 
16994 /**@} */
void SCIPintervalSignPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
static SCIP_RETCODE exprparseReadVariable(BMS_BLKMEM *blkmem, const char **str, SCIP_EXPR **expr, int *nvars, int **varnames, SCIP_HASHTABLE *vartable, SCIP_Real coefficient, const char *varnameendptr)
Definition: expr.c:4908
#define SCIP_EXPRBOUNDSTATUS_CHILDRELAXED
Definition: type_expr.h:211
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13228
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15728
void SCIPexprFreeDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6142
void SCIPexprtreeGetVarsUsage(SCIP_EXPRTREE *tree, int *varsusage)
Definition: expr.c:8838
SCIP_RETCODE SCIPrandomCreate(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem, unsigned int initialseed)
Definition: misc.c:8693
void SCIPquadelemSort(SCIP_QUADELEM *quadelems, int nquadelems)
Definition: expr.c:9124
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15409
void SCIPexprSortMonomials(SCIP_EXPR *expr)
Definition: expr.c:6982
void SCIPintervalSubScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define exprcurvSin
Definition: expr.c:2061
#define QUADELEMS_SWAP(x, y)
Definition: expr.c:9005
void SCIPintervalMax(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:422
SCIP_EXPROPDATA data
Definition: struct_expr.h:51
static void exprgraphSortConstNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:9564
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14865
static SCIP_RETCODE exprgraphNodeAddParent(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9257
SCIP_RETCODE SCIPexprSubstituteVars(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR **substexprs)
Definition: expr.c:8080
static SCIP_RETCODE exprsimplifyConvertToPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4249
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:15065
void SCIPintervalSign(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define QUADELEMS_ISBETTER(a, b)
Definition: expr.c:9002
static SCIP_RETCODE eval(SCIP_EXPR *expr, const vector< Type > &x, SCIP_Real *param, Type &val)
static SCIP_RETCODE exprsimplifyRemoveDuplicatePolynomialChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps)
Definition: expr.c:4273
SCIP_RETCODE SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16657
SCIP_RETCODE SCIPexprtreeEvalInt(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_INTERVAL *val)
Definition: expr.c:8670
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:15149
methods to interpret (evaluate) an expression tree "fast"
void SCIPexprtreePrint(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, const char **paramnames)
Definition: expr.c:8687
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5881
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:14655
static SCIP_RETCODE polynomialdataMultiplyByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:939
static SCIP_RETCODE exprUnconvertPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren, void **children)
Definition: expr.c:3745
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2254
SCIP_Bool constssorted
Definition: struct_expr.h:174
static SCIP_RETCODE exprgraphNodeAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nexprs, SCIP_EXPRGRAPHNODE **exprs, int *childmap)
Definition: expr.c:9394
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12866
static SCIP_RETCODE exprgraphNodeCreateExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPR **expr, int *nexprvars, int *varidx)
Definition: expr.c:11696
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5654
#define infinity
Definition: gastrans.c:71
struct SCIP_UserExprData SCIP_USEREXPRDATA
Definition: type_expr.h:219
void SCIPexprPrint(SCIP_EXPR *expr, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, const char **paramnames, SCIP_Real *paramvals)
Definition: expr.c:8160
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14835
static SCIP_RETCODE exprgraphEnsureDepth(SCIP_EXPRGRAPH *exprgraph, int mindepth)
Definition: expr.c:11963
void SCIPsortPtrPtrRealInt(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_MAXSTRLEN
Definition: def.h:215
static void polynomialdataSortMonomials(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata)
Definition: expr.c:784
static SCIP_RETCODE exprgraphNodeSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange)
Definition: expr.c:11370
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_VARTYPE_INTEGER_CHAR
Definition: def.h:107
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
SCIP_Real * exponents
Definition: struct_expr.h:95
#define SCIP_DECL_USEREXPREVAL(x)
Definition: type_expr.h:246
#define SCIP_DECL_USEREXPRPRINT(x)
Definition: type_expr.h:308
int SCIPexprgraphGetDepth(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14805
static SCIP_RETCODE polynomialdataMultiplyByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *factordata, int *childmap)
Definition: expr.c:983
static SCIP_RETCODE exprparseFindSeparatingComma(const char *str, const char **endptr, int length)
Definition: expr.c:5040
static SCIP_RETCODE exprgraphNodeRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11301
const char * SCIPexpropGetName(SCIP_EXPROP op)
Definition: expr.c:3247
void SCIPexprChgPolynomialConstant(SCIP_EXPR *expr, SCIP_Real constant)
Definition: expr.c:6648
SCIP_RETCODE SCIPexprgraphAddConst(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15222
SCIP_RETCODE SCIPexprtreeGetMaxDegree(SCIP_EXPRTREE *tree, int *maxdegree)
Definition: expr.c:8641
SCIP_Real * SCIPexprtreeGetParamVals(SCIP_EXPRTREE *tree)
Definition: expr.c:8563
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:14909
SCIP_RETCODE SCIPexprCreateMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial, SCIP_Real coef, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:6994
void SCIPexprgraphCaptureNode(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12844
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:13357
static SCIP_DECL_EXPRFREEDATA(exprFreeDataLinear)
Definition: expr.c:2524
SCIP_Real SCIPexprGetRealPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5717
SCIP_EXPROP op
Definition: struct_expr.h:48
int SCIPexprGetOpIndex(SCIP_EXPR *expr)
Definition: expr.c:5684
data definitions for expressions and expression trees
SCIP_RETCODE SCIPexprSimplify(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR *expr, SCIP_Real eps, int maxexpansionexponent, int nvars, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:7754
SCIP_RETCODE SCIPexprPolynomialPower(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int exponent)
Definition: expr.c:6744
void SCIPexprChgMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real newcoef)
Definition: expr.c:6810
SCIP_Bool SCIPexprHasParam(SCIP_EXPR *expr)
Definition: expr.c:7172
SCIPInterval cos(const SCIPInterval &x)
SCIP_Real SCIPexprGetPolynomialConstant(SCIP_EXPR *expr)
Definition: expr.c:5849
SCIP_EXPRBOUNDSTATUS boundstatus
Definition: struct_expr.h:138
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
void SCIPexprgraphPropagateNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:15782
#define FALSE
Definition: def.h:64
void SCIPintervalMul(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2765
#define EPSEQ(x, y, eps)
Definition: def.h:160
#define EPSISINT(x, eps)
Definition: def.h:172
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT
Definition: type_expr.h:212
SCIP_Bool SCIPexprAreEqual(SCIP_EXPR *expr1, SCIP_EXPR *expr2, SCIP_Real eps)
Definition: expr.c:7539
void SCIPexprMonomialPower(SCIP_EXPRDATA_MONOMIAL *monomial, int exponent)
Definition: expr.c:6885
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14855
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:9618
static void exprgraphNodeCheckSeparabilityComponent(SCIP_EXPRGRAPHNODE *node, int *compnr, int nchildcomps, int *childcomps, int nvars, int *varcomps)
Definition: expr.c:11903
static SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11243
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12995
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static int calcGrowSize(int num)
Definition: expr.c:106
static SCIP_RETCODE exprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op, int nchildren, SCIP_EXPR **children, SCIP_EXPROPDATA opdata)
Definition: expr.c:3276
static SCIP_RETCODE exprParse(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR **expr, const char *str, int length, const char *lastchar, int *nvars, int **varnames, SCIP_HASHTABLE *vartable, int recursiondepth)
Definition: expr.c:5072
void SCIPsortPtrPtrInt(void **ptrarray1, void **ptrarray2, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPexprtreeCopy(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **targettree, SCIP_EXPRTREE *sourcetree)
Definition: expr.c:8743
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12886
void SCIPexprGetVarsUsage(SCIP_EXPR *expr, int *varsusage)
Definition: expr.c:7516
void SCIPintervalMin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_INTERVAL SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13218
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15707
void SCIPexprReindexVars(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8118
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
#define SCIP_DECL_USEREXPRINTEVAL(x)
Definition: type_expr.h:259
void SCIPintervalPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int * SCIPexprgraphGetNNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14815
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:78
SCIP_RETCODE SCIPexprEvalInt(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7886
#define EPSGE(x, y, eps)
Definition: def.h:164
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:9380
void SCIPexprSortMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:7075
static void polynomialdataApplyChildmap(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int *childmap)
Definition: expr.c:1142
#define SCIPdebugMessage
Definition: pub_message.h:77
static SCIP_DECL_EXPRCURV(exprcurvDefault)
Definition: expr.c:1402
SCIP_EXPRDATA_MONOMIAL ** monomials
Definition: struct_expr.h:80
static struct exprOpTableElement exprOpTable[]
Definition: expr.c:3200
#define SIGN(x)
Definition: expr.c:46
#define BMSduplicateBlockMemory(mem, ptr, source)
Definition: memory.h:414
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15269
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2903
SCIP_RETCODE SCIPexprMultiplyMonomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6850
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8702
SCIP_Bool SCIPquadelemSortedFind(SCIP_QUADELEM *quadelems, int idx1, int idx2, int nquadelems, int *pos)
Definition: expr.c:9149
unsigned int SCIP_EXPRINTCAPABILITY
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8573
BMS_BLKMEM * blkmem
Definition: struct_expr.h:157
SCIP_EXPRCURV curv
Definition: struct_expr.h:144
SCIP_EXPR * root
Definition: struct_expr.h:58
#define exprevalIntTan
Definition: expr.c:2104
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:15016
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13089
int nchildren
Definition: struct_expr.h:49
static void exprgraphPrintNodeDot(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:9935
#define SCIP_EXPRESSION_MAXCHILDEST
Definition: expr.c:39
static void exprgraphUpdateVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Bool *clearreverseprop, SCIP_Bool *boundchanged)
Definition: expr.c:12731
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:14293
SCIP_EXPRCURV SCIPexprcurvMonomial(int nfactors, SCIP_Real *exponents, int *factoridxs, SCIP_EXPRCURV *factorcurv, SCIP_INTERVAL *factorbounds)
Definition: expr.c:345
SCIP_EXPRDATA_MONOMIAL ** SCIPexprGetMonomials(SCIP_EXPR *expr)
Definition: expr.c:5825
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2015
static SCIP_DECL_EXPREVAL(exprevalVar)
Definition: expr.c:1411
public methods for expressions, expression trees, expression graphs, and related stuff ...
SCIP_EXPRCURV SCIPexprcurvMultiply(SCIP_Real factor, SCIP_EXPRCURV curvature)
Definition: expr.c:224
int SCIPexprGetMonomialNFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5871
int SCIPexprGetIntPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5728
void SCIPintervalSin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2997
#define SCIP_EXPRINTCAPABILITY_INTFUNCVALUE
SCIP_RETCODE SCIPexprtreeCheckCurvature(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:8934
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12926
static SCIP_RETCODE exprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op, SCIP_EXPROPDATA opdata)
Definition: expr.c:9635
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13077
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:14977
#define SCIP_ALLOC_ABORT(x)
Definition: def.h:296
#define SCIP_DECL_EXPRGRAPHVARADDED(x)
Definition: type_expr.h:181
SCIP_HASHMAP * varidxs
Definition: struct_expr.h:169
int SCIPexprgraphGetNodeOperatorIndex(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12936
void SCIPrandomFree(SCIP_RANDNUMGEN **randnumgen)
Definition: misc.c:8710
SCIP_Real coef
Definition: type_expr.h:102
SCIP_Real inf
Definition: intervalarith.h:39
const char * SCIPexprcurvGetName(SCIP_EXPRCURV curv)
Definition: expr.c:458
static const NodeData nodedata[]
Definition: gastrans.c:74
SCIP_Real SCIPexprgraphGetNodeLinearConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13017
#define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize)
Definition: expr.c:87
SCIP_Real * params
Definition: struct_expr.h:62
#define BMSduplicateBlockMemoryArray(mem, ptr, source, num)
Definition: memory.h:416
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13101
SCIP_RETCODE SCIPexprAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:6626
SCIP_Bool SCIPexprgraphHasNodeNonlinearAncestor(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14540
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13238
SCIP_Bool simplified
Definition: struct_expr.h:148
SCIP_RETCODE SCIPexprCreateQuadratic(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real constant, SCIP_Real *lincoefs, int nquadelems, SCIP_QUADELEM *quadelems)
Definition: expr.c:6543
SCIP_Bool SCIPexprgraphFindConstNode(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15610
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:7825
void SCIPexprgraphSetVarsBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_INTERVAL *varbounds)
Definition: expr.c:14877
union SCIP_ExprOpData SCIP_EXPROPDATA
Definition: type_expr.h:90
static SCIP_Bool isUbBetter(SCIP_Real minstrength, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:153
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:102
SCIP_RETCODE SCIPexprgraphCheckCurvature(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop)
Definition: expr.c:15814
SCIP_RETCODE SCIPexprGetMaxDegree(SCIP_EXPR *expr, int *maxdegree)
Definition: expr.c:7191
static void polynomialdataMultiplyByConstant(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_Real factor)
Definition: expr.c:909
#define SCIPerrorMessage
Definition: pub_message.h:45
enum SCIP_ExprOp SCIP_EXPROP
Definition: type_expr.h:89
interval arithmetics for provable bounds
#define SCIPdebugPrintf
Definition: pub_message.h:80
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_RETCODE SCIPexprgraphCreateNodeUser(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_USEREXPRDATA *data, SCIP_EXPRINTCAPABILITY evalcapability, SCIP_DECL_USEREXPREVAL((*eval)), SCIP_DECL_USEREXPRINTEVAL((*inteval)), SCIP_DECL_USEREXPRCURV((*curv)), SCIP_DECL_USEREXPRPROP((*prop)), SCIP_DECL_USEREXPRESTIMATE((*estimate)), SCIP_DECL_USEREXPRCOPYDATA((*copydata)), SCIP_DECL_USEREXPRFREEDATA((*freedata)), SCIP_DECL_USEREXPRPRINT((*print)))
Definition: expr.c:13427
void SCIPsortPtrRealInt(void **ptrarray, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Real * SCIPexprGetQuadLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5801
SCIP_EXPRGRAPHNODE *** SCIPexprgraphGetNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14825
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16621
SCIP_INTERVAL bounds
Definition: struct_expr.h:137
static SCIP_RETCODE exprsimplifyRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4327
void SCIPintervalLog(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprCopyDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **targetexpr, SCIP_EXPR *sourceexpr)
Definition: expr.c:6100
static const char * curvnames[4]
Definition: expr.c:178
SCIPInterval sqrt(const SCIPInterval &x)
SCIP_Bool SCIPexprgraphHasNodeUserEstimator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13206
static SCIP_DECL_EXPRCOPYDATA(exprCopyDataLinear)
Definition: expr.c:2506
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
static SCIP_RETCODE quadraticdataCreate(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_QUADRATIC **quadraticdata, SCIP_Real constant, int nchildren, SCIP_Real *lincoefs, int nquadelems, SCIP_QUADELEM *quadelems)
Definition: expr.c:474
SCIPInterval sign(const SCIPInterval &x)
SCIP_EXPRCURV SCIPexprcurvPower(SCIP_INTERVAL basebounds, SCIP_EXPRCURV basecurv, SCIP_Real exponent)
Definition: expr.c:237
SCIP_Real SCIPexprGetQuadConstant(SCIP_EXPR *expr)
Definition: expr.c:5788
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2798
static SCIP_RETCODE exprgraphNodeReplaceChild(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE **oldchild, SCIP_EXPRGRAPHNODE *newchild)
Definition: expr.c:9495
void SCIPmessagePrintWarning(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:417
SCIP_EXPRGRAPHNODE *** nodes
Definition: struct_expr.h:162
#define EXPROPEMPTY
Definition: expr.c:3196
#define NULL
Definition: lpi_spx1.cpp:137
static SCIP_Bool exprgraphNodeIsParent(SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9363
static void polynomialdataFree(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata)
Definition: expr.c:696
#define REALABS(x)
Definition: def.h:159
void SCIPexprMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:6764
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:8543
SCIP_Bool SCIPexprAreMonomialsEqual(SCIP_EXPRDATA_MONOMIAL *monomial1, SCIP_EXPRDATA_MONOMIAL *monomial2, SCIP_Real eps)
Definition: expr.c:6779
SCIP_EXPRGRAPHNODE ** varnodes
Definition: struct_expr.h:167
SCIP_RETCODE SCIPexprgraphCreateNodeLinear(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int ncoefs, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:13331
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16171
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_CALL(x)
Definition: def.h:306
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12856
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14969
SCIP_RETCODE SCIPexprParse(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR **expr, const char *str, const char *lastchar, int *nvars, int *varnames)
Definition: expr.c:8472
SCIP_RETCODE SCIPexprCreatePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:6591
SCIP_RETCODE SCIPexprCheckCurvature(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_Real *param, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:7984
SCIP_RETCODE SCIPexprEvalUser(SCIP_EXPR *expr, SCIP_Real *argvals, SCIP_Real *val, SCIP_Real *gradient, SCIP_Real *hessian)
Definition: expr.c:7928
SCIP_Real sup
Definition: intervalarith.h:40
void SCIPmessagePrintInfo(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:584
SCIP_RETCODE SCIPexprEvalShallow(SCIP_EXPR *expr, SCIP_Real *argvals, SCIP_Real *varvals, SCIP_Real *param, SCIP_Real *val)
Definition: expr.c:7806
void SCIPexprMultiplyPolynomialByConstant(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real factor)
Definition: expr.c:6661
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:14593
static SCIP_RETCODE exprsimplifyUnconvertPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4874
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:8042
static SCIP_RETCODE exprgraphNodeUpdateBounds(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool parenttightenisinvalid)
Definition: expr.c:10042
#define SCIP_DECL_USEREXPRCURV(x)
Definition: type_expr.h:270
void SCIPexprFreeMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial)
Definition: expr.c:7051
SCIP_RETCODE SCIPexprMulConstant(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPR *term, SCIP_Real factor)
Definition: expr.c:6363
SCIP_EXPR * SCIPexprtreeGetRoot(SCIP_EXPRTREE *tree)
Definition: expr.c:8533
SCIP_RETCODE SCIPexprCreateUser(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_USEREXPRDATA *data, SCIP_EXPRINTCAPABILITY evalcapability, SCIP_DECL_USEREXPREVAL((*eval)), SCIP_DECL_USEREXPRINTEVAL((*inteval)), SCIP_DECL_USEREXPRCURV((*curv)), SCIP_DECL_USEREXPRPROP((*prop)), SCIP_DECL_USEREXPRESTIMATE((*estimate)), SCIP_DECL_USEREXPRCOPYDATA((*copydata)), SCIP_DECL_USEREXPRFREEDATA((*freedata)), SCIP_DECL_USEREXPRPRINT((*print)))
Definition: expr.c:7112
SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
SCIP_Bool SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14505
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:13116
#define SCIP_DECL_USEREXPRESTIMATE(x)
Definition: type_expr.h:234
#define SCIP_DECL_USEREXPRPROP(x)
Definition: type_expr.h:282
SCIP_Real SCIPexprgraphGetNodeOperatorReal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12947
#define SCIP_EXPRBOUNDSTATUS_VALID
Definition: type_expr.h:209
SCIP_RETCODE SCIPexprAdd(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_Real coef1, SCIP_EXPR *term1, SCIP_Real coef2, SCIP_EXPR *term2, SCIP_Real constant)
Definition: expr.c:6205
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13029
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:419
SCIP_RETCODE SCIPexprMultiplyPolynomialByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR *factor, int *childmap)
Definition: expr.c:6698
void SCIPexprMergeMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real eps)
Definition: expr.c:6915
void SCIPintervalCos(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_EXPRINTCAPABILITY SCIPexprGetUserEvalCapability(SCIP_EXPR *expr)
Definition: expr.c:5923
public data structures and miscellaneous methods
static void polynomialdataMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:817
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:5674
SCIP_Real SCIPexprGetSignPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5739
SCIP_EXPRGRAPHNODE ** children
Definition: struct_expr.h:128
#define SCIP_Bool
Definition: def.h:61
void ** vars
Definition: struct_expr.h:60
SCIP_Bool needvarboundprop
Definition: struct_expr.h:181
static SCIP_RETCODE exprgraphNodeEval(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:9977
SCIP_USEREXPRDATA * userdata
Definition: struct_expr.h:103
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14524
SCIPInterval sin(const SCIPInterval &x)
#define BMSallocBlockMemoryArray(mem, ptr, num)
Definition: memory.h:408
void SCIPexprSortQuadElems(SCIP_EXPR *expr)
Definition: expr.c:6579
static SCIP_RETCODE monomialdataEnsureFactorsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomialdata, int minsize)
Definition: expr.c:587
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:14929
static SCIP_RETCODE exprsimplifyFlattenPolynomials(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR *expr, SCIP_Real eps, int maxexpansionexponent)
Definition: expr.c:4444
static SCIP_RETCODE exprgraphNodeRemoveParent(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9312
BMS_BLKMEM * blkmem
Definition: struct_expr.h:57
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8588
SCIP_RETCODE SCIPexprtreeFreeInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8611
void SCIPintervalSolveBivariateQuadExpressionAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
#define BMSfreeBlockMemoryArray(mem, ptr, num)
Definition: memory.h:421
void SCIPquadelemSqueeze(SCIP_QUADELEM *quadelems, int nquadelems, int *nquadelemsnew)
Definition: expr.c:9201
SCIP_Bool SCIPexprHasUserEstimator(SCIP_EXPR *expr)
Definition: expr.c:5912
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:9411
void SCIPintervalSquareRoot(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalQuadBivar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
SCIP_EXPR ** children
Definition: struct_expr.h:50
SCIP_INTERVAL * varbounds
Definition: struct_expr.h:168
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:5664
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:16605
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:14949
static SCIP_Bool exprgraphFindConstNodePos(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *pos)
Definition: expr.c:9580
void SCIPintervalSquare(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprgraphNodeSplitOffLinear(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, int linvarssize, int *nlinvars, void **linvars, SCIP_Real *lincoefs, SCIP_Real *constant)
Definition: expr.c:13481
SCIP_RETCODE SCIPexprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op,...)
Definition: expr.c:5934
void SCIPintervalScalprodScalars(SCIP_Real infinity, SCIP_INTERVAL *resultant, int length, SCIP_INTERVAL *operand1, SCIP_Real *operand2)
SCIP_RETCODE SCIPexprtreeFree(SCIP_EXPRTREE **tree)
Definition: expr.c:8783
SCIP_Bool SCIPexprFindMonomialFactor(SCIP_EXPRDATA_MONOMIAL *monomial, int childidx, int *pos)
Definition: expr.c:7095
static SCIP_DECL_EXPRINTEVAL(exprevalIntDefault)
Definition: expr.c:1393
#define EPSLE(x, y, eps)
Definition: def.h:162
void SCIPexprgraphFreeNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14415
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static void exprgraphNodePropagateBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:10136
#define SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED
Definition: type_expr.h:210
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14467
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:89
SCIPInterval log(const SCIPInterval &x)
SCIP_USEREXPRDATA * SCIPexprGetUserData(SCIP_EXPR *expr)
Definition: expr.c:5901
SCIP_RETCODE SCIPexprtreeAddExpr(SCIP_EXPRTREE *tree, SCIP_EXPR *expr, SCIP_Bool copyexpr)
Definition: expr.c:8911
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2315
#define SCIP_EXPR_DEGREEINFINITY
Definition: type_expr.h:114
SCIP_EXPROPDATA data
Definition: struct_expr.h:120
SCIP_EXPRGRAPHNODE ** parents
Definition: struct_expr.h:133
static long * number
void SCIPintervalAbs(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define BMSclearMemory(ptr)
Definition: memory.h:84
SCIP_Real SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5861
static SCIP_RETCODE polynomialdataCopy(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *sourcepolynomialdata)
Definition: expr.c:659
static SCIP_DECL_SORTPTRCOMP(ptrcomp)
Definition: expr.c:122
static SCIP_RETCODE polynomialdataExpandMonomialFactor(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int monomialpos, int factorpos, SCIP_EXPRDATA_POLYNOMIAL *factorpolynomial, int *childmap, int maxexpansionexponent, SCIP_Bool *success)
Definition: expr.c:1171
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12958
void * SCIPexprGetOpData(SCIP_EXPR *expr)
Definition: expr.c:5706
SCIP_EXPROP op
Definition: struct_expr.h:119
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:8745
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13041
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2065
#define SCIP_REAL_MAX
Definition: def.h:136
static SCIP_RETCODE exprConvertToPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren)
Definition: expr.c:3307
SCIP_RETCODE SCIPexprEvalIntUser(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *val, SCIP_INTERVAL *gradient, SCIP_INTERVAL *hessian)
Definition: expr.c:7951
int SCIPexprgraphGetNodeIntPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12984
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12896
SCIP_QUADELEM * quadelems
Definition: struct_expr.h:71
static void exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:9286
#define EPSLT(x, y, eps)
Definition: def.h:161
#define SCIP_DECL_EXPRGRAPHVARREMOVE(x)
Definition: type_expr.h:191
static SCIP_RETCODE exprgraphAddExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPR *expr, void **vars, SCIP_Real *params, SCIP_EXPRGRAPHNODE **exprnode, SCIP_Bool *exprnodeisnew)
Definition: expr.c:12599
static SCIP_RETCODE polynomialdataAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:742
#define EPSGT(x, y, eps)
Definition: def.h:163
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:93
int SCIPexpropGetNChildren(SCIP_EXPROP op)
Definition: expr.c:3257
static void quadraticdataSort(SCIP_EXPRDATA_QUADRATIC *quadraticdata)
Definition: expr.c:512
#define SCIP_VARTYPE_IMPLINT_CHAR
Definition: def.h:108
SCIP_EXPRINTDATA * interpreterdata
Definition: struct_expr.h:63
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3013
#define exprcurvCos
Definition: expr.c:2089
SCIP_Bool SCIPexprgraphFindVarNode(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_EXPRGRAPHNODE **varnode)
Definition: expr.c:15581
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8139
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13006
#define SCIP_EXPRINTCAPABILITY_FUNCVALUE
SCIP_Real * SCIPexprGetLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5750
#define DEFAULT_RANDSEED
Definition: expr.c:40
SCIP_Bool SCIPexprtreeHasParam(SCIP_EXPRTREE *tree)
Definition: expr.c:8625
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Real SCIPexprGetOpReal(SCIP_EXPR *expr)
Definition: expr.c:5695
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12916
static SCIP_Bool isLbBetter(SCIP_Real minstrength, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:133
SCIP_RETCODE SCIPexprgraphNodePolynomialAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:13408
SCIP_Bool parentssorted
Definition: struct_expr.h:134
#define SCIP_VARTYPE_CONTINUOUS_CHAR
Definition: def.h:109
SCIP_EXPRGRAPHNODE ** constnodes
Definition: struct_expr.h:173
void SCIPexprFreeShallow(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6180
SCIP_QUADELEM * SCIPexprGetQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5776
SCIP_RETCODE SCIPexprgraphCreateNodePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:13383
void SCIPintervalExp(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
public methods for message output
SCIP_USEREXPRDATA * SCIPexprgraphGetNodeUserData(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13194
static SCIP_RETCODE exprsimplifySeparateLinearFromPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps, int nvars, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:4773
SCIP_RETCODE SCIPexprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op,...)
Definition: expr.c:13248
SCIP_RETCODE SCIPexprEvalIntShallow(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7866
SCIP_RETCODE SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14325
int SCIPexprGetNMonomials(SCIP_EXPR *expr)
Definition: expr.c:5837
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE
Definition: type_expr.h:214
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:608
SCIP_RETCODE SCIPhashmapSetImage(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2943
SCIP_RETCODE SCIPexprtreeSimplify(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:8857
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:16118
#define SCIP_DECL_USEREXPRCOPYDATA(x)
Definition: type_expr.h:291
#define SCIP_Real
Definition: def.h:135
#define EPSROUND(x, eps)
Definition: def.h:170
#define MIN(x, y)
Definition: memory.c:75
void SCIPintervalIntersect(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE polynomialdataCreate(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:612
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12876
#define SCIP_INVALID
Definition: def.h:155
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPexprAddMonomialFactors(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:6821
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5891
void SCIPexprgraphPrintNode(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: expr.c:14577
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:8960
#define SCIPisFinite(x)
Definition: pub_misc.h:1601
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:10021
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:106
int SCIPexprtreeGetNParams(SCIP_EXPRTREE *tree)
Definition: expr.c:8553
SCIP_RETCODE SCIPexprgraphSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange, SCIP_Bool *domainerror)
Definition: expr.c:15857
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
static SCIP_RETCODE exprsimplifyRemovePolynomialUnusedChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4393
#define exprcurvTan
Definition: expr.c:2107
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE exprgraphMoveNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int newdepth)
Definition: expr.c:12043
static SCIP_RETCODE exprparseFindClosingParenthesis(const char *str, const char **endptr, int length)
Definition: expr.c:5001
SCIP_RETCODE SCIPexprAddToLinear(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nchildren, SCIP_Real *coefs, SCIP_EXPR **children, SCIP_Real constant)
Definition: expr.c:6498
static SCIP_RETCODE exprsimplifyAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nexprs, SCIP_EXPR **exprs, SCIP_Bool comparechildren, SCIP_Real eps, int *childmap)
Definition: expr.c:4130
#define nnodes
Definition: gastrans.c:65
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:406
SCIP_RETCODE SCIPexprMultiplyPolynomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6675
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12973
SCIP_RETCODE SCIPexprintFreeData(SCIP_EXPRINTDATA **interpreterdata)
#define EPSFLOOR(x, eps)
Definition: def.h:168
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2846
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
static SCIP_DECL_HASHGETKEY(exprparseVarTableGetKey)
Definition: expr.c:4898
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:392
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13065
static SCIP_RETCODE polynomialdataPower(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int exponent)
Definition: expr.c:1072
#define SCIP_CALL_ABORT(x)
Definition: def.h:285
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14845
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT
Definition: type_expr.h:213
SCIP_RETCODE SCIPexprCreateLinear(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:6461
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_ALLOC(x)
Definition: def.h:317
#define SCIPABORT()
Definition: def.h:278
SCIP_Real SCIPexprGetLinearConstant(SCIP_EXPR *expr)
Definition: expr.c:5763
void SCIPexprtreeSetInterpreterData(SCIP_EXPRTREE *tree, SCIP_EXPRINTDATA *interpreterdata)
Definition: expr.c:8598
SCIP_EXPRCURV SCIPexprcurvAdd(SCIP_EXPRCURV curv1, SCIP_EXPRCURV curv2)
Definition: expr.c:189
struct SCIP_ExprIntData SCIP_EXPRINTDATA
static void quadelemsQuickSort(SCIP_QUADELEM *elems, int start, int end)
Definition: expr.c:9014
static SCIP_RETCODE polynomialdataEnsureMonomialsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int minsize)
Definition: expr.c:725
SCIP_RETCODE SCIPexprtreeSetParams(SCIP_EXPRTREE *tree, int nparams, SCIP_Real *paramvals)
Definition: expr.c:8807
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
int SCIPexprGetNQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5813
static void exprgraphPrintNodeExpression(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, SCIP_Bool printchildrenbounds)
Definition: expr.c:9679
#define SCIP_DECL_USEREXPRFREEDATA(x)
Definition: type_expr.h:299
static SCIP_RETCODE exprgraphFindParentByOperator(SCIP_EXPRGRAPH *exprgraph, int nchildren, SCIP_EXPRGRAPHNODE **children, SCIP_EXPROP op, SCIP_EXPROPDATA opdata, SCIP_EXPR **exprchildren, SCIP_EXPRGRAPHNODE **parent)
Definition: expr.c:12131
static void exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:11878
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15658
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:412
void SCIPintervalSetRoundingModeDownwards(void)
#define EPSZ(x, eps)
Definition: def.h:165
void SCIPintervalPowerScalarInverse(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL basedomain, SCIP_Real exponent, SCIP_INTERVAL image)
int SCIPexprgraphGetNodeDepth(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12906
#define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize)
Definition: expr.c:52
SCIP_EXPRCURV SCIPexprcurvNegate(SCIP_EXPRCURV curvature)
Definition: expr.c:198
SCIP_RETCODE SCIPexprtreeEval(SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
Definition: expr.c:8654
SCIP_EXPRINTCAPABILITY evalcapability
Definition: struct_expr.h:104
void SCIPexprgraphSetVarBounds(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_INTERVAL varbounds)
Definition: expr.c:14889
void SCIPsortIntReal(int *intarray, SCIP_Real *realarray, int len)
static SCIP_RETCODE exprgraphRemoveVar(SCIP_EXPRGRAPH *exprgraph, int varidx)
Definition: expr.c:11990
#define SCIP_DECL_EXPRGRAPHVARCHGIDX(x)
Definition: type_expr.h:203
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
void SCIPexprgraphEnableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14440
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13053