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-2014 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 
41 /** sign of a value (-1 or +1)
42  * 0.0 has sign +1
43  */
44 #define SIGN(x) ((x) >= 0.0 ? 1.0 : -1.0)
45 
46 /** ensures that a block memory array has at least a given size
47  * if cursize is 0, then *array1 can be NULL
48  */
49 #define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize) \
50  do { \
51  int __newsize; \
52  assert((blkmem) != NULL); \
53  if( *(cursize) >= (minsize) ) \
54  break; \
55  __newsize = calcGrowSize(minsize); \
56  assert(__newsize >= (minsize)); \
57  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
58  *(cursize) = __newsize; \
59  } while( FALSE )
60 
61 #if 0 /* this macros is currently not used, which offends lint, so disable it */
62 /** ensures that two block memory arrays have at least a given size
63  * if cursize is 0, then arrays can be NULL
64  */
65 #define ensureBlockMemoryArraySize2(blkmem, array1, array2, cursize, minsize) \
66  do { \
67  int __newsize; \
68  assert((blkmem) != NULL); \
69  if( *(cursize) >= (minsize) ) \
70  break; \
71  __newsize = calcGrowSize(minsize); \
72  assert(__newsize >= (minsize)); \
73  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
74  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
75  *(cursize) = __newsize; \
76  } while( FALSE )
77 #endif
78 
79 /** ensures that three block memory arrays have at least a given size
80  * if cursize is 0, then arrays can be NULL
81  */
82 #define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize) \
83  do { \
84  int __newsize; \
85  assert((blkmem) != NULL); \
86  if( *(cursize) >= (minsize) ) \
87  break; \
88  __newsize = calcGrowSize(minsize); \
89  assert(__newsize >= (minsize)); \
90  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
91  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
92  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array3, *(cursize), __newsize) ); \
93  *(cursize) = __newsize; \
94  } while( FALSE )
95 
96 /**@name Miscellaneous private methods */
97 /**@{ */
98 
99 /** calculate memory size for dynamically allocated arrays (copied from scip/set.c) */
100 static
102  int num /**< minimum number of entries to store */
103  )
104 {
105  int size;
106 
107  /* calculate the size with this loop, such that the resulting numbers are always the same (-> block memory) */
108  size = 4;
109  while( size < num )
110  size = (int)(1.2 * size + 4);
111 
112  return size;
113 }
114 
115 /** pointer comparison to use in sorting methods */
116 static
118 {
119  if( elem1 > elem2 )
120  return 1;
121  if( elem1 < elem2 )
122  return -1;
123  return 0;
124 }
125 
126 /** 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) */
127 static
129  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
130  SCIP_Real newlb, /**< new lower bound */
131  SCIP_Real oldlb, /**< old lower bound */
132  SCIP_Real oldub /**< old upper bound */
133  )
134 {
135  SCIP_Real eps;
136 
137  /* nothing can be tighter than an empty interval */
138  if( oldlb > oldub )
139  return FALSE;
140 
141  eps = REALABS(oldlb);
142  eps = MIN(oldub - oldlb, eps);
143  return EPSGT(newlb, oldlb, minstrength * MAX(eps, 1e-3));
144 }
145 
146 /** 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) */
147 static
149  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
150  SCIP_Real newub, /**< new upper bound */
151  SCIP_Real oldlb, /**< old lower bound */
152  SCIP_Real oldub /**< old upper bound */
153  )
154 {
155  SCIP_Real eps;
156 
157  /* nothing can be tighter than an empty interval */
158  if( oldlb > oldub )
159  return FALSE;
160 
161  eps = REALABS(oldub);
162  eps = MIN(oldub - oldlb, eps);
163  return EPSLT(newub, oldub, minstrength * MAX(eps, 1e-3));
164 }
165 
166 /**@} */
167 
168 /**@name Expression curvature methods */
169 /**@{ */
170 
171 /** curvature names as strings */
172 static
173 const char* curvnames[4] =
174  {
175  "unknown",
176  "convex",
177  "concave",
178  "linear"
179  };
180 
181 #undef SCIPexprcurvAdd
182 
183 /* gives curvature for a sum of two functions with given curvature */
185  SCIP_EXPRCURV curv1, /**< curvature of first summand */
186  SCIP_EXPRCURV curv2 /**< curvature of second summand */
187  )
188 {
189  return (SCIP_EXPRCURV) (curv1 & curv2);
190 }
191 
192 /** gives the curvature for the negation of a function with given curvature */
194  SCIP_EXPRCURV curvature /**< curvature of function */
195  )
196 {
197  switch( curvature )
198  {
200  return SCIP_EXPRCURV_CONVEX;
201 
203  return SCIP_EXPRCURV_CONCAVE;
204 
207  /* can return curvature, do this below */
208  break;
209 
210  default:
211  SCIPerrorMessage("unknown curvature status.\n");
212  SCIPABORT();
213  }
214 
215  return curvature;
216 }
217 
218 /* gives curvature for a functions with given curvature multiplied by a constant factor */
220  SCIP_Real factor, /**< constant factor */
221  SCIP_EXPRCURV curvature /**< curvature of other factor */
222  )
223 {
224  if( factor == 0.0 )
225  return SCIP_EXPRCURV_LINEAR;
226  if( factor > 0.0 )
227  return curvature;
228  return SCIPexprcurvNegate(curvature);
229 }
230 
231 /* gives curvature for base^exponent for given bounds and curvature of base-function and constant exponent */
233  SCIP_INTERVAL basebounds, /**< bounds on base function */
234  SCIP_EXPRCURV basecurv, /**< curvature of base function */
235  SCIP_Real exponent /**< exponent */
236  )
237 {
238  SCIP_Bool expisint;
239 
240  assert(basebounds.inf <= basebounds.sup);
241 
242  if( exponent == 0.0 )
243  return SCIP_EXPRCURV_LINEAR;
244 
245  if( exponent == 1.0 )
246  return basecurv;
247 
248  expisint = EPSISINT(exponent, 0.0); /*lint !e835*/
249 
250  /* if exponent is fractional, then power is not defined for a negative base
251  * thus, consider only positive part of basebounds
252  */
253  if( !expisint && basebounds.inf < 0.0 )
254  {
255  basebounds.inf = 0.0;
256  if( basebounds.sup < 0.0 )
257  return SCIP_EXPRCURV_LINEAR;
258  }
259 
260  /* if basebounds contains 0.0, consider negative and positive interval separately, if possible */
261  if( basebounds.inf < 0.0 && basebounds.sup > 0.0 )
262  {
263  SCIP_INTERVAL leftbounds;
264  SCIP_INTERVAL rightbounds;
265 
266  /* 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 */
267  if( exponent < 0.0 )
268  return SCIP_EXPRCURV_UNKNOWN;
269 
270  SCIPintervalSetBounds(&leftbounds, basebounds.inf, 0.0);
271  SCIPintervalSetBounds(&rightbounds, 0.0, basebounds.sup);
272 
273  return (SCIP_EXPRCURV) (SCIPexprcurvPower(leftbounds, basecurv, exponent) & SCIPexprcurvPower(rightbounds, basecurv, exponent));
274  }
275  assert(basebounds.inf >= 0.0 || basebounds.sup <= 0.0);
276 
277  /* (base^exponent)'' = exponent * ( (exponent-1) base^(exponent-2) (base')^2 + base^(exponent-1) base'' )
278  *
279  * if base'' is positive, i.e., base is convex, then
280  * - for base > 0.0 and exponent > 1.0, the second deriv. is positive -> convex
281  * - for base < 0.0 and exponent > 1.0, we can't say (first and second summand opposite signs)
282  * - for base > 0.0 and 0.0 < exponent < 1.0, we can't say (first sommand negative, second summand positive)
283  * - for base > 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
284  * - for base < 0.0 and exponent < 0.0 and even, the second deriv. is positive -> convex
285  * - for base < 0.0 and exponent < 0.0 and odd, the second deriv. is negative -> concave
286  *
287  * if base'' is negative, i.e., base is concave, then
288  * - for base > 0.0 and exponent > 1.0, we can't say (first summand positive, second summand negative)
289  * - for base < 0.0 and exponent > 1.0 and even, the second deriv. is positive -> convex
290  * - for base < 0.0 and exponent > 1.0 and odd, the second deriv. is negative -> concave
291  * - for base > 0.0 and 0.0 < exponent < 1.0, the second deriv. is negative -> concave
292  * - for base > 0.0 and exponent < 0.0, the second deriv. is positive -> convex
293  * - for base < 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
294  *
295  * if base'' is zero, i.e., base is linear, then
296  * (base^exponent)'' = exponent * (exponent-1) base^(exponent-2) (base')^2
297  * - just multiply signs
298  */
299 
300  if( basecurv == SCIP_EXPRCURV_LINEAR )
301  {
302  SCIP_Real sign;
303 
304  /* base^(exponent-2) is negative, if base < 0.0 and exponent is odd */
305  sign = exponent * (exponent - 1.0);
306  assert(basebounds.inf >= 0.0 || expisint);
307  if( basebounds.inf < 0.0 && ((int)exponent)%2 != 0 )
308  sign *= -1.0;
309  assert(sign != 0.0);
310 
311  return sign > 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
312  }
313 
314  if( basecurv == SCIP_EXPRCURV_CONVEX )
315  {
316  if( basebounds.sup <= 0.0 && exponent < 0.0 && expisint )
317  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
318  if( basebounds.inf >= 0.0 && exponent > 1.0 )
319  return SCIP_EXPRCURV_CONVEX ;
320  return SCIP_EXPRCURV_UNKNOWN;
321  }
322 
323  if( basecurv == SCIP_EXPRCURV_CONCAVE )
324  {
325  if( basebounds.sup <= 0.0 && exponent > 1.0 && expisint )
326  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
327  if( basebounds.inf >= 0.0 && exponent < 1.0 )
328  return exponent < 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
329  return SCIP_EXPRCURV_UNKNOWN;
330  }
331 
332  return SCIP_EXPRCURV_UNKNOWN;
333 }
334 
335 /* gives curvature for a monomial with given curvatures and bounds for each factor
336  * see Maranas and Floudas, Finding All Solutions of Nonlinearly Constrained Systems of Equations, JOGO 7, 1995
337  * for the categorization in the case that all factors are linear
338  */
340  int nfactors, /**< number of factors in monomial */
341  SCIP_Real* exponents, /**< exponents in monomial, or NULL if all 1.0 */
342  int* factoridxs, /**< indices of factors (but not exponents), or NULL if identity mapping */
343  SCIP_EXPRCURV* factorcurv, /**< curvature of each factor */
344  SCIP_INTERVAL* factorbounds /**< bounds of each factor */
345  )
346 {
347  SCIP_Real mult;
348  SCIP_Real e;
349  SCIP_EXPRCURV curv;
350  SCIP_EXPRCURV fcurv;
351  int nnegative;
352  int npositive;
353  SCIP_Real sum;
354  SCIP_Bool expcurvpos;
355  SCIP_Bool expcurvneg;
356  int j;
357  int f;
358 
359  assert(nfactors >= 0);
360  assert(factorcurv != NULL || nfactors == 0);
361  assert(factorbounds != NULL || nfactors == 0);
362 
363  if( nfactors == 0 )
364  return SCIP_EXPRCURV_LINEAR;
365 
366  if( nfactors == 1 )
367  {
368  f = factoridxs != NULL ? factoridxs[0] : 0;
369  e = exponents != NULL ? exponents[0] : 1.0;
370  /* SCIPdebugMessage("monomial [%g,%g]^%g is %s\n",
371  factorbounds[f].inf, factorbounds[f].sup, e,
372  SCIPexprcurvGetName(SCIPexprcurvPower(factorbounds[f], factorcurv[f], e))); */
373  return SCIPexprcurvPower(factorbounds[f], factorcurv[f], e); /*lint !e613*/
374  }
375 
376  mult = 1.0;
377 
378  nnegative = 0; /* number of negative exponents */
379  npositive = 0; /* number of positive exponents */
380  sum = 0.0; /* sum of exponents */
381  expcurvpos = TRUE; /* whether exp_j * f_j''(x) >= 0 for all factors (assuming f_j >= 0) */
382  expcurvneg = TRUE; /* whether exp_j * f_j''(x) <= 0 for all factors (assuming f_j >= 0) */
383 
384  for( j = 0; j < nfactors; ++j )
385  {
386  f = factoridxs != NULL ? factoridxs[j] : j;
387  if( factorcurv[f] == SCIP_EXPRCURV_UNKNOWN ) /*lint !e613*/
388  return SCIP_EXPRCURV_UNKNOWN;
389  if( factorbounds[f].inf < 0.0 && factorbounds[f].sup > 0.0 ) /*lint !e613*/
390  return SCIP_EXPRCURV_UNKNOWN;
391 
392  e = exponents != NULL ? exponents[j] : 1.0;
393  if( e < 0.0 )
394  ++nnegative;
395  else
396  ++npositive;
397  sum += e;
398 
399  if( factorbounds[f].inf < 0.0 ) /*lint !e613*/
400  {
401  /* if argument is negative, then exponent should be integer */
402  assert(EPSISINT(e, 0.0)); /*lint !e835*/
403 
404  /* flip j'th argument: (f_j)^(exp_j) = (-1)^(exp_j) (-f_j)^(exp_j) */
405 
406  /* -f_j has negated curvature of f_j */
407  fcurv = SCIPexprcurvNegate(factorcurv[f]); /*lint !e613*/
408 
409  /* negate monomial, if exponent is odd, i.e., (-1)^(exp_j) = -1 */
410  if( (int)e % 2 != 0 )
411  mult *= -1.0;
412  }
413  else
414  {
415  fcurv = factorcurv[f]; /*lint !e613*/
416  }
417 
418  /* check if exp_j * fcurv is convex (>= 0) and/or concave */
419  fcurv = SCIPexprcurvMultiply(e, fcurv);
420  if( !(fcurv & SCIP_EXPRCURV_CONVEX) )
421  expcurvpos = FALSE;
422  if( !(fcurv & SCIP_EXPRCURV_CONCAVE) )
423  expcurvneg = FALSE;
424  }
425 
426  /* if all factors are linear, then a product f_j^exp_j with f_j >= 0 is convex if
427  * - all exponents are negative, or
428  * - 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
429  * further, the product is concave if
430  * - all exponents are positive and the sum of exponents is <= 1.0
431  *
432  * if factors are nonlinear, then we require additionally, that for convexity
433  * - each factor is convex if exp_j >= 0, or concave if exp_j <= 0, i.e., exp_j*f_j'' >= 0
434  * and for concavity, we require that
435  * - all factors are concave, i.e., exp_j*f_j'' <= 0
436  */
437 
438  if( nnegative == nfactors && expcurvpos )
439  curv = SCIP_EXPRCURV_CONVEX;
440  else if( nnegative == nfactors-1 && EPSGE(sum, 1.0, 1e-9) && expcurvpos )
441  curv = SCIP_EXPRCURV_CONVEX;
442  else if( npositive == nfactors && EPSLE(sum, 1.0, 1e-9) && expcurvneg )
443  curv = SCIP_EXPRCURV_CONCAVE;
444  else
445  curv = SCIP_EXPRCURV_UNKNOWN;
446  curv = SCIPexprcurvMultiply(mult, curv);
447 
448  return curv;
449 }
450 
451 /** gives name as string for a curvature */
453  SCIP_EXPRCURV curv /**< curvature */
454  )
455 {
456  assert(curv <= SCIP_EXPRCURV_LINEAR); /*lint !e685*/
457 
458  return curvnames[curv];
459 }
460 
461 /**@} */
462 
463 /**@name Quadratic expression data private methods */
464 /**@{ */
465 
466 /** creates SCIP_EXPRDATA_QUADRATIC data structure from given quadratic elements */
467 static
469  BMS_BLKMEM* blkmem, /**< block memory data structure */
470  SCIP_EXPRDATA_QUADRATIC** quadraticdata, /**< buffer to store pointer to quadratic data */
471  SCIP_Real constant, /**< constant */
472  int nchildren, /**< number of children */
473  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
474  int nquadelems, /**< number of quadratic elements */
475  SCIP_QUADELEM* quadelems /**< quadratic elements */
476  )
477 {
478  assert(blkmem != NULL);
479  assert(quadraticdata != NULL);
480  assert(quadelems != NULL || nquadelems == 0);
481  assert(nchildren >= 0);
482 
483  SCIP_ALLOC( BMSallocBlockMemory(blkmem, quadraticdata) );
484 
485  (*quadraticdata)->constant = constant;
486  (*quadraticdata)->lincoefs = NULL;
487  (*quadraticdata)->nquadelems = nquadelems;
488  (*quadraticdata)->quadelems = NULL;
489  (*quadraticdata)->sorted = (nquadelems <= 1);
490 
491  if( lincoefs != NULL )
492  {
493  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->lincoefs, lincoefs, nchildren) );
494  }
495 
496  if( nquadelems > 0 )
497  {
498  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->quadelems, quadelems, nquadelems) );
499  }
500 
501  return SCIP_OKAY;
502 }
503 
504 /** sorts quadratic elements in a SCIP_EXPRDATA_QUADRATIC data structure */
505 static
507  SCIP_EXPRDATA_QUADRATIC* quadraticdata /**< quadratic data */
508  )
509 {
510  assert(quadraticdata != NULL);
511 
512  if( quadraticdata->sorted )
513  {
514 #ifndef NDEBUG
515  int i;
516  for( i = 1; i < quadraticdata->nquadelems; ++i )
517  {
518  assert(quadraticdata->quadelems[i].idx1 <= quadraticdata->quadelems[i].idx2);
519  assert(quadraticdata->quadelems[i-1].idx1 <= quadraticdata->quadelems[i].idx1);
520  assert(quadraticdata->quadelems[i-1].idx1 < quadraticdata->quadelems[i].idx1 ||
521  quadraticdata->quadelems[i-1].idx2 <= quadraticdata->quadelems[i].idx2);
522  }
523 #endif
524  return;
525  }
526 
527  if( quadraticdata->nquadelems > 0 )
528  SCIPquadelemSort(quadraticdata->quadelems, quadraticdata->nquadelems);
529 
530  quadraticdata->sorted = TRUE;
531 }
532 
533 /**@} */
534 
535 /**@name Polynomial expression data private methods */
536 /**@{ */
537 
538 /** compares two monomials
539  * gives 0 if monomials are equal */
540 static
541 SCIP_DECL_SORTPTRCOMP(monomialdataCompare)
542 {
543  SCIP_EXPRDATA_MONOMIAL* monomial1;
544  SCIP_EXPRDATA_MONOMIAL* monomial2;
545 
546  int i;
547 
548  assert(elem1 != NULL);
549  assert(elem2 != NULL);
550 
551  monomial1 = (SCIP_EXPRDATA_MONOMIAL*)elem1;
552  monomial2 = (SCIP_EXPRDATA_MONOMIAL*)elem2;
553 
554  /* make sure, both monomials are equal */
555  SCIPexprSortMonomialFactors(monomial1);
556  SCIPexprSortMonomialFactors(monomial2);
557 
558  /* for the first factor where both monomials differ,
559  * we return either the difference in the child indices, if children are different
560  * or the sign of the difference in the exponents
561  */
562  for( i = 0; i < monomial1->nfactors && i < monomial2->nfactors; ++i )
563  {
564  if( monomial1->childidxs[i] != monomial2->childidxs[i] )
565  return monomial1->childidxs[i] - monomial2->childidxs[i];
566  if( monomial1->exponents[i] > monomial2->exponents[i] )
567  return 1;
568  else if( monomial1->exponents[i] < monomial2->exponents[i] )
569  return -1;
570  }
571 
572  /* if the factors of one monomial are a proper subset of the factors of the other monomial,
573  * we return the difference in the number of monomials
574  */
575  return monomial1->nfactors - monomial2->nfactors;
576 }
577 
578 /** ensures that the factors arrays of a monomial have at least a given size */
579 static
581  BMS_BLKMEM* blkmem, /**< block memory data structure */
582  SCIP_EXPRDATA_MONOMIAL* monomialdata, /**< monomial data */
583  int minsize /**< minimal size of factors arrays */
584  )
585 {
586  assert(blkmem != NULL);
587  assert(monomialdata != NULL);
588 
589  if( minsize > monomialdata->factorssize )
590  {
591  int newsize;
592 
593  newsize = calcGrowSize(minsize);
594  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->childidxs, monomialdata->factorssize, newsize) );
595  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->exponents, monomialdata->factorssize, newsize) );
596  monomialdata->factorssize = newsize;
597  }
598  assert(minsize <= monomialdata->factorssize);
599 
600  return SCIP_OKAY;
601 }
602 
603 /** creates SCIP_EXPRDATA_POLYNOMIAL data structure from given monomials */
604 static
606  BMS_BLKMEM* blkmem, /**< block memory data structure */
607  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
608  int nmonomials, /**< number of monomials */
609  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
610  SCIP_Real constant, /**< constant part */
611  SCIP_Bool copymonomials /**< whether to copy monomials, or copy only given pointers, in which case polynomialdata assumes ownership of monomial structure */
612  )
613 {
614  assert(blkmem != NULL);
615  assert(polynomialdata != NULL);
616  assert(monomials != NULL || nmonomials == 0);
617 
618  SCIP_ALLOC( BMSallocBlockMemory(blkmem, polynomialdata) );
619 
620  (*polynomialdata)->constant = constant;
621  (*polynomialdata)->nmonomials = nmonomials;
622  (*polynomialdata)->monomialssize = nmonomials;
623  (*polynomialdata)->monomials = NULL;
624  (*polynomialdata)->sorted = (nmonomials <= 1);
625 
626  if( nmonomials > 0 )
627  {
628  int i;
629 
630  if( copymonomials )
631  {
632  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, nmonomials) );
633 
634  for( i = 0; i < nmonomials; ++i )
635  {
636  assert(monomials[i] != NULL); /*lint !e613*/
637  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i],
638  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
639  }
640  }
641  else
642  {
643  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, monomials, nmonomials) );
644  }
645  }
646 
647  return SCIP_OKAY;
648 }
649 
650 /** creates a copy of a SCIP_EXPRDATA_POLYNOMIAL data structure */
651 static
653  BMS_BLKMEM* blkmem, /**< block memory data structure */
654  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
655  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata /**< polynomial data to copy */
656  )
657 {
658  assert(blkmem != NULL);
659  assert(polynomialdata != NULL);
660  assert(sourcepolynomialdata != NULL);
661 
662  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, polynomialdata, sourcepolynomialdata) );
663 
664  (*polynomialdata)->monomialssize = sourcepolynomialdata->nmonomials;
665  if( sourcepolynomialdata->nmonomials > 0 )
666  {
667  int i;
668 
669  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize) );
670 
671  for( i = 0; i < sourcepolynomialdata->nmonomials; ++i )
672  {
673  assert(sourcepolynomialdata->monomials[i] != NULL); /*lint !e613*/
674  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i], sourcepolynomialdata->monomials[i]->coef,
675  sourcepolynomialdata->monomials[i]->nfactors, sourcepolynomialdata->monomials[i]->childidxs, sourcepolynomialdata->monomials[i]->exponents) );
676  (*polynomialdata)->monomials[i]->sorted = sourcepolynomialdata->monomials[i]->sorted;
677  }
678  }
679  else
680  {
681  (*polynomialdata)->monomials = NULL;
682  }
683 
684  return SCIP_OKAY;
685 }
686 
687 /** frees a SCIP_EXPRDATA_POLYNOMIAL data structure */
688 static
690  BMS_BLKMEM* blkmem, /**< block memory data structure */
691  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata /**< pointer to polynomial data to free */
692  )
693 {
694  assert(blkmem != NULL);
695  assert(polynomialdata != NULL);
696  assert(*polynomialdata != NULL);
697 
698  if( (*polynomialdata)->monomialssize > 0 )
699  {
700  int i;
701 
702  for( i = 0; i < (*polynomialdata)->nmonomials; ++i )
703  {
704  assert((*polynomialdata)->monomials[i] != NULL);
705  SCIPexprFreeMonomial(blkmem, &(*polynomialdata)->monomials[i]);
706  assert((*polynomialdata)->monomials[i] == NULL);
707  }
708 
709  BMSfreeBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize);
710  }
711  assert((*polynomialdata)->monomials == NULL);
712 
713  BMSfreeBlockMemory(blkmem, polynomialdata);
714 }
715 
716 /** ensures that the monomials array of a polynomial has at least a given size */
717 static
719  BMS_BLKMEM* blkmem, /**< block memory data structure */
720  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
721  int minsize /**< minimal size of monomials array */
722  )
723 {
724  assert(blkmem != NULL);
725  assert(polynomialdata != NULL);
726 
727  ensureBlockMemoryArraySize(blkmem, &polynomialdata->monomials, &polynomialdata->monomialssize, minsize);
728  assert(minsize <= polynomialdata->monomialssize);
729 
730  return SCIP_OKAY;
731 }
732 
733 /** adds an array of monomials to a polynomial */
734 static
736  BMS_BLKMEM* blkmem, /**< block memory of expression */
737  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
738  int nmonomials, /**< number of monomials to add */
739  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
740  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
741  )
742 {
743  int i;
744 
745  assert(blkmem != NULL);
746  assert(polynomialdata != NULL);
747  assert(monomials != NULL || nmonomials == 0);
748 
749  if( nmonomials == 0 )
750  return SCIP_OKAY;
751 
752  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials + nmonomials) );
753  assert(polynomialdata->monomialssize >= polynomialdata->nmonomials + nmonomials);
754 
755  if( copymonomials )
756  {
757  for( i = 0; i < nmonomials; ++i )
758  {
759  assert(monomials[i] != NULL); /*lint !e613*/
760  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials + i],
761  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
762  }
763  }
764  else
765  {
766  BMScopyMemoryArray(&polynomialdata->monomials[polynomialdata->nmonomials], monomials, nmonomials); /*lint !e866*/
767  }
768  polynomialdata->nmonomials += nmonomials;
769 
770  polynomialdata->sorted = (polynomialdata->nmonomials <= 1);
771 
772  return SCIP_OKAY;
773 }
774 
775 /** ensures that monomials of a polynomial are sorted */
776 static
778  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata /**< polynomial expression */
779  )
780 {
781  assert(polynomialdata != NULL);
782 
783  if( polynomialdata->sorted )
784  {
785 #ifndef NDEBUG
786  int i;
787 
788  /* a polynom with more than one monoms can only be sorted if its monoms are sorted */
789  for( i = 1; i < polynomialdata->nmonomials; ++i )
790  {
791  assert(polynomialdata->monomials[i-1]->sorted);
792  assert(polynomialdata->monomials[i]->sorted);
793  assert(monomialdataCompare(polynomialdata->monomials[i-1], polynomialdata->monomials[i]) <= 0);
794  }
795 #endif
796  return;
797  }
798 
799  if( polynomialdata->nmonomials > 0 )
800  SCIPsortPtr((void**)polynomialdata->monomials, monomialdataCompare, polynomialdata->nmonomials);
801 
802  polynomialdata->sorted = TRUE;
803 }
804 
805 /** merges monomials that differ only in coefficient into a single monomial
806  * eliminates monomials with coefficient between -eps and eps
807  */
808 static
810  BMS_BLKMEM* blkmem, /**< block memory */
811  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
812  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
813  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
814  )
815 {
816  int i;
817  int offset;
818  int oldnfactors;
819 
820  assert(polynomialdata != NULL);
821  assert(eps >= 0.0);
822 
823  polynomialdataSortMonomials(polynomialdata);
824 
825  /* merge monomials by adding their coefficients
826  * eliminate monomials with no factors or zero coefficient*/
827  offset = 0;
828  i = 0;
829  while( i + offset < polynomialdata->nmonomials )
830  {
831  if( offset > 0 )
832  {
833  assert(polynomialdata->monomials[i] == NULL);
834  assert(polynomialdata->monomials[i+offset] != NULL);
835  polynomialdata->monomials[i] = polynomialdata->monomials[i+offset];
836 #ifndef NDEBUG
837  polynomialdata->monomials[i+offset] = NULL;
838 #endif
839  }
840 
841  if( mergefactors )
842  {
843  oldnfactors = polynomialdata->monomials[i]->nfactors;
844  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i], eps);
845 
846  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
847  if( oldnfactors != polynomialdata->monomials[i]->nfactors )
848  polynomialdata->sorted = FALSE;
849  }
850 
851  while( i+offset+1 < polynomialdata->nmonomials )
852  {
853  assert(polynomialdata->monomials[i+offset+1] != NULL);
854  if( mergefactors )
855  {
856  oldnfactors = polynomialdata->monomials[i+offset+1]->nfactors;
857  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i+offset+1], eps);
858 
859  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
860  if( oldnfactors != polynomialdata->monomials[i+offset+1]->nfactors )
861  polynomialdata->sorted = FALSE;
862  }
863  if( monomialdataCompare((void*)polynomialdata->monomials[i], (void*)polynomialdata->monomials[i+offset+1]) != 0 )
864  break;
865  polynomialdata->monomials[i]->coef += polynomialdata->monomials[i+offset+1]->coef;
866  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i+offset+1]);
867  ++offset;
868  }
869 
870  if( polynomialdata->monomials[i]->nfactors == 0 )
871  {
872  /* constant monomial */
873  polynomialdata->constant += polynomialdata->monomials[i]->coef;
874  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
875  ++offset;
876  continue;
877  }
878 
879  if( EPSZ(polynomialdata->monomials[i]->coef, eps) )
880  {
881  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
882  ++offset;
883  continue;
884  }
885 
886  ++i;
887  }
888 
889 #ifndef NDEBUG
890  while( i < polynomialdata->nmonomials )
891  assert(polynomialdata->monomials[i++] == NULL);
892 #endif
893 
894  polynomialdata->nmonomials -= offset;
895 
896  if( EPSZ(polynomialdata->constant, eps) )
897  polynomialdata->constant = 0.0;
898 }
899 
900 /** multiplies each summand of a polynomial by a given constant */
901 static
903  BMS_BLKMEM* blkmem, /**< block memory */
904  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
905  SCIP_Real factor /**< constant factor */
906  )
907 {
908  int i;
909 
910  assert(polynomialdata != NULL);
911 
912  if( factor == 1.0 )
913  return;
914 
915  if( factor == 0.0 )
916  {
917  for( i = 0; i < polynomialdata->nmonomials; ++i )
918  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
919  polynomialdata->nmonomials = 0;
920  }
921  else
922  {
923  for( i = 0; i < polynomialdata->nmonomials; ++i )
924  SCIPexprChgMonomialCoef(polynomialdata->monomials[i], polynomialdata->monomials[i]->coef * factor);
925  }
926 
927  polynomialdata->constant *= factor;
928 }
929 
930 /** multiplies each summand of a polynomial by a given monomial */
931 static
933  BMS_BLKMEM* blkmem, /**< block memory */
934  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
935  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
936  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
937  )
938 {
939  int i;
940 
941  assert(blkmem != NULL);
942  assert(factor != NULL);
943  assert(polynomialdata != NULL);
944 
945  if( factor->nfactors == 0 )
946  {
947  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factor->coef);
948  return SCIP_OKAY;
949  }
950 
951  /* multiply each monomial by factor */
952  for( i = 0; i < polynomialdata->nmonomials; ++i )
953  {
954  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i], factor, childmap) );
955  }
956 
957  /* add new monomial for constant multiplied by factor */
958  if( polynomialdata->constant != 0.0 )
959  {
960  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
961  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
962  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[polynomialdata->nmonomials], factor, childmap) );
963  ++polynomialdata->nmonomials;
964  polynomialdata->sorted = FALSE;
965  polynomialdata->constant = 0.0;
966  }
967 
968  return SCIP_OKAY;
969 }
970 
971 /** multiplies a polynomial by a polynomial
972  * factors need to be different */
973 static
975  BMS_BLKMEM* blkmem, /**< block memory */
976  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
977  SCIP_EXPRDATA_POLYNOMIAL* factordata, /**< polynomial factor data */
978  int* childmap /**< map children in factor to children in polynomialdata, or NULL for 1:1 */
979  )
980 {
981  int i1;
982  int i2;
983  int orignmonomials;
984 
985  assert(blkmem != NULL);
986  assert(polynomialdata != NULL);
987  assert(factordata != NULL);
988  assert(polynomialdata != factordata);
989 
990  if( factordata->nmonomials == 0 )
991  {
992  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factordata->constant);
993  return SCIP_OKAY;
994  }
995 
996  if( factordata->nmonomials == 1 && factordata->constant == 0.0 )
997  {
998  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, polynomialdata, factordata->monomials[0], childmap) );
999  return SCIP_OKAY;
1000  }
1001 
1002  /* turn constant into a monomial, so we can assume below that constant is 0.0 */
1003  if( polynomialdata->constant != 0.0 )
1004  {
1005  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
1006  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
1007  ++polynomialdata->nmonomials;
1008  polynomialdata->sorted = FALSE;
1009  polynomialdata->constant = 0.0;
1010  }
1011 
1012  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials * (factordata->nmonomials + (factordata->constant == 0.0 ? 0 : 1))) );
1013 
1014  /* for each monomial in factordata (except the last, if factordata->constant is 0),
1015  * duplicate monomials from polynomialdata and multiply them by the monomial for factordata */
1016  orignmonomials = polynomialdata->nmonomials;
1017  for( i2 = 0; i2 < factordata->nmonomials; ++i2 )
1018  {
1019  /* add a copy of original monomials to end of polynomialdata's monomials array */
1020  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 */
1021  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, orignmonomials, polynomialdata->monomials, TRUE) );
1022  assert(polynomialdata->nmonomials == (i2+2) * orignmonomials);
1023 
1024  /* multiply each copied monomial by current monomial from factordata */
1025  for( i1 = (i2+1) * orignmonomials; i1 < (i2+2) * orignmonomials; ++i1 )
1026  {
1027  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1028  }
1029 
1030  if( factordata->constant == 0.0 && i2 == factordata->nmonomials - 2 )
1031  {
1032  ++i2;
1033  break;
1034  }
1035  }
1036 
1037  if( factordata->constant != 0.0 )
1038  {
1039  assert(i2 == factordata->nmonomials);
1040  /* multiply original monomials in polynomialdata by constant in factordata */
1041  for( i1 = 0; i1 < orignmonomials; ++i1 )
1042  SCIPexprChgMonomialCoef(polynomialdata->monomials[i1], polynomialdata->monomials[i1]->coef * factordata->constant);
1043  }
1044  else
1045  {
1046  assert(i2 == factordata->nmonomials - 1);
1047  /* multiply original monomials in polynomialdata by last monomial in factordata */
1048  for( i1 = 0; i1 < orignmonomials; ++i1 )
1049  {
1050  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1051  }
1052  }
1053 
1054  return SCIP_OKAY;
1055 }
1056 
1057 /** takes a power of a polynomial
1058  * exponent need to be an integer
1059  * polynomial need to be a monomial, if exponent is negative
1060  */
1061 static
1063  BMS_BLKMEM* blkmem, /**< block memory */
1064  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1065  int exponent /**< exponent of power operation */
1066  )
1067 {
1068  SCIP_EXPRDATA_POLYNOMIAL* factor;
1069  int i;
1070 
1071  assert(blkmem != NULL);
1072  assert(polynomialdata != NULL);
1073 
1074  if( exponent == 0 )
1075  {
1076  /* x^0 = 1, except if x = 0 */
1077  if( polynomialdata->nmonomials == 0 && polynomialdata->constant == 0.0 )
1078  {
1079  polynomialdata->constant = 0.0;
1080  }
1081  else
1082  {
1083  polynomialdata->constant = 1.0;
1084 
1085  for( i = 0; i < polynomialdata->nmonomials; ++i )
1086  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
1087  polynomialdata->nmonomials = 0;
1088  }
1089 
1090  return SCIP_OKAY;
1091  }
1092 
1093  if( exponent == 1 )
1094  return SCIP_OKAY;
1095 
1096  if( polynomialdata->nmonomials == 1 && polynomialdata->constant == 0.0 )
1097  {
1098  /* polynomial is a single monomial */
1099  SCIPexprMonomialPower(polynomialdata->monomials[0], exponent);
1100  return SCIP_OKAY;
1101  }
1102 
1103  if( polynomialdata->nmonomials == 0 )
1104  {
1105  /* polynomial is a constant */
1106  polynomialdata->constant = pow(polynomialdata->constant, (SCIP_Real)exponent);
1107  return SCIP_OKAY;
1108  }
1109 
1110  assert(exponent >= 2); /* negative exponents not allowed if more than one monom */
1111 
1112  /* todo improve, look how SCIPintervalPowerScalar in intervalarith.c does it */
1113 
1114  /* get copy of our polynomial */
1115  SCIP_CALL( polynomialdataCopy(blkmem, &factor, polynomialdata) );
1116 
1117  /* do repeated multiplication */
1118  for( i = 2; i <= exponent; ++i )
1119  {
1120  SCIP_CALL( polynomialdataMultiplyByPolynomial(blkmem, polynomialdata, factor, NULL) );
1121  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
1122  }
1123 
1124  /* free copy again */
1125  polynomialdataFree(blkmem, &factor);
1126 
1127  return SCIP_OKAY;
1128 }
1129 
1130 /** applies a mapping of child indices to the indices used in polynomial monomials */
1131 static
1133  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1134  int* childmap /**< mapping of child indices */
1135  )
1136 {
1137  SCIP_EXPRDATA_MONOMIAL* monomial;
1138  int i;
1139  int j;
1140 
1141  assert(polynomialdata != NULL);
1142 
1143  for( i = 0; i < polynomialdata->nmonomials; ++i )
1144  {
1145  monomial = polynomialdata->monomials[i];
1146  assert(monomial != NULL);
1147 
1148  for( j = 0; j < monomial->nfactors; ++j )
1149  {
1150  monomial->childidxs[j] = childmap[monomial->childidxs[j]];
1151  assert(monomial->childidxs[j] >= 0);
1152  }
1153  monomial->sorted = FALSE;
1154  }
1155 
1156  polynomialdata->sorted = FALSE;
1157 }
1158 
1159 /* replaces a factor in a monomial by a polynomial and expands the result */
1160 static
1162  BMS_BLKMEM* blkmem, /**< block memory data structure */
1163  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1164  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data where to expand a monomial */
1165  int monomialpos, /**< position of monomial which factor to expand */
1166  int factorpos, /**< position of factor in monomial to expand */
1167  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomial,/**< polynomial that should replace factor */
1168  int* childmap, /**< map of child indices in factorpolynomial to children of polynomial */
1169  int maxexpansionexponent,/**< maximal exponent for which polynomials (with > 1 summands) are expanded */
1170  SCIP_Bool* success /**< buffer to store whether expansion has been done */
1171  )
1172 {
1173  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomialcopy;
1174  SCIP_EXPRDATA_MONOMIAL* monomial;
1175  int i;
1176 
1177  assert(blkmem != NULL);
1178  assert(polynomialdata != NULL);
1179  assert(factorpolynomial != NULL);
1180  assert(childmap != NULL || factorpolynomial->nmonomials == 0);
1181  assert(success != NULL);
1182  assert(monomialpos >= 0);
1183  assert(monomialpos < polynomialdata->nmonomials);
1184  assert(factorpos >= 0);
1185 
1186  monomial = polynomialdata->monomials[monomialpos];
1187  assert(monomial != NULL);
1188  assert(factorpos < monomial->nfactors);
1189 
1190  *success = TRUE;
1191 
1192  if( factorpolynomial->nmonomials == 0 )
1193  {
1194  /* factorpolynomial is a constant */
1195 
1196  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && factorpolynomial->constant < 0.0 ) /*lint !e835*/
1197  {
1198  /* if polynomial is a negative constant and our exponent is not integer, then cannot do expansion */
1199  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", factorpolynomial->constant, monomial->exponents[factorpos]);
1200  *success = FALSE;
1201  return SCIP_OKAY;
1202  }
1203  monomial->coef *= pow(factorpolynomial->constant, monomial->exponents[factorpos]);
1204 
1205  /* move last factor to position factorpos */
1206  if( factorpos < monomial->nfactors-1 )
1207  {
1208  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1209  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1210  }
1211  --monomial->nfactors;
1212  monomial->sorted = FALSE;
1213  polynomialdata->sorted = FALSE;
1214 
1215  return SCIP_OKAY;
1216  }
1217 
1218  if( factorpolynomial->constant == 0.0 && factorpolynomial->nmonomials == 1 )
1219  {
1220  /* factorpolynomial is a single monomial */
1221  SCIP_EXPRDATA_MONOMIAL* factormonomial;
1222  int childidx;
1223  SCIP_Real exponent;
1224 
1225  factormonomial = factorpolynomial->monomials[0];
1226  assert(factormonomial != NULL);
1227 
1228  if( !EPSISINT(monomial->exponents[factorpos], 0.0) ) /*lint !e835*/
1229  {
1230  if( factormonomial->coef < 0.0 )
1231  {
1232  /* if coefficient of monomial is negative and our exponent is not integer, then do not do expansion
1233  * @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
1234  */
1235  *success = FALSE;
1236  return SCIP_OKAY;
1237  }
1238  if( factormonomial->nfactors > 1 )
1239  {
1240  /* @todo if there is an even number of factors in factormonomial that are negative, then they always multiply to something positive
1241  * however, we cannot expand them as below, since we cannot compute the single powers
1242  * since we do not have the bounds on the factors here, we skip expansion in this case
1243  * MINLPLib instances tls2,4,6 are examples where we are loosing here (do not recognize convexity)
1244  */
1245  *success = FALSE;
1246  return SCIP_OKAY;
1247  }
1248  }
1249 
1250  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + factormonomial->nfactors) );
1251 
1252  for( i = 0; i < factormonomial->nfactors; ++i )
1253  {
1254  childidx = childmap[factormonomial->childidxs[i]]; /*lint !e613*/
1255  /* can do this because monomial->exponents[factorpos] is assumed to be integer or factormonomial has positive coefficient and only one factor
1256  * thus, if factormonomial->exponents[i] is fractional, then we can assume that it's argument is positive
1257  */
1258  exponent = factormonomial->exponents[i] * monomial->exponents[factorpos];
1259  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
1260  }
1261 
1262  monomial->coef *= pow(factormonomial->coef, monomial->exponents[factorpos]);
1263 
1264  /* move last factor to position factorpos */
1265  if( factorpos < monomial->nfactors-1 )
1266  {
1267  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1268  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1269  }
1270  --monomial->nfactors;
1271  monomial->sorted = FALSE;
1272  polynomialdata->sorted = FALSE;
1273 
1274  return SCIP_OKAY;
1275  }
1276 
1277  /* if exponent is negative or fractional and the polynomial is not just a monomial, then we cannot do expansion */
1278  if( !EPSISINT(monomial->exponents[factorpos], 0.0) || monomial->exponents[factorpos] < 0.0 ) /*lint !e835*/
1279  {
1280  *success = FALSE;
1281  return SCIP_OKAY;
1282  }
1283 
1284  /* if exponent is too large, skip expansion */
1285  if( monomial->exponents[factorpos] > maxexpansionexponent )
1286  {
1287  *success = FALSE;
1288  return SCIP_OKAY;
1289  }
1290 
1291  /* check whether maximal degree of expansion would exceed maxexpansionexponent
1292  * that is, assume monomial is f1^a1 f2^a2 ... and we want to expand f1 = (g11^beta11 g12^beta12... + g21^beta21 g22^beta22 ... + ...)
1293  * then we do this only if all ai and all beta are > 0.0 and a1 max(beta11+beta12+..., beta21+beta22+..., ...) + a2 + ... < maxexpansionexponent
1294  * exception (there need to be one) is if monomial is just f1
1295  */
1296  if( maxexpansionexponent < INT_MAX && (monomial->nfactors > 1 || monomial->exponents[factorpos] != 1.0) )
1297  {
1298  SCIP_Real restdegree;
1299  SCIP_Real degree;
1300  int j;
1301 
1302  restdegree = -monomial->exponents[factorpos];
1303  for( i = 0; i < monomial->nfactors; ++i )
1304  {
1305  if( monomial->exponents[i] < 0.0 )
1306  {
1307  /* ai < 0.0 */
1308  SCIPdebugMessage("skip expansion because factor %d in monomial has negative exponent\n", i);
1309  *success = FALSE;
1310  return SCIP_OKAY;
1311  }
1312  restdegree += monomial->exponents[i];
1313  }
1314 
1315  for( i = 0; i < factorpolynomial->nmonomials; ++i )
1316  {
1317  degree = 0.0;
1318  for( j = 0; j < factorpolynomial->monomials[i]->nfactors; ++j )
1319  {
1320  if( factorpolynomial->monomials[i]->exponents[j] < 0.0 )
1321  {
1322  /* beta_ij < 0.0 */
1323  SCIPdebugMessage("skip expansion because %d'th factor in %d'th monomial of factorpolynomial is negative\n", i, j);
1324  *success = FALSE;
1325  return SCIP_OKAY;
1326  }
1327  degree += factorpolynomial->monomials[i]->exponents[j];
1328  }
1329  if( degree * monomial->exponents[factorpos] + restdegree > maxexpansionexponent )
1330  {
1331  /* (beta_i1+beta_i2+...)*monomial->exponents[factorpos] + rest > maxexpansion */
1332  SCIPdebugMessage("skip expansion because degree of %d'th monomial would yield degree %g > max = %d in expansion\n", i, degree * monomial->exponents[factorpos] + restdegree, maxexpansionexponent);
1333  *success = FALSE;
1334  return SCIP_OKAY;
1335  }
1336  }
1337  }
1338 
1339  /* create a copy of factor */
1340  SCIP_CALL( polynomialdataCopy(blkmem, &factorpolynomialcopy, factorpolynomial) );
1341  /* apply childmap to copy */
1342  polynomialdataApplyChildmap(factorpolynomialcopy, childmap);
1343  /* create power of factor */
1344  SCIP_CALL( polynomialdataPower(blkmem, factorpolynomialcopy, (int)EPSFLOOR(monomial->exponents[factorpos], 0.0)) ); /*lint !e835*/
1345 
1346  /* remove factor from monomial by moving last factor to position factorpos */
1347  if( factorpos < monomial->nfactors-1 )
1348  {
1349  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1350  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1351  }
1352  --monomial->nfactors;
1353  monomial->sorted = FALSE;
1354 
1355  /* multiply factor with this reduced monomial */
1356  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, factorpolynomialcopy, monomial, NULL) );
1357 
1358  /* remove monomial from polynomial and move last monomial to monomialpos */
1359  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[monomialpos]);
1360  if( monomialpos < polynomialdata->nmonomials-1 )
1361  polynomialdata->monomials[monomialpos] = polynomialdata->monomials[polynomialdata->nmonomials-1];
1362  --polynomialdata->nmonomials;
1363  polynomialdata->sorted = FALSE;
1364 
1365  /* add factorpolynomialcopy to polynomial */
1366  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, factorpolynomialcopy->nmonomials, factorpolynomialcopy->monomials, FALSE) );
1367  polynomialdata->constant += factorpolynomialcopy->constant;
1368 
1369  factorpolynomialcopy->nmonomials = 0;
1370  polynomialdataFree(blkmem, &factorpolynomialcopy);
1371 
1372  return SCIP_OKAY;
1373 }
1374 
1375 /**@} */
1376 
1377 /**@name Expression operand private methods */
1378 /**@{ */
1379 
1380 /** a default implementation of expression interval evaluation that always gives a correct result */
1381 static
1382 SCIP_DECL_EXPRINTEVAL( exprevalIntDefault )
1383 {
1384  SCIPintervalSetEntire(infinity, result);
1385 
1386  return SCIP_OKAY;
1387 } /*lint !e715*/
1388 
1389 /** a default implementation of expression curvature check that always gives a correct result */
1390 static
1391 SCIP_DECL_EXPRCURV( exprcurvDefault )
1392 {
1393  *result = SCIP_EXPRCURV_UNKNOWN;
1394 
1395  return SCIP_OKAY;
1396 } /*lint !e715*/
1397 
1398 /** point evaluation for EXPR_VAR */
1399 static
1400 SCIP_DECL_EXPREVAL( exprevalVar )
1401 {
1402  assert(result != NULL);
1403  assert(varvals != NULL);
1404 
1405  *result = varvals[opdata.intval];
1406 
1407  return SCIP_OKAY;
1408 } /*lint !e715*/
1409 
1410 /** interval evaluation for EXPR_VAR */
1411 static
1412 SCIP_DECL_EXPRINTEVAL( exprevalIntVar )
1413 {
1414  assert(result != NULL);
1415  assert(varvals != NULL);
1416 
1417  *result = varvals[opdata.intval];
1418 
1419  return SCIP_OKAY;
1420 } /*lint !e715*/
1421 
1422 /** curvature for EXPR_VAR */
1423 static
1424 SCIP_DECL_EXPRCURV( exprcurvVar )
1425 {
1426  assert(result != NULL);
1427 
1428  *result = SCIP_EXPRCURV_LINEAR;
1429 
1430  return SCIP_OKAY;
1431 } /*lint !e715*/
1432 
1433 /** point evaluation for EXPR_CONST */
1434 static
1435 SCIP_DECL_EXPREVAL( exprevalConst )
1436 {
1437  assert(result != NULL);
1438 
1439  *result = opdata.dbl;
1440 
1441  return SCIP_OKAY;
1442 } /*lint !e715*/
1443 
1444 /** interval evaluation for EXPR_CONST */
1445 static
1446 SCIP_DECL_EXPRINTEVAL( exprevalIntConst )
1447 {
1448  assert(result != NULL);
1449 
1450  SCIPintervalSet(result, opdata.dbl);
1451 
1452  return SCIP_OKAY;
1453 } /*lint !e715*/
1454 
1455 /** curvature for EXPR_CONST */
1456 static
1457 SCIP_DECL_EXPRCURV( exprcurvConst )
1458 {
1459  assert(result != NULL);
1460 
1461  *result = SCIP_EXPRCURV_LINEAR;
1462 
1463  return SCIP_OKAY;
1464 } /*lint !e715*/
1465 
1466 /** point evaluation for EXPR_PARAM */
1467 static
1468 SCIP_DECL_EXPREVAL( exprevalParam )
1469 {
1470  assert(result != NULL);
1471  assert(paramvals != NULL );
1472 
1473  *result = paramvals[opdata.intval];
1474 
1475  return SCIP_OKAY;
1476 } /*lint !e715*/
1477 
1478 /** interval evaluation for EXPR_PARAM */
1479 static
1480 SCIP_DECL_EXPRINTEVAL( exprevalIntParam )
1481 {
1482  assert(result != NULL);
1483  assert(paramvals != NULL );
1484 
1485  SCIPintervalSet(result, paramvals[opdata.intval]);
1486 
1487  return SCIP_OKAY;
1488 } /*lint !e715*/
1489 
1490 /** curvature for EXPR_PARAM */
1491 static
1492 SCIP_DECL_EXPRCURV( exprcurvParam )
1493 {
1494  assert(result != NULL);
1495 
1496  *result = SCIP_EXPRCURV_LINEAR;
1497 
1498  return SCIP_OKAY;
1499 } /*lint !e715*/
1500 
1501 /** point evaluation for EXPR_PLUS */
1502 static
1503 SCIP_DECL_EXPREVAL( exprevalPlus )
1504 {
1505  assert(result != NULL);
1506  assert(argvals != NULL);
1507 
1508  *result = argvals[0] + argvals[1];
1509 
1510  return SCIP_OKAY;
1511 } /*lint !e715*/
1512 
1513 /** interval evaluation for EXPR_PLUS */
1514 static
1515 SCIP_DECL_EXPRINTEVAL( exprevalIntPlus )
1516 {
1517  assert(result != NULL);
1518  assert(argvals != NULL);
1519 
1520  SCIPintervalAdd(infinity, result, argvals[0], argvals[1]);
1521 
1522  return SCIP_OKAY;
1523 } /*lint !e715*/
1524 
1525 /** curvature for EXPR_PLUS */
1526 static
1527 SCIP_DECL_EXPRCURV( exprcurvPlus )
1528 {
1529  assert(result != NULL);
1530  assert(argcurv != NULL);
1531 
1532  *result = SCIPexprcurvAdd(argcurv[0], argcurv[1]);
1533 
1534  return SCIP_OKAY;
1535 } /*lint !e715*/
1536 
1537 /** point evaluation for EXPR_MINUS */
1538 static
1539 SCIP_DECL_EXPREVAL( exprevalMinus )
1540 {
1541  assert(result != NULL);
1542  assert(argvals != NULL);
1543 
1544  *result = argvals[0] - argvals[1];
1545 
1546  return SCIP_OKAY;
1547 } /*lint !e715*/
1548 
1549 /** interval evaluation for EXPR_MINUS */
1550 static
1551 SCIP_DECL_EXPRINTEVAL( exprevalIntMinus )
1552 {
1553  assert(result != NULL);
1554  assert(argvals != NULL);
1555 
1556  SCIPintervalSub(infinity, result, argvals[0], argvals[1]);
1557 
1558  return SCIP_OKAY;
1559 } /*lint !e715*/
1560 
1561 /** curvature for EXPR_MINUS */
1562 static
1563 SCIP_DECL_EXPRCURV( exprcurvMinus )
1564 {
1565  assert(result != NULL);
1566  assert(argcurv != NULL);
1567 
1568  *result = SCIPexprcurvAdd(argcurv[0], SCIPexprcurvNegate(argcurv[1]));
1569 
1570  return SCIP_OKAY;
1571 } /*lint !e715*/
1572 
1573 /** point evaluation for EXPR_MUL */
1574 static
1575 SCIP_DECL_EXPREVAL( exprevalMult )
1576 {
1577  assert(result != NULL);
1578  assert(argvals != NULL);
1579 
1580  *result = argvals[0] * argvals[1];
1581 
1582  return SCIP_OKAY;
1583 } /*lint !e715*/
1584 
1585 /** interval evaluation for EXPR_MUL */
1586 static
1587 SCIP_DECL_EXPRINTEVAL( exprevalIntMult )
1588 {
1589  assert(result != NULL);
1590  assert(argvals != NULL);
1591 
1592  SCIPintervalMul(infinity, result, argvals[0], argvals[1]);
1593 
1594  return SCIP_OKAY;
1595 } /*lint !e715*/
1596 
1597 /** curvature for EXPR_MUL */
1598 static
1599 SCIP_DECL_EXPRCURV( exprcurvMult )
1600 {
1601  assert(result != NULL);
1602  assert(argcurv != NULL);
1603  assert(argbounds != NULL);
1604 
1605  /* if one factor is constant, then product is
1606  * - linear, if constant is 0.0
1607  * - same curvature as other factor, if constant is positive
1608  * - negated curvature of other factor, if constant is negative
1609  *
1610  * if both factors are not constant, then product may not be convex nor concave
1611  */
1612  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1613  {
1614  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1615  }
1616  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1617  {
1618  *result = SCIPexprcurvMultiply(argbounds[0].inf, argcurv[1]);
1619  }
1620  else
1621  {
1622  *result = SCIP_EXPRCURV_UNKNOWN;
1623  }
1624 
1625  return SCIP_OKAY;
1626 } /*lint !e715*/
1627 
1628 /** point evaluation for EXPR_DIV */
1629 static
1630 SCIP_DECL_EXPREVAL( exprevalDiv )
1631 {
1632  assert(result != NULL);
1633  assert(argvals != NULL);
1634 
1635  *result = argvals[0] / argvals[1];
1636 
1637  return SCIP_OKAY;
1638 } /*lint !e715*/
1639 
1640 /** interval evaluation for EXPR_DIV */
1641 static
1642 SCIP_DECL_EXPRINTEVAL( exprevalIntDiv )
1643 {
1644  assert(result != NULL);
1645  assert(argvals != NULL);
1646 
1647  SCIPintervalDiv(infinity, result, argvals[0], argvals[1]);
1648 
1649  return SCIP_OKAY;
1650 } /*lint !e715*/
1651 
1652 /** curvature for EXPR_DIV */
1653 static
1654 SCIP_DECL_EXPRCURV( exprcurvDiv )
1655 {
1656  assert(result != NULL);
1657  assert(argcurv != NULL);
1658  assert(argbounds != NULL);
1659 
1660  /* if denominator is constant, then quotient has curvature sign(denominator) * curv(nominator)
1661  *
1662  * if nominator is a constant, then quotient is
1663  * - sign(nominator) * convex, if denominator is concave and positive
1664  * - sign(nominator) * concave, if denominator is convex and negative
1665  *
1666  * if denominator is positive but convex, then we don't know, e.g.,
1667  * - 1/x^2 is convex for x>=0
1668  * - 1/(1+(x-1)^2) is neither convex nor concave for x >= 0
1669  *
1670  * if both nominator and denominator are not constant, then quotient may not be convex nor concave
1671  */
1672  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1673  {
1674  /* denominator is constant */
1675  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1676  }
1677  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1678  {
1679  /* nominator is constant */
1680  if( argbounds[1].inf >= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
1681  {
1682  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONVEX);
1683  }
1684  else if( argbounds[1].sup <= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
1685  {
1686  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONCAVE);
1687  }
1688  else
1689  {
1690  *result = SCIP_EXPRCURV_UNKNOWN;
1691  }
1692  }
1693  else
1694  {
1695  /* denominator and nominator not constant */
1696  *result = SCIP_EXPRCURV_UNKNOWN;
1697  }
1698 
1699  return SCIP_OKAY;
1700 } /*lint !e715*/
1701 
1702 /** point evaluation for EXPR_SQUARE */
1703 static
1704 SCIP_DECL_EXPREVAL( exprevalSquare )
1705 {
1706  assert(result != NULL);
1707  assert(argvals != NULL);
1708 
1709  *result = argvals[0] * argvals[0];
1710 
1711  return SCIP_OKAY;
1712 } /*lint !e715*/
1713 
1714 /** interval evaluation for EXPR_SQUARE */
1715 static
1716 SCIP_DECL_EXPRINTEVAL( exprevalIntSquare )
1717 {
1718  assert(result != NULL);
1719  assert(argvals != NULL);
1720 
1721  SCIPintervalSquare(infinity, result, argvals[0]);
1722 
1723  return SCIP_OKAY;
1724 } /*lint !e715*/
1725 
1726 /** curvature for EXPR_SQUARE */
1727 static
1728 SCIP_DECL_EXPRCURV( exprcurvSquare )
1729 {
1730  assert(result != NULL);
1731  assert(argcurv != NULL);
1732  assert(argbounds != NULL);
1733 
1734  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], 2.0);
1735 
1736  return SCIP_OKAY;
1737 } /*lint !e715*/
1738 
1739 /** point evaluation for EXPR_SQRT */
1740 static
1741 SCIP_DECL_EXPREVAL( exprevalSquareRoot )
1742 {
1743  assert(result != NULL);
1744  assert(argvals != NULL);
1745 
1746  *result = sqrt(argvals[0]);
1747 
1748  return SCIP_OKAY;
1749 } /*lint !e715*/
1750 
1751 /** interval evaluation for EXPR_SQRT */
1752 static
1753 SCIP_DECL_EXPRINTEVAL( exprevalIntSquareRoot )
1754 {
1755  assert(result != NULL);
1756  assert(argvals != NULL);
1757 
1758  SCIPintervalSquareRoot(infinity, result, argvals[0]);
1759 
1760  return SCIP_OKAY;
1761 } /*lint !e715*/
1762 
1763 /** curvature for EXPR_SQRT */
1764 static
1765 SCIP_DECL_EXPRCURV( exprcurvSquareRoot )
1766 {
1767  assert(result != NULL);
1768  assert(argcurv != NULL);
1769 
1770  /* square-root is concave, if child is concave
1771  * otherwise, we don't know
1772  */
1773 
1774  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
1775  *result = SCIP_EXPRCURV_CONCAVE;
1776  else
1777  *result = SCIP_EXPRCURV_UNKNOWN;
1778 
1779  return SCIP_OKAY;
1780 } /*lint !e715*/
1781 
1782 /** point evaluation for EXPR_REALPOWER */
1783 static
1784 SCIP_DECL_EXPREVAL( exprevalRealPower )
1785 {
1786  assert(result != NULL);
1787  assert(argvals != NULL);
1788 
1789  *result = pow(argvals[0], opdata.dbl);
1790 
1791  return SCIP_OKAY;
1792 } /*lint !e715*/
1793 
1794 /** interval evaluation for EXPR_REALPOWER */
1795 static
1796 SCIP_DECL_EXPRINTEVAL( exprevalIntRealPower )
1797 {
1798  assert(result != NULL);
1799  assert(argvals != NULL);
1800 
1801  SCIPintervalPowerScalar(infinity, result, argvals[0], opdata.dbl);
1802 
1803  return SCIP_OKAY;
1804 } /*lint !e715*/
1805 
1806 /** curvature for EXPR_REALPOWER */
1807 static
1808 SCIP_DECL_EXPRCURV( exprcurvRealPower )
1809 {
1810  assert(result != NULL);
1811  assert(argcurv != NULL);
1812  assert(argbounds != NULL);
1813 
1814  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], opdata.dbl);
1815 
1816  return SCIP_OKAY;
1817 } /*lint !e715*/
1818 
1819 /** point evaluation for EXPR_INTPOWER */
1820 static
1821 SCIP_DECL_EXPREVAL( exprevalIntPower )
1822 {
1823  assert(result != NULL);
1824  assert(argvals != NULL);
1825 
1826  switch( opdata.intval )
1827  {
1828  case -1:
1829  *result = 1.0 / argvals[0];
1830  return SCIP_OKAY;
1831 
1832  case 0:
1833  *result = 1.0;
1834  return SCIP_OKAY;
1835 
1836  case 1:
1837  *result = argvals[0];
1838  return SCIP_OKAY;
1839 
1840  case 2:
1841  *result = argvals[0] * argvals[0];
1842  return SCIP_OKAY;
1843 
1844  default:
1845  *result = pow(argvals[0], (SCIP_Real)opdata.intval);
1846  }
1847 
1848  return SCIP_OKAY;
1849 } /*lint !e715*/
1850 
1851 /** interval evaluation for EXPR_INTPOWER */
1852 static
1853 SCIP_DECL_EXPRINTEVAL( exprevalIntIntPower )
1854 {
1855  assert(result != NULL);
1856  assert(argvals != NULL);
1857 
1858  SCIPintervalPowerScalar(infinity, result, argvals[0], (SCIP_Real)opdata.intval);
1859 
1860  return SCIP_OKAY;
1861 } /*lint !e715*/
1862 
1863 /** curvature for EXPR_INTPOWER */
1864 static
1865 SCIP_DECL_EXPRCURV( exprcurvIntPower )
1866 {
1867  assert(result != NULL);
1868  assert(argcurv != NULL);
1869  assert(argbounds != NULL);
1870 
1871  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], (SCIP_Real)opdata.intval);
1872 
1873  return SCIP_OKAY;
1874 } /*lint !e715*/
1875 
1876 /** point evaluation for EXPR_SIGNPOWER */
1877 static
1878 SCIP_DECL_EXPREVAL( exprevalSignPower )
1879 {
1880  assert(result != NULL);
1881  assert(argvals != NULL);
1882 
1883  if( argvals[0] > 0 )
1884  *result = pow( argvals[0], opdata.dbl);
1885  else
1886  *result = -pow(-argvals[0], opdata.dbl);
1887 
1888  return SCIP_OKAY;
1889 } /*lint !e715*/
1890 
1891 /** interval evaluation for EXPR_SIGNPOWER */
1892 static
1893 SCIP_DECL_EXPRINTEVAL( exprevalIntSignPower )
1894 {
1895  assert(result != NULL);
1896  assert(argvals != NULL);
1897 
1898  SCIPintervalSignPowerScalar(infinity, result, argvals[0], opdata.dbl);
1899 
1900  return SCIP_OKAY;
1901 } /*lint !e715*/
1902 
1903 /** curvature for EXPR_SIGNPOWER */
1904 static
1905 SCIP_DECL_EXPRCURV( exprcurvSignPower )
1906 {
1907  SCIP_INTERVAL tmp;
1908  SCIP_EXPRCURV left;
1909  SCIP_EXPRCURV right;
1910 
1911  assert(result != NULL);
1912  assert(argcurv != NULL);
1913  assert(argbounds != NULL);
1914 
1915  /* for x <= 0, signpower(x,c) = -(-x)^c
1916  * for x >= 0, signpower(x,c) = ( x)^c
1917  *
1918  * thus, get curvatures for both parts and "intersect" them
1919  */
1920 
1921  if( argbounds[0].inf < 0 )
1922  {
1923  SCIPintervalSetBounds(&tmp, 0.0, -argbounds[0].inf);
1924  left = SCIPexprcurvNegate(SCIPexprcurvPower(tmp, SCIPexprcurvNegate(argcurv[0]), opdata.dbl));
1925  }
1926  else
1927  {
1928  left = SCIP_EXPRCURV_LINEAR;
1929  }
1930 
1931  if( argbounds[0].sup > 0 )
1932  {
1933  SCIPintervalSetBounds(&tmp, 0.0, argbounds[0].sup);
1934  right = SCIPexprcurvPower(tmp, argcurv[0], opdata.dbl);
1935  }
1936  else
1937  {
1938  right = SCIP_EXPRCURV_LINEAR;
1939  }
1940 
1941  *result = (SCIP_EXPRCURV) (left & right);
1942 
1943  return SCIP_OKAY;
1944 } /*lint !e715*/
1945 
1946 /** point evaluation for EXPR_EXP */
1947 static
1948 SCIP_DECL_EXPREVAL( exprevalExp )
1949 {
1950  assert(result != NULL);
1951  assert(argvals != NULL);
1952 
1953  *result = exp(argvals[0]);
1954 
1955  return SCIP_OKAY;
1956 } /*lint !e715*/
1957 
1958 /** interval evaluation for EXPR_EXP */
1959 static
1960 SCIP_DECL_EXPRINTEVAL( exprevalIntExp )
1961 {
1962  assert(result != NULL);
1963  assert(argvals != NULL);
1964 
1965  SCIPintervalExp(infinity, result, argvals[0]);
1966 
1967  return SCIP_OKAY;
1968 } /*lint !e715*/
1969 
1970 /** curvature for EXPR_EXP */
1971 static
1972 SCIP_DECL_EXPRCURV( exprcurvExp )
1973 {
1974  assert(result != NULL);
1975  assert(argcurv != NULL);
1976 
1977  /* expression is convex if child is convex
1978  * otherwise, we don't know
1979  */
1980  if( argcurv[0] & SCIP_EXPRCURV_CONVEX )
1981  *result = SCIP_EXPRCURV_CONVEX;
1982  else
1983  *result = SCIP_EXPRCURV_UNKNOWN;
1984 
1985  return SCIP_OKAY;
1986 } /*lint !e715*/
1987 
1988 /** point evaluation for EXPR_LOG */
1989 static
1990 SCIP_DECL_EXPREVAL( exprevalLog )
1991 {
1992  assert(result != NULL);
1993  assert(argvals != NULL);
1994 
1995  *result = log(argvals[0]);
1996 
1997  return SCIP_OKAY;
1998 } /*lint !e715*/
1999 
2000 /** interval evaluation for EXPR_LOG */
2001 static
2002 SCIP_DECL_EXPRINTEVAL( exprevalIntLog )
2003 {
2004  assert(result != NULL);
2005  assert(argvals != NULL);
2006 
2007  SCIPintervalLog(infinity, result, argvals[0]);
2008 
2009  return SCIP_OKAY;
2010 } /*lint !e715*/
2011 
2012 /** curvature for EXPR_LOG */
2013 static
2014 SCIP_DECL_EXPRCURV( exprcurvLog )
2015 {
2016  assert(result != NULL);
2017  assert(argcurv != NULL);
2018 
2019  /* expression is concave if child is concave
2020  * otherwise, we don't know
2021  */
2022  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
2023  *result = SCIP_EXPRCURV_CONCAVE;
2024  else
2025  *result = SCIP_EXPRCURV_UNKNOWN;
2026 
2027  return SCIP_OKAY;
2028 } /*lint !e715*/
2029 
2030 /** point evaluation for EXPR_SIN */
2031 static
2032 SCIP_DECL_EXPREVAL( exprevalSin )
2033 {
2034  assert(result != NULL);
2035  assert(argvals != NULL);
2036 
2037  *result = sin(argvals[0]);
2038 
2039  return SCIP_OKAY;
2040 } /*lint !e715*/
2041 
2042 /** interval evaluation for EXPR_SIN */
2043 static
2044 SCIP_DECL_EXPRINTEVAL( exprevalIntSin )
2045 {
2046  assert(result != NULL);
2047  assert(argvals != NULL);
2048 
2049  /* @todo implement SCIPintervalSin */
2050  SCIPerrorMessage("exprevalSinInt gives only trivial bounds so far\n");
2051  SCIPintervalSetBounds(result, -1.0, 1.0);
2052 
2053  return SCIP_OKAY;
2054 } /*lint !e715*/
2055 
2056 /* @todo implement exprcurvSin */
2057 #define exprcurvSin exprcurvDefault
2058 
2059 /** point evaluation for EXPR_COS */
2060 static
2061 SCIP_DECL_EXPREVAL( exprevalCos )
2062 {
2063  assert(result != NULL);
2064  assert(argvals != NULL);
2065 
2066  *result = cos(argvals[0]);
2067 
2068  return SCIP_OKAY;
2069 } /*lint !e715*/
2070 
2071 /** interval evaluation for EXPR_COS */
2072 static
2073 SCIP_DECL_EXPRINTEVAL( exprevalIntCos )
2074 {
2075  assert(result != NULL);
2076  assert(argvals != NULL);
2077 
2078  /* @todo implement SCIPintervalCos */
2079  SCIPerrorMessage("exprevalCosInt gives only trivial bounds so far\n");
2080  SCIPintervalSetBounds(result, -1.0, 1.0);
2081 
2082  return SCIP_OKAY;
2083 } /*lint !e715*/
2084 
2085 /* @todo implement exprcurvCos */
2086 #define exprcurvCos exprcurvDefault
2087 
2088 /** point evaluation for EXPR_TAN */
2089 static
2090 SCIP_DECL_EXPREVAL( exprevalTan )
2091 {
2092  assert(result != NULL);
2093  assert(argvals != NULL);
2094 
2095  *result = tan(argvals[0]);
2096 
2097  return SCIP_OKAY;
2098 } /*lint !e715*/
2099 
2100 /* @todo implement SCIPintervalTan */
2101 #define exprevalIntTan exprevalIntDefault
2102 
2103 /* @todo implement exprcurvTan */
2104 #define exprcurvTan exprcurvDefault
2105 
2106 /* erf and erfi do not seem to exists on every system, and we cannot really handle them anyway, so they are currently disabled */
2107 #if 0
2108 static
2109 SCIP_DECL_EXPREVAL( exprevalErf )
2110 {
2111  assert(result != NULL);
2112  assert(argvals != NULL);
2113 
2114  *result = erf(argvals[0]);
2115 
2116  return SCIP_OKAY;
2117 } /*lint !e715*/
2118 
2119 /* @todo implement SCIPintervalErf */
2120 #define exprevalIntErf exprevalIntDefault
2121 
2122 /* @todo implement SCIPintervalErf */
2123 #define exprcurvErf exprcurvDefault
2124 
2125 static
2126 SCIP_DECL_EXPREVAL( exprevalErfi )
2127 {
2128  assert(result != NULL);
2129  assert(argvals != NULL);
2130 
2131  /* @TODO implement erfi evaluation */
2132  SCIPerrorMessage("erfi not implemented");
2133 
2134  return SCIP_ERROR;
2135 } /*lint !e715*/
2136 
2137 /* @todo implement SCIPintervalErfi */
2138 #define exprevalIntErfi NULL
2139 
2140 #define exprcurvErfi exprcurvDefault
2141 #endif
2142 
2143 /** point evaluation for EXPR_MIN */
2144 static
2145 SCIP_DECL_EXPREVAL( exprevalMin )
2146 {
2147  assert(result != NULL);
2148  assert(argvals != NULL);
2149 
2150  *result = MIN(argvals[0], argvals[1]);
2151 
2152  return SCIP_OKAY;
2153 } /*lint !e715*/
2154 
2155 /** interval evaluation for EXPR_MIN */
2156 static
2157 SCIP_DECL_EXPRINTEVAL( exprevalIntMin )
2158 {
2159  assert(result != NULL);
2160  assert(argvals != NULL);
2161 
2162  SCIPintervalMin(result, argvals[0], argvals[1]);
2163 
2164  return SCIP_OKAY;
2165 } /*lint !e715*/
2166 
2167 /** curvature for EXPR_MIN */
2168 static
2169 SCIP_DECL_EXPRCURV( exprcurvMin )
2170 {
2171  assert(result != NULL);
2172  assert(argcurv != NULL);
2173 
2174  /* the minimum of two concave functions is concave
2175  * otherwise, we don't know
2176  */
2177 
2178  if( (argcurv[0] & SCIP_EXPRCURV_CONCAVE) && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
2179  *result = SCIP_EXPRCURV_CONCAVE;
2180  else
2181  *result = SCIP_EXPRCURV_UNKNOWN;
2182 
2183  return SCIP_OKAY;
2184 } /*lint !e715*/
2185 
2186 /** point evaluation for EXPR_MAX */
2187 static
2188 SCIP_DECL_EXPREVAL( exprevalMax )
2189 {
2190  assert(result != NULL);
2191  assert(argvals != NULL);
2192 
2193  *result = MAX(argvals[0], argvals[1]);
2194 
2195  return SCIP_OKAY;
2196 } /*lint !e715*/
2197 
2198 /** interval evaluation for EXPR_MAX */
2199 static
2200 SCIP_DECL_EXPRINTEVAL( exprevalIntMax )
2201 {
2202  assert(result != NULL);
2203  assert(argvals != NULL);
2204 
2205  SCIPintervalMax(result, argvals[0], argvals[1]);
2206 
2207  return SCIP_OKAY;
2208 } /*lint !e715*/
2209 
2210 /** curvature for EXPR_MAX */
2211 static
2212 SCIP_DECL_EXPRCURV( exprcurvMax )
2213 {
2214  assert(result != NULL);
2215  assert(argcurv != NULL);
2216 
2217  /* the maximum of two convex functions is convex
2218  * otherwise, we don't know
2219  */
2220  if( (argcurv[0] & SCIP_EXPRCURV_CONVEX) && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
2221  *result = SCIP_EXPRCURV_CONVEX;
2222  else
2223  *result = SCIP_EXPRCURV_UNKNOWN;
2224 
2225  return SCIP_OKAY;
2226 } /*lint !e715*/
2227 
2228 /** point evaluation for EXPR_ABS */
2229 static
2230 SCIP_DECL_EXPREVAL( exprevalAbs )
2231 {
2232  assert(result != NULL);
2233  assert(argvals != NULL);
2234 
2235  *result = ABS(argvals[0]);
2236 
2237  return SCIP_OKAY;
2238 } /*lint !e715*/
2239 
2240 /** interval evaluation for EXPR_ABS */
2241 static
2242 SCIP_DECL_EXPRINTEVAL( exprevalIntAbs )
2243 {
2244  assert(result != NULL);
2245  assert(argvals != NULL);
2246 
2247  SCIPintervalAbs(result, argvals[0]);
2248 
2249  return SCIP_OKAY;
2250 } /*lint !e715*/
2251 
2252 /** curvature for EXPR_ABS */
2253 static
2254 SCIP_DECL_EXPRCURV( exprcurvAbs )
2255 {
2256  assert(result != NULL);
2257  assert(argcurv != NULL);
2258  assert(argbounds != NULL);
2259 
2260  /* if child is only negative, then abs(child) = -child
2261  * if child is only positive, then abs(child) = child
2262  * if child is both positive and negative, but also linear, then abs(child) is convex
2263  * otherwise, we don't know
2264  */
2265  if( argbounds[0].sup <= 0.0 )
2266  *result = SCIPexprcurvMultiply(-1.0, argcurv[0]);
2267  else if( argbounds[0].inf >= 0.0 )
2268  *result = argcurv[0];
2269  else if( argcurv[0] == SCIP_EXPRCURV_LINEAR )
2270  *result = SCIP_EXPRCURV_CONVEX;
2271  else
2272  *result = SCIP_EXPRCURV_UNKNOWN;
2273 
2274  return SCIP_OKAY;
2275 } /*lint !e715*/
2276 
2277 /** point evaluation for EXPR_SIGN */
2278 static
2279 SCIP_DECL_EXPREVAL( exprevalSign )
2280 {
2281  assert(result != NULL);
2282  assert(argvals != NULL);
2283 
2284  *result = SIGN(argvals[0]);
2285 
2286  return SCIP_OKAY;
2287 } /*lint !e715*/
2288 
2289 /** interval evaluation for EXPR_SIGN */
2290 static
2291 SCIP_DECL_EXPRINTEVAL( exprevalIntSign )
2292 {
2293  assert(result != NULL);
2294  assert(argvals != NULL);
2295 
2296  SCIPintervalSign(result, argvals[0]);
2297 
2298  return SCIP_OKAY;
2299 } /*lint !e715*/
2300 
2301 /** curvature for EXPR_SIGN */
2302 static
2303 SCIP_DECL_EXPRCURV( exprcurvSign )
2304 {
2305  assert(result != NULL);
2306  assert(argbounds != NULL);
2307 
2308  /* if sign of child is clear, then sign is linear
2309  * otherwise, we don't know
2310  */
2311  if( argbounds[0].sup <= 0.0 || argbounds[0].inf >= 0.0 )
2312  *result = SCIP_EXPRCURV_LINEAR;
2313  else
2314  *result = SCIP_EXPRCURV_UNKNOWN;
2315 
2316  return SCIP_OKAY;
2317 } /*lint !e715*/
2318 
2319 /** point evaluation for EXPR_SUM */
2320 static
2321 SCIP_DECL_EXPREVAL( exprevalSum )
2322 {
2323  int i;
2324 
2325  assert(result != NULL);
2326  assert(argvals != NULL);
2327 
2328  *result = 0.0;
2329  for( i = 0; i < nargs; ++i )
2330  *result += argvals[i];
2331 
2332  return SCIP_OKAY;
2333 } /*lint !e715*/
2334 
2335 /** interval evaluation for EXPR_SUM */
2336 static
2337 SCIP_DECL_EXPRINTEVAL( exprevalIntSum )
2338 {
2339  int i;
2340 
2341  assert(result != NULL);
2342  assert(argvals != NULL);
2343 
2344  SCIPintervalSet(result, 0.0);
2345 
2346  for( i = 0; i < nargs; ++i )
2347  SCIPintervalAdd(infinity, result, *result, argvals[i]);
2348 
2349  return SCIP_OKAY;
2350 } /*lint !e715*/
2351 
2352 /** curvature for EXPR_SUM */
2353 static
2354 SCIP_DECL_EXPRCURV( exprcurvSum )
2355 {
2356  int i;
2357 
2358  assert(result != NULL);
2359  assert(argcurv != NULL);
2360 
2361  *result = SCIP_EXPRCURV_LINEAR;
2362 
2363  for( i = 0; i < nargs; ++i )
2364  {
2365  *result = SCIPexprcurvAdd(*result, argcurv[i]);
2366  }
2367 
2368  return SCIP_OKAY;
2369 } /*lint !e715*/
2370 
2371 /** point evaluation for EXPR_PRODUCT */
2372 static
2373 SCIP_DECL_EXPREVAL( exprevalProduct )
2374 {
2375  int i;
2376 
2377  assert(result != NULL);
2378  assert(argvals != NULL);
2379 
2380  *result = 1.0;
2381  for( i = 0; i < nargs; ++i )
2382  *result *= argvals[i];
2383 
2384  return SCIP_OKAY;
2385 } /*lint !e715*/
2386 
2387 /** interval evaluation for EXPR_PRODUCT */
2388 static
2389 SCIP_DECL_EXPRINTEVAL( exprevalIntProduct )
2390 {
2391  int i;
2392 
2393  assert(result != NULL);
2394  assert(argvals != NULL);
2395 
2396  SCIPintervalSet(result, 1.0);
2397 
2398  for( i = 0; i < nargs; ++i )
2399  SCIPintervalMul(infinity, result, *result, argvals[i]);
2400 
2401  return SCIP_OKAY;
2402 } /*lint !e715*/
2403 
2404 /** curvature for EXPR_PRODUCT */
2405 static
2406 SCIP_DECL_EXPRCURV( exprcurvProduct )
2407 {
2408  SCIP_Bool hadnonconst;
2409  SCIP_Real constants;
2410  int i;
2411 
2412  assert(result != NULL);
2413  assert(argcurv != NULL);
2414  assert(argbounds != NULL);
2415 
2416  /* if all factors are constant, then product is linear (even constant)
2417  * if only one factor is not constant, then product is curvature of this factor, multiplied by sign of product of remaining factors
2418  */
2419  *result = SCIP_EXPRCURV_LINEAR;
2420  hadnonconst = FALSE;
2421  constants = 1.0;
2422 
2423  for( i = 0; i < nargs; ++i )
2424  {
2425  if( argbounds[i].inf == argbounds[i].sup ) /*lint !e777*/
2426  {
2427  constants *= argbounds[i].inf;
2428  }
2429  else if( !hadnonconst )
2430  {
2431  /* first non-constant child */
2432  *result = argcurv[i];
2433  hadnonconst = TRUE;
2434  }
2435  else
2436  {
2437  /* more than one non-constant child, thus don't know curvature */
2438  *result = SCIP_EXPRCURV_UNKNOWN;
2439  break;
2440  }
2441  }
2442 
2443  *result = SCIPexprcurvMultiply(constants, *result);
2444 
2445  return SCIP_OKAY;
2446 } /*lint !e715*/
2447 
2448 /** point evaluation for EXPR_LINEAR */
2449 static
2450 SCIP_DECL_EXPREVAL( exprevalLinear )
2451 {
2452  SCIP_Real* coef;
2453  int i;
2454 
2455  assert(result != NULL);
2456  assert(argvals != NULL || nargs == 0);
2457  assert(opdata.data != NULL);
2458 
2459  coef = &((SCIP_Real*)opdata.data)[nargs];
2460 
2461  *result = *coef;
2462  for( i = nargs-1, --coef; i >= 0; --i, --coef )
2463  *result += *coef * argvals[i]; /*lint !e613*/
2464 
2465  assert(++coef == (SCIP_Real*)opdata.data);
2466 
2467  return SCIP_OKAY;
2468 } /*lint !e715*/
2469 
2470 /** interval evaluation for EXPR_LINEAR */
2471 static
2472 SCIP_DECL_EXPRINTEVAL( exprevalIntLinear )
2473 {
2474  assert(result != NULL);
2475  assert(argvals != NULL || nargs == 0);
2476  assert(opdata.data != NULL);
2477 
2478  SCIPintervalScalprodScalars(infinity, result, nargs, argvals, (SCIP_Real*)opdata.data);
2479  SCIPintervalAddScalar(infinity, result, *result, ((SCIP_Real*)opdata.data)[nargs]);
2480 
2481  return SCIP_OKAY;
2482 } /*lint !e715*/
2483 
2484 /** curvature for EXPR_LINEAR */
2485 static
2486 SCIP_DECL_EXPRCURV( exprcurvLinear )
2487 {
2488  SCIP_Real* data;
2489  int i;
2490 
2491  assert(result != NULL);
2492  assert(argcurv != NULL);
2493 
2494  data = (SCIP_Real*)opdata.data;
2495  assert(data != NULL);
2496 
2497  *result = SCIP_EXPRCURV_LINEAR;
2498 
2499  for( i = 0; i < nargs; ++i )
2500  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(data[i], argcurv[i]));
2501 
2502  return SCIP_OKAY;
2503 } /*lint !e715*/
2504 
2505 /** expression data copy for EXPR_LINEAR */
2506 static
2507 SCIP_DECL_EXPRCOPYDATA( exprCopyDataLinear )
2508 {
2509  SCIP_Real* targetdata;
2510 
2511  assert(blkmem != NULL);
2512  assert(nchildren >= 0);
2513  assert(opdatatarget != NULL);
2514 
2515  /* for a linear expression, we need to copy the array that holds the coefficients and constant term */
2516  assert(opdatasource.data != NULL);
2517  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &targetdata, (SCIP_Real*)opdatasource.data, nchildren + 1) ); /*lint !e866*/
2518  opdatatarget->data = targetdata;
2519 
2520  return SCIP_OKAY;
2521 }
2522 
2523 /** expression data free for EXPR_LINEAR */
2524 static
2525 SCIP_DECL_EXPRFREEDATA( exprFreeDataLinear )
2526 {
2527  SCIP_Real* freedata;
2528 
2529  assert(blkmem != NULL);
2530  assert(nchildren >= 0);
2531 
2532  freedata = (SCIP_Real*)opdata.data;
2533  assert(freedata != NULL);
2534 
2535  BMSfreeBlockMemoryArray(blkmem, &freedata, nchildren + 1); /*lint !e866*/
2536 }
2537 
2538 /** point evaluation for EXPR_QUADRATIC */
2539 static
2540 SCIP_DECL_EXPREVAL( exprevalQuadratic )
2541 {
2542  SCIP_EXPRDATA_QUADRATIC* quaddata;
2543  SCIP_Real* lincoefs;
2544  SCIP_QUADELEM* quadelems;
2545  int nquadelems;
2546  int i;
2547 
2548  assert(result != NULL);
2549  assert(argvals != NULL || nargs == 0);
2550 
2551  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2552  assert(quaddata != NULL);
2553 
2554  lincoefs = quaddata->lincoefs;
2555  nquadelems = quaddata->nquadelems;
2556  quadelems = quaddata->quadelems;
2557 
2558  assert(quadelems != NULL || nquadelems == 0);
2559  assert(argvals != NULL || nargs == 0);
2560 
2561  *result = quaddata->constant;
2562 
2563  if( lincoefs != NULL )
2564  for( i = nargs-1; i >= 0; --i )
2565  *result += lincoefs[i] * argvals[i]; /*lint !e613*/
2566 
2567  for( i = 0; i < nquadelems; ++i, ++quadelems ) /*lint !e613*/
2568  *result += quadelems->coef * argvals[quadelems->idx1] * argvals[quadelems->idx2]; /*lint !e613*/
2569 
2570  return SCIP_OKAY;
2571 } /*lint !e715*/
2572 
2573 /** interval evaluation for EXPR_QUADRATIC */
2574 static
2575 SCIP_DECL_EXPRINTEVAL( exprevalIntQuadratic )
2576 {
2577  SCIP_EXPRDATA_QUADRATIC* quaddata;
2578  SCIP_Real* lincoefs;
2579  SCIP_QUADELEM* quadelems;
2580  int nquadelems;
2581  int i;
2582  int argidx;
2583  SCIP_Real sqrcoef;
2584  SCIP_INTERVAL lincoef;
2585  SCIP_INTERVAL tmp;
2586 
2587  assert(result != NULL);
2588  assert(argvals != NULL || nargs == 0);
2589 
2590  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2591  assert(quaddata != NULL);
2592 
2593  lincoefs = quaddata->lincoefs;
2594  nquadelems = quaddata->nquadelems;
2595  quadelems = quaddata->quadelems;
2596 
2597  assert(quadelems != NULL || nquadelems == 0);
2598  assert(argvals != NULL || nargs == 0);
2599 
2600  /* something fast for case of only one child */
2601  if( nargs == 1 )
2602  {
2603  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[0] : 0.0);
2604 
2605  sqrcoef = 0.0;
2606  for( i = 0; i < nquadelems; ++i )
2607  {
2608  assert(quadelems[i].idx1 == 0); /*lint !e613*/
2609  assert(quadelems[i].idx2 == 0); /*lint !e613*/
2610  sqrcoef += quadelems[i].coef; /*lint !e613*/
2611  }
2612 
2613  SCIPintervalQuad(infinity, result, sqrcoef, lincoef, argvals[0]); /*lint !e613*/
2614  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2615 
2616  return SCIP_OKAY;
2617  }
2618 
2619  if( nargs == 2 && nquadelems > 0 )
2620  {
2621  /* if it's a bivariate quadratic expression with bilinear term, do something special */
2622  SCIP_Real ax; /* square coefficient of first child */
2623  SCIP_Real ay; /* square coefficient of second child */
2624  SCIP_Real axy; /* bilinear coefficient */
2625 
2626  ax = 0.0;
2627  ay = 0.0;
2628  axy = 0.0;
2629  for( i = 0; i < nquadelems; ++i )
2630  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 ) /*lint !e613*/
2631  ax += quadelems[i].coef; /*lint !e613*/
2632  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 ) /*lint !e613*/
2633  ay += quadelems[i].coef; /*lint !e613*/
2634  else
2635  axy += quadelems[i].coef; /*lint !e613*/
2636 
2637  SCIPintervalQuadBivar(infinity, result, ax, ay, axy,
2638  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2639  argvals[0], argvals[1]); /*lint !e613*/
2640  SCIPdebugMessage("%g x^2 + %g y^2 + %g x y + %g x + %g y = [%g,%g] for x = [%g,%g], y = [%g,%g]\n",
2641  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2642  result->inf, result->sup, argvals[0].inf, argvals[0].sup, argvals[1].inf, argvals[1].sup); /*lint !e613*/
2643 
2644  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2645 
2646  return SCIP_OKAY;
2647  }
2648 
2649  /* make sure coefficients are sorted */
2650  quadraticdataSort(quaddata);
2651 
2652  SCIPintervalSet(result, quaddata->constant);
2653 
2654  /* for each argument, we collect it's linear index from lincoefs, it's square coefficients and all factors from bilinear terms
2655  * then we compute the interval sqrcoef*x^2 + lincoef*x and add it to result
2656  * @todo split quadratic expression into bivariate quadratic terms and apply the above method
2657  */
2658  i = 0;
2659  for( argidx = 0; argidx < nargs; ++argidx )
2660  {
2661  if( i == nquadelems || quadelems[i].idx1 > argidx ) /*lint !e613*/
2662  {
2663  /* there are no quadratic terms with argidx in its first argument, that should be easy to handle */
2664  if( lincoefs != NULL )
2665  {
2666  SCIPintervalMulScalar(infinity, &tmp, argvals[argidx], lincoefs[argidx]); /*lint !e613*/
2667  SCIPintervalAdd(infinity, result, *result, tmp);
2668  }
2669  continue;
2670  }
2671 
2672  sqrcoef = 0.0;
2673  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[argidx] : 0.0);
2674 
2675  assert(i < nquadelems && quadelems[i].idx1 == argidx); /*lint !e613*/
2676  do
2677  {
2678  if( quadelems[i].idx2 == argidx ) /*lint !e613*/
2679  {
2680  sqrcoef += quadelems[i].coef; /*lint !e613*/
2681  }
2682  else
2683  {
2684  SCIPintervalMulScalar(infinity, &tmp, argvals[quadelems[i].idx2], quadelems[i].coef); /*lint !e613*/
2685  SCIPintervalAdd(infinity, &lincoef, lincoef, tmp);
2686  }
2687  ++i;
2688  }
2689  while( i < nquadelems && quadelems[i].idx1 == argidx ); /*lint !e613*/
2690  assert(i == nquadelems || quadelems[i].idx1 > argidx); /*lint !e613*/
2691 
2692  SCIPintervalQuad(infinity, &tmp, sqrcoef, lincoef, argvals[argidx]); /*lint !e613*/
2693  SCIPintervalAdd(infinity, result, *result, tmp);
2694  }
2695  assert(i == nquadelems);
2696 
2697  return SCIP_OKAY;
2698 } /*lint !e715*/
2699 
2700 /** curvature for EXPR_QUADRATIC */
2701 static
2702 SCIP_DECL_EXPRCURV( exprcurvQuadratic )
2703 {
2705  SCIP_QUADELEM* quadelems;
2706  int nquadelems;
2707  SCIP_Real* lincoefs;
2708  int i;
2709 
2710  assert(result != NULL);
2711  assert(argcurv != NULL);
2712  assert(argbounds != NULL);
2713 
2714  data = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2715  assert(data != NULL);
2716 
2717  lincoefs = data->lincoefs;
2718  quadelems = data->quadelems;
2719  nquadelems = data->nquadelems;
2720 
2721  *result = SCIP_EXPRCURV_LINEAR;
2722 
2723  if( lincoefs != NULL )
2724  for( i = 0; i < nargs; ++i )
2725  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(lincoefs[i], argcurv[i]));
2726 
2727  /* @todo could try cholesky factorization if all children linear...
2728  * @todo should then cache the result
2729  */
2730  for( i = 0; i < nquadelems && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
2731  {
2732  if( quadelems[i].coef == 0.0 )
2733  continue;
2734 
2735  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup && /*lint !e777*/
2736  +argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup
2737  ) /*lint !e777*/
2738  {
2739  /* both factors are constants -> curvature does not change */
2740  continue;
2741  }
2742 
2743  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup ) /*lint !e777*/
2744  {
2745  /* first factor is constant, second is not -> add curvature of second */
2746  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx1].inf, argcurv[quadelems[i].idx2]));
2747  }
2748  else if( argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup ) /*lint !e777*/
2749  {
2750  /* first factor is not constant, second is -> add curvature of first */
2751  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx2].inf, argcurv[quadelems[i].idx1]));
2752  }
2753  else if( quadelems[i].idx1 == quadelems[i].idx2 )
2754  {
2755  /* both factors not constant, but the same (square term) */
2756  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef, SCIPexprcurvPower(argbounds[quadelems[i].idx1], argcurv[quadelems[i].idx1], 2.0)));
2757  }
2758  else
2759  {
2760  /* two different non-constant factors -> can't tell about curvature */
2761  *result = SCIP_EXPRCURV_UNKNOWN;
2762  }
2763  }
2764 
2765  return SCIP_OKAY;
2766 } /*lint !e715*/
2767 
2768 /** expression data copy for EXPR_QUADRATIC */
2769 static
2770 SCIP_DECL_EXPRCOPYDATA( exprCopyDataQuadratic )
2771 {
2772  SCIP_EXPRDATA_QUADRATIC* sourcedata;
2773 
2774  assert(blkmem != NULL);
2775  assert(opdatatarget != NULL);
2776 
2777  sourcedata = (SCIP_EXPRDATA_QUADRATIC*)opdatasource.data;
2778  assert(sourcedata != NULL);
2779 
2780  SCIP_CALL( quadraticdataCreate(blkmem, (SCIP_EXPRDATA_QUADRATIC**)&opdatatarget->data,
2781  sourcedata->constant, nchildren, sourcedata->lincoefs, sourcedata->nquadelems, sourcedata->quadelems) );
2782 
2783  return SCIP_OKAY;
2784 }
2785 
2786 /** expression data free for EXPR_QUADRATIC */
2787 static
2788 SCIP_DECL_EXPRFREEDATA( exprFreeDataQuadratic )
2789 {
2790  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
2791 
2792  assert(blkmem != NULL);
2793  assert(nchildren >= 0);
2794 
2795  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2796  assert(quadraticdata != NULL);
2797 
2798  if( quadraticdata->lincoefs != NULL )
2799  {
2800  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->lincoefs, nchildren);
2801  }
2802 
2803  if( quadraticdata->nquadelems > 0 )
2804  {
2805  assert(quadraticdata->quadelems != NULL);
2806  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->quadelems, quadraticdata->nquadelems);
2807  }
2808 
2809  BMSfreeBlockMemory(blkmem, &quadraticdata);
2810 }
2811 
2812 /** point evaluation for EXPR_POLYNOMIAL */
2813 static
2814 SCIP_DECL_EXPREVAL( exprevalPolynomial )
2815 {
2816  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2817  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2818  SCIP_Real childval;
2819  SCIP_Real exponent;
2820  SCIP_Real monomialval;
2821  int i;
2822  int j;
2823 
2824  assert(result != NULL);
2825  assert(argvals != NULL || nargs == 0);
2826  assert(opdata.data != NULL);
2827 
2828  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2829  assert(polynomialdata != NULL);
2830 
2831  *result = polynomialdata->constant;
2832 
2833  for( i = 0; i < polynomialdata->nmonomials; ++i )
2834  {
2835  monomialdata = polynomialdata->monomials[i];
2836  assert(monomialdata != NULL);
2837 
2838  monomialval = monomialdata->coef;
2839  for( j = 0; j < monomialdata->nfactors; ++j )
2840  {
2841  assert(monomialdata->childidxs[j] >= 0);
2842  assert(monomialdata->childidxs[j] < nargs);
2843 
2844  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2845  if( childval == 1.0 ) /* 1^anything == 1 */
2846  continue;
2847 
2848  exponent = monomialdata->exponents[j];
2849 
2850  if( childval == 0.0 )
2851  {
2852  if( exponent > 0.0 )
2853  {
2854  /* 0^positive == 0 */
2855  monomialval = 0.0;
2856  break;
2857  }
2858  else if( exponent < 0.0 )
2859  {
2860  /* 0^negative = nan */
2861  *result = log(-1.0);
2862  return SCIP_OKAY;
2863  }
2864  /* 0^0 == 1 */
2865  continue;
2866  }
2867 
2868  /* cover some special exponents separately to avoid calling expensive pow function */
2869  if( exponent == 0.0 )
2870  continue;
2871  if( exponent == 1.0 )
2872  {
2873  monomialval *= childval;
2874  continue;
2875  }
2876  if( exponent == 2.0 )
2877  {
2878  monomialval *= childval * childval;
2879  continue;
2880  }
2881  if( exponent == 0.5 )
2882  {
2883  monomialval *= sqrt(childval);
2884  continue;
2885  }
2886  if( exponent == -1.0 )
2887  {
2888  monomialval /= childval;
2889  continue;
2890  }
2891  if( exponent == -2.0 )
2892  {
2893  monomialval /= childval * childval;
2894  continue;
2895  }
2896  monomialval *= pow(childval, exponent);
2897  }
2898 
2899  *result += monomialval;
2900  }
2901 
2902  return SCIP_OKAY;
2903 } /*lint !e715*/
2904 
2905 /** interval evaluation for EXPR_POLYNOMIAL */
2906 static
2907 SCIP_DECL_EXPRINTEVAL( exprevalIntPolynomial )
2908 {
2909  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2910  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2911  SCIP_INTERVAL childval;
2912  SCIP_INTERVAL monomialval;
2913  SCIP_Real exponent;
2914  int i;
2915  int j;
2916 
2917  assert(result != NULL);
2918  assert(argvals != NULL || nargs == 0);
2919  assert(opdata.data != NULL);
2920 
2921  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2922  assert(polynomialdata != NULL);
2923 
2924  SCIPintervalSet(result, polynomialdata->constant);
2925 
2926  for( i = 0; i < polynomialdata->nmonomials; ++i )
2927  {
2928  monomialdata = polynomialdata->monomials[i];
2929  assert(monomialdata != NULL);
2930 
2931  SCIPintervalSet(&monomialval, monomialdata->coef);
2932  for( j = 0; j < monomialdata->nfactors && !SCIPintervalIsEntire(infinity, monomialval); ++j )
2933  {
2934  assert(monomialdata->childidxs[j] >= 0);
2935  assert(monomialdata->childidxs[j] < nargs);
2936 
2937  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2938 
2939  exponent = monomialdata->exponents[j];
2940 
2941  /* cover some special exponents separately to avoid calling expensive pow function */
2942  if( exponent == 0.0 )
2943  continue;
2944 
2945  if( exponent == 1.0 )
2946  {
2947  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2948  continue;
2949  }
2950 
2951  if( exponent == 2.0 )
2952  {
2953  SCIPintervalSquare(infinity, &childval, childval);
2954  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2955  continue;
2956  }
2957 
2958  if( exponent == 0.5 )
2959  {
2960  SCIPintervalSquareRoot(infinity, &childval, childval);
2961  if( SCIPintervalIsEmpty(childval) )
2962  {
2963  SCIPintervalSetEmpty(result);
2964  break;
2965  }
2966  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2967  continue;
2968  }
2969  else if( exponent == -1.0 )
2970  {
2971  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2972  }
2973  else if( exponent == -2.0 )
2974  {
2975  SCIPintervalSquare(infinity, &childval, childval);
2976  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2977  }
2978  else
2979  {
2980  SCIPintervalPowerScalar(infinity, &childval, childval, exponent);
2981  if( SCIPintervalIsEmpty(childval) )
2982  {
2983  SCIPintervalSetEmpty(result);
2984  return SCIP_OKAY;
2985  }
2986  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2987  }
2988 
2989  /* the cases in which monomialval gets empty should have been catched */
2990  assert(!SCIPintervalIsEmpty(monomialval));
2991  }
2992 
2993  SCIPintervalAdd(infinity, result, *result, monomialval);
2994  }
2995 
2996  return SCIP_OKAY;
2997 } /*lint !e715*/
2998 
2999 /** curvature for EXPR_POLYNOMIAL */
3000 static
3001 SCIP_DECL_EXPRCURV( exprcurvPolynomial )
3002 {
3004  SCIP_EXPRDATA_MONOMIAL** monomials;
3005  SCIP_EXPRDATA_MONOMIAL* monomial;
3006  int nmonomials;
3007  int i;
3008 
3009  assert(result != NULL);
3010  assert(argcurv != NULL);
3011  assert(argbounds != NULL);
3012 
3013  data = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3014  assert(data != NULL);
3015 
3016  monomials = data->monomials;
3017  nmonomials = data->nmonomials;
3018 
3019  *result = SCIP_EXPRCURV_LINEAR;
3020 
3021  for( i = 0; i < nmonomials && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
3022  {
3023  /* we assume that some simplifier was running, so that monomials do not have constants in their factors and such that all factors are different
3024  * (result would still be correct)
3025  */
3026  monomial = monomials[i];
3027  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(monomial->coef, SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, monomial->childidxs, argcurv, argbounds)));
3028  }
3029 
3030  return SCIP_OKAY;
3031 } /*lint !e715*/
3032 
3033 /** expression data copy for EXPR_POLYNOMIAL */
3034 static
3035 SCIP_DECL_EXPRCOPYDATA( exprCopyDataPolynomial )
3036 {
3037  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata;
3038  SCIP_EXPRDATA_POLYNOMIAL* targetpolynomialdata;
3039 
3040  assert(blkmem != NULL);
3041  assert(opdatatarget != NULL);
3042 
3043  sourcepolynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdatasource.data;
3044  assert(sourcepolynomialdata != NULL);
3045 
3046  SCIP_CALL( polynomialdataCopy(blkmem, &targetpolynomialdata, sourcepolynomialdata) );
3047 
3048  opdatatarget->data = (void*)targetpolynomialdata;
3049 
3050  return SCIP_OKAY;
3051 } /*lint !e715*/
3052 
3053 /** expression data free for EXPR_POLYNOMIAL */
3054 static
3055 SCIP_DECL_EXPRFREEDATA( exprFreeDataPolynomial )
3056 {
3057  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3058 
3059  assert(blkmem != NULL);
3060 
3061  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3062  assert(polynomialdata != NULL);
3063 
3064  polynomialdataFree(blkmem, &polynomialdata);
3065 } /*lint !e715*/
3066 
3067 /** element in table of expression operands */
3068 struct exprOpTableElement
3069 {
3070  const char* name; /**< name of operand (used for printing) */
3071  int nargs; /**< number of arguments (negative if not fixed) */
3072  SCIP_DECL_EXPREVAL ((*eval)); /**< evaluation function */
3073  SCIP_DECL_EXPRINTEVAL ((*inteval)); /**< interval evaluation function */
3074  SCIP_DECL_EXPRCURV ((*curv)); /**< curvature check function */
3075  SCIP_DECL_EXPRCOPYDATA ((*copydata)); /**< expression data copy function, or NULL to only opdata union */
3076  SCIP_DECL_EXPRFREEDATA ((*freedata)); /**< expression data free function, or NULL if nothing to free */
3077 };
3078 
3079 #define EXPROPEMPTY {NULL, -1, NULL, NULL, NULL, NULL, NULL}
3080 
3081 /** table containing for each operand the name, the number of children, and some evaluation functions */
3082 static
3083 struct exprOpTableElement exprOpTable[] =
3084  {
3085  EXPROPEMPTY,
3086  { "variable", 0, exprevalVar, exprevalIntVar, exprcurvVar, NULL, NULL },
3087  { "constant", 0, exprevalConst, exprevalIntConst, exprcurvConst, NULL, NULL },
3088  { "parameter", 0, exprevalParam, exprevalIntParam, exprcurvParam, NULL, NULL },
3090  { "plus", 2, exprevalPlus, exprevalIntPlus, exprcurvPlus, NULL, NULL },
3091  { "minus", 2, exprevalMinus, exprevalIntMinus, exprcurvMinus, NULL, NULL },
3092  { "mul", 2, exprevalMult, exprevalIntMult, exprcurvMult, NULL, NULL },
3093  { "div", 2, exprevalDiv, exprevalIntDiv, exprcurvDiv, NULL, NULL },
3094  { "sqr", 1, exprevalSquare, exprevalIntSquare, exprcurvSquare, NULL, NULL },
3095  { "sqrt", 1, exprevalSquareRoot, exprevalIntSquareRoot, exprcurvSquareRoot, NULL, NULL },
3096  { "realpower", 1, exprevalRealPower, exprevalIntRealPower, exprcurvRealPower, NULL, NULL },
3097  { "intpower", 1, exprevalIntPower, exprevalIntIntPower, exprcurvIntPower, NULL, NULL },
3098  { "signpower", 1, exprevalSignPower, exprevalIntSignPower, exprcurvSignPower, NULL, NULL },
3099  { "exp", 1, exprevalExp, exprevalIntExp, exprcurvExp, NULL, NULL },
3100  { "log", 1, exprevalLog, exprevalIntLog, exprcurvLog, NULL, NULL },
3101  { "sin", 1, exprevalSin, exprevalIntSin, exprcurvSin, NULL, NULL },
3102  { "cos", 1, exprevalCos, exprevalIntCos, exprcurvCos, NULL, NULL },
3103  { "tan", 1, exprevalTan, exprevalIntTan, exprcurvTan, NULL, NULL },
3104  /* { "erf", 1, exprevalErf, exprevalIntErf, exprcurvErf, NULL, NULL }, */
3105  /* { "erfi", 1, exprevalErfi, exprevalIntErfi exprcurvErfi, NULL, NULL }, */
3107  { "min", 2, exprevalMin, exprevalIntMin, exprcurvMin, NULL, NULL },
3108  { "max", 2, exprevalMax, exprevalIntMax, exprcurvMax, NULL, NULL },
3109  { "abs", 1, exprevalAbs, exprevalIntAbs, exprcurvAbs, NULL, NULL },
3110  { "sign", 1, exprevalSign, exprevalIntSign, exprcurvSign, NULL, NULL },
3116  { "sum", -2, exprevalSum, exprevalIntSum, exprcurvSum, NULL, NULL },
3117  { "prod", -2, exprevalProduct, exprevalIntProduct, exprcurvProduct, NULL, NULL },
3118  { "linear", -2, exprevalLinear, exprevalIntLinear, exprcurvLinear, exprCopyDataLinear, exprFreeDataLinear },
3119  { "quadratic", -2, exprevalQuadratic, exprevalIntQuadratic, exprcurvQuadratic, exprCopyDataQuadratic, exprFreeDataQuadratic },
3120  { "polynomial", -2, exprevalPolynomial, exprevalIntPolynomial, exprcurvPolynomial, exprCopyDataPolynomial, exprFreeDataPolynomial }
3121  };
3122 
3123 /**@} */
3124 
3125 /**@name Expression operand methods */
3126 /**@{ */
3127 
3128 /** gives the name of an operand as string */
3129 const char* SCIPexpropGetName(
3130  SCIP_EXPROP op /**< expression operand */
3131  )
3132 {
3133  assert(op < SCIP_EXPR_LAST);
3134 
3135  return exprOpTable[op].name;
3136 }
3137 
3138 /** gives the number of children of a simple operand */
3140  SCIP_EXPROP op /**< expression operand */
3141  )
3142 {
3143  assert(op < SCIP_EXPR_LAST);
3144 
3145  return exprOpTable[op].nargs;
3146 }
3147 
3148 /**@} */
3149 
3150 /**@name Expressions private methods */
3151 /**@{ */
3152 
3153 /** creates an expression
3154  * Note, that the expression is allocated but for the children only the pointer is copied.
3155  */
3156 static
3158  BMS_BLKMEM* blkmem, /**< block memory data structure */
3159  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
3160  SCIP_EXPROP op, /**< operand of expression */
3161  int nchildren, /**< number of children */
3162  SCIP_EXPR** children, /**< children */
3163  SCIP_EXPROPDATA opdata /**< operand data */
3164  )
3165 {
3166  assert(blkmem != NULL);
3167  assert(expr != NULL);
3168  assert(children != NULL || nchildren == 0);
3169  assert(children == NULL || nchildren > 0);
3170 
3171  SCIP_ALLOC( BMSallocBlockMemory(blkmem, expr) );
3172 
3173  (*expr)->op = op;
3174  (*expr)->nchildren = nchildren;
3175  (*expr)->children = children;
3176  (*expr)->data = opdata;
3177 
3178  return SCIP_OKAY;
3179 }
3180 
3181 /** tries to convert a given (operator,operatordata) pair into a polynomial operator with corresponding data
3182  * does not do this for constants
3183  * if conversion is not possible or operator is already polynomial, *op and *data are left untouched
3184  */
3185 static
3187  BMS_BLKMEM* blkmem, /**< block memory */
3188  SCIP_EXPROP* op, /**< pointer to expression operator */
3189  SCIP_EXPROPDATA* data, /**< pointer to expression data */
3190  int nchildren /**< number of children of operator */
3191  )
3192 {
3193  assert(blkmem != NULL);
3194  assert(op != NULL);
3195  assert(data != NULL);
3196 
3197  switch( *op )
3198  {
3199  case SCIP_EXPR_VARIDX:
3200  case SCIP_EXPR_PARAM:
3201  case SCIP_EXPR_CONST:
3202  break;
3203 
3204  case SCIP_EXPR_PLUS:
3205  {
3206  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3207  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3208  int childidx;
3209  SCIP_Real exponent;
3210 
3211  assert(nchildren == 2);
3212 
3213  /* create monomial for first child */
3214  childidx = 0;
3215  exponent = 1.0;
3216  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3217 
3218  /* create monomial for second child */
3219  childidx = 1;
3220  exponent = 1.0;
3221  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], 1.0, 1, &childidx, &exponent) );
3222 
3223  /* create polynomial for sum of children */
3224  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3225 
3226  *op = SCIP_EXPR_POLYNOMIAL;
3227  data->data = (void*)polynomialdata;
3228 
3229  break;
3230  }
3231 
3232  case SCIP_EXPR_MINUS:
3233  {
3234  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3235  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3236  int childidx;
3237  SCIP_Real exponent;
3238 
3239  assert(nchildren == 2);
3240 
3241  /* create monomial for first child */
3242  childidx = 0;
3243  exponent = 1.0;
3244  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3245 
3246  /* create monomial for second child */
3247  childidx = 1;
3248  exponent = 1.0;
3249  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], -1.0, 1, &childidx, &exponent) );
3250 
3251  /* create polynomial for difference of children */
3252  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3253 
3254  *op = SCIP_EXPR_POLYNOMIAL;
3255  data->data = (void*)polynomialdata;
3256 
3257  break;
3258  }
3259 
3260  case SCIP_EXPR_MUL:
3261  {
3262  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3263  SCIP_EXPRDATA_MONOMIAL* monomial;
3264  int childidx[2];
3265  SCIP_Real exponent[2];
3266 
3267  assert(nchildren == 2);
3268 
3269  /* create monomial for product of children */
3270  childidx[0] = 0;
3271  childidx[1] = 1;
3272  exponent[0] = 1.0;
3273  exponent[1] = 1.0;
3274  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3275 
3276  /* create polynomial */
3277  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3278 
3279  *op = SCIP_EXPR_POLYNOMIAL;
3280  data->data = (void*)polynomialdata;
3281 
3282  break;
3283  }
3284 
3285  case SCIP_EXPR_DIV:
3286  {
3287  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3288  SCIP_EXPRDATA_MONOMIAL* monomial;
3289  int childidx[2];
3290  SCIP_Real exponent[2];
3291 
3292  assert(nchildren == 2);
3293 
3294  /* create monomial for division of children */
3295  childidx[0] = 0;
3296  childidx[1] = 1;
3297  exponent[0] = 1.0;
3298  exponent[1] = -1.0;
3299  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3300 
3301  /* create polynomial */
3302  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3303 
3304  *op = SCIP_EXPR_POLYNOMIAL;
3305  data->data = (void*)polynomialdata;
3306 
3307  break;
3308  }
3309 
3310  case SCIP_EXPR_SQUARE:
3311  {
3312  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3313  SCIP_EXPRDATA_MONOMIAL* monomial;
3314  int childidx;
3315  SCIP_Real exponent;
3316 
3317  assert(nchildren == 1);
3318 
3319  /* create monomial for square of child */
3320  childidx = 0;
3321  exponent = 2.0;
3322  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3323 
3324  /* create polynomial */
3325  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3326 
3327  *op = SCIP_EXPR_POLYNOMIAL;
3328  data->data = (void*)polynomialdata;
3329 
3330  break;
3331  }
3332 
3333  case SCIP_EXPR_SQRT:
3334  {
3335  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3336  SCIP_EXPRDATA_MONOMIAL* monomial;
3337  int childidx;
3338  SCIP_Real exponent;
3339 
3340  assert(nchildren == 1);
3341 
3342  /* create monomial for square root of child */
3343  childidx = 0;
3344  exponent = 0.5;
3345  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3346 
3347  /* create polynomial */
3348  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3349 
3350  *op = SCIP_EXPR_POLYNOMIAL;
3351  data->data = (void*)polynomialdata;
3352 
3353  break;
3354  }
3355 
3356  case SCIP_EXPR_REALPOWER:
3357  {
3358  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3359  SCIP_EXPRDATA_MONOMIAL* monomial;
3360  int childidx;
3361 
3362  assert(nchildren == 1);
3363 
3364  /* convert to child0 to the power of exponent */
3365 
3366  /* create monomial for power of first child */
3367  childidx = 0;
3368  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &data->dbl) );
3369 
3370  /* create polynomial */
3371  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3372 
3373  *op = SCIP_EXPR_POLYNOMIAL;
3374  data->data = (void*)polynomialdata;
3375 
3376  break;
3377  }
3378 
3379  case SCIP_EXPR_SIGNPOWER:
3380  {
3381  SCIP_Real exponent;
3382 
3383  assert(nchildren == 1);
3384 
3385  /* check if exponent is an odd integer */
3386  exponent = data->dbl;
3387  if( EPSISINT(exponent, 0.0) && (int)exponent % 2 != 0 ) /*lint !e835*/
3388  {
3389  /* convert to child0 to the power of exponent, since sign is kept by taking power */
3390  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3391  SCIP_EXPRDATA_MONOMIAL* monomial;
3392  int childidx;
3393 
3394  /* create monomial for power of first child */
3395  childidx = 0;
3396  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3397 
3398  /* create polynomial */
3399  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3400 
3401  *op = SCIP_EXPR_POLYNOMIAL;
3402  data->data = (void*)polynomialdata;
3403  }
3404  /* if exponent is not an odd integer constant, then keep it as signpower expression */
3405  break;
3406  }
3407 
3408  case SCIP_EXPR_INTPOWER:
3409  {
3410  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3411  SCIP_EXPRDATA_MONOMIAL* monomial;
3412  int childidx;
3413  SCIP_Real exponent;
3414 
3415  assert(nchildren == 1);
3416 
3417  /* create monomial for power of child */
3418  childidx = 0;
3419  exponent = data->intval;
3420  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &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_EXP:
3432  case SCIP_EXPR_LOG:
3433  case SCIP_EXPR_SIN:
3434  case SCIP_EXPR_COS:
3435  case SCIP_EXPR_TAN:
3436  /* case SCIP_EXPR_ERF: */
3437  /* case SCIP_EXPR_ERFI: */
3438  case SCIP_EXPR_MIN:
3439  case SCIP_EXPR_MAX:
3440  case SCIP_EXPR_ABS:
3441  case SCIP_EXPR_SIGN:
3442  break;
3443 
3444  case SCIP_EXPR_SUM:
3445  {
3446  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3447  SCIP_EXPRDATA_MONOMIAL* monomial;
3448  int childidx;
3449  int i;
3450  SCIP_Real exponent;
3451 
3452  /* create empty polynomial */
3453  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, 0.0, FALSE) );
3454  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3455  assert(polynomialdata->monomialssize >= nchildren);
3456 
3457  /* add summands as monomials */
3458  childidx = 0;
3459  exponent = 1.0;
3460  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3461  for( i = 0; i < nchildren; ++i )
3462  {
3463  monomial->childidxs[0] = i;
3464  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3465  }
3466  SCIPexprFreeMonomial(blkmem, &monomial);
3467 
3468  *op = SCIP_EXPR_POLYNOMIAL;
3469  data->data = (void*)polynomialdata;
3470 
3471  break;
3472  }
3473 
3474  case SCIP_EXPR_PRODUCT:
3475  {
3476  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3477  SCIP_EXPRDATA_MONOMIAL* monomial;
3478  int childidx;
3479  int i;
3480  SCIP_Real exponent;
3481 
3482  /* create monomial */
3483  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 0, NULL, NULL) );
3484  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, nchildren) );
3485  exponent = 1.0;
3486  for( i = 0; i < nchildren; ++i )
3487  {
3488  childidx = i;
3489  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
3490  }
3491 
3492  /* create polynomial */
3493  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3494 
3495  *op = SCIP_EXPR_POLYNOMIAL;
3496  data->data = (void*)polynomialdata;
3497 
3498  break;
3499  }
3500 
3501  case SCIP_EXPR_LINEAR:
3502  {
3503  SCIP_Real* lineardata;
3504  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3505  SCIP_EXPRDATA_MONOMIAL* monomial;
3506  int childidx;
3507  int i;
3508  SCIP_Real exponent;
3509 
3510  /* get coefficients of linear term */
3511  lineardata = (SCIP_Real*)data->data;
3512  assert(lineardata != NULL);
3513 
3514  /* create polynomial consisting of constant from linear term */
3515  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, lineardata[nchildren], FALSE) );
3516  /* ensure space for linear coefficients */
3517  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3518  assert(polynomialdata->monomialssize >= nchildren);
3519 
3520  /* add summands as monomials */
3521  childidx = 0;
3522  exponent = 1.0;
3523  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3524  for( i = 0; i < nchildren; ++i )
3525  {
3526  monomial->coef = lineardata[i];
3527  monomial->childidxs[0] = i;
3528  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3529  }
3530  SCIPexprFreeMonomial(blkmem, &monomial);
3531 
3532  /* free linear expression data */
3533  exprFreeDataLinear(blkmem, nchildren, *data);
3534 
3535  *op = SCIP_EXPR_POLYNOMIAL;
3536  data->data = (void*)polynomialdata;
3537 
3538  break;
3539  }
3540 
3541  case SCIP_EXPR_QUADRATIC:
3542  {
3543  SCIP_EXPRDATA_QUADRATIC* quaddata;
3544  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3545  SCIP_EXPRDATA_MONOMIAL* squaremonomial;
3546  SCIP_EXPRDATA_MONOMIAL* bilinmonomial;
3547  SCIP_EXPRDATA_MONOMIAL* linmonomial;
3548  int childidx[2];
3549  SCIP_Real exponent[2];
3550  int i;
3551 
3552  /* get data of quadratic expression */
3553  quaddata = (SCIP_EXPRDATA_QUADRATIC*)data->data;
3554  assert(quaddata != NULL);
3555 
3556  /* create empty polynomial */
3557  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, quaddata->constant, FALSE) );
3558  /* ensure space for linear and quadratic terms */
3559  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, (quaddata->lincoefs != NULL ? nchildren : 0) + quaddata->nquadelems) );
3560  assert(polynomialdata->monomialssize >= quaddata->nquadelems);
3561 
3562  childidx[0] = 0;
3563  childidx[1] = 0;
3564 
3565  /* create monomial templates */
3566  exponent[0] = 2.0;
3567  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &squaremonomial, 1.0, 1, childidx, exponent) );
3568  exponent[0] = 1.0;
3569  exponent[1] = 1.0;
3570  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &bilinmonomial, 1.0, 2, childidx, exponent) );
3571  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &linmonomial, 1.0, 1, childidx, exponent) );
3572 
3573  /* add linear terms as monomials */
3574  if( quaddata->lincoefs != NULL )
3575  for( i = 0; i < nchildren; ++i )
3576  if( quaddata->lincoefs[i] != 0.0 )
3577  {
3578  linmonomial->childidxs[0] = i;
3579  linmonomial->coef = quaddata->lincoefs[i];
3580  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &linmonomial, TRUE) );
3581  }
3582 
3583  /* add quadratic terms as monomials */
3584  for( i = 0; i < quaddata->nquadelems; ++i )
3585  {
3586  if( quaddata->quadelems[i].idx1 == quaddata->quadelems[i].idx2 )
3587  {
3588  squaremonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3589  squaremonomial->coef = quaddata->quadelems[i].coef;
3590  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &squaremonomial, TRUE) );
3591  }
3592  else
3593  {
3594  bilinmonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3595  bilinmonomial->childidxs[1] = quaddata->quadelems[i].idx2;
3596  bilinmonomial->coef = quaddata->quadelems[i].coef;
3597  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &bilinmonomial, TRUE) );
3598  }
3599  }
3600  SCIPexprFreeMonomial(blkmem, &squaremonomial);
3601  SCIPexprFreeMonomial(blkmem, &bilinmonomial);
3602  SCIPexprFreeMonomial(blkmem, &linmonomial);
3603 
3604  /* free quadratic expression data */
3605  exprFreeDataQuadratic(blkmem, nchildren, *data);
3606 
3607  *op = SCIP_EXPR_POLYNOMIAL;
3608  data->data = (void*)polynomialdata;
3609 
3610  break;
3611  }
3612 
3613  case SCIP_EXPR_POLYNOMIAL:
3614  break;
3615 
3616  default:
3617  SCIPerrorMessage("operand %d unknown\n", *op);
3618  return SCIP_ERROR;
3619  } /*lint !e788*/
3620 
3621  return SCIP_OKAY;
3622 }
3623 
3624 /** converts polynomial expression back into simpler expression, if possible */
3625 static
3627  BMS_BLKMEM* blkmem, /**< block memory data structure */
3628  SCIP_EXPROP* op, /**< pointer to expression operator */
3629  SCIP_EXPROPDATA* data, /**< pointer to expression data holding polynomial data */
3630  int nchildren, /**< number of children of operator */
3631  void** children /**< children array */
3632  )
3633 {
3634  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3635  SCIP_EXPRDATA_MONOMIAL* monomial;
3636  int maxdegree;
3637  int nlinmonomials;
3638  int i;
3639  int j;
3640 
3641  assert(blkmem != NULL);
3642  assert(op != NULL);
3643  assert(*op == SCIP_EXPR_POLYNOMIAL);
3644  assert(data != NULL);
3645  assert(children != NULL || nchildren == 0);
3646 
3647  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)data->data;
3648  assert(polynomialdata != NULL);
3649 
3650  /* make sure monomials are sorted and merged */
3651  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
3652 
3653  /* if no monomials, then leave as it is */
3654  if( polynomialdata->nmonomials == 0 )
3655  return SCIP_OKAY;
3656 
3657  /* check maximal degree of polynomial only - not considering children expressions
3658  * check number of linear monomials */
3659  maxdegree = 0;
3660  nlinmonomials = 0;
3661  for( i = 0; i < polynomialdata->nmonomials; ++i )
3662  {
3663  int monomialdegree;
3664 
3665  monomial = polynomialdata->monomials[i];
3666  assert(monomial != NULL);
3667 
3668  monomialdegree = 0;
3669  for(j = 0; j < monomial->nfactors; ++j )
3670  {
3671  if( !EPSISINT(monomial->exponents[j], 0.0) || monomial->exponents[j] < 0.0 ) /*lint !e835*/
3672  {
3673  monomialdegree = SCIP_EXPR_DEGREEINFINITY;
3674  break;
3675  }
3676 
3677  monomialdegree += (int)EPSROUND(monomial->exponents[j], 0.0); /*lint !e835*/
3678  }
3679 
3680  if( monomialdegree == SCIP_EXPR_DEGREEINFINITY )
3681  {
3682  maxdegree = SCIP_EXPR_DEGREEINFINITY;
3683  break;
3684  }
3685 
3686  if( monomialdegree == 1 )
3687  ++nlinmonomials;
3688 
3689  if( monomialdegree > maxdegree )
3690  maxdegree = monomialdegree;
3691  }
3692  assert(maxdegree > 0 );
3693 
3694  if( maxdegree == 1 )
3695  {
3696  /* polynomial is a linear expression in children */
3697 
3698  /* polynomial simplification and monomial merging should ensure that monomial i corresponds to child i and that there are not unused children */
3699  assert(polynomialdata->nmonomials == nchildren);
3700  assert(polynomialdata->nmonomials == nlinmonomials);
3701 
3702  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3703  {
3704  /* polynomial is addition of two expressions, so turn into SCIP_EXPR_PLUS */
3705 
3706  assert(polynomialdata->monomials[0]->nfactors == 1);
3707  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3708  assert(polynomialdata->monomials[1]->nfactors == 1);
3709  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3710 
3711  polynomialdataFree(blkmem, &polynomialdata);
3712  data->data = NULL;
3713 
3714  /* change operator type to PLUS */
3715  *op = SCIP_EXPR_PLUS;
3716 
3717  return SCIP_OKAY;
3718  }
3719 
3720  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == -1.0 )
3721  {
3722  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3723 
3724  assert(polynomialdata->monomials[0]->nfactors == 1);
3725  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3726  assert(polynomialdata->monomials[1]->nfactors == 1);
3727  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3728 
3729  polynomialdataFree(blkmem, &polynomialdata);
3730  data->data = NULL;
3731 
3732  /* change operator type to MINUS */
3733  *op = SCIP_EXPR_MINUS;
3734 
3735  return SCIP_OKAY;
3736  }
3737 
3738  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == -1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3739  {
3740  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3741  void* tmp;
3742 
3743  assert(polynomialdata->monomials[0]->nfactors == 1);
3744  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3745  assert(polynomialdata->monomials[1]->nfactors == 1);
3746  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3747 
3748  polynomialdataFree(blkmem, &polynomialdata);
3749  data->data = NULL;
3750 
3751  /* swap children */
3752  tmp = children[1]; /*lint !e613*/
3753  children[1] = children[0]; /*lint !e613*/
3754  children[0] = tmp; /*lint !e613*/
3755 
3756  /* change operator type to MINUS */
3757  *op = SCIP_EXPR_MINUS;
3758 
3759  return SCIP_OKAY;
3760  }
3761 
3762  if( polynomialdata->constant == 0.0 )
3763  {
3764  /* check if all monomials have coefficient 1.0 */
3765  for( i = 0; i < polynomialdata->nmonomials; ++i )
3766  if( polynomialdata->monomials[i]->coef != 1.0 )
3767  break;
3768 
3769  if( i == polynomialdata->nmonomials )
3770  {
3771  /* polynomial is sum of children, so turn into SCIP_EXPR_SUM */
3772 
3773  polynomialdataFree(blkmem, &polynomialdata);
3774  data->data = NULL;
3775 
3776  /* change operator type to MINUS */
3777  *op = SCIP_EXPR_SUM;
3778 
3779  return SCIP_OKAY;
3780  }
3781  }
3782 
3783  /* turn polynomial into linear expression */
3784  {
3785  SCIP_Real* lindata;
3786 
3787  /* monomial merging should ensure that each child appears in at most one monomial,
3788  * that monomials are ordered according to the child index, and that constant monomials have been removed
3789  */
3790 
3791  /* setup data of linear expression */
3792  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &lindata, polynomialdata->nmonomials + 1) );
3793 
3794  for( i = 0; i < polynomialdata->nmonomials; ++i )
3795  {
3796  assert(polynomialdata->monomials[i]->childidxs[0] == i);
3797  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3798  lindata[i] = polynomialdata->monomials[i]->coef; /*lint !e644*/
3799  }
3800  lindata[i] = polynomialdata->constant;
3801 
3802  polynomialdataFree(blkmem, &polynomialdata);
3803  *op = SCIP_EXPR_LINEAR;
3804  data->data = (void*)lindata;
3805 
3806  return SCIP_OKAY;
3807  }
3808  }
3809 
3810  if( maxdegree == 2 && (polynomialdata->nmonomials > 1 || polynomialdata->constant != 0.0 || polynomialdata->monomials[0]->coef != 1.0) )
3811  {
3812  /* 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 */
3813  SCIP_EXPRDATA_QUADRATIC* quaddata;
3814  int quadelemidx;
3815 
3816  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &quaddata) );
3817  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->quadelems, polynomialdata->nmonomials - nlinmonomials) );
3818  quaddata->nquadelems = polynomialdata->nmonomials - nlinmonomials;
3819  quaddata->constant = polynomialdata->constant;
3820  quaddata->sorted = FALSE; /* quadratic data is sorted different than polynomials */
3821 
3822  if( nlinmonomials > 0 )
3823  {
3824  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->lincoefs, nchildren) );
3825  BMSclearMemoryArray(quaddata->lincoefs, nchildren);
3826  }
3827  else
3828  quaddata->lincoefs = NULL;
3829 
3830  quadelemidx = 0;
3831  for( i = 0; i < polynomialdata->nmonomials; ++i )
3832  {
3833  assert(polynomialdata->monomials[i]->nfactors == 1 || polynomialdata->monomials[i]->nfactors == 2);
3834  if( polynomialdata->monomials[i]->nfactors == 1 )
3835  {
3836  if( polynomialdata->monomials[i]->exponents[0] == 1.0 )
3837  {
3838  /* monomial is a linear term */
3839  assert(quaddata->lincoefs != NULL);
3840  quaddata->lincoefs[polynomialdata->monomials[i]->childidxs[0]] += polynomialdata->monomials[i]->coef;
3841  }
3842  else
3843  {
3844  /* monomial should be a square term */
3845  assert(polynomialdata->monomials[i]->exponents[0] == 2.0);
3846  assert(quadelemidx < quaddata->nquadelems);
3847  quaddata->quadelems[quadelemidx].idx1 = polynomialdata->monomials[i]->childidxs[0];
3848  quaddata->quadelems[quadelemidx].idx2 = polynomialdata->monomials[i]->childidxs[0];
3849  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3850  ++quadelemidx;
3851  }
3852  }
3853  else
3854  {
3855  /* monomial should be a bilinear term */
3856  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3857  assert(polynomialdata->monomials[i]->exponents[1] == 1.0);
3858  assert(quadelemidx < quaddata->nquadelems);
3859  quaddata->quadelems[quadelemidx].idx1 = MIN(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3860  quaddata->quadelems[quadelemidx].idx2 = MAX(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3861  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3862  ++quadelemidx;
3863  }
3864  }
3865  assert(quadelemidx == quaddata->nquadelems);
3866 
3867  polynomialdataFree(blkmem, &polynomialdata);
3868 
3869  *op = SCIP_EXPR_QUADRATIC;
3870  data->data = (void*)quaddata;
3871 
3872  return SCIP_OKAY;
3873  }
3874 
3875  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 1 && polynomialdata->monomials[0]->coef == 1.0 )
3876  {
3877  /* polynomial is product of children */
3878  monomial = polynomialdata->monomials[0];
3879 
3880  if( monomial->nfactors == 1 )
3881  {
3882  /* polynomial is x^k for some k */
3883  assert(monomial->exponents[0] != 1.0); /* should have been handled before */
3884 
3885  if( monomial->exponents[0] == 2.0 )
3886  {
3887  /* polynomial is x^2, so turn into SCIP_EXPR_SQUARE */
3888 
3889  polynomialdataFree(blkmem, &polynomialdata);
3890  data->data = NULL;
3891 
3892  *op = SCIP_EXPR_SQUARE;
3893 
3894  return SCIP_OKAY;
3895  }
3896 
3897  if( EPSISINT(monomial->exponents[0], 0.0) ) /*lint !e835*/
3898  {
3899  /* k is an integer, so turn into SCIP_EXPR_INTPOWER */
3900  int exponent;
3901 
3902  exponent = (int)EPSROUND(monomial->exponents[0], 0.0); /*lint !e835*/
3903 
3904  polynomialdataFree(blkmem, &polynomialdata);
3905 
3906  *op = SCIP_EXPR_INTPOWER;
3907  data->intval = exponent;
3908 
3909  return SCIP_OKAY;
3910  }
3911 
3912  if( monomial->exponents[0] == 0.5 )
3913  {
3914  /* polynomial is sqrt(x), so turn into SCIP_EXPR_SQRT */
3915 
3916  polynomialdataFree(blkmem, &polynomialdata);
3917  data->data = NULL;
3918 
3919  *op = SCIP_EXPR_SQRT;
3920 
3921  return SCIP_OKAY;
3922  }
3923 
3924  {
3925  /* polynomial is x^a with a some real number, so turn into SCIP_EXPR_REALPOWER */
3926  SCIP_Real exponent;
3927 
3928  exponent = monomial->exponents[0];
3929 
3930  polynomialdataFree(blkmem, &polynomialdata);
3931 
3932  *op = SCIP_EXPR_REALPOWER;
3933  data->dbl = exponent;
3934 
3935  return SCIP_OKAY;
3936  }
3937  }
3938 
3939  if( maxdegree == 2 && monomial->nfactors == 2 )
3940  {
3941  /* polynomial is product of two children, so turn into SCIP_EXPR_MUL */
3942  assert(monomial->exponents[0] == 1.0);
3943  assert(monomial->exponents[1] == 1.0);
3944 
3945  polynomialdataFree(blkmem, &polynomialdata);
3946  data->data = NULL;
3947 
3948  *op = SCIP_EXPR_MUL;
3949 
3950  return SCIP_OKAY;
3951  }
3952 
3953  if( maxdegree == monomial->nfactors )
3954  {
3955  /* polynomial is a product of n children, so turn into SCIP_EXPR_PRODUCT */
3956 
3957  polynomialdataFree(blkmem, &polynomialdata);
3958  data->data = NULL;
3959 
3960  *op = SCIP_EXPR_PRODUCT;
3961 
3962  return SCIP_OKAY;
3963  }
3964 
3965  if( monomial->nfactors == 2 && monomial->exponents[0] == 1.0 && monomial->exponents[1] == -1.0 )
3966  {
3967  /* polynomial is x/y, so turn into SCIP_EXPR_DIV */
3968 
3969  polynomialdataFree(blkmem, &polynomialdata);
3970  data->data = NULL;
3971 
3972  *op = SCIP_EXPR_DIV;
3973 
3974  return SCIP_OKAY;
3975  }
3976 
3977  if( monomial->nfactors == 2 && monomial->exponents[0] == -1.0 && monomial->exponents[1] == 1.0 )
3978  {
3979  /* polynomial is y/x, so turn into SCIP_EXPR_DIV */
3980  void* tmp;
3981 
3982  polynomialdataFree(blkmem, &polynomialdata);
3983  data->data = NULL;
3984 
3985  /* swap children */
3986  tmp = children[1]; /*lint !e613*/
3987  children[1] = children[0]; /*lint !e613*/
3988  children[0] = tmp; /*lint !e613*/
3989 
3990  *op = SCIP_EXPR_DIV;
3991 
3992  return SCIP_OKAY;
3993  }
3994  }
3995 
3996  return SCIP_OKAY;
3997 }
3998 
3999 /** adds copies of expressions to the array of children of a sum, product, linear, quadratic, or polynomial expression
4000  * for a sum or product expression, this corresponds to add additional summands and factors, resp.
4001  * for a linear expression, this corresponds to add each expression with coefficient 1.0
4002  * for a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same
4003  */
4004 static
4006  BMS_BLKMEM* blkmem, /**< block memory */
4007  SCIP_EXPR* expr, /**< quadratic or polynomial expression */
4008  int nexprs, /**< number of expressions to add */
4009  SCIP_EXPR** exprs, /**< expressions to add */
4010  SCIP_Bool comparechildren, /**< whether to compare expressions with already existing children (no effect for sum and product) */
4011  SCIP_Real eps, /**< which epsilon to use when comparing expressions */
4012  int* childmap /**< array where to store mapping of indices from exprs to children array in expr, or NULL if not of interest */
4013  )
4014 {
4015  int i;
4016 
4017  assert(blkmem != NULL);
4018  assert(expr != NULL);
4019  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);
4020  assert(exprs != NULL || nexprs == 0);
4021 
4022  if( nexprs == 0 )
4023  return SCIP_OKAY;
4024 
4025  switch( expr->op )
4026  {
4027  case SCIP_EXPR_SUM:
4028  case SCIP_EXPR_PRODUCT:
4029  {
4030  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4031  for( i = 0; i < nexprs; ++i )
4032  {
4033  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren + i], exprs[i]) ); /*lint !e613*/
4034  if( childmap != NULL )
4035  childmap[i] = expr->nchildren + i;
4036  }
4037  expr->nchildren += nexprs;
4038 
4039  break;
4040  }
4041 
4042  case SCIP_EXPR_LINEAR:
4043  case SCIP_EXPR_QUADRATIC:
4044  case SCIP_EXPR_POLYNOMIAL:
4045  {
4046  int j;
4047  int orignchildren;
4048  SCIP_Bool existsalready;
4049 
4050  orignchildren = expr->nchildren;
4051  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4052 
4053  for( i = 0; i < nexprs; ++i )
4054  {
4055  existsalready = FALSE;
4056  if( comparechildren )
4057  for( j = 0; j < orignchildren; ++j )
4058  /* during simplification of polynomials, their may be NULL's in children array */
4059  if( expr->children[j] != NULL && SCIPexprAreEqual(expr->children[j], exprs[i], eps) ) /*lint !e613*/
4060  {
4061  existsalready = TRUE;
4062  break;
4063  }
4064 
4065  if( !existsalready )
4066  {
4067  /* add copy of exprs[j] to children array */
4068  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren], exprs[i]) ); /*lint !e613*/
4069  if( childmap != NULL )
4070  childmap[i] = expr->nchildren;
4071  ++expr->nchildren;
4072  }
4073  else
4074  {
4075  if( childmap != NULL )
4076  childmap[i] = j; /*lint !e644*/
4077  if( expr->op == SCIP_EXPR_LINEAR )
4078  {
4079  /* if linear expression, increase coefficient by 1.0 */
4080  ((SCIP_Real*)expr->data.data)[j] += 1.0;
4081  }
4082  }
4083  }
4084 
4085  /* shrink children array to actually used size */
4086  assert(comparechildren || expr->nchildren == orignchildren + nexprs);
4087  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, orignchildren + nexprs, expr->nchildren) );
4088 
4089  if( expr->op == SCIP_EXPR_LINEAR && expr->nchildren > orignchildren )
4090  {
4091  /* if linear expression, then add 1.0 coefficients for new expressions */
4092  SCIP_Real* data;
4093 
4094  data = (SCIP_Real*)expr->data.data;
4095  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, expr->nchildren + 1) );
4096  data[expr->nchildren] = data[orignchildren]; /* move constant from old end to new end */
4097  for( i = orignchildren; i < expr->nchildren; ++i )
4098  data[i] = 1.0;
4099  expr->data.data = (void*)data;
4100  }
4101  else if( expr->op == SCIP_EXPR_QUADRATIC && expr->nchildren > orignchildren )
4102  {
4103  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
4105 
4106  data = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
4107  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, expr->nchildren) );
4108  BMSclearMemoryArray(&data->lincoefs[orignchildren], expr->nchildren - orignchildren); /*lint !e866*/
4109  }
4110 
4111  break;
4112  }
4113 
4114  default:
4115  SCIPerrorMessage("exprsimplifyAddChildren cannot be called for operand %d\n", expr->op);
4116  return SCIP_INVALIDDATA;
4117  } /*lint !e788*/
4118 
4119  return SCIP_OKAY;
4120 }
4121 
4122 /** converts expressions into polynomials, where possible and obvious
4123  */
4124 static
4126  BMS_BLKMEM* blkmem, /**< block memory data structure */
4127  SCIP_EXPR* expr /**< expression to convert */
4128  )
4129 {
4130  int i;
4131 
4132  assert(expr != NULL);
4133 
4134  for( i = 0; i < expr->nchildren; ++i )
4135  {
4137  }
4138 
4139  SCIP_CALL( exprConvertToPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren) );
4140 
4141  return SCIP_OKAY;
4142 }
4143 
4144 /** removes duplicate children in a polynomial expression
4145  * leaves NULL's in children array */
4146 static
4148  BMS_BLKMEM* blkmem, /**< block memory data structure */
4149  SCIP_EXPR* expr, /**< expression */
4150  SCIP_Real eps /**< threshold for zero */
4151  )
4152 {
4153  SCIP_Bool foundduplicates;
4154  int* childmap;
4155  int i;
4156  int j;
4157 
4158  assert(blkmem != NULL);
4159  assert(expr != NULL);
4160  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4161 
4162  if( expr->nchildren == 0 )
4163  return SCIP_OKAY;
4164 
4165  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4166 
4167  foundduplicates = FALSE;
4168  for( i = 0; i < expr->nchildren; ++i )
4169  {
4170  if( expr->children[i] == NULL )
4171  continue;
4172  childmap[i] = i; /*lint !e644*/
4173 
4174  for( j = i+1; j < expr->nchildren; ++j )
4175  {
4176  if( expr->children[j] == NULL )
4177  continue;
4178 
4179  if( SCIPexprAreEqual(expr->children[i], expr->children[j], eps) )
4180  {
4181  /* forget about expr j and remember that is to be replaced by i */
4182  SCIPexprFreeDeep(blkmem, &expr->children[j]);
4183  childmap[j] = i;
4184  foundduplicates = TRUE;
4185  }
4186  }
4187  }
4188 
4189  /* apply childmap to monomials */
4190  if( foundduplicates )
4192 
4193  /* free childmap */
4194  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4195 
4196  return SCIP_OKAY;
4197 }
4198 
4199 /** eliminates NULL's in children array and shrinks it to actual size */
4200 static
4202  BMS_BLKMEM* blkmem, /**< block memory data structure */
4203  SCIP_EXPR* expr /**< expression */
4204  )
4205 {
4206  int* childmap;
4207  int lastnonnull;
4208  int i;
4209 
4210  assert(blkmem != NULL);
4211  assert(expr != NULL);
4212  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4213 
4214  if( expr->nchildren == 0 )
4215  return SCIP_OKAY;
4216 
4217  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4218 
4219  /* close gaps in children array */
4220  lastnonnull = expr->nchildren-1;
4221  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4222  --lastnonnull;
4223  for( i = 0; i <= lastnonnull; ++i )
4224  {
4225  if( expr->children[i] != NULL )
4226  {
4227  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
4228  continue;
4229  }
4230  assert(expr->children[lastnonnull] != NULL);
4231 
4232  /* move child at lastnonnull to position i */
4233  expr->children[i] = expr->children[lastnonnull];
4234  expr->children[lastnonnull] = NULL;
4235  childmap[lastnonnull] = i;
4236 
4237  /* update lastnonnull */
4238  --lastnonnull;
4239  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4240  --lastnonnull;
4241  }
4242  assert(i > lastnonnull);
4243 
4244  /* apply childmap to monomials */
4245  if( lastnonnull < expr->nchildren-1 )
4247 
4248  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4249 
4250  /* shrink children array */
4251  if( lastnonnull >= 0 )
4252  {
4253  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, lastnonnull+1) );
4254  expr->nchildren = lastnonnull+1;
4255  }
4256  else
4257  {
4258  BMSfreeBlockMemoryArray(blkmem, &expr->children, expr->nchildren);
4259  expr->nchildren = 0;
4260  }
4261 
4262  return SCIP_OKAY;
4263 }
4264 
4265 /** checks which children are still in use and frees those which are not */
4266 static
4268  BMS_BLKMEM* blkmem, /**< block memory data structure */
4269  SCIP_EXPR* expr /**< polynomial expression */
4270  )
4271 {
4272  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4273  SCIP_EXPRDATA_MONOMIAL* monomial;
4274  SCIP_Bool* childinuse;
4275  int i;
4276  int j;
4277 
4278  assert(blkmem != NULL);
4279  assert(expr != NULL);
4280 
4281  if( expr->nchildren == 0 )
4282  return SCIP_OKAY;
4283 
4284  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4285  assert(polynomialdata != NULL);
4286 
4287  /* check which children are still in use */
4288  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, expr->nchildren) );
4289  BMSclearMemoryArray(childinuse, expr->nchildren); /*lint !e644*/
4290  for( i = 0; i < polynomialdata->nmonomials; ++i )
4291  {
4292  monomial = polynomialdata->monomials[i];
4293  assert(monomial != NULL);
4294 
4295  for( j = 0; j < monomial->nfactors; ++j )
4296  {
4297  assert(monomial->childidxs[j] >= 0);
4298  assert(monomial->childidxs[j] < expr->nchildren);
4299  childinuse[monomial->childidxs[j]] = TRUE;
4300  }
4301  }
4302 
4303  /* free children that are not used in any monomial */
4304  for( i = 0; i < expr->nchildren; ++i )
4305  if( expr->children[i] != NULL && !childinuse[i] )
4306  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4307 
4308  BMSfreeBlockMemoryArray(blkmem, &childinuse, expr->nchildren);
4309 
4310  return SCIP_OKAY;
4311 }
4312 
4313 /** flattens polynomials in polynomials, check for constants in non-polynomials expressions
4314  * exprsimplifyConvertToPolynomials should have been called before to eliminate simple polynomial operands
4315  */
4316 static
4318  BMS_BLKMEM* blkmem, /**< block memory data structure */
4319  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4320  SCIP_EXPR* expr, /**< expression */
4321  SCIP_Real eps, /**< threshold, under which values are treat as 0 */
4322  int maxexpansionexponent/**< maximal exponent for which we still expand non-monomial polynomials */
4323  )
4324 {
4325  int i;
4326 
4327  assert(expr != NULL);
4328 
4329  for( i = 0; i < expr->nchildren; ++i )
4330  {
4331  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr->children[i], eps, maxexpansionexponent) );
4332  }
4333 
4334  switch( SCIPexprGetOperator(expr) )
4335  {
4336  case SCIP_EXPR_VARIDX:
4337  case SCIP_EXPR_CONST:
4338  case SCIP_EXPR_PARAM:
4339  case SCIP_EXPR_PLUS:
4340  case SCIP_EXPR_MINUS:
4341  case SCIP_EXPR_MUL:
4342  case SCIP_EXPR_DIV:
4343  case SCIP_EXPR_SQUARE:
4344  case SCIP_EXPR_SQRT:
4345  case SCIP_EXPR_INTPOWER:
4346  case SCIP_EXPR_REALPOWER:
4347  case SCIP_EXPR_SIGNPOWER:
4348  break;
4349 
4350  case SCIP_EXPR_EXP:
4351  case SCIP_EXPR_LOG:
4352  case SCIP_EXPR_SIN:
4353  case SCIP_EXPR_COS:
4354  case SCIP_EXPR_TAN:
4355  /* case SCIP_EXPR_ERF: */
4356  /* case SCIP_EXPR_ERFI: */
4357  case SCIP_EXPR_ABS:
4358  case SCIP_EXPR_SIGN:
4359  {
4360  /* check if argument is a constant */
4361  if( (expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) ||
4362  expr->children[0]->op == SCIP_EXPR_CONST )
4363  {
4364  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4365  SCIP_Real exprval;
4366 
4367  /* since child0 has no children and it's polynomial was flattened, it should have no monomials */
4368  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4369 
4370  /* evaluate expression in constant polynomial */
4371  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4372 
4373  /* create polynomial */
4374  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4375 
4376  expr->op = SCIP_EXPR_POLYNOMIAL;
4377  expr->data.data = (void*)polynomialdata;
4378 
4379  /* forget child */
4380  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4381  BMSfreeBlockMemoryArray(blkmem, &expr->children, 1);
4382  expr->nchildren = 0;
4383  }
4384 
4385  break;
4386  }
4387 
4388  case SCIP_EXPR_MIN:
4389  case SCIP_EXPR_MAX:
4390  {
4391  /* check if both arguments are constants */
4392  if( ((expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) || expr->children[0]->op == SCIP_EXPR_CONST) &&
4393  ((expr->children[1]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[1]) == 0) || expr->children[1]->op == SCIP_EXPR_CONST) )
4394  {
4395  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4396  SCIP_Real exprval;
4397 
4398  /* since children have no children and it's polynomial was flattened, it should have no monomials */
4399  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4400  assert(expr->children[1]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[1]) == 0);
4401 
4402  /* evaluate expression in constants */
4403  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4404 
4405  /* create polynomial */
4406  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4407 
4408  expr->op = SCIP_EXPR_POLYNOMIAL;
4409  expr->data.data = (void*)polynomialdata;
4410 
4411  /* forget children */
4412  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4413  SCIPexprFreeDeep(blkmem, &expr->children[1]);
4414  BMSfreeBlockMemoryArray(blkmem, &expr->children, 2);
4415  expr->nchildren = 0;
4416  }
4417 
4418  break;
4419  }
4420 
4421  case SCIP_EXPR_SUM:
4422  case SCIP_EXPR_PRODUCT:
4423  case SCIP_EXPR_LINEAR:
4424  case SCIP_EXPR_QUADRATIC:
4425  break;
4426 
4427  case SCIP_EXPR_POLYNOMIAL:
4428  {
4429  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4430  SCIP_EXPRDATA_MONOMIAL* monomial;
4431  SCIP_Bool removechild;
4432  int* childmap;
4433  int childmapsize;
4434  int j;
4435 
4436  /* simplify current polynomial */
4438  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4439 
4440  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4441  assert(polynomialdata != NULL);
4442 
4443  SCIPdebugMessage("expand factors in expression ");
4444  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4445  SCIPdebugPrintf("\n");
4446 
4447  childmap = NULL;
4448  childmapsize = 0;
4449 
4450  /* resolve children that are constants
4451  * we do this first, because it reduces the degree and number of factors in the monomials,
4452  * 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
4453  */
4454  for( i = 0; i < expr->nchildren; ++i )
4455  {
4456  if( expr->children[i] == NULL )
4457  continue;
4458 
4459  if( SCIPexprGetOperator(expr->children[i]) != SCIP_EXPR_CONST )
4460  continue;
4461 
4462  removechild = TRUE; /* we intend to delete children[i] */
4463 
4464  if( childmapsize < expr->children[i]->nchildren )
4465  {
4466  int newsize;
4467 
4468  newsize = calcGrowSize(expr->children[i]->nchildren);
4469  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4470  childmapsize = newsize;
4471  }
4472 
4473  /* put constant of child i into every monomial where child i is used */
4474  for( j = 0; j < polynomialdata->nmonomials; ++j )
4475  {
4476  int factorpos;
4477  SCIP_Bool success;
4478 
4479  monomial = polynomialdata->monomials[j];
4480  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4481  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4482 
4483  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4484  {
4485  assert(factorpos >= 0);
4486  assert(factorpos < monomial->nfactors);
4487  /* assert that factors have been merged */
4488  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4489  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4490 
4491  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4492  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4493  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4494 
4495  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && SCIPexprGetOpReal(expr->children[i]) < 0.0 ) /*lint !e835*/
4496  {
4497  /* if constant is negative and our exponent is not integer, then cannot do expansion */
4498  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n",
4499  SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4500  success = FALSE;
4501  }
4502  else
4503  {
4504  monomial->coef *= pow(SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4505 
4506  /* move last factor to position factorpos */
4507  if( factorpos < monomial->nfactors-1 )
4508  {
4509  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
4510  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
4511  }
4512  --monomial->nfactors;
4513  monomial->sorted = FALSE;
4514  polynomialdata->sorted = FALSE;
4515 
4516  success = TRUE;
4517  }
4518 
4519  if( !success )
4520  removechild = FALSE;
4521  }
4522  }
4523 
4524  /* forget about child i, if it is not used anymore */
4525  if( removechild )
4526  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4527 
4528  /* simplify current polynomial again */
4529  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4530  }
4531 
4532  /* try to resolve children that are polynomials itself */
4533  for( i = 0; i < expr->nchildren; ++i )
4534  {
4535  if( expr->children[i] == NULL )
4536  continue;
4537 
4539  continue;
4540 
4541  removechild = TRUE; /* we intend to delete children[i] */
4542 
4543  if( childmapsize < expr->children[i]->nchildren )
4544  {
4545  int newsize;
4546 
4547  newsize = calcGrowSize(expr->children[i]->nchildren);
4548  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4549  childmapsize = newsize;
4550  }
4551 
4552  /* add children of child i */
4553  SCIP_CALL( exprsimplifyAddChildren(blkmem, expr, expr->children[i]->nchildren, expr->children[i]->children, TRUE, eps, childmap) );
4554 
4555  /* put polynomial of child i into every monomial where child i is used */
4556  j = 0;
4557  while( j < polynomialdata->nmonomials )
4558  {
4559  int factorpos;
4560  SCIP_Bool success;
4561 
4562  monomial = polynomialdata->monomials[j];
4563  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4564  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4565 
4566  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4567  {
4568  assert(factorpos >= 0);
4569  assert(factorpos < monomial->nfactors);
4570  /* assert that factors have been merged */
4571  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4572  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4573 
4574  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4575  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4576  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4577 
4578  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos, (SCIP_EXPRDATA_POLYNOMIAL*)expr->children[i]->data.data, childmap, maxexpansionexponent, &success) );
4579 
4580  if( !success )
4581  {
4582  removechild = FALSE;
4583  ++j;
4584  }
4585  }
4586  else
4587  ++j;
4588 
4589  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
4590  * we thus repeat with index j, if a factor was successfully expanded
4591  */
4592  }
4593 
4594  /* forget about child i, if it is not used anymore */
4595  if( removechild )
4596  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4597 
4598  /* simplify current polynomial again */
4599  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4600  }
4601 
4602  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
4603 
4604  /* free children that are not in use anymore */
4606 
4607  /* remove NULLs from children array */
4609 
4610  /* if no children left, then it's a constant polynomial -> change into EXPR_CONST */
4611  if( expr->nchildren == 0 )
4612  {
4613  SCIP_Real val;
4614 
4615  /* if no children, then it should also have no monomials */
4616  assert(polynomialdata->nmonomials == 0);
4617 
4618  val = polynomialdata->constant;
4619  polynomialdataFree(blkmem, &polynomialdata);
4620 
4621  expr->op = SCIP_EXPR_CONST;
4622  expr->data.dbl = val;
4623  }
4624 
4625  SCIPdebugMessage("-> ");
4626  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4627  SCIPdebugPrintf("\n");
4628 
4629  break;
4630  }
4631 
4632  default:
4633  SCIPerrorMessage("operand %d unknown\n", expr->op);
4634  return SCIP_ERROR;
4635  } /*lint !e788*/
4636 
4637  return SCIP_OKAY;
4638 }
4639 
4640 /** separates linear monomials from an expression, if it is a polynomial expression
4641  * separates only those linear terms which variable is not used otherwise in the expression
4642  */
4643 static
4645  BMS_BLKMEM* blkmem, /**< block memory data structure */
4646  SCIP_EXPR* expr, /**< expression */
4647  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
4648  int nvars, /**< number of variables in expression */
4649  int* nlinvars, /**< buffer to store number of linear variables in linear part */
4650  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part */
4651  SCIP_Real* lincoefs /**< array to store coefficients of linear part */
4652  )
4653 {
4654  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4655  SCIP_EXPRDATA_MONOMIAL* monomial;
4656  int* varsusage;
4657  int* childusage;
4658  int childidx;
4659  int i;
4660  int j;
4661 
4662  assert(blkmem != NULL);
4663  assert(expr != NULL);
4664  assert(nlinvars != NULL);
4665  assert(linidxs != NULL);
4666  assert(lincoefs != NULL);
4667 
4668  *nlinvars = 0;
4669 
4671  return SCIP_OKAY;
4672 
4673  if( SCIPexprGetNChildren(expr) == 0 )
4674  return SCIP_OKAY;
4675 
4676  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4677  assert(polynomialdata != NULL);
4678 
4679  /* get variable usage */
4680  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &varsusage, nvars) );
4681  BMSclearMemoryArray(varsusage, nvars); /*lint !e644*/
4682  SCIPexprGetVarsUsage(expr, varsusage);
4683 
4684  /* get child usage: how often each child is used in the polynomial */
4685  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childusage, expr->nchildren) );
4686  BMSclearMemoryArray(childusage, expr->nchildren); /*lint !e644*/
4687  for( i = 0; i < polynomialdata->nmonomials; ++i )
4688  {
4689  monomial = polynomialdata->monomials[i];
4690  assert(monomial != NULL);
4691  for( j = 0; j < monomial->nfactors; ++j )
4692  {
4693  assert(monomial->childidxs[j] >= 0);
4694  assert(monomial->childidxs[j] < expr->nchildren);
4695  ++childusage[monomial->childidxs[j]];
4696  }
4697  }
4698 
4699  /* move linear monomials out of polynomial */
4700  for( i = 0; i < polynomialdata->nmonomials; ++i )
4701  {
4702  monomial = polynomialdata->monomials[i];
4703  assert(monomial != NULL);
4704  if( monomial->nfactors != 1 )
4705  continue;
4706  if( monomial->exponents[0] != 1.0 )
4707  continue;
4708  childidx = monomial->childidxs[0];
4709  if( SCIPexprGetOperator(expr->children[childidx]) != SCIP_EXPR_VARIDX )
4710  continue;
4711 
4712  /* we are at a linear monomial in a variable */
4713  assert(SCIPexprGetOpIndex(expr->children[childidx]) < nvars);
4714  if( childusage[childidx] == 1 && varsusage[SCIPexprGetOpIndex(expr->children[childidx])] == 1 )
4715  {
4716  /* if the child expression is not used in another monomial (which would due to merging be not linear)
4717  * and if the variable is not used somewhere else in the tree,
4718  * then move this monomial into linear part and free child
4719  */
4720  linidxs[*nlinvars] = SCIPexprGetOpIndex(expr->children[childidx]);
4721  lincoefs[*nlinvars] = monomial->coef;
4722  ++*nlinvars;
4723 
4724  SCIPexprFreeDeep(blkmem, &expr->children[childidx]);
4725  monomial->coef = 0.0;
4726  monomial->nfactors = 0;
4727  }
4728  }
4729 
4730  BMSfreeBlockMemoryArray(blkmem, &varsusage, nvars);
4731  BMSfreeBlockMemoryArray(blkmem, &childusage, expr->nchildren);
4732 
4733  if( *nlinvars > 0 )
4734  {
4735  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
4736  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, FALSE);
4738  }
4739 
4740  return SCIP_OKAY;
4741 }
4742 
4743 /** converts polynomial expressions back into simpler expressions, where possible */
4744 static
4746  BMS_BLKMEM* blkmem, /**< block memory data structure */
4747  SCIP_EXPR* expr /**< expression to convert back */
4748  )
4749 {
4750  int i;
4751 
4752  assert(blkmem != NULL);
4753  assert(expr != NULL);
4754 
4755  for( i = 0; i < expr->nchildren; ++i )
4756  {
4758  }
4759 
4760  if( expr->op != SCIP_EXPR_POLYNOMIAL )
4761  return SCIP_OKAY;
4762 
4763  SCIP_CALL( exprUnconvertPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren, (void**)expr->children) );
4764 
4765  return SCIP_OKAY;
4766 }
4767 
4768 static
4769 SCIP_DECL_HASHGETKEY( exprparseVarTableGetKey )
4770 { /*lint --e{715}*/
4771  return (void*)((char*)elem + sizeof(int));
4772 }
4773 
4774 /** parses a variable name from a string and creates corresponding expression
4775  *
4776  * creates a new variable index if variable not seen before, updates varnames and vartable structures
4777  */
4778 static
4780  BMS_BLKMEM* blkmem, /**< block memory data structure */
4781  const char** str, /**< pointer to the string to be parsed */
4782  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
4783  int* nvars, /**< running number of encountered variables so far */
4784  int** varnames, /**< pointer to buffer to store new variable names */
4785  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
4786  SCIP_Real coefficient, /**< coefficient to be used when creating the expression */
4787  const char* varnameendptr /**< if a <varname> should be parsed, set this to NULL. Then, str points to the '<'
4788  else, str should point to the first letter of the varname, and varnameendptr should
4789  point one char behind the last char of the variable name */
4790  )
4791 {
4792  int namelength;
4793  int varidx;
4794  char varname[SCIP_MAXSTRLEN];
4795  void* element;
4796 
4797  assert(blkmem != NULL);
4798  assert(str != NULL);
4799  assert(expr != NULL);
4800  assert(nvars != NULL);
4801  assert(varnames != NULL);
4802  assert(vartable != NULL);
4803 
4804  if( varnameendptr == NULL )
4805  {
4806  ++*str;
4807  varnameendptr = *str;
4808  while( varnameendptr[0] != '>' )
4809  ++varnameendptr;
4810  }
4811 
4812  namelength = varnameendptr - *str;
4813  if( namelength >= SCIP_MAXSTRLEN )
4814  {
4815  SCIPerrorMessage("Variable name %.*s is too long for buffer in exprparseReadVariable.\n", namelength, str);
4816  return SCIP_READERROR;
4817  }
4818 
4819  memcpy(varname, *str, namelength * sizeof(char));
4820  varname[namelength] = '\0';
4821 
4822  element = SCIPhashtableRetrieve(vartable, varname);
4823  if( element != NULL )
4824  {
4825  /* variable is old friend */
4826  assert(strcmp((char*)element + sizeof(int), varname) == 0);
4827 
4828  varidx = *(int*)element;
4829  }
4830  else
4831  {
4832  /* variable is new */
4833  varidx = *nvars;
4834 
4835  /* store index of variable and variable name in varnames buffer */
4836  **varnames = varidx;
4837  strcpy((char*)(*varnames + 1), varname);
4838 
4839  /* insert variable into hashtable */
4840  SCIP_CALL( SCIPhashtableInsert(vartable, (void*)*varnames) );
4841 
4842  ++*nvars;
4843  *varnames += 1 + (strlen(varname) + 1) / sizeof(int) + 1;
4844  }
4845 
4846  /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
4847  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_VARIDX, varidx) ); /*lint !e613*/
4848  if( coefficient != 1.0 )
4849  {
4850  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, expr, &coefficient, 0.0) );
4851  }
4852 
4853  /* Move pointer to char behind end of variable */
4854  *str = varnameendptr + 1;
4855 
4856  /* consprint sometimes prints a variable type identifier which we don't need */
4857  if( (*str)[0] == '[' && (*str)[2] == ']' &&
4858  ((*str)[1] == SCIP_VARTYPE_BINARY_CHAR ||
4859  (*str)[1] == SCIP_VARTYPE_INTEGER_CHAR ||
4860  (*str)[1] == SCIP_VARTYPE_IMPLINT_CHAR ||
4861  (*str)[1] == SCIP_VARTYPE_CONTINUOUS_CHAR
4862  )
4863  )
4864  *str += 3;
4865 
4866  return SCIP_OKAY;
4867 }
4868 
4869 /* if str[0] points to an opening parenthesis, this function sets endptr to point to the matching closing bracket in str
4870  *
4871  * searches for at most length characters
4872  */
4873 static
4875  const char* str, /**< pointer to the string to be parsed */
4876  const char** endptr, /**< pointer to point to the closing parenthesis */
4877  int length /**< length of the string to be parsed */
4878  )
4879 {
4880  int nopenbrackets;
4881 
4882  assert(str[0] == '(');
4883 
4884  *endptr = str;
4885 
4886  /* find the end of this expression */
4887  nopenbrackets = 0;
4888  while( (*endptr - str ) < length && !(nopenbrackets == 1 && *endptr[0] == ')') )
4889  {
4890  if( *endptr[0] == '(')
4891  ++nopenbrackets;
4892  if( *endptr[0] == ')')
4893  --nopenbrackets;
4894  ++*endptr;
4895  }
4896 
4897  if( *endptr[0] != ')' )
4898  {
4899  SCIPerrorMessage("unable to find closing parenthesis in unbalanced expression %.*s\n", length, str);
4900  return SCIP_READERROR;
4901  }
4902 
4903  return SCIP_OKAY;
4904 }
4905 
4906 /** parses an expression from a string */
4907 static
4909  BMS_BLKMEM* blkmem, /**< block memory data structure */
4910  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4911  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
4912  const char* str, /**< pointer to the string to be parsed */
4913  int length, /**< length of the string to be parsed */
4914  const char* lastchar, /**< pointer to the last char of str that should be parsed */
4915  int* nvars, /**< running number of encountered variables so far */
4916  int** varnames, /**< pointer to buffer to store new variable names */
4917  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
4918  int recursiondepth /**< current recursion depth */
4919  )
4920 {
4921  SCIP_EXPR* arg1;
4922  SCIP_EXPR* arg2;
4923  const char* subexpptr;
4924  const char* subexpendptr;
4925  const char* strstart;
4926  const char* endptr;
4927  char* nonconstendptr;
4928  SCIP_Real number;
4929  int subexplength;
4930  int nopenbrackets;
4931 
4932  assert(blkmem != NULL);
4933  assert(expr != NULL);
4934  assert(str != NULL);
4935  assert(lastchar >= str);
4936  assert(nvars != NULL);
4937  assert(varnames != NULL);
4938  assert(vartable != NULL);
4939 
4940  assert(recursiondepth < 100);
4941 
4942  strstart = str; /* might be needed for error message... */
4943 
4944  SCIPdebugMessage("exprParse (%i): parsing %.*s\n", recursiondepth, (int) (lastchar-str + 1), str);
4945 
4946  /* ignore whitespace */
4947  while( isspace((unsigned char)*str) )
4948  ++str;
4949 
4950  /* look for a sum or difference not contained in brackets */
4951  subexpptr = str;
4952  nopenbrackets = 0;
4953 
4954  /* find the end of this expression
4955  * a '+' right at the beginning indicates a coefficient, not treated here
4956  */
4957  while( subexpptr != lastchar && !(nopenbrackets == 0 && (subexpptr[0] == '+' || subexpptr[0] == '-') && subexpptr != str) )
4958  {
4959  if( subexpptr[0] == '(')
4960  ++nopenbrackets;
4961  if( subexpptr[0] == ')')
4962  --nopenbrackets;
4963  ++subexpptr;
4964  }
4965 
4966  if( subexpptr != lastchar )
4967  {
4968  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str, (int) ((subexpptr - 1) - str + 1), subexpptr - 1, nvars, varnames, vartable, recursiondepth + 1) );
4969  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, subexpptr , (int) (lastchar - (subexpptr ) + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
4970 
4971  /* make new expression from two arguments
4972  * we always use add, because we leave the operator between the found expressions in the second argument
4973  * this way, we do not have to worry about ''minus brackets'' in the case of more then two summands:
4974  * a - b - c = a + (-b -c)
4975  */
4976  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
4977 
4978  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
4979  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
4980  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
4981 
4982  return SCIP_OKAY;
4983  }
4984 
4985  /* check for a bracketed subexpression */
4986  if( str[0] == '(' )
4987  {
4988  nopenbrackets = 0;
4989 
4990  subexplength = -1; /* we do not want the closing bracket in the string */
4991  subexpptr = str + 1; /* leave out opening bracket */
4992 
4993  /* find the end of this expression */
4994  while( subexplength < length && !(nopenbrackets == 1 && str[0] == ')') )
4995  {
4996  if( str[0] == '(' )
4997  ++nopenbrackets;
4998  if( str[0] == ')' )
4999  --nopenbrackets;
5000  ++str;
5001  ++subexplength;
5002  }
5003  subexpendptr = str - 1; /* leave out closing bracket */
5004 
5005  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, subexpptr, subexplength, subexpendptr, nvars, varnames, vartable, recursiondepth + 1) );
5006  ++str;
5007  }
5008  else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5009  {
5010  /* there is a number coming */
5011  if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5012  {
5013  SCIPerrorMessage("error parsing number from <%s>\n", str);
5014  return SCIP_READERROR;
5015  }
5016  str = nonconstendptr;
5017 
5018  /* ignore whitespace */
5019  while( isspace((unsigned char)*str) && str != lastchar )
5020  ++str;
5021 
5022  if( str[0] != '*' && str[0] != '/' && str[0] != '+' && str[0] != '-' && str[0] != '/' && str[0] != '^' )
5023  {
5024  if( str < lastchar )
5025  {
5026  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, str, (int)(lastchar - str) + 1, lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5027  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, *expr, number) );
5028  }
5029  else
5030  {
5031  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5032  }
5033  str = lastchar + 1;
5034  }
5035  else
5036  {
5037  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5038  }
5039  }
5040  else if( str[0] == '<' )
5041  {
5042  /* check if expressions begins with a variable */
5043  SCIP_CALL( exprparseReadVariable(blkmem, &str, expr, nvars, varnames, vartable, 1.0, NULL) );
5044  }
5045  /* four character operators */
5046  else if( strncmp(str, "sqrt", 4) == 0 )
5047  {
5048  str += 4;
5049  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5050  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5051  str = endptr + 1;
5052 
5053  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQRT, arg1) );
5054  }
5055  /* three character operators */
5056  else if(
5057  strncmp(str, "abs", 3) == 0 ||
5058  strncmp(str, "cos", 3) == 0 ||
5059  strncmp(str, "exp", 3) == 0 ||
5060  strncmp(str, "log", 3) == 0 ||
5061  strncmp(str, "sin", 3) == 0 ||
5062  strncmp(str, "sqr", 3) == 0 ||
5063  strncmp(str, "tan", 3) == 0 )
5064  {
5065  const char* opname = str;
5066 
5067  str += 3;
5068  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5069  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5070  str = endptr + 1;
5071 
5072  if( strncmp(opname, "abs", 3) == 0 )
5073  {
5074  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_ABS, arg1) );
5075  }
5076  else if( strncmp(opname, "cos", 3) == 0 )
5077  {
5078  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_COS, arg1) );
5079  }
5080  else if( strncmp(opname, "exp", 3) == 0 )
5081  {
5082  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, arg1) );
5083  }
5084  else if( strncmp(opname, "log", 3) == 0 )
5085  {
5086  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5087  }
5088  else if( strncmp(opname, "sin", 3) == 0 )
5089  {
5090  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIN, arg1) );
5091  }
5092  else if( strncmp(opname, "sqr", 3) == 0 )
5093  {
5094  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQUARE, arg1) );
5095  }
5096  else
5097  {
5098  assert(strncmp(opname, "tan", 3) == 0);
5099  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_TAN, arg1) );
5100  }
5101  }
5102  /* Unsupported single argument operands */
5103  else if( strncmp(str, "realpower", 9) == 0 || strncmp(str, "intpower", 8) == 0 || strncmp(str, "signpower", 9) == 0 )
5104  {
5105  SCIPerrorMessage("parsing of expression %.*s is unsupported yet.\n", (int) (lastchar - str + 1), str);
5106  return SCIP_READERROR;
5107  }
5108  else if( isalpha(*str) || *str == '_' )
5109  {
5110  /* check for a variable, that was not recognized earlier because somebody omitted the '<' and '>' we need for
5111  * SCIPparseVarName, making everyones life harder;
5112  * we allow only variable names starting with a character or underscore here
5113  */
5114  const char* varnamestartptr = str;
5115 
5116  /* allow only variable names containing characters, digits, and underscores here */
5117  while( isalnum(str[0]) || str[0] == '_' )
5118  ++str;
5119 
5120  SCIP_CALL( exprparseReadVariable(blkmem, &varnamestartptr, expr, nvars, varnames, vartable, 1.0, str) );
5121  }
5122  else
5123  {
5124  SCIPerrorMessage("parsing of invalid expression %.*s.\n", (int) (lastchar - str + 1), str);
5125  return SCIP_READERROR;
5126  }
5127 
5128  /* if we are one char behind lastchar, we are done */
5129  if( str == lastchar + 1)
5130  {
5131  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5132  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5133  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5134 
5135  return SCIP_OKAY;
5136  }
5137 
5138  /* check if we are still in bounds */
5139  if( str > lastchar + 1)
5140  {
5141  SCIPerrorMessage("error finding first expression in \"%.*s\" took us outside of given subexpression length\n", length, strstart);
5142  return SCIP_READERROR;
5143  }
5144 
5145  /* ignore whitespace */
5146  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5147  ++str;
5148 
5149  /* maybe now we're done? */
5150  if( str >= lastchar + 1)
5151  {
5152  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5153  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5154  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5155 
5156  return SCIP_OKAY;
5157  }
5158 
5159  if( str[0] == '^' )
5160  {
5161  /* a '^' behind the found expression indicates a constant power */
5162  SCIP_Real constant;
5163 
5164  arg1 = *expr;
5165  ++str;
5166 
5167  if( str[0] == '(' )
5168  {
5169  /* we use exprParse to evaluate the bracketed argument */
5170  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5171  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5172 
5173  /* everything else should be written as (int|real|sign)power(a,b)... */
5174  assert(SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST);
5175 
5176  str = endptr + 1;
5177  }
5178  else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5179  {
5180  /* there is a number coming */
5181  if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5182  {
5183  SCIPerrorMessage("error parsing number from <%s>\n", str);
5184  return SCIP_READERROR;
5185  }
5186 
5187  SCIP_CALL( SCIPexprCreate(blkmem, &arg2, SCIP_EXPR_CONST, number) );
5188  str = nonconstendptr;
5189  }
5190  else
5191  {
5192  SCIPerrorMessage("unexpected string following ^ in %.*s\n", length, str);
5193  return SCIP_READERROR;
5194  }
5195 
5196  constant = SCIPexprGetOpReal(arg2);
5197 
5198  /* expr^number is intpower or realpower */
5199  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5200  {
5201  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)SCIPexprGetOpReal(arg2)) );
5202  }
5203  else
5204  {
5205  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, SCIPexprGetOpReal(arg2)) );
5206  }
5207 
5208  /* ignore whitespace */
5209  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5210  ++str;
5211  }
5212 
5213  /* check for a two argument operator that is not a multiplication */
5214  if( str[0] == '+' || str[0] == '-' || str[0] == '/' || str[0] == '^' )
5215  {
5216  char op;
5217 
5218  op = str[0];
5219  arg1 = *expr;
5220 
5221  /* step forward over the operator to go to the beginning of the second argument */
5222  ++str;
5223 
5224  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5225  str = lastchar + 1;
5226 
5227  /* make new expression from two arguments */
5228  if( op == '+')
5229  {
5230  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5231  }
5232  else if( op == '-')
5233  {
5234  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, -1.0, arg2, 0.0) );
5235  }
5236  else if( op == '*' )
5237  {
5238  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5239  {
5240  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5241  }
5242  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5243  {
5244  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5245  }
5246  else
5247  {
5248  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5249  }
5250  }
5251  else
5252  {
5253  assert(op == '/');
5254 
5255  if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5256  {
5257  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, 1.0 / SCIPexprGetOpReal(arg2)) );
5258  }
5259  else
5260  {
5261  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_DIV, arg1, arg2) );
5262  }
5263  }
5264  }
5265 
5266  /* ignore whitespace */
5267  while( isspace((unsigned char)*str) )
5268  ++str;
5269 
5270  /* we are either done or we have a multiplication? */
5271  if( str >= lastchar + 1)
5272  {
5273  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5274  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5275  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5276 
5277  return SCIP_OKAY;
5278  }
5279 
5280  /* if there is a part of the string left to be parsed, we assume that this as a multiplication */
5281  arg1 = *expr;
5282 
5283  /* stepping over multiplication operator if needed */
5284  if( str[0] == '*' )
5285  {
5286  ++str;
5287  }
5288  else if( str[0] != '(' )
5289  {
5290  SCIPdebugMessage("No operator found, assuming a multiplication before %.*s\n", (int) (lastchar - str + 1), str);
5291  }
5292 
5293  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5294 
5295  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5296  {
5297  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5298  }
5299  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5300  {
5301  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5302  }
5303  else
5304  {
5305  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5306  }
5307 
5308  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5309  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5310  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5311 
5312  return SCIP_OKAY;
5313 }
5314 
5315 /**@} */
5316 
5317 /**@name Expression methods */
5318 /**@{ */
5319 
5320 /* In debug mode, the following methods are implemented as function calls to ensure
5321  * type validity.
5322  * In optimized mode, the methods are implemented as defines to improve performance.
5323  * However, we want to have them in the library anyways, so we have to undef the defines.
5324  */
5325 
5326 #undef SCIPexprGetOperator
5327 #undef SCIPexprGetNChildren
5328 #undef SCIPexprGetChildren
5329 #undef SCIPexprGetOpIndex
5330 #undef SCIPexprGetOpReal
5331 #undef SCIPexprGetOpData
5332 #undef SCIPexprGetRealPowerExponent
5333 #undef SCIPexprGetIntPowerExponent
5334 #undef SCIPexprGetSignPowerExponent
5335 #undef SCIPexprGetLinearCoefs
5336 #undef SCIPexprGetLinearConstant
5337 #undef SCIPexprGetQuadElements
5338 #undef SCIPexprGetQuadConstant
5339 #undef SCIPexprGetQuadLinearCoefs
5340 #undef SCIPexprGetNQuadElements
5341 #undef SCIPexprGetMonomials
5342 #undef SCIPexprGetNMonomials
5343 #undef SCIPexprGetPolynomialConstant
5344 #undef SCIPexprGetMonomialCoef
5345 #undef SCIPexprGetMonomialNFactors
5346 #undef SCIPexprGetMonomialChildIndices
5347 #undef SCIPexprGetMonomialExponents
5348 
5349 /** gives operator of expression */
5351  SCIP_EXPR* expr /**< expression */
5352  )
5353 {
5354  assert(expr != NULL);
5355 
5356  return expr->op;
5357 }
5358 
5359 /** gives number of children of an expression */
5361  SCIP_EXPR* expr /**< expression */
5362  )
5363 {
5364  assert(expr != NULL);
5365 
5366  return expr->nchildren;
5367 }
5368 
5369 /** gives pointer to array with children of an expression */
5371  SCIP_EXPR* expr /**< expression */
5372  )
5373 {
5374  assert(expr != NULL);
5375 
5376  return expr->children;
5377 }
5378 
5379 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
5381  SCIP_EXPR* expr /**< expression */
5382  )
5383 {
5384  assert(expr != NULL);
5385  assert(expr->op == SCIP_EXPR_VARIDX || expr->op == SCIP_EXPR_PARAM);
5386 
5387  return expr->data.intval;
5388 }
5389 
5390 /** gives real belonging to a SCIP_EXPR_CONST operand */
5392  SCIP_EXPR* expr /**< expression */
5393  )
5394 {
5395  assert(expr != NULL);
5396  assert(expr->op == SCIP_EXPR_CONST);
5397 
5398  return expr->data.dbl;
5399 }
5400 
5401 /** gives void* belonging to a complex operand */
5403  SCIP_EXPR* expr /**< expression */
5404  )
5405 {
5406  assert(expr != NULL);
5407  assert(expr->op >= SCIP_EXPR_SUM); /* only complex operands store their data as void* */
5408 
5409  return expr->data.data;
5410 }
5411 
5412 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
5414  SCIP_EXPR* expr /**< expression */
5415  )
5416 {
5417  assert(expr != NULL);
5418  assert(expr->op == SCIP_EXPR_REALPOWER);
5419 
5420  return expr->data.dbl;
5421 }
5422 
5423 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
5425  SCIP_EXPR* expr /**< expression */
5426  )
5427 {
5428  assert(expr != NULL);
5429  assert(expr->op == SCIP_EXPR_INTPOWER);
5430 
5431  return expr->data.intval;
5432 }
5433 
5434 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
5436  SCIP_EXPR* expr /**< expression */
5437  )
5438 {
5439  assert(expr != NULL);
5440  assert(expr->op == SCIP_EXPR_SIGNPOWER);
5441 
5442  return expr->data.dbl;
5443 }
5444 
5445 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
5447  SCIP_EXPR* expr /**< expression */
5448  )
5449 {
5450  assert(expr != NULL);
5451  assert(expr->op == SCIP_EXPR_LINEAR);
5452  assert(expr->data.data != NULL);
5453 
5454  /* the coefficients are stored in the first nchildren elements of the array stored as expression data */
5455  return (SCIP_Real*)expr->data.data;
5456 }
5457 
5458 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
5460  SCIP_EXPR* expr /**< expression */
5461  )
5462 {
5463  assert(expr != NULL);
5464  assert(expr->op == SCIP_EXPR_LINEAR);
5465  assert(expr->data.data != NULL);
5466 
5467  /* the constant is stored in the nchildren's element of the array stored as expression data */
5468  return ((SCIP_Real*)expr->data.data)[expr->nchildren];
5469 }
5470 
5471 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5473  SCIP_EXPR* expr /**< quadratic expression */
5474  )
5475 {
5476  assert(expr != NULL);
5477  assert(expr->op == SCIP_EXPR_QUADRATIC);
5478  assert(expr->data.data != NULL);
5479 
5480  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->quadelems;
5481 }
5482 
5483 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
5485  SCIP_EXPR* expr /**< quadratic expression */
5486  )
5487 {
5488  assert(expr != NULL);
5489  assert(expr->op == SCIP_EXPR_QUADRATIC);
5490  assert(expr->data.data != NULL);
5491 
5492  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->constant;
5493 }
5494 
5495 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression
5496  * can be NULL if all coefficients are 0.0 */
5498  SCIP_EXPR* expr /**< quadratic expression */
5499  )
5500 {
5501  assert(expr != NULL);
5502  assert(expr->op == SCIP_EXPR_QUADRATIC);
5503  assert(expr->data.data != NULL);
5504 
5505  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->lincoefs;
5506 }
5507 
5508 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5510  SCIP_EXPR* expr /**< quadratic expression */
5511  )
5512 {
5513  assert(expr != NULL);
5514  assert(expr->op == SCIP_EXPR_QUADRATIC);
5515  assert(expr->data.data != NULL);
5516 
5517  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->nquadelems;
5518 }
5519 
5520 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5522  SCIP_EXPR* expr /**< expression */
5523  )
5524 {
5525  assert(expr != NULL);
5526  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5527  assert(expr->data.data != NULL);
5528 
5529  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->monomials;
5530 }
5531 
5532 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5534  SCIP_EXPR* expr /**< expression */
5535  )
5536 {
5537  assert(expr != NULL);
5538  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5539  assert(expr->data.data != NULL);
5540 
5541  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->nmonomials;
5542 }
5543 
5544 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
5546  SCIP_EXPR* expr /**< expression */
5547  )
5548 {
5549  assert(expr != NULL);
5550  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5551  assert(expr->data.data != NULL);
5552 
5553  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant;
5554 }
5555 
5556 /** gets coefficient of a monomial */
5558  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5559  )
5560 {
5561  assert(monomial != NULL);
5562 
5563  return monomial->coef;
5564 }
5565 
5566 /** gets number of factors of a monomial */
5568  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5569  )
5570 {
5571  assert(monomial != NULL);
5572 
5573  return monomial->nfactors;
5574 }
5575 
5576 /** gets indices of children corresponding to factors of a monomial */
5578  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5579  )
5580 {
5581  assert(monomial != NULL);
5582 
5583  return monomial->childidxs;
5584 }
5585 
5586 /** gets exponents in factors of a monomial */
5588  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5589  )
5590 {
5591  assert(monomial != NULL);
5592 
5593  return monomial->exponents;
5594 }
5595 
5596 
5597 
5598 /** creates a simple expression */
5600  BMS_BLKMEM* blkmem, /**< block memory data structure */
5601  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
5602  SCIP_EXPROP op, /**< operand of expression */
5603  ... /**< arguments of operand */
5604  )
5605 {
5606  va_list ap;
5607  SCIP_EXPR** children;
5608  SCIP_EXPROPDATA opdata;
5609 
5610  assert(blkmem != NULL);
5611  assert(expr != NULL);
5612 
5613  switch( op )
5614  {
5615  case SCIP_EXPR_VARIDX:
5616  case SCIP_EXPR_PARAM:
5617  {
5618  va_start( ap, op ); /*lint !e826*/
5619  opdata.intval = va_arg( ap, int ); /*lint !e416 !e826*/
5620  va_end( ap ); /*lint !e826*/
5621 
5622  assert( opdata.intval >= 0 );
5623 
5624  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5625  break;
5626  }
5627 
5628  case SCIP_EXPR_CONST:
5629  {
5630  va_start(ap, op ); /*lint !e826*/
5631  opdata.dbl = va_arg( ap, SCIP_Real ); /*lint !e416 !e826*/
5632  va_end( ap ); /*lint !e826*/
5633 
5634  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5635  break;
5636  }
5637 
5638  /* operands with two children */
5639  case SCIP_EXPR_PLUS :
5640  case SCIP_EXPR_MINUS :
5641  case SCIP_EXPR_MUL :
5642  case SCIP_EXPR_DIV :
5643  case SCIP_EXPR_MIN :
5644  case SCIP_EXPR_MAX :
5645  {
5646  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 2) ); /*lint !e506*/
5647 
5648  va_start(ap, op ); /*lint !e826*/
5649  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5650  children[1] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5651  assert(children[0] != NULL);
5652  assert(children[1] != NULL);
5653  va_end( ap ); /*lint !e826*/
5654  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
5655 
5656  SCIP_CALL( exprCreate( blkmem, expr, op, 2, children, opdata ) );
5657  break;
5658  }
5659 
5660  /* operands with one child */
5661  case SCIP_EXPR_SQUARE:
5662  case SCIP_EXPR_SQRT :
5663  case SCIP_EXPR_EXP :
5664  case SCIP_EXPR_LOG :
5665  case SCIP_EXPR_SIN :
5666  case SCIP_EXPR_COS :
5667  case SCIP_EXPR_TAN :
5668  /* case SCIP_EXPR_ERF : */
5669  /* case SCIP_EXPR_ERFI : */
5670  case SCIP_EXPR_ABS :
5671  case SCIP_EXPR_SIGN :
5672  {
5673  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
5674 
5675  va_start(ap, op ); /*lint !e826*/
5676  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5677  assert(children[0] != NULL);
5678  va_end( ap ); /*lint !e826*/
5679  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
5680 
5681  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
5682  break;
5683  }
5684 
5685  case SCIP_EXPR_REALPOWER:
5686  case SCIP_EXPR_SIGNPOWER:
5687  {
5688  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
5689 
5690  va_start(ap, op ); /*lint !e826*/
5691  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5692  assert(children[0] != NULL);
5693  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
5694  va_end( ap ); /*lint !e826*/
5695 
5696  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
5697  break;
5698  }
5699 
5700  case SCIP_EXPR_INTPOWER:
5701  {
5702  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
5703 
5704  va_start(ap, op ); /*lint !e826*/
5705  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5706  assert(children[0] != NULL);
5707  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
5708  va_end( ap ); /*lint !e826*/
5709 
5710  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
5711  break;
5712  }
5713 
5714  /* complex operands */
5715  case SCIP_EXPR_SUM :
5716  case SCIP_EXPR_PRODUCT:
5717  {
5718  int nchildren;
5719  SCIP_EXPR** childrenarg;
5720 
5721  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
5722 
5723  va_start(ap, op ); /*lint !e826*/
5724  /* first argument should be number of children */
5725  nchildren = va_arg( ap, int ); /*lint !e416 !e826*/
5726  assert(nchildren >= 0);
5727 
5728  /* for a sum or product of 0 terms we can finish here */
5729  if( nchildren == 0 )
5730  {
5731  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata) );
5732  va_end( ap ); /*lint !e826*/
5733  break;
5734  }
5735 
5736  /* next argument should be array of children expressions */
5737  childrenarg = va_arg( ap, SCIP_EXPR** ); /*lint !e416 !e826*/
5738  assert(childrenarg != NULL);
5739  va_end( ap ); /*lint !e826*/
5740 
5741  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &children, childrenarg, nchildren) );
5742 
5743  SCIP_CALL( exprCreate( blkmem, expr, op, nchildren, children, opdata) );
5744  break;
5745  }
5746 
5747  case SCIP_EXPR_LINEAR :
5748  case SCIP_EXPR_QUADRATIC:
5749  case SCIP_EXPR_POLYNOMIAL:
5750  {
5751  SCIPerrorMessage("cannot create complex expression linear, quadratic, or polynomial with SCIPexprCreate\n");
5752  return SCIP_INVALIDDATA;
5753  }
5754 
5755  case SCIP_EXPR_LAST:
5756  default:
5757  SCIPerrorMessage("unknown operand: %d\n", op);
5758  return SCIP_INVALIDDATA;
5759  }
5760 
5761  return SCIP_OKAY;
5762 }
5763 
5764 /** copies an expression including its children */
5766  BMS_BLKMEM* blkmem, /**< block memory data structure */
5767  SCIP_EXPR** targetexpr, /**< buffer to store pointer to copied expression */
5768  SCIP_EXPR* sourceexpr /**< expression to copy */
5769  )
5770 {
5771  assert(blkmem != NULL);
5772  assert(targetexpr != NULL);
5773  assert(sourceexpr != NULL);
5774 
5775  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targetexpr, sourceexpr) );
5776 
5777  if( sourceexpr->nchildren )
5778  {
5779  int i;
5780 
5781  /* alloc memory for children expressions */
5782  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetexpr)->children, sourceexpr->nchildren) );
5783 
5784  /* copy children expressions */
5785  for( i = 0; i < sourceexpr->nchildren; ++i )
5786  {
5787  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targetexpr)->children[i], sourceexpr->children[i]) );
5788  }
5789  }
5790  else
5791  {
5792  assert((*targetexpr)->children == NULL); /* otherwise, sourceexpr->children was not NULL, which is wrong */
5793  }
5794 
5795  /* call operands data copy callback for complex operands
5796  * for simple operands BMSduplicate above should have done the job
5797  */
5798  if( exprOpTable[sourceexpr->op].copydata != NULL )
5799  {
5800  SCIP_CALL( exprOpTable[sourceexpr->op].copydata(blkmem, sourceexpr->nchildren, sourceexpr->data, &(*targetexpr)->data) );
5801  }
5802 
5803  return SCIP_OKAY;
5804 }
5805 
5806 /** frees an expression including its children */
5808  BMS_BLKMEM* blkmem, /**< block memory data structure */
5809  SCIP_EXPR** expr /**< pointer to expression to free */
5810  )
5811 {
5812  assert(blkmem != NULL);
5813  assert(expr != NULL);
5814  assert(*expr != NULL);
5815 
5816  /* call operands data free callback, if given */
5817  if( exprOpTable[(*expr)->op].freedata != NULL )
5818  {
5819  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
5820  }
5821 
5822  if( (*expr)->nchildren )
5823  {
5824  int i;
5825 
5826  assert( (*expr)->children != NULL );
5827 
5828  for( i = 0; i < (*expr)->nchildren; ++i )
5829  {
5830  SCIPexprFreeDeep(blkmem, &(*expr)->children[i]);
5831  assert((*expr)->children[i] == NULL);
5832  }
5833 
5834  BMSfreeBlockMemoryArray(blkmem, &(*expr)->children, (*expr)->nchildren);
5835  }
5836  else
5837  {
5838  assert( (*expr)->children == NULL );
5839  }
5840 
5841  BMSfreeBlockMemory(blkmem, expr);
5842 }
5843 
5844 /** frees an expression but not its children */
5846  BMS_BLKMEM* blkmem, /**< block memory data structure */
5847  SCIP_EXPR** expr /**< pointer to expression to free */
5848  )
5849 {
5850  assert(blkmem != NULL);
5851  assert(expr != NULL);
5852  assert(*expr != NULL);
5853 
5854  /* call operands data free callback, if given */
5855  if( exprOpTable[(*expr)->op].freedata != NULL )
5856  {
5857  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
5858  }
5859 
5860  BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->nchildren);
5861 
5862  BMSfreeBlockMemory(blkmem, expr);
5863 }
5864 
5865 /** creates an expression from the addition of two given expression, with coefficients, and a constant
5866  *
5867  * the given expressions may be modified or freed, otherwise it will be used a child expression
5868  * favors creation and maintaining of SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM
5869  */
5871  BMS_BLKMEM* blkmem, /**< block memory data structure */
5872  SCIP_EXPR** expr, /**< pointer to store pointer to created expression */
5873  SCIP_Real coef1, /**< coefficient of first term */
5874  SCIP_EXPR* term1, /**< expression of first term, or NULL */
5875  SCIP_Real coef2, /**< coefficient of second term */
5876  SCIP_EXPR* term2, /**< expression of second term, or NULL */
5877  SCIP_Real constant /**< constant term to add */
5878  )
5879 {
5880  assert(blkmem != NULL);
5881  assert(expr != NULL);
5882 
5883  /* @todo could do something special with quadratic and polynomial expressions */
5884 
5885  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_CONST )
5886  {
5887  constant += coef1 * SCIPexprGetOpReal(term1);
5888  SCIPexprFreeDeep(blkmem, &term1);
5889  }
5890 
5891  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_CONST )
5892  {
5893  constant += coef2 * SCIPexprGetOpReal(term2);
5894  SCIPexprFreeDeep(blkmem, &term2);
5895  }
5896 
5897  if( term1 == NULL && term2 == NULL )
5898  {
5899  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, constant) );
5900  return SCIP_OKAY;
5901  }
5902 
5903  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && coef1 != 1.0 )
5904  {
5905  /* multiply coefficients and constant of linear expression term1 by coef1 */
5906  SCIP_Real* data;
5907  int i;
5908 
5909  data = (SCIP_Real*)term1->data.data;
5910  assert(data != NULL);
5911 
5912  /* loop one more index to multiply also constant of linear expression */
5913  for( i = 0; i <= term1->nchildren; ++i )
5914  data[i] *= coef1;
5915 
5916  coef1 = 1.0;
5917  }
5918 
5919  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR && coef2 != 1.0 )
5920  {
5921  /* multiply coefficients and constant of linear expression term2 by coef2 */
5922  SCIP_Real* data;
5923  int i;
5924 
5925  data = (SCIP_Real*)term2->data.data;
5926  assert(data != NULL);
5927 
5928  /* loop one more index to multiply also constant of linear expression */
5929  for( i = 0; i <= term2->nchildren; ++i )
5930  data[i] *= coef2;
5931 
5932  coef2 = 1.0;
5933  }
5934 
5935  if( term1 == NULL || term2 == NULL )
5936  {
5937  if( term1 == NULL )
5938  {
5939  term1 = term2;
5940  coef1 = coef2;
5941  }
5942  if( constant != 0.0 || coef1 != 1.0 )
5943  {
5944  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
5945  {
5946  assert(coef1 == 1.0);
5947 
5948  /* add constant to existing linear expression */
5949  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 0, NULL, NULL, constant) );
5950  *expr = term1;
5951  }
5952  else
5953  {
5954  /* create new linear expression for coef1 * term1 + constant */
5955  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term1, &coef1, constant) );
5956  }
5957  }
5958  else
5959  {
5960  assert(constant == 0.0);
5961  assert(coef1 == 1.0);
5962  *expr = term1;
5963  }
5964 
5965  return SCIP_OKAY;
5966  }
5967 
5969  {
5970  /* add 2nd linear expression to first one */
5971  assert(coef1 == 1.0);
5972  assert(coef2 == 1.0);
5973 
5975  SCIPexprFreeShallow(blkmem, &term2);
5976 
5977  *expr = term1;
5978 
5979  return SCIP_OKAY;
5980  }
5981 
5982  if( SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
5983  {
5984  /* if only term2 is linear, then swap */
5985  SCIP_EXPR* tmp;
5986 
5987  tmp = term2;
5988  assert(coef2 == 1.0);
5989 
5990  term2 = term1;
5991  coef2 = coef1;
5992  term1 = tmp;
5993  coef1 = 1.0;
5994  }
5995 
5996  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
5997  {
5998  /* add coef2*term2 as extra child to linear expression term1 */
5999  assert(coef1 == 1.0);
6000 
6001  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 1, &coef2, &term2, constant) );
6002  *expr = term1;
6003 
6004  return SCIP_OKAY;
6005  }
6006 
6007  /* both terms are not linear, then create new linear term for sum */
6008  {
6009  SCIP_Real coefs[2];
6010  SCIP_EXPR* children[2];
6011 
6012  coefs[0] = coef1;
6013  coefs[1] = coef2;
6014  children[0] = term1;
6015  children[1] = term2;
6016 
6017  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 2, children, coefs, constant) );
6018  }
6019 
6020  return SCIP_OKAY;
6021 }
6022 
6023 /** creates an expression from the multiplication of an expression with a constant
6024  *
6025  * the given expressions may be modified or freed, otherwise it will be used a child expression
6026  * favors creation and maintaining SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM
6027  */
6029  BMS_BLKMEM* blkmem, /**< block memory data structure */
6030  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
6031  SCIP_EXPR* term, /**< term to multiply by factor */
6032  SCIP_Real factor /**< factor */
6033  )
6034 {
6035  assert(blkmem != NULL);
6036  assert(expr != NULL);
6037  assert(term != NULL);
6038 
6039  if( factor == 0.0 )
6040  {
6041  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, 0.0) );
6042 
6043  SCIPexprFreeDeep(blkmem, &term);
6044 
6045  return SCIP_OKAY;
6046  }
6047  if( factor == 1.0 )
6048  {
6049  *expr = term;
6050  return SCIP_OKAY;
6051  }
6052 
6053  switch( SCIPexprGetOperator(term) )
6054  {
6055  case SCIP_EXPR_CONST :
6056  {
6057  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, factor * SCIPexprGetOpReal(term)) );
6058  SCIPexprFreeDeep(blkmem, &term);
6059  break;
6060  }
6061 
6062  case SCIP_EXPR_LINEAR :
6063  {
6064  SCIP_Real* data;
6065  int i;
6066 
6067  data = (SCIP_Real*)term->data.data;
6068  assert(data != NULL);
6069 
6070  /* loop one more index to multiply also constant of linear expression */
6071  for( i = 0; i <= SCIPexprGetNChildren(term); ++i )
6072  data[i] *= factor;
6073 
6074  *expr = term;
6075  break;
6076  }
6077 
6078  case SCIP_EXPR_QUADRATIC :
6079  {
6081  int i;
6082 
6083  data = (SCIP_EXPRDATA_QUADRATIC*)term->data.data;
6084 
6085  data->constant *= factor;
6086 
6087  if( data->lincoefs != NULL )
6088  for( i = 0; i < term->nchildren; ++i )
6089  data->lincoefs[i] *= factor;
6090 
6091  for( i = 0; i < data->nquadelems; ++i )
6092  data->quadelems[i].coef *= factor;
6093 
6094  *expr = term;
6095  break;
6096  }
6097 
6098  case SCIP_EXPR_POLYNOMIAL :
6099  {
6101  int i;
6102 
6103  data = (SCIP_EXPRDATA_POLYNOMIAL*)term->data.data;
6104 
6105  data->constant *= factor;
6106 
6107  for( i = 0; i < data->nmonomials; ++i )
6108  data->monomials[i]->coef *= factor;
6109 
6110  *expr = term;
6111  break;
6112  }
6113 
6114  default:
6115  {
6116  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term, &factor, 0.0) );
6117  break;
6118  }
6119 
6120  } /*lint !e788 */
6121 
6122  return SCIP_OKAY;
6123 }
6124 
6125 /** creates a SCIP_EXPR_LINEAR expression that is (affine) linear in its children: constant + sum_i coef_i child_i */
6127  BMS_BLKMEM* blkmem, /**< block memory data structure */
6128  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6129  int nchildren, /**< number of children */
6130  SCIP_EXPR** children, /**< children of expression */
6131  SCIP_Real* coefs, /**< coefficients of children */
6132  SCIP_Real constant /**< constant part */
6133  )
6134 {
6135  SCIP_EXPROPDATA opdata;
6136  SCIP_EXPR** childrencopy;
6137  SCIP_Real* data;
6138 
6139  assert(nchildren >= 0);
6140  assert(children != NULL || nchildren == 0);
6141  assert(coefs != NULL || nchildren == 0);
6142 
6143  if( nchildren > 0 )
6144  {
6145  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6146  }
6147  else
6148  childrencopy = NULL;
6149 
6150  /* we store the coefficients and the constant in a single array and make this our operand data */
6151  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, nchildren + 1) );
6152  BMScopyMemoryArray(data, coefs, nchildren); /*lint !e644*/
6153  data[nchildren] = constant;
6154 
6155  opdata.data = (void*)data;
6156 
6157  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_LINEAR, nchildren, childrencopy, opdata) );
6158 
6159  return SCIP_OKAY;
6160 }
6161 
6162 /** adds new terms to a linear expression */
6164  BMS_BLKMEM* blkmem, /**< block memory */
6165  SCIP_EXPR* expr, /**< linear expression */
6166  int nchildren, /**< number of children to add */
6167  SCIP_Real* coefs, /**< coefficients of additional children */
6168  SCIP_EXPR** children, /**< additional children expressions */
6169  SCIP_Real constant /**< constant to add */
6170  )
6171 {
6172  SCIP_Real* data;
6173 
6174  assert(blkmem != NULL);
6175  assert(expr != NULL);
6176  assert(expr->op == SCIP_EXPR_LINEAR);
6177  assert(nchildren >= 0);
6178  assert(coefs != NULL || nchildren == 0);
6179  assert(children != NULL || nchildren == 0);
6180 
6181  data = (SCIP_Real*)expr->data.data;
6182  assert(data != NULL);
6183 
6184  /* handle simple case of adding a constant */
6185  if( nchildren == 0 )
6186  {
6187  data[expr->nchildren] += constant;
6188 
6189  return SCIP_OKAY;
6190  }
6191 
6192  /* add new children to expr's children array */
6193  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nchildren) );
6194  BMScopyMemoryArray(&expr->children[expr->nchildren], children, nchildren); /*lint !e866*/
6195 
6196  /* add constant and new coefs to expr's data array */
6197  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, expr->nchildren + 1, expr->nchildren + nchildren + 1) );
6198  data[expr->nchildren + nchildren] = data[expr->nchildren] + constant;
6199  BMScopyMemoryArray(&data[expr->nchildren], coefs, nchildren); /*lint !e866*/
6200  expr->data.data = (void*)data;
6201 
6202  expr->nchildren += nchildren;
6203 
6204  return SCIP_OKAY;
6205 }
6206 
6207 /** creates a SCIP_EXPR_QUADRATIC expression: constant + sum_i coef_i child_i + sum_i coef_i child1_i child2_i */
6209  BMS_BLKMEM* blkmem, /**< block memory data structure */
6210  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6211  int nchildren, /**< number of children */
6212  SCIP_EXPR** children, /**< children of expression */
6213  SCIP_Real constant, /**< constant */
6214  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
6215  int nquadelems, /**< number of quadratic elements */
6216  SCIP_QUADELEM* quadelems /**< quadratic elements specifying coefficients and child indices */
6217  )
6218 {
6219  SCIP_EXPROPDATA opdata;
6220  SCIP_EXPR** childrencopy;
6222 
6223  assert(nchildren >= 0);
6224  assert(children != NULL || nchildren == 0);
6225  assert(quadelems != NULL || nquadelems == 0);
6226 
6227  if( nchildren > 0 )
6228  {
6229  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6230  }
6231  else
6232  childrencopy = NULL;
6233 
6234  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
6235 
6236  opdata.data = (void*)data;
6237 
6238  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_QUADRATIC, nchildren, childrencopy, opdata) );
6239 
6240  return SCIP_OKAY;
6241 }
6242 
6243 /** ensures that quadratic elements of a quadratic expression are sorted */
6245  SCIP_EXPR* expr /**< quadratic expression */
6246  )
6247 {
6248  assert(expr != NULL);
6249  assert(expr->op == SCIP_EXPR_QUADRATIC);
6250  assert(expr->data.data != NULL);
6251 
6253 }
6254 
6255 /** creates a SCIP_EXPR_POLYNOMIAL expression from an array of monomials: constant + sum_i monomial_i */
6257  BMS_BLKMEM* blkmem, /**< block memory data structure */
6258  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6259  int nchildren, /**< number of children */
6260  SCIP_EXPR** children, /**< children of expression */
6261  int nmonomials, /**< number of monomials */
6262  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
6263  SCIP_Real constant, /**< constant part */
6264  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6265  )
6266 {
6267  SCIP_EXPROPDATA opdata;
6268  SCIP_EXPR** childrencopy;
6270 
6271  assert(nchildren >= 0);
6272  assert(children != NULL || nchildren == 0);
6273  assert(monomials != NULL || nmonomials == 0);
6274 
6275  if( nchildren > 0 )
6276  {
6277  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6278  }
6279  else
6280  childrencopy = NULL;
6281 
6282  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
6283  opdata.data = (void*)data;
6284 
6285  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_POLYNOMIAL, nchildren, childrencopy, opdata) );
6286 
6287  return SCIP_OKAY;
6288 }
6289 
6290 /** adds an array of monomials to a SCIP_EXPR_POLYNOMIAL expression */
6292  BMS_BLKMEM* blkmem, /**< block memory of expression */
6293  SCIP_EXPR* expr, /**< expression */
6294  int nmonomials, /**< number of monomials to add */
6295  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
6296  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6297  )
6298 {
6299  assert(blkmem != NULL);
6300  assert(expr != NULL);
6301  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6302  assert(monomials != NULL || nmonomials == 0);
6303 
6304  if( nmonomials == 0 )
6305  return SCIP_OKAY;
6306 
6307  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, nmonomials, monomials, copymonomials) );
6308 
6309  return SCIP_OKAY;
6310 }
6311 
6312 /** changes the constant in a SCIP_EXPR_POLYNOMIAL expression */
6314  SCIP_EXPR* expr, /**< expression */
6315  SCIP_Real constant /**< new value for constant */
6316  )
6317 {
6318  assert(expr != NULL);
6319  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6320  assert(expr->data.data != NULL);
6321 
6322  ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant = constant;
6323 }
6324 
6325 /** multiplies each summand of a polynomial by a given constant */
6327  BMS_BLKMEM* blkmem, /**< block memory */
6328  SCIP_EXPR* expr, /**< polynomial expression */
6329  SCIP_Real factor /**< constant factor */
6330  )
6331 {
6332  assert(expr != NULL);
6333  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6334  assert(expr->data.data != NULL);
6335 
6336  polynomialdataMultiplyByConstant(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor);
6337 }
6338 
6339 /** multiplies each summand of a polynomial by a given monomial */
6341  BMS_BLKMEM* blkmem, /**< block memory */
6342  SCIP_EXPR* expr, /**< polynomial expression */
6343  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
6344  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6345  )
6346 {
6347  assert(blkmem != NULL);
6348  assert(factor != NULL);
6349  assert(expr != NULL);
6350  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6351  assert(expr->data.data != NULL);
6352 
6353  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor, childmap) );
6354 
6355  return SCIP_OKAY;
6356 }
6357 
6358 /** multiplies this polynomial by a polynomial
6359  * factor needs to be different from expr
6360  * children of factor need to be children of expr already, w.r.t. an optional mapping of child indices */
6362  BMS_BLKMEM* blkmem, /**< block memory */
6363  SCIP_EXPR* expr, /**< polynomial expression */
6364  SCIP_EXPR* factor, /**< polynomial factor */
6365  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6366  )
6367 {
6368  assert(blkmem != NULL);
6369  assert(expr != NULL);
6370  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6371  assert(expr->data.data != NULL);
6372  assert(factor != NULL);
6373  assert(factor->op == SCIP_EXPR_POLYNOMIAL);
6374  assert(factor->data.data != NULL);
6375  assert(expr != factor);
6376 
6377 #ifndef NDEBUG
6378  if( childmap == NULL )
6379  {
6380  int i;
6381  assert(factor->nchildren == expr->nchildren);
6382  for( i = 0; i < factor->nchildren; ++i )
6383  assert(SCIPexprAreEqual(expr->children[i], factor->children[i], 0.0));
6384  }
6385  else
6386  {
6387  int i;
6388  for( i = 0; i < factor->nchildren; ++i )
6389  {
6390  assert(childmap[i] >= 0);
6391  assert(childmap[i] < expr->nchildren);
6392  assert(SCIPexprAreEqual(expr->children[childmap[i]], factor->children[i], 0.0));
6393  }
6394  }
6395 #endif
6396 
6398 
6399  return SCIP_OKAY;
6400 }
6401 
6402 /** takes a power of the polynomial
6403  * exponent need to be an integer
6404  * polynomial need to be a monomial, if exponent is negative
6405  */
6407  BMS_BLKMEM* blkmem, /**< block memory */
6408  SCIP_EXPR* expr, /**< polynomial expression */
6409  int exponent /**< exponent of power operation */
6410  )
6411 {
6412  assert(blkmem != NULL);
6413  assert(expr != NULL);
6414  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6415  assert(expr->data.data != NULL);
6416 
6417  SCIP_CALL( polynomialdataPower(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, exponent) );
6418 
6419  return SCIP_OKAY;
6420 }
6421 
6422 /** merges monomials in a polynomial expression that differ only in coefficient into a single monomial
6423  * eliminates monomials with coefficient between -eps and eps
6424  */
6426  BMS_BLKMEM* blkmem, /**< block memory */
6427  SCIP_EXPR* expr, /**< polynomial expression */
6428  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
6429  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
6430  )
6431 {
6432  assert(expr != NULL);
6433  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6434  assert(expr->data.data != NULL);
6435 
6436  polynomialdataMergeMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, eps, mergefactors);
6437 }
6438 
6439 /** checks if two monomials are equal */
6441  SCIP_EXPRDATA_MONOMIAL* monomial1, /**< first monomial */
6442  SCIP_EXPRDATA_MONOMIAL* monomial2, /**< second monomial */
6443  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6444  )
6445 {
6446  int i;
6447 
6448  assert(monomial1 != NULL);
6449  assert(monomial2 != NULL);
6450 
6451  if( monomial1->nfactors != monomial2->nfactors )
6452  return FALSE;
6453 
6454  if( !EPSEQ(monomial1->coef, monomial2->coef, eps) )
6455  return FALSE;
6456 
6457  SCIPexprSortMonomialFactors(monomial1);
6458  SCIPexprSortMonomialFactors(monomial2);
6459 
6460  for( i = 0; i < monomial1->nfactors; ++i )
6461  {
6462  if( monomial1->childidxs[i] != monomial2->childidxs[i] ||
6463  !EPSEQ(monomial1->exponents[i], monomial2->exponents[i], eps) )
6464  return FALSE;
6465  }
6466 
6467  return TRUE;
6468 }
6469 
6470 /** changes coefficient of monomial */
6472  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6473  SCIP_Real newcoef /**< new coefficient */
6474  )
6475 {
6476  assert(monomial != NULL);
6477 
6478  monomial->coef = newcoef;
6479 }
6480 
6481 /** adds factors to a monomial */
6483  BMS_BLKMEM* blkmem, /**< block memory */
6484  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6485  int nfactors, /**< number of factors to add */
6486  int* childidxs, /**< indices of children corresponding to factors */
6487  SCIP_Real* exponents /**< exponent in each factor */
6488  )
6489 {
6490  assert(monomial != NULL);
6491  assert(nfactors >= 0);
6492  assert(childidxs != NULL || nfactors == 0);
6493  assert(exponents != NULL || nfactors == 0);
6494 
6495  if( nfactors == 0 )
6496  return SCIP_OKAY;
6497 
6498  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + nfactors) );
6499  assert(monomial->nfactors + nfactors <= monomial->factorssize);
6500 
6501  BMScopyMemoryArray(&monomial->childidxs[monomial->nfactors], childidxs, nfactors); /*lint !e866*/
6502  BMScopyMemoryArray(&monomial->exponents[monomial->nfactors], exponents, nfactors); /*lint !e866*/
6503 
6504  monomial->nfactors += nfactors;
6505  monomial->sorted = (monomial->nfactors <= 1);
6506 
6507  return SCIP_OKAY;
6508 }
6509 
6510 /** multiplies a monomial with a monomial */
6512  BMS_BLKMEM* blkmem, /**< block memory */
6513  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6514  SCIP_EXPRDATA_MONOMIAL* factor, /**< factor monomial */
6515  int* childmap /**< map to apply to children in factor, or NULL for 1:1 */
6516  )
6517 {
6518  assert(monomial != NULL);
6519  assert(factor != NULL);
6520 
6521  if( factor->coef == 0.0 )
6522  {
6523  monomial->nfactors = 0;
6524  monomial->coef = 0.0;
6525  return SCIP_OKAY;
6526  }
6527 
6528  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, factor->nfactors, factor->childidxs, factor->exponents) );
6529 
6530  if( childmap != NULL )
6531  {
6532  int i;
6533  for( i = monomial->nfactors - factor->nfactors; i < monomial->nfactors; ++i )
6534  monomial->childidxs[i] = childmap[monomial->childidxs[i]];
6535  }
6536 
6537  monomial->coef *= factor->coef;
6538 
6539  return SCIP_OKAY;
6540 }
6541 
6542 /** replaces the monomial by a power of the monomial
6543  * allows only integers as exponent
6544  */
6546  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6547  int exponent /**< integer exponent of power operation */
6548  )
6549 {
6550  int i;
6551 
6552  assert(monomial != NULL);
6553 
6554  if( exponent == 1 )
6555  return;
6556 
6557  if( exponent == 0 )
6558  {
6559  /* x^0 = 1, unless x = 0; 0^0 = 0 */
6560  if( monomial->coef != 0.0 )
6561  monomial->coef = 1.0;
6562  monomial->nfactors = 0;
6563  return;
6564  }
6565 
6566  monomial->coef = pow(monomial->coef, (SCIP_Real)exponent);
6567  for( i = 0; i < monomial->nfactors; ++i )
6568  monomial->exponents[i] *= exponent;
6569 }
6570 
6571 /** merges factors that correspond to the same child by adding exponents
6572  * eliminates factors with exponent between -eps and eps
6573  */
6575  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6576  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6577  )
6578 {
6579  int i;
6580  int offset;
6581 
6582  assert(monomial != NULL);
6583  assert(eps >= 0.0);
6584 
6585  SCIPexprSortMonomialFactors(monomial);
6586 
6587  /* merge factors with same child index by adding up their exponents
6588  * delete factors with exponent 0.0 */
6589  offset = 0;
6590  i = 0;
6591  while( i + offset < monomial->nfactors )
6592  {
6593  if( offset > 0 )
6594  {
6595  assert(monomial->childidxs[i] == -1);
6596  assert(monomial->childidxs[i+offset] >= 0);
6597  monomial->childidxs[i] = monomial->childidxs[i+offset];
6598  monomial->exponents[i] = monomial->exponents[i+offset];
6599 #ifndef NDEBUG
6600  monomial->childidxs[i+offset] = -1;
6601 #endif
6602  }
6603 
6604  while( i+offset+1 < monomial->nfactors && monomial->childidxs[i] == monomial->childidxs[i+offset+1] )
6605  {
6606  monomial->exponents[i] += monomial->exponents[i+offset+1];
6607 #ifndef NDEBUG
6608  monomial->childidxs[i+offset+1] = -1;
6609 #endif
6610  ++offset;
6611  }
6612 
6613  if( EPSZ(monomial->exponents[i], eps) )
6614  {
6615 #ifndef NDEBUG
6616  monomial->childidxs[i] = -1;
6617 #endif
6618  ++offset;
6619  continue;
6620  }
6621  else if( EPSISINT(monomial->exponents[i], eps) )
6622  monomial->exponents[i] = EPSROUND(monomial->exponents[i], eps);
6623 
6624  ++i;
6625  }
6626 
6627 #ifndef NDEBUG
6628  while( i < monomial->nfactors )
6629  assert(monomial->childidxs[i++] == -1);
6630 #endif
6631 
6632  monomial->nfactors -= offset;
6633 
6634  if( EPSEQ(monomial->coef, 1.0, eps) )
6635  monomial->coef = 1.0;
6636  else if( EPSEQ(monomial->coef, -1.0, eps) )
6637  monomial->coef = -1.0;
6638 }
6639 
6640 /** ensures that monomials of a polynomial are sorted */
6642  SCIP_EXPR* expr /**< polynomial expression */
6643  )
6644 {
6645  assert(expr != NULL);
6646  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6647  assert(expr->data.data != NULL);
6648 
6650 }
6651 
6652 /** creates a monomial */
6654  BMS_BLKMEM* blkmem, /**< block memory */
6655  SCIP_EXPRDATA_MONOMIAL** monomial, /**< buffer where to store pointer to new monomial */
6656  SCIP_Real coef, /**< coefficient of monomial */
6657  int nfactors, /**< number of factors in monomial */
6658  int* childidxs, /**< indices of children corresponding to factors, or NULL if identity */
6659  SCIP_Real* exponents /**< exponent in each factor, or NULL if all 1.0 */
6660  )
6661 {
6662  assert(blkmem != NULL);
6663  assert(monomial != NULL);
6664 
6665  SCIP_ALLOC( BMSallocBlockMemory(blkmem, monomial) );
6666 
6667  (*monomial)->coef = coef;
6668  (*monomial)->nfactors = nfactors;
6669  (*monomial)->factorssize = nfactors;
6670  (*monomial)->sorted = (nfactors <= 1);
6671 
6672  if( nfactors > 0 )
6673  {
6674  if( childidxs != NULL )
6675  {
6676  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->childidxs, childidxs, nfactors) );
6677  }
6678  else
6679  {
6680  int i;
6681 
6682  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->childidxs, nfactors) );
6683  for( i = 0; i < nfactors; ++i )
6684  (*monomial)->childidxs[i] = i;
6685  }
6686 
6687  if( exponents != NULL )
6688  {
6689  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->exponents, exponents, nfactors) );
6690  }
6691  else
6692  {
6693  int i;
6694 
6695  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->exponents, nfactors) );
6696  for( i = 0; i < nfactors; ++i )
6697  (*monomial)->exponents[i] = 1.0;
6698  }
6699  }
6700  else
6701  {
6702  (*monomial)->childidxs = NULL;
6703  (*monomial)->exponents = NULL;
6704  }
6705 
6706  return SCIP_OKAY;
6707 }
6708 
6709 /** frees a monomial */
6711  BMS_BLKMEM* blkmem, /**< block memory */
6712  SCIP_EXPRDATA_MONOMIAL** monomial /**< pointer to monomial that should be freed */
6713  )
6714 {
6715  assert(blkmem != NULL);
6716  assert( monomial != NULL);
6717  assert(*monomial != NULL);
6718 
6719  if( (*monomial)->factorssize > 0 )
6720  {
6721  assert((*monomial)->childidxs != NULL);
6722  assert((*monomial)->exponents != NULL);
6723 
6724  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->childidxs, (*monomial)->factorssize);
6725  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->exponents, (*monomial)->factorssize);
6726  }
6727  assert((*monomial)->childidxs == NULL);
6728  assert((*monomial)->exponents == NULL);
6729 
6730  BMSfreeBlockMemory(blkmem, monomial);
6731 }
6732 
6733 /** ensures that factors in a monomial are sorted */
6735  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
6736  )
6737 {
6738  assert(monomial != NULL);
6739 
6740  if( monomial->sorted )
6741  return;
6742 
6743  if( monomial->nfactors > 0 )
6744  SCIPsortIntReal(monomial->childidxs, monomial->exponents, monomial->nfactors);
6745 
6746  monomial->sorted = TRUE;
6747 }
6748 
6749 /** finds a factor corresponding to a given child index in a monomial
6750  * note that if the factors have not been merged, the position of some factor corresponding to a given child is given
6751  * returns TRUE if a factor is found, FALSE if not
6752  */
6754  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6755  int childidx, /**< index of the child which factor to search for */
6756  int* pos /**< buffer to store position of factor */
6757  )
6758 {
6759  assert(monomial != NULL);
6760 
6761  if( monomial->nfactors == 0 )
6762  return FALSE;
6763 
6764  SCIPexprSortMonomialFactors(monomial);
6765 
6766  return SCIPsortedvecFindInt(monomial->childidxs, childidx, monomial->nfactors, pos);
6767 }
6768 
6769 /** indicates whether the expression contains a SCIP_EXPR_PARAM */
6771  SCIP_EXPR* expr /**< expression */
6772  )
6773 {
6774  int i;
6775 
6776  assert(expr != NULL);
6777 
6778  if( expr->op == SCIP_EXPR_PARAM )
6779  return TRUE;
6780 
6781  for( i = 0; i < expr->nchildren; ++i )
6782  if( SCIPexprHasParam(expr->children[i]) )
6783  return TRUE;
6784 
6785  return FALSE;
6786 }
6787 
6788 /** gets maximal degree of expression, or SCIP_EXPR_DEGREEINFINITY if not a polynomial */
6790  SCIP_EXPR* expr, /**< expression */
6791  int* maxdegree /**< buffer to store maximal degree */
6792  )
6793 {
6794  int child1;
6795  int child2;
6796 
6797  assert(expr != NULL);
6798  assert(maxdegree != NULL);
6799 
6800  switch( expr->op )
6801  {
6802  case SCIP_EXPR_VARIDX:
6803  *maxdegree = 1;
6804  break;
6805 
6806  case SCIP_EXPR_CONST:
6807  case SCIP_EXPR_PARAM:
6808  *maxdegree = 0;
6809  break;
6810 
6811  case SCIP_EXPR_PLUS:
6812  case SCIP_EXPR_MINUS:
6813  {
6814  assert(expr->children[0] != NULL);
6815  assert(expr->children[1] != NULL);
6816 
6817  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6818  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
6819 
6820  *maxdegree = MAX(child1, child2);
6821  break;
6822  }
6823 
6824  case SCIP_EXPR_MUL:
6825  {
6826  assert(expr->children[0] != NULL);
6827  assert(expr->children[1] != NULL);
6828 
6829  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6830  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
6831 
6832  *maxdegree = child1 + child2;
6833  break;
6834  }
6835 
6836  case SCIP_EXPR_DIV:
6837  {
6838  assert(expr->children[0] != NULL);
6839  assert(expr->children[1] != NULL);
6840 
6841  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6842  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
6843 
6844  /* if not division by constant, then it is not a polynomial */
6845  *maxdegree = (child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : child1;
6846  break;
6847  }
6848 
6849  case SCIP_EXPR_SQUARE:
6850  {
6851  assert(expr->children[0] != NULL);
6852 
6853  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6854 
6855  *maxdegree = 2 * child1;
6856  break;
6857  }
6858 
6859  case SCIP_EXPR_SQRT:
6860  {
6861  assert(expr->children[0] != NULL);
6862 
6863  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6864 
6865  /* if not squareroot of constant, then no polynomial */
6866  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
6867  break;
6868  }
6869 
6870  case SCIP_EXPR_REALPOWER:
6871  {
6872  assert(expr->children[0] != NULL);
6873 
6874  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6875 
6876  /* constant ^ constant has degree 0 */
6877  if( child1 == 0 )
6878  {
6879  *maxdegree = 0;
6880  break;
6881  }
6882 
6883  /* non-polynomial ^ constant is not a polynomial */
6884  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
6885  {
6886  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
6887  break;
6888  }
6889 
6890  /* so it is polynomial ^ constant
6891  * let's see whether the constant is integral */
6892 
6893  if( expr->data.dbl == 0.0 ) /* polynomial ^ 0 == 0 */
6894  *maxdegree = 0;
6895  else if( expr->data.dbl > 0.0 && (int)expr->data.dbl == expr->data.dbl ) /* natural exponent gives polynomial again */ /*lint !e777*/
6896  *maxdegree = child1 * (int)expr->data.dbl;
6897  else /* negative or nonintegral exponent does not give polynomial */
6898  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
6899 
6900  break;
6901  }
6902 
6903  case SCIP_EXPR_INTPOWER:
6904  {
6905  assert(expr->children[0] != NULL);
6906 
6907  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6908 
6909  /* constant ^ integer or something ^ 0 has degree 0 */
6910  if( child1 == 0 || expr->data.intval == 0 )
6911  {
6912  *maxdegree = 0;
6913  break;
6914  }
6915 
6916  /* non-polynomial ^ integer or something ^ negative is not a polynomial */
6917  if( child1 >= SCIP_EXPR_DEGREEINFINITY || expr->data.intval < 0 )
6918  {
6919  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
6920  break;
6921  }
6922 
6923  /* so it is polynomial ^ natural, which gives a polynomial again */
6924  *maxdegree = child1 * expr->data.intval;
6925 
6926  break;
6927  }
6928 
6929  case SCIP_EXPR_SIGNPOWER:
6930  {
6931  assert(expr->children[0] != NULL);
6932 
6933  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6934 
6935  /* if child is not constant, then it is no polynomial */
6936  *maxdegree = child1 != 0 ? SCIP_EXPR_DEGREEINFINITY : 0;
6937  break;
6938  }
6939 
6940  case SCIP_EXPR_EXP:
6941  case SCIP_EXPR_LOG:
6942  case SCIP_EXPR_SIN:
6943  case SCIP_EXPR_COS:
6944  case SCIP_EXPR_TAN:
6945  /* case SCIP_EXPR_ERF: */
6946  /* case SCIP_EXPR_ERFI: */
6947  case SCIP_EXPR_ABS:
6948  case SCIP_EXPR_SIGN:
6949  {
6950  assert(expr->children[0] != NULL);
6951 
6952  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6953 
6954  /* if argument is not a constant, then no polynomial, otherwise it is a constant */
6955  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
6956  break;
6957  }
6958 
6959  case SCIP_EXPR_MIN:
6960  case SCIP_EXPR_MAX:
6961  {
6962  assert(expr->children[0] != NULL);
6963  assert(expr->children[1] != NULL);
6964 
6965  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6966  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
6967 
6968  /* if any of the operands is not constant, then it is no polynomial */
6969  *maxdegree = (child1 != 0 || child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
6970  break;
6971  }
6972 
6973  case SCIP_EXPR_SUM:
6974  case SCIP_EXPR_LINEAR:
6975  {
6976  int i;
6977 
6978  *maxdegree = 0;
6979  for( i = 0; i < expr->nchildren && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
6980  {
6981  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
6982  if( child1 > *maxdegree )
6983  *maxdegree = child1;
6984  }
6985 
6986  break;
6987  }
6988 
6989  case SCIP_EXPR_PRODUCT:
6990  {
6991  int i;
6992 
6993  *maxdegree = 0;
6994  for( i = 0; i < expr->nchildren; ++i )
6995  {
6996  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
6997  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
6998  {
6999  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7000  break;
7001  }
7002  *maxdegree += child1;
7003  }
7004 
7005  break;
7006  }
7007 
7008  case SCIP_EXPR_QUADRATIC:
7009  {
7010  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7011  int childidx;
7012  int quadidx;
7013 
7014  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7015 
7016  /* make sure quadratic elements are sorted */
7017  quadraticdataSort(quadraticdata);
7018 
7019  *maxdegree = 0;
7020  quadidx = 0;
7021  for( childidx = 0; childidx < expr->nchildren; ++childidx )
7022  {
7023  /* if no linear or no quadratic coefficient with current child on first position, then nothing to do */
7024  if( (quadraticdata->lincoefs == NULL || quadraticdata->lincoefs[childidx] == 0.0) &&
7025  (quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 > childidx) )
7026  continue;
7027 
7028  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[childidx], &child1) );
7029  if( child1 == SCIP_EXPR_DEGREEINFINITY )
7030  {
7031  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7032  break;
7033  }
7034 
7035  while( quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 == childidx )
7036  {
7037  if( quadraticdata->quadelems[quadidx].idx2 == childidx )
7038  {
7039  /* square term */
7040  if( 2*child1 > *maxdegree )
7041  *maxdegree = 2*child1;
7042  }
7043  else
7044  {
7045  /* bilinear term */
7046  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[quadraticdata->quadelems[quadidx].idx2], &child2) );
7047  if( child2 == SCIP_EXPR_DEGREEINFINITY )
7048  {
7049  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7050  break;
7051  }
7052  if( child1 + child2 > *maxdegree )
7053  *maxdegree = child1 + child2;
7054  }
7055  ++quadidx;
7056  }
7057  if( *maxdegree == SCIP_EXPR_DEGREEINFINITY )
7058  break;
7059  }
7060 
7061  break;
7062  }
7063 
7064  case SCIP_EXPR_POLYNOMIAL:
7065  {
7066  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7067  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7068  int monomialdegree;
7069  int i;
7070  int j;
7071 
7072  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7073 
7074  *maxdegree = 0;
7075  for( i = 0; i < polynomialdata->nmonomials && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7076  {
7077  monomialdata = polynomialdata->monomials[i];
7078  assert(monomialdata != NULL);
7079 
7080  /* compute degree of monomial = sum of degree of factors */
7081  monomialdegree = 0;
7082  for( j = 0; j < monomialdata->nfactors; ++j )
7083  {
7084  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[monomialdata->childidxs[j]], &child1) );
7085 
7086  /* if the exponent of the factor is not a natural number and the child is not constant (degree 0),
7087  * then we report that we are not really a polynomial */
7088  if( child1 != 0 && (monomialdata->exponents[j] < 0.0 || (int)monomialdata->exponents[j] != monomialdata->exponents[j]) )
7089  {
7090  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7091  break;
7092  }
7093 
7094  monomialdegree += child1 * (int)monomialdata->exponents[j];
7095  }
7096 
7097  if( monomialdegree > *maxdegree )
7098  *maxdegree = monomialdegree;
7099  }
7100 
7101  break;
7102  }
7103 
7104  case SCIP_EXPR_LAST:
7105  default:
7106  SCIPerrorMessage("unknown operand: %d\n", expr->op);
7107  return SCIP_ERROR;
7108  }
7109 
7110  return SCIP_OKAY;
7111 }
7112 
7113 /** counts usage of variables in expression */
7115  SCIP_EXPR* expr, /**< expression to update */
7116  int* varsusage /**< array with counters of variable usage */
7117  )
7118 {
7119  int i;
7120 
7121  assert(expr != NULL);
7122  assert(varsusage != NULL);
7123 
7124  if( expr->op == SCIP_EXPR_VARIDX )
7125  {
7126  ++varsusage[expr->data.intval];
7127  }
7128 
7129  for( i = 0; i < expr->nchildren; ++i )
7130  SCIPexprGetVarsUsage(expr->children[i], varsusage);
7131 }
7132 
7133 /** compares whether two expressions are the same
7134  * inconclusive, i.e., may give FALSE even if expressions are equivalent (x*y != y*x)
7135  */
7137  SCIP_EXPR* expr1, /**< first expression */
7138  SCIP_EXPR* expr2, /**< second expression */
7139  SCIP_Real eps /**< threshold under which numbers are assumed to be zero */
7140  )
7141 {
7142  assert(expr1 != NULL);
7143  assert(expr2 != NULL);
7144 
7145  if( expr1 == expr2 )
7146  return TRUE;
7147 
7148  if( expr1->op != expr2->op )
7149  return FALSE;
7150 
7151  switch( expr1->op )
7152  {
7153  case SCIP_EXPR_VARIDX:
7154  case SCIP_EXPR_PARAM:
7155  return expr1->data.intval == expr2->data.intval;
7156 
7157  case SCIP_EXPR_CONST:
7158  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps);
7159 
7160  /* operands with two children */
7161  case SCIP_EXPR_PLUS :
7162  case SCIP_EXPR_MINUS :
7163  case SCIP_EXPR_MUL :
7164  case SCIP_EXPR_DIV :
7165  case SCIP_EXPR_MIN :
7166  case SCIP_EXPR_MAX :
7167  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps) && SCIPexprAreEqual(expr1->children[1], expr2->children[1], eps);
7168 
7169  /* operands with one child */
7170  case SCIP_EXPR_SQUARE:
7171  case SCIP_EXPR_SQRT :
7172  case SCIP_EXPR_EXP :
7173  case SCIP_EXPR_LOG :
7174  case SCIP_EXPR_SIN :
7175  case SCIP_EXPR_COS :
7176  case SCIP_EXPR_TAN :
7177  /* case SCIP_EXPR_ERF : */
7178  /* case SCIP_EXPR_ERFI : */
7179  case SCIP_EXPR_ABS :
7180  case SCIP_EXPR_SIGN :
7181  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7182 
7183  case SCIP_EXPR_REALPOWER:
7184  case SCIP_EXPR_SIGNPOWER:
7185  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps) && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7186 
7187  case SCIP_EXPR_INTPOWER:
7188  return expr1->data.intval == expr2->data.intval && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7189 
7190  /* complex operands */
7191  case SCIP_EXPR_SUM :
7192  case SCIP_EXPR_PRODUCT:
7193  {
7194  int i;
7195 
7196  /* @todo sort children and have sorted flag in data? */
7197 
7198  if( expr1->nchildren != expr2->nchildren )
7199  return FALSE;
7200 
7201  for( i = 0; i < expr1->nchildren; ++i )
7202  {
7203  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7204  return FALSE;
7205  }
7206 
7207  return TRUE;
7208  }
7209 
7210  case SCIP_EXPR_LINEAR :
7211  {
7212  SCIP_Real* data1;
7213  SCIP_Real* data2;
7214  int i;
7215 
7216  /* @todo sort children and have sorted flag in data? */
7217 
7218  if( expr1->nchildren != expr2->nchildren )
7219  return FALSE;
7220 
7221  data1 = (SCIP_Real*)expr1->data.data;
7222  data2 = (SCIP_Real*)expr2->data.data;
7223 
7224  /* check if constant and coefficients are equal */
7225  for( i = 0; i < expr1->nchildren + 1; ++i )
7226  if( !EPSEQ(data1[i], data2[i], eps) )
7227  return FALSE;
7228 
7229  /* check if children are equal */
7230  for( i = 0; i < expr1->nchildren; ++i )
7231  {
7232  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7233  return FALSE;
7234  }
7235 
7236  return TRUE;
7237  }
7238 
7239  case SCIP_EXPR_QUADRATIC:
7240  {
7241  SCIP_EXPRDATA_QUADRATIC* data1;
7242  SCIP_EXPRDATA_QUADRATIC* data2;
7243  int i;
7244 
7245  if( expr1->nchildren != expr2->nchildren )
7246  return FALSE;
7247 
7248  data1 = (SCIP_EXPRDATA_QUADRATIC*)expr1->data.data;
7249  data2 = (SCIP_EXPRDATA_QUADRATIC*)expr2->data.data;
7250 
7251  if( data1->nquadelems != data2->nquadelems )
7252  return FALSE;
7253 
7254  if( !EPSEQ(data1->constant, data2->constant, eps) )
7255  return FALSE;
7256 
7257  /* check if linear part is equal */
7258  if( data1->lincoefs != NULL || data2->lincoefs != NULL )
7259  for( i = 0; i < expr1->nchildren; ++i )
7260  {
7261  if( data1->lincoefs == NULL && !EPSZ(data2->lincoefs[i], eps) )
7262  return FALSE;
7263  if( data2->lincoefs == NULL && !EPSZ(data1->lincoefs[i], eps) )
7264  return FALSE;
7265  if( !EPSEQ(data1->lincoefs[i], data2->lincoefs[i], eps) )
7266  return FALSE;
7267  }
7268 
7269  SCIPexprSortQuadElems(expr1);
7270  SCIPexprSortQuadElems(expr2);
7271 
7272  /* check if quadratic elements are equal */
7273  for( i = 0; i < data1->nquadelems; ++i )
7274  if( data1->quadelems[i].idx1 != data2->quadelems[i].idx1 ||
7275  data1->quadelems[i].idx2 != data2->quadelems[i].idx2 ||
7276  !EPSEQ(data1->quadelems[i].coef, data2->quadelems[i].coef, eps) )
7277  return FALSE;
7278 
7279  /* check if children are equal */
7280  for( i = 0; i < expr1->nchildren; ++i )
7281  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7282  return FALSE;
7283 
7284  return TRUE;
7285  }
7286 
7287  case SCIP_EXPR_POLYNOMIAL:
7288  {
7289  SCIP_EXPRDATA_POLYNOMIAL* data1;
7290  SCIP_EXPRDATA_POLYNOMIAL* data2;
7291  int i;
7292 
7293  if( expr1->nchildren != expr2->nchildren )
7294  return FALSE;
7295 
7296  data1 = (SCIP_EXPRDATA_POLYNOMIAL*)expr1->data.data;
7297  data2 = (SCIP_EXPRDATA_POLYNOMIAL*)expr2->data.data;
7298 
7299  if( data1->nmonomials != data2->nmonomials )
7300  return FALSE;
7301 
7302  if( !EPSEQ(data1->constant, data2->constant, eps) )
7303  return FALSE;
7304 
7305  /* make sure polynomials are sorted */
7306  SCIPexprSortMonomials(expr1);
7307  SCIPexprSortMonomials(expr2);
7308 
7309  /* check if monomials are equal */
7310  for( i = 0; i < data1->nmonomials; ++i )
7311  {
7312  if( !SCIPexprAreMonomialsEqual(data1->monomials[i], data2->monomials[i], eps) )
7313  return FALSE;
7314  }
7315 
7316  /* check if children are equal */
7317  for( i = 0; i < expr1->nchildren; ++i )
7318  {
7319  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7320  return FALSE;
7321  }
7322 
7323  return TRUE;
7324  }
7325 
7326  case SCIP_EXPR_LAST:
7327  default:
7328  SCIPerrorMessage("got expression with invalid operand %d\n", expr1->op);
7329  }
7330 
7331  SCIPerrorMessage("this should never happen\n");
7332  SCIPABORT();
7333  return FALSE; /*lint !e527*/
7334 }
7335 
7336 /** aims at simplifying an expression and splitting of a linear expression
7337  * if linear variables are split off, expression interpreter data, if stored in the tree, is freed
7338  */
7340  BMS_BLKMEM* blkmem, /**< block memory data structure */
7341  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7342  SCIP_EXPR* expr, /**< expression */
7343  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
7344  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
7345  int nvars, /**< number of variables in expression */
7346  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
7347  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
7348  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
7349  )
7350 {
7351  assert(blkmem != NULL);
7352  assert(expr != NULL);
7353  assert(eps >= 0.0);
7354 
7355  SCIPdebugMessage("simplify expression: ");
7356  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7357  SCIPdebugPrintf("\n");
7358 
7360 
7361  SCIPdebugMessage("converted to polynomials: ");
7362  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7363  SCIPdebugPrintf("\n");
7364 
7365  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr, eps, maxexpansionexponent) );
7366 
7367  SCIPdebugMessage("polynomials flattened: ");
7368  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7369  SCIPdebugPrintf("\n");
7370 
7371  if( nlinvars != NULL )
7372  {
7373  /* separate linear part from root polynomial */
7374  SCIP_CALL( exprsimplifySeparateLinearFromPolynomial(blkmem, expr, eps, nvars, nlinvars, linidxs, lincoefs) );
7375 
7376  SCIPdebugMessage("separated linear part: ");
7377  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7378  SCIPdebugPrintf("\n");
7379  }
7380 
7382 
7383  SCIPdebugMessage("converted back from polynomials: ");
7384  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7385  SCIPdebugPrintf("\n");
7386 
7387  return SCIP_OKAY;
7388 }
7389 
7390 /** evaluates an expression w.r.t. a point */
7392  SCIP_EXPR* expr, /**< expression */
7393  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression is constant */
7394  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7395  SCIP_Real* val /**< buffer to store value */
7396  )
7397 {
7398  int i;
7400  SCIP_Real* buf;
7401 
7402  /* if many children, get large enough memory to store argument values */
7404  {
7405  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7406  }
7407  else
7408  {
7409  buf = staticbuf;
7410  }
7411 
7412  /* evaluate children */
7413  for( i = 0; i < expr->nchildren; ++i )
7414  {
7415  SCIP_CALL( SCIPexprEval(expr->children[i], varvals, param, &buf[i]) ); /*lint !e644*/
7416  }
7417 
7418  /* evaluate this expression */
7419  assert( exprOpTable[expr->op].eval != NULL );
7420  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, buf, varvals, param, val) );
7421 
7422  /* free memory, if allocated before */
7423  if( staticbuf != buf )
7424  {
7425  BMSfreeMemoryArray(&buf);
7426  }
7427 
7428  return SCIP_OKAY;
7429 }
7430 
7431 /** evaluates an expression w.r.t. an interval */
7433  SCIP_EXPR* expr, /**< expression */
7434  SCIP_Real infinity, /**< value to use for infinity */
7435  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7436  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7437  SCIP_INTERVAL* val /**< buffer to store value */
7438  )
7439 {
7440  int i;
7442  SCIP_INTERVAL* buf;
7443 
7444  /* if many children, get large enough memory to store argument values */
7446  {
7447  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7448  }
7449  else
7450  {
7451  buf = staticbuf;
7452  }
7453 
7454  /* evaluate children */
7455  for( i = 0; i < expr->nchildren; ++i )
7456  {
7457  SCIP_CALL( SCIPexprEvalInt(expr->children[i], infinity, varvals, param, &buf[i]) ); /*lint !e644*/
7458  }
7459 
7460  /* evaluate this expression */
7461  assert( exprOpTable[expr->op].inteval != NULL );
7462  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, buf, varvals, param, val) );
7463 
7464  /* free memory, if allocated before */
7465  if( staticbuf != buf )
7466  {
7467  BMSfreeMemoryArray(&buf);
7468  }
7469 
7470  return SCIP_OKAY;
7471 }
7472 
7473 /** tries to determine the curvature type of an expression w.r.t. given variable domains */
7475  SCIP_EXPR* expr, /**< expression to check */
7476  SCIP_Real infinity, /**< value to use for infinity */
7477  SCIP_INTERVAL* varbounds, /**< domains of variables */
7478  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7479  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
7480  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
7481  )
7482 {
7484  SCIP_INTERVAL* childbounds;
7486  SCIP_EXPRCURV* childcurv;
7487  int i;
7488 
7489  assert(expr != NULL);
7490  assert(curv != NULL);
7491  assert(bounds != NULL);
7492 
7493  /* if many children, get large enough memory to store argument values */
7495  {
7496  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, expr->nchildren) );
7497  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, expr->nchildren) );
7498  }
7499  else
7500  {
7501  childbounds = childboundsbuf;
7502  childcurv = childcurvbuf;
7503  }
7504 
7505  /* check curvature and compute bounds of children
7506  * constant children can be considered as always linear */
7507  for( i = 0; i < expr->nchildren; ++i )
7508  {
7509  SCIP_CALL( SCIPexprCheckCurvature(expr->children[i], infinity, varbounds, param, &childcurv[i], &childbounds[i]) ); /*lint !e644*/
7510  if( childbounds[i].inf == childbounds[i].sup ) /*lint !e777*/
7511  childcurv[i] = SCIP_EXPRCURV_LINEAR;
7512  }
7513 
7514  /* get curvature and bounds of expr */
7515  assert(exprOpTable[expr->op].curv != NULL);
7516  assert(exprOpTable[expr->op].inteval != NULL);
7517 
7518  SCIP_CALL( exprOpTable[expr->op].curv(infinity, expr->data, expr->nchildren, childbounds, childcurv, curv) );
7519  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, childbounds, varbounds, param, bounds) );
7520 
7521  /* free memory, if allocated before */
7522  if( childboundsbuf != childbounds )
7523  {
7524  BMSfreeMemoryArray(&childcurv);
7525  BMSfreeMemoryArray(&childbounds);
7526  }
7527 
7528  return SCIP_OKAY;
7529 }
7530 
7531 /** substitutes variables (SCIP_EXPR_VARIDX) by expressions
7532  * Note that only the children of the given expr are checked!
7533  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL
7534  * if substexprs[i] == NULL, then the variable expression i is not touched
7535  */
7537  BMS_BLKMEM* blkmem, /**< block memory data structure */
7538  SCIP_EXPR* expr, /**< expression, which of the children may be replaced */
7539  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
7540  )
7541 {
7542  int i;
7543 
7544  assert(blkmem != NULL);
7545  assert(expr != NULL);
7546  assert(substexprs != NULL);
7547 
7548  for( i = 0; i < expr->nchildren; ++i )
7549  {
7550  if( expr->children[i]->op == SCIP_EXPR_VARIDX )
7551  {
7552  int varidx;
7553  varidx = expr->children[i]->data.intval;
7554 
7555  assert(varidx >= 0);
7556  if( substexprs[varidx] != NULL )
7557  {
7558  /* replace child i by copy of substexprs[expr->children[i]->opdata.intval] */
7559  SCIPexprFreeDeep(blkmem, &expr->children[i]);
7560  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[i], substexprs[varidx]) );
7561  }
7562  }
7563  else
7564  {
7565  /* call recursively */
7566  SCIP_CALL( SCIPexprSubstituteVars(blkmem, expr->children[i], substexprs) );
7567  }
7568  }
7569 
7570  return SCIP_OKAY;
7571 }
7572 
7573 /** updates variable indices in expression tree */
7575  SCIP_EXPR* expr, /**< expression to update */
7576  int* newindices /**< new indices of variables */
7577  )
7578 {
7579  int i;
7580 
7581  assert(expr != NULL);
7582  assert(newindices != NULL);
7583 
7584  if( expr->op == SCIP_EXPR_VARIDX )
7585  {
7586  expr->data.intval = newindices[expr->data.intval];
7587  assert(expr->data.intval >= 0);
7588  }
7589 
7590  for( i = 0; i < expr->nchildren; ++i )
7591  SCIPexprReindexVars(expr->children[i], newindices);
7592 }
7593 
7594 /** updates parameter indices in expression tree */
7596  SCIP_EXPR* expr, /**< expression to update */
7597  int* newindices /**< new indices of variables */
7598  )
7599 {
7600  int i;
7601 
7602  assert(expr != NULL);
7603  assert(newindices != NULL);
7604 
7605  if( expr->op == SCIP_EXPR_PARAM )
7606  {
7607  expr->data.intval = newindices[expr->data.intval];
7608  assert(expr->data.intval >= 0);
7609  }
7610 
7611  for( i = 0; i < expr->nchildren; ++i )
7612  SCIPexprReindexParams(expr->children[i], newindices);
7613 }
7614 
7615 /** prints an expression */
7617  SCIP_EXPR* expr, /**< expression */
7618  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7619  FILE* file, /**< file for printing, or NULL for stdout */
7620  const char** varnames, /**< names of variables, or NULL for default names */
7621  const char** paramnames, /**< names of parameters, or NULL for default names */
7622  SCIP_Real* paramvals /**< values of parameters, or NULL for not printing */
7623  )
7624 {
7625  assert( expr != NULL );
7626 
7627  switch( expr->op )
7628  {
7629  /* @Note: 'expr->data.intval' is either between 0 and number of variables-1, if it uses the varnames array, or
7630  * between 0 and number of params in the expression tree, if it uses the paramnames array
7631  * because, here, we cannot get the values above we cannot assert them
7632  */
7633  case SCIP_EXPR_VARIDX:
7634  if( varnames != NULL )
7635  {
7636  assert(varnames[expr->data.intval] != NULL);
7637  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", varnames[expr->data.intval]);
7638  }
7639  else
7640  {
7641  SCIPmessageFPrintInfo(messagehdlr, file, "var%d", expr->data.intval);
7642  }
7643  break;
7644 
7645  case SCIP_EXPR_PARAM:
7646  if( paramnames != NULL )
7647  {
7648  assert(paramnames[expr->data.intval] != NULL);
7649  SCIPmessageFPrintInfo(messagehdlr, file, "%s", paramnames[expr->data.intval]);
7650  }
7651  else
7652  {
7653  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", expr->data.intval );
7654  }
7655  if( paramvals != NULL )
7656  {
7657  SCIPmessageFPrintInfo(messagehdlr, file, "[%g]", paramvals[expr->data.intval] );
7658  }
7659  break;
7660 
7661  case SCIP_EXPR_CONST:
7662  if (expr->data.dbl < 0.0 )
7663  SCIPmessageFPrintInfo(messagehdlr, file, "(%lf)", expr->data.dbl );
7664  else
7665  SCIPmessageFPrintInfo(messagehdlr, file, "%lf", expr->data.dbl );
7666  break;
7667 
7668  case SCIP_EXPR_PLUS:
7669  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7670  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
7671  SCIPmessageFPrintInfo(messagehdlr, file, " + ");
7672  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
7673  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7674  break;
7675 
7676  case SCIP_EXPR_MINUS:
7677  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7678  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
7679  SCIPmessageFPrintInfo(messagehdlr, file, " - ");
7680  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
7681  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7682  break;
7683 
7684  case SCIP_EXPR_MUL:
7685  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7686  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
7687  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
7688  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
7689  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7690  break;
7691 
7692  case SCIP_EXPR_DIV:
7693  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7694  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
7695  SCIPmessageFPrintInfo(messagehdlr, file, " / ");
7696  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
7697  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7698  break;
7699 
7700  case SCIP_EXPR_REALPOWER:
7701  case SCIP_EXPR_SIGNPOWER:
7702  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
7703  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
7704  SCIPmessageFPrintInfo(messagehdlr, file, ", %g)", expr->data.dbl);
7705  break;
7706 
7707  case SCIP_EXPR_INTPOWER:
7708  SCIPmessageFPrintInfo(messagehdlr, file, "power(");
7709  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
7710  SCIPmessageFPrintInfo(messagehdlr, file, ", %d)", expr->data.intval);
7711  break;
7712 
7713  case SCIP_EXPR_SQUARE:
7714  case SCIP_EXPR_SQRT:
7715  case SCIP_EXPR_EXP:
7716  case SCIP_EXPR_LOG:
7717  case SCIP_EXPR_SIN:
7718  case SCIP_EXPR_COS:
7719  case SCIP_EXPR_TAN:
7720  /* case SCIP_EXPR_ERF: */
7721  /* case SCIP_EXPR_ERFI: */
7722  case SCIP_EXPR_MIN:
7723  case SCIP_EXPR_MAX:
7724  case SCIP_EXPR_ABS:
7725  case SCIP_EXPR_SIGN:
7726  {
7727  int i;
7728 
7729  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
7730 
7731  for( i = 0; i < expr->nchildren; ++i )
7732  {
7733  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
7734  if( i + 1 < expr->nchildren )
7735  {
7736  SCIPmessageFPrintInfo(messagehdlr, file, ", ");
7737  }
7738  }
7739 
7740  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7741  break;
7742  }
7743 
7744  case SCIP_EXPR_SUM:
7745  case SCIP_EXPR_PRODUCT:
7746  {
7747  switch( expr->nchildren )
7748  {
7749  case 0:
7750  SCIPmessageFPrintInfo(messagehdlr, file, expr->op == SCIP_EXPR_SUM ? "0" : "1");
7751  break;
7752  case 1:
7753  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
7754  break;
7755  default:
7756  {
7757  int i;
7758  const char* opstr = expr->op == SCIP_EXPR_SUM ? " + " : " * ";
7759 
7760  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7761  for( i = 0; i < expr->nchildren; ++i )
7762  {
7763  if( i > 0 )
7764  {
7765  SCIPmessageFPrintInfo(messagehdlr, file, opstr);
7766  }
7767  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
7768  }
7769  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7770  }
7771  }
7772  break;
7773  }
7774 
7775  case SCIP_EXPR_LINEAR:
7776  {
7777  SCIP_Real constant;
7778  int i;
7779 
7780  constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
7781 
7782  if( expr->nchildren == 0 )
7783  {
7784  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
7785  break;
7786  }
7787 
7788  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7789 
7790  if( constant != 0.0 )
7791  {
7792  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
7793  }
7794 
7795  for( i = 0; i < expr->nchildren; ++i )
7796  {
7797  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", ((SCIP_Real*)expr->data.data)[i]);
7798  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
7799  }
7800 
7801  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7802  break;
7803  }
7804 
7805  case SCIP_EXPR_QUADRATIC:
7806  {
7807  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7808  int i;
7809 
7810  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7811  assert(quadraticdata != NULL);
7812 
7813  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7814 
7815  if( quadraticdata->constant != 0.0 )
7816  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->constant);
7817 
7818  if( quadraticdata->lincoefs != NULL )
7819  for( i = 0; i < expr->nchildren; ++i )
7820  {
7821  if( quadraticdata->lincoefs[i] == 0.0 )
7822  continue;
7823  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->lincoefs[i]);
7824  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
7825  }
7826 
7827  for( i = 0; i < quadraticdata->nquadelems; ++i )
7828  {
7829  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->quadelems[i].coef);
7830  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
7831  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
7832  {
7833  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
7834  }
7835  else
7836  {
7837  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
7838  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
7839  }
7840  }
7841 
7842  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7843  break;
7844  }
7845 
7846  case SCIP_EXPR_POLYNOMIAL:
7847  {
7848  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7849  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7850  int i;
7851  int j;
7852 
7853  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7854 
7855  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7856  assert(polynomialdata != NULL);
7857 
7858  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
7859  {
7860  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", polynomialdata->constant);
7861  }
7862 
7863  for( i = 0; i < polynomialdata->nmonomials; ++i )
7864  {
7865  monomialdata = polynomialdata->monomials[i];
7866  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g", monomialdata->coef);
7867 
7868  for( j = 0; j < monomialdata->nfactors; ++j )
7869  {
7870  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
7871 
7872  SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
7873  if( monomialdata->exponents[j] < 0.0 )
7874  {
7875  SCIPmessageFPrintInfo(messagehdlr, file, "^(%.20g)", monomialdata->exponents[j]);
7876  }
7877  else if( monomialdata->exponents[j] != 1.0 )
7878  {
7879  SCIPmessageFPrintInfo(messagehdlr, file, "^%.20g", monomialdata->exponents[j]);
7880  }
7881  }
7882  }
7883 
7884  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7885  break;
7886  }
7887 
7888  case SCIP_EXPR_LAST:
7889  {
7890  SCIPerrorMessage("invalid expression\n");
7891  SCIPABORT();
7892  }
7893  }
7894 }
7895 
7896 /** parses an expression from a string */
7898  BMS_BLKMEM* blkmem, /**< block memory data structure */
7899  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7900  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
7901  const char* str, /**< pointer to the string to be parsed */
7902  const char* lastchar, /**< pointer to the last char of str that should be parsed */
7903  int* nvars, /**< buffer to store number of variables */
7904  int* varnames /**< buffer to store variable names, prefixed by index (as int) */
7905  )
7906 {
7907  SCIP_HASHTABLE* vartable;
7908 
7909  assert(blkmem != NULL);
7910  assert(expr != NULL);
7911  assert(str != NULL);
7912  assert(lastchar != NULL);
7913  assert(nvars != NULL);
7914  assert(varnames != NULL);
7915 
7916  *nvars = 0;
7917 
7918  /* create a hash table for variable names and corresponding expression index
7919  * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
7920  */
7921  SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) );
7922 
7923  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames,
7924  vartable, 0) );
7925 
7926  SCIPhashtableFree(&vartable);
7927 
7928  return SCIP_OKAY;
7929 }
7930 
7931 
7932 /**@} */
7933 
7934 /**@name Expression tree methods */
7935 /**@{ */
7936 
7937 /* In debug mode, the following methods are implemented as function calls to ensure
7938  * type validity.
7939  * In optimized mode, the methods are implemented as defines to improve performance.
7940  * However, we want to have them in the library anyways, so we have to undef the defines.
7941  */
7942 
7943 #undef SCIPexprtreeGetRoot
7944 #undef SCIPexprtreeGetNVars
7945 #undef SCIPexprtreeGetNParams
7946 #undef SCIPexprtreeGetParamVals
7947 #undef SCIPexprtreeSetParamVal
7948 #undef SCIPexprtreeGetInterpreterData
7949 #undef SCIPexprtreeSetInterpreterData
7950 #undef SCIPexprtreeFreeInterpreterData
7951 #undef SCIPexprtreeHasParam
7952 #undef SCIPexprtreeGetMaxDegree
7953 #undef SCIPexprtreeEval
7954 #undef SCIPexprtreeEvalInt
7955 #undef SCIPexprtreePrint
7956 
7957 /** returns root expression of an expression tree */
7959  SCIP_EXPRTREE* tree /**< expression tree */
7960  )
7961 {
7962  assert(tree != NULL);
7963 
7964  return tree->root;
7965 }
7966 
7967 /** returns number of variables in expression tree */
7969  SCIP_EXPRTREE* tree /**< expression tree */
7970  )
7971 {
7972  assert(tree != NULL);
7973 
7974  return tree->nvars;
7975 }
7976 
7977 /** returns number of parameters in expression tree */
7979  SCIP_EXPRTREE* tree /**< expression tree */
7980  )
7981 {
7982  assert(tree != NULL);
7983 
7984  return tree->nparams;
7985 }
7986 
7987 /** returns values of parameters or NULL if none */
7989  SCIP_EXPRTREE* tree /**< expression tree */
7990  )
7991 {
7992  assert(tree != NULL);
7993 
7994  return tree->params;
7995 }
7996 
7997 /** sets value of a single parameter in expression tree */
7999  SCIP_EXPRTREE* tree, /**< expression tree */
8000  int paramidx, /**< index of parameter */
8001  SCIP_Real paramval /**< new value of parameter */
8002  )
8003 {
8004  assert(tree != NULL);
8005  assert(paramidx >= 0);
8006  assert(paramidx < tree->nparams);
8007  assert(tree->params != NULL);
8008 
8009  tree->params[paramidx] = paramval;
8010 }
8011 
8012 /** gets data of expression tree interpreter, or NULL if not set */
8014  SCIP_EXPRTREE* tree /**< expression tree */
8015  )
8016 {
8017  assert(tree != NULL);
8018 
8019  return tree->interpreterdata;
8020 }
8021 
8022 /** sets data of expression tree interpreter */
8024  SCIP_EXPRTREE* tree, /**< expression tree */
8025  SCIP_EXPRINTDATA* interpreterdata /**< expression interpreter data */
8026  )
8027 {
8028  assert(tree != NULL);
8029  assert(interpreterdata != NULL);
8030  assert(tree->interpreterdata == NULL);
8031 
8032  tree->interpreterdata = interpreterdata;
8033 }
8034 
8035 /** frees data of expression tree interpreter, if any */
8037  SCIP_EXPRTREE* tree /**< expression tree */
8038  )
8039 {
8040  if( tree->interpreterdata != NULL )
8041  {
8043  assert(tree->interpreterdata == NULL);
8044  }
8045 
8046  return SCIP_OKAY;
8047 }
8048 
8049 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
8051  SCIP_EXPRTREE* tree /**< expression tree */
8052  )
8053 {
8054  assert(tree != NULL);
8055 
8056  return SCIPexprHasParam(tree->root);
8057 }
8058 
8059 /** Gives maximal degree of expression in expression tree.
8060  * If constant expression, gives 0,
8061  * if linear expression, gives 1,
8062  * if polynomial expression, gives its maximal degree,
8063  * otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8064  */
8066  SCIP_EXPRTREE* tree, /**< expression tree */
8067  int* maxdegree /**< buffer to store maximal degree */
8068  )
8069 {
8070  assert(tree != NULL);
8071 
8072  SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8073 
8074  return SCIP_OKAY;
8075 }
8076 
8077 /** evaluates an expression tree w.r.t. a point */
8079  SCIP_EXPRTREE* tree, /**< expression tree */
8080  SCIP_Real* varvals, /**< values for variables */
8081  SCIP_Real* val /**< buffer to store expression tree value */
8082  )
8083 {
8084  assert(tree != NULL);
8085  assert(varvals != NULL || tree->nvars == 0);
8086  assert(val != NULL);
8087 
8088  SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8089 
8090  return SCIP_OKAY;
8091 }
8092 
8093 /** evaluates an expression tree w.r.t. an interval */
8095  SCIP_EXPRTREE* tree, /**< expression tree */
8096  SCIP_Real infinity, /**< value for infinity */
8097  SCIP_INTERVAL* varvals, /**< intervals for variables */
8098  SCIP_INTERVAL* val /**< buffer to store expression tree value */
8099  )
8100 {
8101  assert(tree != NULL);
8102  assert(varvals != NULL || tree->nvars == 0);
8103  assert(val != NULL);
8104 
8105  SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8106 
8107  return SCIP_OKAY;
8108 }
8109 
8110 /** prints an expression tree */
8112  SCIP_EXPRTREE* tree, /**< expression tree */
8113  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8114  FILE* file, /**< file for printing, or NULL for stdout */
8115  const char** varnames, /**< names of variables, or NULL for default names */
8116  const char** paramnames /**< names of parameters, or NULL for default names */
8117  )
8118 {
8119  assert(tree != NULL);
8120 
8121  SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8122 }
8123 
8124 
8125 /** creates an expression tree */
8127  BMS_BLKMEM* blkmem, /**< block memory data structure */
8128  SCIP_EXPRTREE** tree, /**< buffer to store address of created expression tree */
8129  SCIP_EXPR* root, /**< pointer to root expression, not copied deep !, can be NULL */
8130  int nvars, /**< number of variables in variable mapping */
8131  int nparams, /**< number of parameters in expression */
8132  SCIP_Real* params /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8133  )
8134 {
8135  assert(blkmem != NULL);
8136  assert(tree != NULL);
8137 
8138  SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8139 
8140  (*tree)->blkmem = blkmem;
8141  (*tree)->root = root;
8142  (*tree)->nvars = nvars;
8143  (*tree)->vars = NULL;
8144  (*tree)->nparams = nparams;
8145  (*tree)->interpreterdata = NULL;
8146 
8147  if( params != NULL )
8148  {
8149  assert(nparams > 0);
8150  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8151  }
8152  else if( nparams > 0 )
8153  {
8154  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8155  BMSclearMemoryArray((*tree)->params, nparams);
8156  }
8157  else
8158  {
8159  assert(nparams == 0);
8160  (*tree)->params = NULL;
8161  }
8162 
8163  return SCIP_OKAY;
8164 }
8165 
8166 /** copies an expression tree */
8168  BMS_BLKMEM* blkmem, /**< block memory that should be used in new expression tree */
8169  SCIP_EXPRTREE** targettree, /**< buffer to store address of copied expression tree */
8170  SCIP_EXPRTREE* sourcetree /**< expression tree to copy */
8171  )
8172 {
8173  assert(blkmem != NULL);
8174  assert(targettree != NULL);
8175  assert(sourcetree != NULL);
8176 
8177  /* copy expression tree "header" */
8178  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8179 
8180  /* we may have a new block memory; and we do not want to keep the others interpreter data */
8181  (*targettree)->blkmem = blkmem;
8182  (*targettree)->interpreterdata = NULL;
8183 
8184  /* copy variables, if any */
8185  if( sourcetree->vars != NULL )
8186  {
8187  assert(sourcetree->nvars > 0);
8188 
8189  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8190  }
8191 
8192  /* copy parameters, if any */
8193  if( sourcetree->params != NULL )
8194  {
8195  assert(sourcetree->nparams > 0);
8196 
8197  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8198  }
8199 
8200  /* copy expression */
8201  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8202 
8203  return SCIP_OKAY;
8204 }
8205 
8206 /** frees an expression tree */
8208  SCIP_EXPRTREE** tree /**< pointer to expression tree that is freed */
8209  )
8210 {
8211  assert( tree != NULL);
8212  assert(*tree != NULL);
8213 
8215 
8216  if( (*tree)->root != NULL )
8217  {
8218  SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8219  assert((*tree)->root == NULL);
8220  }
8221 
8222  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars, (*tree)->nvars );
8223  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8224 
8225  BMSfreeBlockMemory((*tree)->blkmem, tree);
8226 
8227  return SCIP_OKAY;
8228 }
8229 
8230 /** sets number and values of all parameters in expression tree */
8232  SCIP_EXPRTREE* tree, /**< expression tree */
8233  int nparams, /**< number of parameters */
8234  SCIP_Real* paramvals /**< values of parameters, can be NULL if nparams == 0 */
8235  )
8236 {
8237  assert(tree != NULL);
8238  assert(paramvals != NULL || nparams == 0);
8239 
8240  if( nparams == 0 )
8241  {
8242  BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8243  }
8244  else if( tree->params != NULL )
8245  {
8246  SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8247  BMScopyMemoryArray(tree->params, paramvals, nparams);
8248  }
8249  else
8250  {
8251  SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8252  }
8253 
8254  tree->nparams = nparams;
8255  assert(tree->params != NULL || tree->nparams == 0);
8256 
8257  return SCIP_OKAY;
8258 }
8259 
8260 
8261 /** gives the number of usages for each variable in the expression tree */
8263  SCIP_EXPRTREE* tree, /**< expression tree */
8264  int* varsusage /**< array where to store for each variable how often it is used in the tree */
8265  )
8266 {
8267  assert(tree != NULL);
8268  assert(varsusage != NULL);
8269 
8270  if( tree->nvars == 0 )
8271  return;
8272 
8273  BMSclearMemoryArray(varsusage, tree->nvars);
8274  SCIPexprGetVarsUsage(tree->root, varsusage);
8275 }
8276 
8277 /** aims at simplifying an expression and splitting of a linear expression
8278  * if linear variables are split off, expression interpreter data, if stored in the tree, is freed
8279  */
8281  SCIP_EXPRTREE* tree, /**< expression tree */
8282  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8283  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
8284  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8285  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8286  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8287  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
8288  )
8289 {
8290 #ifndef NDEBUG
8291  SCIP_Real* testx;
8292  SCIP_Real testval_before;
8293  SCIP_Real testval_after;
8294  int i;
8295  unsigned int seed;
8296 #endif
8297 
8298  assert(tree != NULL);
8299 
8300 #ifndef NDEBUG
8301  seed = 42;
8302  SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) ); /*lint !e666*/
8303  for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8304  testx[i] = SCIPgetRandomReal(-100.0, 100.0, &seed); /*lint !e644*/
8305  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8306 #endif
8307 
8308  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8309  SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8310 
8311 #ifndef NDEBUG
8312  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8313  if( nlinvars != NULL && testval_before == testval_before ) /*lint !e777*/
8314  for( i = 0; i < *nlinvars; ++i )
8315  testval_after += lincoefs[i] * testx[linidxs[i]];
8316  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
8317  BMSfreeMemoryArray(&testx);
8318 #endif
8319 
8320  /* removing something from the the tree may invalidate the interpreter data */
8321  if( nlinvars != NULL && *nlinvars > 0 )
8323 
8324  return SCIP_OKAY;
8325 }
8326 
8327 /** adds an expression to the root expression of the tree
8328  * 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
8329  */
8331  SCIP_EXPRTREE* tree, /**< expression tree */
8332  SCIP_EXPR* expr, /**< expression to add to tree */
8333  SCIP_Bool copyexpr /**< whether expression should be copied */
8334  )
8335 {
8336  assert(tree != NULL);
8337  assert(tree->root != NULL);
8338 
8339  /* adding something to the tree may invalidate the interpreter data */
8341 
8342  if( copyexpr )
8343  {
8344  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &expr, expr) );
8345  }
8346 
8347  SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
8348 
8349  return SCIP_OKAY;
8350 }
8351 
8352 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
8354  SCIP_EXPRTREE* tree, /**< expression tree */
8355  SCIP_Real infinity, /**< value for infinity */
8356  SCIP_INTERVAL* varbounds, /**< domains of variables */
8357  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8358  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression, or NULL if not needed */
8359  )
8360 {
8361  SCIP_INTERVAL exprbounds;
8362 
8363  assert(tree != NULL);
8364  assert(tree->root != NULL);
8365 
8366  SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
8367 
8368  if( bounds != NULL )
8369  *bounds = exprbounds;
8370 
8371  return SCIP_OKAY;
8372 }
8373 
8374 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
8375  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL
8376  * if substexprs[i] == NULL, then the variable expression i is not touched
8377  */
8379  SCIP_EXPRTREE* tree, /**< expression tree */
8380  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8381  )
8382 {
8383  assert(tree != NULL);
8384  assert(tree->root != NULL);
8385 
8386  if( tree->root->op == SCIP_EXPR_VARIDX )
8387  {
8388  int varidx;
8389 
8390  varidx = tree->root->data.intval;
8391  assert(varidx >= 0);
8392  if( substexprs[varidx] != NULL )
8393  {
8394  /* substitute root expression */
8395  SCIPexprFreeDeep(tree->blkmem, &tree->root);
8396  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
8397  }
8398  }
8399  else
8400  {
8401  /* check children (and grandchildren and so on...) of root expression */
8402  SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
8403  }
8404 
8405  /* substitution of variables should invalidate interpreter data */
8407 
8408  return SCIP_OKAY;
8409 }
8410 
8411 /**@} */
8412 
8413 /**@name Quadratic element methods */
8414 /**@{ */
8415 
8416 /** comparing two quadratic elements
8417  * 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
8418  */
8419 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
8420 
8421 /** swaps two quadratic elements */
8422 #define QUADELEMS_SWAP(x,y) \
8423  { \
8424  SCIP_QUADELEM temp = x; \
8425  x = y; \
8426  y = temp; \
8427  }
8428 
8429 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
8430 static
8432  SCIP_QUADELEM* elems, /**< array to be sorted */
8433  int start, /**< starting index */
8434  int end /**< ending index */
8435  )
8436 {
8437  assert(start <= end);
8438 
8439  /* use quick sort for long lists */
8440  while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
8441  {
8442  SCIP_QUADELEM pivotkey;
8443  int lo;
8444  int hi;
8445  int mid;
8446 
8447  /* select pivot element */
8448  mid = (start+end)/2;
8449  pivotkey = elems[mid];
8450 
8451  /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
8452  lo = start;
8453  hi = end;
8454  for( ;; )
8455  {
8456  while( lo < end && QUADELEMS_ISBETTER(elems[lo], pivotkey) )
8457  lo++;
8458  while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
8459  hi--;
8460 
8461  if( lo >= hi )
8462  break;
8463 
8464  QUADELEMS_SWAP(elems[lo], elems[hi]);
8465 
8466  lo++;
8467  hi--;
8468  }
8469  assert(hi == lo-1 || hi == start);
8470 
8471  /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
8472  while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
8473  lo++;
8474 
8475  /* make sure that we have at least one element in the smaller partition */
8476  if( lo == start )
8477  {
8478  /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
8479  assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
8480  assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
8481  QUADELEMS_SWAP(elems[lo], elems[mid]);
8482  lo++;
8483  }
8484 
8485  /* sort the smaller partition by a recursive call, sort the larger part without recursion */
8486  if( hi - start <= end - lo )
8487  {
8488  /* sort [start,hi] with a recursive call */
8489  if( start < hi )
8490  quadelemsQuickSort(elems, start, hi);
8491 
8492  /* now focus on the larger part [lo,end] */
8493  start = lo;
8494  }
8495  else
8496  {
8497  /* sort [lo,end] with a recursive call */
8498  if( lo < end )
8499  quadelemsQuickSort(elems, lo, end);
8500 
8501  /* now focus on the larger part [start,hi] */
8502  end = hi;
8503  }
8504  }
8505 
8506  /* use shell sort on the remaining small list */
8507  if( end - start >= 1 )
8508  {
8509  static const int incs[3] = {1, 5, 19}; /* sequence of increments */
8510  int k;
8511 
8512  for( k = 2; k >= 0; --k )
8513  {
8514  int h;
8515  int i;
8516 
8517  for( h = incs[k], i = h + start; i <= end; ++i )
8518  {
8519  int j;
8520  SCIP_QUADELEM tempkey = elems[i];
8521 
8522  j = i;
8523  while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
8524  {
8525  elems[j] = elems[j-h];
8526  j -= h;
8527  }
8528 
8529  elems[j] = tempkey;
8530  }
8531  }
8532  }
8533 }
8534 
8535 /** sorts an array of quadratic elements
8536  * The elements are sorted such that the first index is increasing and
8537  * such that among elements with the same first index, the second index is increasing.
8538  * For elements with same first and second index, the order is not defined.
8539  */
8541  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
8542  int nquadelems /**< number of quadratic elements */
8543  )
8544 {
8545  if( nquadelems == 0 )
8546  return;
8547 
8548 #ifndef NDEBUG
8549  {
8550  int i;
8551  for( i = 0; i < nquadelems; ++i )
8552  assert(quadelems[i].idx1 <= quadelems[i].idx2);
8553  }
8554 #endif
8555 
8556  quadelemsQuickSort(quadelems, 0, nquadelems-1);
8557 }
8558 
8559 /** Finds an index pair in a sorted array of quadratic elements.
8560  * If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
8561  * 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.
8562  * Assumes that idx1 <= idx2.
8563  */
8565  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
8566  int idx1, /**< index of first variable in element to search for */
8567  int idx2, /**< index of second variable in element to search for */
8568  int nquadelems, /**< number of quadratic elements in array */
8569  int* pos /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
8570  )
8571 {
8572  int left;
8573  int right;
8574 
8575  assert(quadelems != NULL || nquadelems == 0);
8576  assert(idx1 <= idx2);
8577 
8578  if( nquadelems == 0 )
8579  {
8580  if( pos != NULL )
8581  *pos = 0;
8582  return FALSE;
8583  }
8584 
8585  left = 0;
8586  right = nquadelems - 1;
8587  while( left <= right )
8588  {
8589  int middle;
8590 
8591  middle = (left+right)/2;
8592  assert(0 <= middle && middle < nquadelems);
8593 
8594  if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) ) /*lint !e613*/
8595  right = middle - 1;
8596  else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) ) /*lint !e613*/
8597  left = middle + 1;
8598  else
8599  {
8600  if( pos != NULL )
8601  *pos = middle;
8602  return TRUE;
8603  }
8604  }
8605  assert(left == right+1);
8606 
8607  if( pos != NULL )
8608  *pos = left;
8609  return FALSE;
8610 }
8611 
8612 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
8613  * Assumes that elements have been sorted before.
8614  */
8616  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
8617  int nquadelems, /**< number of quadratic elements */
8618  int* nquadelemsnew /**< pointer to store new (reduced) number of quadratic elements */
8619  )
8620 {
8621  int i;
8622  int next;
8623 
8624  assert(quadelems != NULL);
8625  assert(nquadelemsnew != NULL);
8626  assert(nquadelems >= 0);
8627 
8628  i = 0;
8629  next = 0;
8630  while( next < nquadelems )
8631  {
8632  /* assert that array is sorted */
8633  assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
8634  (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
8635 
8636  /* skip elements with coefficient 0.0 */
8637  if( quadelems[next].coef == 0.0 )
8638  {
8639  ++next;
8640  continue;
8641  }
8642 
8643  /* if next element has same index as previous one, add it to the previous one */
8644  if( i >= 1 &&
8645  quadelems[i-1].idx1 == quadelems[next].idx1 &&
8646  quadelems[i-1].idx2 == quadelems[next].idx2 )
8647  {
8648  quadelems[i-1].coef += quadelems[next].coef;
8649  ++next;
8650  continue;
8651  }
8652 
8653  /* otherwise, move next element to current position */
8654  quadelems[i] = quadelems[next];
8655  ++i;
8656  ++next;
8657  }
8658  assert(next == nquadelems);
8659 
8660  /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
8661  *nquadelemsnew = i;
8662 }
8663 
8664 /**@} */
8665 
8666 /**@name Expression graph node private methods */
8667 /**@{ */
8668 
8669 /** adds a parent to an expression graph node */
8670 static
8672  BMS_BLKMEM* blkmem, /**< block memory */
8673  SCIP_EXPRGRAPHNODE* node, /**< expression graph node where to add a parent */
8674  SCIP_EXPRGRAPHNODE* parent /**< parent node */
8675  )
8676 {
8677  assert(blkmem != NULL);
8678  assert(node != NULL);
8679  assert(node->depth >= 0);
8680  assert(node->pos >= 0);
8681  assert(parent != NULL);
8682  assert(parent->depth >= 0);
8683  assert(parent->pos >= 0);
8684  assert(parent->depth > node->depth); /* a parent node need to have larger depth */
8685 
8686  ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
8687  assert(node->nparents < node->parentssize);
8688 
8689  node->parents[node->nparents] = parent;
8690  ++node->nparents;
8691 
8692  /* update sorted flag */
8693  node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (node->parents[node->nparents-2] <= parent));
8694 
8695  return SCIP_OKAY;
8696 }
8697 
8698 /** ensures that array of parents in a node is sorted */
8699 static
8701  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
8702  )
8703 {
8704  assert(node != NULL);
8705 
8706  if( node->parentssorted )
8707  {
8708 #ifndef NDEBUG
8709  int i;
8710  for( i = 1; i < node->nparents; ++i )
8711  assert(ptrcomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
8712 #endif
8713  return;
8714  }
8715 
8716  SCIPsortPtr((void**)node->parents, ptrcomp, node->nparents);
8717 
8718  node->parentssorted = TRUE;
8719 }
8720 
8721 /** removes a parent from an expression graph node
8722  * if the node is not used and has no other parents, then it is freed
8723  */
8724 static
8726  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
8727  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to remove a parent, *node will be set to NULL */
8728  SCIP_EXPRGRAPHNODE* parent /**< parent node to remove */
8729  )
8730 {
8731  SCIP_EXPRGRAPHNODE* node_;
8732  int pos;
8733 
8734  assert(exprgraph != NULL);
8735  assert(node != NULL);
8736  assert(*node != NULL);
8737  assert((*node)->depth >= 0);
8738  assert((*node)->pos >= 0);
8739  assert((*node)->nparents > 0);
8740  assert(parent != NULL);
8741  assert(parent->depth >= 0);
8742  assert(parent->pos >= 0);
8743  assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
8744 
8745  /* find parent */
8746  exprgraphNodeSortParents(*node);
8747  (void) SCIPsortedvecFindPtr((void**)(*node)->parents, ptrcomp, (void*)parent, (*node)->nparents, &pos);
8748  assert(pos >= 0);
8749  assert(pos < (*node)->nparents);
8750  assert((*node)->parents[pos] == parent);
8751 
8752  /* move last parent to pos, if pos is before last
8753  * update sorted flag */
8754  if( pos < (*node)->nparents-1 )
8755  {
8756  (*node)->parents[pos] = (*node)->parents[(*node)->nparents-1];
8757  (*node)->parentssorted = ((*node)->nparents <= 2);
8758  }
8759  --(*node)->nparents;
8760 
8761  /* keep pointer to *node in case it is still used */
8762  node_ = (*node)->nuses > 0 ? *node : NULL;
8763 
8764  /* capture and release node so it is freed if possible */
8765  SCIPexprgraphCaptureNode(*node);
8766  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
8767 
8768  /* restore pointer, if node still exists */
8769  *node = node_;
8770 
8771  return SCIP_OKAY;
8772 }
8773 
8774 /** checks if a node is parent of a node */
8775 static
8777  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
8778  SCIP_EXPRGRAPHNODE* parent /**< parent to look for */
8779  )
8780 {
8781  int pos;
8782 
8783  assert(node != NULL);
8784  assert(parent != NULL);
8785 
8786  /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
8787  if( node->depth >= parent->depth || node->nparents == 0 )
8788  return FALSE;
8789  assert(node->parents != NULL);
8790 
8791  /* ensure parents array is sorted */
8793 
8794  return SCIPsortedvecFindPtr((void**)node->parents, ptrcomp, (void*)parent, node->nparents, &pos);
8795 }
8796 
8797 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
8798  * for a sum or product expression, this corresponds to add additional summands and factors, resp.
8799  * for a linear expression, this corresponds to add each expression with coefficient 1.0
8800  * for a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same
8801  *
8802  * it is assumed that node and all exprs are in the expression graph already
8803  * it is assumed that all expressions that are added have lower depth than node
8804  */
8805 static
8807  BMS_BLKMEM* blkmem, /**< block memory */
8808  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
8809  int nexprs, /**< number of children to add */
8810  SCIP_EXPRGRAPHNODE** exprs, /**< children nodes to add */
8811  int* childmap /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
8812  )
8813 {
8814  int i;
8815  int j;
8816  int orignchildren;
8817  SCIP_Bool existsalready;
8818 
8819  assert(blkmem != NULL);
8820  assert(node != NULL);
8821  assert(node->depth > 0);
8822  assert(node->pos >= 0);
8823  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);
8824  assert(exprs != NULL || nexprs == 0);
8825 
8826  if( nexprs == 0 )
8827  return SCIP_OKAY;
8828 
8829  orignchildren = node->nchildren;
8830  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
8831 
8832  for( i = 0; i < nexprs; ++i )
8833  {
8834  assert(exprs[i]->depth >= 0); /*lint !e613*/
8835  assert(exprs[i]->pos >= 0); /*lint !e613*/
8836  assert(exprs[i]->depth < node->depth); /*lint !e613*/
8837 
8838  /* check if exprs[i] is a child already, if not SUM or PRODUCT */
8839  existsalready = FALSE;
8840  if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
8841  for( j = 0; j < orignchildren; ++j )
8842  /* during simplification of polynomials, their may be NULL's in children array */
8843  if( node->children[j] != NULL && node->children[j] == exprs[i] ) /*lint !e613*/
8844  {
8845  existsalready = TRUE;
8846  break;
8847  }
8848 
8849  if( !existsalready )
8850  {
8851  /* add exprs[i] to children array */
8852  node->children[node->nchildren] = exprs[i]; /*lint !e613*/
8853  SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) ); /*lint !e613*/
8854  if( childmap != NULL )
8855  childmap[i] = node->nchildren;
8856  ++node->nchildren;
8857  }
8858  else
8859  {
8860  if( childmap != NULL )
8861  childmap[i] = j; /*lint !e644*/
8862  if( node->op == SCIP_EXPR_LINEAR )
8863  {
8864  /* if linear expression, increase coefficient by 1.0 */
8865  ((SCIP_Real*)node->data.data)[j] += 1.0;
8866  }
8867  }
8868  }
8869 
8870  /* shrink children array to actually used size */
8871  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
8872 
8873  if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
8874  {
8875  /* if linear expression, then add 1.0 coefficients for new expressions */
8876  SCIP_Real* data;
8877 
8878  data = (SCIP_Real*)node->data.data;
8879  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
8880  data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
8881  for( i = orignchildren; i < node->nchildren; ++i )
8882  data[i] = 1.0;
8883  node->data.data = (void*)data;
8884  }
8885  else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
8886  {
8887  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
8889 
8890  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
8891  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
8892  BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren); /*lint !e866*/
8893  }
8894 
8895  node->simplified = FALSE;
8896 
8897  return SCIP_OKAY;
8898 }
8899 
8900 /** replaces a child node by another node
8901  * assumes that both nodes represent the same expression
8902  * if this node was the last parent of oldchild and oldchild is not in use, then it is freed
8903  * newchild must have deeper depth than node
8904  */
8905 static
8907  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
8908  SCIP_EXPRGRAPHNODE* node, /**< pointer to expression graph node */
8909  SCIP_EXPRGRAPHNODE** oldchild, /**< child node that should be replaced, it may be freed */
8910  SCIP_EXPRGRAPHNODE* newchild /**< node that should take position of oldchild */
8911  )
8912 {
8913  int i;
8914 
8915  assert(exprgraph != NULL);
8916  assert(node != NULL);
8917  assert(oldchild != NULL);
8918  assert(*oldchild != NULL);
8919  assert(newchild != NULL);
8920 
8921  if( *oldchild == newchild )
8922  return SCIP_OKAY;
8923 
8924  SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
8925 
8926  /* search for oldchild in children array */
8927  for( i = 0; i < node->nchildren; ++i )
8928  {
8929  if( node->children[i] == *oldchild )
8930  {
8931  /* add as parent to newchild */
8932  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
8933 
8934  /* remove as parent from oldchild */
8935  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
8936 
8937  /* set newchild as child i */
8938  node->children[i] = newchild;
8939 
8940  /* we're done */
8941  break;
8942  }
8943  }
8944  assert(i < node->nchildren); /* assert that oldchild has been found in children array */
8945 
8946  node->simplified = FALSE;
8947 
8948  return SCIP_OKAY;
8949 }
8950 
8951 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
8952  * a node is larger than another node, if their corresponding constants are related that way
8953  */
8954 static
8955 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
8956 {
8957  assert(elem1 != NULL);
8958  assert(elem2 != NULL);
8959  assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
8960  assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
8961  assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
8962  assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
8963 
8964  if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
8965  return 1;
8966  else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
8967  return -1;
8968  else
8969  return 0;
8970 }
8971 
8972 /** sort array of nodes that holds constants */
8973 static
8975  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
8976  )
8977 {
8978  assert(exprgraph != NULL);
8979 
8980  if( exprgraph->constssorted )
8981  return;
8982 
8983  SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
8984 
8985  exprgraph->constssorted = TRUE;
8986 }
8987 
8988 /** finds position of expression graph node corresponding to a constant in constnodes array */
8989 static
8991  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
8992  SCIP_EXPRGRAPHNODE* node, /**< node to search for */
8993  int* pos /**< buffer to store position of node, if found */
8994  )
8995 {
8996  int left;
8997  int right;
8998  int middle;
8999 
9000  assert(exprgraph != NULL);
9001  assert(node != NULL);
9002  assert(node->op == SCIP_EXPR_CONST);
9003  assert(node->depth == 0);
9004  assert(node->pos >= 0);
9005  assert(pos != NULL);
9006 
9007  exprgraphSortConstNodes(exprgraph);
9008  assert(exprgraph->constssorted);
9009 
9010  /* find a node with constant node->data.dbl using binary search */
9011  left = 0;
9012  right = exprgraph->nconsts-1;
9013  *pos = -1;
9014  while( left <= right )
9015  {
9016  middle = (left+right)/2;
9017  assert(0 <= middle && middle < exprgraph->nconsts);
9018 
9019  if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9020  right = middle - 1;
9021  else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9022  left = middle + 1;
9023  else
9024  {
9025  *pos = middle;
9026  break;
9027  }
9028  }
9029  assert(left == right+1 || *pos >= 0);
9030  if( left == right+1 )
9031  return FALSE;
9032 
9033  /* search left of *pos to find node */
9034  while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl ) /*lint !e777*/
9035  --*pos;
9036  /* search right of *pos to find node */
9037  while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl ) /*lint !e777*/
9038  ++*pos;
9039 
9040  return exprgraph->constnodes[*pos] == node;
9041 }
9042 
9043 /** creates an expression graph node */
9044 static
9046  BMS_BLKMEM* blkmem, /**< block memory */
9047  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
9048  SCIP_EXPROP op, /**< operator type of expression */
9049  SCIP_EXPROPDATA opdata /**< operator data of expression */
9050  )
9051 {
9052  assert(blkmem != NULL);
9053  assert(node != NULL);
9054 
9055  SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9056  BMSclearMemory(*node);
9057 
9058  (*node)->op = op;
9059  (*node)->data = opdata;
9060 
9061  /* mark graph position as not in graph yet */
9062  (*node)->depth = -1;
9063  (*node)->pos = -1;
9064 
9065  /* arrays of length 0 are trivially sorted */
9066  (*node)->parentssorted = TRUE;
9067 
9068  /* set bounds interval to entire */
9069  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9070  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9071 
9072  /* set initial value to invalid */
9073  (*node)->value = SCIP_INVALID;
9074 
9075  /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9076  if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9077  (*node)->curv = SCIP_EXPRCURV_LINEAR;
9078  else
9079  (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9080 
9081  /* per default, a node is enabled */
9082  (*node)->enabled = TRUE;
9083 
9084  return SCIP_OKAY;
9085 }
9086 
9087 /** prints the expression corresponding to a node (not recursively) */
9088 static
9090  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9091  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9092  FILE* file, /**< file to print to, or NULL for stdout */
9093  const char** varnames, /**< variable names, or NULL for generic names */
9094  SCIP_Bool printchildrenbounds /**< whether to print bounds of children */
9095  )
9096 {
9097  int i;
9098 
9099  assert(node != NULL);
9100 
9101  switch( node->op )
9102  {
9103  case SCIP_EXPR_VARIDX:
9104  if( varnames != NULL )
9105  {
9106  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9107  }
9108  else
9109  SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9110  break;
9111 
9112  case SCIP_EXPR_CONST:
9113  SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9114  break;
9115 
9116  case SCIP_EXPR_PARAM:
9117  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9118  break;
9119 
9120  case SCIP_EXPR_PLUS:
9121  if( printchildrenbounds )
9122  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9123  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9124  if( printchildrenbounds )
9125  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9126  break;
9127 
9128  case SCIP_EXPR_MINUS:
9129  if( printchildrenbounds )
9130  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9131  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9132  if( printchildrenbounds )
9133  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9134  break;
9135 
9136  case SCIP_EXPR_MUL:
9137  if( printchildrenbounds )
9138  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9139  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9140  if( printchildrenbounds )
9141  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9142  break;
9143 
9144  case SCIP_EXPR_DIV:
9145  if( printchildrenbounds )
9146  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9147  SCIPmessageFPrintInfo(messagehdlr, file, "/");
9148  if( printchildrenbounds )
9149  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9150  break;
9151 
9152  case SCIP_EXPR_SQUARE:
9153  if( printchildrenbounds )
9154  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9155  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9156  break;
9157 
9158  case SCIP_EXPR_REALPOWER:
9159  if( printchildrenbounds )
9160  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9161  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9162  break;
9163 
9164  case SCIP_EXPR_SIGNPOWER:
9165  if( printchildrenbounds )
9166  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9167  node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9168  else
9169  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9170  break;
9171 
9172  case SCIP_EXPR_INTPOWER:
9173  SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9174  if( printchildrenbounds )
9175  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9176  SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9177  break;
9178 
9179  case SCIP_EXPR_SQRT:
9180  case SCIP_EXPR_EXP:
9181  case SCIP_EXPR_LOG:
9182  case SCIP_EXPR_SIN:
9183  case SCIP_EXPR_COS:
9184  case SCIP_EXPR_TAN:
9185  /* SCIP_EXPR_ERF = 20, */ /**< gaussian error function (1 operand) */
9186  /* SCIP_EXPR_ERFI = 21, */ /**< imaginary part of gaussian error function (1 operand) */
9187  case SCIP_EXPR_MIN:
9188  case SCIP_EXPR_MAX:
9189  case SCIP_EXPR_ABS:
9190  case SCIP_EXPR_SIGN:
9191  SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9192  if( printchildrenbounds )
9193  {
9194  SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9195  if( node->nchildren == 2 )
9196  SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9197  SCIPmessageFPrintInfo(messagehdlr, file, ")");
9198  }
9199  break;
9200 
9201  case SCIP_EXPR_SUM:
9202  if( printchildrenbounds )
9203  for( i = 0; i < node->nchildren; ++i )
9204  {
9205  if( i > 0 )
9206  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9207  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9208  }
9209  else
9210  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9211  break;
9212 
9213  case SCIP_EXPR_PRODUCT:
9214  if( printchildrenbounds )
9215  for( i = 0; i < node->nchildren; ++i )
9216  {
9217  if( i > 0 )
9218  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9219  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9220  }
9221  else
9222  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9223  break;
9224 
9225  case SCIP_EXPR_LINEAR:
9226  {
9227  SCIP_Real constant;
9228 
9229  constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9230 
9231  if( constant != 0.0 || node->nchildren == 0 )
9232  SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9233 
9234  for( i = 0; i < node->nchildren; ++i )
9235  {
9236  if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9237  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9238  else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9239  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9240  else
9241  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9242  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9243  if( printchildrenbounds )
9244  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9245  }
9246 
9247  break;
9248  }
9249 
9250  case SCIP_EXPR_QUADRATIC:
9251  {
9252  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9253 
9254  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9255  assert(quadraticdata != NULL);
9256 
9257  if( quadraticdata->constant != 0.0 )
9258  SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9259 
9260  if( quadraticdata->lincoefs != NULL )
9261  for( i = 0; i < node->nchildren; ++i )
9262  {
9263  if( quadraticdata->lincoefs[i] == 0.0 )
9264  continue;
9265  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9266  if( printchildrenbounds )
9267  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9268  }
9269 
9270  for( i = 0; i < quadraticdata->nquadelems; ++i )
9271  {
9272  if( quadraticdata->quadelems[i].coef == 1.0 )
9273  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9274  else if( quadraticdata->quadelems[i].coef == -1.0 )
9275  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9276  else
9277  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9278  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9279  if( printchildrenbounds )
9280  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9281  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9282  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9283  else
9284  {
9285  SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9286  if( printchildrenbounds )
9287  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9288  }
9289  }
9290 
9291  break;
9292  }
9293 
9294  case SCIP_EXPR_POLYNOMIAL:
9295  {
9296  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9297  SCIP_EXPRDATA_MONOMIAL* monomialdata;
9298  int j;
9299 
9300  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9301  assert(polynomialdata != NULL);
9302 
9303  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
9304  {
9305  SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
9306  }
9307 
9308  for( i = 0; i < polynomialdata->nmonomials; ++i )
9309  {
9310  monomialdata = polynomialdata->monomials[i];
9311  if( monomialdata->coef == 1.0 )
9312  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9313  else if( monomialdata->coef == -1.0 )
9314  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9315  else
9316  SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
9317 
9318  for( j = 0; j < monomialdata->nfactors; ++j )
9319  {
9320  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
9321  if( printchildrenbounds )
9322  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
9323  if( monomialdata->exponents[j] < 0.0 )
9324  SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
9325  else if( monomialdata->exponents[j] != 1.0 )
9326  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
9327  }
9328  }
9329 
9330  break;
9331  }
9332 
9333  case SCIP_EXPR_LAST:
9334  default:
9335  SCIPmessageFPrintInfo(messagehdlr, file, SCIPexpropGetName(node->op));
9336  break;
9337  }
9338 }
9339 
9340 /** prints a node of an expression graph */
9341 static
9343  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9344  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9345  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9346  FILE* file, /**< file to print to, or NULL for stdout */
9347  const char** varnames /**< variable names, or NULL for generic names */
9348  )
9349 {
9350  SCIP_Real color;
9351  int i;
9352 
9353  assert(exprgraph != NULL);
9354  assert(node != NULL);
9355  assert(file != NULL);
9356 
9357  color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
9358  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
9359 
9360  exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
9361 
9362  SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
9364  SCIPmessageFPrintInfo(messagehdlr, file, "!");
9366  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9368  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9369 
9370  SCIPmessageFPrintInfo(messagehdlr, file, "\"");
9371 
9372  if( !node->enabled )
9373  SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
9374 
9375  SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
9376 
9377  /* add edges from node to children */
9378  for( i = 0; i < node->nchildren; ++i )
9379  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);
9380 }
9381 
9382 /** evaluate node of expression graph w.r.t. values stored in children */
9383 static
9385  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9386  SCIP_Real* varvals /**< values for variables */
9387  )
9388 {
9389  int i;
9391  SCIP_Real* buf;
9392 
9393  assert(node != NULL);
9394 
9395  /* if many children, get large enough memory to store argument values */
9397  {
9398  SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
9399  }
9400  else
9401  {
9402  buf = staticbuf;
9403  }
9404 
9405  /* get values of children */
9406  for( i = 0; i < node->nchildren; ++i )
9407  {
9408  assert(node->children[i]->value != SCIP_INVALID); /*lint !e777*/
9409  buf[i] = node->children[i]->value; /*lint !e644*/
9410  }
9411 
9412  /* evaluate this expression */
9413  assert(exprOpTable[node->op].eval != NULL);
9414  SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
9415  assert(node->value != SCIP_INVALID); /*lint !e777*/
9416 
9417  /* free memory, if allocated before */
9418  if( staticbuf != buf )
9419  {
9420  BMSfreeMemoryArray(&buf);
9421  }
9422 
9423  return SCIP_OKAY;
9424 }
9425 
9426 /** evaluates node including subtree */
9427 static
9429  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9430  SCIP_Real* varvals /**< values for variables */
9431  )
9432 {
9433  int i;
9434 
9435  assert(node != NULL);
9436 
9437  for( i = 0; i < node->nchildren; ++i )
9438  {
9439  SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
9440  }
9441 
9442  SCIP_CALL( exprgraphNodeEval(node, varvals) );
9443 
9444  return SCIP_OKAY;
9445 }
9446 
9447 /** updates bounds of a node if a children has changed its bounds */
9448 static
9450  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9451  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
9452  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
9453  SCIP_Bool parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
9454  )
9455 {
9456  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
9457  SCIP_INTERVAL* childbounds;
9458  SCIP_INTERVAL newbounds;
9459  int i;
9460 
9461  assert(node != NULL);
9462  assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
9463  assert(node->pos >= 0); /* node should be in graph */
9464  assert(node->op != SCIP_EXPR_VARIDX);
9465  assert(node->op != SCIP_EXPR_PARAM);
9466 
9467  /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
9468  * if node is disabled, then also do nothing */
9469  if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
9470  return SCIP_OKAY;
9471 
9472  /* if many children, get large enough memory to store children bounds */
9474  {
9475  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
9476  }
9477  else
9478  {
9479  childbounds = childboundsstatic;
9480  }
9481 
9482  /* assemble bounds of children */
9483  for( i = 0; i < node->nchildren; ++i )
9484  {
9485  /* child should have valid and non-empty bounds */
9487  assert(!SCIPintervalIsEmpty(node->children[i]->bounds));
9488 
9489  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
9490  }
9491 
9492  /* call interval evaluation function for this operand */
9493  assert( exprOpTable[node->op].inteval != NULL );
9494  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
9495 
9496  /* free memory, if allocated before */
9497  if( childbounds != childboundsstatic )
9498  {
9499  BMSfreeMemoryArray(&childbounds);
9500  }
9501 
9502  /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
9503 
9504  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
9505  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
9506  *
9507  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
9508  *
9509  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
9510  */
9511  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
9512  ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
9513  {
9514  for( i = 0; i < node->nparents; ++i )
9516 
9517  node->bounds = newbounds;
9518  }
9519  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
9520  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
9521  {
9522  for( i = 0; i < node->nparents; ++i )
9524 
9525  node->bounds = newbounds;
9526  }
9527  else
9528  {
9529  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
9530  }
9531 
9532  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);
9533 
9534  /* node now has valid bounds */
9536 
9537  return SCIP_OKAY;
9538 }
9539 
9540 /** propagate bounds of a node into children by reverting the nodes expression */
9541 static
9543  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9544  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
9545  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
9546  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
9547  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
9548  )
9549 {
9550  SCIP_INTERVAL childbounds;
9551  int i;
9552 
9553  assert(exprgraph != NULL);
9554  assert(node != NULL);
9555  assert(node->depth >= 0); /* node should be in graph */
9556  assert(node->pos >= 0); /* node should be in graph */
9557  assert(minstrength >= 0.0);
9558  assert(cutoff != NULL);
9559  assert(!SCIPintervalIsEmpty(node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
9560  assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
9561 
9562  /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
9564  return;
9565 
9566  /* if node is not enabled, then do nothing */
9567  if( !node->enabled )
9568  return;
9569 
9570  /* tell children that they should propagate their bounds even if not tightened */
9572  minstrength = -1.0;
9573 
9574  /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
9576 
9577  /* 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);
9578  * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
9579  * SCIPdebugPrintf("\n");
9580  */
9581 
9582  /* @todo add callback to exprOpTable for this */
9583 
9584  switch( node->op )
9585  {
9586  case SCIP_EXPR_VARIDX:
9587  case SCIP_EXPR_CONST:
9588  case SCIP_EXPR_PARAM:
9589  /* cannot propagate bound changes further */
9590  break;
9591 
9592  case SCIP_EXPR_PLUS:
9593  {
9594  assert(node->nchildren == 2);
9595  /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
9596 
9597  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
9598  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9599 
9600  if( *cutoff )
9601  break;
9602 
9603  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
9604  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9605 
9606  break;
9607  }
9608 
9609  case SCIP_EXPR_MINUS:
9610  {
9611  assert(node->nchildren == 2);
9612  /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
9613 
9614  SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
9615  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9616 
9617  if( *cutoff )
9618  break;
9619 
9620  SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
9621  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9622 
9623  break;
9624  }
9625 
9626  case SCIP_EXPR_MUL:
9627  {
9628  assert(node->nchildren == 2);
9629  /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
9630 
9631  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
9632  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9633 
9634  if( *cutoff )
9635  break;
9636 
9637  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
9638  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9639 
9640  break;
9641  }
9642 
9643  case SCIP_EXPR_DIV:
9644  {
9645  assert(node->nchildren == 2);
9646  /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
9647 
9648  SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
9649  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9650 
9651  if( *cutoff )
9652  break;
9653 
9654  SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
9655  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9656 
9657  break;
9658  }
9659 
9660  case SCIP_EXPR_SQUARE:
9661  {
9662  assert(node->nchildren == 1);
9663  /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
9664 
9665  if( node->bounds.sup < 0.0 )
9666  {
9667  *cutoff = TRUE;
9668  break;
9669  }
9670 
9671  SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
9672  if( node->children[0]->bounds.inf <= -childbounds.inf )
9673  SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
9674  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9675 
9676  break;
9677  }
9678 
9679  case SCIP_EXPR_SQRT:
9680  {
9681  assert(node->nchildren == 1);
9682  /* f = sqrt(c0) -> c0 = f^2 */
9683 
9684  SCIPintervalSquare(infinity, &childbounds, node->bounds);
9685  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9686 
9687  break;
9688  }
9689 
9690  case SCIP_EXPR_REALPOWER:
9691  {
9692  assert(node->nchildren == 1);
9693 
9694  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
9695 
9696  if( SCIPintervalIsEmpty(childbounds) )
9697  {
9698  *cutoff = TRUE;
9699  break;
9700  }
9701  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9702 
9703  break;
9704  }
9705 
9706  case SCIP_EXPR_SIGNPOWER:
9707  {
9708  assert(node->nchildren == 1);
9709 
9710  if( node->data.dbl != 0.0 )
9711  {
9712  SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
9713  }
9714  else
9715  {
9716  /* behaves like SCIP_EXPR_SIGN */
9717  SCIPintervalSetBounds(&childbounds,
9718  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
9719  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
9720  }
9721 
9722  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9723 
9724  break;
9725  }
9726 
9727  case SCIP_EXPR_INTPOWER:
9728  {
9729  assert(node->nchildren == 1);
9730 
9731  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
9732 
9733  if( SCIPintervalIsEmpty(childbounds) )
9734  {
9735  *cutoff = TRUE;
9736  break;
9737  }
9738  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9739 
9740  break;
9741  }
9742 
9743  case SCIP_EXPR_EXP:
9744  {
9745  assert(node->nchildren == 1);
9746  /* f = exp(c0) -> c0 = log(f) */
9747 
9748  if( node->bounds.sup < 0.0 )
9749  {
9750  *cutoff = TRUE;
9751  break;
9752  }
9753 
9754  SCIPintervalLog(infinity, &childbounds, node->bounds);
9755  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9756 
9757  break;
9758  }
9759 
9760  case SCIP_EXPR_LOG:
9761  {
9762  assert(node->nchildren == 1);
9763  /* f = log(c0) -> c0 = exp(f) */
9764 
9765  SCIPintervalExp(infinity, &childbounds, node->bounds);
9766  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9767 
9768  break;
9769  }
9770 
9771  case SCIP_EXPR_SIN:
9772  case SCIP_EXPR_COS:
9773  case SCIP_EXPR_TAN:
9774  /* case SCIP_EXPR_ERF: */
9775  /* case SCIP_EXPR_ERFI: */
9776  {
9777  assert(node->nchildren == 1);
9778 
9779  /* @todo implement */
9780 
9781  break;
9782  }
9783 
9784  case SCIP_EXPR_ABS:
9785  {
9786  assert(node->nchildren == 1);
9787  /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
9788 
9789  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
9790  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9791 
9792  break;
9793  }
9794 
9795  case SCIP_EXPR_SIGN:
9796  {
9797  assert(node->nchildren == 1);
9798  /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
9799 
9800  SCIPintervalSetBounds(&childbounds,
9801  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
9802  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
9803  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9804 
9805  break;
9806  }
9807 
9808  case SCIP_EXPR_MIN:
9809  {
9810  assert(node->nchildren == 2);
9811  /* f = min(c0,c1) -> f <= c0, f <= c1
9812  * if c1 > f -> c0 = f
9813  * if c0 > f -> c1 = f
9814  */
9815 
9816  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
9817  node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
9818  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9819 
9820  if( *cutoff )
9821  break;
9822 
9823  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
9824  node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
9825  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9826 
9827  break;
9828  }
9829 
9830  case SCIP_EXPR_MAX:
9831  {
9832  assert(node->nchildren == 2);
9833  /* f = max(c0, c1) -> f >= c0, f >= c1
9834  * if c1 < f -> c0 = f
9835  * if c0 < f -> c1 = f
9836  */
9837 
9838  SCIPintervalSetBounds(&childbounds,
9839  node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
9840  node->bounds.sup);
9841  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9842 
9843  SCIPintervalSetBounds(&childbounds,
9844  node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
9845  node->bounds.sup);
9846  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9847 
9848  break;
9849  }
9850 
9851  case SCIP_EXPR_SUM:
9852  {
9853  SCIP_ROUNDMODE prevroundmode;
9854 
9855  /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
9856 
9857  SCIP_Real minlinactivity;
9858  SCIP_Real maxlinactivity;
9859  int minlinactivityinf;
9860  int maxlinactivityinf;
9861 
9862  if( node->nchildren == 0 )
9863  break;
9864 
9865  if( SCIPintervalIsEntire(infinity, node->bounds) )
9866  break;
9867 
9868  minlinactivity = 0.0;
9869  maxlinactivity = 0.0;
9870  minlinactivityinf = 0;
9871  maxlinactivityinf = 0;
9872 
9873  prevroundmode = SCIPintervalGetRoundingMode();
9875 
9876  for( i = 0; i < node->nchildren; ++i )
9877  {
9878  assert(!SCIPintervalIsEmpty(node->children[i]->bounds));
9879 
9880  /* minimal activity is only useful if node has a finite upper bound */
9881  if( node->bounds.sup < infinity )
9882  {
9883  if( node->children[i]->bounds.inf <= -infinity )
9884  {
9885  ++minlinactivityinf;
9886  }
9887  else
9888  {
9889  assert(node->children[i]->bounds.inf < infinity);
9890  minlinactivity += node->children[i]->bounds.inf;
9891  }
9892  }
9893 
9894  /* maximal activity is only useful if node has a finite lower bound
9895  * we compute negated maximal activity here so we can keep downward rounding
9896  */
9897  if( node->bounds.inf > -infinity )
9898  {
9899  if( node->children[i]->bounds.sup >= infinity )
9900  {
9901  ++maxlinactivityinf;
9902  }
9903  else
9904  {
9905  assert(node->children[i]->bounds.sup > -infinity);
9906  maxlinactivity -= node->children[i]->bounds.sup;
9907  }
9908  }
9909  }
9910  maxlinactivity = -maxlinactivity; /* correct sign */
9911 
9912  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
9913  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
9914  ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
9915  )
9916  {
9917  SCIPintervalSetRoundingMode(prevroundmode);
9918  break;
9919  }
9920 
9921  for( i = 0; i < node->nchildren && !*cutoff; ++i )
9922  {
9923  /* upper bounds of c_i is
9924  * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
9925  * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
9926  */
9927  SCIPintervalSetEntire(infinity, &childbounds);
9928  if( node->bounds.sup < infinity )
9929  {
9930  /* we are still in downward rounding mode, so negate and negate to get upward rounding */
9931  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
9932  {
9933  assert(minlinactivityinf == 1);
9934  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
9935  }
9936  else if( minlinactivityinf == 0 )
9937  {
9938  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
9939  }
9940  }
9941 
9942  /* lower bounds of c_i is
9943  * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
9944  * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
9945  */
9946  if( node->bounds.inf > -infinity )
9947  {
9948  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
9949  {
9950  assert(maxlinactivityinf == 1);
9951  childbounds.inf = node->bounds.inf - maxlinactivity;
9952  }
9953  else
9954  {
9955  childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
9956  }
9957  }
9958 
9959  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, cutoff);
9960  }
9961 
9962  SCIPintervalSetRoundingMode(prevroundmode);
9963 
9964  break;
9965  }
9966 
9967  case SCIP_EXPR_PRODUCT:
9968  {
9969  int j;
9970  /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
9971 
9972  /* too expensive (runtime here is quadratic in number of children) */
9973  if( node->nchildren > 10 )
9974  break;
9975 
9976  /* useless */
9977  if( SCIPintervalIsEntire(infinity, node->bounds) )
9978  break;
9979 
9980  for( i = 0; i < node->nchildren && !*cutoff; ++i )
9981  {
9982  /* compute prod_{j:j!=i} c_j */
9983  SCIPintervalSet(&childbounds, 1.0);
9984  for( j = 0; j < node->nchildren; ++j )
9985  {
9986  if( i == j )
9987  continue;
9988  SCIPintervalMul(infinity, &childbounds, childbounds, node->children[i]->bounds);
9989 
9990  /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
9991  if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
9992  break;
9993  }
9994 
9995  if( j == node->nchildren )
9996  {
9997  SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
9998  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, cutoff);
9999  }
10000  }
10001 
10002  break;
10003  }
10004 
10005  case SCIP_EXPR_LINEAR:
10006  {
10007  SCIP_ROUNDMODE prevroundmode;
10008  SCIP_Real* coefs;
10009 
10010  /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10011 
10012  SCIP_Real minlinactivity;
10013  SCIP_Real maxlinactivity;
10014  int minlinactivityinf;
10015  int maxlinactivityinf;
10016 
10017  if( node->nchildren == 0 )
10018  break;
10019 
10020  if( SCIPintervalIsEntire(infinity, node->bounds) )
10021  break;
10022 
10023  coefs = (SCIP_Real*)node->data.data;
10024 
10025  minlinactivity = coefs[node->nchildren];
10026  maxlinactivity = -coefs[node->nchildren];
10027  minlinactivityinf = 0;
10028  maxlinactivityinf = 0;
10029 
10030  prevroundmode = SCIPintervalGetRoundingMode();
10032 
10033  for( i = 0; i < node->nchildren; ++i )
10034  {
10035  assert(!SCIPintervalIsEmpty(node->children[i]->bounds));
10036 
10037  /* minimal activity is only useful if node has a finite upper bound */
10038  if( node->bounds.sup < infinity )
10039  {
10040  if( coefs[i] >= 0.0 )
10041  {
10042  if( node->children[i]->bounds.inf <= -infinity )
10043  {
10044  ++minlinactivityinf;
10045  }
10046  else
10047  {
10048  assert(node->children[i]->bounds.inf < infinity);
10049  minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10050  }
10051  }
10052  else
10053  {
10054  if( node->children[i]->bounds.sup >= infinity )
10055  {
10056  ++minlinactivityinf;
10057  }
10058  else
10059  {
10060  assert(node->children[i]->bounds.sup > -infinity);
10061  minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10062  }
10063  }
10064  }
10065 
10066  /* maximal activity is only useful if node has a finite lower bound
10067  * we compute negated maximal activity here so we can keep downward rounding
10068  */
10069  if( node->bounds.inf > -infinity )
10070  {
10071  if( coefs[i] >= 0.0 )
10072  {
10073  if( node->children[i]->bounds.sup >= infinity )
10074  {
10075  ++maxlinactivityinf;
10076  }
10077  else
10078  {
10079  assert(node->children[i]->bounds.sup > -infinity);
10080  maxlinactivity -= coefs[i] * node->children[i]->bounds.sup;
10081  }
10082  }
10083  else
10084  {
10085  if( node->children[i]->bounds.inf <= -infinity )
10086  {
10087  ++maxlinactivityinf;
10088  }
10089  else
10090  {
10091  assert(node->children[i]->bounds.inf < infinity);
10092  maxlinactivity -= coefs[i] * node->children[i]->bounds.inf;
10093  }
10094  }
10095  }
10096  }
10097  maxlinactivity = -maxlinactivity; /* correct sign */
10098 
10099  SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf);
10100 
10101  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10102  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10103  (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10104  )
10105  {
10106  SCIPintervalSetRoundingMode(prevroundmode);
10107  break;
10108  }
10109 
10110  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10111  {
10112  SCIP_INTERVAL ac;
10113 
10114  if( coefs[i] == 0.0 )
10115  continue;
10116 
10117  /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10118  SCIPintervalSet(&ac, 0.0);
10119  if( coefs[i] >= 0.0 )
10120  {
10121  if( node->children[i]->bounds.inf > -infinity )
10122  ac.inf = coefs[i] * node->children[i]->bounds.inf;
10123  if( node->children[i]->bounds.sup < infinity )
10125  }
10126  else
10127  {
10128  if( node->children[i]->bounds.sup < infinity )
10129  ac.inf = coefs[i] * node->children[i]->bounds.sup;
10130  if( node->children[i]->bounds.inf > -infinity )
10131  ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10132  }
10133 
10134  SCIPintervalSetEntire(infinity, &childbounds);
10135  if( coefs[i] > 0.0 )
10136  {
10137  /* upper bounds of c_i is
10138  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10139  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10140  */
10141  if( node->bounds.sup < infinity )
10142  {
10143  /* we are still in downward rounding mode, so negate to get upward rounding */
10144  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10145  {
10146  assert(minlinactivityinf == 1);
10147  childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10148  }
10149  else if( minlinactivityinf == 0 )
10150  {
10151  childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10152  }
10153  }
10154 
10155  /* lower bounds of c_i is
10156  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10157  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10158  */
10159  if( node->bounds.inf > -infinity )
10160  {
10161  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10162  {
10163  assert(maxlinactivityinf == 1);
10164  childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10165  }
10166  else if( maxlinactivityinf == 0 )
10167  {
10168  childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10169  }
10170  }
10171  }
10172  else
10173  {
10174  /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10175  * thus, we do (b-a)/(-c) in downward rounding
10176  */
10177  /* lower bounds of c_i is
10178  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10179  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10180  */
10181  if( node->bounds.sup < infinity )
10182  {
10183  if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10184  {
10185  assert(minlinactivityinf == 1);
10186  childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10187  }
10188  else if( minlinactivityinf == 0 )
10189  {
10190  childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10191  }
10192  }
10193 
10194  /* upper bounds of c_i is
10195  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10196  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10197  */
10198  if( node->bounds.inf > -infinity )
10199  {
10200  /* we are still in downward rounding mode, so negate to get upward rounding */
10201  if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10202  {
10203  assert(maxlinactivityinf == 1);
10204  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10205  }
10206  else if( maxlinactivityinf == 0 )
10207  {
10208  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10209  }
10210  }
10211  }
10212 
10213  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, cutoff);
10214  }
10215 
10216  SCIPintervalSetRoundingMode(prevroundmode);
10217 
10218  break;
10219  }
10220 
10221  case SCIP_EXPR_QUADRATIC:
10222  {
10223  SCIP_EXPRDATA_QUADRATIC* quaddata;
10224  SCIP_INTERVAL tmp;
10225  SCIP_INTERVAL a;
10226  SCIP_INTERVAL b;
10227  SCIP_INTERVAL c;
10228  SCIP_QUADELEM* quadelems;
10229  int nquadelems;
10230  SCIP_Real* lincoefs;
10231  int k;
10232 
10233  /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10234  * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10235  */
10236 
10237  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10238  quadelems = quaddata->quadelems;
10239  nquadelems = quaddata->nquadelems;
10240  lincoefs = quaddata->lincoefs;
10241 
10242  /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10243  if( nquadelems > 10 )
10244  break;
10245 
10246  if( SCIPintervalIsEntire(infinity, node->bounds) )
10247  break;
10248 
10249  if( node->nchildren == 2 && nquadelems > 0 )
10250  {
10251  /* if it's a bivariate quadratic expression with bilinear term, do something special */
10252  SCIP_Real ax; /* square coefficient of first child */
10253  SCIP_Real ay; /* square coefficient of second child */
10254  SCIP_Real axy; /* bilinear coefficient */
10255 
10256  ax = 0.0;
10257  ay = 0.0;
10258  axy = 0.0;
10259  for( i = 0; i < nquadelems; ++i )
10260  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10261  ax += quadelems[i].coef;
10262  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10263  ay += quadelems[i].coef;
10264  else
10265  axy += quadelems[i].coef;
10266 
10267  c = node->bounds;
10268  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10269 
10270  /* compute bounds for x */
10272  infinity, &childbounds, ax, ay, axy,
10273  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10274  c, node->children[0]->bounds, node->children[1]->bounds
10275  );
10276  if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10277  {
10278  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",
10279  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10280  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10281  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(childbounds)
10282  );
10283  }
10284 
10285  if( SCIPintervalIsEmpty(childbounds) )
10286  *cutoff = TRUE;
10287  else
10288  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
10289  if( *cutoff )
10290  break;
10291 
10292  /* compute bounds for y */
10294  infinity, &childbounds, ay, ax, axy,
10295  lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
10296  c, node->children[1]->bounds, node->children[0]->bounds
10297  );
10298 
10299  if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
10300  {
10301  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",
10302  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10303  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10304  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(childbounds)
10305  );
10306  }
10307 
10308  if( SCIPintervalIsEmpty(childbounds) )
10309  *cutoff = TRUE;
10310  else
10311  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
10312  if( *cutoff )
10313  break;
10314 
10315  break;
10316  }
10317 
10318  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10319  {
10320  SCIPintervalSet(&a, 0.0);
10321  SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
10322  c = node->bounds;
10323  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10324 
10325  /* move linear terms not corresponding to i into c
10326  * @todo do this faster, see EXPR_LINEAR
10327  */
10328  if( lincoefs != NULL )
10329  for( k = 0; k < node->nchildren; ++k )
10330  if( i != k && lincoefs[k] != 0.0 )
10331  {
10332  SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
10333  SCIPintervalSub(infinity, &c, c, tmp);
10334  }
10335 
10336  for( k = 0; k < nquadelems; ++k )
10337  {
10338  if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
10339  {
10340  SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
10341  }
10342  else if( quadelems[k].idx1 == i )
10343  {
10344  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
10345  SCIPintervalAdd(infinity, &b, b, tmp);
10346  }
10347  else if( quadelems[k].idx2 == i )
10348  {
10349  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
10350  SCIPintervalAdd(infinity, &b, b, tmp);
10351  }
10352  else if( quadelems[k].idx1 == quadelems[k].idx2 )
10353  {
10354  SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
10355  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
10356  SCIPintervalSub(infinity, &c, c, tmp);
10357  }
10358  else
10359  {
10360  SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
10361  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
10362  SCIPintervalSub(infinity, &c, c, tmp);
10363  }
10364  }
10365 
10366  SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
10367  a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
10368  SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c);
10369  if( SCIPintervalIsEmpty(childbounds) )
10370  *cutoff = TRUE;
10371  else
10372  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, cutoff);
10373  }
10374 
10375  break;
10376  }
10377 
10378  case SCIP_EXPR_POLYNOMIAL:
10379  {
10380  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
10381  SCIP_EXPRDATA_MONOMIAL** monomials;
10382  SCIP_EXPRDATA_MONOMIAL* monomial;
10383  int nmonomials;
10384  int j;
10385  int k;
10386  SCIP_Real n;
10387  int nexpisdoublen;
10388  int nexpishalfn;
10389  char abc_flag;
10390 
10391  SCIP_INTERVAL monomialcoef;
10392  SCIP_INTERVAL tmp;
10393  SCIP_INTERVAL a;
10394  SCIP_INTERVAL b;
10395  SCIP_INTERVAL c;
10396 
10397  /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
10398  * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
10399  *
10400  * we determine n by setting n to the first exponent of x that we see
10401  * then we count how often we see x^(2n) and x^(n/2)
10402  * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
10403  */
10404 
10405  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
10406  monomials = polynomialdata->monomials;
10407  nmonomials = polynomialdata->nmonomials;
10408 
10409  if( SCIPintervalIsEntire(infinity, node->bounds) )
10410  break;
10411 
10412  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10413  {
10414  n = 0.0;
10415  nexpisdoublen = 0;
10416  nexpishalfn = 0;
10417  for( j = 0; j < nmonomials; ++j )
10418  {
10419  monomial = monomials[j];
10420  for( k = 0; k < monomial->nfactors; ++k )
10421  {
10422  if( monomial->childidxs[k] == i )
10423  {
10424  if( n == 0.0 )
10425  n = monomial->exponents[k];
10426  else if( n == 2*monomial->exponents[k] ) /*lint !e777*/
10427  ++nexpishalfn;
10428  else if( 2*n == monomial->exponents[k] ) /*lint !e777*/
10429  ++nexpisdoublen;
10430  }
10431  }
10432  }
10433 
10434  if( n == 0.0 )
10435  {
10436  /* child does not appear in polynomial -> cannot deduce bound */
10437  continue;
10438  }
10439 
10440  /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
10441  if( nexpishalfn > nexpisdoublen )
10442  n /= 2.0;
10443 
10444  SCIPintervalSet(&a, 0.0);
10445  SCIPintervalSet(&b, 0.0);
10446  SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
10447 
10448  for( j = 0; j < nmonomials; ++j )
10449  {
10450  monomial = monomials[j];
10451  SCIPintervalSet(&monomialcoef, monomial->coef);
10452  abc_flag = 'c';
10453  for( k = 0; k < monomial->nfactors; ++k )
10454  {
10455  if( monomial->childidxs[k] == i )
10456  {
10457  assert(abc_flag == 'c'); /* child should appear only once per monom */
10458  if( n > 0.0 )
10459  {
10460  if( monomial->exponents[k] > 2.0*n )
10461  {
10462  abc_flag = 'a';
10463  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
10464  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10465  }
10466  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
10467  {
10468  abc_flag = 'a';
10469  }
10470  else if( monomial->exponents[k] > n )
10471  {
10472  abc_flag = 'b';
10473  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
10474  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10475  }
10476  else if( monomial->exponents[k] == n ) /*lint !e777*/
10477  {
10478  abc_flag = 'b';
10479  }
10480  else
10481  {
10482  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
10483  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10484  }
10485  }
10486  else
10487  {
10488  assert(n < 0.0);
10489  if( monomial->exponents[k] < 2.0*n )
10490  {
10491  abc_flag = 'a';
10492  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
10493  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10494  }
10495  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
10496  {
10497  abc_flag = 'a';
10498  }
10499  else if( monomial->exponents[k] < n )
10500  {
10501  abc_flag = 'b';
10502  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
10503  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10504  }
10505  else if( monomial->exponents[k] == n ) /*lint !e777*/
10506  {
10507  abc_flag = 'b';
10508  }
10509  else
10510  {
10511  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
10512  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10513  }
10514  }
10515  }
10516  else
10517  {
10518  SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
10519  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10520  }
10521  }
10522 
10523  if( abc_flag == 'a' )
10524  SCIPintervalAdd(infinity, &a, a, monomialcoef);
10525  else if( abc_flag == 'b' )
10526  SCIPintervalAdd(infinity, &b, b, monomialcoef);
10527  else
10528  SCIPintervalSub(infinity, &c, c, monomialcoef);
10529  }
10530 
10531  /* now have equation a*child^(2n) + b*child^n = c
10532  * solve a*y^2 + b*y = c, then child^n = y
10533  */
10534  SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g]",
10535  a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup);
10536  SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c);
10537  SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
10538 
10539  if( SCIPintervalIsEmpty(tmp) )
10540  {
10541  *cutoff = TRUE;
10542  break;
10543  }
10544 
10545  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
10546  SCIPdebugPrintf(" -> c%d = [%10g, %10g]\n", i, childbounds.inf, childbounds.sup);
10547  if( SCIPintervalIsEmpty(childbounds) )
10548  {
10549  SCIPdebugMessage(" -> cutoff\n");
10550  *cutoff = TRUE;
10551  break;
10552  }
10553 
10554  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, cutoff);
10555 
10556  /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
10557  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10558  SCIPdebugPrintf("\n"); */
10559  }
10560 
10561  break;
10562  }
10563 
10564  case SCIP_EXPR_LAST:
10565  default:
10566  SCIPerrorMessage("unknown or unexpected operand: %d\n", node->op);
10567  SCIPABORT();
10568  }
10569 }
10570 
10571 /** removes duplicate children in a polynomial expression node
10572  * leaves NULL's in children array
10573  */
10574 static
10576  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10577  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
10578  )
10579 {
10580  SCIP_Bool foundduplicates;
10581  int* childmap;
10582  int i;
10583  int j;
10584 
10585  assert(exprgraph != NULL);
10586  assert(node != NULL);
10587  assert(node->op == SCIP_EXPR_POLYNOMIAL);
10588 
10589  if( node->nchildren == 0 )
10590  return SCIP_OKAY;
10591 
10592  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
10593 
10594  foundduplicates = FALSE;
10595  for( i = 0; i < node->nchildren; ++i )
10596  {
10597  if( node->children[i] == NULL )
10598  continue;
10599  childmap[i] = i; /*lint !e644*/
10600 
10601  for( j = i+1; j < node->nchildren; ++j )
10602  {
10603  if( node->children[j] == NULL )
10604  continue;
10605 
10606  if( node->children[i] == node->children[j] )
10607  {
10608  /* node should be parent of children[j] at least twice,
10609  * so we remove it once
10610  */
10611  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
10612  node->children[j] = NULL;
10613  assert(exprgraphNodeIsParent(node->children[i], node));
10614 
10615  childmap[j] = i;
10616  foundduplicates = TRUE;
10617  }
10618  }
10619  }
10620 
10621  /* apply childmap to monomials */
10622  if( foundduplicates )
10624 
10625  /* free childmap */
10626  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
10627 
10628  return SCIP_OKAY;
10629 }
10630 
10631 /** eliminates NULL's in children array and shrinks it to actual size */
10632 static
10634  BMS_BLKMEM* blkmem, /**< block memory */
10635  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
10636  )
10637 {
10638  int* childmap;
10639  int lastnonnull;
10640  int i;
10641 
10642  assert(blkmem != NULL);
10643  assert(node != NULL);
10644  assert(node->op == SCIP_EXPR_POLYNOMIAL);
10645 
10646  if( node->nchildren == 0 )
10647  return SCIP_OKAY;
10648 
10649  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
10650 
10651  /* close gaps in children array */
10652  lastnonnull = node->nchildren-1;
10653  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
10654  --lastnonnull;
10655  for( i = 0; i <= lastnonnull; ++i )
10656  {
10657  if( node->children[i] != NULL )
10658  {
10659  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
10660  continue;
10661  }
10662  assert(node->children[lastnonnull] != NULL);
10663 
10664  /* move child at lastnonnull to position i */
10665  node->children[i] = node->children[lastnonnull];
10666  node->children[lastnonnull] = NULL;
10667  childmap[lastnonnull] = i;
10668 
10669  /* update lastnonnull */
10670  --lastnonnull;
10671  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
10672  --lastnonnull;
10673  }
10674  assert(i > lastnonnull);
10675 
10676  /* apply childmap to monomials */
10677  if( lastnonnull < node->nchildren-1 )
10679 
10680  BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
10681 
10682  /* shrink children array */
10683  if( lastnonnull >= 0 )
10684  {
10685  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
10686  node->nchildren = lastnonnull+1;
10687  }
10688  else
10689  {
10690  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
10691  node->nchildren = 0;
10692  }
10693 
10694  return SCIP_OKAY;
10695 }
10696 
10697 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
10698  * converts node into polynomial, if possible and not constant
10699  */
10700 static
10702  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10703  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10704  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
10705  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
10706  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
10707  SCIP_Bool* havechange /**< flag to set if the node has been changed */
10708  )
10709 {
10710  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
10711  SCIP_EXPRDATA_MONOMIAL* monomial;
10712  BMS_BLKMEM* blkmem;
10713  SCIP_Bool removechild;
10714  SCIP_Bool* childinuse;
10715  int* childmap;
10716  int childmapsize;
10717  int i;
10718  int j;
10719  int orignchildren;
10720 
10721  assert(exprgraph != NULL);
10722  assert(node != NULL);
10723  assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
10724  assert(havechange != NULL);
10725 
10726  blkmem = exprgraph->blkmem;
10727  assert(blkmem != NULL);
10728 
10729  SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
10730 
10731  /* if all children are constants, then turn this node into constant */
10732  for( i = 0; i < node->nchildren; ++i )
10733  if( node->children[i]->op != SCIP_EXPR_CONST )
10734  break;
10735  if( node->nchildren > 0 && i == node->nchildren )
10736  {
10737  /* get value of node */
10739  assert(node->value != SCIP_INVALID); /*lint !e777*/
10740 
10741  SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
10742  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10743  SCIPdebugPrintf("\n");
10744 
10745  /* free expression data */
10746  if( exprOpTable[node->op].freedata != NULL )
10747  exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
10748 
10749  /* disconnect from children */
10750  for( i = 0; i < node->nchildren; ++i )
10751  {
10752  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
10753  }
10754  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
10755  node->nchildren = 0;
10756 
10757  /* turn into constant expression */
10758  node->op = SCIP_EXPR_CONST;
10759  node->data.dbl = node->value;
10760 
10761  *havechange = TRUE;
10762  node->simplified = TRUE;
10763 
10764  return SCIP_OKAY;
10765  }
10766 
10767  /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
10768  * @todo log(product) -> sum(log)
10769  * @todo product(exp) -> exp(sum)
10770  * @todo exp(x)^p -> exp(p*x)
10771  * @todo exp(const*log(x)) -> x^const
10772  */
10773 
10774  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
10775 
10776  if( node->op != SCIP_EXPR_POLYNOMIAL )
10777  {
10778  node->simplified = TRUE;
10779  return SCIP_OKAY;
10780  }
10781 
10782  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
10783  assert(polynomialdata != NULL);
10784 
10785  orignchildren = node->nchildren;
10786 
10787  /* check if we have duplicate children and merge */
10789  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
10790 
10791  SCIPdebugMessage("expand factors in expression node ");
10792  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
10793  SCIPdebugPrintf("\n");
10794 
10795  childmap = NULL;
10796  childmapsize = 0;
10797 
10798  /* resolve children that are constants
10799  * we do this first, because it reduces the degree and number of factors in the monomials,
10800  * 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
10801  */
10802  for( i = 0; i < node->nchildren; ++i )
10803  {
10804  if( node->children[i] == NULL )
10805  continue;
10806 
10807  /* convert children to polynomial, if not constant or polynomial
10808  * if child was simplified in this round, it may have already been converted, and then nothing happens
10809  * but if child was already simplified, then it was not converted, and thus we try it here
10810  */
10811  if( node->children[i]->op != SCIP_EXPR_CONST )
10812  continue;
10813 
10814  SCIPdebugMessage("expand child %d in expression node ", i);
10815  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
10816  SCIPdebugPrintf("\n\tchild = ");
10817  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
10818  SCIPdebugPrintf("\n");
10819 
10820  removechild = TRUE; /* we intend to release children[i] */
10821 
10822  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
10823 
10824  /* put constant of child i into every monomial where child i is used */
10825  for( j = 0; j < polynomialdata->nmonomials; ++j )
10826  {
10827  int factorpos;
10828 
10829  monomial = polynomialdata->monomials[j];
10830  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
10831  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
10832 
10833  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
10834  {
10835  assert(factorpos >= 0);
10836  assert(factorpos < monomial->nfactors);
10837  /* assert that factors have been merged */
10838  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
10839  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
10840 
10841  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
10842 
10843  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 ) /*lint !e835*/
10844  {
10845  /* if constant is negative and our exponent is not integer, then cannot do expansion */
10846  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
10847  removechild = FALSE;
10848  }
10849  else
10850  {
10851  monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
10852 
10853  /* move last factor to position factorpos */
10854  if( factorpos < monomial->nfactors-1 )
10855  {
10856  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
10857  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
10858  }
10859  --monomial->nfactors;
10860  monomial->sorted = FALSE;
10861  polynomialdata->sorted = FALSE;
10862 
10863  *havechange = TRUE;
10864  }
10865  }
10866  }
10867 
10868  /* forget about child i, if it is not used anymore */
10869  if( removechild )
10870  {
10871  /* remove node from list of parents of child i */
10872  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
10873  node->children[i] = NULL;
10874  }
10875 
10876  /* simplify current polynomial again */
10877  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
10878  }
10879 
10880  /* resolve children that are polynomials itself */
10881  for( i = 0; i < node->nchildren; ++i )
10882  {
10883  if( node->children[i] == NULL )
10884  continue;
10885 
10886  /* convert children to polynomial, if not constant or polynomial
10887  * if child was simplified in this round, it may have already been converted, and then nothing happens
10888  * but if child was already simplified, then it was not converted, and thus we try it here
10889  */
10890  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
10891 
10892  if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
10893  continue;
10894 
10895  SCIPdebugMessage("expand child %d in expression node ", i);
10896  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
10897  SCIPdebugPrintf("\n\tchild = ");
10898  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
10899  SCIPdebugPrintf("\n");
10900 
10901  removechild = TRUE; /* we intend to release children[i] */
10902 
10903  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
10904 
10905  /* add children of child i to node */
10906  SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
10907 
10908  /* put polynomial of child i into every monomial where child i is used */
10909  j = 0;
10910  while( j < polynomialdata->nmonomials )
10911  {
10912  int factorpos;
10913  SCIP_Bool success;
10914 
10915  monomial = polynomialdata->monomials[j];
10916  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
10917  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
10918 
10919  if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
10920  {
10921  ++j;
10922  continue;
10923  }
10924 
10925  assert(factorpos >= 0);
10926  assert(factorpos < monomial->nfactors);
10927  /* assert that factors have been merged */
10928  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
10929  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
10930 
10931  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
10932 
10933  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos, (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
10934 
10935  if( !success )
10936  {
10937  removechild = FALSE;
10938  ++j;
10939  }
10940  else
10941  *havechange = TRUE;
10942 
10943  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
10944  * we thus repeat with index j, if a factor was successfully expanded
10945  */
10946  }
10947 
10948  /* forget about child i, if it is not used anymore */
10949  if( removechild )
10950  {
10951  /* remove node from list of parents of child i */
10952  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
10953  node->children[i] = NULL;
10954  }
10955 
10956  /* simplify current polynomial again */
10957  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
10958  }
10959 
10960  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
10961 
10962  /* check which children are still in use */
10963  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
10964  BMSclearMemoryArray(childinuse, node->nchildren); /*lint !e644*/
10965  for( i = 0; i < polynomialdata->nmonomials; ++i )
10966  {
10967  monomial = polynomialdata->monomials[i];
10968  assert(monomial != NULL);
10969 
10970  for( j = 0; j < monomial->nfactors; ++j )
10971  {
10972  assert(monomial->childidxs[j] >= 0);
10973  assert(monomial->childidxs[j] < node->nchildren);
10974  childinuse[monomial->childidxs[j]] = TRUE;
10975  }
10976  }
10977 
10978  /* free children that are not used in any monomial */
10979  for( i = 0; i < node->nchildren; ++i )
10980  if( node->children[i] != NULL && !childinuse[i] )
10981  {
10982  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
10983  node->children[i] = NULL;
10984  }
10985 
10986  BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
10987 
10988  /* remove NULLs from children array */
10990 
10991  /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
10992  if( node->nchildren == 0 )
10993  {
10994  SCIP_Real val;
10995 
10996  /* if no children, then it should also have no monomials */
10997  assert(polynomialdata->nmonomials == 0);
10998 
10999  val = polynomialdata->constant;
11000  polynomialdataFree(blkmem, &polynomialdata);
11001 
11002  node->op = SCIP_EXPR_CONST;
11003  node->data.dbl = val;
11004  node->value = val;
11005  }
11006 
11007  /* if no factor in a monomial was replaced, the number of children should not have changed
11008  * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11009  */
11010  *havechange |= (node->nchildren < orignchildren); /*lint !e514*/
11011 
11012  node->simplified = TRUE;
11013 
11014  SCIPdebugMessage("-> %p = ", (void*)node);
11015  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11016  SCIPdebugPrintf("\n");
11017 
11018  return SCIP_OKAY;
11019 }
11020 
11021 /** creates an expression from a given node in an expression graph
11022  * assembles mapping of variables from graph to tree
11023  */
11024 static
11026  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11027  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which expression should be created */
11028  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
11029  int* nexprvars, /**< current number of variables in expression */
11030  int* varidx /**< current mapping of variable indices from graph to expression */
11031  )
11032 {
11033  SCIP_EXPR** childexprs;
11034  int i;
11035 
11036  assert(exprgraph != NULL);
11037  assert(node != NULL);
11038  assert(expr != NULL);
11039  assert(nexprvars != NULL);
11040  assert(*nexprvars >= 0);
11041  assert(varidx != NULL);
11042 
11043  childexprs = NULL;
11044  if( node->nchildren > 0 )
11045  {
11046  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11047  for( i = 0; i < node->nchildren; ++i )
11048  {
11049  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) ); /*lint !e613*/
11050  }
11051  }
11052 
11053  switch( node->op )
11054  {
11055  case SCIP_EXPR_VARIDX:
11056  {
11057  /* check if the variable already has an index assigned in the expression tree
11058  * if not, create one and increase nexprvars
11059  */
11060  assert(node->data.intval >= 0);
11061  assert(node->data.intval < exprgraph->nvars);
11062  assert(varidx[node->data.intval] >= -1);
11063  assert(varidx[node->data.intval] < *nexprvars);
11064  if( varidx[node->data.intval] == -1 )
11065  {
11066  varidx[node->data.intval] = *nexprvars;
11067  ++*nexprvars;
11068  }
11069 
11070  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11071  break;
11072  }
11073 
11074  case SCIP_EXPR_CONST:
11075  {
11076  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11077  break;
11078  }
11079 
11080  case SCIP_EXPR_REALPOWER:
11081  case SCIP_EXPR_SIGNPOWER:
11082  {
11083  assert(childexprs != NULL);
11084  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11085  break;
11086  }
11087 
11088  case SCIP_EXPR_INTPOWER:
11089  {
11090  assert(childexprs != NULL);
11091  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11092  break;
11093  }
11094 
11095  case SCIP_EXPR_PLUS:
11096  case SCIP_EXPR_MINUS:
11097  case SCIP_EXPR_MUL:
11098  case SCIP_EXPR_DIV:
11099  case SCIP_EXPR_MIN:
11100  case SCIP_EXPR_MAX:
11101  {
11102  assert(node->nchildren == 2);
11103  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11104  break;
11105  }
11106 
11107  case SCIP_EXPR_SQUARE:
11108  case SCIP_EXPR_SQRT:
11109  case SCIP_EXPR_EXP:
11110  case SCIP_EXPR_LOG:
11111  case SCIP_EXPR_SIN:
11112  case SCIP_EXPR_COS:
11113  case SCIP_EXPR_TAN:
11114  /* case SCIP_EXPR_ERF: */
11115  /* case SCIP_EXPR_ERFI: */
11116  case SCIP_EXPR_ABS:
11117  case SCIP_EXPR_SIGN:
11118  {
11119  assert(node->nchildren == 1);
11120  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11121  break;
11122  }
11123 
11124  case SCIP_EXPR_SUM:
11125  case SCIP_EXPR_PRODUCT:
11126  {
11127  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11128  break;
11129  }
11130 
11131  case SCIP_EXPR_LINEAR:
11132  {
11133  assert(node->data.data != NULL);
11134 
11135  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11136  break;
11137  }
11138 
11139  case SCIP_EXPR_QUADRATIC:
11140  {
11141  SCIP_EXPRDATA_QUADRATIC* quaddata;
11142 
11143  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11144  assert(quaddata != NULL);
11145 
11146  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11147  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11148  break;
11149  }
11150 
11151  case SCIP_EXPR_POLYNOMIAL:
11152  {
11153  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11154 
11155  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11156  assert(polynomialdata != NULL);
11157 
11158  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11159  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11160 
11161  break;
11162  }
11163 
11164  case SCIP_EXPR_LAST:
11165  case SCIP_EXPR_PARAM:
11166  default:
11167  {
11168  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11169  return SCIP_ERROR;
11170  }
11171  }
11172 
11173  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11174 
11175  return SCIP_OKAY;
11176 }
11177 
11178 /** counts how often expression graph variables are used in a subtree of the expression graph
11179  *
11180  * @note The function does not clear the array first, but only increases already existing counts.
11181  */
11182 static
11184  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11185  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11186  )
11187 {
11188  int i;
11189 
11190  assert(node != NULL);
11191  assert(varsusage != NULL);
11192 
11193  if( node->op == SCIP_EXPR_VARIDX )
11194  {
11195  ++varsusage[node->data.intval];
11196  return;
11197  }
11198 
11199  for( i = 0; i < node->nchildren; ++i )
11200  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
11201 }
11202 
11203 /* checks whether a node can be put into a component when checking block separability of an expression
11204  * if a variable used by node is already in another component, components are merged and component number is updated
11205  */
11206 static
11208  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
11209  int* compnr, /**< component number to assign, may be reduced if variables overlap */
11210  int nchildcomps, /**< number of entries for which childcomps have been set already */
11211  int* childcomps, /**< component numbers of children */
11212  int nvars, /**< number of variables */
11213  int* varcomps /**< component numbers of variables */
11214  )
11215 {
11216  int varidx;
11217  int i;
11218 
11219  assert(node != NULL);
11220  assert(compnr != NULL);
11221  assert(*compnr >= 0);
11222  assert(childcomps != NULL);
11223  assert(varcomps != NULL);
11224 
11225  if( node->op != SCIP_EXPR_VARIDX )
11226  {
11227  for( i = 0; i < node->nchildren; ++i )
11228  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
11229  return;
11230  }
11231 
11232  varidx = node->data.intval;
11233  assert(varidx >= 0);
11234  assert(varidx < nvars);
11235 
11236  if( varcomps[varidx] == -1 )
11237  {
11238  /* first time we get to this variable, so set it's component to compnr and we are done */
11239  varcomps[varidx] = *compnr;
11240  return;
11241  }
11242 
11243  if( varcomps[varidx] == *compnr )
11244  {
11245  /* variable is already in current component, that's also good and we are done */
11246  return;
11247  }
11248 
11249  /* variable is already in another component, so have to merge component compnr into that component
11250  * do this by updating varcomps and childcomps */
11251  for( i = 0; i < nvars; ++i )
11252  if( varcomps[i] == *compnr )
11253  varcomps[i] = varcomps[varidx];
11254  for( i = 0; i < nchildcomps; ++i )
11255  if( childcomps[i] == *compnr )
11256  childcomps[i] = varcomps[varidx];
11257  *compnr = varcomps[varidx];
11258 }
11259 
11260 /**@} */
11261 
11262 /**@name Expression graph private methods */
11263 /**@{ */
11264 
11265 /** assert that expression tree has at least a given depth */
11266 static
11268  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
11269  int mindepth /**< minimal depth that should be ensured */
11270  )
11271 {
11272  int olddepth;
11273 
11274  assert(exprgraph != NULL);
11275  assert(exprgraph->blkmem != NULL);
11276 
11277  if( mindepth <= exprgraph->depth )
11278  return SCIP_OKAY;
11279 
11280  olddepth = exprgraph->depth;
11281  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
11282  assert(exprgraph->depth >= mindepth);
11283 
11284  /* initialize new array entries to 0 and NULL, resp. */
11285  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11286  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11287  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11288 
11289  return SCIP_OKAY;
11290 }
11291 
11292 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
11293 static
11295  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11296  int varidx /**< variable index */
11297  )
11298 {
11299  SCIP_EXPRGRAPHNODE* varnode;
11300  void* var;
11301 
11302  assert(exprgraph != NULL);
11303  assert(varidx >= 0);
11304  assert(varidx < exprgraph->nvars);
11305 
11306  varnode = exprgraph->varnodes[varidx];
11307  assert(varnode->data.intval == varidx);
11308 
11309  var = exprgraph->vars[varidx];
11310 
11311  /* call varremove callback method, if set */
11312  if( exprgraph->exprgraphvarremove != NULL )
11313  {
11314  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
11315  }
11316 
11317  /* remove variable from hashmap */
11318  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
11319 
11320  /* move last variable to position varidx and give it the new index */
11321  if( varidx < exprgraph->nvars-1 )
11322  {
11323  /* call callback method, if set */
11324  if( exprgraph->exprgraphvarchgidx != NULL )
11325  {
11326  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
11327  }
11328 
11329  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
11330  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
11331  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
11332  exprgraph->varnodes[varidx]->data.intval = varidx;
11333  SCIP_CALL( SCIPhashmapSetImage(exprgraph->varidxs, exprgraph->vars[varidx], (void*)(size_t)(varidx)) );
11334  }
11335  --exprgraph->nvars;
11336 
11337  return SCIP_OKAY;
11338 }
11339 
11340 /** moves a node in an expression graph to a different depth
11341  * new depth must be larger than children depth
11342  * moves parent nodes to higher depth, if needed
11343  * variable nodes cannot be moved
11344  */
11345 static
11347  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11348  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
11349  int newdepth /**< new depth to which to move node */
11350  )
11351 {
11352  int olddepth;
11353  int oldpos;
11354  int i;
11355 
11356  assert(exprgraph != NULL);
11357  assert(node != NULL);
11358  assert(node->depth >= 0); /* node should be in graph */
11359  assert(newdepth >= 0);
11360 
11361  /* if already on aimed depth, then don't need to move */
11362  if( node->depth == newdepth )
11363  return SCIP_OKAY;
11364 
11365  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
11366 
11367 #ifndef NDEBUG
11368  /* assert that children are at lower depth than new depth */
11369  for( i = 0; i < node->nchildren; ++i )
11370  assert(node->children[i]->depth < newdepth);
11371 #endif
11372 
11373  /* move parents to higher depth, if needed */
11374  for( i = 0; i < node->nparents; ++i )
11375  {
11376  if( node->parents[i]->depth <= newdepth )
11377  {
11378  /* move parent to depth+1 */
11379  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
11380  assert(node->parents[i]->depth > newdepth);
11381  }
11382  }
11383 
11384  /* ensure that graph is deep enough */
11385  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
11386  assert(exprgraph->depth > newdepth);
11387 
11388  olddepth = node->depth;
11389  oldpos = node->pos;
11390 
11391  /* add node to new depth */
11392  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
11393  node->depth = newdepth;
11394  node->pos = exprgraph->nnodes[newdepth];
11395  exprgraph->nodes[newdepth][node->pos] = node;
11396  ++exprgraph->nnodes[newdepth];
11397 
11398  /* move last node at previous depth to previous position, if it wasn't last */
11399  if( oldpos < exprgraph->nnodes[olddepth]-1 )
11400  {
11401  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
11402  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
11403  }
11404  --exprgraph->nnodes[olddepth];
11405 
11406  if( node->depth == 0 )
11407  {
11408  /* if at depth 0, then it need to be a node for either a constant or a variable */
11409  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
11410  if( node->op == SCIP_EXPR_CONST )
11411  {
11412  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
11413  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
11414  exprgraph->constnodes[exprgraph->nconsts] = node;
11415  ++exprgraph->nconsts;
11416  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
11417  }
11418  else
11419  {
11420  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
11421  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
11422  return SCIP_ERROR;
11423  }
11424 
11425  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
11426  node->curv = SCIP_EXPRCURV_LINEAR;
11427  }
11428 
11429  return SCIP_OKAY;
11430 }
11431 
11432 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
11433 static
11435  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11436  int nchildren, /**< number of children */
11437  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
11438  SCIP_EXPROP op, /**< operator */
11439  SCIP_EXPROPDATA opdata, /**< operator data */
11440  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
11441  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
11442  )
11443 {
11444  SCIP_EXPRGRAPHNODE** parentcands;
11445  int nparentcands;
11446  int parentcandssize;
11447  int i;
11448  int p;
11449 
11450  assert(exprgraph != NULL);
11451  assert(nchildren > 0);
11452  assert(children != NULL);
11453  assert(parent != NULL);
11454 
11455  *parent = NULL;
11456 
11457  /* create initial set of parent candidates as
11458  * all parents of first child that have the same operator type and the same number of children
11459  * additionally, some easy conditions for complex expression types:
11460  * if expression type is int/real/signpower, then compare also exponent,
11461  * if expression type is linear, then compare also constant part,
11462  * if expression type is quadratic, then compare also number of quadratic elements,
11463  * if expression type is polynomial, then compare also number of monmials and constant part
11464  */
11465  parentcandssize = children[0]->nparents;
11466  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
11467  nparentcands = 0;
11468  for( p = 0; p < children[0]->nparents; ++p )
11469  if( children[0]->parents[p]->op == op &&
11470  children[0]->parents[p]->nchildren == nchildren &&
11471  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
11472  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
11473  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
11474  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
11475  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
11476  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
11477  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
11478  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
11479  )
11480  {
11481  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
11482  }
11483 
11484  /* for all remaining children, remove parent candidates, that are not in their list of parents */
11485  for( i = 1; i < nchildren && nparentcands > 0; ++i )
11486  {
11487  p = 0;
11488  while( p < nparentcands )
11489  {
11490  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
11491  * otherwise keep candidate and check next one
11492  */
11493  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
11494  {
11495  parentcands[p] = parentcands[nparentcands-1];
11496  --nparentcands;
11497  }
11498  else
11499  ++p;
11500  }
11501  }
11502 
11503  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
11504 
11505  if( nparentcands == 0 )
11506  {
11507  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
11508  return SCIP_OKAY;
11509  }
11510 
11511  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
11512  * check if there is also one which corresponds to same expression and store that one in *parent
11513  */
11514  switch( op )
11515  {
11516  /* commutative operands with no data */
11517  case SCIP_EXPR_PLUS :
11518  case SCIP_EXPR_MUL :
11519  case SCIP_EXPR_MIN :
11520  case SCIP_EXPR_MAX :
11521  case SCIP_EXPR_SUM :
11522  case SCIP_EXPR_PRODUCT:
11523  case SCIP_EXPR_SQUARE :
11524  case SCIP_EXPR_SQRT :
11525  case SCIP_EXPR_EXP :
11526  case SCIP_EXPR_LOG :
11527  case SCIP_EXPR_SIN :
11528  case SCIP_EXPR_COS :
11529  case SCIP_EXPR_TAN :
11530  /* case SCIP_EXPR_ERF : */
11531  /* case SCIP_EXPR_ERFI : */
11532  case SCIP_EXPR_ABS :
11533  case SCIP_EXPR_SIGN :
11534  {
11535  /* sort childnodes, if needed for later */
11536  if( nchildren > 2 )
11537  SCIPsortPtr((void**)children, ptrcomp, nchildren);
11538  for( p = 0; p < nparentcands; ++p )
11539  {
11540  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
11541  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
11542 
11543  if( nchildren == 1 )
11544  {
11545  assert(parentcands[p]->children[0] == children[0]);
11546  /* same operand, same child, so same expression */
11547  *parent = parentcands[p];
11548  break;
11549  }
11550  else if( nchildren == 2 )
11551  {
11552  /* We know that every node in children is also a child of parentcands[p].
11553  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
11554  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
11555  */
11556  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
11557  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
11558  {
11559  *parent = parentcands[p];
11560  break;
11561  }
11562  }
11563  else
11564  {
11565  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
11566 
11567  /* sort children of parent candidate */
11568  SCIPsortPtr((void**)parentcands[p]->children, ptrcomp, nchildren);
11569 
11570  /* check if childnodes and parentcands[p]->children are the same */
11571  for( i = 0; i < nchildren; ++i )
11572  if( children[i] != parentcands[p]->children[i] )
11573  break;
11574  if( i == nchildren )
11575  {
11576  /* yeah, found an exact match */
11577  *parent = parentcands[p];
11578  break;
11579  }
11580  }
11581  }
11582 
11583  break;
11584  }
11585 
11586  /* non-commutative operands with two children */
11587  case SCIP_EXPR_MINUS :
11588  case SCIP_EXPR_DIV :
11589  {
11590  for( p = 0; p < nparentcands; ++p )
11591  {
11592  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
11593  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
11594  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
11595  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
11596  {
11597  /* yeah, found one */
11598  *parent = parentcands[p];
11599  break;
11600  }
11601  }
11602 
11603  break;
11604  }
11605 
11606  /* operands with one child and data */
11607  case SCIP_EXPR_INTPOWER:
11608  {
11609  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
11610  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
11611  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
11612  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
11613 
11614  /* yeah, have one with same exponent */
11615  *parent = parentcands[0];
11616 
11617  break;
11618  }
11619 
11620  case SCIP_EXPR_REALPOWER:
11621  case SCIP_EXPR_SIGNPOWER:
11622  {
11623  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
11624  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
11625  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
11626  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
11627 
11628  /* yeah, have one with same exponent */
11629  *parent = parentcands[0];
11630 
11631  break;
11632  }
11633 
11634  /* commutative operands with n children and data */
11635  case SCIP_EXPR_LINEAR:
11636  {
11637  SCIP_Real* exprcoef;
11638  SCIP_Real* candcoef;
11639 
11640  exprcoef = (SCIP_Real*)opdata.data;
11641  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
11642  if( exprchildren != NULL )
11643  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, ptrcomp, nchildren);
11644  else
11645  SCIPsortPtrReal((void**)children, exprcoef, ptrcomp, nchildren);
11646  for( p = 0; p < nparentcands; ++p )
11647  {
11648  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
11649  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
11650 
11651  candcoef = (SCIP_Real*)parentcands[p]->data.data;
11652  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
11653 
11654  /* sort children of parent candidate */
11655  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, ptrcomp, nchildren);
11656 
11657  /* check if children and coefficients in parent candidate and expression are the same */
11658  for( i = 0; i < nchildren; ++i )
11659  {
11660  if( children[i] != parentcands[p]->children[i] )
11661  break;
11662  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
11663  break;
11664  }
11665  if( i < nchildren )
11666  continue;
11667 
11668  /* yeah, found an exact match */
11669  *parent = parentcands[p];
11670  break;
11671  }
11672 
11673  break;
11674  }
11675 
11676  case SCIP_EXPR_QUADRATIC:
11677  {
11678  SCIP_EXPRDATA_QUADRATIC* exprdata;
11679  SCIP_Real* exprlincoef;
11680  SCIP_Real* candlincoef;
11681  SCIP_EXPRDATA_QUADRATIC* canddata;
11682  int* perm;
11683  int* invperm;
11684 
11685  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
11686  exprlincoef = exprdata->lincoefs;
11687 
11688  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
11689 
11690  /* sort expr->children and childnodes and store inverse permutation in invperm */
11691  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
11692  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
11693  for( i = 0; i < nchildren; ++i )
11694  invperm[i] = i; /*lint !e644*/
11695 
11696  if( exprlincoef != NULL )
11697  if( exprchildren != NULL )
11698  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, ptrcomp, nchildren);
11699  else
11700  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, ptrcomp, nchildren);
11701  else
11702  if( exprchildren != NULL )
11703  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, ptrcomp, nchildren);
11704  else
11705  SCIPsortPtrInt((void**)children, invperm, ptrcomp, nchildren);
11706 
11707  /* compute permutation from its inverse */
11708  for( i = 0; i < nchildren; ++i )
11709  perm[invperm[i]] = i; /*lint !e644*/
11710 
11711  /* apply permuation to exprdata->quadelems and sort again */
11712  for( i = 0; i < exprdata->nquadelems; ++i )
11713  {
11714  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
11715  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
11716  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
11717  {
11718  int tmp;
11719  tmp = exprdata->quadelems[i].idx1;
11720  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
11721  exprdata->quadelems[i].idx2 = tmp;
11722  }
11723  }
11724  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
11725  exprdata->sorted = TRUE;
11726 
11727  for( p = 0; p < nparentcands; ++p )
11728  {
11729  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
11730  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
11731 
11732  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
11733  candlincoef = canddata->lincoefs;
11734  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
11735  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
11736 
11737  /* sort parentcands[p]->children and store inverse permutation in invperm */
11738  for( i = 0; i < nchildren; ++i )
11739  invperm[i] = i;
11740 
11741  if( candlincoef != NULL )
11742  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, ptrcomp, parentcands[p]->nchildren);
11743  else
11744  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, ptrcomp, nchildren);
11745 
11746  /* compute permutation from its inverse */
11747  for( i = 0; i < nchildren; ++i )
11748  perm[invperm[i]] = i;
11749 
11750  /* apply permutation to canddata->quadelems */
11751  for( i = 0; i < canddata->nquadelems; ++i )
11752  {
11753  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
11754  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
11755  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
11756  {
11757  int tmp;
11758  tmp = canddata->quadelems[i].idx1;
11759  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
11760  canddata->quadelems[i].idx2 = tmp;
11761  }
11762  }
11763  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
11764  canddata->sorted = TRUE;
11765 
11766  /* check if children and linear coefficients in parent candidate and expression are the same */
11767  for( i = 0; i < nchildren; ++i )
11768  {
11769  if( children[i] != parentcands[p]->children[i] )
11770  break;
11771  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
11772  break;
11773  }
11774  if( i < nchildren )
11775  continue;
11776 
11777  assert(exprdata->nquadelems == canddata->nquadelems);
11778  for( i = 0; i < exprdata->nquadelems; ++i )
11779  {
11780  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
11781  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
11782  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
11783  break;
11784  }
11785  if( i == exprdata->nquadelems )
11786  {
11787  /* yeah, parentcands[p] is same quadratic expression as expr */
11788  *parent = parentcands[p];
11789  break;
11790  }
11791  }
11792 
11793  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
11794  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
11795 
11796  break;
11797  }
11798 
11799  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
11800  case SCIP_EXPR_POLYNOMIAL:
11801  {
11802  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
11803  SCIP_EXPRDATA_POLYNOMIAL* canddata;
11804  int* perm;
11805  int* invperm;
11806 
11807  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
11808 
11809  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
11810 
11811  /* sort exprchildren and childnodes and store inverse permutation in invperm */
11812  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
11813  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
11814  for( i = 0; i < nchildren; ++i )
11815  invperm[i] = i; /*lint !e644*/
11816 
11817  if( exprchildren != NULL )
11818  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, ptrcomp, nchildren);
11819  else
11820  SCIPsortPtrInt((void**)children, invperm, ptrcomp, nchildren);
11821 
11822  /* compute permutation from its inverse */
11823  for( i = 0; i < nchildren; ++i )
11824  perm[invperm[i]] = i; /*lint !e644*/
11825 
11826  /* apply permutation to exprdata and sort again */
11827  polynomialdataApplyChildmap(exprdata, perm);
11828  polynomialdataSortMonomials(exprdata);
11829 
11830  for( p = 0; p < nparentcands; ++p )
11831  {
11832  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
11833  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
11834 
11835  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
11836  assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
11837  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
11838 
11839  /* sort parentcands[p]->children and store inverse permutation in invperm */
11840  for( i = 0; i < nchildren; ++i )
11841  invperm[i] = i;
11842 
11843  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, ptrcomp, nchildren);
11844 
11845  /* compute permutation from its inverse */
11846  for( i = 0; i < nchildren; ++i )
11847  perm[invperm[i]] = i;
11848 
11849  /* apply permutation to canddata and sort again */
11850  polynomialdataApplyChildmap(canddata, perm);
11851  polynomialdataSortMonomials(canddata);
11852 
11853  /* check if children are equal */
11854  for( i = 0; i < nchildren; ++i )
11855  if( children[i] != parentcands[p]->children[i] )
11856  break;
11857  if( i < nchildren )
11858  continue;
11859 
11860  /* check if monomials are equal */
11861  for( i = 0; i < exprdata->nmonomials; ++i )
11862  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
11863  break;
11864  if( i == exprdata->nmonomials )
11865  {
11866  /* yeah, parentcands[p] is same polynomial expression as expr */
11867  *parent = parentcands[p];
11868  break;
11869  }
11870  }
11871 
11872  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
11873  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
11874 
11875  break;
11876  }
11877 
11878  case SCIP_EXPR_VARIDX:
11879  case SCIP_EXPR_PARAM:
11880  case SCIP_EXPR_CONST:
11881  case SCIP_EXPR_LAST:
11882  default:
11883  SCIPerrorMessage("expression operand %d unexpected here\n", op);
11884  return SCIP_ERROR;
11885  }
11886 
11887  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
11888 
11889  return SCIP_OKAY;
11890 }
11891 
11892 /** adds an expression into an expression graph
11893  * enables corresponding nodes */
11894 static
11896  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11897  SCIP_EXPR* expr, /**< expression to add */
11898  void** vars, /**< variables corresponding to VARIDX expressions */
11899  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
11900  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
11901  )
11902 {
11903  SCIP_EXPRGRAPHNODE** childnodes;
11904  SCIP_Bool childisnew;
11905  SCIP_Bool nochildisnew;
11906  SCIP_EXPROPDATA opdata;
11907  int i;
11908 
11909  assert(exprgraph != NULL);
11910  assert(expr != NULL);
11911  assert(exprnode != NULL);
11912  assert(exprnodeisnew != NULL);
11913 
11914  if( expr->op == SCIP_EXPR_VARIDX )
11915  {
11916  /* find node corresponding to variable and add if not existing yet */
11917  assert(expr->nchildren == 0);
11918 
11919  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
11920  assert(*exprnode != NULL);
11921  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
11922  assert((*exprnode)->data.intval >= 0);
11923  assert((*exprnode)->data.intval < exprgraph->nvars);
11924  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
11925 
11926  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
11927 
11928  return SCIP_OKAY;
11929  }
11930 
11931  if( expr->op == SCIP_EXPR_CONST )
11932  {
11933  /* find node corresponding to constant and add if not existing yet */
11934  assert(expr->nchildren == 0);
11935 
11936  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
11937  assert(*exprnode != NULL);
11938  assert((*exprnode)->op == SCIP_EXPR_CONST);
11939  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
11940 
11941  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
11942 
11943  return SCIP_OKAY;
11944  }
11945 
11946  /* expression should be variable or constant or have children, i.e., parameters are not allowed here (so far) */
11947  assert(expr->nchildren > 0);
11948 
11949  /* add children expressions into expression graph
11950  * check if we can find a common parent
11951  */
11952  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
11953  nochildisnew = TRUE;
11954  for( i = 0; i < expr->nchildren; ++i )
11955  {
11956  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, &childnodes[i], &childisnew) ); /*lint !e644*/
11957  assert(childnodes[i] != NULL);
11958  nochildisnew &= !childisnew; /*lint !e514*/
11959  }
11960 
11961  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
11962  if( nochildisnew )
11963  {
11964  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
11965 
11966  if( *exprnode != NULL )
11967  {
11968  /* node already existing, make sure it is enabled */
11969  (*exprnode)->enabled = TRUE;
11970  *exprnodeisnew = FALSE;
11971 
11972  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
11973  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
11974  * SCIPdebugPrintf("\n");
11975  */
11976 
11977  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
11978  return SCIP_OKAY;
11979  }
11980  }
11981 
11982  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
11983 
11984  /* copy expression data */
11985  if( exprOpTable[expr->op].copydata != NULL )
11986  {
11987  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
11988  }
11989  else
11990  {
11991  opdata = expr->data;
11992  }
11993 
11994  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
11995  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
11996  *exprnodeisnew = TRUE;
11997 
11998  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
11999 
12000  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12001  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12002  * SCIPdebugPrintf("\n");
12003  */
12004 
12005  return SCIP_OKAY;
12006 }
12007 
12008 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12009 static
12011  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12012  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12013  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12014  )
12015 {
12016  SCIP_EXPRGRAPHNODE* node;
12017  int i;
12018  int p;
12019 
12020  assert(exprgraph != NULL);
12021  assert(clearreverseprop != NULL);
12022  assert(boundchanged != NULL);
12023 
12024  *boundchanged = FALSE;
12025  for( i = 0; i < exprgraph->nvars; ++i )
12026  {
12027  node = exprgraph->varnodes[i];
12028 
12029  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12030  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12031  {
12033  continue;
12034  }
12035 
12036  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12037  {
12038  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12039  SCIP_Real tmp;
12040 
12041  tmp = exprgraph->varbounds[i].inf;
12042  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12043  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12044  }
12045 
12046  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12047  +exprgraph->varbounds[i].sup > node->bounds.sup )
12048  {
12049  for( p = 0; p < node->nparents; ++p )
12051 
12052  node->bounds = exprgraph->varbounds[i];
12053  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12054 
12055  *boundchanged = TRUE;
12056 
12057  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12058  *clearreverseprop = TRUE;
12059  }
12060  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12061  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12062  {
12063  for( p = 0; p < node->nparents; ++p )
12065 
12066  node->bounds = exprgraph->varbounds[i];
12067  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12068 
12069  *boundchanged = TRUE;
12070  }
12071  else
12072  {
12073  node->bounds = exprgraph->varbounds[i];
12074  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12075  }
12076 
12078  }
12079 }
12080 
12081 /**@} */
12082 
12083 /**@name Expression graph node methods */
12084 /**@{ */
12085 
12086 /* In debug mode, the following methods are implemented as function calls to ensure
12087  * type validity.
12088  * In optimized mode, the methods are implemented as defines to improve performance.
12089  * However, we want to have them in the library anyways, so we have to undef the defines.
12090  */
12091 
12092 #undef SCIPexprgraphCaptureNode
12093 #undef SCIPexprgraphIsNodeEnabled
12094 #undef SCIPexprgraphGetNodeNChildren
12095 #undef SCIPexprgraphGetNodeChildren
12096 #undef SCIPexprgraphGetNodeNParents
12097 #undef SCIPexprgraphGetNodeParents
12098 #undef SCIPexprgraphGetNodeDepth
12099 #undef SCIPexprgraphGetNodePosition
12100 #undef SCIPexprgraphGetNodeOperator
12101 #undef SCIPexprgraphGetNodeOperatorIndex
12102 #undef SCIPexprgraphGetNodeOperatorReal
12103 #undef SCIPexprgraphGetNodeVar
12104 #undef SCIPexprgraphGetNodeRealPowerExponent
12105 #undef SCIPexprgraphGetNodeIntPowerExponent
12106 #undef SCIPexprgraphGetNodeSignPowerExponent
12107 #undef SCIPexprgraphGetNodeLinearCoefs
12108 #undef SCIPexprgraphGetNodeLinearConstant
12109 #undef SCIPexprgraphGetNodeQuadraticConstant
12110 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12111 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12112 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12113 #undef SCIPexprgraphGetNodePolynomialMonomials
12114 #undef SCIPexprgraphGetNodePolynomialNMonomials
12115 #undef SCIPexprgraphGetNodePolynomialConstant
12116 #undef SCIPexprgraphGetNodeBounds
12117 #undef SCIPexprgraphGetNodeVal
12118 #undef SCIPexprgraphGetNodeCurvature
12119 
12120 /** captures node, i.e., increases number of uses */
12122  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12123  )
12124 {
12125  assert(node->nuses >= 0);
12126 
12127  SCIPdebugMessage("capture node %p\n", (void*)node);
12128 
12129  ++node->nuses;
12130 }
12131 
12132 /** returns whether a node is currently enabled */
12134  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12135  )
12136 {
12137  assert(node != NULL);
12138 
12139  return node->enabled;
12140 }
12141 
12142 /** gets number of children of a node in an expression graph */
12144  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12145  )
12146 {
12147  assert(node != NULL);
12148 
12149  return node->nchildren;
12150 }
12151 
12152 /** gets children of a node in an expression graph */
12154  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12155  )
12156 {
12157  assert(node != NULL);
12158 
12159  return node->children;
12160 }
12161 
12162 /** gets number of parents of a node in an expression graph */
12164  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12165  )
12166 {
12167  assert(node != NULL);
12168 
12169  return node->nparents;
12170 }
12171 
12172 /** gets parents of a node in an expression graph */
12174  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12175  )
12176 {
12177  assert(node != NULL);
12178 
12179  return node->parents;
12180 }
12181 
12182 /** gets depth of node in expression graph */
12184  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12185  )
12186 {
12187  assert(node != NULL);
12188 
12189  return node->depth;
12190 }
12191 
12192 /** gets position of node in expression graph at its depth level */
12194  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12195  )
12196 {
12197  assert(node != NULL);
12198 
12199  return node->pos;
12200 }
12201 
12202 /** gets operator of a node in an expression graph */
12204  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12205  )
12206 {
12207  assert(node != NULL);
12208 
12209  return node->op;
12210 }
12211 
12212 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
12214  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12215  )
12216 {
12217  assert(node != NULL);
12218  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
12219 
12220  return node->data.intval;
12221 }
12222 
12223 /** gives real belonging to a SCIP_EXPR_CONST operand */
12225  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12226  )
12227 {
12228  assert(node != NULL);
12229  assert(node->op == SCIP_EXPR_CONST);
12230 
12231  return node->data.dbl;
12232 }
12233 
12234 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
12236  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12237  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12238  )
12239 {
12240  assert(exprgraph != NULL);
12241  assert(node != NULL);
12242  assert(node->op == SCIP_EXPR_VARIDX);
12243  assert(node->data.intval >= 0);
12244  assert(node->data.intval < exprgraph->nvars);
12245 
12246  return exprgraph->vars[node->data.intval];
12247 }
12248 
12249 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
12251  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12252  )
12253 {
12254  assert(node != NULL);
12255  assert(node->op == SCIP_EXPR_REALPOWER);
12256 
12257  return node->data.dbl;
12258 }
12259 
12260 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
12262  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12263  )
12264 {
12265  assert(node != NULL);
12266  assert(node->op == SCIP_EXPR_INTPOWER);
12267 
12268  return node->data.intval;
12269 }
12270 
12271 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
12273  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12274  )
12275 {
12276  assert(node != NULL);
12277  assert(node->op == SCIP_EXPR_SIGNPOWER);
12278 
12279  return node->data.dbl;
12280 }
12281 
12282 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
12284  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12285  )
12286 {
12287  assert(node != NULL);
12288  assert(node->op == SCIP_EXPR_LINEAR);
12289 
12290  return (SCIP_Real*)node->data.data;
12291 }
12292 
12293 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
12295  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12296  )
12297 {
12298  assert(node != NULL);
12299  assert(node->op == SCIP_EXPR_LINEAR);
12300  assert(node->data.data != NULL);
12301 
12302  return ((SCIP_Real*)node->data.data)[node->nchildren];
12303 }
12304 
12305 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
12307  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12308  )
12309 {
12310  assert(node != NULL);
12311  assert(node->op == SCIP_EXPR_QUADRATIC);
12312  assert(node->data.data != NULL);
12313 
12314  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
12315 }
12316 
12317 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
12319  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12320  )
12321 {
12322  assert(node != NULL);
12323  assert(node->op == SCIP_EXPR_QUADRATIC);
12324  assert(node->data.data != NULL);
12325 
12326  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
12327 }
12328 
12329 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
12331  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12332  )
12333 {
12334  assert(node != NULL);
12335  assert(node->op == SCIP_EXPR_QUADRATIC);
12336  assert(node->data.data != NULL);
12337 
12338  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
12339 }
12340 
12341 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
12343  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12344  )
12345 {
12346  assert(node != NULL);
12347  assert(node->op == SCIP_EXPR_QUADRATIC);
12348  assert(node->data.data != NULL);
12349 
12350  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
12351 }
12352 
12353 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
12355  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12356  )
12357 {
12358  assert(node != NULL);
12359  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12360  assert(node->data.data != NULL);
12361 
12362  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
12363 }
12364 
12365 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
12367  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12368  )
12369 {
12370  assert(node != NULL);
12371  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12372  assert(node->data.data != NULL);
12373 
12374  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
12375 }
12376 
12377 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
12379  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12380  )
12381 {
12382  assert(node != NULL);
12383  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12384  assert(node->data.data != NULL);
12385 
12386  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
12387 }
12388 
12389 /** gets bounds of a node in an expression graph */
12391  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12392  )
12393 {
12394  assert(node != NULL);
12395 
12396  return node->bounds;
12397 }
12398 
12399 /** gets value of expression associated to node from last evaluation call */
12401  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12402  )
12403 {
12404  assert(node != NULL);
12405 
12406  return node->value;
12407 }
12408 
12409 /** gets curvature of expression associated to node from last curvature check call */
12411  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12412  )
12413 {
12414  assert(node != NULL);
12415 
12416  return node->curv;
12417 }
12418 
12419 /** creates an expression graph node */
12421  BMS_BLKMEM* blkmem, /**< block memory */
12422  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
12423  SCIP_EXPROP op, /**< operator type of expression */
12424  ...
12425  )
12426 {
12427  va_list ap;
12428  SCIP_EXPROPDATA opdata;
12429 
12430  assert(blkmem != NULL);
12431  assert(node != NULL);
12432 
12433  *node = NULL;
12434 
12435  switch( op )
12436  {
12437  case SCIP_EXPR_VARIDX :
12438  case SCIP_EXPR_PARAM :
12439  case SCIP_EXPR_CONST :
12440  case SCIP_EXPR_LINEAR :
12441  case SCIP_EXPR_QUADRATIC :
12442  case SCIP_EXPR_POLYNOMIAL:
12443  {
12444  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
12445  SCIPABORT();
12446  return SCIP_ERROR; /*lint !e527*/
12447  }
12448 
12449  /* operands without data */
12450  case SCIP_EXPR_PLUS :
12451  case SCIP_EXPR_MINUS :
12452  case SCIP_EXPR_MUL :
12453  case SCIP_EXPR_DIV :
12454  case SCIP_EXPR_MIN :
12455  case SCIP_EXPR_MAX :
12456  case SCIP_EXPR_SQUARE :
12457  case SCIP_EXPR_SQRT :
12458  case SCIP_EXPR_EXP :
12459  case SCIP_EXPR_LOG :
12460  case SCIP_EXPR_SIN :
12461  case SCIP_EXPR_COS :
12462  case SCIP_EXPR_TAN :
12463  /* case SCIP_EXPR_ERF : */
12464  /* case SCIP_EXPR_ERFI: */
12465  case SCIP_EXPR_ABS :
12466  case SCIP_EXPR_SIGN :
12467  case SCIP_EXPR_SUM :
12468  case SCIP_EXPR_PRODUCT:
12469  opdata.data = NULL;
12470  break;
12471 
12472  case SCIP_EXPR_REALPOWER:
12473  case SCIP_EXPR_SIGNPOWER:
12474  {
12475  va_start(ap, op ); /*lint !e826*/
12476  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
12477  va_end( ap ); /*lint !e826*/
12478 
12479  break;
12480  }
12481 
12482  case SCIP_EXPR_INTPOWER:
12483  {
12484  va_start(ap, op ); /*lint !e826*/
12485  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
12486  va_end( ap ); /*lint !e826*/
12487 
12488  break;
12489  }
12490 
12491  case SCIP_EXPR_LAST:
12492  default:
12493  SCIPerrorMessage("unknown operand: %d\n", op);
12494  return SCIP_INVALIDDATA;
12495  }
12496 
12497  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) );
12498 
12499  return SCIP_OKAY;
12500 }
12501 
12502 /** creates an expression graph node for a linear expression */
12504  BMS_BLKMEM* blkmem, /**< block memory */
12505  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
12506  int ncoefs, /**< number of coefficients */
12507  SCIP_Real* coefs, /**< coefficients of linear expression */
12508  SCIP_Real constant /**< constant of linear expression */
12509  )
12510 {
12511  SCIP_EXPROPDATA opdata;
12512  SCIP_Real* data;
12513 
12514  assert(blkmem != NULL);
12515  assert(node != NULL);
12516 
12517  /* we store the coefficients and the constant in a single array and make this our operand data */
12518  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
12519  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
12520  data[ncoefs] = constant;
12521 
12522  opdata.data = data;
12523  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
12524 
12525  return SCIP_OKAY;
12526 }
12527 
12528 /** creates an expression graph node for a quadratic expression */
12530  BMS_BLKMEM* blkmem, /**< block memory */
12531  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
12532  int nchildren, /**< number of children */
12533  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
12534  int nquadelems, /**< number of quadratic elements */
12535  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
12536  SCIP_Real constant /**< constant */
12537  )
12538 {
12539  SCIP_EXPROPDATA opdata;
12541 
12542  assert(blkmem != NULL);
12543  assert(node != NULL);
12544  assert(quadelems != NULL || nquadelems == 0);
12545 
12546  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
12547 
12548  opdata.data = data;
12549  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
12550 
12551  return SCIP_OKAY;
12552 }
12553 
12554 /** creates an expression graph node for a polynomial expression */
12556  BMS_BLKMEM* blkmem, /**< block memory */
12557  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
12558  int nmonomials, /**< number of monomials */
12559  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
12560  SCIP_Real constant, /**< constant of polynomial */
12561  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
12562  )
12563 {
12564  SCIP_EXPROPDATA opdata;
12566 
12567  assert(blkmem != NULL);
12568  assert(node != NULL);
12569  assert(monomials != NULL || nmonomials == 0);
12570 
12571  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
12572 
12573  opdata.data = data;
12574  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
12575 
12576  return SCIP_OKAY;
12577 }
12578 
12579 /** adds monomials to an expression graph node that is a polynomial expression */
12581  BMS_BLKMEM* blkmem, /**< block memory */
12582  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
12583  int nmonomials, /**< number of monomials */
12584  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
12585  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
12586  )
12587 {
12588  assert(blkmem != NULL);
12589  assert(node != NULL);
12591  assert(monomials != NULL || nmonomials == 0);
12592 
12593  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
12594 
12595  return SCIP_OKAY;
12596 }
12597 
12598 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
12599  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
12600  * If the node is a linear expression, it may be freed.
12601  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
12602  * It is assumed that the user had captured the node.
12603  * It is assumed that the expression graph has been simplified before.
12604  */
12606  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12607  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
12608  int linvarssize, /**< length of linvars and lincoefs arrays */
12609  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
12610  void** linvars, /**< buffer to store variables of linear part */
12611  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
12612  SCIP_Real* constant /**< buffer to store constant part */
12613  )
12614 {
12615  int orignvars;
12616  int* varsusage;
12617  SCIP_EXPRGRAPHNODE* orignode;
12618  SCIP_Bool havechange;
12619  int i;
12620 
12621  assert(exprgraph != NULL);
12622  assert(node != NULL);
12623  assert(*node != NULL);
12624  assert((*node)->nuses > 0);
12625  assert(nlinvars != NULL);
12626  assert(linvars != NULL || linvarssize == 0);
12627  assert(lincoefs != NULL || linvarssize == 0);
12628  assert(constant != NULL);
12629 
12630  *constant = 0.0;
12631  *nlinvars = 0;
12632 
12633  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
12634 
12635  /* do some obvious and easy cases */
12636  switch( (*node)->op )
12637  {
12638  case SCIP_EXPR_VARIDX:
12639  {
12640  if( linvarssize >= 1 )
12641  {
12642  *nlinvars = 1;
12643  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
12644  lincoefs[0] = 1.0; /*lint !e613*/
12645 
12646  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12647  }
12648  return SCIP_OKAY;
12649  }
12650 
12651  case SCIP_EXPR_CONST:
12652  {
12653  *constant = (*node)->data.dbl;
12654  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12655 
12656  return SCIP_OKAY;
12657  }
12658 
12659  case SCIP_EXPR_REALPOWER:
12660  case SCIP_EXPR_SIGNPOWER:
12661  {
12662  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12663  {
12664  *nlinvars = 1;
12665  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12666  lincoefs[0] = 1.0; /*lint !e613*/
12667 
12668  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12669  }
12670  return SCIP_OKAY;
12671  }
12672 
12673  case SCIP_EXPR_INTPOWER:
12674  {
12675  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12676  {
12677  *nlinvars = 1;
12678  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12679  lincoefs[0] = 1.0; /*lint !e613*/
12680 
12681  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12682  }
12683  return SCIP_OKAY;
12684  }
12685 
12686  case SCIP_EXPR_PLUS:
12687  {
12688  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12689  {
12690  *constant = (*node)->children[0]->data.dbl;
12691  *nlinvars = 1;
12692  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
12693  lincoefs[0] = 1.0; /*lint !e613*/
12694 
12695  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12696 
12697  return SCIP_OKAY;
12698  }
12699  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12700  {
12701  *constant = (*node)->children[1]->data.dbl;
12702  *nlinvars = 1;
12703  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12704  lincoefs[0] = 1.0; /*lint !e613*/
12705 
12706  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12707 
12708  return SCIP_OKAY;
12709  }
12710  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
12711  {
12712  *nlinvars = 2;
12713  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12714  lincoefs[0] = 1.0; /*lint !e613*/
12715  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
12716  lincoefs[1] = 1.0; /*lint !e613*/
12717 
12718  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12719 
12720  return SCIP_OKAY;
12721  }
12722  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
12723  {
12724  /* handle this one later */
12725  break;
12726  }
12727  return SCIP_OKAY;
12728  }
12729 
12730  case SCIP_EXPR_MINUS:
12731  {
12732  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12733  {
12734  *constant = (*node)->children[0]->data.dbl;
12735  *nlinvars = 1;
12736  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
12737  lincoefs[0] = -1.0; /*lint !e613*/
12738 
12739  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12740 
12741  return SCIP_OKAY;
12742  }
12743  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12744  {
12745  *constant = -(*node)->children[1]->data.dbl;
12746  *nlinvars = 1;
12747  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12748  lincoefs[0] = 1.0; /*lint !e613*/
12749 
12750  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12751 
12752  return SCIP_OKAY;
12753  }
12754  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
12755  {
12756  *nlinvars = 2;
12757  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12758  lincoefs[0] = 1.0; /*lint !e613*/
12759  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
12760  lincoefs[1] = -1.0; /*lint !e613*/
12761 
12762  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12763 
12764  return SCIP_OKAY;
12765  }
12766  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
12767  {
12768  /* handle this one later */
12769  break;
12770  }
12771  return SCIP_OKAY;
12772  }
12773 
12774  case SCIP_EXPR_MUL:
12775  {
12776  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12777  {
12778  *nlinvars = 1;
12779  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
12780  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
12781 
12782  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12783  }
12784  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12785  {
12786  *nlinvars = 1;
12787  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12788  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
12789 
12790  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12791  }
12792  return SCIP_OKAY;
12793  }
12794 
12795  case SCIP_EXPR_DIV:
12796  {
12797  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
12798  return SCIP_OKAY;
12799 
12800  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12801  {
12802  *nlinvars = 1;
12803  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12804  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
12805 
12806  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12807  }
12808  return SCIP_OKAY;
12809  }
12810 
12811  case SCIP_EXPR_SQUARE:
12812  case SCIP_EXPR_SQRT:
12813  case SCIP_EXPR_EXP:
12814  case SCIP_EXPR_LOG:
12815  case SCIP_EXPR_SIN:
12816  case SCIP_EXPR_COS:
12817  case SCIP_EXPR_TAN:
12818  /* case SCIP_EXPR_ERF: */
12819  /* case SCIP_EXPR_ERFI: */
12820  case SCIP_EXPR_ABS:
12821  case SCIP_EXPR_SIGN:
12822  case SCIP_EXPR_MIN:
12823  case SCIP_EXPR_MAX:
12824  return SCIP_OKAY;
12825 
12826  case SCIP_EXPR_PRODUCT:
12827  return SCIP_OKAY;
12828 
12829  case SCIP_EXPR_SUM:
12830  case SCIP_EXPR_LINEAR:
12831  case SCIP_EXPR_QUADRATIC:
12832  case SCIP_EXPR_POLYNOMIAL:
12833  default:
12834  {
12835  /* check if there is a child that is a variable */
12836  for( i = 0; i < (*node)->nchildren; ++i )
12837  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
12838  break;
12839 
12840  if( i == (*node)->nchildren )
12841  return SCIP_OKAY;
12842 
12843  break;
12844  }
12845  } /*lint !e788*/
12846 
12847  /* count how often variables are used in this expression */
12848  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
12849  orignvars = exprgraph->nvars;
12850  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
12851  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
12852 
12853  exprgraphNodeGetVarsUsage(*node, varsusage);
12854 
12855  /* duplicate node if it has parents or more than one user */
12856  orignode = NULL;
12857  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
12858  {
12859  SCIP_EXPROPDATA data;
12860 
12861  orignode = *node;
12862 
12863  if( exprOpTable[orignode->op].copydata != NULL )
12864  {
12865  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
12866  }
12867  else
12868  {
12869  data = orignode->data;
12870  }
12871 
12872  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
12873  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
12874  SCIPexprgraphCaptureNode(*node);
12875  }
12876 
12877  havechange = FALSE;
12878  /* split up constant and linear part */
12879  switch( (*node)->op )
12880  {
12881  case SCIP_EXPR_PLUS:
12882  case SCIP_EXPR_MINUS:
12883  {
12884  SCIP_EXPRGRAPHNODE* varchild;
12885  SCIP_EXPRGRAPHNODE* otherchild;
12886  int varidx;
12887 
12888  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
12889  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
12890  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
12891  assert(linvarssize >= 1);
12892 
12893  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
12894  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
12895  varidx = varchild->data.intval;
12896  /* if variable is used in other child (which should be nonlinear), we don't take it */
12897  if( varsusage[varidx] > 1 )
12898  break;
12899 
12900  /* add to linear variables */
12901  *nlinvars = 1;
12902  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
12903  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
12904  lincoefs[0] = -1.0; /*lint !e613*/
12905  else
12906  lincoefs[0] = 1.0; /*lint !e613*/
12907 
12908  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
12909  {
12910  /* replace *node by otherchild */
12911  SCIPexprgraphCaptureNode(otherchild);
12912  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12913  *node = otherchild;
12914  }
12915  else
12916  {
12917  SCIP_Real* lindata;
12918 
12919  /* turn *node into linear expression -1.0 * otherchild */
12920 
12921  /* reduce to one child */
12922  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
12923  (*node)->children[0] = otherchild;
12924  (*node)->nchildren = 1;
12925  (*node)->op = SCIP_EXPR_LINEAR;
12926 
12927  /* setup linear data -1.0 * child0 + 0.0 */
12928  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
12929  lindata[0] = -1.0;
12930  lindata[1] = 0.0;
12931  (*node)->data.data = (void*)lindata;
12932 
12933  /* remove *node as parent of varchild */
12934  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
12935  }
12936 
12937  havechange = TRUE;
12938 
12939  break;
12940  }
12941 
12942  case SCIP_EXPR_SUM:
12943  {
12944  int nchildren;
12945 
12946  i = 0;
12947  nchildren = (*node)->nchildren;
12948  while( i < nchildren )
12949  {
12950  /* sort out constants */
12951  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
12952  {
12953  *constant += (*node)->children[i]->data.dbl;
12954  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
12955 
12956  if( i < nchildren-1 )
12957  {
12958  (*node)->children[i] = (*node)->children[nchildren-1];
12959  (*node)->children[nchildren-1] = NULL;
12960  }
12961  --nchildren;
12962 
12963  continue;
12964  }
12965 
12966  /* keep every child that is not a constant or variable */
12967  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
12968  {
12969  ++i;
12970  continue;
12971  }
12972 
12973  /* skip variables that are used in other parts of the expression */
12974  if( varsusage[(*node)->children[i]->data.intval] > 1 )
12975  {
12976  ++i;
12977  continue;
12978  }
12979 
12980  /* move variable into linear part, if still space */
12981  if( *nlinvars < linvarssize )
12982  {
12983  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
12984  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
12985  ++*nlinvars;
12986 
12987  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
12988  if( i < nchildren-1 )
12989  {
12990  (*node)->children[i] = (*node)->children[nchildren-1];
12991  (*node)->children[nchildren-1] = NULL;
12992  }
12993  --nchildren;
12994 
12995  continue;
12996  }
12997  }
12998  assert(i == nchildren);
12999 
13000  if( nchildren == 0 )
13001  {
13002  /* all children were removed */
13003  havechange = TRUE;
13004  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13005  (*node)->nchildren = 0;
13006  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13007  break;
13008  }
13009 
13010  if( nchildren < (*node)->nchildren )
13011  {
13012  /* some children were removed */
13013  havechange = TRUE;
13014  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13015  (*node)->nchildren = nchildren;
13016  }
13017 
13018  if( havechange && (*node)->nchildren == 1 )
13019  {
13020  /* replace node by its child */
13021  SCIP_EXPRGRAPHNODE* child;
13022 
13023  child = (*node)->children[0];
13024  SCIPexprgraphCaptureNode(child);
13025  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13026  *node = child;
13027 
13028  break;
13029  }
13030 
13031  break;
13032  }
13033 
13034  case SCIP_EXPR_LINEAR:
13035  {
13036  int nchildren;
13037  SCIP_Real* coefs;
13038 
13039  coefs = (SCIP_Real*)(*node)->data.data;
13040  assert(coefs != NULL);
13041 
13042  /* remove constant, if nonzero */
13043  if( coefs[(*node)->nchildren] != 0.0 )
13044  {
13045  *constant = coefs[(*node)->nchildren];
13046  coefs[(*node)->nchildren] = 0.0;
13047  havechange = TRUE;
13048  }
13049 
13050  i = 0;
13051  nchildren = (*node)->nchildren;
13052  while( i < nchildren )
13053  {
13054  /* sort out constants */
13055  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13056  {
13057  *constant += coefs[i] * (*node)->children[i]->data.dbl;
13058  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13059 
13060  if( i < nchildren-1 )
13061  {
13062  (*node)->children[i] = (*node)->children[nchildren-1];
13063  (*node)->children[nchildren-1] = NULL;
13064  coefs[i] = coefs[nchildren-1];
13065  coefs[nchildren-1] = 0.0;
13066  }
13067  --nchildren;
13068 
13069  continue;
13070  }
13071 
13072  /* keep everything that is not a constant or variable */
13073  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13074  {
13075  ++i;
13076  continue;
13077  }
13078 
13079  /* skip variables that are used in other parts of the expression */
13080  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13081  {
13082  ++i;
13083  continue;
13084  }
13085 
13086  /* move variable into linear part, if still space */
13087  if( *nlinvars < linvarssize )
13088  {
13089  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13090  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
13091  ++*nlinvars;
13092 
13093  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13094  if( i < nchildren-1 )
13095  {
13096  (*node)->children[i] = (*node)->children[nchildren-1];
13097  (*node)->children[nchildren-1] = NULL;
13098  coefs[i] = coefs[nchildren-1];
13099  coefs[nchildren-1] = 0.0;
13100  }
13101  --nchildren;
13102 
13103  continue;
13104  }
13105  }
13106  assert(i == nchildren);
13107 
13108  if( nchildren == 0 )
13109  {
13110  /* all children were removed */
13111  havechange = TRUE;
13112  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13113  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
13114  (*node)->data.data = NULL;
13115  (*node)->nchildren = 0;
13116  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
13117  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13118  break;
13119  }
13120 
13121  if( nchildren < (*node)->nchildren )
13122  {
13123  /* some children were removed */
13124  havechange = TRUE;
13125  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13126  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
13127  coefs[nchildren] = 0.0;
13128  (*node)->data.data = (void*)coefs;
13129  (*node)->nchildren = nchildren;
13130  }
13131 
13132  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
13133  {
13134  /* replace node by its child */
13135  SCIP_EXPRGRAPHNODE* child;
13136 
13137  child = (*node)->children[0];
13138  SCIPexprgraphCaptureNode(child);
13139  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13140  *node = child;
13141 
13142  break;
13143  }
13144 
13145  break;
13146  }
13147 
13148  case SCIP_EXPR_QUADRATIC:
13149  {
13150  SCIP_EXPRDATA_QUADRATIC* quaddata;
13151  SCIP_Bool* childused;
13152  int* childmap;
13153  int nchildren;
13154 
13155  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
13156  assert(quaddata != NULL);
13157 
13158  /* remove constant, if nonzero */
13159  if( quaddata->constant != 0.0 )
13160  {
13161  *constant = quaddata->constant;
13162  quaddata->constant = 0.0;
13163  havechange = TRUE;
13164  }
13165 
13166  /* if there is no linear part or no space left for linear variables, then stop */
13167  if( quaddata->lincoefs != NULL || linvarssize == 0 )
13168  break;
13169 
13170  /* check which childs are used in quadratic terms */
13171  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
13172  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
13173 
13174  for( i = 0; i < quaddata->nquadelems; ++i )
13175  {
13176  childused[quaddata->quadelems[i].idx1] = TRUE;
13177  childused[quaddata->quadelems[i].idx2] = TRUE;
13178  }
13179 
13180  /* alloc space for mapping of children indices */
13181  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
13182 
13183  nchildren = (*node)->nchildren;
13184  for( i = 0; i < nchildren; ++i )
13185  {
13186  childmap[i] = i; /*lint !e644*/
13187  if( *nlinvars >= linvarssize )
13188  continue;
13189  /* skip child if not variable or also used in quadratic part or other parts of expression */
13190  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13191  continue;
13192  if( childused[i] )
13193  continue;
13194  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13195  continue;
13196 
13197  /* put variable into linear part */
13198  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13199  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
13200  quaddata->lincoefs[i] = 0.0;
13201  ++*nlinvars;
13202 
13203  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13204 
13205  /* move last child to position i */
13206  if( i < nchildren-1 )
13207  {
13208  (*node)->children[i] = (*node)->children[nchildren-1];
13209  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
13210  childused[i] = childused[nchildren-1];
13211  childmap[nchildren-1] = i;
13212  }
13213  --nchildren;
13214  childmap[i] = -1;
13215 
13216  havechange = TRUE;
13217  --i; /* look at i again */
13218  }
13219 
13220  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
13221 
13222  if( nchildren < (*node)->nchildren )
13223  {
13224  /* apply childmap to quadratic term */
13225  for( i = 0; i < quaddata->nquadelems; ++i )
13226  {
13227  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
13228  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
13229  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
13230  {
13231  int tmp;
13232  tmp = quaddata->quadelems[i].idx1;
13233  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
13234  quaddata->quadelems[i].idx2 = tmp;
13235  }
13236  }
13237  quaddata->sorted = FALSE;
13238  }
13239  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
13240 
13241  if( nchildren == 0 )
13242  {
13243  /* all children were removed (so it was actually a linear expression) */
13244  havechange = TRUE;
13245  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13246  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
13247  (*node)->data.data = NULL;
13248  (*node)->nchildren = 0;
13249  (*node)->op = SCIP_EXPR_SUM;
13250  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13251  break;
13252  }
13253 
13254  if( nchildren < (*node)->nchildren )
13255  {
13256  /* reduce number of children */
13257  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13258  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
13259  (*node)->nchildren = nchildren;
13260  }
13261 
13262  break;
13263  }
13264 
13265  case SCIP_EXPR_POLYNOMIAL:
13266  {
13267  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
13268  SCIP_EXPRDATA_MONOMIAL* monomial;
13269  SCIP_Bool* childused;
13270  int childidx;
13271  int j;
13272 
13273  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
13274  assert(polynomialdata != NULL);
13275 
13276  /* make sure linear monomials are merged */
13277  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
13278 
13279  /* remove constant, if nonzero */
13280  if( polynomialdata->constant != 0.0 )
13281  {
13282  *constant = polynomialdata->constant;
13283  polynomialdata->constant = 0.0;
13284  havechange = TRUE;
13285  }
13286 
13287  /* if there is no space for linear variables, then stop */
13288  if( linvarssize == 0 )
13289  break;
13290 
13291  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
13292  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
13293  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
13294  for( i = 0; i < polynomialdata->nmonomials; ++i )
13295  {
13296  monomial = polynomialdata->monomials[i];
13297  assert(monomial != NULL);
13298  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
13299  continue;
13300  for( j = 0; j < monomial->nfactors; ++j )
13301  {
13302  assert(monomial->childidxs[j] >= 0);
13303  assert(monomial->childidxs[j] < (*node)->nchildren);
13304  childused[monomial->childidxs[j]] = TRUE;
13305  }
13306  }
13307 
13308  /* move linear monomials out of polynomial */
13309  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
13310  {
13311  monomial = polynomialdata->monomials[i];
13312  assert(monomial != NULL);
13313 
13314  /* sort out constants */
13315  if( monomial->nfactors == 0 )
13316  {
13317  if( monomial->coef != 0.0 )
13318  {
13319  *constant += monomial->coef;
13320  havechange = TRUE;
13321  }
13322  continue;
13323  }
13324 
13325  if( monomial->nfactors != 1 )
13326  continue;
13327  if( monomial->exponents[0] != 1.0 )
13328  continue;
13329  childidx = monomial->childidxs[0];
13330  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
13331  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
13332  continue;
13333  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
13334  continue;
13335 
13336  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
13337 
13338  /* put variable into linear part */
13339  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
13340  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
13341  ++*nlinvars;
13342 
13343  monomial->coef = 0.0;
13344  monomial->nfactors = 0;
13345  polynomialdata->sorted = FALSE;
13346 
13347  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
13348  (*node)->children[childidx] = NULL;
13349 
13350  havechange = TRUE;
13351  }
13352 
13353  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
13354 
13355  if( *nlinvars > 0 )
13356  {
13357  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
13358  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
13360  }
13361 
13362  if( (*node)->nchildren == 0 )
13363  {
13364  assert(polynomialdata->nmonomials == 0);
13365  assert(polynomialdata->constant == 0.0);
13366  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13367  havechange = TRUE;
13368  break;
13369  }
13370 
13371  break;
13372  }
13373 
13374  default: ;
13375  } /*lint !e788*/
13376 
13377  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
13378 
13379  if( orignode != NULL )
13380  {
13381  /* if node was duplicated, we need to forget about original or duplicate */
13382  if( !havechange )
13383  {
13384  /* if nothing has changed, then forget about duplicate */
13385  assert(*constant == 0.0);
13386  assert(*nlinvars == 0);
13387  assert(*node != NULL);
13388  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13389  *node = orignode;
13390  }
13391  else
13392  {
13393  /* if something changed, then release original node */
13394  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
13395  }
13396  }
13397  else if( havechange && *node != NULL )
13398  {
13399  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
13400  (*node)->value = SCIP_INVALID;
13401  (*node)->simplified = FALSE;
13402  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
13403  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
13404  exprgraph->needvarboundprop = TRUE;
13405  }
13406 
13407  return SCIP_OKAY;
13408 }
13409 
13410 /** moves parents from a one node to another node
13411  * in other words, replaces the child srcnode by targetnode in all parents of srcnode
13412  * srcnode may be freed, if not captured
13413  * it is assumes that targetnode represents the same expression as srcnode
13414  */
13416  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13417  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
13418  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
13419  )
13420 {
13421  assert(exprgraph != NULL);
13422  assert(srcnode != NULL);
13423  assert(*srcnode != NULL);
13424  assert(targetnode != NULL);
13425 
13426  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
13427  {
13428  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
13429  {
13430  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
13431  }
13432  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
13433  }
13434  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
13435 
13436  return SCIP_OKAY;
13437 }
13438 
13439 /** releases node, i.e., decreases number of uses
13440  * node is freed if no parents and no other uses
13441  * children are recursively released if they have no other parents
13442  * nodes that are removed are also freed
13443  * if node correspond to a variable, then the variable is removed from the expression graph
13444  * similar for constants
13445  */
13447  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13448  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
13449  )
13450 {
13451  int i;
13452 
13453  assert(exprgraph != NULL);
13454  assert(node != NULL);
13455  assert(*node != NULL);
13456  assert((*node)->depth >= 0); /* node should be in graph */
13457  assert((*node)->pos >= 0); /* node should be in graph */
13458  assert((*node)->depth < exprgraph->depth);
13459  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
13460  assert((*node)->nuses >= 1);
13461  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
13462 
13463  SCIPdebugMessage("release node %p\n", (void*)*node);
13464 
13465  --(*node)->nuses;
13466 
13467  /* do nothing if node still has parents or is still in use */
13468  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
13469  {
13470  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);
13471  *node = NULL;
13472  return SCIP_OKAY;
13473  }
13474 
13475  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
13476 
13477  /* notify children about removal of its parent
13478  * they are also freed, if possible */
13479  for( i = 0; i < (*node)->nchildren; ++i )
13480  {
13481  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13482  (*node)->children[i] = NULL;
13483  }
13484 
13485  if( (*node)->op == SCIP_EXPR_VARIDX )
13486  {
13487  assert((*node)->depth == 0);
13488  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
13489  }
13490  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
13491  {
13492  int constidx;
13493 
13494  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
13495  assert(constidx >= 0);
13496  assert(constidx < exprgraph->nconsts);
13497  assert(exprgraph->constnodes[constidx] == *node);
13498 
13499  /* move last constant to position constidx */
13500  if( constidx < exprgraph->nconsts-1 )
13501  {
13502  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
13503  exprgraph->constssorted = (exprgraph->nconsts <= 2);
13504  }
13505  --exprgraph->nconsts;
13506  }
13507  else
13508  {
13509  /* only variables and constants are allowed at depth 0 */
13510  assert((*node)->depth > 0);
13511  }
13512 
13513  /* remove node from nodes array in expression graph */
13514  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
13515  {
13516  /* move last node at depth of *node to position of *node */
13517  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
13518  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
13519  }
13520  --exprgraph->nnodes[(*node)->depth];
13521 
13522  /* node is now not in graph anymore */
13523  (*node)->depth = -1;
13524  (*node)->pos = -1;
13525 
13526  /* free node */
13527  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
13528 
13529  *node = NULL;
13530 
13531  return SCIP_OKAY;
13532 }
13533 
13534 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
13535 /** frees a node of an expression graph */
13537  BMS_BLKMEM* blkmem, /**< block memory */
13538  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
13539  )
13540 {
13541  assert(blkmem != NULL);
13542  assert( node != NULL);
13543  assert(*node != NULL);
13544  assert((*node)->depth == -1); /* node should not be in graph anymore */
13545  assert((*node)->pos == -1); /* node should not be in graph anymore */
13546  assert((*node)->nuses == 0); /* node should not be in use */
13547 
13548  /* free operator data, if needed */
13549  if( exprOpTable[(*node)->op].freedata != NULL )
13550  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
13551 
13552  /* free arrays of children and parent nodes */
13553  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
13554  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
13555 
13556  /* free node struct */
13557  BMSfreeBlockMemory(blkmem, node);
13558 }
13559 
13560 /** enables a node and recursively all its children in an expression graph */
13562  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13563  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
13564  )
13565 {
13566  int i;
13567 
13568  assert(exprgraph != NULL);
13569  assert(node != NULL);
13570  assert(node->depth >= 0);
13571  assert(node->pos >= 0);
13572 
13573  if( node->enabled )
13574  return;
13575 
13576  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
13577 
13578  node->enabled = TRUE;
13579  for( i = 0; i < node->nchildren; ++i )
13580  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
13581 
13582  /* make sure bounds are updated in next bound propagation round */
13584  exprgraph->needvarboundprop = TRUE;
13585 }
13586 
13587 /** disables a node and recursively all children which have no enabled parents in an expression graph */
13589  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13590  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
13591  )
13592 {
13593  int i;
13594 
13595  assert(exprgraph != NULL);
13596  assert(node != NULL);
13597  assert(node->depth >= 0);
13598  assert(node->pos >= 0);
13599 
13600  if( !node->enabled )
13601  return;
13602 
13603  /* if all parents of node are disabled, then also node can be disabled */
13604  node->enabled = FALSE;
13605  for( i = 0; i < node->nparents; ++i )
13606  if( node->parents[i]->enabled )
13607  {
13608  node->enabled = TRUE;
13609  return;
13610  }
13611 
13612  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
13613 
13614  for( i = 0; i < node->nchildren; ++i )
13615  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
13616 }
13617 
13618 /** returns whether the node has siblings in the expression graph */
13620  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13621  )
13622 {
13623  int p;
13624 
13625  assert(node != NULL);
13626 
13627  for( p = 0; p < node->nparents; ++p )
13628  if( node->parents[p]->nchildren > 1 )
13629  return TRUE;
13630 
13631  return FALSE;
13632 }
13633 
13634 /** returns whether all children of an expression graph node are variable nodes
13635  * gives TRUE for nodes without children
13636  */
13638  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13639  )
13640 {
13641  int i;
13642 
13643  assert(node != NULL);
13644 
13645  for( i = 0; i < node->nchildren; ++i )
13646  if( node->children[i]->op != SCIP_EXPR_VARIDX )
13647  return FALSE;
13648 
13649  return TRUE;
13650 }
13651 
13652 /** returns whether the node has an ancestor which has a nonlinear expression operand */
13654  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13655  )
13656 {
13657  int p;
13658 
13659  for( p = 0; p < node->nparents; ++p )
13660  {
13661  assert(node->parents[p]->depth > node->depth);
13662  switch( node->parents[p]->op )
13663  {
13664  case SCIP_EXPR_PLUS:
13665  case SCIP_EXPR_MINUS:
13666  case SCIP_EXPR_SUM:
13667  case SCIP_EXPR_LINEAR:
13669  return TRUE;
13670  break;
13671 
13672 #ifndef NDEBUG
13673  case SCIP_EXPR_VARIDX:
13674  case SCIP_EXPR_CONST:
13675  case SCIP_EXPR_PARAM:
13676  assert(0); /* these expressions cannot have children */
13677  break;
13678 #endif
13679 
13680  default:
13681  /* parent has nonlinear expression operand */
13682  return TRUE;
13683  }/*lint !e788*/
13684  }
13685 
13686  return FALSE;
13687 }
13688 
13689 /** prints an expression graph node */
13691  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13692  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
13693  FILE* file /**< file to print to, or NULL for stdout */
13694  )
13695 {
13696  assert(node != NULL);
13697 
13698  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
13699 }
13700 
13701 /** tightens the bounds in a node of the graph
13702  * preparation for reverse propagation
13703  * sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff
13704  */
13706  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13707  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
13708  SCIP_INTERVAL nodebounds, /**< new bounds for node */
13709  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) */
13710  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
13711  )
13712 {
13713  assert(exprgraph != NULL);
13714  assert(node != NULL);
13715  assert(node->depth >= 0);
13716  assert(node->pos >= 0);
13717  assert(!SCIPintervalIsEmpty(nodebounds));
13718  assert(cutoff != NULL);
13719 
13720  *cutoff = FALSE;
13721 
13722  /* if node is disabled, then ignore new bounds */
13723  if( !node->enabled )
13724  {
13725  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
13726  return;
13727  }
13728 
13729  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
13730  (void*)node, node->depth, node->pos,
13731  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
13732 
13733  /* bounds in node should be valid */
13735 
13736  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
13737  {
13738  *cutoff = TRUE;
13739  SCIPdebugPrintf(" -> cutoff\n");
13740  return;
13741  }
13742 
13743  /* if minstrength is negative, always mark that node has recently tightened bounds,
13744  * if bounds are considerably improved or tightening leads to an empty interval,
13745  * mark that node has recently tightened bounds
13746  * if bounds are only slightly improved, set the status to tightened by parent,
13747  * so next propagateVarBound round will reset the bounds
13748  */
13749  if( minstrength < 0.0 )
13751  else if(
13752  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
13753  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
13755  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
13757 
13758  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
13759  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
13760 }
13761 
13762 /** ensures that bounds and curvature information in a node is uptodate
13763  * assumes that bounds and curvature in children are uptodate
13764  */
13766  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13767  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
13768  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
13769  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
13770  )
13771 {
13772  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13773  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13774  SCIP_INTERVAL* childbounds;
13775  SCIP_EXPRCURV* childcurv;
13776  int i;
13777 
13778  assert(node != NULL);
13779  assert(node->depth >= 0); /* node should be in graph */
13780  assert(node->pos >= 0); /* node should be in graph */
13781  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13782 
13783  if( node->depth == 0 )
13784  {
13785  /* we cannot update bound tightenings in variable nodes here */
13786  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
13787  return SCIP_OKAY;
13788  }
13789 
13790  assert(node->op != SCIP_EXPR_VARIDX);
13791  assert(node->op != SCIP_EXPR_PARAM);
13792 
13793  /* if many children, get large enough memory to store children bounds */
13795  {
13796  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
13797  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, node->nchildren) );
13798  }
13799  else
13800  {
13801  childbounds = childboundsstatic;
13802  childcurv = childcurvstatic;
13803  }
13804 
13805  /* assemble bounds and curvature of children */
13806  for( i = 0; i < node->nchildren; ++i )
13807  {
13808  /* child should have valid and non-empty bounds */
13810  assert(!SCIPintervalIsEmpty(node->children[i]->bounds));
13811  /* nodes at depth 0 are always linear */
13812  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
13813 
13814  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
13815  childcurv[i] = node->children[i]->curv; /*lint !e644*/
13816  }
13817 
13818  /* if we do not have valid bounds, then update
13819  * code below is copied from exprgraphNodeUpdateBounds */
13821  {
13822  SCIP_INTERVAL newbounds;
13823 
13824  /* calling interval evaluation function for this operand */
13825  assert( exprOpTable[node->op].inteval != NULL );
13826  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
13827 
13828  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
13829  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
13830  *
13831  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
13832  *
13833  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
13834  */
13835  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
13837  {
13838  for( i = 0; i < node->nparents; ++i )
13840 
13841  node->bounds = newbounds;
13842  }
13843  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
13844  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
13845  {
13846  for( i = 0; i < node->nparents; ++i )
13848 
13849  node->bounds = newbounds;
13850  }
13851  else
13852  {
13853  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
13854  }
13855 
13856  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);
13857 
13858  /* node now has valid bounds */
13860  }
13861 
13862  /* update curvature */
13863  if( SCIPintervalIsEmpty(node->bounds) )
13864  {
13865  node->curv = SCIP_EXPRCURV_LINEAR;
13866 
13867  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
13868  }
13869  else
13870  {
13871  SCIP_CALL( exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv) );
13872 
13873  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
13874  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
13875  * SCIPdebugPrintf("\n");
13876  */
13877  }
13878 
13879  /* free memory, if allocated before */
13880  if( childbounds != childboundsstatic )
13881  {
13882  BMSfreeMemoryArray(&childbounds);
13883  BMSfreeMemoryArray(&childcurv);
13884  }
13885 
13886  return SCIP_OKAY;
13887 }
13888 
13889 /**@} */
13890 
13891 /**@name Expression graph methods */
13892 /**@{ */
13893 
13894 /* In debug mode, the following methods are implemented as function calls to ensure
13895  * type validity.
13896  * In optimized mode, the methods are implemented as defines to improve performance.
13897  * However, we want to have them in the library anyways, so we have to undef the defines.
13898  */
13899 
13900 #undef SCIPexprgraphGetDepth
13901 #undef SCIPexprgraphGetNNodes
13902 #undef SCIPexprgraphGetNodes
13903 #undef SCIPexprgraphGetNVars
13904 #undef SCIPexprgraphGetVars
13905 #undef SCIPexprgraphGetVarNodes
13906 #undef SCIPexprgraphSetVarNodeValue
13907 #undef SCIPexprgraphSetVarsBounds
13908 #undef SCIPexprgraphSetVarBounds
13909 #undef SCIPexprgraphSetVarNodeBounds
13910 #undef SCIPexprgraphSetVarNodeLb
13911 #undef SCIPexprgraphSetVarNodeUb
13912 #undef SCIPexprgraphGetVarsBounds
13913 
13914 /** get current maximal depth of expression graph */
13916  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
13917  )
13918 {
13919  assert(exprgraph != NULL);
13920 
13921  return exprgraph->depth;
13922 }
13923 
13924 /** gets array with number of nodes at each depth of expression graph */
13926  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
13927  )
13928 {
13929  assert(exprgraph != NULL);
13930 
13931  return exprgraph->nnodes;
13932 }
13933 
13934 /** gets nodes of expression graph, one array per depth */
13936  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
13937  )
13938 {
13939  assert(exprgraph != NULL);
13940 
13941  return exprgraph->nodes;
13942 }
13943 
13944 /** gets number of variables in expression graph */
13946  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
13947  )
13948 {
13949  assert(exprgraph != NULL);
13950 
13951  return exprgraph->nvars;
13952 }
13953 
13954 /** gets array of variables in expression graph */
13956  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
13957  )
13958 {
13959  assert(exprgraph != NULL);
13960 
13961  return exprgraph->vars;
13962 }
13963 
13964 /** gets array of expression graph nodes corresponding to variables */
13966  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
13967  )
13968 {
13969  assert(exprgraph != NULL);
13970 
13971  return exprgraph->varnodes;
13972 }
13973 
13974 /** sets value for a single variable given as expression graph node */
13976  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
13977  SCIP_Real value /**< new value for variable */
13978  )
13979 {
13980  assert(varnode != NULL);
13981  assert(varnode->op == SCIP_EXPR_VARIDX);
13982 
13983  varnode->value = value;
13984 }
13985 
13986 /** sets bounds for variables */
13988  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13989  SCIP_INTERVAL* varbounds /**< new bounds for variables */
13990  )
13991 {
13992  assert(exprgraph != NULL);
13993  assert(varbounds != NULL || exprgraph->nvars == 0);
13994 
13995  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
13996 }
13997 
13998 /** sets bounds for a single variable */
14000  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14001  void* var, /**< variable */
14002  SCIP_INTERVAL varbounds /**< new bounds of variable */
14003  )
14004 {
14005  int pos;
14006 
14007  assert(exprgraph != NULL);
14008  assert(var != NULL);
14009  assert(SCIPhashmapExists(exprgraph->varidxs, var));
14010 
14011  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
14012  assert(pos < exprgraph->nvars);
14013  assert(exprgraph->vars[pos] == var);
14014 
14015  exprgraph->varbounds[pos] = varbounds;
14016 }
14017 
14018 /** sets bounds for a single variable given as expression graph node */
14020  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14021  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14022  SCIP_INTERVAL varbounds /**< new bounds of variable */
14023  )
14024 {
14025  int pos;
14026 
14027  assert(exprgraph != NULL);
14028  assert(varnode != NULL);
14029 
14030  pos = varnode->data.intval;
14031  assert(pos >= 0);
14032  assert(pos < exprgraph->nvars);
14033  assert(exprgraph->varnodes[pos] == varnode);
14034 
14035  exprgraph->varbounds[pos] = varbounds;
14036 }
14037 
14038 /** sets lower bound for a single variable given as expression graph node */
14040  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14041  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14042  SCIP_Real lb /**< new lower bound for variable */
14043  )
14044 {
14045  int pos;
14046 
14047  assert(exprgraph != NULL);
14048  assert(varnode != NULL);
14049 
14050  pos = varnode->data.intval;
14051  assert(pos >= 0);
14052  assert(pos < exprgraph->nvars);
14053  assert(exprgraph->varnodes[pos] == varnode);
14054 
14055  exprgraph->varbounds[pos].inf = lb;
14056 }
14057 
14058 /** sets upper bound for a single variable given as expression graph node */
14060  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14061  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14062  SCIP_Real ub /**< new upper bound for variable */
14063  )
14064 {
14065  int pos;
14066 
14067  assert(exprgraph != NULL);
14068  assert(varnode != NULL);
14069 
14070  pos = varnode->data.intval;
14071  assert(pos >= 0);
14072  assert(pos < exprgraph->nvars);
14073  assert(exprgraph->varnodes[pos] == varnode);
14074 
14075  exprgraph->varbounds[pos].sup = ub;
14076 }
14077 
14078 /** gets bounds that are stored for all variables */
14080  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14081  )
14082 {
14083  return exprgraph->varbounds;
14084 }
14085 
14086 /** creates an empty expression graph */
14088  BMS_BLKMEM* blkmem, /**< block memory */
14089  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
14090  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
14091  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
14092  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /** callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
14093  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /** callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
14094  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /** callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
14095  void* userdata /**< user data to pass to callback functions */
14096  )
14097 {
14098  assert(blkmem != NULL);
14099  assert(exprgraph != NULL);
14100 
14101  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
14102  BMSclearMemory(*exprgraph);
14103  (*exprgraph)->blkmem = blkmem;
14104 
14105  /* create nodes's arrays */
14106  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
14107  assert((*exprgraph)->depth >= 1);
14108 
14109  /* create var's arrays and hashmap */
14110  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
14111  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, SCIPcalcHashtableSize(5 * (*exprgraph)->varssize)) );
14112 
14113  /* empty array of constants is sorted */
14114  (*exprgraph)->constssorted = TRUE;
14115 
14116  /* store callback functions and user data */
14117  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
14118  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
14119  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
14120  (*exprgraph)->userdata = userdata;
14121 
14122  return SCIP_OKAY;
14123 }
14124 
14125 /** frees an expression graph */
14127  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
14128  )
14129 {
14130  BMS_BLKMEM* blkmem;
14131  int d;
14132 
14133  assert( exprgraph != NULL);
14134  assert(*exprgraph != NULL);
14135  assert((*exprgraph)->nvars == 0);
14136  assert((*exprgraph)->nconsts == 0);
14137 
14138  blkmem = (*exprgraph)->blkmem;
14139  assert(blkmem != NULL);
14140 
14141  /* free nodes arrays */
14142  for( d = 0; d < (*exprgraph)->depth; ++d )
14143  {
14144  assert((*exprgraph)->nnodes[d] == 0);
14145  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
14146  }
14147  assert((*exprgraph)->nodes != NULL);
14148  assert((*exprgraph)->nnodes != NULL);
14149  assert((*exprgraph)->nodessize != NULL);
14150  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
14151  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
14152  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
14153 
14154  /* free variables arrays and hashmap */
14155  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
14156  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
14157  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
14158  SCIPhashmapFree(&(*exprgraph)->varidxs);
14159 
14160  /* free constants array */
14161  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
14162 
14163  /* free graph struct */
14164  BMSfreeBlockMemory(blkmem, exprgraph);
14165 
14166  return SCIP_OKAY;
14167 }
14168 
14169 /** adds an expression graph node to an expression graph
14170  * expression graph assumes ownership of node
14171  * children are notified about new parent
14172  * depth will be chosen to be the maximum of mindepth and the depth of all children plus one
14173  */
14175  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14176  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
14177  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
14178  int nchildren, /**< number of children */
14179  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
14180  )
14181 {
14182  SCIP_Bool childvalsvalid;
14183  int depth;
14184  int i;
14185 
14186  assert(exprgraph != NULL);
14187  assert(node != NULL);
14188  assert(node->pos < 0); /* node should have no position in graph yet */
14189  assert(node->depth < 0); /* node should have no position in graph yet */
14190  assert(node->nchildren == 0); /* node should not have stored children yet */
14191  assert(node->children == NULL); /* node should not have stored children yet */
14192  assert(node->nparents == 0); /* node should not have parents stored yet */
14193  assert(children != NULL || nchildren == 0);
14194 
14195  /* choose depth as maximal depth of children + 1, and at least mindepth */
14196  depth = MAX(0, mindepth);
14197  for( i = 0; i < nchildren; ++i )
14198  {
14199  if( children[i]->depth >= depth ) /*lint !e613*/
14200  depth = children[i]->depth + 1; /*lint !e613*/
14201  }
14202 
14203  /* ensure that expression graph is deep enough */
14204  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
14205  assert(exprgraph->depth > depth);
14206 
14207  /* ensure enough space for nodes at depth depth */
14208  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
14209 
14210  /* add node to graph */
14211  node->depth = depth;
14212  node->pos = exprgraph->nnodes[depth];
14213  exprgraph->nodes[depth][node->pos] = node;
14214  ++exprgraph->nnodes[depth];
14215 
14216  /* add as parent to children
14217  * and check if children has valid values */
14218  childvalsvalid = TRUE;
14219  for( i = 0; i < nchildren; ++i )
14220  {
14221  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
14222  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
14223  }
14224  /* store children */
14225  if( nchildren > 0 )
14226  {
14227  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
14228  node->nchildren = nchildren;
14229  }
14230 
14231  if( node->op == SCIP_EXPR_CONST )
14232  {
14233  /* set bounds to constant value of node */
14235  SCIPintervalSet(&node->bounds, node->data.dbl);
14236  }
14237  else
14238  {
14239  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
14242  exprgraph->needvarboundprop = TRUE;
14243  }
14244 
14245  /* if not a variable, set value of node according to values of children (if all have valid values) */
14246  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
14247  {
14248  SCIP_CALL( exprgraphNodeEval(node, NULL) );
14249  }
14250 
14251  return SCIP_OKAY;
14252 }
14253 
14254 /** adds variables to an expression graph, if not existing yet
14255  * also already existing nodes are enabled
14256  */
14258  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14259  int nvars, /**< number of variables to add */
14260  void** vars, /**< variables to add */
14261  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
14262  )
14263 {
14264  SCIP_EXPRGRAPHNODE* node;
14265  SCIP_EXPROPDATA opdata;
14266  int i;
14267 
14268  assert(exprgraph != NULL);
14269  assert(exprgraph->depth >= 1);
14270  assert(vars != NULL || nvars == 0);
14271 
14272  /* 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 */
14273  if( exprgraph->nvars == 0 )
14274  {
14275  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
14276  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
14277  }
14278 
14279  for( i = 0; i < nvars; ++i )
14280  {
14281  /* skip variables that exist already */
14282  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
14283  {
14284  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
14285  assert(node != NULL);
14286 
14287  /* enable node */
14288  node->enabled = TRUE;
14289 
14290  if( varnodes != NULL )
14291  varnodes[i] = node;
14292 
14293  continue;
14294  }
14295 
14296  /* create new variable expression */
14297  opdata.intval = exprgraph->nvars;
14298  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
14299 
14300  /* add expression node to expression graph at depth 0 */
14301  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
14302 
14303  /* add variable node to vars arrays and hashmap */
14304  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
14305  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
14306  exprgraph->varnodes[exprgraph->nvars] = node;
14307  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
14308  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[i], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
14309  ++exprgraph->nvars;
14310 
14311  if( varnodes != NULL )
14312  varnodes[i] = node;
14313 
14314  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
14315 
14316  /* call callback method, if set */
14317  if( exprgraph->exprgraphvaradded != NULL )
14318  {
14319  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
14320  }
14321  }
14322 
14323  return SCIP_OKAY;
14324 }
14325 
14326 /** adds a constant to an expression graph, if not existing yet
14327  * also already existing nodes are enabled
14328  */
14330  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14331  SCIP_Real constant, /**< constant to add */
14332  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
14333  )
14334 {
14335  SCIP_EXPROPDATA opdata;
14336 
14337  assert(exprgraph != NULL);
14338  assert(constnode != NULL);
14339 
14340  /* check if there is already an expression for this constant */
14341  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
14342  {
14343  assert(*constnode != NULL);
14344  assert((*constnode)->op == SCIP_EXPR_CONST);
14345  assert((*constnode)->data.dbl == constant); /*lint !e777*/
14346  (*constnode)->enabled = TRUE;
14347  return SCIP_OKAY;
14348  }
14349 
14350  /* create new node for constant */
14351  opdata.dbl = constant;
14352  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
14353 
14354  /* add node to expression graph at depth 0 */
14355  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
14356  assert((*constnode)->depth == 0);
14357  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
14358 
14359  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
14360  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
14361  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
14362  ++exprgraph->nconsts;
14363  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
14364 
14365  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
14366 
14367  return SCIP_OKAY;
14368 }
14369 
14370 /** adds sum of expression trees into expression graph
14371  * node will also be captured
14372  */
14374  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14375  int nexprtrees, /**< number of expression trees to add */
14376  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
14377  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
14378  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
14379  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) */
14380  )
14381 {
14382  SCIP_Bool allone;
14383 
14384  assert(exprgraph != NULL);
14385  assert(nexprtrees > 0);
14386  assert(exprtrees != NULL);
14387  assert(rootnode != NULL);
14388  assert(rootnodeisnew != NULL);
14389 
14390  *rootnode = NULL;
14391 
14392  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
14393  {
14394  assert(exprtrees[0] != NULL);
14395  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
14396 
14397  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, rootnode, rootnodeisnew) );
14398  }
14399  else
14400  {
14401  SCIP_EXPROP op;
14402  SCIP_EXPRGRAPHNODE** rootnodes;
14403  SCIP_Bool rootnodeisnew_;
14404  int i;
14405 
14406  *rootnodeisnew = TRUE;
14407  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
14408 
14409  allone = TRUE;
14410  for( i = 0; i < nexprtrees; ++i )
14411  {
14412  assert(exprtrees[i] != NULL);
14413  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
14414 
14415  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
14416  assert(rootnodes[i] != NULL);
14417  *rootnodeisnew &= rootnodeisnew_;
14418 
14419  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
14420  }
14421 
14422  /* decide which operand we want to use for the root node */
14423  if( coefs == NULL || allone )
14424  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
14425  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
14426  op = SCIP_EXPR_MINUS;
14427  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
14428  {
14429  SCIP_EXPRGRAPHNODE* tmp;
14430 
14431  tmp = rootnodes[0];
14432  rootnodes[0] = rootnodes[1];
14433  rootnodes[1] = tmp;
14434  op = SCIP_EXPR_MINUS;
14435  }
14436  else
14437  op = SCIP_EXPR_LINEAR;
14438 
14439  if( op != SCIP_EXPR_LINEAR )
14440  {
14441  SCIP_EXPROPDATA data;
14442  data.data = NULL;
14443 
14444  if( !*rootnodeisnew )
14445  {
14446  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
14447  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
14448  }
14449 
14450  if( *rootnode == NULL )
14451  {
14452  /* create new node for sum of rootnodes and add to exprgraph */
14453  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
14454  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
14455  *rootnodeisnew = TRUE;
14456  }
14457  else
14458  {
14459  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
14460  *rootnodeisnew = FALSE;
14461  }
14462  }
14463  else
14464  {
14465  SCIP_EXPROPDATA data;
14466  SCIP_Real* lindata;
14467 
14468  assert(op == SCIP_EXPR_LINEAR);
14469 
14470  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
14471  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
14472  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
14473  lindata[nexprtrees] = 0.0;
14474  data.data = lindata;
14475 
14476  if( !*rootnodeisnew )
14477  {
14478  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
14479  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
14480  }
14481 
14482  if( *rootnode == NULL )
14483  {
14484  /* create new node for linear combination of rootnodes and add to exprgraph */
14485  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
14486  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
14487  *rootnodeisnew = TRUE;
14488  }
14489  else
14490  {
14491  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
14492  *rootnodeisnew = FALSE;
14493  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
14494  }
14495  }
14496 
14497  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
14498  }
14499  assert(*rootnode != NULL);
14500 
14501  SCIPexprgraphCaptureNode(*rootnode);
14502 
14503  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
14504  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
14505 
14506  return SCIP_OKAY;
14507 }
14508 
14509 /** replaces variable in expression graph by a linear sum of variables
14510  * variables will be added if not in the graph yet
14511  */
14513  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14514  void* var, /**< variable to replace */
14515  int ncoefs, /**< number of coefficients in linear term */
14516  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
14517  void** vars, /**< variables in linear term */
14518  SCIP_Real constant /**< constant offset */
14519  )
14520 {
14521  SCIP_EXPRGRAPHNODE* varnode;
14522  SCIP_Real* lindata;
14523  int varidx;
14524  int i;
14525 
14526  assert(exprgraph != NULL);
14527  assert(var != NULL);
14528  assert(SCIPhashmapExists(exprgraph->varidxs, var));
14529  assert(coefs != NULL || ncoefs == 0);
14530  assert(vars != NULL || ncoefs == 0);
14531 
14532  varidx = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
14533  assert(varidx < exprgraph->nvars);
14534  assert(exprgraph->vars[varidx] == var);
14535  varnode = exprgraph->varnodes[varidx];
14536  assert(varnode != NULL);
14537  assert(varnode->data.intval == varidx);
14538 
14539  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
14540  {
14541  /* variable is replaced by constant or variable */
14542  SCIP_EXPRGRAPHNODE* node;
14543 
14544  /* check if there is already a node for this constant or variable */
14545  node = NULL;
14546  if( ncoefs == 0 )
14547  {
14548  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
14549  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
14550  }
14551  else
14552  {
14553  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
14554  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
14555  }
14556 
14557  if( node != NULL )
14558  {
14559  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
14560 
14561  /* tell parents of varnode to replace child varnode by node, this may free varnode */
14562  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
14563 
14564  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
14565  if( varnode != NULL )
14566  {
14567  assert(varnode->nuses > 0);
14568  assert(varnode->nparents == 0);
14569 
14570  /* remove variable (but don't free it's node) from graph */
14571  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
14572 
14573  /* move varnode up to depth 1 */
14574  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
14575 
14576  /* turn into EXPR_SUM expression */
14577  varnode->op = SCIP_EXPR_SUM;
14578  varnode->data.data = NULL;
14579  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
14580  varnode->children[0] = node;
14581  varnode->nchildren = 1;
14582  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
14583 
14584  varnode->value = node->value;
14585  varnode->bounds = node->bounds;
14587  }
14588  }
14589  else if( ncoefs == 0 )
14590  {
14591  /* turn node into EXPR_CONST node */
14592 
14593  /* remove variable (but don't free it's node) from graph */
14594  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
14595 
14596  /* convert into EXPR_CONST node */
14597  varnode->op = SCIP_EXPR_CONST;
14598  varnode->data.dbl = constant;
14599 
14600  varnode->value = constant;
14601  SCIPintervalSet(&varnode->bounds, constant);
14603 
14604  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
14605  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
14606  exprgraph->constnodes[exprgraph->nconsts] = varnode;
14607  ++exprgraph->nconsts;
14608  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
14609  }
14610  else
14611  {
14612  /* turn node into EXPR_VARIDX node for new variable */
14613 
14614  /* remove variable (but don't free it's node) from graph */
14615  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
14616 
14617  varnode->data.intval = exprgraph->nvars;
14618 
14619  /* add variable node to vars arrays and hashmap */
14620  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
14621  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
14622  exprgraph->varnodes[exprgraph->nvars] = varnode;
14623  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
14624  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[0], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
14625  ++exprgraph->nvars;
14626 
14627  /* call callback method, if set */
14628  if( exprgraph->exprgraphvaradded != NULL )
14629  {
14630  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
14631  }
14632  }
14633 
14634  /* mark varnode and its parents as not simplified */
14635  if( varnode != NULL )
14636  {
14637  varnode->simplified = FALSE;
14638  for( i = 0; i < varnode->nparents; ++i )
14639  varnode->parents[i]->simplified = FALSE;
14640  }
14641 
14642  return SCIP_OKAY;
14643  }
14644 
14645  /* turn varnode into EXPR_LINEAR */
14646 
14647  /* remove variable (but don't free it's node) from graph */
14648  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
14649 
14650  /* move varnode up to depth 1 */
14651  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
14652 
14653  /* convert into EXPR_LINEAR node */
14654  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
14655  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
14656  lindata[ncoefs] = constant;
14657  varnode->data.data = (void*)lindata;
14658  varnode->op = SCIP_EXPR_LINEAR;
14659 
14660  /* add nodes corresponding to vars to expression graph, if not existing yet */
14661  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
14662  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
14663  varnode->nchildren = ncoefs;
14664 
14665  /* notify vars about new parent varnode */
14666  for( i = 0; i < ncoefs; ++i )
14667  {
14668  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
14669  }
14670 
14671  /* set value and bounds to invalid, curvature can remain (still linear) */
14672  varnode->value = SCIP_INVALID;
14674 
14675  /* mark varnode and its parents as not simplified */
14676  varnode->simplified = FALSE;
14677  for( i = 0; i < varnode->nparents; ++i )
14678  varnode->parents[i]->simplified = FALSE;
14679 
14680  return SCIP_OKAY;
14681 }
14682 
14683 /** finds expression graph node corresponding to a variable */
14685  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14686  void* var, /**< variable to search for */
14687  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
14688  )
14689 {
14690  int pos;
14691 
14692  assert(exprgraph != NULL);
14693  assert(var != NULL);
14694  assert(varnode != NULL);
14695 
14696  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
14697  {
14698  *varnode = NULL;
14699  return FALSE;
14700  }
14701 
14702  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
14703  assert(pos < exprgraph->nvars);
14704 
14705  *varnode = exprgraph->varnodes[pos];
14706  assert(*varnode != NULL);
14707  assert((*varnode)->op == SCIP_EXPR_VARIDX);
14708 
14709  return TRUE;
14710 }
14711 
14712 /** finds expression graph node corresponding to a constant */
14714  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14715  SCIP_Real constant, /**< constant to search for */
14716  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
14717  )
14718 {
14719  int left;
14720  int right;
14721  int middle;
14722 
14723  assert(exprgraph != NULL);
14724  assert(constnode != NULL);
14725  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
14726 
14727  exprgraphSortConstNodes(exprgraph);
14728  assert(exprgraph->constssorted);
14729 
14730  /* find node using binary search */
14731  left = 0;
14732  right = exprgraph->nconsts-1;
14733  *constnode = NULL;
14734 
14735  while( left <= right )
14736  {
14737  middle = (left+right)/2;
14738  assert(0 <= middle && middle < exprgraph->nconsts);
14739 
14740  if( constant < exprgraph->constnodes[middle]->data.dbl )
14741  right = middle - 1;
14742  else if( constant > exprgraph->constnodes[middle]->data.dbl )
14743  left = middle + 1;
14744  else
14745  {
14746  *constnode = exprgraph->constnodes[middle];
14747  break;
14748  }
14749  }
14750  assert(left == right+1 || *constnode != NULL);
14751  if( left == right+1 )
14752  return FALSE;
14753 
14754  assert((*constnode)->op == SCIP_EXPR_CONST);
14755  assert((*constnode)->data.dbl == constant); /*lint !e777*/
14756 
14757  return TRUE;
14758 }
14759 
14760 /** prints an expression graph in dot format */
14762  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14763  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14764  FILE* file, /**< file to print to, or NULL for stdout */
14765  const char** varnames /**< variable names, or NULL for generic names */
14766  )
14767 {
14768  int d;
14769  int i;
14770 
14771  assert(exprgraph != NULL);
14772 
14773  if( file == NULL )
14774  file = stdout;
14775 
14776  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
14777  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
14778 
14779  for( d = 0; d < exprgraph->depth; ++d )
14780  {
14781  if( exprgraph->nnodes[d] == 0 )
14782  continue;
14783 
14784  for( i = 0; i < exprgraph->nnodes[d]; ++i )
14785  {
14786  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
14787  }
14788  }
14789 
14790  /* tell dot that all nodes of depth 0 have the same rank */
14791  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
14792  for( i = 0; i < exprgraph->nnodes[0]; ++i )
14793  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
14794  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
14795 
14796  /* tell dot that all nodes without parent have the same rank */
14797  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
14798  for( d = 0; d < exprgraph->depth; ++d )
14799  for( i = 0; i < exprgraph->nnodes[d]; ++i )
14800  if( exprgraph->nodes[d][i]->nparents == 0 )
14801  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
14802  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
14803 
14804  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
14805 
14806  return SCIP_OKAY;
14807 }
14808 
14809 /** evaluates nodes of expression graph for given values of variables */
14811  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14812  SCIP_Real* varvals /**< values for variables */
14813  )
14814 {
14815  int d;
14816  int i;
14817 
14818  assert(exprgraph != NULL);
14819  assert(varvals != NULL || exprgraph->nvars == 0);
14820 
14821  for( d = 0; d < exprgraph->depth; ++d )
14822  for( i = 0; i < exprgraph->nnodes[d]; ++i )
14823  {
14824  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
14825  }
14826 
14827  return SCIP_OKAY;
14828 }
14829 
14830 /** propagates bound changes in variables forward through the expression graph */
14832  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14833  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14834  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
14835  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
14836  )
14837 {
14838  SCIP_EXPRGRAPHNODE* node;
14839  SCIP_Bool boundchanged;
14840  int d;
14841  int i;
14842 
14843  assert(exprgraph != NULL);
14844  assert(domainerror != NULL);
14845 
14846  *domainerror = FALSE;
14847 
14848  /* update bounds in varnodes of expression graph */
14849  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
14850 
14851  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
14852  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
14853  {
14854  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
14855  return SCIP_OKAY;
14856  }
14857 
14858  /* propagate bound changes, interrupt if we get to a node with empty bounds */
14859  for( d = 1; d < exprgraph->depth; ++d )
14860  {
14861  for( i = 0; i < exprgraph->nnodes[d]; ++i )
14862  {
14863  node = exprgraph->nodes[d][i];
14864  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
14865  if( SCIPintervalIsEmpty(node->bounds) )
14866  {
14867  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
14868  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
14869  *domainerror = TRUE;
14870  return SCIP_OKAY;
14871  }
14872  }
14873  }
14874 
14875  exprgraph->needvarboundprop = FALSE;
14876 
14877  return SCIP_OKAY;
14878 }
14879 
14880 /** propagates bound changes in nodes backward through the graph
14881  * new bounds are not stored in varbounds, but only in nodes corresponding to variables
14882  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed
14883  */
14885  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14886  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14887  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
14888  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14889  )
14890 {
14891  SCIP_EXPRGRAPHNODE* node;
14892  int d;
14893  int i;
14894 
14895  assert(exprgraph != NULL);
14896  assert(cutoff != NULL);
14897 
14898  *cutoff = FALSE;
14899 
14900  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
14901  {
14902  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
14903  {
14904  node = exprgraph->nodes[d][i];
14905  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
14906  }
14907  }
14908  if( *cutoff )
14909  return;
14910 }
14911 
14912 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
14913  * implies update of bounds in expression graph
14914  */
14916  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14917  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14918  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14919  )
14920 {
14921  SCIP_EXPRGRAPHNODE* node;
14922  SCIP_Bool boundchanged;
14923  int d;
14924  int i;
14925 
14926  assert(exprgraph != NULL);
14927 
14928  /* update bounds in varnodes of expression graph */
14929  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
14930 
14931 #ifndef NDEBUG
14932  for( i = 0; i < exprgraph->nnodes[0]; ++i )
14933  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
14934 #endif
14935 
14936  for( d = 1; d < exprgraph->depth; ++d )
14937  for( i = 0; i < exprgraph->nnodes[d]; ++i )
14938  {
14939  node = exprgraph->nodes[d][i];
14940  assert(node != NULL);
14941 
14942  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
14943 
14944  if( SCIPintervalIsEmpty(node->bounds) )
14945  {
14946  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
14947  return SCIP_OKAY;
14948  }
14949  }
14950 
14951  return SCIP_OKAY;
14952 }
14953 
14954 /** aims at simplifying an expression graph
14955  * 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))
14956  */
14958  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14959  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14960  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
14961  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
14962  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
14963  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
14964  )
14965 {
14966  SCIP_EXPRGRAPHNODE* node;
14967  SCIP_Bool havechangenode;
14968  SCIP_Bool allsimplified;
14969  int d;
14970  int i;
14971  int j;
14972 
14973 #ifndef NDEBUG
14974  SCIP_Real* testx;
14975  SCIP_HASHMAP* testvalidx;
14976  SCIP_Real* testvals;
14977  int testvalssize;
14978  int ntestvals;
14979  unsigned int seed;
14980 #endif
14981 
14982  assert(exprgraph != NULL);
14983  assert(eps >= 0.0);
14984  assert(havechange != NULL);
14985  assert(domainerror != NULL);
14986 
14987 #ifndef NDEBUG
14988  seed = 42;
14989  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
14990  testvals = NULL;
14991  ntestvals = 0;
14992  testvalssize = 0;
14993 
14994  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
14995  for( i = 0; i < exprgraph->nvars; ++i )
14996  testx[i] = SCIPgetRandomReal(-100.0, 100.0, &seed); /*lint !e644*/
14997  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
14998  for( d = 1; d < exprgraph->depth; ++d )
14999  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15000  {
15001  node = exprgraph->nodes[d][i];
15002  assert(node != NULL);
15003 
15004  /* 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 */
15005  if( node->nuses > 0 )
15006  {
15007  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
15008  SCIP_CALL( SCIPhashmapInsert(testvalidx, (void*)node, (void*)(size_t)ntestvals) );
15009  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
15010  ++ntestvals;
15011  }
15012  }
15013 #endif
15014 
15015 #ifdef SCIP_OUTPUT
15016  {
15017  FILE* file;
15018  file = fopen("exprgraph_beforesimplify.dot", "w");
15019  if( file != NULL )
15020  {
15021  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
15022  fclose(file);
15023  }
15024  }
15025 #endif
15026 
15027  *havechange = FALSE; /* we have not changed any node yet */
15028  *domainerror = FALSE; /* no domain errors encountered so far */
15029  allsimplified = TRUE; /* all nodes we looked at are simplified */
15030 
15031  /* call node simplifier from bottom up
15032  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
15033  */
15034  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
15035  {
15036  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15037  {
15038  node = exprgraph->nodes[d][i];
15039  assert(node != NULL);
15040 
15041  havechangenode = FALSE; /* node did not change yet */
15042 
15043  if( node->op != SCIP_EXPR_CONST )
15044  {
15045  /* skip nodes that are already simplified */
15046  if( node->simplified )
15047  continue;
15048 
15049  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
15050 
15051  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
15052  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
15053  assert(node->simplified == TRUE);
15054  *havechange |= havechangenode;
15055  }
15056 
15057  /* if node was or has been converted into constant, may move to depth 0 */
15058  if( node->op == SCIP_EXPR_CONST )
15059  {
15060  SCIP_EXPRGRAPHNODE* constnode;
15061 
15062  if( node->value != node->value ) /*lint !e777*/
15063  {
15064  SCIPdebugMessage("Expression graph simplify turned node into NaN.\n");
15065  *domainerror = TRUE;
15066  break;
15067  }
15068 
15069  /* check if there is already a node for this constant */
15070  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
15071  {
15072  assert(constnode->op == SCIP_EXPR_CONST);
15073  assert(constnode->data.dbl == node->value); /*lint !e777*/
15074 
15075  if( node->nparents > 0 )
15076  {
15077  /* move parents of this node to constnode, node may be freed if not in use */
15078  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
15079  /* node should have no parents anymore, so it should have been freed if not in use */
15080  assert(node == NULL || node->nuses > 0);
15081  havechangenode = TRUE;
15082 
15083  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
15084  if( node == NULL )
15085  {
15086  --i;
15087  continue;
15088  }
15089  }
15090  assert(node != NULL);
15091  assert(node->nuses > 0);
15092 
15093  if( constnode->nuses == 0 )
15094  {
15095  /* move node to depth 0, adding it to constnodes */
15096  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
15097 
15098  /* move parents of constnode to node, so constnode is freed */
15099  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
15100  assert(constnode == NULL);
15101  havechangenode = TRUE;
15102 
15103  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
15104  --i;
15105  continue;
15106  }
15107  }
15108  else
15109  {
15110  /* move to depth 0, adding it to constnodes */
15111  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
15112 
15113  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
15114  --i;
15115  }
15116  }
15117 
15118  /* if there was a change, mark parents as not simplified */
15119  if( havechangenode )
15120  for( j = 0; j < node->nparents; ++j )
15121  node->parents[j]->simplified = FALSE;
15122  }
15123  } /*lint !e850*/
15124 
15125  /* if we did nothing, clean up and escape from here */
15126  if( allsimplified || *domainerror )
15127  goto EXPRGRAPHSIMPLIFY_CLEANUP;
15128 
15129  /* @todo find duplicate subexpressions in expression graph */
15130 
15131  /* unconvert polynomials into simpler expressions, where possible */
15132  for( d = 1; d < exprgraph->depth; ++d )
15133  {
15134  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15135  {
15136  node = exprgraph->nodes[d][i];
15137  assert(node != NULL);
15138 
15139  if( node->op != SCIP_EXPR_POLYNOMIAL )
15140  continue;
15141 
15142  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
15143 
15144  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
15145  {
15146  /* node is identity w.r.t only child
15147  * replace node as child of parents by child of node
15148  */
15149 
15150  for( j = 0; node != NULL && j < node->nparents; ++j )
15151  {
15152  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
15153  }
15154  /* node should have no parents anymore, so it should have been freed if not in use */
15155  assert(node == NULL || node->nuses > 0);
15156 
15157  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
15158  if( node == NULL )
15159  --i;
15160  }
15161  }
15162  } /*lint !e850*/
15163 
15164 #ifdef SCIP_OUTPUT
15165  {
15166  FILE* file;
15167  file = fopen("exprgraph_aftersimplify.dot", "w");
15168  if( file != NULL )
15169  {
15170  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
15171  fclose(file);
15172  }
15173  }
15174 #endif
15175 
15176 #ifndef NDEBUG
15177  for( d = 1; d < exprgraph->depth; ++d )
15178  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15179  {
15180  int idx;
15181  SCIP_Real testval_before;
15182  SCIP_Real testval_after;
15183 
15184  node = exprgraph->nodes[d][i];
15185  assert(node != NULL);
15186 
15187  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15188 
15189  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
15190  if( node->nuses > 0 )
15191  {
15192  assert(SCIPhashmapExists(testvalidx, (void*)node));
15193 
15194  idx = (int)(size_t)(void*)SCIPhashmapGetImage(testvalidx, (void*)node);
15195  assert(idx < ntestvals);
15196 
15197  testval_before = testvals[idx]; /*lint !e613*/
15198  testval_after = SCIPexprgraphGetNodeVal(node);
15199 
15200  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
15201  }
15202  }
15203 #endif
15204 
15205  EXPRGRAPHSIMPLIFY_CLEANUP:
15206 #ifndef NDEBUG
15207  BMSfreeMemoryArray(&testx);
15208  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
15209  SCIPhashmapFree(&testvalidx);
15210 #endif
15211 
15212  return SCIP_OKAY;
15213 }
15214 
15215 /** creates an expression tree from a given node in an expression graph */
15217  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15218  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
15219  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
15220  )
15221 {
15222  SCIP_EXPR* root;
15223  int nexprvars;
15224  int* varidx;
15225  int i;
15226 
15227  assert(exprgraph != NULL);
15228  assert(rootnode != NULL);
15229  assert(rootnode->depth >= 0);
15230  assert(rootnode->pos >= 0);
15231  assert(exprtree != NULL);
15232 
15233  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
15234  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
15235 
15236  /* initially, no variable appears in the expression tree */
15237  for( i = 0; i < exprgraph->nvars; ++i )
15238  varidx[i] = -1; /*lint !e644*/
15239  nexprvars = 0;
15240 
15241  /* create expression from the subgraph that has rootnode as root */
15242  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
15243 
15244  /* create expression tree for this expression */
15245  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
15246 
15247  /* copy variables into expression tree */
15248  if( nexprvars > 0 )
15249  {
15250  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
15251  for( i = 0; i < exprgraph->nvars; ++i )
15252  {
15253  assert(varidx[i] >= -1);
15254  assert(varidx[i] < nexprvars);
15255  if( varidx[i] >= 0 )
15256  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
15257  }
15258  }
15259 
15260  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
15261 
15262  return SCIP_OKAY;
15263 }
15264 
15265 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
15266  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
15267  */
15269  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15270  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
15271  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
15272  int* nexprtrees, /**< buffer to store number of expression trees */
15273  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
15274  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
15275  )
15276 {
15277  int ncomponents;
15278  int* childcomp;
15279  int* varcomp;
15280  int compnr;
15281  SCIP_Bool haveoverlap;
15282  int i;
15283  int j;
15284  int k;
15285 
15286  SCIP_EXPR** exprs;
15287  int nexprs;
15288  int* childmap;
15289  int* childmapinv;
15290  int* varidx;
15291  int nexprvars;
15292 
15293  assert(exprgraph != NULL);
15294  assert(node != NULL);
15295  assert(node->depth >= 0);
15296  assert(node->pos >= 0);
15297  assert(exprtreessize > 0);
15298  assert(nexprtrees != NULL);
15299  assert(exprtrees != NULL);
15300  assert(exprtreecoefs != NULL);
15301 
15302  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
15303  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
15304  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
15305  ( node->op != SCIP_EXPR_PLUS &&
15306  node->op != SCIP_EXPR_MINUS &&
15307  node->op != SCIP_EXPR_SUM &&
15308  node->op != SCIP_EXPR_LINEAR &&
15309  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
15310  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
15311  {
15312  *nexprtrees = 1;
15313  exprtreecoefs[0] = 1.0;
15314  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
15315 
15316  return SCIP_OKAY;
15317  }
15318 
15319  /* find components in node->children <-> variables graph */
15320  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
15321  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
15322  for( i = 0; i < exprgraph->nvars; ++i )
15323  varcomp[i] = -1; /*lint !e644*/
15324 
15325  haveoverlap = FALSE;
15326  for( i = 0; i < node->nchildren; ++i )
15327  {
15328  compnr = i;
15329  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
15330  assert(compnr >= 0);
15331  assert(compnr < node->nchildren);
15332  childcomp[i] = compnr;
15333 
15334  /* remember if component number was changed by CheckComponent */
15335  if( compnr != i )
15336  haveoverlap = TRUE;
15337  }
15338 
15339  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
15340 
15341  if( node->op == SCIP_EXPR_QUADRATIC )
15342  {
15343  /* merge components for products of children from different components */
15345 
15346  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
15347  assert(data != NULL);
15348 
15349  for( i = 0; i < data->nquadelems; ++i )
15350  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
15351  {
15352  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
15353  compnr = childcomp[data->quadelems[i].idx2];
15354  for( j = 0; j < node->nchildren; ++j )
15355  if( childcomp[j] == compnr )
15356  childcomp[j] = childcomp[data->quadelems[i].idx1];
15357  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
15358  haveoverlap = TRUE;
15359  }
15360  }
15361  else if( node->op == SCIP_EXPR_POLYNOMIAL )
15362  {
15363  /* merge components for monomials of children from different components */
15365 
15366  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
15367  assert(data != NULL);
15368 
15369  for( i = 0; i < data->nmonomials; ++i )
15370  for( j = 1; j < data->monomials[i]->nfactors; ++j )
15371  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
15372  {
15373  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
15374  compnr = childcomp[data->monomials[i]->childidxs[j]];
15375  for( k = 0; k < node->nchildren; ++k )
15376  if( childcomp[k] == compnr )
15377  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
15378  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
15379  haveoverlap = TRUE;
15380  }
15381  }
15382 
15383  if( haveoverlap )
15384  {
15385  /* some component numbers are unused, thus relabel and count final number of components */
15386  int* compmap;
15387 
15388  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
15389  for( i = 0; i < node->nchildren; ++i )
15390  compmap[i] = -1; /*lint !e644*/
15391 
15392  ncomponents = 0;
15393  for( i = 0; i < node->nchildren; ++i )
15394  {
15395  if( compmap[childcomp[i]] == -1 )
15396  compmap[childcomp[i]] = ncomponents++;
15397  childcomp[i] = compmap[childcomp[i]];
15398  }
15399 
15400  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
15401  }
15402  else
15403  {
15404  ncomponents = node->nchildren;
15405  }
15406 
15407  if( ncomponents == 1 )
15408  {
15409  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
15410  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
15411 
15412  *nexprtrees = 1;
15413  exprtreecoefs[0] = 1.0;
15414  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
15415 
15416  return SCIP_OKAY;
15417  }
15418 
15419  if( ncomponents > exprtreessize )
15420  {
15421  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
15422  for( i = 0; i < node->nchildren; ++i )
15423  if( childcomp[i] >= exprtreessize )
15424  childcomp[i] = exprtreessize-1;
15425  ncomponents = exprtreessize;
15426  }
15427 
15428  assert(ncomponents >= 2);
15429 
15430  /* setup expression trees for each component */
15431  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
15432  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
15433  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
15434  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
15435  for( i = 0; i < ncomponents; ++i )
15436  {
15437  /* initially, no variable appears in the expression tree */
15438  for( j = 0; j < exprgraph->nvars; ++j )
15439  varidx[j] = -1; /*lint !e644*/
15440  nexprvars = 0;
15441 
15442  /* collect expressions from children belonging to component i */
15443  nexprs = 0;
15444  for( j = 0; j < node->nchildren; ++j )
15445  {
15446  assert(childcomp[j] >= 0);
15447  assert(childcomp[j] < ncomponents);
15448  if( childcomp[j] != i )
15449  continue;
15450 
15451  /* create expression from the subgraph that has child j as root */
15452  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
15453  childmap[j] = nexprs; /*lint !e644*/
15454  childmapinv[nexprs] = j; /*lint !e644*/
15455  ++nexprs;
15456  }
15457 
15458  /* setup expression tree for component i */
15459  switch( node->op )
15460  {
15461  case SCIP_EXPR_PLUS:
15462  {
15463  assert(ncomponents == 2);
15464  assert(nexprs == 1);
15465 
15466  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
15467  exprtreecoefs[i] = 1.0;
15468 
15469  break;
15470  }
15471 
15472  case SCIP_EXPR_MINUS:
15473  {
15474  assert(ncomponents == 2);
15475  assert(nexprs == 1);
15476 
15477  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
15478  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
15479  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
15480  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
15481 
15482  break;
15483  }
15484 
15485  case SCIP_EXPR_SUM:
15486  {
15487  if( nexprs == 1 )
15488  {
15489  /* component corresponds to exactly one child of node */
15490  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
15491  }
15492  else
15493  {
15494  /* component corresponds to a sum of children of node */
15495  SCIP_EXPR* sumexpr;
15496 
15497  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
15498  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
15499  }
15500  exprtreecoefs[i] = 1.0;
15501 
15502  break;
15503  }
15504 
15505  case SCIP_EXPR_LINEAR:
15506  {
15507  SCIP_Real* nodecoefs;
15508  SCIP_EXPR* sumexpr;
15509 
15510  nodecoefs = (SCIP_Real*)node->data.data;
15511 
15512  /* if there is a constant, then we put it into the expression of the first component */
15513  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
15514  {
15515  /* component corresponds to exactly one child of node */
15516  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
15517  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
15518  }
15519  else if( nexprs == 1 )
15520  {
15521  /* component corresponds to a sum of one child and a constant */
15522  assert(i == 0);
15523  assert(nodecoefs[node->nchildren] != 0.0);
15524  assert(nodecoefs[childmapinv[0]] != 0.0);
15525  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
15526  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
15527  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
15528  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
15529  }
15530  else
15531  {
15532  /* component corresponds to a linear combination of children of node */
15533 
15534  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
15535  {
15536  /* if two expressions with equal sign, then create PLUS expression */
15537  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
15538  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
15539  }
15540  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
15541  {
15542  /* if two expressions with opposite sign, then create MINUS expression */
15543  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
15544  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
15545  }
15546  else
15547  {
15548  /* assemble coefficents and create SUM or LINEAR expression */
15549  SCIP_Real* coefs;
15550  SCIP_Bool allcoefsequal;
15551 
15552  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
15553  allcoefsequal = TRUE;
15554  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
15555  for( j = 0; j < nexprs; ++j )
15556  {
15557  coefs[j] = nodecoefs[childmapinv[j]];
15558  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
15559  }
15560 
15561  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
15562  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
15563  {
15564  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
15565  exprtreecoefs[i] = coefs[0];
15566  }
15567  else
15568  {
15569  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
15570  exprtreecoefs[i] = 1.0;
15571  }
15572 
15573  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
15574  }
15575 
15576  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
15577  }
15578 
15579  break;
15580  }
15581 
15582  case SCIP_EXPR_QUADRATIC:
15583  {
15584  SCIP_EXPR* quadexpr;
15585  SCIP_EXPRDATA_QUADRATIC* nodedata;
15586  SCIP_Real* lincoefs;
15587  SCIP_QUADELEM* quadelems;
15588  int nquadelems;
15589 
15590  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
15591 
15592  exprtreecoefs[i] = 1.0;
15593 
15594  /* assemble coefficients corresponding to component i */
15595  if( nodedata->lincoefs != NULL )
15596  {
15597  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
15598  for( j = 0; j < nexprs; ++j )
15599  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
15600  }
15601  else
15602  lincoefs = NULL;
15603 
15604  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
15605  nquadelems = 0;
15606  for( j = 0; j < nodedata->nquadelems; ++j )
15607  {
15608  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
15609  if( childcomp[nodedata->quadelems[j].idx1] != i )
15610  continue;
15611  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
15612  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
15613  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
15614  ++nquadelems;
15615  }
15616 
15617  /* put constant into first component */
15618  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
15619  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
15620 
15621  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
15622  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
15623 
15624  break;
15625  }
15626 
15627  case SCIP_EXPR_POLYNOMIAL:
15628  {
15629  SCIP_EXPR* polyexpr;
15630  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
15631  SCIP_EXPRDATA_MONOMIAL** monomials;
15632  SCIP_Real constant;
15633  int nmonomials;
15634 
15635  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
15636 
15637  constant = nodedata->constant;
15638  exprtreecoefs[i] = 1.0;
15639 
15640  /* collect monomials belonging to component i */
15641  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
15642  nmonomials = 0;
15643  for( j = 0; j < nodedata->nmonomials; ++j )
15644  {
15645  if( nodedata->monomials[j]->nfactors == 0 )
15646  {
15647  constant += nodedata->monomials[j]->coef;
15648  continue;
15649  }
15650  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
15651  continue;
15652 
15653  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors, nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
15654  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
15655  {
15656  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
15657  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
15658  }
15659  ++nmonomials;
15660  }
15661 
15662  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
15663  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
15664 
15665  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
15666 
15667  break;
15668  }
15669 
15670  default:
15671  SCIPerrorMessage("unexpected operator type %d\n", node->op);
15672  return SCIP_ERROR;
15673  } /*lint !e788*/
15674 
15675  /* copy variables into expression tree */
15676  if( nexprvars > 0 )
15677  {
15678  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
15679  for( j = 0; j < exprgraph->nvars; ++j )
15680  {
15681  assert(varidx[j] >= -1);
15682  assert(varidx[j] < nexprvars);
15683  if( varidx[j] >= 0 )
15684  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
15685  }
15686  }
15687  }
15688 
15689  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
15690  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
15691  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
15692  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
15693  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
15694 
15695  *nexprtrees = ncomponents;
15696 
15697  return SCIP_OKAY;
15698 }
15699 
15700 /** returns how often expression graph variables are used in a subtree of the expression graph */
15702  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15703  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
15704  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
15705  )
15706 {
15707  assert(exprgraph != NULL);
15708  assert(node != NULL);
15709  assert(varsusage != NULL);
15710 
15711  BMSclearMemoryArray(varsusage, exprgraph->nvars);
15712 
15713  exprgraphNodeGetVarsUsage(node, varsusage);
15714 }
15715 
15716 /** gives the number of summands which the expression of an expression graph node consists of */
15718  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
15719  )
15720 {
15721  switch( node->op )
15722  {
15723  case SCIP_EXPR_PLUS:
15724  case SCIP_EXPR_MINUS:
15725  return 2;
15726 
15727  case SCIP_EXPR_SUM:
15728  case SCIP_EXPR_LINEAR:
15729  return node->nchildren;
15730 
15731  case SCIP_EXPR_QUADRATIC:
15732  {
15733  SCIP_EXPRDATA_QUADRATIC* nodedata;
15734 
15735  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
15736  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
15737  }
15738 
15739  case SCIP_EXPR_POLYNOMIAL:
15740  {
15741  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
15742 
15743  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
15744  return nodedata->nmonomials;
15745  }
15746 
15747  default:
15748  return 1;
15749  } /*lint !e788*/
15750 }
15751 
15752 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
15754  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15755  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
15756  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
15757  int* nexprtrees, /**< buffer to store number of expression trees */
15758  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
15759  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
15760  )
15761 {
15762  int* varidx;
15763  int nexprvars;
15764  int i;
15765 
15766  assert(exprgraph != NULL);
15767  assert(node != NULL);
15768  assert(node->depth >= 0);
15769  assert(node->pos >= 0);
15770  assert(exprtreessize > 0);
15771  assert(nexprtrees != NULL);
15772  assert(exprtrees != NULL);
15773  assert(exprtreecoefs != NULL);
15774 
15775  /* if node is not separable, fallback to SCIPexprgraphGetTree */
15776  if( node->op != SCIP_EXPR_PLUS &&
15777  node->op != SCIP_EXPR_MINUS &&
15778  node->op != SCIP_EXPR_SUM &&
15779  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
15780  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
15781  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
15782  {
15783  *nexprtrees = 1;
15784  exprtreecoefs[0] = 1.0;
15785  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
15786 
15787  return SCIP_OKAY;
15788  }
15789 
15790  switch( node->op )
15791  {
15792  case SCIP_EXPR_PLUS:
15793  {
15794  assert(exprtreessize >= 2);
15795 
15796  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
15797  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
15798 
15799  exprtreecoefs[0] = 1.0;
15800  exprtreecoefs[1] = 1.0;
15801 
15802  *nexprtrees = 2;
15803  break;
15804  }
15805 
15806  case SCIP_EXPR_MINUS:
15807  {
15808  assert(exprtreessize >= 2);
15809 
15810  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
15811  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
15812 
15813  exprtreecoefs[0] = 1.0;
15814  exprtreecoefs[1] = -1.0;
15815 
15816  *nexprtrees = 2;
15817  break;
15818  }
15819 
15820  case SCIP_EXPR_SUM:
15821  {
15822  assert(exprtreessize >= node->nchildren);
15823 
15824  for( i = 0; i < node->nchildren; ++i )
15825  {
15826  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
15827  exprtreecoefs[i] = 1.0;
15828  }
15829 
15830  *nexprtrees = node->nchildren;
15831  break;
15832  }
15833 
15834  case SCIP_EXPR_LINEAR:
15835  {
15836  SCIP_Real* nodecoefs;
15837 
15838  assert(exprtreessize >= node->nchildren);
15839  assert(node->nchildren > 0);
15840 
15841  nodecoefs = (SCIP_Real*)node->data.data;
15842  assert(nodecoefs != NULL);
15843 
15844  for( i = 0; i < node->nchildren; ++i )
15845  {
15846  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
15847  exprtreecoefs[i] = nodecoefs[i];
15848  }
15849 
15850  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
15851  if( nodecoefs[node->nchildren] != 0.0 )
15852  {
15853  SCIP_EXPR* constexpr_;
15854 
15855  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
15856  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
15857  }
15858 
15859  *nexprtrees = node->nchildren;
15860  break;
15861  }
15862 
15863  case SCIP_EXPR_QUADRATIC:
15864  {
15865  SCIP_EXPRDATA_QUADRATIC* nodedata;
15866  SCIP_Real* lincoefs;
15867  SCIP_QUADELEM* quadelems;
15868  int nquadelems;
15869  SCIP_EXPR* expr;
15870  int j;
15871 
15872  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
15873  lincoefs = nodedata->lincoefs;
15874  quadelems = nodedata->quadelems;
15875  nquadelems = nodedata->nquadelems;
15876 
15877  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
15878  assert(node->nchildren > 0);
15879 
15880  *nexprtrees = 0;
15881  if( lincoefs != NULL )
15882  {
15883  for( i = 0; i < node->nchildren; ++i )
15884  {
15885  if( lincoefs[i] == 0.0 )
15886  continue;
15887  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
15888  exprtreecoefs[*nexprtrees] = lincoefs[i];
15889  ++*nexprtrees;
15890  }
15891  }
15892 
15893  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
15894  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
15895 
15896  for( i = 0; i < nquadelems; ++i )
15897  {
15898  /* initially, no variable appears in the expression tree */
15899  for( j = 0; j < exprgraph->nvars; ++j )
15900  varidx[j] = -1; /*lint !e644*/
15901  nexprvars = 0;
15902 
15903  /* create expression from the subgraph at quadelems[i].idx1 */
15904  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
15905 
15906  if( quadelems[i].idx1 == quadelems[i].idx2 )
15907  {
15908  /* create expression for square of expr */
15909  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
15910  }
15911  else
15912  {
15913  SCIP_EXPR* expr2;
15914 
15915  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
15916  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
15917  /* create expression for product */
15918  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
15919  }
15920 
15921  /* create expression tree for expr */
15922  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
15923 
15924  /* copy variables into expression tree */
15925  if( nexprvars > 0 )
15926  {
15927  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
15928  for( j = 0; j < exprgraph->nvars; ++j )
15929  {
15930  assert(varidx[j] >= -1);
15931  assert(varidx[j] < nexprvars);
15932  if( varidx[j] >= 0 )
15933  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
15934  }
15935  }
15936 
15937  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
15938 
15939  ++*nexprtrees;
15940  }
15941 
15942  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
15943  if( nodedata->constant != 0.0 )
15944  {
15945  SCIP_EXPR* constexpr_;
15946 
15947  assert(*nexprtrees > 0);
15948  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
15949  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
15950  }
15951 
15952  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
15953 
15954  break;
15955  }
15956 
15957  case SCIP_EXPR_POLYNOMIAL:
15958  {
15959  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
15960  SCIP_EXPRDATA_MONOMIAL** monomials;
15961  SCIP_Real constant;
15962  int nmonomials;
15963  SCIP_EXPR* expr;
15964  int* childidxs;
15965  int j;
15966 
15967  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
15968  monomials = nodedata->monomials;
15969  nmonomials = nodedata->nmonomials;
15970  constant = nodedata->constant;
15971 
15972  assert(exprtreessize >= nmonomials);
15973  assert(node->nchildren > 0);
15974 
15975  *nexprtrees = 0;
15976 
15977  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
15978  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
15979 
15980  for( i = 0; i < nmonomials; ++i )
15981  {
15982  /* initially, no variable appears in the expression tree */
15983  for( j = 0; j < exprgraph->nvars; ++j )
15984  varidx[j] = -1;
15985  nexprvars = 0;
15986 
15987  if( monomials[i]->nfactors == 1 )
15988  {
15989  /* create expression from the subgraph at only factor */
15990  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
15991 
15992  /* put exponent in, if not 1.0 */
15993  if( monomials[i]->exponents[0] == 1.0 )
15994  ;
15995  else if( monomials[i]->exponents[0] == 2.0 )
15996  {
15997  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
15998  }
15999  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
16000  {
16001  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
16002  }
16003  else
16004  {
16005  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
16006  }
16007  }
16008  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
16009  {
16010  SCIP_EXPR* expr2;
16011 
16012  /* create expressions for both factors */
16013  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16014  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
16015 
16016  /* create expression for product of factors */
16017  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16018  }
16019  else
16020  {
16021  SCIP_EXPRDATA_MONOMIAL* monomial;
16022  SCIP_EXPR** exprs;
16023  int f;
16024 
16025  /* create expression for each factor, assemble varidx and nexprvars
16026  * create child indices (= identity) */
16027  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
16028  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
16029  for( f = 0; f < monomials[i]->nfactors; ++f )
16030  {
16031  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
16032  childidxs[f] = f; /*lint !e644*/
16033  }
16034 
16035  /* create monomial and polynomial expression for this monomial
16036  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
16037  */
16038  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
16039  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
16040  constant = 0.0;
16041 
16042  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
16043  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
16044  }
16045 
16046  /* create expression tree for expr */
16047  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16048 
16049  /* copy variables into expression tree */
16050  if( nexprvars > 0 )
16051  {
16052  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16053  for( j = 0; j < exprgraph->nvars; ++j )
16054  {
16055  assert(varidx[j] >= -1);
16056  assert(varidx[j] < nexprvars);
16057  if( varidx[j] >= 0 )
16058  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16059  }
16060  }
16061 
16062  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
16063 
16064  ++*nexprtrees;
16065  }
16066 
16067  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
16068  if( constant != 0.0 )
16069  {
16070  SCIP_EXPR* constexpr_;
16071 
16072  assert(*nexprtrees > 0);
16073  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
16074  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16075  }
16076 
16077  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16078 
16079  break;
16080  }
16081 
16082  default:
16083  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16084  return SCIP_ERROR;
16085  } /*lint !e788*/
16086 
16087  return SCIP_OKAY;
16088 }
16089 
16090 /**@} */
16091