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  *
43  * 0.0 has sign +1
44  */
45 #define SIGN(x) ((x) >= 0.0 ? 1.0 : -1.0)
46 
47 /** ensures that a block memory array has at least a given size
48  *
49  * if cursize is 0, then *array1 can be NULL
50  */
51 #define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize) \
52  do { \
53  int __newsize; \
54  assert((blkmem) != NULL); \
55  if( *(cursize) >= (minsize) ) \
56  break; \
57  __newsize = calcGrowSize(minsize); \
58  assert(__newsize >= (minsize)); \
59  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
60  *(cursize) = __newsize; \
61  } while( FALSE )
62 
63 #ifdef SCIP_DISABLED_CODE /* this macro is currently not used, which offends lint, so disable it */
64 /** ensures that two block memory arrays have at least a given size
65  *
66  * if cursize is 0, then arrays can be NULL
67  */
68 #define ensureBlockMemoryArraySize2(blkmem, array1, array2, cursize, minsize) \
69  do { \
70  int __newsize; \
71  assert((blkmem) != NULL); \
72  if( *(cursize) >= (minsize) ) \
73  break; \
74  __newsize = calcGrowSize(minsize); \
75  assert(__newsize >= (minsize)); \
76  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
77  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
78  *(cursize) = __newsize; \
79  } while( FALSE )
80 #endif
81 
82 /** ensures that three block memory arrays have at least a given size
83  *
84  * if cursize is 0, then arrays can be NULL
85  */
86 #define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize) \
87  do { \
88  int __newsize; \
89  assert((blkmem) != NULL); \
90  if( *(cursize) >= (minsize) ) \
91  break; \
92  __newsize = calcGrowSize(minsize); \
93  assert(__newsize >= (minsize)); \
94  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
95  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
96  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array3, *(cursize), __newsize) ); \
97  *(cursize) = __newsize; \
98  } while( FALSE )
99 
100 /**@name Miscellaneous private methods */
101 /**@{ */
102 
103 /** calculate memory size for dynamically allocated arrays (copied from scip/set.c) */
104 static
106  int num /**< minimum number of entries to store */
107  )
108 {
109  int size;
110 
111  /* calculate the size with this loop, such that the resulting numbers are always the same (-> block memory) */
112  size = 4;
113  while( size < num )
114  size = (int)(1.2 * size + 4);
115 
116  return size;
117 }
118 
119 /** pointer comparison to use in sorting methods */
120 static
122 {
123  if( elem1 > elem2 )
124  return 1;
125  if( elem1 < elem2 )
126  return -1;
127  return 0;
128 }
129 
130 /** 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) */
131 static
133  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
134  SCIP_Real newlb, /**< new lower bound */
135  SCIP_Real oldlb, /**< old lower bound */
136  SCIP_Real oldub /**< old upper bound */
137  )
138 {
139  SCIP_Real eps;
140 
141  /* nothing can be tighter than an empty interval */
142  if( oldlb > oldub )
143  return FALSE;
144 
145  eps = REALABS(oldlb);
146  eps = MIN(oldub - oldlb, eps);
147  return EPSGT(newlb, oldlb, minstrength * MAX(eps, 1e-3));
148 }
149 
150 /** 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) */
151 static
153  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
154  SCIP_Real newub, /**< new upper bound */
155  SCIP_Real oldlb, /**< old lower bound */
156  SCIP_Real oldub /**< old upper bound */
157  )
158 {
159  SCIP_Real eps;
160 
161  /* nothing can be tighter than an empty interval */
162  if( oldlb > oldub )
163  return FALSE;
164 
165  eps = REALABS(oldub);
166  eps = MIN(oldub - oldlb, eps);
167  return EPSLT(newub, oldub, minstrength * MAX(eps, 1e-3));
168 }
169 
170 /**@} */
171 
172 /**@name Expression curvature methods */
173 /**@{ */
174 
175 /** curvature names as strings */
176 static
177 const char* curvnames[4] =
178  {
179  "unknown",
180  "convex",
181  "concave",
182  "linear"
183  };
184 
185 #undef SCIPexprcurvAdd
186 
187 /** gives curvature for a sum of two functions with given curvature */
189  SCIP_EXPRCURV curv1, /**< curvature of first summand */
190  SCIP_EXPRCURV curv2 /**< curvature of second summand */
191  )
192 {
193  return (SCIP_EXPRCURV) (curv1 & curv2);
194 }
195 
196 /** gives the curvature for the negation of a function with given curvature */
198  SCIP_EXPRCURV curvature /**< curvature of function */
199  )
200 {
201  switch( curvature )
202  {
204  return SCIP_EXPRCURV_CONVEX;
205 
207  return SCIP_EXPRCURV_CONCAVE;
208 
211  /* can return curvature, do this below */
212  break;
213 
214  default:
215  SCIPerrorMessage("unknown curvature status.\n");
216  SCIPABORT();
217  }
218 
219  return curvature;
220 }
221 
222 /** gives curvature for a functions with given curvature multiplied by a constant factor */
224  SCIP_Real factor, /**< constant factor */
225  SCIP_EXPRCURV curvature /**< curvature of other factor */
226  )
227 {
228  if( factor == 0.0 )
229  return SCIP_EXPRCURV_LINEAR;
230  if( factor > 0.0 )
231  return curvature;
232  return SCIPexprcurvNegate(curvature);
233 }
234 
235 /** gives curvature for base^exponent for given bounds and curvature of base-function and constant exponent */
237  SCIP_INTERVAL basebounds, /**< bounds on base function */
238  SCIP_EXPRCURV basecurv, /**< curvature of base function */
239  SCIP_Real exponent /**< exponent */
240  )
241 {
242  SCIP_Bool expisint;
243 
244  assert(basebounds.inf <= basebounds.sup);
245 
246  if( exponent == 0.0 )
247  return SCIP_EXPRCURV_LINEAR;
248 
249  if( exponent == 1.0 )
250  return basecurv;
251 
252  expisint = EPSISINT(exponent, 0.0); /*lint !e835*/
253 
254  /* if exponent is fractional, then power is not defined for a negative base
255  * thus, consider only positive part of basebounds
256  */
257  if( !expisint && basebounds.inf < 0.0 )
258  {
259  basebounds.inf = 0.0;
260  if( basebounds.sup < 0.0 )
261  return SCIP_EXPRCURV_LINEAR;
262  }
263 
264  /* if basebounds contains 0.0, consider negative and positive interval separately, if possible */
265  if( basebounds.inf < 0.0 && basebounds.sup > 0.0 )
266  {
267  SCIP_INTERVAL leftbounds;
268  SCIP_INTERVAL rightbounds;
269 
270  /* 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 */
271  if( exponent < 0.0 )
272  return SCIP_EXPRCURV_UNKNOWN;
273 
274  SCIPintervalSetBounds(&leftbounds, basebounds.inf, 0.0);
275  SCIPintervalSetBounds(&rightbounds, 0.0, basebounds.sup);
276 
277  return (SCIP_EXPRCURV) (SCIPexprcurvPower(leftbounds, basecurv, exponent) & SCIPexprcurvPower(rightbounds, basecurv, exponent));
278  }
279  assert(basebounds.inf >= 0.0 || basebounds.sup <= 0.0);
280 
281  /* (base^exponent)'' = exponent * ( (exponent-1) base^(exponent-2) (base')^2 + base^(exponent-1) base'' )
282  *
283  * if base'' is positive, i.e., base is convex, then
284  * - for base > 0.0 and exponent > 1.0, the second deriv. is positive -> convex
285  * - for base < 0.0 and exponent > 1.0, we can't say (first and second summand opposite signs)
286  * - for base > 0.0 and 0.0 < exponent < 1.0, we can't say (first sommand negative, second summand positive)
287  * - for base > 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
288  * - for base < 0.0 and exponent < 0.0 and even, the second deriv. is positive -> convex
289  * - for base < 0.0 and exponent < 0.0 and odd, the second deriv. is negative -> concave
290  *
291  * if base'' is negative, i.e., base is concave, then
292  * - for base > 0.0 and exponent > 1.0, we can't say (first summand positive, second summand negative)
293  * - for base < 0.0 and exponent > 1.0 and even, the second deriv. is positive -> convex
294  * - for base < 0.0 and exponent > 1.0 and odd, the second deriv. is negative -> concave
295  * - for base > 0.0 and 0.0 < exponent < 1.0, the second deriv. is negative -> concave
296  * - for base > 0.0 and exponent < 0.0, the second deriv. is positive -> convex
297  * - for base < 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
298  *
299  * if base'' is zero, i.e., base is linear, then
300  * (base^exponent)'' = exponent * (exponent-1) base^(exponent-2) (base')^2
301  * - just multiply signs
302  */
303 
304  if( basecurv == SCIP_EXPRCURV_LINEAR )
305  {
306  SCIP_Real sign;
307 
308  /* base^(exponent-2) is negative, if base < 0.0 and exponent is odd */
309  sign = exponent * (exponent - 1.0);
310  assert(basebounds.inf >= 0.0 || expisint);
311  if( basebounds.inf < 0.0 && ((int)exponent)%2 != 0 )
312  sign *= -1.0;
313  assert(sign != 0.0);
314 
315  return sign > 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
316  }
317 
318  if( basecurv == SCIP_EXPRCURV_CONVEX )
319  {
320  if( basebounds.sup <= 0.0 && exponent < 0.0 && expisint )
321  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
322  if( basebounds.inf >= 0.0 && exponent > 1.0 )
323  return SCIP_EXPRCURV_CONVEX ;
324  return SCIP_EXPRCURV_UNKNOWN;
325  }
326 
327  if( basecurv == SCIP_EXPRCURV_CONCAVE )
328  {
329  if( basebounds.sup <= 0.0 && exponent > 1.0 && expisint )
330  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
331  if( basebounds.inf >= 0.0 && exponent < 1.0 )
332  return exponent < 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
333  return SCIP_EXPRCURV_UNKNOWN;
334  }
335 
336  return SCIP_EXPRCURV_UNKNOWN;
337 }
338 
339 /** gives curvature for a monomial with given curvatures and bounds for each factor
340  *
341  * See Maranas and Floudas, Finding All Solutions of Nonlinearly Constrained Systems of Equations, JOGO 7, 1995
342  * for the categorization in the case that all factors are linear.
343  */
345  int nfactors, /**< number of factors in monomial */
346  SCIP_Real* exponents, /**< exponents in monomial, or NULL if all 1.0 */
347  int* factoridxs, /**< indices of factors (but not exponents), or NULL if identity mapping */
348  SCIP_EXPRCURV* factorcurv, /**< curvature of each factor */
349  SCIP_INTERVAL* factorbounds /**< bounds of each factor */
350  )
351 {
352  SCIP_Real mult;
353  SCIP_Real e;
354  SCIP_EXPRCURV curv;
355  SCIP_EXPRCURV fcurv;
356  int nnegative;
357  int npositive;
358  SCIP_Real sum;
359  SCIP_Bool expcurvpos;
360  SCIP_Bool expcurvneg;
361  int j;
362  int f;
363 
364  assert(nfactors >= 0);
365  assert(factorcurv != NULL || nfactors == 0);
366  assert(factorbounds != NULL || nfactors == 0);
367 
368  if( nfactors == 0 )
369  return SCIP_EXPRCURV_LINEAR;
370 
371  if( nfactors == 1 )
372  {
373  f = factoridxs != NULL ? factoridxs[0] : 0;
374  e = exponents != NULL ? exponents[0] : 1.0;
375  /* SCIPdebugMessage("monomial [%g,%g]^%g is %s\n",
376  factorbounds[f].inf, factorbounds[f].sup, e,
377  SCIPexprcurvGetName(SCIPexprcurvPower(factorbounds[f], factorcurv[f], e))); */
378  return SCIPexprcurvPower(factorbounds[f], factorcurv[f], e); /*lint !e613*/
379  }
380 
381  mult = 1.0;
382 
383  nnegative = 0; /* number of negative exponents */
384  npositive = 0; /* number of positive exponents */
385  sum = 0.0; /* sum of exponents */
386  expcurvpos = TRUE; /* whether exp_j * f_j''(x) >= 0 for all factors (assuming f_j >= 0) */
387  expcurvneg = TRUE; /* whether exp_j * f_j''(x) <= 0 for all factors (assuming f_j >= 0) */
388 
389  for( j = 0; j < nfactors; ++j )
390  {
391  f = factoridxs != NULL ? factoridxs[j] : j;
392  if( factorcurv[f] == SCIP_EXPRCURV_UNKNOWN ) /*lint !e613*/
393  return SCIP_EXPRCURV_UNKNOWN;
394  if( factorbounds[f].inf < 0.0 && factorbounds[f].sup > 0.0 ) /*lint !e613*/
395  return SCIP_EXPRCURV_UNKNOWN;
396 
397  e = exponents != NULL ? exponents[j] : 1.0;
398  if( e < 0.0 )
399  ++nnegative;
400  else
401  ++npositive;
402  sum += e;
403 
404  if( factorbounds[f].inf < 0.0 ) /*lint !e613*/
405  {
406  /* if argument is negative, then exponent should be integer */
407  assert(EPSISINT(e, 0.0)); /*lint !e835*/
408 
409  /* flip j'th argument: (f_j)^(exp_j) = (-1)^(exp_j) (-f_j)^(exp_j) */
410 
411  /* -f_j has negated curvature of f_j */
412  fcurv = SCIPexprcurvNegate(factorcurv[f]); /*lint !e613*/
413 
414  /* negate monomial, if exponent is odd, i.e., (-1)^(exp_j) = -1 */
415  if( (int)e % 2 != 0 )
416  mult *= -1.0;
417  }
418  else
419  {
420  fcurv = factorcurv[f]; /*lint !e613*/
421  }
422 
423  /* check if exp_j * fcurv is convex (>= 0) and/or concave */
424  fcurv = SCIPexprcurvMultiply(e, fcurv);
425  if( !(fcurv & SCIP_EXPRCURV_CONVEX) )
426  expcurvpos = FALSE;
427  if( !(fcurv & SCIP_EXPRCURV_CONCAVE) )
428  expcurvneg = FALSE;
429  }
430 
431  /* if all factors are linear, then a product f_j^exp_j with f_j >= 0 is convex if
432  * - all exponents are negative, or
433  * - 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
434  * further, the product is concave if
435  * - all exponents are positive and the sum of exponents is <= 1.0
436  *
437  * if factors are nonlinear, then we require additionally, that for convexity
438  * - each factor is convex if exp_j >= 0, or concave if exp_j <= 0, i.e., exp_j*f_j'' >= 0
439  * and for concavity, we require that
440  * - all factors are concave, i.e., exp_j*f_j'' <= 0
441  */
442 
443  if( nnegative == nfactors && expcurvpos )
444  curv = SCIP_EXPRCURV_CONVEX;
445  else if( nnegative == nfactors-1 && EPSGE(sum, 1.0, 1e-9) && expcurvpos )
446  curv = SCIP_EXPRCURV_CONVEX;
447  else if( npositive == nfactors && EPSLE(sum, 1.0, 1e-9) && expcurvneg )
448  curv = SCIP_EXPRCURV_CONCAVE;
449  else
450  curv = SCIP_EXPRCURV_UNKNOWN;
451  curv = SCIPexprcurvMultiply(mult, curv);
452 
453  return curv;
454 }
455 
456 /** gives name as string for a curvature */
458  SCIP_EXPRCURV curv /**< curvature */
459  )
460 {
461  assert(curv <= SCIP_EXPRCURV_LINEAR); /*lint !e685*/
462 
463  return curvnames[curv];
464 }
465 
466 /**@} */
467 
468 /**@name Quadratic expression data private methods */
469 /**@{ */
470 
471 /** creates SCIP_EXPRDATA_QUADRATIC data structure from given quadratic elements */
472 static
474  BMS_BLKMEM* blkmem, /**< block memory data structure */
475  SCIP_EXPRDATA_QUADRATIC** quadraticdata, /**< buffer to store pointer to quadratic data */
476  SCIP_Real constant, /**< constant */
477  int nchildren, /**< number of children */
478  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
479  int nquadelems, /**< number of quadratic elements */
480  SCIP_QUADELEM* quadelems /**< quadratic elements */
481  )
482 {
483  assert(blkmem != NULL);
484  assert(quadraticdata != NULL);
485  assert(quadelems != NULL || nquadelems == 0);
486  assert(nchildren >= 0);
487 
488  SCIP_ALLOC( BMSallocBlockMemory(blkmem, quadraticdata) );
489 
490  (*quadraticdata)->constant = constant;
491  (*quadraticdata)->lincoefs = NULL;
492  (*quadraticdata)->nquadelems = nquadelems;
493  (*quadraticdata)->quadelems = NULL;
494  (*quadraticdata)->sorted = (nquadelems <= 1);
495 
496  if( lincoefs != NULL )
497  {
498  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->lincoefs, lincoefs, nchildren) );
499  }
500 
501  if( nquadelems > 0 )
502  {
503  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->quadelems, quadelems, nquadelems) );
504  }
505 
506  return SCIP_OKAY;
507 }
508 
509 /** sorts quadratic elements in a SCIP_EXPRDATA_QUADRATIC data structure */
510 static
512  SCIP_EXPRDATA_QUADRATIC* quadraticdata /**< quadratic data */
513  )
514 {
515  assert(quadraticdata != NULL);
516 
517  if( quadraticdata->sorted )
518  {
519 #ifndef NDEBUG
520  int i;
521  for( i = 1; i < quadraticdata->nquadelems; ++i )
522  {
523  assert(quadraticdata->quadelems[i].idx1 <= quadraticdata->quadelems[i].idx2);
524  assert(quadraticdata->quadelems[i-1].idx1 <= quadraticdata->quadelems[i].idx1);
525  assert(quadraticdata->quadelems[i-1].idx1 < quadraticdata->quadelems[i].idx1 ||
526  quadraticdata->quadelems[i-1].idx2 <= quadraticdata->quadelems[i].idx2);
527  }
528 #endif
529  return;
530  }
531 
532  if( quadraticdata->nquadelems > 0 )
533  SCIPquadelemSort(quadraticdata->quadelems, quadraticdata->nquadelems);
534 
535  quadraticdata->sorted = TRUE;
536 }
537 
538 /**@} */
539 
540 /**@name Polynomial expression data private methods */
541 /**@{ */
542 
543 /** compares two monomials
544  *
545  * gives 0 if monomials are equal */
546 static
547 SCIP_DECL_SORTPTRCOMP(monomialdataCompare)
548 {
549  SCIP_EXPRDATA_MONOMIAL* monomial1;
550  SCIP_EXPRDATA_MONOMIAL* monomial2;
551 
552  int i;
553 
554  assert(elem1 != NULL);
555  assert(elem2 != NULL);
556 
557  monomial1 = (SCIP_EXPRDATA_MONOMIAL*)elem1;
558  monomial2 = (SCIP_EXPRDATA_MONOMIAL*)elem2;
559 
560  /* make sure, both monomials are equal */
561  SCIPexprSortMonomialFactors(monomial1);
562  SCIPexprSortMonomialFactors(monomial2);
563 
564  /* for the first factor where both monomials differ,
565  * we return either the difference in the child indices, if children are different
566  * or the sign of the difference in the exponents
567  */
568  for( i = 0; i < monomial1->nfactors && i < monomial2->nfactors; ++i )
569  {
570  if( monomial1->childidxs[i] != monomial2->childidxs[i] )
571  return monomial1->childidxs[i] - monomial2->childidxs[i];
572  if( monomial1->exponents[i] > monomial2->exponents[i] )
573  return 1;
574  else if( monomial1->exponents[i] < monomial2->exponents[i] )
575  return -1;
576  }
577 
578  /* if the factors of one monomial are a proper subset of the factors of the other monomial,
579  * we return the difference in the number of monomials
580  */
581  return monomial1->nfactors - monomial2->nfactors;
582 }
583 
584 /** ensures that the factors arrays of a monomial have at least a given size */
585 static
587  BMS_BLKMEM* blkmem, /**< block memory data structure */
588  SCIP_EXPRDATA_MONOMIAL* monomialdata, /**< monomial data */
589  int minsize /**< minimal size of factors arrays */
590  )
591 {
592  assert(blkmem != NULL);
593  assert(monomialdata != NULL);
594 
595  if( minsize > monomialdata->factorssize )
596  {
597  int newsize;
598 
599  newsize = calcGrowSize(minsize);
600  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->childidxs, monomialdata->factorssize, newsize) );
601  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->exponents, monomialdata->factorssize, newsize) );
602  monomialdata->factorssize = newsize;
603  }
604  assert(minsize <= monomialdata->factorssize);
605 
606  return SCIP_OKAY;
607 }
608 
609 /** creates SCIP_EXPRDATA_POLYNOMIAL data structure from given monomials */
610 static
612  BMS_BLKMEM* blkmem, /**< block memory data structure */
613  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
614  int nmonomials, /**< number of monomials */
615  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
616  SCIP_Real constant, /**< constant part */
617  SCIP_Bool copymonomials /**< whether to copy monomials, or copy only given pointers, in which case polynomialdata assumes ownership of monomial structure */
618  )
619 {
620  assert(blkmem != NULL);
621  assert(polynomialdata != NULL);
622  assert(monomials != NULL || nmonomials == 0);
623 
624  SCIP_ALLOC( BMSallocBlockMemory(blkmem, polynomialdata) );
625 
626  (*polynomialdata)->constant = constant;
627  (*polynomialdata)->nmonomials = nmonomials;
628  (*polynomialdata)->monomialssize = nmonomials;
629  (*polynomialdata)->monomials = NULL;
630  (*polynomialdata)->sorted = (nmonomials <= 1);
631 
632  if( nmonomials > 0 )
633  {
634  int i;
635 
636  if( copymonomials )
637  {
638  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, nmonomials) );
639 
640  for( i = 0; i < nmonomials; ++i )
641  {
642  assert(monomials[i] != NULL); /*lint !e613*/
643  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i],
644  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
645  }
646  }
647  else
648  {
649  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, monomials, nmonomials) );
650  }
651  }
652 
653  return SCIP_OKAY;
654 }
655 
656 /** creates a copy of a SCIP_EXPRDATA_POLYNOMIAL data structure */
657 static
659  BMS_BLKMEM* blkmem, /**< block memory data structure */
660  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
661  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata /**< polynomial data to copy */
662  )
663 {
664  assert(blkmem != NULL);
665  assert(polynomialdata != NULL);
666  assert(sourcepolynomialdata != NULL);
667 
668  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, polynomialdata, sourcepolynomialdata) );
669 
670  (*polynomialdata)->monomialssize = sourcepolynomialdata->nmonomials;
671  if( sourcepolynomialdata->nmonomials > 0 )
672  {
673  int i;
674 
675  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize) );
676 
677  for( i = 0; i < sourcepolynomialdata->nmonomials; ++i )
678  {
679  assert(sourcepolynomialdata->monomials[i] != NULL); /*lint !e613*/
680  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i], sourcepolynomialdata->monomials[i]->coef,
681  sourcepolynomialdata->monomials[i]->nfactors, sourcepolynomialdata->monomials[i]->childidxs, sourcepolynomialdata->monomials[i]->exponents) );
682  (*polynomialdata)->monomials[i]->sorted = sourcepolynomialdata->monomials[i]->sorted;
683  }
684  }
685  else
686  {
687  (*polynomialdata)->monomials = NULL;
688  }
689 
690  return SCIP_OKAY;
691 }
692 
693 /** frees a SCIP_EXPRDATA_POLYNOMIAL data structure */
694 static
696  BMS_BLKMEM* blkmem, /**< block memory data structure */
697  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata /**< pointer to polynomial data to free */
698  )
699 {
700  assert(blkmem != NULL);
701  assert(polynomialdata != NULL);
702  assert(*polynomialdata != NULL);
703 
704  if( (*polynomialdata)->monomialssize > 0 )
705  {
706  int i;
707 
708  for( i = 0; i < (*polynomialdata)->nmonomials; ++i )
709  {
710  assert((*polynomialdata)->monomials[i] != NULL);
711  SCIPexprFreeMonomial(blkmem, &(*polynomialdata)->monomials[i]);
712  assert((*polynomialdata)->monomials[i] == NULL);
713  }
714 
715  BMSfreeBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize);
716  }
717  assert((*polynomialdata)->monomials == NULL);
718 
719  BMSfreeBlockMemory(blkmem, polynomialdata);
720 }
721 
722 /** ensures that the monomials array of a polynomial has at least a given size */
723 static
725  BMS_BLKMEM* blkmem, /**< block memory data structure */
726  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
727  int minsize /**< minimal size of monomials array */
728  )
729 {
730  assert(blkmem != NULL);
731  assert(polynomialdata != NULL);
732 
733  ensureBlockMemoryArraySize(blkmem, &polynomialdata->monomials, &polynomialdata->monomialssize, minsize);
734  assert(minsize <= polynomialdata->monomialssize);
735 
736  return SCIP_OKAY;
737 }
738 
739 /** adds an array of monomials to a polynomial */
740 static
742  BMS_BLKMEM* blkmem, /**< block memory of expression */
743  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
744  int nmonomials, /**< number of monomials to add */
745  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
746  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
747  )
748 {
749  int i;
750 
751  assert(blkmem != NULL);
752  assert(polynomialdata != NULL);
753  assert(monomials != NULL || nmonomials == 0);
754 
755  if( nmonomials == 0 )
756  return SCIP_OKAY;
757 
758  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials + nmonomials) );
759  assert(polynomialdata->monomialssize >= polynomialdata->nmonomials + nmonomials);
760 
761  if( copymonomials )
762  {
763  for( i = 0; i < nmonomials; ++i )
764  {
765  assert(monomials[i] != NULL); /*lint !e613*/
766  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials + i],
767  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
768  }
769  }
770  else
771  {
772  BMScopyMemoryArray(&polynomialdata->monomials[polynomialdata->nmonomials], monomials, nmonomials); /*lint !e866*/
773  }
774  polynomialdata->nmonomials += nmonomials;
775 
776  polynomialdata->sorted = (polynomialdata->nmonomials <= 1);
777 
778  return SCIP_OKAY;
779 }
780 
781 /** ensures that monomials of a polynomial are sorted */
782 static
784  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata /**< polynomial expression */
785  )
786 {
787  assert(polynomialdata != NULL);
788 
789  if( polynomialdata->sorted )
790  {
791 #ifndef NDEBUG
792  int i;
793 
794  /* a polynom with more than one monoms can only be sorted if its monoms are sorted */
795  for( i = 1; i < polynomialdata->nmonomials; ++i )
796  {
797  assert(polynomialdata->monomials[i-1]->sorted);
798  assert(polynomialdata->monomials[i]->sorted);
799  assert(monomialdataCompare(polynomialdata->monomials[i-1], polynomialdata->monomials[i]) <= 0);
800  }
801 #endif
802  return;
803  }
804 
805  if( polynomialdata->nmonomials > 0 )
806  SCIPsortPtr((void**)polynomialdata->monomials, monomialdataCompare, polynomialdata->nmonomials);
807 
808  polynomialdata->sorted = TRUE;
809 }
810 
811 /** merges monomials that differ only in coefficient into a single monomial
812  *
813  * Eliminates monomials with coefficient between -eps and eps.
814  */
815 static
817  BMS_BLKMEM* blkmem, /**< block memory */
818  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
819  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
820  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
821  )
822 {
823  int i;
824  int offset;
825  int oldnfactors;
826 
827  assert(polynomialdata != NULL);
828  assert(eps >= 0.0);
829 
830  polynomialdataSortMonomials(polynomialdata);
831 
832  /* merge monomials by adding their coefficients, eliminate monomials with no factors or zero coefficient*/
833  offset = 0;
834  i = 0;
835  while( i + offset < polynomialdata->nmonomials )
836  {
837  if( offset > 0 )
838  {
839  assert(polynomialdata->monomials[i] == NULL);
840  assert(polynomialdata->monomials[i+offset] != NULL);
841  polynomialdata->monomials[i] = polynomialdata->monomials[i+offset];
842 #ifndef NDEBUG
843  polynomialdata->monomials[i+offset] = NULL;
844 #endif
845  }
846 
847  if( mergefactors )
848  {
849  oldnfactors = polynomialdata->monomials[i]->nfactors;
850  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i], eps);
851 
852  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
853  if( oldnfactors != polynomialdata->monomials[i]->nfactors )
854  polynomialdata->sorted = FALSE;
855  }
856 
857  while( i+offset+1 < polynomialdata->nmonomials )
858  {
859  assert(polynomialdata->monomials[i+offset+1] != NULL);
860  if( mergefactors )
861  {
862  oldnfactors = polynomialdata->monomials[i+offset+1]->nfactors;
863  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i+offset+1], eps);
864 
865  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
866  if( oldnfactors != polynomialdata->monomials[i+offset+1]->nfactors )
867  polynomialdata->sorted = FALSE;
868  }
869  if( monomialdataCompare((void*)polynomialdata->monomials[i], (void*)polynomialdata->monomials[i+offset+1]) != 0 )
870  break;
871  polynomialdata->monomials[i]->coef += polynomialdata->monomials[i+offset+1]->coef;
872  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i+offset+1]);
873  ++offset;
874  }
875 
876  if( polynomialdata->monomials[i]->nfactors == 0 )
877  {
878  /* constant monomial */
879  polynomialdata->constant += polynomialdata->monomials[i]->coef;
880  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
881  ++offset;
882  continue;
883  }
884 
885  if( EPSZ(polynomialdata->monomials[i]->coef, eps) )
886  {
887  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
888  ++offset;
889  continue;
890  }
891 
892  ++i;
893  }
894 
895 #ifndef NDEBUG
896  while( i < polynomialdata->nmonomials )
897  assert(polynomialdata->monomials[i++] == NULL);
898 #endif
899 
900  polynomialdata->nmonomials -= offset;
901 
902  if( EPSZ(polynomialdata->constant, eps) )
903  polynomialdata->constant = 0.0;
904 }
905 
906 /** multiplies each summand of a polynomial by a given constant */
907 static
909  BMS_BLKMEM* blkmem, /**< block memory */
910  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
911  SCIP_Real factor /**< constant factor */
912  )
913 {
914  int i;
915 
916  assert(polynomialdata != NULL);
917 
918  if( factor == 1.0 )
919  return;
920 
921  if( factor == 0.0 )
922  {
923  for( i = 0; i < polynomialdata->nmonomials; ++i )
924  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
925  polynomialdata->nmonomials = 0;
926  }
927  else
928  {
929  for( i = 0; i < polynomialdata->nmonomials; ++i )
930  SCIPexprChgMonomialCoef(polynomialdata->monomials[i], polynomialdata->monomials[i]->coef * factor);
931  }
932 
933  polynomialdata->constant *= factor;
934 }
935 
936 /** multiplies each summand of a polynomial by a given monomial */
937 static
939  BMS_BLKMEM* blkmem, /**< block memory */
940  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
941  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
942  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
943  )
944 {
945  int i;
946 
947  assert(blkmem != NULL);
948  assert(factor != NULL);
949  assert(polynomialdata != NULL);
950 
951  if( factor->nfactors == 0 )
952  {
953  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factor->coef);
954  return SCIP_OKAY;
955  }
956 
957  /* multiply each monomial by factor */
958  for( i = 0; i < polynomialdata->nmonomials; ++i )
959  {
960  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i], factor, childmap) );
961  }
962 
963  /* add new monomial for constant multiplied by factor */
964  if( polynomialdata->constant != 0.0 )
965  {
966  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
967  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
968  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[polynomialdata->nmonomials], factor, childmap) );
969  ++polynomialdata->nmonomials;
970  polynomialdata->sorted = FALSE;
971  polynomialdata->constant = 0.0;
972  }
973 
974  return SCIP_OKAY;
975 }
976 
977 /** multiplies a polynomial by a polynomial
978  *
979  * Factors need to be different.
980  */
981 static
983  BMS_BLKMEM* blkmem, /**< block memory */
984  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
985  SCIP_EXPRDATA_POLYNOMIAL* factordata, /**< polynomial factor data */
986  int* childmap /**< map children in factor to children in polynomialdata, or NULL for 1:1 */
987  )
988 {
989  int i1;
990  int i2;
991  int orignmonomials;
992 
993  assert(blkmem != NULL);
994  assert(polynomialdata != NULL);
995  assert(factordata != NULL);
996  assert(polynomialdata != factordata);
997 
998  if( factordata->nmonomials == 0 )
999  {
1000  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factordata->constant);
1001  return SCIP_OKAY;
1002  }
1003 
1004  if( factordata->nmonomials == 1 && factordata->constant == 0.0 )
1005  {
1006  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, polynomialdata, factordata->monomials[0], childmap) );
1007  return SCIP_OKAY;
1008  }
1009 
1010  /* turn constant into a monomial, so we can assume below that constant is 0.0 */
1011  if( polynomialdata->constant != 0.0 )
1012  {
1013  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
1014  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
1015  ++polynomialdata->nmonomials;
1016  polynomialdata->sorted = FALSE;
1017  polynomialdata->constant = 0.0;
1018  }
1019 
1020  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials * (factordata->nmonomials + (factordata->constant == 0.0 ? 0 : 1))) );
1021 
1022  /* for each monomial in factordata (except the last, if factordata->constant is 0),
1023  * duplicate monomials from polynomialdata and multiply them by the monomial for factordata */
1024  orignmonomials = polynomialdata->nmonomials;
1025  for( i2 = 0; i2 < factordata->nmonomials; ++i2 )
1026  {
1027  /* add a copy of original monomials to end of polynomialdata's monomials array */
1028  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 */
1029  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, orignmonomials, polynomialdata->monomials, TRUE) );
1030  assert(polynomialdata->nmonomials == (i2+2) * orignmonomials);
1031 
1032  /* multiply each copied monomial by current monomial from factordata */
1033  for( i1 = (i2+1) * orignmonomials; i1 < (i2+2) * orignmonomials; ++i1 )
1034  {
1035  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1036  }
1037 
1038  if( factordata->constant == 0.0 && i2 == factordata->nmonomials - 2 )
1039  {
1040  ++i2;
1041  break;
1042  }
1043  }
1044 
1045  if( factordata->constant != 0.0 )
1046  {
1047  assert(i2 == factordata->nmonomials);
1048  /* multiply original monomials in polynomialdata by constant in factordata */
1049  for( i1 = 0; i1 < orignmonomials; ++i1 )
1050  SCIPexprChgMonomialCoef(polynomialdata->monomials[i1], polynomialdata->monomials[i1]->coef * factordata->constant);
1051  }
1052  else
1053  {
1054  assert(i2 == factordata->nmonomials - 1);
1055  /* multiply original monomials in polynomialdata by last monomial in factordata */
1056  for( i1 = 0; i1 < orignmonomials; ++i1 )
1057  {
1058  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1059  }
1060  }
1061 
1062  return SCIP_OKAY;
1063 }
1064 
1065 /** takes a power of a polynomial
1066  *
1067  * Exponent needs to be an integer,
1068  * polynomial needs to be a monomial, if exponent is negative.
1069  */
1070 static
1072  BMS_BLKMEM* blkmem, /**< block memory */
1073  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1074  int exponent /**< exponent of power operation */
1075  )
1076 {
1077  SCIP_EXPRDATA_POLYNOMIAL* factor;
1078  int i;
1079 
1080  assert(blkmem != NULL);
1081  assert(polynomialdata != NULL);
1082 
1083  if( exponent == 0 )
1084  {
1085  /* x^0 = 1, except if x = 0 */
1086  if( polynomialdata->nmonomials == 0 && polynomialdata->constant == 0.0 )
1087  {
1088  polynomialdata->constant = 0.0;
1089  }
1090  else
1091  {
1092  polynomialdata->constant = 1.0;
1093 
1094  for( i = 0; i < polynomialdata->nmonomials; ++i )
1095  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
1096  polynomialdata->nmonomials = 0;
1097  }
1098 
1099  return SCIP_OKAY;
1100  }
1101 
1102  if( exponent == 1 )
1103  return SCIP_OKAY;
1104 
1105  if( polynomialdata->nmonomials == 1 && polynomialdata->constant == 0.0 )
1106  {
1107  /* polynomial is a single monomial */
1108  SCIPexprMonomialPower(polynomialdata->monomials[0], exponent);
1109  return SCIP_OKAY;
1110  }
1111 
1112  if( polynomialdata->nmonomials == 0 )
1113  {
1114  /* polynomial is a constant */
1115  polynomialdata->constant = pow(polynomialdata->constant, (SCIP_Real)exponent);
1116  return SCIP_OKAY;
1117  }
1118 
1119  assert(exponent >= 2); /* negative exponents not allowed if more than one monom */
1120 
1121  /* todo improve, look how SCIPintervalPowerScalar in intervalarith.c does it */
1122 
1123  /* get copy of our polynomial */
1124  SCIP_CALL( polynomialdataCopy(blkmem, &factor, polynomialdata) );
1125 
1126  /* do repeated multiplication */
1127  for( i = 2; i <= exponent; ++i )
1128  {
1129  SCIP_CALL( polynomialdataMultiplyByPolynomial(blkmem, polynomialdata, factor, NULL) );
1130  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
1131  }
1132 
1133  /* free copy again */
1134  polynomialdataFree(blkmem, &factor);
1135 
1136  return SCIP_OKAY;
1137 }
1138 
1139 /** applies a mapping of child indices to the indices used in polynomial monomials */
1140 static
1142  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1143  int* childmap /**< mapping of child indices */
1144  )
1145 {
1146  SCIP_EXPRDATA_MONOMIAL* monomial;
1147  int i;
1148  int j;
1149 
1150  assert(polynomialdata != NULL);
1151 
1152  for( i = 0; i < polynomialdata->nmonomials; ++i )
1153  {
1154  monomial = polynomialdata->monomials[i];
1155  assert(monomial != NULL);
1156 
1157  for( j = 0; j < monomial->nfactors; ++j )
1158  {
1159  monomial->childidxs[j] = childmap[monomial->childidxs[j]];
1160  assert(monomial->childidxs[j] >= 0);
1161  }
1162  monomial->sorted = FALSE;
1163  }
1164 
1165  polynomialdata->sorted = FALSE;
1166 }
1167 
1168 /** replaces a factor in a monomial by a polynomial and expands the result */
1169 static
1171  BMS_BLKMEM* blkmem, /**< block memory data structure */
1172  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1173  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data where to expand a monomial */
1174  int monomialpos, /**< position of monomial which factor to expand */
1175  int factorpos, /**< position of factor in monomial to expand */
1176  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomial,/**< polynomial that should replace factor */
1177  int* childmap, /**< map of child indices in factorpolynomial to children of polynomial */
1178  int maxexpansionexponent,/**< maximal exponent for which polynomials (with > 1 summands) are expanded */
1179  SCIP_Bool* success /**< buffer to store whether expansion has been done */
1180  )
1181 {
1182  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomialcopy;
1183  SCIP_EXPRDATA_MONOMIAL* monomial;
1184  int i;
1185 
1186  assert(blkmem != NULL);
1187  assert(polynomialdata != NULL);
1188  assert(factorpolynomial != NULL);
1189  assert(childmap != NULL || factorpolynomial->nmonomials == 0);
1190  assert(success != NULL);
1191  assert(monomialpos >= 0);
1192  assert(monomialpos < polynomialdata->nmonomials);
1193  assert(factorpos >= 0);
1194 
1195  monomial = polynomialdata->monomials[monomialpos];
1196  assert(monomial != NULL);
1197  assert(factorpos < monomial->nfactors);
1198 
1199  *success = TRUE;
1200 
1201  if( factorpolynomial->nmonomials == 0 )
1202  {
1203  /* factorpolynomial is a constant */
1204 
1205  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && factorpolynomial->constant < 0.0 ) /*lint !e835*/
1206  {
1207  /* if polynomial is a negative constant and our exponent is not integer, then cannot do expansion */
1208  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", factorpolynomial->constant, monomial->exponents[factorpos]);
1209  *success = FALSE;
1210  return SCIP_OKAY;
1211  }
1212  monomial->coef *= pow(factorpolynomial->constant, monomial->exponents[factorpos]);
1213 
1214  /* move last factor to position factorpos */
1215  if( factorpos < monomial->nfactors-1 )
1216  {
1217  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1218  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1219  }
1220  --monomial->nfactors;
1221  monomial->sorted = FALSE;
1222  polynomialdata->sorted = FALSE;
1223 
1224  return SCIP_OKAY;
1225  }
1226 
1227  if( factorpolynomial->constant == 0.0 && factorpolynomial->nmonomials == 1 )
1228  {
1229  /* factorpolynomial is a single monomial */
1230  SCIP_EXPRDATA_MONOMIAL* factormonomial;
1231  int childidx;
1232  SCIP_Real exponent;
1233 
1234  factormonomial = factorpolynomial->monomials[0];
1235  assert(factormonomial != NULL);
1236 
1237  if( !EPSISINT(monomial->exponents[factorpos], 0.0) ) /*lint !e835*/
1238  {
1239  if( factormonomial->coef < 0.0 )
1240  {
1241  /* if coefficient of monomial is negative and our exponent is not integer, then do not do expansion
1242  * @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
1243  */
1244  *success = FALSE;
1245  return SCIP_OKAY;
1246  }
1247  if( factormonomial->nfactors > 1 )
1248  {
1249  /* @todo if there is an even number of factors in factormonomial that are negative, then they always multiply to something positive
1250  * however, we cannot expand them as below, since we cannot compute the single powers
1251  * since we do not have the bounds on the factors here, we skip expansion in this case
1252  * MINLPLib instances tls2,4,6 are examples where we are loosing here (do not recognize convexity)
1253  */
1254  *success = FALSE;
1255  return SCIP_OKAY;
1256  }
1257  }
1258 
1259  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + factormonomial->nfactors) );
1260 
1261  for( i = 0; i < factormonomial->nfactors; ++i )
1262  {
1263  childidx = childmap[factormonomial->childidxs[i]]; /*lint !e613*/
1264  /* can do this because monomial->exponents[factorpos] is assumed to be integer or factormonomial has positive coefficient and only one factor
1265  * thus, if factormonomial->exponents[i] is fractional, then we can assume that it's argument is positive
1266  */
1267  exponent = factormonomial->exponents[i] * monomial->exponents[factorpos];
1268  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
1269  }
1270 
1271  monomial->coef *= pow(factormonomial->coef, monomial->exponents[factorpos]);
1272 
1273  /* move last factor to position factorpos */
1274  if( factorpos < monomial->nfactors-1 )
1275  {
1276  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1277  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1278  }
1279  --monomial->nfactors;
1280  monomial->sorted = FALSE;
1281  polynomialdata->sorted = FALSE;
1282 
1283  return SCIP_OKAY;
1284  }
1285 
1286  /* if exponent is negative or fractional and the polynomial is not just a monomial, then we cannot do expansion */
1287  if( !EPSISINT(monomial->exponents[factorpos], 0.0) || monomial->exponents[factorpos] < 0.0 ) /*lint !e835*/
1288  {
1289  *success = FALSE;
1290  return SCIP_OKAY;
1291  }
1292 
1293  /* if exponent is too large, skip expansion */
1294  if( monomial->exponents[factorpos] > maxexpansionexponent )
1295  {
1296  *success = FALSE;
1297  return SCIP_OKAY;
1298  }
1299 
1300  /* check whether maximal degree of expansion would exceed maxexpansionexponent
1301  * that is, assume monomial is f1^a1 f2^a2 ... and we want to expand f1 = (g11^beta11 g12^beta12... + g21^beta21 g22^beta22 ... + ...)
1302  * then we do this only if all ai and all beta are > 0.0 and a1 max(beta11+beta12+..., beta21+beta22+..., ...) + a2 + ... < maxexpansionexponent
1303  * exception (there need to be one) is if monomial is just f1
1304  */
1305  if( maxexpansionexponent < INT_MAX && (monomial->nfactors > 1 || monomial->exponents[factorpos] != 1.0) )
1306  {
1307  SCIP_Real restdegree;
1308  SCIP_Real degree;
1309  int j;
1310 
1311  restdegree = -monomial->exponents[factorpos];
1312  for( i = 0; i < monomial->nfactors; ++i )
1313  {
1314  if( monomial->exponents[i] < 0.0 )
1315  {
1316  /* ai < 0.0 */
1317  SCIPdebugMessage("skip expansion because factor %d in monomial has negative exponent\n", i);
1318  *success = FALSE;
1319  return SCIP_OKAY;
1320  }
1321  restdegree += monomial->exponents[i];
1322  }
1323 
1324  for( i = 0; i < factorpolynomial->nmonomials; ++i )
1325  {
1326  degree = 0.0;
1327  for( j = 0; j < factorpolynomial->monomials[i]->nfactors; ++j )
1328  {
1329  if( factorpolynomial->monomials[i]->exponents[j] < 0.0 )
1330  {
1331  /* beta_ij < 0.0 */
1332  SCIPdebugMessage("skip expansion because %d'th factor in %d'th monomial of factorpolynomial is negative\n", i, j);
1333  *success = FALSE;
1334  return SCIP_OKAY;
1335  }
1336  degree += factorpolynomial->monomials[i]->exponents[j];
1337  }
1338  if( degree * monomial->exponents[factorpos] + restdegree > maxexpansionexponent )
1339  {
1340  /* (beta_i1+beta_i2+...)*monomial->exponents[factorpos] + rest > maxexpansion */
1341  SCIPdebugMessage("skip expansion because degree of %d'th monomial would yield degree %g > max = %d in expansion\n",
1342  i, degree * monomial->exponents[factorpos] + restdegree, maxexpansionexponent);
1343  *success = FALSE;
1344  return SCIP_OKAY;
1345  }
1346  }
1347  }
1348 
1349  /* create a copy of factor */
1350  SCIP_CALL( polynomialdataCopy(blkmem, &factorpolynomialcopy, factorpolynomial) );
1351  /* apply childmap to copy */
1352  polynomialdataApplyChildmap(factorpolynomialcopy, childmap);
1353  /* create power of factor */
1354  SCIP_CALL( polynomialdataPower(blkmem, factorpolynomialcopy, (int)EPSFLOOR(monomial->exponents[factorpos], 0.0)) ); /*lint !e835*/
1355 
1356  /* remove factor from monomial by moving last factor to position factorpos */
1357  if( factorpos < monomial->nfactors-1 )
1358  {
1359  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1360  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1361  }
1362  --monomial->nfactors;
1363  monomial->sorted = FALSE;
1364 
1365  /* multiply factor with this reduced monomial */
1366  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, factorpolynomialcopy, monomial, NULL) );
1367 
1368  /* remove monomial from polynomial and move last monomial to monomialpos */
1369  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[monomialpos]);
1370  if( monomialpos < polynomialdata->nmonomials-1 )
1371  polynomialdata->monomials[monomialpos] = polynomialdata->monomials[polynomialdata->nmonomials-1];
1372  --polynomialdata->nmonomials;
1373  polynomialdata->sorted = FALSE;
1374 
1375  /* add factorpolynomialcopy to polynomial */
1376  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, factorpolynomialcopy->nmonomials, factorpolynomialcopy->monomials, FALSE) );
1377  polynomialdata->constant += factorpolynomialcopy->constant;
1378 
1379  factorpolynomialcopy->nmonomials = 0;
1380  polynomialdataFree(blkmem, &factorpolynomialcopy);
1381 
1382  return SCIP_OKAY;
1383 }
1384 
1385 /**@} */
1386 
1387 /**@name Expression operand private methods */
1388 /**@{ */
1389 
1390 /** a default implementation of expression interval evaluation that always gives a correct result */
1391 static
1392 SCIP_DECL_EXPRINTEVAL( exprevalIntDefault )
1393 { /*lint --e{715}*/
1394  SCIPintervalSetEntire(infinity, result);
1395 
1396  return SCIP_OKAY;
1397 }
1398 
1399 /** a default implementation of expression curvature check that always gives a correct result */
1400 static
1401 SCIP_DECL_EXPRCURV( exprcurvDefault )
1402 { /*lint --e{715}*/
1403  *result = SCIP_EXPRCURV_UNKNOWN;
1404 
1405  return SCIP_OKAY;
1406 }
1407 
1408 /** point evaluation for EXPR_VAR */
1409 static
1410 SCIP_DECL_EXPREVAL( exprevalVar )
1411 { /*lint --e{715}*/
1412  assert(result != NULL);
1413  assert(varvals != NULL);
1414 
1415  *result = varvals[opdata.intval];
1416 
1417  return SCIP_OKAY;
1418 }
1419 
1420 /** interval evaluation for EXPR_VAR */
1421 static
1422 SCIP_DECL_EXPRINTEVAL( exprevalIntVar )
1423 { /*lint --e{715}*/
1424  assert(result != NULL);
1425  assert(varvals != NULL);
1426 
1427  *result = varvals[opdata.intval];
1428 
1429  return SCIP_OKAY;
1430 }
1431 
1432 /** curvature for EXPR_VAR */
1433 static
1434 SCIP_DECL_EXPRCURV( exprcurvVar )
1435 { /*lint --e{715}*/
1436  assert(result != NULL);
1437 
1438  *result = SCIP_EXPRCURV_LINEAR;
1439 
1440  return SCIP_OKAY;
1441 }
1442 
1443 /** point evaluation for EXPR_CONST */
1444 static
1445 SCIP_DECL_EXPREVAL( exprevalConst )
1446 { /*lint --e{715}*/
1447  assert(result != NULL);
1448 
1449  *result = opdata.dbl;
1450 
1451  return SCIP_OKAY;
1452 }
1453 
1454 /** interval evaluation for EXPR_CONST */
1455 static
1456 SCIP_DECL_EXPRINTEVAL( exprevalIntConst )
1457 { /*lint --e{715}*/
1458  assert(result != NULL);
1459 
1460  SCIPintervalSet(result, opdata.dbl);
1461 
1462  return SCIP_OKAY;
1463 }
1464 
1465 /** curvature for EXPR_CONST */
1466 static
1467 SCIP_DECL_EXPRCURV( exprcurvConst )
1468 { /*lint --e{715}*/
1469  assert(result != NULL);
1470 
1471  *result = SCIP_EXPRCURV_LINEAR;
1472 
1473  return SCIP_OKAY;
1474 }
1475 
1476 /** point evaluation for EXPR_PARAM */
1477 static
1478 SCIP_DECL_EXPREVAL( exprevalParam )
1479 { /*lint --e{715}*/
1480  assert(result != NULL);
1481  assert(paramvals != NULL );
1482 
1483  *result = paramvals[opdata.intval];
1484 
1485  return SCIP_OKAY;
1486 }
1487 
1488 /** interval evaluation for EXPR_PARAM */
1489 static
1490 SCIP_DECL_EXPRINTEVAL( exprevalIntParam )
1491 { /*lint --e{715}*/
1492  assert(result != NULL);
1493  assert(paramvals != NULL );
1494 
1495  SCIPintervalSet(result, paramvals[opdata.intval]);
1496 
1497  return SCIP_OKAY;
1498 }
1499 
1500 /** curvature for EXPR_PARAM */
1501 static
1502 SCIP_DECL_EXPRCURV( exprcurvParam )
1503 { /*lint --e{715}*/
1504  assert(result != NULL);
1505 
1506  *result = SCIP_EXPRCURV_LINEAR;
1507 
1508  return SCIP_OKAY;
1509 }
1510 
1511 /** point evaluation for EXPR_PLUS */
1512 static
1513 SCIP_DECL_EXPREVAL( exprevalPlus )
1514 { /*lint --e{715}*/
1515  assert(result != NULL);
1516  assert(argvals != NULL);
1517 
1518  *result = argvals[0] + argvals[1];
1519 
1520  return SCIP_OKAY;
1521 }
1522 
1523 /** interval evaluation for EXPR_PLUS */
1524 static
1525 SCIP_DECL_EXPRINTEVAL( exprevalIntPlus )
1526 { /*lint --e{715}*/
1527  assert(result != NULL);
1528  assert(argvals != NULL);
1529 
1530  SCIPintervalAdd(infinity, result, argvals[0], argvals[1]);
1531 
1532  return SCIP_OKAY;
1533 }
1534 
1535 /** curvature for EXPR_PLUS */
1536 static
1537 SCIP_DECL_EXPRCURV( exprcurvPlus )
1538 { /*lint --e{715}*/
1539  assert(result != NULL);
1540  assert(argcurv != NULL);
1541 
1542  *result = SCIPexprcurvAdd(argcurv[0], argcurv[1]);
1543 
1544  return SCIP_OKAY;
1545 }
1546 
1547 /** point evaluation for EXPR_MINUS */
1548 static
1549 SCIP_DECL_EXPREVAL( exprevalMinus )
1550 { /*lint --e{715}*/
1551  assert(result != NULL);
1552  assert(argvals != NULL);
1553 
1554  *result = argvals[0] - argvals[1];
1555 
1556  return SCIP_OKAY;
1557 }
1558 
1559 /** interval evaluation for EXPR_MINUS */
1560 static
1561 SCIP_DECL_EXPRINTEVAL( exprevalIntMinus )
1562 { /*lint --e{715}*/
1563  assert(result != NULL);
1564  assert(argvals != NULL);
1565 
1566  SCIPintervalSub(infinity, result, argvals[0], argvals[1]);
1567 
1568  return SCIP_OKAY;
1569 }
1570 
1571 /** curvature for EXPR_MINUS */
1572 static
1573 SCIP_DECL_EXPRCURV( exprcurvMinus )
1574 { /*lint --e{715}*/
1575  assert(result != NULL);
1576  assert(argcurv != NULL);
1577 
1578  *result = SCIPexprcurvAdd(argcurv[0], SCIPexprcurvNegate(argcurv[1]));
1579 
1580  return SCIP_OKAY;
1581 }
1582 
1583 /** point evaluation for EXPR_MUL */
1584 static
1585 SCIP_DECL_EXPREVAL( exprevalMult )
1586 { /*lint --e{715}*/
1587  assert(result != NULL);
1588  assert(argvals != NULL);
1589 
1590  *result = argvals[0] * argvals[1];
1591 
1592  return SCIP_OKAY;
1593 }
1594 
1595 /** interval evaluation for EXPR_MUL */
1596 static
1597 SCIP_DECL_EXPRINTEVAL( exprevalIntMult )
1598 { /*lint --e{715}*/
1599  assert(result != NULL);
1600  assert(argvals != NULL);
1601 
1602  SCIPintervalMul(infinity, result, argvals[0], argvals[1]);
1603 
1604  return SCIP_OKAY;
1605 }
1606 
1607 /** curvature for EXPR_MUL */
1608 static
1609 SCIP_DECL_EXPRCURV( exprcurvMult )
1610 { /*lint --e{715}*/
1611  assert(result != NULL);
1612  assert(argcurv != NULL);
1613  assert(argbounds != NULL);
1614 
1615  /* if one factor is constant, then product is
1616  * - linear, if constant is 0.0
1617  * - same curvature as other factor, if constant is positive
1618  * - negated curvature of other factor, if constant is negative
1619  *
1620  * if both factors are not constant, then product may not be convex nor concave
1621  */
1622  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1623  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1624  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1625  *result = SCIPexprcurvMultiply(argbounds[0].inf, argcurv[1]);
1626  else
1627  *result = SCIP_EXPRCURV_UNKNOWN;
1628 
1629  return SCIP_OKAY;
1630 }
1631 
1632 /** point evaluation for EXPR_DIV */
1633 static
1634 SCIP_DECL_EXPREVAL( exprevalDiv )
1635 { /*lint --e{715}*/
1636  assert(result != NULL);
1637  assert(argvals != NULL);
1638 
1639  *result = argvals[0] / argvals[1];
1640 
1641  return SCIP_OKAY;
1642 }
1643 
1644 /** interval evaluation for EXPR_DIV */
1645 static
1646 SCIP_DECL_EXPRINTEVAL( exprevalIntDiv )
1647 { /*lint --e{715}*/
1648  assert(result != NULL);
1649  assert(argvals != NULL);
1650 
1651  SCIPintervalDiv(infinity, result, argvals[0], argvals[1]);
1652 
1653  return SCIP_OKAY;
1654 }
1655 
1656 /** curvature for EXPR_DIV */
1657 static
1658 SCIP_DECL_EXPRCURV( exprcurvDiv )
1659 { /*lint --e{715}*/
1660  assert(result != NULL);
1661  assert(argcurv != NULL);
1662  assert(argbounds != NULL);
1663 
1664  /* if denominator is constant, then quotient has curvature sign(denominator) * curv(nominator)
1665  *
1666  * if nominator is a constant, then quotient is
1667  * - sign(nominator) * convex, if denominator is concave and positive
1668  * - sign(nominator) * concave, if denominator is convex and negative
1669  *
1670  * if denominator is positive but convex, then we don't know, e.g.,
1671  * - 1/x^2 is convex for x>=0
1672  * - 1/(1+(x-1)^2) is neither convex nor concave for x >= 0
1673  *
1674  * if both nominator and denominator are not constant, then quotient may not be convex nor concave
1675  */
1676  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1677  {
1678  /* denominator is constant */
1679  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1680  }
1681  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1682  {
1683  /* nominator is constant */
1684  if( argbounds[1].inf >= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
1685  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONVEX);
1686  else if( argbounds[1].sup <= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
1687  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONCAVE);
1688  else
1689  *result = SCIP_EXPRCURV_UNKNOWN;
1690  }
1691  else
1692  {
1693  /* denominator and nominator not constant */
1694  *result = SCIP_EXPRCURV_UNKNOWN;
1695  }
1696 
1697  return SCIP_OKAY;
1698 }
1699 
1700 /** point evaluation for EXPR_SQUARE */
1701 static
1702 SCIP_DECL_EXPREVAL( exprevalSquare )
1703 { /*lint --e{715}*/
1704  assert(result != NULL);
1705  assert(argvals != NULL);
1706 
1707  *result = argvals[0] * argvals[0];
1708 
1709  return SCIP_OKAY;
1710 }
1711 
1712 /** interval evaluation for EXPR_SQUARE */
1713 static
1714 SCIP_DECL_EXPRINTEVAL( exprevalIntSquare )
1715 { /*lint --e{715}*/
1716  assert(result != NULL);
1717  assert(argvals != NULL);
1718 
1719  SCIPintervalSquare(infinity, result, argvals[0]);
1720 
1721  return SCIP_OKAY;
1722 }
1723 
1724 /** curvature for EXPR_SQUARE */
1725 static
1726 SCIP_DECL_EXPRCURV( exprcurvSquare )
1727 { /*lint --e{715}*/
1728  assert(result != NULL);
1729  assert(argcurv != NULL);
1730  assert(argbounds != NULL);
1731 
1732  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], 2.0);
1733 
1734  return SCIP_OKAY;
1735 }
1736 
1737 /** point evaluation for EXPR_SQRT */
1738 static
1739 SCIP_DECL_EXPREVAL( exprevalSquareRoot )
1740 { /*lint --e{715}*/
1741  assert(result != NULL);
1742  assert(argvals != NULL);
1743 
1744  *result = sqrt(argvals[0]);
1745 
1746  return SCIP_OKAY;
1747 }
1748 
1749 /** interval evaluation for EXPR_SQRT */
1750 static
1751 SCIP_DECL_EXPRINTEVAL( exprevalIntSquareRoot )
1752 { /*lint --e{715}*/
1753  assert(result != NULL);
1754  assert(argvals != NULL);
1755 
1756  SCIPintervalSquareRoot(infinity, result, argvals[0]);
1757 
1758  return SCIP_OKAY;
1759 }
1760 
1761 /** curvature for EXPR_SQRT */
1762 static
1763 SCIP_DECL_EXPRCURV( exprcurvSquareRoot )
1764 { /*lint --e{715}*/
1765  assert(result != NULL);
1766  assert(argcurv != NULL);
1767 
1768  /* square-root is concave, if child is concave
1769  * otherwise, we don't know
1770  */
1771 
1772  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
1773  *result = SCIP_EXPRCURV_CONCAVE;
1774  else
1775  *result = SCIP_EXPRCURV_UNKNOWN;
1776 
1777  return SCIP_OKAY;
1778 }
1779 
1780 /** point evaluation for EXPR_REALPOWER */
1781 static
1782 SCIP_DECL_EXPREVAL( exprevalRealPower )
1783 { /*lint --e{715}*/
1784  assert(result != NULL);
1785  assert(argvals != NULL);
1786 
1787  *result = pow(argvals[0], opdata.dbl);
1788 
1789  return SCIP_OKAY;
1790 }
1791 
1792 /** interval evaluation for EXPR_REALPOWER */
1793 static
1794 SCIP_DECL_EXPRINTEVAL( exprevalIntRealPower )
1795 { /*lint --e{715}*/
1796  assert(result != NULL);
1797  assert(argvals != NULL);
1798 
1799  SCIPintervalPowerScalar(infinity, result, argvals[0], opdata.dbl);
1800 
1801  return SCIP_OKAY;
1802 }
1803 
1804 /** curvature for EXPR_REALPOWER */
1805 static
1806 SCIP_DECL_EXPRCURV( exprcurvRealPower )
1807 { /*lint --e{715}*/
1808  assert(result != NULL);
1809  assert(argcurv != NULL);
1810  assert(argbounds != NULL);
1811 
1812  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], opdata.dbl);
1813 
1814  return SCIP_OKAY;
1815 }
1816 
1817 /** point evaluation for EXPR_INTPOWER */
1818 static
1819 SCIP_DECL_EXPREVAL( exprevalIntPower )
1820 { /*lint --e{715}*/
1821  assert(result != NULL);
1822  assert(argvals != NULL);
1823 
1824  switch( opdata.intval )
1825  {
1826  case -1:
1827  *result = 1.0 / argvals[0];
1828  return SCIP_OKAY;
1829 
1830  case 0:
1831  *result = 1.0;
1832  return SCIP_OKAY;
1833 
1834  case 1:
1835  *result = argvals[0];
1836  return SCIP_OKAY;
1837 
1838  case 2:
1839  *result = argvals[0] * argvals[0];
1840  return SCIP_OKAY;
1841 
1842  default:
1843  *result = pow(argvals[0], (SCIP_Real)opdata.intval);
1844  }
1845 
1846  return SCIP_OKAY;
1847 }
1848 
1849 /** interval evaluation for EXPR_INTPOWER */
1850 static
1851 SCIP_DECL_EXPRINTEVAL( exprevalIntIntPower )
1852 { /*lint --e{715}*/
1853  assert(result != NULL);
1854  assert(argvals != NULL);
1855 
1856  SCIPintervalPowerScalar(infinity, result, argvals[0], (SCIP_Real)opdata.intval);
1857 
1858  return SCIP_OKAY;
1859 }
1860 
1861 /** curvature for EXPR_INTPOWER */
1862 static
1863 SCIP_DECL_EXPRCURV( exprcurvIntPower )
1864 { /*lint --e{715}*/
1865  assert(result != NULL);
1866  assert(argcurv != NULL);
1867  assert(argbounds != NULL);
1868 
1869  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], (SCIP_Real)opdata.intval);
1870 
1871  return SCIP_OKAY;
1872 }
1873 
1874 /** point evaluation for EXPR_SIGNPOWER */
1875 static
1876 SCIP_DECL_EXPREVAL( exprevalSignPower )
1877 { /*lint --e{715}*/
1878  assert(result != NULL);
1879  assert(argvals != NULL);
1880 
1881  if( argvals[0] > 0 )
1882  *result = pow( argvals[0], opdata.dbl);
1883  else
1884  *result = -pow(-argvals[0], opdata.dbl);
1885 
1886  return SCIP_OKAY;
1887 }
1888 
1889 /** interval evaluation for EXPR_SIGNPOWER */
1890 static
1891 SCIP_DECL_EXPRINTEVAL( exprevalIntSignPower )
1892 { /*lint --e{715}*/
1893  assert(result != NULL);
1894  assert(argvals != NULL);
1895 
1896  SCIPintervalSignPowerScalar(infinity, result, argvals[0], opdata.dbl);
1897 
1898  return SCIP_OKAY;
1899 }
1900 
1901 /** curvature for EXPR_SIGNPOWER */
1902 static
1903 SCIP_DECL_EXPRCURV( exprcurvSignPower )
1904 { /*lint --e{715}*/
1905  SCIP_INTERVAL tmp;
1906  SCIP_EXPRCURV left;
1907  SCIP_EXPRCURV right;
1908 
1909  assert(result != NULL);
1910  assert(argcurv != NULL);
1911  assert(argbounds != NULL);
1912 
1913  /* for x <= 0, signpower(x,c) = -(-x)^c
1914  * for x >= 0, signpower(x,c) = ( x)^c
1915  *
1916  * thus, get curvatures for both parts and "intersect" them
1917  */
1918 
1919  if( argbounds[0].inf < 0 )
1920  {
1921  SCIPintervalSetBounds(&tmp, 0.0, -argbounds[0].inf);
1922  left = SCIPexprcurvNegate(SCIPexprcurvPower(tmp, SCIPexprcurvNegate(argcurv[0]), opdata.dbl));
1923  }
1924  else
1925  {
1926  left = SCIP_EXPRCURV_LINEAR;
1927  }
1928 
1929  if( argbounds[0].sup > 0 )
1930  {
1931  SCIPintervalSetBounds(&tmp, 0.0, argbounds[0].sup);
1932  right = SCIPexprcurvPower(tmp, argcurv[0], opdata.dbl);
1933  }
1934  else
1935  {
1936  right = SCIP_EXPRCURV_LINEAR;
1937  }
1938 
1939  *result = (SCIP_EXPRCURV) (left & right);
1940 
1941  return SCIP_OKAY;
1942 }
1943 
1944 /** point evaluation for EXPR_EXP */
1945 static
1946 SCIP_DECL_EXPREVAL( exprevalExp )
1947 { /*lint --e{715}*/
1948  assert(result != NULL);
1949  assert(argvals != NULL);
1950 
1951  *result = exp(argvals[0]);
1952 
1953  return SCIP_OKAY;
1954 }
1955 
1956 /** interval evaluation for EXPR_EXP */
1957 static
1958 SCIP_DECL_EXPRINTEVAL( exprevalIntExp )
1959 { /*lint --e{715}*/
1960  assert(result != NULL);
1961  assert(argvals != NULL);
1962 
1963  SCIPintervalExp(infinity, result, argvals[0]);
1964 
1965  return SCIP_OKAY;
1966 }
1967 
1968 /** curvature for EXPR_EXP */
1969 static
1970 SCIP_DECL_EXPRCURV( exprcurvExp )
1971 { /*lint --e{715}*/
1972  assert(result != NULL);
1973  assert(argcurv != NULL);
1974 
1975  /* expression is convex if child is convex
1976  * otherwise, we don't know
1977  */
1978  if( argcurv[0] & SCIP_EXPRCURV_CONVEX )
1979  *result = SCIP_EXPRCURV_CONVEX;
1980  else
1981  *result = SCIP_EXPRCURV_UNKNOWN;
1982 
1983  return SCIP_OKAY;
1984 }
1985 
1986 /** point evaluation for EXPR_LOG */
1987 static
1988 SCIP_DECL_EXPREVAL( exprevalLog )
1989 { /*lint --e{715}*/
1990  assert(result != NULL);
1991  assert(argvals != NULL);
1992 
1993  *result = log(argvals[0]);
1994 
1995  return SCIP_OKAY;
1996 }
1997 
1998 /** interval evaluation for EXPR_LOG */
1999 static
2000 SCIP_DECL_EXPRINTEVAL( exprevalIntLog )
2001 { /*lint --e{715}*/
2002  assert(result != NULL);
2003  assert(argvals != NULL);
2004 
2005  SCIPintervalLog(infinity, result, argvals[0]);
2006 
2007  return SCIP_OKAY;
2008 }
2009 
2010 /** curvature for EXPR_LOG */
2011 static
2012 SCIP_DECL_EXPRCURV( exprcurvLog )
2013 { /*lint --e{715}*/
2014  assert(result != NULL);
2015  assert(argcurv != NULL);
2016 
2017  /* expression is concave if child is concave
2018  * otherwise, we don't know
2019  */
2020  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
2021  *result = SCIP_EXPRCURV_CONCAVE;
2022  else
2023  *result = SCIP_EXPRCURV_UNKNOWN;
2024 
2025  return SCIP_OKAY;
2026 }
2027 
2028 /** point evaluation for EXPR_SIN */
2029 static
2030 SCIP_DECL_EXPREVAL( exprevalSin )
2031 { /*lint --e{715}*/
2032  assert(result != NULL);
2033  assert(argvals != NULL);
2034 
2035  *result = sin(argvals[0]);
2036 
2037  return SCIP_OKAY;
2038 }
2039 
2040 /** interval evaluation for EXPR_SIN */
2041 static
2042 SCIP_DECL_EXPRINTEVAL( exprevalIntSin )
2043 { /*lint --e{715}*/
2044  assert(result != NULL);
2045  assert(argvals != NULL);
2046 
2047  /* @todo implement SCIPintervalSin */
2048  SCIPerrorMessage("exprevalSinInt gives only trivial bounds so far\n");
2049  SCIPintervalSetBounds(result, -1.0, 1.0);
2050 
2051  return SCIP_OKAY;
2052 }
2053 
2054 /* @todo implement exprcurvSin */
2055 #define exprcurvSin exprcurvDefault
2056 
2057 /** point evaluation for EXPR_COS */
2058 static
2059 SCIP_DECL_EXPREVAL( exprevalCos )
2060 { /*lint --e{715}*/
2061  assert(result != NULL);
2062  assert(argvals != NULL);
2063 
2064  *result = cos(argvals[0]);
2065 
2066  return SCIP_OKAY;
2067 }
2068 
2069 /** interval evaluation for EXPR_COS */
2070 static
2071 SCIP_DECL_EXPRINTEVAL( exprevalIntCos )
2072 { /*lint --e{715}*/
2073  assert(result != NULL);
2074  assert(argvals != NULL);
2075 
2076  /* @todo implement SCIPintervalCos */
2077  SCIPerrorMessage("exprevalCosInt gives only trivial bounds so far\n");
2078  SCIPintervalSetBounds(result, -1.0, 1.0);
2079 
2080  return SCIP_OKAY;
2081 }
2082 
2083 /* @todo implement exprcurvCos */
2084 #define exprcurvCos exprcurvDefault
2085 
2086 /** point evaluation for EXPR_TAN */
2087 static
2088 SCIP_DECL_EXPREVAL( exprevalTan )
2089 { /*lint --e{715}*/
2090  assert(result != NULL);
2091  assert(argvals != NULL);
2092 
2093  *result = tan(argvals[0]);
2094 
2095  return SCIP_OKAY;
2096 }
2097 
2098 /* @todo implement SCIPintervalTan */
2099 #define exprevalIntTan exprevalIntDefault
2100 
2101 /* @todo implement exprcurvTan */
2102 #define exprcurvTan exprcurvDefault
2103 
2104 /* erf and erfi do not seem to exist on every system, and we cannot really handle them anyway, so they are currently disabled */
2105 #ifdef SCIP_DISABLED_CODE
2106 static
2107 SCIP_DECL_EXPREVAL( exprevalErf )
2108 { /*lint --e{715}*/
2109  assert(result != NULL);
2110  assert(argvals != NULL);
2111 
2112  *result = erf(argvals[0]);
2113 
2114  return SCIP_OKAY;
2115 }
2116 
2117 /* @todo implement SCIPintervalErf */
2118 #define exprevalIntErf exprevalIntDefault
2119 
2120 /* @todo implement SCIPintervalErf */
2121 #define exprcurvErf exprcurvDefault
2122 
2123 static
2124 SCIP_DECL_EXPREVAL( exprevalErfi )
2125 { /*lint --e{715}*/
2126  assert(result != NULL);
2127  assert(argvals != NULL);
2128 
2129  /* @TODO implement erfi evaluation */
2130  SCIPerrorMessage("erfi not implemented");
2131 
2132  return SCIP_ERROR;
2133 }
2134 
2135 /* @todo implement SCIPintervalErfi */
2136 #define exprevalIntErfi NULL
2137 
2138 #define exprcurvErfi exprcurvDefault
2139 #endif
2140 
2141 /** point evaluation for EXPR_MIN */
2142 static
2143 SCIP_DECL_EXPREVAL( exprevalMin )
2144 { /*lint --e{715}*/
2145  assert(result != NULL);
2146  assert(argvals != NULL);
2147 
2148  *result = MIN(argvals[0], argvals[1]);
2149 
2150  return SCIP_OKAY;
2151 }
2152 
2153 /** interval evaluation for EXPR_MIN */
2154 static
2155 SCIP_DECL_EXPRINTEVAL( exprevalIntMin )
2156 { /*lint --e{715}*/
2157  assert(result != NULL);
2158  assert(argvals != NULL);
2159 
2160  SCIPintervalMin(result, argvals[0], argvals[1]);
2161 
2162  return SCIP_OKAY;
2163 }
2164 
2165 /** curvature for EXPR_MIN */
2166 static
2167 SCIP_DECL_EXPRCURV( exprcurvMin )
2168 { /*lint --e{715}*/
2169  assert(result != NULL);
2170  assert(argcurv != NULL);
2171 
2172  /* the minimum of two concave functions is concave
2173  * otherwise, we don't know
2174  */
2175 
2176  if( (argcurv[0] & SCIP_EXPRCURV_CONCAVE) && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
2177  *result = SCIP_EXPRCURV_CONCAVE;
2178  else
2179  *result = SCIP_EXPRCURV_UNKNOWN;
2180 
2181  return SCIP_OKAY;
2182 }
2183 
2184 /** point evaluation for EXPR_MAX */
2185 static
2186 SCIP_DECL_EXPREVAL( exprevalMax )
2187 { /*lint --e{715}*/
2188  assert(result != NULL);
2189  assert(argvals != NULL);
2190 
2191  *result = MAX(argvals[0], argvals[1]);
2192 
2193  return SCIP_OKAY;
2194 }
2195 
2196 /** interval evaluation for EXPR_MAX */
2197 static
2198 SCIP_DECL_EXPRINTEVAL( exprevalIntMax )
2199 { /*lint --e{715}*/
2200  assert(result != NULL);
2201  assert(argvals != NULL);
2202 
2203  SCIPintervalMax(result, argvals[0], argvals[1]);
2204 
2205  return SCIP_OKAY;
2206 }
2207 
2208 /** curvature for EXPR_MAX */
2209 static
2210 SCIP_DECL_EXPRCURV( exprcurvMax )
2211 { /*lint --e{715}*/
2212  assert(result != NULL);
2213  assert(argcurv != NULL);
2214 
2215  /* the maximum of two convex functions is convex
2216  * otherwise, we don't know
2217  */
2218  if( (argcurv[0] & SCIP_EXPRCURV_CONVEX) && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
2219  *result = SCIP_EXPRCURV_CONVEX;
2220  else
2221  *result = SCIP_EXPRCURV_UNKNOWN;
2222 
2223  return SCIP_OKAY;
2224 }
2225 
2226 /** point evaluation for EXPR_ABS */
2227 static
2228 SCIP_DECL_EXPREVAL( exprevalAbs )
2229 { /*lint --e{715}*/
2230  assert(result != NULL);
2231  assert(argvals != NULL);
2232 
2233  *result = ABS(argvals[0]);
2234 
2235  return SCIP_OKAY;
2236 }
2237 
2238 /** interval evaluation for EXPR_ABS */
2239 static
2240 SCIP_DECL_EXPRINTEVAL( exprevalIntAbs )
2241 { /*lint --e{715}*/
2242  assert(result != NULL);
2243  assert(argvals != NULL);
2244 
2245  SCIPintervalAbs(result, argvals[0]);
2246 
2247  return SCIP_OKAY;
2248 }
2249 
2250 /** curvature for EXPR_ABS */
2251 static
2252 SCIP_DECL_EXPRCURV( exprcurvAbs )
2253 { /*lint --e{715}*/
2254  assert(result != NULL);
2255  assert(argcurv != NULL);
2256  assert(argbounds != NULL);
2257 
2258  /* if child is only negative, then abs(child) = -child
2259  * if child is only positive, then abs(child) = child
2260  * if child is both positive and negative, but also linear, then abs(child) is convex
2261  * otherwise, we don't know
2262  */
2263  if( argbounds[0].sup <= 0.0 )
2264  *result = SCIPexprcurvMultiply(-1.0, argcurv[0]);
2265  else if( argbounds[0].inf >= 0.0 )
2266  *result = argcurv[0];
2267  else if( argcurv[0] == SCIP_EXPRCURV_LINEAR )
2268  *result = SCIP_EXPRCURV_CONVEX;
2269  else
2270  *result = SCIP_EXPRCURV_UNKNOWN;
2271 
2272  return SCIP_OKAY;
2273 }
2274 
2275 /** point evaluation for EXPR_SIGN */
2276 static
2277 SCIP_DECL_EXPREVAL( exprevalSign )
2278 { /*lint --e{715}*/
2279  assert(result != NULL);
2280  assert(argvals != NULL);
2281 
2282  *result = SIGN(argvals[0]);
2283 
2284  return SCIP_OKAY;
2285 }
2286 
2287 /** interval evaluation for EXPR_SIGN */
2288 static
2289 SCIP_DECL_EXPRINTEVAL( exprevalIntSign )
2290 { /*lint --e{715}*/
2291  assert(result != NULL);
2292  assert(argvals != NULL);
2293 
2294  SCIPintervalSign(result, argvals[0]);
2295 
2296  return SCIP_OKAY;
2297 }
2298 
2299 /** curvature for EXPR_SIGN */
2300 static
2301 SCIP_DECL_EXPRCURV( exprcurvSign )
2302 { /*lint --e{715}*/
2303  assert(result != NULL);
2304  assert(argbounds != NULL);
2305 
2306  /* if sign of child is clear, then sign is linear otherwise, we don't know */
2307  if( argbounds[0].sup <= 0.0 || argbounds[0].inf >= 0.0 )
2308  *result = SCIP_EXPRCURV_LINEAR;
2309  else
2310  *result = SCIP_EXPRCURV_UNKNOWN;
2311 
2312  return SCIP_OKAY;
2313 }
2314 
2315 /** point evaluation for EXPR_SUM */
2316 static
2317 SCIP_DECL_EXPREVAL( exprevalSum )
2318 { /*lint --e{715}*/
2319  int i;
2320 
2321  assert(result != NULL);
2322  assert(argvals != NULL);
2323 
2324  *result = 0.0;
2325  for( i = 0; i < nargs; ++i )
2326  *result += argvals[i];
2327 
2328  return SCIP_OKAY;
2329 }
2330 
2331 /** interval evaluation for EXPR_SUM */
2332 static
2333 SCIP_DECL_EXPRINTEVAL( exprevalIntSum )
2334 { /*lint --e{715}*/
2335  int i;
2336 
2337  assert(result != NULL);
2338  assert(argvals != NULL);
2339 
2340  SCIPintervalSet(result, 0.0);
2341 
2342  for( i = 0; i < nargs; ++i )
2343  SCIPintervalAdd(infinity, result, *result, argvals[i]);
2344 
2345  return SCIP_OKAY;
2346 }
2347 
2348 /** curvature for EXPR_SUM */
2349 static
2350 SCIP_DECL_EXPRCURV( exprcurvSum )
2351 { /*lint --e{715}*/
2352  int i;
2353 
2354  assert(result != NULL);
2355  assert(argcurv != NULL);
2356 
2357  *result = SCIP_EXPRCURV_LINEAR;
2358 
2359  for( i = 0; i < nargs; ++i )
2360  *result = SCIPexprcurvAdd(*result, argcurv[i]);
2361 
2362  return SCIP_OKAY;
2363 }
2364 
2365 /** point evaluation for EXPR_PRODUCT */
2366 static
2367 SCIP_DECL_EXPREVAL( exprevalProduct )
2368 { /*lint --e{715}*/
2369  int i;
2370 
2371  assert(result != NULL);
2372  assert(argvals != NULL);
2373 
2374  *result = 1.0;
2375  for( i = 0; i < nargs; ++i )
2376  *result *= argvals[i];
2377 
2378  return SCIP_OKAY;
2379 }
2380 
2381 /** interval evaluation for EXPR_PRODUCT */
2382 static
2383 SCIP_DECL_EXPRINTEVAL( exprevalIntProduct )
2384 { /*lint --e{715}*/
2385  int i;
2386 
2387  assert(result != NULL);
2388  assert(argvals != NULL);
2389 
2390  SCIPintervalSet(result, 1.0);
2391 
2392  for( i = 0; i < nargs; ++i )
2393  SCIPintervalMul(infinity, result, *result, argvals[i]);
2394 
2395  return SCIP_OKAY;
2396 }
2397 
2398 /** curvature for EXPR_PRODUCT */
2399 static
2400 SCIP_DECL_EXPRCURV( exprcurvProduct )
2401 { /*lint --e{715}*/
2402  SCIP_Bool hadnonconst;
2403  SCIP_Real constants;
2404  int i;
2405 
2406  assert(result != NULL);
2407  assert(argcurv != NULL);
2408  assert(argbounds != NULL);
2409 
2410  /* if all factors are constant, then product is linear (even constant)
2411  * if only one factor is not constant, then product is curvature of this factor, multiplied by sign of product of remaining factors
2412  */
2413  *result = SCIP_EXPRCURV_LINEAR;
2414  hadnonconst = FALSE;
2415  constants = 1.0;
2416 
2417  for( i = 0; i < nargs; ++i )
2418  {
2419  if( argbounds[i].inf == argbounds[i].sup ) /*lint !e777*/
2420  {
2421  constants *= argbounds[i].inf;
2422  }
2423  else if( !hadnonconst )
2424  {
2425  /* first non-constant child */
2426  *result = argcurv[i];
2427  hadnonconst = TRUE;
2428  }
2429  else
2430  {
2431  /* more than one non-constant child, thus don't know curvature */
2432  *result = SCIP_EXPRCURV_UNKNOWN;
2433  break;
2434  }
2435  }
2436 
2437  *result = SCIPexprcurvMultiply(constants, *result);
2438 
2439  return SCIP_OKAY;
2440 }
2441 
2442 /** point evaluation for EXPR_LINEAR */
2443 static
2444 SCIP_DECL_EXPREVAL( exprevalLinear )
2445 { /*lint --e{715}*/
2446  SCIP_Real* coef;
2447  int i;
2448 
2449  assert(result != NULL);
2450  assert(argvals != NULL || nargs == 0);
2451  assert(opdata.data != NULL);
2452 
2453  coef = &((SCIP_Real*)opdata.data)[nargs];
2454 
2455  *result = *coef;
2456  for( i = nargs-1, --coef; i >= 0; --i, --coef )
2457  *result += *coef * argvals[i]; /*lint !e613*/
2458 
2459  assert(++coef == (SCIP_Real*)opdata.data);
2460 
2461  return SCIP_OKAY;
2462 }
2463 
2464 /** interval evaluation for EXPR_LINEAR */
2465 static
2466 SCIP_DECL_EXPRINTEVAL( exprevalIntLinear )
2467 { /*lint --e{715}*/
2468  assert(result != NULL);
2469  assert(argvals != NULL || nargs == 0);
2470  assert(opdata.data != NULL);
2471 
2472  SCIPintervalScalprodScalars(infinity, result, nargs, argvals, (SCIP_Real*)opdata.data);
2473  SCIPintervalAddScalar(infinity, result, *result, ((SCIP_Real*)opdata.data)[nargs]);
2474 
2475  return SCIP_OKAY;
2476 }
2477 
2478 /** curvature for EXPR_LINEAR */
2479 static
2480 SCIP_DECL_EXPRCURV( exprcurvLinear )
2481 { /*lint --e{715}*/
2482  SCIP_Real* data;
2483  int i;
2484 
2485  assert(result != NULL);
2486  assert(argcurv != NULL);
2487 
2488  data = (SCIP_Real*)opdata.data;
2489  assert(data != NULL);
2490 
2491  *result = SCIP_EXPRCURV_LINEAR;
2492 
2493  for( i = 0; i < nargs; ++i )
2494  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(data[i], argcurv[i]));
2495 
2496  return SCIP_OKAY;
2497 }
2498 
2499 /** expression data copy for EXPR_LINEAR */
2500 static
2501 SCIP_DECL_EXPRCOPYDATA( exprCopyDataLinear )
2502 { /*lint --e{715}*/
2503  SCIP_Real* targetdata;
2504 
2505  assert(blkmem != NULL);
2506  assert(nchildren >= 0);
2507  assert(opdatatarget != NULL);
2508 
2509  /* for a linear expression, we need to copy the array that holds the coefficients and constant term */
2510  assert(opdatasource.data != NULL);
2511  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &targetdata, (SCIP_Real*)opdatasource.data, nchildren + 1) ); /*lint !e866*/
2512  opdatatarget->data = targetdata;
2513 
2514  return SCIP_OKAY;
2515 }
2516 
2517 /** expression data free for EXPR_LINEAR */
2518 static
2519 SCIP_DECL_EXPRFREEDATA( exprFreeDataLinear )
2520 { /*lint --e{715}*/
2521  SCIP_Real* freedata;
2522 
2523  assert(blkmem != NULL);
2524  assert(nchildren >= 0);
2525 
2526  freedata = (SCIP_Real*)opdata.data;
2527  assert(freedata != NULL);
2528 
2529  BMSfreeBlockMemoryArray(blkmem, &freedata, nchildren + 1); /*lint !e866*/
2530 }
2531 
2532 /** point evaluation for EXPR_QUADRATIC */
2533 static
2534 SCIP_DECL_EXPREVAL( exprevalQuadratic )
2535 { /*lint --e{715}*/
2536  SCIP_EXPRDATA_QUADRATIC* quaddata;
2537  SCIP_Real* lincoefs;
2538  SCIP_QUADELEM* quadelems;
2539  int nquadelems;
2540  int i;
2541 
2542  assert(result != NULL);
2543  assert(argvals != NULL || nargs == 0);
2544 
2545  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2546  assert(quaddata != NULL);
2547 
2548  lincoefs = quaddata->lincoefs;
2549  nquadelems = quaddata->nquadelems;
2550  quadelems = quaddata->quadelems;
2551 
2552  assert(quadelems != NULL || nquadelems == 0);
2553  assert(argvals != NULL || nargs == 0);
2554 
2555  *result = quaddata->constant;
2556 
2557  if( lincoefs != NULL )
2558  {
2559  for( i = nargs-1; i >= 0; --i )
2560  *result += lincoefs[i] * argvals[i]; /*lint !e613*/
2561  }
2562 
2563  for( i = 0; i < nquadelems; ++i, ++quadelems ) /*lint !e613*/
2564  *result += quadelems->coef * argvals[quadelems->idx1] * argvals[quadelems->idx2]; /*lint !e613*/
2565 
2566  return SCIP_OKAY;
2567 }
2568 
2569 /** interval evaluation for EXPR_QUADRATIC */
2570 static
2571 SCIP_DECL_EXPRINTEVAL( exprevalIntQuadratic )
2572 { /*lint --e{715}*/
2573  SCIP_EXPRDATA_QUADRATIC* quaddata;
2574  SCIP_Real* lincoefs;
2575  SCIP_QUADELEM* quadelems;
2576  int nquadelems;
2577  int i;
2578  int argidx;
2579  SCIP_Real sqrcoef;
2580  SCIP_INTERVAL lincoef;
2581  SCIP_INTERVAL tmp;
2582 
2583  assert(result != NULL);
2584  assert(argvals != NULL || nargs == 0);
2585 
2586  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2587  assert(quaddata != NULL);
2588 
2589  lincoefs = quaddata->lincoefs;
2590  nquadelems = quaddata->nquadelems;
2591  quadelems = quaddata->quadelems;
2592 
2593  assert(quadelems != NULL || nquadelems == 0);
2594  assert(argvals != NULL || nargs == 0);
2595 
2596  /* something fast for case of only one child */
2597  if( nargs == 1 )
2598  {
2599  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[0] : 0.0);
2600 
2601  sqrcoef = 0.0;
2602  for( i = 0; i < nquadelems; ++i )
2603  {
2604  assert(quadelems[i].idx1 == 0); /*lint !e613*/
2605  assert(quadelems[i].idx2 == 0); /*lint !e613*/
2606  sqrcoef += quadelems[i].coef; /*lint !e613*/
2607  }
2608 
2609  SCIPintervalQuad(infinity, result, sqrcoef, lincoef, argvals[0]); /*lint !e613*/
2610  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2611 
2612  return SCIP_OKAY;
2613  }
2614 
2615  if( nargs == 2 && nquadelems > 0 )
2616  {
2617  /* if it's a bivariate quadratic expression with bilinear term, do something special */
2618  SCIP_Real ax; /* square coefficient of first child */
2619  SCIP_Real ay; /* square coefficient of second child */
2620  SCIP_Real axy; /* bilinear coefficient */
2621 
2622  ax = 0.0;
2623  ay = 0.0;
2624  axy = 0.0;
2625  for( i = 0; i < nquadelems; ++i )
2626  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 ) /*lint !e613*/
2627  ax += quadelems[i].coef; /*lint !e613*/
2628  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 ) /*lint !e613*/
2629  ay += quadelems[i].coef; /*lint !e613*/
2630  else
2631  axy += quadelems[i].coef; /*lint !e613*/
2632 
2633  SCIPintervalQuadBivar(infinity, result, ax, ay, axy,
2634  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2635  argvals[0], argvals[1]); /*lint !e613*/
2636  SCIPdebugMessage("%g x^2 + %g y^2 + %g x y + %g x + %g y = [%g,%g] for x = [%g,%g], y = [%g,%g]\n",
2637  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2638  result->inf, result->sup, argvals[0].inf, argvals[0].sup, argvals[1].inf, argvals[1].sup); /*lint !e613*/
2639 
2640  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2641 
2642  return SCIP_OKAY;
2643  }
2644 
2645  /* make sure coefficients are sorted */
2646  quadraticdataSort(quaddata);
2647 
2648  SCIPintervalSet(result, quaddata->constant);
2649 
2650  /* for each argument, we collect it's linear index from lincoefs, it's square coefficients and all factors from bilinear terms
2651  * then we compute the interval sqrcoef*x^2 + lincoef*x and add it to result
2652  * @todo split quadratic expression into bivariate quadratic terms and apply the above method
2653  */
2654  i = 0;
2655  for( argidx = 0; argidx < nargs; ++argidx )
2656  {
2657  if( i == nquadelems || quadelems[i].idx1 > argidx ) /*lint !e613*/
2658  {
2659  /* there are no quadratic terms with argidx in its first argument, that should be easy to handle */
2660  if( lincoefs != NULL )
2661  {
2662  SCIPintervalMulScalar(infinity, &tmp, argvals[argidx], lincoefs[argidx]); /*lint !e613*/
2663  SCIPintervalAdd(infinity, result, *result, tmp);
2664  }
2665  continue;
2666  }
2667 
2668  sqrcoef = 0.0;
2669  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[argidx] : 0.0);
2670 
2671  assert(i < nquadelems && quadelems[i].idx1 == argidx); /*lint !e613*/
2672  do
2673  {
2674  if( quadelems[i].idx2 == argidx ) /*lint !e613*/
2675  {
2676  sqrcoef += quadelems[i].coef; /*lint !e613*/
2677  }
2678  else
2679  {
2680  SCIPintervalMulScalar(infinity, &tmp, argvals[quadelems[i].idx2], quadelems[i].coef); /*lint !e613*/
2681  SCIPintervalAdd(infinity, &lincoef, lincoef, tmp);
2682  }
2683  ++i;
2684  }
2685  while( i < nquadelems && quadelems[i].idx1 == argidx ); /*lint !e613*/
2686  assert(i == nquadelems || quadelems[i].idx1 > argidx); /*lint !e613*/
2687 
2688  SCIPintervalQuad(infinity, &tmp, sqrcoef, lincoef, argvals[argidx]); /*lint !e613*/
2689  SCIPintervalAdd(infinity, result, *result, tmp);
2690  }
2691  assert(i == nquadelems);
2692 
2693  return SCIP_OKAY;
2694 }
2695 
2696 /** curvature for EXPR_QUADRATIC */
2697 static
2698 SCIP_DECL_EXPRCURV( exprcurvQuadratic )
2699 { /*lint --e{715}*/
2701  SCIP_QUADELEM* quadelems;
2702  int nquadelems;
2703  SCIP_Real* lincoefs;
2704  int i;
2705 
2706  assert(result != NULL);
2707  assert(argcurv != NULL);
2708  assert(argbounds != NULL);
2709 
2710  data = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2711  assert(data != NULL);
2712 
2713  lincoefs = data->lincoefs;
2714  quadelems = data->quadelems;
2715  nquadelems = data->nquadelems;
2716 
2717  *result = SCIP_EXPRCURV_LINEAR;
2718 
2719  if( lincoefs != NULL )
2720  for( i = 0; i < nargs; ++i )
2721  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(lincoefs[i], argcurv[i]));
2722 
2723  /* @todo could try cholesky factorization if all children linear...
2724  * @todo should then cache the result
2725  */
2726  for( i = 0; i < nquadelems && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
2727  {
2728  if( quadelems[i].coef == 0.0 )
2729  continue;
2730 
2731  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup && /*lint !e777*/
2732  +argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup
2733  ) /*lint !e777*/
2734  {
2735  /* both factors are constants -> curvature does not change */
2736  continue;
2737  }
2738 
2739  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup ) /*lint !e777*/
2740  {
2741  /* first factor is constant, second is not -> add curvature of second */
2742  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx1].inf, argcurv[quadelems[i].idx2]));
2743  }
2744  else if( argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup ) /*lint !e777*/
2745  {
2746  /* first factor is not constant, second is -> add curvature of first */
2747  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx2].inf, argcurv[quadelems[i].idx1]));
2748  }
2749  else if( quadelems[i].idx1 == quadelems[i].idx2 )
2750  {
2751  /* both factors not constant, but the same (square term) */
2752  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef, SCIPexprcurvPower(argbounds[quadelems[i].idx1], argcurv[quadelems[i].idx1], 2.0)));
2753  }
2754  else
2755  {
2756  /* two different non-constant factors -> can't tell about curvature */
2757  *result = SCIP_EXPRCURV_UNKNOWN;
2758  }
2759  }
2760 
2761  return SCIP_OKAY;
2762 }
2763 
2764 /** expression data copy for EXPR_QUADRATIC */
2765 static
2766 SCIP_DECL_EXPRCOPYDATA( exprCopyDataQuadratic )
2767 { /*lint --e{715}*/
2768  SCIP_EXPRDATA_QUADRATIC* sourcedata;
2769 
2770  assert(blkmem != NULL);
2771  assert(opdatatarget != NULL);
2772 
2773  sourcedata = (SCIP_EXPRDATA_QUADRATIC*)opdatasource.data;
2774  assert(sourcedata != NULL);
2775 
2776  SCIP_CALL( quadraticdataCreate(blkmem, (SCIP_EXPRDATA_QUADRATIC**)&opdatatarget->data,
2777  sourcedata->constant, nchildren, sourcedata->lincoefs, sourcedata->nquadelems, sourcedata->quadelems) );
2778 
2779  return SCIP_OKAY;
2780 }
2781 
2782 /** expression data free for EXPR_QUADRATIC */
2783 static
2784 SCIP_DECL_EXPRFREEDATA( exprFreeDataQuadratic )
2785 { /*lint --e{715}*/
2786  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
2787 
2788  assert(blkmem != NULL);
2789  assert(nchildren >= 0);
2790 
2791  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2792  assert(quadraticdata != NULL);
2793 
2794  if( quadraticdata->lincoefs != NULL )
2795  {
2796  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->lincoefs, nchildren);
2797  }
2798 
2799  if( quadraticdata->nquadelems > 0 )
2800  {
2801  assert(quadraticdata->quadelems != NULL);
2802  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->quadelems, quadraticdata->nquadelems);
2803  }
2804 
2805  BMSfreeBlockMemory(blkmem, &quadraticdata);
2806 }
2807 
2808 /** point evaluation for EXPR_POLYNOMIAL */
2809 static
2810 SCIP_DECL_EXPREVAL( exprevalPolynomial )
2811 { /*lint --e{715}*/
2812  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2813  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2814  SCIP_Real childval;
2815  SCIP_Real exponent;
2816  SCIP_Real monomialval;
2817  int i;
2818  int j;
2819 
2820  assert(result != NULL);
2821  assert(argvals != NULL || nargs == 0);
2822  assert(opdata.data != NULL);
2823 
2824  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2825  assert(polynomialdata != NULL);
2826 
2827  *result = polynomialdata->constant;
2828 
2829  for( i = 0; i < polynomialdata->nmonomials; ++i )
2830  {
2831  monomialdata = polynomialdata->monomials[i];
2832  assert(monomialdata != NULL);
2833 
2834  monomialval = monomialdata->coef;
2835  for( j = 0; j < monomialdata->nfactors; ++j )
2836  {
2837  assert(monomialdata->childidxs[j] >= 0);
2838  assert(monomialdata->childidxs[j] < nargs);
2839 
2840  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2841  if( childval == 1.0 ) /* 1^anything == 1 */
2842  continue;
2843 
2844  exponent = monomialdata->exponents[j];
2845 
2846  if( childval == 0.0 )
2847  {
2848  if( exponent > 0.0 )
2849  {
2850  /* 0^positive == 0 */
2851  monomialval = 0.0;
2852  break;
2853  }
2854  else if( exponent < 0.0 )
2855  {
2856  /* 0^negative = nan */
2857  *result = log(-1.0);
2858  return SCIP_OKAY;
2859  }
2860  /* 0^0 == 1 */
2861  continue;
2862  }
2863 
2864  /* cover some special exponents separately to avoid calling expensive pow function */
2865  if( exponent == 0.0 )
2866  continue;
2867  if( exponent == 1.0 )
2868  {
2869  monomialval *= childval;
2870  continue;
2871  }
2872  if( exponent == 2.0 )
2873  {
2874  monomialval *= childval * childval;
2875  continue;
2876  }
2877  if( exponent == 0.5 )
2878  {
2879  monomialval *= sqrt(childval);
2880  continue;
2881  }
2882  if( exponent == -1.0 )
2883  {
2884  monomialval /= childval;
2885  continue;
2886  }
2887  if( exponent == -2.0 )
2888  {
2889  monomialval /= childval * childval;
2890  continue;
2891  }
2892  monomialval *= pow(childval, exponent);
2893  }
2894 
2895  *result += monomialval;
2896  }
2897 
2898  return SCIP_OKAY;
2899 }
2900 
2901 /** interval evaluation for EXPR_POLYNOMIAL */
2902 static
2903 SCIP_DECL_EXPRINTEVAL( exprevalIntPolynomial )
2904 { /*lint --e{715}*/
2905  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2906  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2907  SCIP_INTERVAL childval;
2908  SCIP_INTERVAL monomialval;
2909  SCIP_Real exponent;
2910  int i;
2911  int j;
2912 
2913  assert(result != NULL);
2914  assert(argvals != NULL || nargs == 0);
2915  assert(opdata.data != NULL);
2916 
2917  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2918  assert(polynomialdata != NULL);
2919 
2920  SCIPintervalSet(result, polynomialdata->constant);
2921 
2922  for( i = 0; i < polynomialdata->nmonomials; ++i )
2923  {
2924  monomialdata = polynomialdata->monomials[i];
2925  assert(monomialdata != NULL);
2926 
2927  SCIPintervalSet(&monomialval, monomialdata->coef);
2928  for( j = 0; j < monomialdata->nfactors && !SCIPintervalIsEntire(infinity, monomialval); ++j )
2929  {
2930  assert(monomialdata->childidxs[j] >= 0);
2931  assert(monomialdata->childidxs[j] < nargs);
2932 
2933  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2934 
2935  exponent = monomialdata->exponents[j];
2936 
2937  /* cover some special exponents separately to avoid calling expensive pow function */
2938  if( exponent == 0.0 )
2939  continue;
2940 
2941  if( exponent == 1.0 )
2942  {
2943  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2944  continue;
2945  }
2946 
2947  if( exponent == 2.0 )
2948  {
2949  SCIPintervalSquare(infinity, &childval, childval);
2950  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2951  continue;
2952  }
2953 
2954  if( exponent == 0.5 )
2955  {
2956  SCIPintervalSquareRoot(infinity, &childval, childval);
2957  if( SCIPintervalIsEmpty(childval) )
2958  {
2959  SCIPintervalSetEmpty(result);
2960  break;
2961  }
2962  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2963  continue;
2964  }
2965  else if( exponent == -1.0 )
2966  {
2967  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2968  }
2969  else if( exponent == -2.0 )
2970  {
2971  SCIPintervalSquare(infinity, &childval, childval);
2972  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2973  }
2974  else
2975  {
2976  SCIPintervalPowerScalar(infinity, &childval, childval, exponent);
2977  if( SCIPintervalIsEmpty(childval) )
2978  {
2979  SCIPintervalSetEmpty(result);
2980  return SCIP_OKAY;
2981  }
2982  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2983  }
2984 
2985  /* the cases in which monomialval gets empty should have been catched */
2986  assert(!SCIPintervalIsEmpty(monomialval));
2987  }
2988 
2989  SCIPintervalAdd(infinity, result, *result, monomialval);
2990  }
2991 
2992  return SCIP_OKAY;
2993 }
2994 
2995 /** curvature for EXPR_POLYNOMIAL */
2996 static
2997 SCIP_DECL_EXPRCURV( exprcurvPolynomial )
2998 { /*lint --e{715}*/
3000  SCIP_EXPRDATA_MONOMIAL** monomials;
3001  SCIP_EXPRDATA_MONOMIAL* monomial;
3002  int nmonomials;
3003  int i;
3004 
3005  assert(result != NULL);
3006  assert(argcurv != NULL);
3007  assert(argbounds != NULL);
3008 
3009  data = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3010  assert(data != NULL);
3011 
3012  monomials = data->monomials;
3013  nmonomials = data->nmonomials;
3014 
3015  *result = SCIP_EXPRCURV_LINEAR;
3016 
3017  for( i = 0; i < nmonomials && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
3018  {
3019  /* we assume that some simplifier was running, so that monomials do not have constants in their factors and such that all factors are different
3020  * (result would still be correct)
3021  */
3022  monomial = monomials[i];
3023  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(monomial->coef, SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, monomial->childidxs, argcurv, argbounds)));
3024  }
3025 
3026  return SCIP_OKAY;
3027 }
3028 
3029 /** expression data copy for EXPR_POLYNOMIAL */
3030 static
3031 SCIP_DECL_EXPRCOPYDATA( exprCopyDataPolynomial )
3032 { /*lint --e{715}*/
3033  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata;
3034  SCIP_EXPRDATA_POLYNOMIAL* targetpolynomialdata;
3035 
3036  assert(blkmem != NULL);
3037  assert(opdatatarget != NULL);
3038 
3039  sourcepolynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdatasource.data;
3040  assert(sourcepolynomialdata != NULL);
3041 
3042  SCIP_CALL( polynomialdataCopy(blkmem, &targetpolynomialdata, sourcepolynomialdata) );
3043 
3044  opdatatarget->data = (void*)targetpolynomialdata;
3045 
3046  return SCIP_OKAY;
3047 }
3048 
3049 /** expression data free for EXPR_POLYNOMIAL */
3050 static
3051 SCIP_DECL_EXPRFREEDATA( exprFreeDataPolynomial )
3052 { /*lint --e{715}*/
3053  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3054 
3055  assert(blkmem != NULL);
3056 
3057  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3058  assert(polynomialdata != NULL);
3059 
3060  polynomialdataFree(blkmem, &polynomialdata);
3061 }
3062 
3063 /** element in table of expression operands */
3064 struct exprOpTableElement
3065 {
3066  const char* name; /**< name of operand (used for printing) */
3067  int nargs; /**< number of arguments (negative if not fixed) */
3068  SCIP_DECL_EXPREVAL ((*eval)); /**< evaluation function */
3069  SCIP_DECL_EXPRINTEVAL ((*inteval)); /**< interval evaluation function */
3070  SCIP_DECL_EXPRCURV ((*curv)); /**< curvature check function */
3071  SCIP_DECL_EXPRCOPYDATA ((*copydata)); /**< expression data copy function, or NULL to only opdata union */
3072  SCIP_DECL_EXPRFREEDATA ((*freedata)); /**< expression data free function, or NULL if nothing to free */
3073 };
3074 
3075 #define EXPROPEMPTY {NULL, -1, NULL, NULL, NULL, NULL, NULL}
3076 
3077 /** table containing for each operand the name, the number of children, and some evaluation functions */
3078 static
3079 struct exprOpTableElement exprOpTable[] =
3080  {
3081  EXPROPEMPTY,
3082  { "variable", 0, exprevalVar, exprevalIntVar, exprcurvVar, NULL, NULL },
3083  { "constant", 0, exprevalConst, exprevalIntConst, exprcurvConst, NULL, NULL },
3084  { "parameter", 0, exprevalParam, exprevalIntParam, exprcurvParam, NULL, NULL },
3086  { "plus", 2, exprevalPlus, exprevalIntPlus, exprcurvPlus, NULL, NULL },
3087  { "minus", 2, exprevalMinus, exprevalIntMinus, exprcurvMinus, NULL, NULL },
3088  { "mul", 2, exprevalMult, exprevalIntMult, exprcurvMult, NULL, NULL },
3089  { "div", 2, exprevalDiv, exprevalIntDiv, exprcurvDiv, NULL, NULL },
3090  { "sqr", 1, exprevalSquare, exprevalIntSquare, exprcurvSquare, NULL, NULL },
3091  { "sqrt", 1, exprevalSquareRoot, exprevalIntSquareRoot, exprcurvSquareRoot, NULL, NULL },
3092  { "realpower", 1, exprevalRealPower, exprevalIntRealPower, exprcurvRealPower, NULL, NULL },
3093  { "intpower", 1, exprevalIntPower, exprevalIntIntPower, exprcurvIntPower, NULL, NULL },
3094  { "signpower", 1, exprevalSignPower, exprevalIntSignPower, exprcurvSignPower, NULL, NULL },
3095  { "exp", 1, exprevalExp, exprevalIntExp, exprcurvExp, NULL, NULL },
3096  { "log", 1, exprevalLog, exprevalIntLog, exprcurvLog, NULL, NULL },
3097  { "sin", 1, exprevalSin, exprevalIntSin, exprcurvSin, NULL, NULL },
3098  { "cos", 1, exprevalCos, exprevalIntCos, exprcurvCos, NULL, NULL },
3099  { "tan", 1, exprevalTan, exprevalIntTan, exprcurvTan, NULL, NULL },
3100  /* { "erf", 1, exprevalErf, exprevalIntErf, exprcurvErf, NULL, NULL }, */
3101  /* { "erfi", 1, exprevalErfi, exprevalIntErfi exprcurvErfi, NULL, NULL }, */
3103  { "min", 2, exprevalMin, exprevalIntMin, exprcurvMin, NULL, NULL },
3104  { "max", 2, exprevalMax, exprevalIntMax, exprcurvMax, NULL, NULL },
3105  { "abs", 1, exprevalAbs, exprevalIntAbs, exprcurvAbs, NULL, NULL },
3106  { "sign", 1, exprevalSign, exprevalIntSign, exprcurvSign, NULL, NULL },
3112  { "sum", -2, exprevalSum, exprevalIntSum, exprcurvSum, NULL, NULL },
3113  { "prod", -2, exprevalProduct, exprevalIntProduct, exprcurvProduct, NULL, NULL },
3114  { "linear", -2, exprevalLinear, exprevalIntLinear, exprcurvLinear, exprCopyDataLinear, exprFreeDataLinear },
3115  { "quadratic", -2, exprevalQuadratic, exprevalIntQuadratic, exprcurvQuadratic, exprCopyDataQuadratic, exprFreeDataQuadratic },
3116  { "polynomial", -2, exprevalPolynomial, exprevalIntPolynomial, exprcurvPolynomial, exprCopyDataPolynomial, exprFreeDataPolynomial }
3117  };
3118 
3119 /**@} */
3120 
3121 /**@name Expression operand methods */
3122 /**@{ */
3123 
3124 /** gives the name of an operand as string */
3125 const char* SCIPexpropGetName(
3126  SCIP_EXPROP op /**< expression operand */
3127  )
3128 {
3129  assert(op < SCIP_EXPR_LAST);
3130 
3131  return exprOpTable[op].name;
3132 }
3133 
3134 /** gives the number of children of a simple operand */
3136  SCIP_EXPROP op /**< expression operand */
3137  )
3138 {
3139  assert(op < SCIP_EXPR_LAST);
3140 
3141  return exprOpTable[op].nargs;
3142 }
3143 
3144 /**@} */
3145 
3146 /**@name Expressions private methods */
3147 /**@{ */
3148 
3149 /** creates an expression
3150  *
3151  * Note, that the expression is allocated but for the children only the pointer is copied.
3152  */
3153 static
3155  BMS_BLKMEM* blkmem, /**< block memory data structure */
3156  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
3157  SCIP_EXPROP op, /**< operand of expression */
3158  int nchildren, /**< number of children */
3159  SCIP_EXPR** children, /**< children */
3160  SCIP_EXPROPDATA opdata /**< operand data */
3161  )
3162 {
3163  assert(blkmem != NULL);
3164  assert(expr != NULL);
3165  assert(children != NULL || nchildren == 0);
3166  assert(children == NULL || nchildren > 0);
3167 
3168  SCIP_ALLOC( BMSallocBlockMemory(blkmem, expr) );
3169 
3170  (*expr)->op = op;
3171  (*expr)->nchildren = nchildren;
3172  (*expr)->children = children;
3173  (*expr)->data = opdata;
3174 
3175  return SCIP_OKAY;
3176 }
3177 
3178 /** tries to convert a given (operator,operatordata) pair into a polynomial operator with corresponding data
3179  *
3180  * Does not do this for constants.
3181  * If conversion is not possible or operator is already polynomial, *op and *data are
3182  * left untouched.
3183  */
3184 static
3186  BMS_BLKMEM* blkmem, /**< block memory */
3187  SCIP_EXPROP* op, /**< pointer to expression operator */
3188  SCIP_EXPROPDATA* data, /**< pointer to expression data */
3189  int nchildren /**< number of children of operator */
3190  )
3191 {
3192  assert(blkmem != NULL);
3193  assert(op != NULL);
3194  assert(data != NULL);
3195 
3196  switch( *op )
3197  {
3198  case SCIP_EXPR_VARIDX:
3199  case SCIP_EXPR_PARAM:
3200  case SCIP_EXPR_CONST:
3201  break;
3202 
3203  case SCIP_EXPR_PLUS:
3204  {
3205  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3206  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3207  int childidx;
3208  SCIP_Real exponent;
3209 
3210  assert(nchildren == 2);
3211 
3212  /* create monomial for first child */
3213  childidx = 0;
3214  exponent = 1.0;
3215  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3216 
3217  /* create monomial for second child */
3218  childidx = 1;
3219  exponent = 1.0;
3220  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], 1.0, 1, &childidx, &exponent) );
3221 
3222  /* create polynomial for sum of children */
3223  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3224 
3225  *op = SCIP_EXPR_POLYNOMIAL;
3226  data->data = (void*)polynomialdata;
3227 
3228  break;
3229  }
3230 
3231  case SCIP_EXPR_MINUS:
3232  {
3233  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3234  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3235  int childidx;
3236  SCIP_Real exponent;
3237 
3238  assert(nchildren == 2);
3239 
3240  /* create monomial for first child */
3241  childidx = 0;
3242  exponent = 1.0;
3243  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3244 
3245  /* create monomial for second child */
3246  childidx = 1;
3247  exponent = 1.0;
3248  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], -1.0, 1, &childidx, &exponent) );
3249 
3250  /* create polynomial for difference of children */
3251  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3252 
3253  *op = SCIP_EXPR_POLYNOMIAL;
3254  data->data = (void*)polynomialdata;
3255 
3256  break;
3257  }
3258 
3259  case SCIP_EXPR_MUL:
3260  {
3261  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3262  SCIP_EXPRDATA_MONOMIAL* monomial;
3263  int childidx[2];
3264  SCIP_Real exponent[2];
3265 
3266  assert(nchildren == 2);
3267 
3268  /* create monomial for product of children */
3269  childidx[0] = 0;
3270  childidx[1] = 1;
3271  exponent[0] = 1.0;
3272  exponent[1] = 1.0;
3273  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3274 
3275  /* create polynomial */
3276  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3277 
3278  *op = SCIP_EXPR_POLYNOMIAL;
3279  data->data = (void*)polynomialdata;
3280 
3281  break;
3282  }
3283 
3284  case SCIP_EXPR_DIV:
3285  {
3286  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3287  SCIP_EXPRDATA_MONOMIAL* monomial;
3288  int childidx[2];
3289  SCIP_Real exponent[2];
3290 
3291  assert(nchildren == 2);
3292 
3293  /* create monomial for division of children */
3294  childidx[0] = 0;
3295  childidx[1] = 1;
3296  exponent[0] = 1.0;
3297  exponent[1] = -1.0;
3298  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3299 
3300  /* create polynomial */
3301  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3302 
3303  *op = SCIP_EXPR_POLYNOMIAL;
3304  data->data = (void*)polynomialdata;
3305 
3306  break;
3307  }
3308 
3309  case SCIP_EXPR_SQUARE:
3310  {
3311  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3312  SCIP_EXPRDATA_MONOMIAL* monomial;
3313  int childidx;
3314  SCIP_Real exponent;
3315 
3316  assert(nchildren == 1);
3317 
3318  /* create monomial for square of child */
3319  childidx = 0;
3320  exponent = 2.0;
3321  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3322 
3323  /* create polynomial */
3324  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3325 
3326  *op = SCIP_EXPR_POLYNOMIAL;
3327  data->data = (void*)polynomialdata;
3328 
3329  break;
3330  }
3331 
3332  case SCIP_EXPR_SQRT:
3333  {
3334  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3335  SCIP_EXPRDATA_MONOMIAL* monomial;
3336  int childidx;
3337  SCIP_Real exponent;
3338 
3339  assert(nchildren == 1);
3340 
3341  /* create monomial for square root of child */
3342  childidx = 0;
3343  exponent = 0.5;
3344  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3345 
3346  /* create polynomial */
3347  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3348 
3349  *op = SCIP_EXPR_POLYNOMIAL;
3350  data->data = (void*)polynomialdata;
3351 
3352  break;
3353  }
3354 
3355  case SCIP_EXPR_REALPOWER:
3356  {
3357  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3358  SCIP_EXPRDATA_MONOMIAL* monomial;
3359  int childidx;
3360 
3361  assert(nchildren == 1);
3362 
3363  /* convert to child0 to the power of exponent */
3364 
3365  /* create monomial for power of first child */
3366  childidx = 0;
3367  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &data->dbl) );
3368 
3369  /* create polynomial */
3370  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3371 
3372  *op = SCIP_EXPR_POLYNOMIAL;
3373  data->data = (void*)polynomialdata;
3374 
3375  break;
3376  }
3377 
3378  case SCIP_EXPR_SIGNPOWER:
3379  {
3380  SCIP_Real exponent;
3381 
3382  assert(nchildren == 1);
3383 
3384  /* check if exponent is an odd integer */
3385  exponent = data->dbl;
3386  if( EPSISINT(exponent, 0.0) && (int)exponent % 2 != 0 ) /*lint !e835*/
3387  {
3388  /* convert to child0 to the power of exponent, since sign is kept by taking power */
3389  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3390  SCIP_EXPRDATA_MONOMIAL* monomial;
3391  int childidx;
3392 
3393  /* create monomial for power of first child */
3394  childidx = 0;
3395  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3396 
3397  /* create polynomial */
3398  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3399 
3400  *op = SCIP_EXPR_POLYNOMIAL;
3401  data->data = (void*)polynomialdata;
3402  }
3403  /* if exponent is not an odd integer constant, then keep it as signpower expression */
3404  break;
3405  }
3406 
3407  case SCIP_EXPR_INTPOWER:
3408  {
3409  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3410  SCIP_EXPRDATA_MONOMIAL* monomial;
3411  int childidx;
3412  SCIP_Real exponent;
3413 
3414  assert(nchildren == 1);
3415 
3416  /* create monomial for power of child */
3417  childidx = 0;
3418  exponent = data->intval;
3419  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3420 
3421  /* create polynomial */
3422  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3423 
3424  *op = SCIP_EXPR_POLYNOMIAL;
3425  data->data = (void*)polynomialdata;
3426 
3427  break;
3428  }
3429 
3430  case SCIP_EXPR_EXP:
3431  case SCIP_EXPR_LOG:
3432  case SCIP_EXPR_SIN:
3433  case SCIP_EXPR_COS:
3434  case SCIP_EXPR_TAN:
3435  /* case SCIP_EXPR_ERF: */
3436  /* case SCIP_EXPR_ERFI: */
3437  case SCIP_EXPR_MIN:
3438  case SCIP_EXPR_MAX:
3439  case SCIP_EXPR_ABS:
3440  case SCIP_EXPR_SIGN:
3441  break;
3442 
3443  case SCIP_EXPR_SUM:
3444  {
3445  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3446  SCIP_EXPRDATA_MONOMIAL* monomial;
3447  int childidx;
3448  int i;
3449  SCIP_Real exponent;
3450 
3451  /* create empty polynomial */
3452  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, 0.0, FALSE) );
3453  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3454  assert(polynomialdata->monomialssize >= nchildren);
3455 
3456  /* add summands as monomials */
3457  childidx = 0;
3458  exponent = 1.0;
3459  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3460  for( i = 0; i < nchildren; ++i )
3461  {
3462  monomial->childidxs[0] = i;
3463  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3464  }
3465  SCIPexprFreeMonomial(blkmem, &monomial);
3466 
3467  *op = SCIP_EXPR_POLYNOMIAL;
3468  data->data = (void*)polynomialdata;
3469 
3470  break;
3471  }
3472 
3473  case SCIP_EXPR_PRODUCT:
3474  {
3475  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3476  SCIP_EXPRDATA_MONOMIAL* monomial;
3477  int childidx;
3478  int i;
3479  SCIP_Real exponent;
3480 
3481  /* create monomial */
3482  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 0, NULL, NULL) );
3483  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, nchildren) );
3484  exponent = 1.0;
3485  for( i = 0; i < nchildren; ++i )
3486  {
3487  childidx = i;
3488  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
3489  }
3490 
3491  /* create polynomial */
3492  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3493 
3494  *op = SCIP_EXPR_POLYNOMIAL;
3495  data->data = (void*)polynomialdata;
3496 
3497  break;
3498  }
3499 
3500  case SCIP_EXPR_LINEAR:
3501  {
3502  SCIP_Real* lineardata;
3503  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3504  SCIP_EXPRDATA_MONOMIAL* monomial;
3505  int childidx;
3506  int i;
3507  SCIP_Real exponent;
3508 
3509  /* get coefficients of linear term */
3510  lineardata = (SCIP_Real*)data->data;
3511  assert(lineardata != NULL);
3512 
3513  /* create polynomial consisting of constant from linear term */
3514  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, lineardata[nchildren], FALSE) );
3515  /* ensure space for linear coefficients */
3516  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3517  assert(polynomialdata->monomialssize >= nchildren);
3518 
3519  /* add summands as monomials */
3520  childidx = 0;
3521  exponent = 1.0;
3522  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3523  for( i = 0; i < nchildren; ++i )
3524  {
3525  monomial->coef = lineardata[i];
3526  monomial->childidxs[0] = i;
3527  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3528  }
3529  SCIPexprFreeMonomial(blkmem, &monomial);
3530 
3531  /* free linear expression data */
3532  exprFreeDataLinear(blkmem, nchildren, *data);
3533 
3534  *op = SCIP_EXPR_POLYNOMIAL;
3535  data->data = (void*)polynomialdata;
3536 
3537  break;
3538  }
3539 
3540  case SCIP_EXPR_QUADRATIC:
3541  {
3542  SCIP_EXPRDATA_QUADRATIC* quaddata;
3543  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3544  SCIP_EXPRDATA_MONOMIAL* squaremonomial;
3545  SCIP_EXPRDATA_MONOMIAL* bilinmonomial;
3546  SCIP_EXPRDATA_MONOMIAL* linmonomial;
3547  int childidx[2];
3548  SCIP_Real exponent[2];
3549  int i;
3550 
3551  /* get data of quadratic expression */
3552  quaddata = (SCIP_EXPRDATA_QUADRATIC*)data->data;
3553  assert(quaddata != NULL);
3554 
3555  /* create empty polynomial */
3556  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, quaddata->constant, FALSE) );
3557  /* ensure space for linear and quadratic terms */
3558  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, (quaddata->lincoefs != NULL ? nchildren : 0) + quaddata->nquadelems) );
3559  assert(polynomialdata->monomialssize >= quaddata->nquadelems);
3560 
3561  childidx[0] = 0;
3562  childidx[1] = 0;
3563 
3564  /* create monomial templates */
3565  exponent[0] = 2.0;
3566  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &squaremonomial, 1.0, 1, childidx, exponent) );
3567  exponent[0] = 1.0;
3568  exponent[1] = 1.0;
3569  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &bilinmonomial, 1.0, 2, childidx, exponent) );
3570  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &linmonomial, 1.0, 1, childidx, exponent) );
3571 
3572  /* add linear terms as monomials */
3573  if( quaddata->lincoefs != NULL )
3574  for( i = 0; i < nchildren; ++i )
3575  if( quaddata->lincoefs[i] != 0.0 )
3576  {
3577  linmonomial->childidxs[0] = i;
3578  linmonomial->coef = quaddata->lincoefs[i];
3579  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &linmonomial, TRUE) );
3580  }
3581 
3582  /* add quadratic terms as monomials */
3583  for( i = 0; i < quaddata->nquadelems; ++i )
3584  {
3585  if( quaddata->quadelems[i].idx1 == quaddata->quadelems[i].idx2 )
3586  {
3587  squaremonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3588  squaremonomial->coef = quaddata->quadelems[i].coef;
3589  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &squaremonomial, TRUE) );
3590  }
3591  else
3592  {
3593  bilinmonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3594  bilinmonomial->childidxs[1] = quaddata->quadelems[i].idx2;
3595  bilinmonomial->coef = quaddata->quadelems[i].coef;
3596  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &bilinmonomial, TRUE) );
3597  }
3598  }
3599  SCIPexprFreeMonomial(blkmem, &squaremonomial);
3600  SCIPexprFreeMonomial(blkmem, &bilinmonomial);
3601  SCIPexprFreeMonomial(blkmem, &linmonomial);
3602 
3603  /* free quadratic expression data */
3604  exprFreeDataQuadratic(blkmem, nchildren, *data);
3605 
3606  *op = SCIP_EXPR_POLYNOMIAL;
3607  data->data = (void*)polynomialdata;
3608 
3609  break;
3610  }
3611 
3612  case SCIP_EXPR_POLYNOMIAL:
3613  break;
3614 
3615  default:
3616  SCIPerrorMessage("operand %d unknown\n", *op);
3617  return SCIP_ERROR;
3618  } /*lint !e788*/
3619 
3620  return SCIP_OKAY;
3621 }
3622 
3623 /** converts polynomial expression back into simpler expression, if possible */
3624 static
3626  BMS_BLKMEM* blkmem, /**< block memory data structure */
3627  SCIP_EXPROP* op, /**< pointer to expression operator */
3628  SCIP_EXPROPDATA* data, /**< pointer to expression data holding polynomial data */
3629  int nchildren, /**< number of children of operator */
3630  void** children /**< children array */
3631  )
3632 {
3633  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3634  SCIP_EXPRDATA_MONOMIAL* monomial;
3635  int maxdegree;
3636  int nlinmonomials;
3637  int i;
3638  int j;
3639 
3640  assert(blkmem != NULL);
3641  assert(op != NULL);
3642  assert(*op == SCIP_EXPR_POLYNOMIAL);
3643  assert(data != NULL);
3644  assert(children != NULL || nchildren == 0);
3645 
3646  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)data->data;
3647  assert(polynomialdata != NULL);
3648 
3649  /* make sure monomials are sorted and merged */
3650  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
3651 
3652  /* if no monomials, then leave as it is */
3653  if( polynomialdata->nmonomials == 0 )
3654  return SCIP_OKAY;
3655 
3656  /* check maximal degree of polynomial only - not considering children expressions
3657  * check number of linear monomials */
3658  maxdegree = 0;
3659  nlinmonomials = 0;
3660  for( i = 0; i < polynomialdata->nmonomials; ++i )
3661  {
3662  int monomialdegree;
3663 
3664  monomial = polynomialdata->monomials[i];
3665  assert(monomial != NULL);
3666 
3667  monomialdegree = 0;
3668  for(j = 0; j < monomial->nfactors; ++j )
3669  {
3670  if( !EPSISINT(monomial->exponents[j], 0.0) || monomial->exponents[j] < 0.0 ) /*lint !e835*/
3671  {
3672  monomialdegree = SCIP_EXPR_DEGREEINFINITY;
3673  break;
3674  }
3675 
3676  monomialdegree += (int)EPSROUND(monomial->exponents[j], 0.0); /*lint !e835*/
3677  }
3678 
3679  if( monomialdegree == SCIP_EXPR_DEGREEINFINITY )
3680  {
3681  maxdegree = SCIP_EXPR_DEGREEINFINITY;
3682  break;
3683  }
3684 
3685  if( monomialdegree == 1 )
3686  ++nlinmonomials;
3687 
3688  if( monomialdegree > maxdegree )
3689  maxdegree = monomialdegree;
3690  }
3691  assert(maxdegree > 0 );
3692 
3693  if( maxdegree == 1 )
3694  {
3695  /* polynomial is a linear expression in children */
3696 
3697  /* polynomial simplification and monomial merging should ensure that monomial i corresponds to child i and that there are not unused children */
3698  assert(polynomialdata->nmonomials == nchildren);
3699  assert(polynomialdata->nmonomials == nlinmonomials);
3700 
3701  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3702  {
3703  /* polynomial is addition of two expressions, so turn into SCIP_EXPR_PLUS */
3704  assert(polynomialdata->monomials[0]->nfactors == 1);
3705  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3706  assert(polynomialdata->monomials[1]->nfactors == 1);
3707  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3708 
3709  polynomialdataFree(blkmem, &polynomialdata);
3710  data->data = NULL;
3711 
3712  /* change operator type to PLUS */
3713  *op = SCIP_EXPR_PLUS;
3714 
3715  return SCIP_OKAY;
3716  }
3717 
3718  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == -1.0 )
3719  {
3720  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3721  assert(polynomialdata->monomials[0]->nfactors == 1);
3722  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3723  assert(polynomialdata->monomials[1]->nfactors == 1);
3724  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3725 
3726  polynomialdataFree(blkmem, &polynomialdata);
3727  data->data = NULL;
3728 
3729  /* change operator type to MINUS */
3730  *op = SCIP_EXPR_MINUS;
3731 
3732  return SCIP_OKAY;
3733  }
3734 
3735  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == -1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3736  {
3737  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3738  void* tmp;
3739 
3740  assert(polynomialdata->monomials[0]->nfactors == 1);
3741  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3742  assert(polynomialdata->monomials[1]->nfactors == 1);
3743  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3744 
3745  polynomialdataFree(blkmem, &polynomialdata);
3746  data->data = NULL;
3747 
3748  /* swap children */
3749  tmp = children[1]; /*lint !e613*/
3750  children[1] = children[0]; /*lint !e613*/
3751  children[0] = tmp; /*lint !e613*/
3752 
3753  /* change operator type to MINUS */
3754  *op = SCIP_EXPR_MINUS;
3755 
3756  return SCIP_OKAY;
3757  }
3758 
3759  if( polynomialdata->constant == 0.0 )
3760  {
3761  /* check if all monomials have coefficient 1.0 */
3762  for( i = 0; i < polynomialdata->nmonomials; ++i )
3763  if( polynomialdata->monomials[i]->coef != 1.0 )
3764  break;
3765 
3766  if( i == polynomialdata->nmonomials )
3767  {
3768  /* polynomial is sum of children, so turn into SCIP_EXPR_SUM */
3769 
3770  polynomialdataFree(blkmem, &polynomialdata);
3771  data->data = NULL;
3772 
3773  /* change operator type to MINUS */
3774  *op = SCIP_EXPR_SUM;
3775 
3776  return SCIP_OKAY;
3777  }
3778  }
3779 
3780  /* turn polynomial into linear expression */
3781  {
3782  SCIP_Real* lindata;
3783 
3784  /* monomial merging should ensure that each child appears in at most one monomial,
3785  * that monomials are ordered according to the child index, and that constant monomials have been removed
3786  */
3787 
3788  /* setup data of linear expression */
3789  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &lindata, polynomialdata->nmonomials + 1) );
3790 
3791  for( i = 0; i < polynomialdata->nmonomials; ++i )
3792  {
3793  assert(polynomialdata->monomials[i]->childidxs[0] == i);
3794  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3795  lindata[i] = polynomialdata->monomials[i]->coef; /*lint !e644*/
3796  }
3797  lindata[i] = polynomialdata->constant;
3798 
3799  polynomialdataFree(blkmem, &polynomialdata);
3800  *op = SCIP_EXPR_LINEAR;
3801  data->data = (void*)lindata;
3802 
3803  return SCIP_OKAY;
3804  }
3805  }
3806 
3807  if( maxdegree == 2 && (polynomialdata->nmonomials > 1 || polynomialdata->constant != 0.0 || polynomialdata->monomials[0]->coef != 1.0) )
3808  {
3809  /* 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 */
3810  SCIP_EXPRDATA_QUADRATIC* quaddata;
3811  int quadelemidx;
3812 
3813  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &quaddata) );
3814  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->quadelems, polynomialdata->nmonomials - nlinmonomials) );
3815  quaddata->nquadelems = polynomialdata->nmonomials - nlinmonomials;
3816  quaddata->constant = polynomialdata->constant;
3817  quaddata->sorted = FALSE; /* quadratic data is sorted different than polynomials */
3818 
3819  if( nlinmonomials > 0 )
3820  {
3821  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->lincoefs, nchildren) );
3822  BMSclearMemoryArray(quaddata->lincoefs, nchildren);
3823  }
3824  else
3825  quaddata->lincoefs = NULL;
3826 
3827  quadelemidx = 0;
3828  for( i = 0; i < polynomialdata->nmonomials; ++i )
3829  {
3830  assert(polynomialdata->monomials[i]->nfactors == 1 || polynomialdata->monomials[i]->nfactors == 2);
3831  if( polynomialdata->monomials[i]->nfactors == 1 )
3832  {
3833  if( polynomialdata->monomials[i]->exponents[0] == 1.0 )
3834  {
3835  /* monomial is a linear term */
3836  assert(quaddata->lincoefs != NULL);
3837  quaddata->lincoefs[polynomialdata->monomials[i]->childidxs[0]] += polynomialdata->monomials[i]->coef;
3838  }
3839  else
3840  {
3841  /* monomial should be a square term */
3842  assert(polynomialdata->monomials[i]->exponents[0] == 2.0);
3843  assert(quadelemidx < quaddata->nquadelems);
3844  quaddata->quadelems[quadelemidx].idx1 = polynomialdata->monomials[i]->childidxs[0];
3845  quaddata->quadelems[quadelemidx].idx2 = polynomialdata->monomials[i]->childidxs[0];
3846  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3847  ++quadelemidx;
3848  }
3849  }
3850  else
3851  {
3852  /* monomial should be a bilinear term */
3853  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3854  assert(polynomialdata->monomials[i]->exponents[1] == 1.0);
3855  assert(quadelemidx < quaddata->nquadelems);
3856  quaddata->quadelems[quadelemidx].idx1 = MIN(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3857  quaddata->quadelems[quadelemidx].idx2 = MAX(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3858  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3859  ++quadelemidx;
3860  }
3861  }
3862  assert(quadelemidx == quaddata->nquadelems);
3863 
3864  polynomialdataFree(blkmem, &polynomialdata);
3865 
3866  *op = SCIP_EXPR_QUADRATIC;
3867  data->data = (void*)quaddata;
3868 
3869  return SCIP_OKAY;
3870  }
3871 
3872  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 1 && polynomialdata->monomials[0]->coef == 1.0 )
3873  {
3874  /* polynomial is product of children */
3875  monomial = polynomialdata->monomials[0];
3876 
3877  if( monomial->nfactors == 1 )
3878  {
3879  /* polynomial is x^k for some k */
3880  assert(monomial->exponents[0] != 1.0); /* should have been handled before */
3881 
3882  if( monomial->exponents[0] == 2.0 )
3883  {
3884  /* polynomial is x^2, so turn into SCIP_EXPR_SQUARE */
3885 
3886  polynomialdataFree(blkmem, &polynomialdata);
3887  data->data = NULL;
3888 
3889  *op = SCIP_EXPR_SQUARE;
3890 
3891  return SCIP_OKAY;
3892  }
3893 
3894  if( EPSISINT(monomial->exponents[0], 0.0) ) /*lint !e835*/
3895  {
3896  /* k is an integer, so turn into SCIP_EXPR_INTPOWER */
3897  int exponent;
3898 
3899  exponent = (int)EPSROUND(monomial->exponents[0], 0.0); /*lint !e835*/
3900 
3901  polynomialdataFree(blkmem, &polynomialdata);
3902 
3903  *op = SCIP_EXPR_INTPOWER;
3904  data->intval = exponent;
3905 
3906  return SCIP_OKAY;
3907  }
3908 
3909  if( monomial->exponents[0] == 0.5 )
3910  {
3911  /* polynomial is sqrt(x), so turn into SCIP_EXPR_SQRT */
3912 
3913  polynomialdataFree(blkmem, &polynomialdata);
3914  data->data = NULL;
3915 
3916  *op = SCIP_EXPR_SQRT;
3917 
3918  return SCIP_OKAY;
3919  }
3920 
3921  {
3922  /* polynomial is x^a with a some real number, so turn into SCIP_EXPR_REALPOWER */
3923  SCIP_Real exponent;
3924 
3925  exponent = monomial->exponents[0];
3926 
3927  polynomialdataFree(blkmem, &polynomialdata);
3928 
3929  *op = SCIP_EXPR_REALPOWER;
3930  data->dbl = exponent;
3931 
3932  return SCIP_OKAY;
3933  }
3934  }
3935 
3936  if( maxdegree == 2 && monomial->nfactors == 2 )
3937  {
3938  /* polynomial is product of two children, so turn into SCIP_EXPR_MUL */
3939  assert(monomial->exponents[0] == 1.0);
3940  assert(monomial->exponents[1] == 1.0);
3941 
3942  polynomialdataFree(blkmem, &polynomialdata);
3943  data->data = NULL;
3944 
3945  *op = SCIP_EXPR_MUL;
3946 
3947  return SCIP_OKAY;
3948  }
3949 
3950  if( maxdegree == monomial->nfactors )
3951  {
3952  /* polynomial is a product of n children, so turn into SCIP_EXPR_PRODUCT */
3953 
3954  polynomialdataFree(blkmem, &polynomialdata);
3955  data->data = NULL;
3956 
3957  *op = SCIP_EXPR_PRODUCT;
3958 
3959  return SCIP_OKAY;
3960  }
3961 
3962  if( monomial->nfactors == 2 && monomial->exponents[0] == 1.0 && monomial->exponents[1] == -1.0 )
3963  {
3964  /* polynomial is x/y, so turn into SCIP_EXPR_DIV */
3965 
3966  polynomialdataFree(blkmem, &polynomialdata);
3967  data->data = NULL;
3968 
3969  *op = SCIP_EXPR_DIV;
3970 
3971  return SCIP_OKAY;
3972  }
3973 
3974  if( monomial->nfactors == 2 && monomial->exponents[0] == -1.0 && monomial->exponents[1] == 1.0 )
3975  {
3976  /* polynomial is y/x, so turn into SCIP_EXPR_DIV */
3977  void* tmp;
3978 
3979  polynomialdataFree(blkmem, &polynomialdata);
3980  data->data = NULL;
3981 
3982  /* swap children */
3983  tmp = children[1]; /*lint !e613*/
3984  children[1] = children[0]; /*lint !e613*/
3985  children[0] = tmp; /*lint !e613*/
3986 
3987  *op = SCIP_EXPR_DIV;
3988 
3989  return SCIP_OKAY;
3990  }
3991  }
3992 
3993  return SCIP_OKAY;
3994 }
3995 
3996 /** adds copies of expressions to the array of children of a sum, product, linear, quadratic, or polynomial expression
3997  *
3998  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
3999  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
4000  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
4001  */
4002 static
4004  BMS_BLKMEM* blkmem, /**< block memory */
4005  SCIP_EXPR* expr, /**< quadratic or polynomial expression */
4006  int nexprs, /**< number of expressions to add */
4007  SCIP_EXPR** exprs, /**< expressions to add */
4008  SCIP_Bool comparechildren, /**< whether to compare expressions with already existing children (no effect for sum and product) */
4009  SCIP_Real eps, /**< which epsilon to use when comparing expressions */
4010  int* childmap /**< array where to store mapping of indices from exprs to children array in expr, or NULL if not of interest */
4011  )
4012 {
4013  int i;
4014 
4015  assert(blkmem != NULL);
4016  assert(expr != NULL);
4017  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);
4018  assert(exprs != NULL || nexprs == 0);
4019 
4020  if( nexprs == 0 )
4021  return SCIP_OKAY;
4022 
4023  switch( expr->op )
4024  {
4025  case SCIP_EXPR_SUM:
4026  case SCIP_EXPR_PRODUCT:
4027  {
4028  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4029  for( i = 0; i < nexprs; ++i )
4030  {
4031  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren + i], exprs[i]) ); /*lint !e613*/
4032  if( childmap != NULL )
4033  childmap[i] = expr->nchildren + i;
4034  }
4035  expr->nchildren += nexprs;
4036 
4037  break;
4038  }
4039 
4040  case SCIP_EXPR_LINEAR:
4041  case SCIP_EXPR_QUADRATIC:
4042  case SCIP_EXPR_POLYNOMIAL:
4043  {
4044  int j;
4045  int orignchildren;
4046  SCIP_Bool existsalready;
4047 
4048  orignchildren = expr->nchildren;
4049  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4050 
4051  for( i = 0; i < nexprs; ++i )
4052  {
4053  existsalready = FALSE;
4054  if( comparechildren )
4055  for( j = 0; j < orignchildren; ++j )
4056  /* during simplification of polynomials, their may be NULL's in children array */
4057  if( expr->children[j] != NULL && SCIPexprAreEqual(expr->children[j], exprs[i], eps) ) /*lint !e613*/
4058  {
4059  existsalready = TRUE;
4060  break;
4061  }
4062 
4063  if( !existsalready )
4064  {
4065  /* add copy of exprs[j] to children array */
4066  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren], exprs[i]) ); /*lint !e613*/
4067  if( childmap != NULL )
4068  childmap[i] = expr->nchildren;
4069  ++expr->nchildren;
4070  }
4071  else
4072  {
4073  if( childmap != NULL )
4074  childmap[i] = j; /*lint !e644*/
4075  if( expr->op == SCIP_EXPR_LINEAR )
4076  {
4077  /* if linear expression, increase coefficient by 1.0 */
4078  ((SCIP_Real*)expr->data.data)[j] += 1.0;
4079  }
4080  }
4081  }
4082 
4083  /* shrink children array to actually used size */
4084  assert(comparechildren || expr->nchildren == orignchildren + nexprs);
4085  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, orignchildren + nexprs, expr->nchildren) );
4086 
4087  if( expr->op == SCIP_EXPR_LINEAR && expr->nchildren > orignchildren )
4088  {
4089  /* if linear expression, then add 1.0 coefficients for new expressions */
4090  SCIP_Real* data;
4091 
4092  data = (SCIP_Real*)expr->data.data;
4093  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, expr->nchildren + 1) );
4094  data[expr->nchildren] = data[orignchildren]; /* move constant from old end to new end */
4095  for( i = orignchildren; i < expr->nchildren; ++i )
4096  data[i] = 1.0;
4097  expr->data.data = (void*)data;
4098  }
4099  else if( expr->op == SCIP_EXPR_QUADRATIC && expr->nchildren > orignchildren )
4100  {
4101  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
4103 
4104  data = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
4105  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, expr->nchildren) );
4106  BMSclearMemoryArray(&data->lincoefs[orignchildren], expr->nchildren - orignchildren); /*lint !e866*/
4107  }
4108 
4109  break;
4110  }
4111 
4112  default:
4113  SCIPerrorMessage("exprsimplifyAddChildren cannot be called for operand %d\n", expr->op);
4114  return SCIP_INVALIDDATA;
4115  } /*lint !e788*/
4116 
4117  return SCIP_OKAY;
4118 }
4119 
4120 /** converts expressions into polynomials, where possible and obvious */
4121 static
4123  BMS_BLKMEM* blkmem, /**< block memory data structure */
4124  SCIP_EXPR* expr /**< expression to convert */
4125  )
4126 {
4127  int i;
4128 
4129  assert(expr != NULL);
4130 
4131  for( i = 0; i < expr->nchildren; ++i )
4132  {
4134  }
4135 
4136  SCIP_CALL( exprConvertToPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren) );
4137 
4138  return SCIP_OKAY;
4139 }
4140 
4141 /** removes duplicate children in a polynomial expression
4142  *
4143  * Leaves NULL's in children array.
4144  */
4145 static
4147  BMS_BLKMEM* blkmem, /**< block memory data structure */
4148  SCIP_EXPR* expr, /**< expression */
4149  SCIP_Real eps /**< threshold for zero */
4150  )
4151 {
4152  SCIP_Bool foundduplicates;
4153  int* childmap;
4154  int i;
4155  int j;
4156 
4157  assert(blkmem != NULL);
4158  assert(expr != NULL);
4159  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4160 
4161  if( expr->nchildren == 0 )
4162  return SCIP_OKAY;
4163 
4164  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4165 
4166  foundduplicates = FALSE;
4167  for( i = 0; i < expr->nchildren; ++i )
4168  {
4169  if( expr->children[i] == NULL )
4170  continue;
4171  childmap[i] = i; /*lint !e644*/
4172 
4173  for( j = i+1; j < expr->nchildren; ++j )
4174  {
4175  if( expr->children[j] == NULL )
4176  continue;
4177 
4178  if( SCIPexprAreEqual(expr->children[i], expr->children[j], eps) )
4179  {
4180  /* forget about expr j and remember that is to be replaced by i */
4181  SCIPexprFreeDeep(blkmem, &expr->children[j]);
4182  childmap[j] = i;
4183  foundduplicates = TRUE;
4184  }
4185  }
4186  }
4187 
4188  /* apply childmap to monomials */
4189  if( foundduplicates )
4191 
4192  /* free childmap */
4193  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4194 
4195  return SCIP_OKAY;
4196 }
4197 
4198 /** eliminates NULL's in children array and shrinks it to actual size */
4199 static
4201  BMS_BLKMEM* blkmem, /**< block memory data structure */
4202  SCIP_EXPR* expr /**< expression */
4203  )
4204 {
4205  int* childmap;
4206  int lastnonnull;
4207  int i;
4208 
4209  assert(blkmem != NULL);
4210  assert(expr != NULL);
4211  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4212 
4213  if( expr->nchildren == 0 )
4214  return SCIP_OKAY;
4215 
4216  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4217 
4218  /* close gaps in children array */
4219  lastnonnull = expr->nchildren-1;
4220  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4221  --lastnonnull;
4222  for( i = 0; i <= lastnonnull; ++i )
4223  {
4224  if( expr->children[i] != NULL )
4225  {
4226  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
4227  continue;
4228  }
4229  assert(expr->children[lastnonnull] != NULL);
4230 
4231  /* move child at lastnonnull to position i */
4232  expr->children[i] = expr->children[lastnonnull];
4233  expr->children[lastnonnull] = NULL;
4234  childmap[lastnonnull] = i;
4235 
4236  /* update lastnonnull */
4237  --lastnonnull;
4238  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4239  --lastnonnull;
4240  }
4241  assert(i > lastnonnull);
4242 
4243  /* apply childmap to monomials */
4244  if( lastnonnull < expr->nchildren-1 )
4246 
4247  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4248 
4249  /* shrink children array */
4250  if( lastnonnull >= 0 )
4251  {
4252  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, lastnonnull+1) );
4253  expr->nchildren = lastnonnull+1;
4254  }
4255  else
4256  {
4257  BMSfreeBlockMemoryArray(blkmem, &expr->children, expr->nchildren);
4258  expr->nchildren = 0;
4259  }
4260 
4261  return SCIP_OKAY;
4262 }
4263 
4264 /** checks which children are still in use and frees those which are not */
4265 static
4267  BMS_BLKMEM* blkmem, /**< block memory data structure */
4268  SCIP_EXPR* expr /**< polynomial expression */
4269  )
4270 {
4271  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4272  SCIP_EXPRDATA_MONOMIAL* monomial;
4273  SCIP_Bool* childinuse;
4274  int i;
4275  int j;
4276 
4277  assert(blkmem != NULL);
4278  assert(expr != NULL);
4279 
4280  if( expr->nchildren == 0 )
4281  return SCIP_OKAY;
4282 
4283  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4284  assert(polynomialdata != NULL);
4285 
4286  /* check which children are still in use */
4287  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, expr->nchildren) );
4288  BMSclearMemoryArray(childinuse, expr->nchildren); /*lint !e644*/
4289  for( i = 0; i < polynomialdata->nmonomials; ++i )
4290  {
4291  monomial = polynomialdata->monomials[i];
4292  assert(monomial != NULL);
4293 
4294  for( j = 0; j < monomial->nfactors; ++j )
4295  {
4296  assert(monomial->childidxs[j] >= 0);
4297  assert(monomial->childidxs[j] < expr->nchildren);
4298  childinuse[monomial->childidxs[j]] = TRUE;
4299  }
4300  }
4301 
4302  /* free children that are not used in any monomial */
4303  for( i = 0; i < expr->nchildren; ++i )
4304  if( expr->children[i] != NULL && !childinuse[i] )
4305  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4306 
4307  BMSfreeBlockMemoryArray(blkmem, &childinuse, expr->nchildren);
4308 
4309  return SCIP_OKAY;
4310 }
4311 
4312 /** flattens polynomials in polynomials, check for constants in non-polynomials expressions
4313  *
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,
4579  (SCIP_EXPRDATA_POLYNOMIAL*)expr->children[i]->data.data, childmap, maxexpansionexponent, &success) );
4580 
4581  if( !success )
4582  {
4583  removechild = FALSE;
4584  ++j;
4585  }
4586  }
4587  else
4588  ++j;
4589 
4590  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
4591  * we thus repeat with index j, if a factor was successfully expanded
4592  */
4593  }
4594 
4595  /* forget about child i, if it is not used anymore */
4596  if( removechild )
4597  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4598 
4599  /* simplify current polynomial again */
4600  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4601  }
4602 
4603  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
4604 
4605  /* free children that are not in use anymore */
4607 
4608  /* remove NULLs from children array */
4610 
4611  /* if no children left, then it's a constant polynomial -> change into EXPR_CONST */
4612  if( expr->nchildren == 0 )
4613  {
4614  SCIP_Real val;
4615 
4616  /* if no children, then it should also have no monomials */
4617  assert(polynomialdata->nmonomials == 0);
4618 
4619  val = polynomialdata->constant;
4620  polynomialdataFree(blkmem, &polynomialdata);
4621 
4622  expr->op = SCIP_EXPR_CONST;
4623  expr->data.dbl = val;
4624  }
4625 
4626  SCIPdebugMessage("-> ");
4627  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4628  SCIPdebugPrintf("\n");
4629 
4630  break;
4631  }
4632 
4633  default:
4634  SCIPerrorMessage("operand %d unknown\n", expr->op);
4635  return SCIP_ERROR;
4636  } /*lint !e788*/
4637 
4638  return SCIP_OKAY;
4639 }
4640 
4641 /** separates linear monomials from an expression, if it is a polynomial expression
4642  *
4643  * Separates only those linear terms whose variable is not used otherwise in the expression.
4644  */
4645 static
4647  BMS_BLKMEM* blkmem, /**< block memory data structure */
4648  SCIP_EXPR* expr, /**< expression */
4649  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
4650  int nvars, /**< number of variables in expression */
4651  int* nlinvars, /**< buffer to store number of linear variables in linear part */
4652  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part */
4653  SCIP_Real* lincoefs /**< array to store coefficients of linear part */
4654  )
4655 {
4656  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4657  SCIP_EXPRDATA_MONOMIAL* monomial;
4658  int* varsusage;
4659  int* childusage;
4660  int childidx;
4661  int i;
4662  int j;
4663 
4664  assert(blkmem != NULL);
4665  assert(expr != NULL);
4666  assert(nlinvars != NULL);
4667  assert(linidxs != NULL);
4668  assert(lincoefs != NULL);
4669 
4670  *nlinvars = 0;
4671 
4673  return SCIP_OKAY;
4674 
4675  if( SCIPexprGetNChildren(expr) == 0 )
4676  return SCIP_OKAY;
4677 
4678  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4679  assert(polynomialdata != NULL);
4680 
4681  /* get variable usage */
4682  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &varsusage, nvars) );
4683  BMSclearMemoryArray(varsusage, nvars); /*lint !e644*/
4684  SCIPexprGetVarsUsage(expr, varsusage);
4685 
4686  /* get child usage: how often each child is used in the polynomial */
4687  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childusage, expr->nchildren) );
4688  BMSclearMemoryArray(childusage, expr->nchildren); /*lint !e644*/
4689  for( i = 0; i < polynomialdata->nmonomials; ++i )
4690  {
4691  monomial = polynomialdata->monomials[i];
4692  assert(monomial != NULL);
4693  for( j = 0; j < monomial->nfactors; ++j )
4694  {
4695  assert(monomial->childidxs[j] >= 0);
4696  assert(monomial->childidxs[j] < expr->nchildren);
4697  ++childusage[monomial->childidxs[j]];
4698  }
4699  }
4700 
4701  /* move linear monomials out of polynomial */
4702  for( i = 0; i < polynomialdata->nmonomials; ++i )
4703  {
4704  monomial = polynomialdata->monomials[i];
4705  assert(monomial != NULL);
4706  if( monomial->nfactors != 1 )
4707  continue;
4708  if( monomial->exponents[0] != 1.0 )
4709  continue;
4710  childidx = monomial->childidxs[0];
4711  if( SCIPexprGetOperator(expr->children[childidx]) != SCIP_EXPR_VARIDX )
4712  continue;
4713 
4714  /* we are at a linear monomial in a variable */
4715  assert(SCIPexprGetOpIndex(expr->children[childidx]) < nvars);
4716  if( childusage[childidx] == 1 && varsusage[SCIPexprGetOpIndex(expr->children[childidx])] == 1 )
4717  {
4718  /* if the child expression is not used in another monomial (which would due to merging be not linear)
4719  * and if the variable is not used somewhere else in the tree,
4720  * then move this monomial into linear part and free child
4721  */
4722  linidxs[*nlinvars] = SCIPexprGetOpIndex(expr->children[childidx]);
4723  lincoefs[*nlinvars] = monomial->coef;
4724  ++*nlinvars;
4725 
4726  SCIPexprFreeDeep(blkmem, &expr->children[childidx]);
4727  monomial->coef = 0.0;
4728  monomial->nfactors = 0;
4729  }
4730  }
4731 
4732  BMSfreeBlockMemoryArray(blkmem, &varsusage, nvars);
4733  BMSfreeBlockMemoryArray(blkmem, &childusage, expr->nchildren);
4734 
4735  if( *nlinvars > 0 )
4736  {
4737  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
4738  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, FALSE);
4740  }
4741 
4742  return SCIP_OKAY;
4743 }
4744 
4745 /** converts polynomial expressions back into simpler expressions, where possible */
4746 static
4748  BMS_BLKMEM* blkmem, /**< block memory data structure */
4749  SCIP_EXPR* expr /**< expression to convert back */
4750  )
4751 {
4752  int i;
4753 
4754  assert(blkmem != NULL);
4755  assert(expr != NULL);
4756 
4757  for( i = 0; i < expr->nchildren; ++i )
4758  {
4760  }
4761 
4762  if( expr->op != SCIP_EXPR_POLYNOMIAL )
4763  return SCIP_OKAY;
4764 
4765  SCIP_CALL( exprUnconvertPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren, (void**)expr->children) );
4766 
4767  return SCIP_OKAY;
4768 }
4769 
4770 static
4771 SCIP_DECL_HASHGETKEY( exprparseVarTableGetKey )
4772 { /*lint --e{715}*/
4773  return (void*)((char*)elem + sizeof(int));
4774 }
4775 
4776 /** parses a variable name from a string and creates corresponding expression
4777  *
4778  * Creates a new variable index if variable not seen before, updates varnames and vartable structures.
4779  */
4780 static
4782  BMS_BLKMEM* blkmem, /**< block memory data structure */
4783  const char** str, /**< pointer to the string to be parsed */
4784  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
4785  int* nvars, /**< running number of encountered variables so far */
4786  int** varnames, /**< pointer to buffer to store new variable names */
4787  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
4788  SCIP_Real coefficient, /**< coefficient to be used when creating the expression */
4789  const char* varnameendptr /**< if a <varname> should be parsed, set this to NULL. Then, str points to the '<'
4790  else, str should point to the first letter of the varname, and varnameendptr should
4791  point one char behind the last char of the variable name */
4792  )
4793 {
4794  int namelength;
4795  int varidx;
4796  char varname[SCIP_MAXSTRLEN];
4797  void* element;
4798 
4799  assert(blkmem != NULL);
4800  assert(str != NULL);
4801  assert(expr != NULL);
4802  assert(nvars != NULL);
4803  assert(varnames != NULL);
4804  assert(vartable != NULL);
4805 
4806  if( varnameendptr == NULL )
4807  {
4808  ++*str;
4809  varnameendptr = *str;
4810  while( varnameendptr[0] != '>' )
4811  ++varnameendptr;
4812  }
4813 
4814  namelength = varnameendptr - *str;
4815  if( namelength >= SCIP_MAXSTRLEN )
4816  {
4817  SCIPerrorMessage("Variable name %.*s is too long for buffer in exprparseReadVariable.\n", namelength, str);
4818  return SCIP_READERROR;
4819  }
4820 
4821  memcpy(varname, *str, namelength * sizeof(char));
4822  varname[namelength] = '\0';
4823 
4824  element = SCIPhashtableRetrieve(vartable, varname);
4825  if( element != NULL )
4826  {
4827  /* variable is old friend */
4828  assert(strcmp((char*)element + sizeof(int), varname) == 0);
4829 
4830  varidx = *(int*)element;
4831  }
4832  else
4833  {
4834  /* variable is new */
4835  varidx = *nvars;
4836 
4837  /* store index of variable and variable name in varnames buffer */
4838  **varnames = varidx;
4839  strcpy((char*)(*varnames + 1), varname);
4840 
4841  /* insert variable into hashtable */
4842  SCIP_CALL( SCIPhashtableInsert(vartable, (void*)*varnames) );
4843 
4844  ++*nvars;
4845  *varnames += 1 + (strlen(varname) + 1) / sizeof(int) + 1;
4846  }
4847 
4848  /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
4849  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_VARIDX, varidx) ); /*lint !e613*/
4850  if( coefficient != 1.0 )
4851  {
4852  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, expr, &coefficient, 0.0) );
4853  }
4854 
4855  /* Move pointer to char behind end of variable */
4856  *str = varnameendptr + 1;
4857 
4858  /* consprint sometimes prints a variable type identifier which we don't need */
4859  if( (*str)[0] == '[' && (*str)[2] == ']' &&
4860  ((*str)[1] == SCIP_VARTYPE_BINARY_CHAR ||
4861  (*str)[1] == SCIP_VARTYPE_INTEGER_CHAR ||
4862  (*str)[1] == SCIP_VARTYPE_IMPLINT_CHAR ||
4863  (*str)[1] == SCIP_VARTYPE_CONTINUOUS_CHAR ) )
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 == '_' || *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, hash marks, and underscores here */
5117  while( isalnum(str[0]) || 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 /** creates a simple expression */
5598  BMS_BLKMEM* blkmem, /**< block memory data structure */
5599  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
5600  SCIP_EXPROP op, /**< operand of expression */
5601  ... /**< arguments of operand */
5602  )
5603 {
5604  va_list ap;
5605  SCIP_EXPR** children;
5606  SCIP_EXPROPDATA opdata;
5607 
5608  assert(blkmem != NULL);
5609  assert(expr != NULL);
5610 
5611  switch( op )
5612  {
5613  case SCIP_EXPR_VARIDX:
5614  case SCIP_EXPR_PARAM:
5615  {
5616  va_start( ap, op ); /*lint !e826*/
5617  opdata.intval = va_arg( ap, int ); /*lint !e416 !e826*/
5618  va_end( ap ); /*lint !e826*/
5619 
5620  assert( opdata.intval >= 0 );
5621 
5622  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5623  break;
5624  }
5625 
5626  case SCIP_EXPR_CONST:
5627  {
5628  va_start(ap, op ); /*lint !e826*/
5629  opdata.dbl = va_arg( ap, SCIP_Real ); /*lint !e416 !e826*/
5630  va_end( ap ); /*lint !e826*/
5631 
5632  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5633  break;
5634  }
5635 
5636  /* operands with two children */
5637  case SCIP_EXPR_PLUS :
5638  case SCIP_EXPR_MINUS :
5639  case SCIP_EXPR_MUL :
5640  case SCIP_EXPR_DIV :
5641  case SCIP_EXPR_MIN :
5642  case SCIP_EXPR_MAX :
5643  {
5644  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 2) ); /*lint !e506*/
5645 
5646  va_start(ap, op ); /*lint !e826*/
5647  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5648  children[1] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5649  assert(children[0] != NULL);
5650  assert(children[1] != NULL);
5651  va_end( ap ); /*lint !e826*/
5652  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
5653 
5654  SCIP_CALL( exprCreate( blkmem, expr, op, 2, children, opdata ) );
5655  break;
5656  }
5657 
5658  /* operands with one child */
5659  case SCIP_EXPR_SQUARE:
5660  case SCIP_EXPR_SQRT :
5661  case SCIP_EXPR_EXP :
5662  case SCIP_EXPR_LOG :
5663  case SCIP_EXPR_SIN :
5664  case SCIP_EXPR_COS :
5665  case SCIP_EXPR_TAN :
5666  /* case SCIP_EXPR_ERF : */
5667  /* case SCIP_EXPR_ERFI : */
5668  case SCIP_EXPR_ABS :
5669  case SCIP_EXPR_SIGN :
5670  {
5671  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
5672 
5673  va_start(ap, op ); /*lint !e826*/
5674  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5675  assert(children[0] != NULL);
5676  va_end( ap ); /*lint !e826*/
5677  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
5678 
5679  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
5680  break;
5681  }
5682 
5683  case SCIP_EXPR_REALPOWER:
5684  case SCIP_EXPR_SIGNPOWER:
5685  {
5686  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
5687 
5688  va_start(ap, op ); /*lint !e826*/
5689  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5690  assert(children[0] != NULL);
5691  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
5692  va_end( ap ); /*lint !e826*/
5693 
5694  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
5695  break;
5696  }
5697 
5698  case SCIP_EXPR_INTPOWER:
5699  {
5700  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
5701 
5702  va_start(ap, op ); /*lint !e826*/
5703  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5704  assert(children[0] != NULL);
5705  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
5706  va_end( ap ); /*lint !e826*/
5707 
5708  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
5709  break;
5710  }
5711 
5712  /* complex operands */
5713  case SCIP_EXPR_SUM :
5714  case SCIP_EXPR_PRODUCT:
5715  {
5716  int nchildren;
5717  SCIP_EXPR** childrenarg;
5718 
5719  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
5720 
5721  va_start(ap, op ); /*lint !e826*/
5722  /* first argument should be number of children */
5723  nchildren = va_arg( ap, int ); /*lint !e416 !e826*/
5724  assert(nchildren >= 0);
5725 
5726  /* for a sum or product of 0 terms we can finish here */
5727  if( nchildren == 0 )
5728  {
5729  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata) );
5730  va_end( ap ); /*lint !e826*/
5731  break;
5732  }
5733 
5734  /* next argument should be array of children expressions */
5735  childrenarg = va_arg( ap, SCIP_EXPR** ); /*lint !e416 !e826*/
5736  assert(childrenarg != NULL);
5737  va_end( ap ); /*lint !e826*/
5738 
5739  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &children, childrenarg, nchildren) );
5740 
5741  SCIP_CALL( exprCreate( blkmem, expr, op, nchildren, children, opdata) );
5742  break;
5743  }
5744 
5745  case SCIP_EXPR_LINEAR :
5746  case SCIP_EXPR_QUADRATIC:
5747  case SCIP_EXPR_POLYNOMIAL:
5748  {
5749  SCIPerrorMessage("cannot create complex expression linear, quadratic, or polynomial with SCIPexprCreate\n");
5750  return SCIP_INVALIDDATA;
5751  }
5752 
5753  case SCIP_EXPR_LAST:
5754  default:
5755  SCIPerrorMessage("unknown operand: %d\n", op);
5756  return SCIP_INVALIDDATA;
5757  }
5758 
5759  return SCIP_OKAY;
5760 }
5761 
5762 /** copies an expression including its children */
5764  BMS_BLKMEM* blkmem, /**< block memory data structure */
5765  SCIP_EXPR** targetexpr, /**< buffer to store pointer to copied expression */
5766  SCIP_EXPR* sourceexpr /**< expression to copy */
5767  )
5768 {
5769  assert(blkmem != NULL);
5770  assert(targetexpr != NULL);
5771  assert(sourceexpr != NULL);
5772 
5773  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targetexpr, sourceexpr) );
5774 
5775  if( sourceexpr->nchildren )
5776  {
5777  int i;
5778 
5779  /* alloc memory for children expressions */
5780  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetexpr)->children, sourceexpr->nchildren) );
5781 
5782  /* copy children expressions */
5783  for( i = 0; i < sourceexpr->nchildren; ++i )
5784  {
5785  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targetexpr)->children[i], sourceexpr->children[i]) );
5786  }
5787  }
5788  else
5789  {
5790  assert((*targetexpr)->children == NULL); /* otherwise, sourceexpr->children was not NULL, which is wrong */
5791  }
5792 
5793  /* call operands data copy callback for complex operands
5794  * for simple operands BMSduplicate above should have done the job
5795  */
5796  if( exprOpTable[sourceexpr->op].copydata != NULL )
5797  {
5798  SCIP_CALL( exprOpTable[sourceexpr->op].copydata(blkmem, sourceexpr->nchildren, sourceexpr->data, &(*targetexpr)->data) );
5799  }
5800 
5801  return SCIP_OKAY;
5802 }
5803 
5804 /** frees an expression including its children */
5806  BMS_BLKMEM* blkmem, /**< block memory data structure */
5807  SCIP_EXPR** expr /**< pointer to expression to free */
5808  )
5809 {
5810  assert(blkmem != NULL);
5811  assert(expr != NULL);
5812  assert(*expr != NULL);
5813 
5814  /* call operands data free callback, if given */
5815  if( exprOpTable[(*expr)->op].freedata != NULL )
5816  {
5817  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
5818  }
5819 
5820  if( (*expr)->nchildren )
5821  {
5822  int i;
5823 
5824  assert( (*expr)->children != NULL );
5825 
5826  for( i = 0; i < (*expr)->nchildren; ++i )
5827  {
5828  SCIPexprFreeDeep(blkmem, &(*expr)->children[i]);
5829  assert((*expr)->children[i] == NULL);
5830  }
5831 
5832  BMSfreeBlockMemoryArray(blkmem, &(*expr)->children, (*expr)->nchildren);
5833  }
5834  else
5835  {
5836  assert( (*expr)->children == NULL );
5837  }
5838 
5839  BMSfreeBlockMemory(blkmem, expr);
5840 }
5841 
5842 /** frees an expression but not its children */
5844  BMS_BLKMEM* blkmem, /**< block memory data structure */
5845  SCIP_EXPR** expr /**< pointer to expression to free */
5846  )
5847 {
5848  assert(blkmem != NULL);
5849  assert(expr != NULL);
5850  assert(*expr != NULL);
5851 
5852  /* call operands data free callback, if given */
5853  if( exprOpTable[(*expr)->op].freedata != NULL )
5854  {
5855  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
5856  }
5857 
5858  BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->nchildren);
5859 
5860  BMSfreeBlockMemory(blkmem, expr);
5861 }
5862 
5863 /** creates an expression from the addition of two given expression, with coefficients, and a constant
5864  *
5865  * The given expressions may be modified or freed, otherwise it will be used a child expression.
5866  * Favors creation and maintaining of SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
5867  */
5869  BMS_BLKMEM* blkmem, /**< block memory data structure */
5870  SCIP_EXPR** expr, /**< pointer to store pointer to created expression */
5871  SCIP_Real coef1, /**< coefficient of first term */
5872  SCIP_EXPR* term1, /**< expression of first term, or NULL */
5873  SCIP_Real coef2, /**< coefficient of second term */
5874  SCIP_EXPR* term2, /**< expression of second term, or NULL */
5875  SCIP_Real constant /**< constant term to add */
5876  )
5877 {
5878  assert(blkmem != NULL);
5879  assert(expr != NULL);
5880 
5881  /* @todo could do something special with quadratic and polynomial expressions */
5882 
5883  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_CONST )
5884  {
5885  constant += coef1 * SCIPexprGetOpReal(term1);
5886  SCIPexprFreeDeep(blkmem, &term1);
5887  }
5888 
5889  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_CONST )
5890  {
5891  constant += coef2 * SCIPexprGetOpReal(term2);
5892  SCIPexprFreeDeep(blkmem, &term2);
5893  }
5894 
5895  if( term1 == NULL && term2 == NULL )
5896  {
5897  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, constant) );
5898  return SCIP_OKAY;
5899  }
5900 
5901  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && coef1 != 1.0 )
5902  {
5903  /* multiply coefficients and constant of linear expression term1 by coef1 */
5904  SCIP_Real* data;
5905  int i;
5906 
5907  data = (SCIP_Real*)term1->data.data;
5908  assert(data != NULL);
5909 
5910  /* loop one more index to multiply also constant of linear expression */
5911  for( i = 0; i <= term1->nchildren; ++i )
5912  data[i] *= coef1;
5913 
5914  coef1 = 1.0;
5915  }
5916 
5917  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR && coef2 != 1.0 )
5918  {
5919  /* multiply coefficients and constant of linear expression term2 by coef2 */
5920  SCIP_Real* data;
5921  int i;
5922 
5923  data = (SCIP_Real*)term2->data.data;
5924  assert(data != NULL);
5925 
5926  /* loop one more index to multiply also constant of linear expression */
5927  for( i = 0; i <= term2->nchildren; ++i )
5928  data[i] *= coef2;
5929 
5930  coef2 = 1.0;
5931  }
5932 
5933  if( term1 == NULL || term2 == NULL )
5934  {
5935  if( term1 == NULL )
5936  {
5937  term1 = term2;
5938  coef1 = coef2;
5939  }
5940  if( constant != 0.0 || coef1 != 1.0 )
5941  {
5942  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
5943  {
5944  assert(coef1 == 1.0);
5945 
5946  /* add constant to existing linear expression */
5947  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 0, NULL, NULL, constant) );
5948  *expr = term1;
5949  }
5950  else
5951  {
5952  /* create new linear expression for coef1 * term1 + constant */
5953  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term1, &coef1, constant) );
5954  }
5955  }
5956  else
5957  {
5958  assert(constant == 0.0);
5959  assert(coef1 == 1.0);
5960  *expr = term1;
5961  }
5962 
5963  return SCIP_OKAY;
5964  }
5965 
5967  {
5968  /* add 2nd linear expression to first one */
5969  assert(coef1 == 1.0);
5970  assert(coef2 == 1.0);
5971 
5973  SCIPexprFreeShallow(blkmem, &term2);
5974 
5975  *expr = term1;
5976 
5977  return SCIP_OKAY;
5978  }
5979 
5980  if( SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
5981  {
5982  /* if only term2 is linear, then swap */
5983  SCIP_EXPR* tmp;
5984 
5985  tmp = term2;
5986  assert(coef2 == 1.0);
5987 
5988  term2 = term1;
5989  coef2 = coef1;
5990  term1 = tmp;
5991  coef1 = 1.0;
5992  }
5993 
5994  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
5995  {
5996  /* add coef2*term2 as extra child to linear expression term1 */
5997  assert(coef1 == 1.0);
5998 
5999  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 1, &coef2, &term2, constant) );
6000  *expr = term1;
6001 
6002  return SCIP_OKAY;
6003  }
6004 
6005  /* both terms are not linear, then create new linear term for sum */
6006  {
6007  SCIP_Real coefs[2];
6008  SCIP_EXPR* children[2];
6009 
6010  coefs[0] = coef1;
6011  coefs[1] = coef2;
6012  children[0] = term1;
6013  children[1] = term2;
6014 
6015  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 2, children, coefs, constant) );
6016  }
6017 
6018  return SCIP_OKAY;
6019 }
6020 
6021 /** creates an expression from the multiplication of an expression with a constant
6022  *
6023  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6024  * Favors creation and maintaining SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6025  */
6027  BMS_BLKMEM* blkmem, /**< block memory data structure */
6028  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
6029  SCIP_EXPR* term, /**< term to multiply by factor */
6030  SCIP_Real factor /**< factor */
6031  )
6032 {
6033  assert(blkmem != NULL);
6034  assert(expr != NULL);
6035  assert(term != NULL);
6036 
6037  if( factor == 0.0 )
6038  {
6039  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, 0.0) );
6040 
6041  SCIPexprFreeDeep(blkmem, &term);
6042 
6043  return SCIP_OKAY;
6044  }
6045  if( factor == 1.0 )
6046  {
6047  *expr = term;
6048  return SCIP_OKAY;
6049  }
6050 
6051  switch( SCIPexprGetOperator(term) )
6052  {
6053  case SCIP_EXPR_CONST :
6054  {
6055  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, factor * SCIPexprGetOpReal(term)) );
6056  SCIPexprFreeDeep(blkmem, &term);
6057  break;
6058  }
6059 
6060  case SCIP_EXPR_LINEAR :
6061  {
6062  SCIP_Real* data;
6063  int i;
6064 
6065  data = (SCIP_Real*)term->data.data;
6066  assert(data != NULL);
6067 
6068  /* loop one more index to multiply also constant of linear expression */
6069  for( i = 0; i <= SCIPexprGetNChildren(term); ++i )
6070  data[i] *= factor;
6071 
6072  *expr = term;
6073  break;
6074  }
6075 
6076  case SCIP_EXPR_QUADRATIC :
6077  {
6079  int i;
6080 
6081  data = (SCIP_EXPRDATA_QUADRATIC*)term->data.data;
6082 
6083  data->constant *= factor;
6084 
6085  if( data->lincoefs != NULL )
6086  for( i = 0; i < term->nchildren; ++i )
6087  data->lincoefs[i] *= factor;
6088 
6089  for( i = 0; i < data->nquadelems; ++i )
6090  data->quadelems[i].coef *= factor;
6091 
6092  *expr = term;
6093  break;
6094  }
6095 
6096  case SCIP_EXPR_POLYNOMIAL :
6097  {
6099  int i;
6100 
6101  data = (SCIP_EXPRDATA_POLYNOMIAL*)term->data.data;
6102 
6103  data->constant *= factor;
6104 
6105  for( i = 0; i < data->nmonomials; ++i )
6106  data->monomials[i]->coef *= factor;
6107 
6108  *expr = term;
6109  break;
6110  }
6111 
6112  default:
6113  {
6114  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term, &factor, 0.0) );
6115  break;
6116  }
6117 
6118  } /*lint !e788 */
6119 
6120  return SCIP_OKAY;
6121 }
6122 
6123 /** creates a SCIP_EXPR_LINEAR expression that is (affine) linear in its children: constant + sum_i coef_i child_i */
6125  BMS_BLKMEM* blkmem, /**< block memory data structure */
6126  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6127  int nchildren, /**< number of children */
6128  SCIP_EXPR** children, /**< children of expression */
6129  SCIP_Real* coefs, /**< coefficients of children */
6130  SCIP_Real constant /**< constant part */
6131  )
6132 {
6133  SCIP_EXPROPDATA opdata;
6134  SCIP_EXPR** childrencopy;
6135  SCIP_Real* data;
6136 
6137  assert(nchildren >= 0);
6138  assert(children != NULL || nchildren == 0);
6139  assert(coefs != NULL || nchildren == 0);
6140 
6141  if( nchildren > 0 )
6142  {
6143  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6144  }
6145  else
6146  childrencopy = NULL;
6147 
6148  /* we store the coefficients and the constant in a single array and make this our operand data */
6149  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, nchildren + 1) );
6150  BMScopyMemoryArray(data, coefs, nchildren); /*lint !e644*/
6151  data[nchildren] = constant;
6152 
6153  opdata.data = (void*)data;
6154 
6155  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_LINEAR, nchildren, childrencopy, opdata) );
6156 
6157  return SCIP_OKAY;
6158 }
6159 
6160 /** adds new terms to a linear expression */
6162  BMS_BLKMEM* blkmem, /**< block memory */
6163  SCIP_EXPR* expr, /**< linear expression */
6164  int nchildren, /**< number of children to add */
6165  SCIP_Real* coefs, /**< coefficients of additional children */
6166  SCIP_EXPR** children, /**< additional children expressions */
6167  SCIP_Real constant /**< constant to add */
6168  )
6169 {
6170  SCIP_Real* data;
6171 
6172  assert(blkmem != NULL);
6173  assert(expr != NULL);
6174  assert(expr->op == SCIP_EXPR_LINEAR);
6175  assert(nchildren >= 0);
6176  assert(coefs != NULL || nchildren == 0);
6177  assert(children != NULL || nchildren == 0);
6178 
6179  data = (SCIP_Real*)expr->data.data;
6180  assert(data != NULL);
6181 
6182  /* handle simple case of adding a constant */
6183  if( nchildren == 0 )
6184  {
6185  data[expr->nchildren] += constant;
6186 
6187  return SCIP_OKAY;
6188  }
6189 
6190  /* add new children to expr's children array */
6191  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nchildren) );
6192  BMScopyMemoryArray(&expr->children[expr->nchildren], children, nchildren); /*lint !e866*/
6193 
6194  /* add constant and new coefs to expr's data array */
6195  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, expr->nchildren + 1, expr->nchildren + nchildren + 1) );
6196  data[expr->nchildren + nchildren] = data[expr->nchildren] + constant;
6197  BMScopyMemoryArray(&data[expr->nchildren], coefs, nchildren); /*lint !e866*/
6198  expr->data.data = (void*)data;
6199 
6200  expr->nchildren += nchildren;
6201 
6202  return SCIP_OKAY;
6203 }
6204 
6205 /** creates a SCIP_EXPR_QUADRATIC expression: constant + sum_i coef_i child_i + sum_i coef_i child1_i child2_i */
6207  BMS_BLKMEM* blkmem, /**< block memory data structure */
6208  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6209  int nchildren, /**< number of children */
6210  SCIP_EXPR** children, /**< children of expression */
6211  SCIP_Real constant, /**< constant */
6212  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
6213  int nquadelems, /**< number of quadratic elements */
6214  SCIP_QUADELEM* quadelems /**< quadratic elements specifying coefficients and child indices */
6215  )
6216 {
6217  SCIP_EXPROPDATA opdata;
6218  SCIP_EXPR** childrencopy;
6220 
6221  assert(nchildren >= 0);
6222  assert(children != NULL || nchildren == 0);
6223  assert(quadelems != NULL || nquadelems == 0);
6224 
6225  if( nchildren > 0 )
6226  {
6227  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6228  }
6229  else
6230  childrencopy = NULL;
6231 
6232  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
6233 
6234  opdata.data = (void*)data;
6235 
6236  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_QUADRATIC, nchildren, childrencopy, opdata) );
6237 
6238  return SCIP_OKAY;
6239 }
6240 
6241 /** ensures that quadratic elements of a quadratic expression are sorted */
6243  SCIP_EXPR* expr /**< quadratic expression */
6244  )
6245 {
6246  assert(expr != NULL);
6247  assert(expr->op == SCIP_EXPR_QUADRATIC);
6248  assert(expr->data.data != NULL);
6249 
6251 }
6252 
6253 /** creates a SCIP_EXPR_POLYNOMIAL expression from an array of monomials: constant + sum_i monomial_i */
6255  BMS_BLKMEM* blkmem, /**< block memory data structure */
6256  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6257  int nchildren, /**< number of children */
6258  SCIP_EXPR** children, /**< children of expression */
6259  int nmonomials, /**< number of monomials */
6260  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
6261  SCIP_Real constant, /**< constant part */
6262  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6263  )
6264 {
6265  SCIP_EXPROPDATA opdata;
6266  SCIP_EXPR** childrencopy;
6268 
6269  assert(nchildren >= 0);
6270  assert(children != NULL || nchildren == 0);
6271  assert(monomials != NULL || nmonomials == 0);
6272 
6273  if( nchildren > 0 )
6274  {
6275  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6276  }
6277  else
6278  childrencopy = NULL;
6279 
6280  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
6281  opdata.data = (void*)data;
6282 
6283  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_POLYNOMIAL, nchildren, childrencopy, opdata) );
6284 
6285  return SCIP_OKAY;
6286 }
6287 
6288 /** adds an array of monomials to a SCIP_EXPR_POLYNOMIAL expression */
6290  BMS_BLKMEM* blkmem, /**< block memory of expression */
6291  SCIP_EXPR* expr, /**< expression */
6292  int nmonomials, /**< number of monomials to add */
6293  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
6294  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6295  )
6296 {
6297  assert(blkmem != NULL);
6298  assert(expr != NULL);
6299  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6300  assert(monomials != NULL || nmonomials == 0);
6301 
6302  if( nmonomials == 0 )
6303  return SCIP_OKAY;
6304 
6305  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, nmonomials, monomials, copymonomials) );
6306 
6307  return SCIP_OKAY;
6308 }
6309 
6310 /** changes the constant in a SCIP_EXPR_POLYNOMIAL expression */
6312  SCIP_EXPR* expr, /**< expression */
6313  SCIP_Real constant /**< new value for constant */
6314  )
6315 {
6316  assert(expr != NULL);
6317  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6318  assert(expr->data.data != NULL);
6319 
6320  ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant = constant;
6321 }
6322 
6323 /** multiplies each summand of a polynomial by a given constant */
6325  BMS_BLKMEM* blkmem, /**< block memory */
6326  SCIP_EXPR* expr, /**< polynomial expression */
6327  SCIP_Real factor /**< constant factor */
6328  )
6329 {
6330  assert(expr != NULL);
6331  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6332  assert(expr->data.data != NULL);
6333 
6334  polynomialdataMultiplyByConstant(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor);
6335 }
6336 
6337 /** multiplies each summand of a polynomial by a given monomial */
6339  BMS_BLKMEM* blkmem, /**< block memory */
6340  SCIP_EXPR* expr, /**< polynomial expression */
6341  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
6342  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6343  )
6344 {
6345  assert(blkmem != NULL);
6346  assert(factor != NULL);
6347  assert(expr != NULL);
6348  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6349  assert(expr->data.data != NULL);
6350 
6351  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor, childmap) );
6352 
6353  return SCIP_OKAY;
6354 }
6355 
6356 /** multiplies this polynomial by a polynomial
6357  *
6358  * Factor needs to be different from expr.
6359  * Children of factor need to be children of expr already, w.r.t. an optional mapping of child indices.
6360  */
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  *
6404  * Exponent need to be an integer.
6405  * Polynomial needs to be a monomial, if exponent is negative.
6406  */
6408  BMS_BLKMEM* blkmem, /**< block memory */
6409  SCIP_EXPR* expr, /**< polynomial expression */
6410  int exponent /**< exponent of power operation */
6411  )
6412 {
6413  assert(blkmem != NULL);
6414  assert(expr != NULL);
6415  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6416  assert(expr->data.data != NULL);
6417 
6418  SCIP_CALL( polynomialdataPower(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, exponent) );
6419 
6420  return SCIP_OKAY;
6421 }
6422 
6423 /** merges monomials in a polynomial expression that differ only in coefficient into a single monomial
6424  *
6425  * Eliminates monomials with coefficient between -eps and eps.
6426  */
6428  BMS_BLKMEM* blkmem, /**< block memory */
6429  SCIP_EXPR* expr, /**< polynomial expression */
6430  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
6431  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
6432  )
6433 {
6434  assert(expr != NULL);
6435  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6436  assert(expr->data.data != NULL);
6437 
6438  polynomialdataMergeMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, eps, mergefactors);
6439 }
6440 
6441 /** checks if two monomials are equal */
6443  SCIP_EXPRDATA_MONOMIAL* monomial1, /**< first monomial */
6444  SCIP_EXPRDATA_MONOMIAL* monomial2, /**< second monomial */
6445  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6446  )
6447 {
6448  int i;
6449 
6450  assert(monomial1 != NULL);
6451  assert(monomial2 != NULL);
6452 
6453  if( monomial1->nfactors != monomial2->nfactors )
6454  return FALSE;
6455 
6456  if( !EPSEQ(monomial1->coef, monomial2->coef, eps) )
6457  return FALSE;
6458 
6459  SCIPexprSortMonomialFactors(monomial1);
6460  SCIPexprSortMonomialFactors(monomial2);
6461 
6462  for( i = 0; i < monomial1->nfactors; ++i )
6463  {
6464  if( monomial1->childidxs[i] != monomial2->childidxs[i] ||
6465  !EPSEQ(monomial1->exponents[i], monomial2->exponents[i], eps) )
6466  return FALSE;
6467  }
6468 
6469  return TRUE;
6470 }
6471 
6472 /** changes coefficient of monomial */
6474  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6475  SCIP_Real newcoef /**< new coefficient */
6476  )
6477 {
6478  assert(monomial != NULL);
6479 
6480  monomial->coef = newcoef;
6481 }
6482 
6483 /** adds factors to a monomial */
6485  BMS_BLKMEM* blkmem, /**< block memory */
6486  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6487  int nfactors, /**< number of factors to add */
6488  int* childidxs, /**< indices of children corresponding to factors */
6489  SCIP_Real* exponents /**< exponent in each factor */
6490  )
6491 {
6492  assert(monomial != NULL);
6493  assert(nfactors >= 0);
6494  assert(childidxs != NULL || nfactors == 0);
6495  assert(exponents != NULL || nfactors == 0);
6496 
6497  if( nfactors == 0 )
6498  return SCIP_OKAY;
6499 
6500  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + nfactors) );
6501  assert(monomial->nfactors + nfactors <= monomial->factorssize);
6502 
6503  BMScopyMemoryArray(&monomial->childidxs[monomial->nfactors], childidxs, nfactors); /*lint !e866*/
6504  BMScopyMemoryArray(&monomial->exponents[monomial->nfactors], exponents, nfactors); /*lint !e866*/
6505 
6506  monomial->nfactors += nfactors;
6507  monomial->sorted = (monomial->nfactors <= 1);
6508 
6509  return SCIP_OKAY;
6510 }
6511 
6512 /** multiplies a monomial with a monomial */
6514  BMS_BLKMEM* blkmem, /**< block memory */
6515  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6516  SCIP_EXPRDATA_MONOMIAL* factor, /**< factor monomial */
6517  int* childmap /**< map to apply to children in factor, or NULL for 1:1 */
6518  )
6519 {
6520  assert(monomial != NULL);
6521  assert(factor != NULL);
6522 
6523  if( factor->coef == 0.0 )
6524  {
6525  monomial->nfactors = 0;
6526  monomial->coef = 0.0;
6527  return SCIP_OKAY;
6528  }
6529 
6530  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, factor->nfactors, factor->childidxs, factor->exponents) );
6531 
6532  if( childmap != NULL )
6533  {
6534  int i;
6535  for( i = monomial->nfactors - factor->nfactors; i < monomial->nfactors; ++i )
6536  monomial->childidxs[i] = childmap[monomial->childidxs[i]];
6537  }
6538 
6539  monomial->coef *= factor->coef;
6540 
6541  return SCIP_OKAY;
6542 }
6543 
6544 /** replaces the monomial by a power of the monomial
6545  *
6546  * Allows only integers as exponent.
6547  */
6549  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6550  int exponent /**< integer exponent of power operation */
6551  )
6552 {
6553  int i;
6554 
6555  assert(monomial != NULL);
6556 
6557  if( exponent == 1 )
6558  return;
6559 
6560  if( exponent == 0 )
6561  {
6562  /* x^0 = 1, unless x = 0; 0^0 = 0 */
6563  if( monomial->coef != 0.0 )
6564  monomial->coef = 1.0;
6565  monomial->nfactors = 0;
6566  return;
6567  }
6568 
6569  monomial->coef = pow(monomial->coef, (SCIP_Real)exponent);
6570  for( i = 0; i < monomial->nfactors; ++i )
6571  monomial->exponents[i] *= exponent;
6572 }
6573 
6574 /** merges factors that correspond to the same child by adding exponents
6575  *
6576  * Eliminates factors with exponent between -eps and eps.
6577  */
6579  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6580  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6581  )
6582 {
6583  int i;
6584  int offset;
6585 
6586  assert(monomial != NULL);
6587  assert(eps >= 0.0);
6588 
6589  SCIPexprSortMonomialFactors(monomial);
6590 
6591  /* merge factors with same child index by adding up their exponents
6592  * delete factors with exponent 0.0 */
6593  offset = 0;
6594  i = 0;
6595  while( i + offset < monomial->nfactors )
6596  {
6597  if( offset > 0 )
6598  {
6599  assert(monomial->childidxs[i] == -1);
6600  assert(monomial->childidxs[i+offset] >= 0);
6601  monomial->childidxs[i] = monomial->childidxs[i+offset];
6602  monomial->exponents[i] = monomial->exponents[i+offset];
6603 #ifndef NDEBUG
6604  monomial->childidxs[i+offset] = -1;
6605 #endif
6606  }
6607 
6608  while( i+offset+1 < monomial->nfactors && monomial->childidxs[i] == monomial->childidxs[i+offset+1] )
6609  {
6610  monomial->exponents[i] += monomial->exponents[i+offset+1];
6611 #ifndef NDEBUG
6612  monomial->childidxs[i+offset+1] = -1;
6613 #endif
6614  ++offset;
6615  }
6616 
6617  if( EPSZ(monomial->exponents[i], eps) )
6618  {
6619 #ifndef NDEBUG
6620  monomial->childidxs[i] = -1;
6621 #endif
6622  ++offset;
6623  continue;
6624  }
6625  else if( EPSISINT(monomial->exponents[i], eps) )
6626  monomial->exponents[i] = EPSROUND(monomial->exponents[i], eps);
6627 
6628  ++i;
6629  }
6630 
6631 #ifndef NDEBUG
6632  while( i < monomial->nfactors )
6633  assert(monomial->childidxs[i++] == -1);
6634 #endif
6635 
6636  monomial->nfactors -= offset;
6637 
6638  if( EPSEQ(monomial->coef, 1.0, eps) )
6639  monomial->coef = 1.0;
6640  else if( EPSEQ(monomial->coef, -1.0, eps) )
6641  monomial->coef = -1.0;
6642 }
6643 
6644 /** ensures that monomials of a polynomial are sorted */
6646  SCIP_EXPR* expr /**< polynomial expression */
6647  )
6648 {
6649  assert(expr != NULL);
6650  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6651  assert(expr->data.data != NULL);
6652 
6654 }
6655 
6656 /** creates a monomial */
6658  BMS_BLKMEM* blkmem, /**< block memory */
6659  SCIP_EXPRDATA_MONOMIAL** monomial, /**< buffer where to store pointer to new monomial */
6660  SCIP_Real coef, /**< coefficient of monomial */
6661  int nfactors, /**< number of factors in monomial */
6662  int* childidxs, /**< indices of children corresponding to factors, or NULL if identity */
6663  SCIP_Real* exponents /**< exponent in each factor, or NULL if all 1.0 */
6664  )
6665 {
6666  assert(blkmem != NULL);
6667  assert(monomial != NULL);
6668 
6669  SCIP_ALLOC( BMSallocBlockMemory(blkmem, monomial) );
6670 
6671  (*monomial)->coef = coef;
6672  (*monomial)->nfactors = nfactors;
6673  (*monomial)->factorssize = nfactors;
6674  (*monomial)->sorted = (nfactors <= 1);
6675 
6676  if( nfactors > 0 )
6677  {
6678  if( childidxs != NULL )
6679  {
6680  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->childidxs, childidxs, nfactors) );
6681  }
6682  else
6683  {
6684  int i;
6685 
6686  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->childidxs, nfactors) );
6687  for( i = 0; i < nfactors; ++i )
6688  (*monomial)->childidxs[i] = i;
6689  }
6690 
6691  if( exponents != NULL )
6692  {
6693  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->exponents, exponents, nfactors) );
6694  }
6695  else
6696  {
6697  int i;
6698 
6699  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->exponents, nfactors) );
6700  for( i = 0; i < nfactors; ++i )
6701  (*monomial)->exponents[i] = 1.0;
6702  }
6703  }
6704  else
6705  {
6706  (*monomial)->childidxs = NULL;
6707  (*monomial)->exponents = NULL;
6708  }
6709 
6710  return SCIP_OKAY;
6711 }
6712 
6713 /** frees a monomial */
6715  BMS_BLKMEM* blkmem, /**< block memory */
6716  SCIP_EXPRDATA_MONOMIAL** monomial /**< pointer to monomial that should be freed */
6717  )
6718 {
6719  assert(blkmem != NULL);
6720  assert( monomial != NULL);
6721  assert(*monomial != NULL);
6722 
6723  if( (*monomial)->factorssize > 0 )
6724  {
6725  assert((*monomial)->childidxs != NULL);
6726  assert((*monomial)->exponents != NULL);
6727 
6728  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->childidxs, (*monomial)->factorssize);
6729  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->exponents, (*monomial)->factorssize);
6730  }
6731  assert((*monomial)->childidxs == NULL);
6732  assert((*monomial)->exponents == NULL);
6733 
6734  BMSfreeBlockMemory(blkmem, monomial);
6735 }
6736 
6737 /** ensures that factors in a monomial are sorted */
6739  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
6740  )
6741 {
6742  assert(monomial != NULL);
6743 
6744  if( monomial->sorted )
6745  return;
6746 
6747  if( monomial->nfactors > 0 )
6748  SCIPsortIntReal(monomial->childidxs, monomial->exponents, monomial->nfactors);
6749 
6750  monomial->sorted = TRUE;
6751 }
6752 
6753 /** finds a factor corresponding to a given child index in a monomial
6754  *
6755  * Note that if the factors have not been merged, the position of some factor corresponding to a given child is given.
6756  * Returns TRUE if a factor is found, FALSE if not.
6757  */
6759  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6760  int childidx, /**< index of the child which factor to search for */
6761  int* pos /**< buffer to store position of factor */
6762  )
6763 {
6764  assert(monomial != NULL);
6765 
6766  if( monomial->nfactors == 0 )
6767  return FALSE;
6768 
6769  SCIPexprSortMonomialFactors(monomial);
6770 
6771  return SCIPsortedvecFindInt(monomial->childidxs, childidx, monomial->nfactors, pos);
6772 }
6773 
6774 /** indicates whether the expression contains a SCIP_EXPR_PARAM */
6776  SCIP_EXPR* expr /**< expression */
6777  )
6778 {
6779  int i;
6780 
6781  assert(expr != NULL);
6782 
6783  if( expr->op == SCIP_EXPR_PARAM )
6784  return TRUE;
6785 
6786  for( i = 0; i < expr->nchildren; ++i )
6787  if( SCIPexprHasParam(expr->children[i]) )
6788  return TRUE;
6789 
6790  return FALSE;
6791 }
6792 
6793 /** gets maximal degree of expression, or SCIP_EXPR_DEGREEINFINITY if not a polynomial */
6795  SCIP_EXPR* expr, /**< expression */
6796  int* maxdegree /**< buffer to store maximal degree */
6797  )
6798 {
6799  int child1;
6800  int child2;
6801 
6802  assert(expr != NULL);
6803  assert(maxdegree != NULL);
6804 
6805  switch( expr->op )
6806  {
6807  case SCIP_EXPR_VARIDX:
6808  *maxdegree = 1;
6809  break;
6810 
6811  case SCIP_EXPR_CONST:
6812  case SCIP_EXPR_PARAM:
6813  *maxdegree = 0;
6814  break;
6815 
6816  case SCIP_EXPR_PLUS:
6817  case SCIP_EXPR_MINUS:
6818  {
6819  assert(expr->children[0] != NULL);
6820  assert(expr->children[1] != NULL);
6821 
6822  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6823  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
6824 
6825  *maxdegree = MAX(child1, child2);
6826  break;
6827  }
6828 
6829  case SCIP_EXPR_MUL:
6830  {
6831  assert(expr->children[0] != NULL);
6832  assert(expr->children[1] != NULL);
6833 
6834  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6835  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
6836 
6837  *maxdegree = child1 + child2;
6838  break;
6839  }
6840 
6841  case SCIP_EXPR_DIV:
6842  {
6843  assert(expr->children[0] != NULL);
6844  assert(expr->children[1] != NULL);
6845 
6846  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6847  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
6848 
6849  /* if not division by constant, then it is not a polynomial */
6850  *maxdegree = (child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : child1;
6851  break;
6852  }
6853 
6854  case SCIP_EXPR_SQUARE:
6855  {
6856  assert(expr->children[0] != NULL);
6857 
6858  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6859 
6860  *maxdegree = 2 * child1;
6861  break;
6862  }
6863 
6864  case SCIP_EXPR_SQRT:
6865  {
6866  assert(expr->children[0] != NULL);
6867 
6868  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6869 
6870  /* if not squareroot of constant, then no polynomial */
6871  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
6872  break;
6873  }
6874 
6875  case SCIP_EXPR_REALPOWER:
6876  {
6877  assert(expr->children[0] != NULL);
6878 
6879  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6880 
6881  /* constant ^ constant has degree 0 */
6882  if( child1 == 0 )
6883  {
6884  *maxdegree = 0;
6885  break;
6886  }
6887 
6888  /* non-polynomial ^ constant is not a polynomial */
6889  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
6890  {
6891  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
6892  break;
6893  }
6894 
6895  /* so it is polynomial ^ constant
6896  * let's see whether the constant is integral */
6897 
6898  if( expr->data.dbl == 0.0 ) /* polynomial ^ 0 == 0 */
6899  *maxdegree = 0;
6900  else if( expr->data.dbl > 0.0 && (int)expr->data.dbl == expr->data.dbl ) /* natural exponent gives polynomial again */ /*lint !e777*/
6901  *maxdegree = child1 * (int)expr->data.dbl;
6902  else /* negative or nonintegral exponent does not give polynomial */
6903  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
6904 
6905  break;
6906  }
6907 
6908  case SCIP_EXPR_INTPOWER:
6909  {
6910  assert(expr->children[0] != NULL);
6911 
6912  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6913 
6914  /* constant ^ integer or something ^ 0 has degree 0 */
6915  if( child1 == 0 || expr->data.intval == 0 )
6916  {
6917  *maxdegree = 0;
6918  break;
6919  }
6920 
6921  /* non-polynomial ^ integer or something ^ negative is not a polynomial */
6922  if( child1 >= SCIP_EXPR_DEGREEINFINITY || expr->data.intval < 0 )
6923  {
6924  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
6925  break;
6926  }
6927 
6928  /* so it is polynomial ^ natural, which gives a polynomial again */
6929  *maxdegree = child1 * expr->data.intval;
6930 
6931  break;
6932  }
6933 
6934  case SCIP_EXPR_SIGNPOWER:
6935  {
6936  assert(expr->children[0] != NULL);
6937 
6938  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6939 
6940  /* if child is not constant, then it is no polynomial */
6941  *maxdegree = child1 != 0 ? SCIP_EXPR_DEGREEINFINITY : 0;
6942  break;
6943  }
6944 
6945  case SCIP_EXPR_EXP:
6946  case SCIP_EXPR_LOG:
6947  case SCIP_EXPR_SIN:
6948  case SCIP_EXPR_COS:
6949  case SCIP_EXPR_TAN:
6950  /* case SCIP_EXPR_ERF: */
6951  /* case SCIP_EXPR_ERFI: */
6952  case SCIP_EXPR_ABS:
6953  case SCIP_EXPR_SIGN:
6954  {
6955  assert(expr->children[0] != NULL);
6956 
6957  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6958 
6959  /* if argument is not a constant, then no polynomial, otherwise it is a constant */
6960  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
6961  break;
6962  }
6963 
6964  case SCIP_EXPR_MIN:
6965  case SCIP_EXPR_MAX:
6966  {
6967  assert(expr->children[0] != NULL);
6968  assert(expr->children[1] != NULL);
6969 
6970  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
6971  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
6972 
6973  /* if any of the operands is not constant, then it is no polynomial */
6974  *maxdegree = (child1 != 0 || child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
6975  break;
6976  }
6977 
6978  case SCIP_EXPR_SUM:
6979  case SCIP_EXPR_LINEAR:
6980  {
6981  int i;
6982 
6983  *maxdegree = 0;
6984  for( i = 0; i < expr->nchildren && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
6985  {
6986  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
6987  if( child1 > *maxdegree )
6988  *maxdegree = child1;
6989  }
6990 
6991  break;
6992  }
6993 
6994  case SCIP_EXPR_PRODUCT:
6995  {
6996  int i;
6997 
6998  *maxdegree = 0;
6999  for( i = 0; i < expr->nchildren; ++i )
7000  {
7001  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7002  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7003  {
7004  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7005  break;
7006  }
7007  *maxdegree += child1;
7008  }
7009 
7010  break;
7011  }
7012 
7013  case SCIP_EXPR_QUADRATIC:
7014  {
7015  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7016  int childidx;
7017  int quadidx;
7018 
7019  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7020 
7021  /* make sure quadratic elements are sorted */
7022  quadraticdataSort(quadraticdata);
7023 
7024  *maxdegree = 0;
7025  quadidx = 0;
7026  for( childidx = 0; childidx < expr->nchildren; ++childidx )
7027  {
7028  /* if no linear or no quadratic coefficient with current child on first position, then nothing to do */
7029  if( (quadraticdata->lincoefs == NULL || quadraticdata->lincoefs[childidx] == 0.0) &&
7030  (quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 > childidx) )
7031  continue;
7032 
7033  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[childidx], &child1) );
7034  if( child1 == SCIP_EXPR_DEGREEINFINITY )
7035  {
7036  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7037  break;
7038  }
7039 
7040  while( quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 == childidx )
7041  {
7042  if( quadraticdata->quadelems[quadidx].idx2 == childidx )
7043  {
7044  /* square term */
7045  if( 2*child1 > *maxdegree )
7046  *maxdegree = 2*child1;
7047  }
7048  else
7049  {
7050  /* bilinear term */
7051  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[quadraticdata->quadelems[quadidx].idx2], &child2) );
7052  if( child2 == SCIP_EXPR_DEGREEINFINITY )
7053  {
7054  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7055  break;
7056  }
7057  if( child1 + child2 > *maxdegree )
7058  *maxdegree = child1 + child2;
7059  }
7060  ++quadidx;
7061  }
7062  if( *maxdegree == SCIP_EXPR_DEGREEINFINITY )
7063  break;
7064  }
7065 
7066  break;
7067  }
7068 
7069  case SCIP_EXPR_POLYNOMIAL:
7070  {
7071  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7072  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7073  int monomialdegree;
7074  int i;
7075  int j;
7076 
7077  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7078 
7079  *maxdegree = 0;
7080  for( i = 0; i < polynomialdata->nmonomials && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7081  {
7082  monomialdata = polynomialdata->monomials[i];
7083  assert(monomialdata != NULL);
7084 
7085  /* compute degree of monomial = sum of degree of factors */
7086  monomialdegree = 0;
7087  for( j = 0; j < monomialdata->nfactors; ++j )
7088  {
7089  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[monomialdata->childidxs[j]], &child1) );
7090 
7091  /* if the exponent of the factor is not a natural number and the child is not constant (degree 0),
7092  * then we report that we are not really a polynomial */
7093  if( child1 != 0 && (monomialdata->exponents[j] < 0.0 || (int)monomialdata->exponents[j] != monomialdata->exponents[j]) )
7094  {
7095  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7096  break;
7097  }
7098 
7099  monomialdegree += child1 * (int)monomialdata->exponents[j];
7100  }
7101 
7102  if( monomialdegree > *maxdegree )
7103  *maxdegree = monomialdegree;
7104  }
7105 
7106  break;
7107  }
7108 
7109  case SCIP_EXPR_LAST:
7110  default:
7111  SCIPerrorMessage("unknown operand: %d\n", expr->op);
7112  return SCIP_ERROR;
7113  }
7114 
7115  return SCIP_OKAY;
7116 }
7117 
7118 /** counts usage of variables in expression */
7120  SCIP_EXPR* expr, /**< expression to update */
7121  int* varsusage /**< array with counters of variable usage */
7122  )
7123 {
7124  int i;
7125 
7126  assert(expr != NULL);
7127  assert(varsusage != NULL);
7128 
7129  if( expr->op == SCIP_EXPR_VARIDX )
7130  {
7131  ++varsusage[expr->data.intval];
7132  }
7133 
7134  for( i = 0; i < expr->nchildren; ++i )
7135  SCIPexprGetVarsUsage(expr->children[i], varsusage);
7136 }
7137 
7138 /** compares whether two expressions are the same
7139  *
7140  * Inconclusive, i.e., may give FALSE even if expressions are equivalent (x*y != y*x).
7141  */
7143  SCIP_EXPR* expr1, /**< first expression */
7144  SCIP_EXPR* expr2, /**< second expression */
7145  SCIP_Real eps /**< threshold under which numbers are assumed to be zero */
7146  )
7147 {
7148  assert(expr1 != NULL);
7149  assert(expr2 != NULL);
7150 
7151  if( expr1 == expr2 )
7152  return TRUE;
7153 
7154  if( expr1->op != expr2->op )
7155  return FALSE;
7156 
7157  switch( expr1->op )
7158  {
7159  case SCIP_EXPR_VARIDX:
7160  case SCIP_EXPR_PARAM:
7161  return expr1->data.intval == expr2->data.intval;
7162 
7163  case SCIP_EXPR_CONST:
7164  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps);
7165 
7166  /* operands with two children */
7167  case SCIP_EXPR_PLUS :
7168  case SCIP_EXPR_MINUS :
7169  case SCIP_EXPR_MUL :
7170  case SCIP_EXPR_DIV :
7171  case SCIP_EXPR_MIN :
7172  case SCIP_EXPR_MAX :
7173  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps) && SCIPexprAreEqual(expr1->children[1], expr2->children[1], eps);
7174 
7175  /* operands with one child */
7176  case SCIP_EXPR_SQUARE:
7177  case SCIP_EXPR_SQRT :
7178  case SCIP_EXPR_EXP :
7179  case SCIP_EXPR_LOG :
7180  case SCIP_EXPR_SIN :
7181  case SCIP_EXPR_COS :
7182  case SCIP_EXPR_TAN :
7183  /* case SCIP_EXPR_ERF : */
7184  /* case SCIP_EXPR_ERFI : */
7185  case SCIP_EXPR_ABS :
7186  case SCIP_EXPR_SIGN :
7187  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7188 
7189  case SCIP_EXPR_REALPOWER:
7190  case SCIP_EXPR_SIGNPOWER:
7191  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps) && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7192 
7193  case SCIP_EXPR_INTPOWER:
7194  return expr1->data.intval == expr2->data.intval && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7195 
7196  /* complex operands */
7197  case SCIP_EXPR_SUM :
7198  case SCIP_EXPR_PRODUCT:
7199  {
7200  int i;
7201 
7202  /* @todo sort children and have sorted flag in data? */
7203 
7204  if( expr1->nchildren != expr2->nchildren )
7205  return FALSE;
7206 
7207  for( i = 0; i < expr1->nchildren; ++i )
7208  {
7209  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7210  return FALSE;
7211  }
7212 
7213  return TRUE;
7214  }
7215 
7216  case SCIP_EXPR_LINEAR :
7217  {
7218  SCIP_Real* data1;
7219  SCIP_Real* data2;
7220  int i;
7221 
7222  /* @todo sort children and have sorted flag in data? */
7223 
7224  if( expr1->nchildren != expr2->nchildren )
7225  return FALSE;
7226 
7227  data1 = (SCIP_Real*)expr1->data.data;
7228  data2 = (SCIP_Real*)expr2->data.data;
7229 
7230  /* check if constant and coefficients are equal */
7231  for( i = 0; i < expr1->nchildren + 1; ++i )
7232  if( !EPSEQ(data1[i], data2[i], eps) )
7233  return FALSE;
7234 
7235  /* check if children are equal */
7236  for( i = 0; i < expr1->nchildren; ++i )
7237  {
7238  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7239  return FALSE;
7240  }
7241 
7242  return TRUE;
7243  }
7244 
7245  case SCIP_EXPR_QUADRATIC:
7246  {
7247  SCIP_EXPRDATA_QUADRATIC* data1;
7248  SCIP_EXPRDATA_QUADRATIC* data2;
7249  int i;
7250 
7251  if( expr1->nchildren != expr2->nchildren )
7252  return FALSE;
7253 
7254  data1 = (SCIP_EXPRDATA_QUADRATIC*)expr1->data.data;
7255  data2 = (SCIP_EXPRDATA_QUADRATIC*)expr2->data.data;
7256 
7257  if( data1->nquadelems != data2->nquadelems )
7258  return FALSE;
7259 
7260  if( !EPSEQ(data1->constant, data2->constant, eps) )
7261  return FALSE;
7262 
7263  /* check if linear part is equal */
7264  if( data1->lincoefs != NULL || data2->lincoefs != NULL )
7265  for( i = 0; i < expr1->nchildren; ++i )
7266  {
7267  if( data1->lincoefs == NULL && !EPSZ(data2->lincoefs[i], eps) )
7268  return FALSE;
7269  if( data2->lincoefs == NULL && !EPSZ(data1->lincoefs[i], eps) )
7270  return FALSE;
7271  if( !EPSEQ(data1->lincoefs[i], data2->lincoefs[i], eps) )
7272  return FALSE;
7273  }
7274 
7275  SCIPexprSortQuadElems(expr1);
7276  SCIPexprSortQuadElems(expr2);
7277 
7278  /* check if quadratic elements are equal */
7279  for( i = 0; i < data1->nquadelems; ++i )
7280  if( data1->quadelems[i].idx1 != data2->quadelems[i].idx1 ||
7281  data1->quadelems[i].idx2 != data2->quadelems[i].idx2 ||
7282  !EPSEQ(data1->quadelems[i].coef, data2->quadelems[i].coef, eps) )
7283  return FALSE;
7284 
7285  /* check if children are equal */
7286  for( i = 0; i < expr1->nchildren; ++i )
7287  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7288  return FALSE;
7289 
7290  return TRUE;
7291  }
7292 
7293  case SCIP_EXPR_POLYNOMIAL:
7294  {
7295  SCIP_EXPRDATA_POLYNOMIAL* data1;
7296  SCIP_EXPRDATA_POLYNOMIAL* data2;
7297  int i;
7298 
7299  if( expr1->nchildren != expr2->nchildren )
7300  return FALSE;
7301 
7302  data1 = (SCIP_EXPRDATA_POLYNOMIAL*)expr1->data.data;
7303  data2 = (SCIP_EXPRDATA_POLYNOMIAL*)expr2->data.data;
7304 
7305  if( data1->nmonomials != data2->nmonomials )
7306  return FALSE;
7307 
7308  if( !EPSEQ(data1->constant, data2->constant, eps) )
7309  return FALSE;
7310 
7311  /* make sure polynomials are sorted */
7312  SCIPexprSortMonomials(expr1);
7313  SCIPexprSortMonomials(expr2);
7314 
7315  /* check if monomials are equal */
7316  for( i = 0; i < data1->nmonomials; ++i )
7317  {
7318  if( !SCIPexprAreMonomialsEqual(data1->monomials[i], data2->monomials[i], eps) )
7319  return FALSE;
7320  }
7321 
7322  /* check if children are equal */
7323  for( i = 0; i < expr1->nchildren; ++i )
7324  {
7325  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7326  return FALSE;
7327  }
7328 
7329  return TRUE;
7330  }
7331 
7332  case SCIP_EXPR_LAST:
7333  default:
7334  SCIPerrorMessage("got expression with invalid operand %d\n", expr1->op);
7335  }
7336 
7337  SCIPerrorMessage("this should never happen\n");
7338  SCIPABORT();
7339  return FALSE; /*lint !e527*/
7340 }
7341 
7342 /** aims at simplifying an expression and splitting of a linear expression
7343  *
7344  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
7345  */
7347  BMS_BLKMEM* blkmem, /**< block memory data structure */
7348  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7349  SCIP_EXPR* expr, /**< expression */
7350  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
7351  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
7352  int nvars, /**< number of variables in expression */
7353  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
7354  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
7355  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
7356  )
7357 {
7358  assert(blkmem != NULL);
7359  assert(expr != NULL);
7360  assert(eps >= 0.0);
7361 
7362  SCIPdebugMessage("simplify expression: ");
7363  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7364  SCIPdebugPrintf("\n");
7365 
7367 
7368  SCIPdebugMessage("converted to polynomials: ");
7369  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7370  SCIPdebugPrintf("\n");
7371 
7372  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr, eps, maxexpansionexponent) );
7373 
7374  SCIPdebugMessage("polynomials flattened: ");
7375  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7376  SCIPdebugPrintf("\n");
7377 
7378  if( nlinvars != NULL )
7379  {
7380  /* separate linear part from root polynomial */
7381  SCIP_CALL( exprsimplifySeparateLinearFromPolynomial(blkmem, expr, eps, nvars, nlinvars, linidxs, lincoefs) );
7382 
7383  SCIPdebugMessage("separated linear part: ");
7384  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7385  SCIPdebugPrintf("\n");
7386  }
7387 
7389 
7390  SCIPdebugMessage("converted back from polynomials: ");
7391  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7392  SCIPdebugPrintf("\n");
7393 
7394  return SCIP_OKAY;
7395 }
7396 
7397 /** evaluates an expression w.r.t. a point */
7399  SCIP_EXPR* expr, /**< expression */
7400  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression is constant */
7401  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7402  SCIP_Real* val /**< buffer to store value */
7403  )
7404 {
7405  int i;
7407  SCIP_Real* buf;
7408 
7409  /* if many children, get large enough memory to store argument values */
7411  {
7412  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7413  }
7414  else
7415  {
7416  buf = staticbuf;
7417  }
7418 
7419  /* evaluate children */
7420  for( i = 0; i < expr->nchildren; ++i )
7421  {
7422  SCIP_CALL( SCIPexprEval(expr->children[i], varvals, param, &buf[i]) ); /*lint !e644*/
7423  }
7424 
7425  /* evaluate this expression */
7426  assert( exprOpTable[expr->op].eval != NULL );
7427  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, buf, varvals, param, val) );
7428 
7429  /* free memory, if allocated before */
7430  if( staticbuf != buf )
7431  {
7432  BMSfreeMemoryArray(&buf);
7433  }
7434 
7435  return SCIP_OKAY;
7436 }
7437 
7438 /** evaluates an expression w.r.t. an interval */
7440  SCIP_EXPR* expr, /**< expression */
7441  SCIP_Real infinity, /**< value to use for infinity */
7442  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7443  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7444  SCIP_INTERVAL* val /**< buffer to store value */
7445  )
7446 {
7447  int i;
7449  SCIP_INTERVAL* buf;
7450 
7451  /* if many children, get large enough memory to store argument values */
7453  {
7454  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7455  }
7456  else
7457  {
7458  buf = staticbuf;
7459  }
7460 
7461  /* evaluate children */
7462  for( i = 0; i < expr->nchildren; ++i )
7463  {
7464  SCIP_CALL( SCIPexprEvalInt(expr->children[i], infinity, varvals, param, &buf[i]) ); /*lint !e644*/
7465  }
7466 
7467  /* evaluate this expression */
7468  assert( exprOpTable[expr->op].inteval != NULL );
7469  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, buf, varvals, param, val) );
7470 
7471  /* free memory, if allocated before */
7472  if( staticbuf != buf )
7473  {
7474  BMSfreeMemoryArray(&buf);
7475  }
7476 
7477  return SCIP_OKAY;
7478 }
7479 
7480 /** tries to determine the curvature type of an expression w.r.t. given variable domains */
7482  SCIP_EXPR* expr, /**< expression to check */
7483  SCIP_Real infinity, /**< value to use for infinity */
7484  SCIP_INTERVAL* varbounds, /**< domains of variables */
7485  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7486  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
7487  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
7488  )
7489 {
7491  SCIP_INTERVAL* childbounds;
7493  SCIP_EXPRCURV* childcurv;
7494  int i;
7495 
7496  assert(expr != NULL);
7497  assert(curv != NULL);
7498  assert(bounds != NULL);
7499 
7500  /* if many children, get large enough memory to store argument values */
7502  {
7503  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, expr->nchildren) );
7504  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, expr->nchildren) );
7505  }
7506  else
7507  {
7508  childbounds = childboundsbuf;
7509  childcurv = childcurvbuf;
7510  }
7511 
7512  /* check curvature and compute bounds of children
7513  * constant children can be considered as always linear */
7514  for( i = 0; i < expr->nchildren; ++i )
7515  {
7516  SCIP_CALL( SCIPexprCheckCurvature(expr->children[i], infinity, varbounds, param, &childcurv[i], &childbounds[i]) ); /*lint !e644*/
7517  if( childbounds[i].inf == childbounds[i].sup ) /*lint !e777*/
7518  childcurv[i] = SCIP_EXPRCURV_LINEAR;
7519  }
7520 
7521  /* get curvature and bounds of expr */
7522  assert(exprOpTable[expr->op].curv != NULL);
7523  assert(exprOpTable[expr->op].inteval != NULL);
7524 
7525  SCIP_CALL( exprOpTable[expr->op].curv(infinity, expr->data, expr->nchildren, childbounds, childcurv, curv) );
7526  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, childbounds, varbounds, param, bounds) );
7527 
7528  /* free memory, if allocated before */
7529  if( childboundsbuf != childbounds )
7530  {
7531  BMSfreeMemoryArray(&childcurv);
7532  BMSfreeMemoryArray(&childbounds);
7533  }
7534 
7535  return SCIP_OKAY;
7536 }
7537 
7538 /** substitutes variables (SCIP_EXPR_VARIDX) by expressions
7539  *
7540  * Note that only the children of the given expr are checked!
7541  * A variable with index i is replaced by a copy of substexprs[i], if the latter is not NULL.
7542  * If substexprs[i] == NULL, then the variable expression i is not touched.
7543  */
7545  BMS_BLKMEM* blkmem, /**< block memory data structure */
7546  SCIP_EXPR* expr, /**< expression, which of the children may be replaced */
7547  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
7548  )
7549 {
7550  int i;
7551 
7552  assert(blkmem != NULL);
7553  assert(expr != NULL);
7554  assert(substexprs != NULL);
7555 
7556  for( i = 0; i < expr->nchildren; ++i )
7557  {
7558  if( expr->children[i]->op == SCIP_EXPR_VARIDX )
7559  {
7560  int varidx;
7561  varidx = expr->children[i]->data.intval;
7562 
7563  assert(varidx >= 0);
7564  if( substexprs[varidx] != NULL )
7565  {
7566  /* replace child i by copy of substexprs[expr->children[i]->opdata.intval] */
7567  SCIPexprFreeDeep(blkmem, &expr->children[i]);
7568  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[i], substexprs[varidx]) );
7569  }
7570  }
7571  else
7572  {
7573  /* call recursively */
7574  SCIP_CALL( SCIPexprSubstituteVars(blkmem, expr->children[i], substexprs) );
7575  }
7576  }
7577 
7578  return SCIP_OKAY;
7579 }
7580 
7581 /** updates variable indices in expression tree */
7583  SCIP_EXPR* expr, /**< expression to update */
7584  int* newindices /**< new indices of variables */
7585  )
7586 {
7587  int i;
7588 
7589  assert(expr != NULL);
7590  assert(newindices != NULL);
7591 
7592  if( expr->op == SCIP_EXPR_VARIDX )
7593  {
7594  expr->data.intval = newindices[expr->data.intval];
7595  assert(expr->data.intval >= 0);
7596  }
7597 
7598  for( i = 0; i < expr->nchildren; ++i )
7599  SCIPexprReindexVars(expr->children[i], newindices);
7600 }
7601 
7602 /** updates parameter indices in expression tree */
7604  SCIP_EXPR* expr, /**< expression to update */
7605  int* newindices /**< new indices of variables */
7606  )
7607 {
7608  int i;
7609 
7610  assert(expr != NULL);
7611  assert(newindices != NULL);
7612 
7613  if( expr->op == SCIP_EXPR_PARAM )
7614  {
7615  expr->data.intval = newindices[expr->data.intval];
7616  assert(expr->data.intval >= 0);
7617  }
7618 
7619  for( i = 0; i < expr->nchildren; ++i )
7620  SCIPexprReindexParams(expr->children[i], newindices);
7621 }
7622 
7623 /** prints an expression */
7625  SCIP_EXPR* expr, /**< expression */
7626  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7627  FILE* file, /**< file for printing, or NULL for stdout */
7628  const char** varnames, /**< names of variables, or NULL for default names */
7629  const char** paramnames, /**< names of parameters, or NULL for default names */
7630  SCIP_Real* paramvals /**< values of parameters, or NULL for not printing */
7631  )
7632 {
7633  assert( expr != NULL );
7634 
7635  switch( expr->op )
7636  {
7637  /* @Note: 'expr->data.intval' is either between 0 and number of variables-1, if it uses the varnames array, or
7638  * between 0 and number of params in the expression tree, if it uses the paramnames array
7639  * because, here, we cannot get the values above we cannot assert them
7640  */
7641  case SCIP_EXPR_VARIDX:
7642  if( varnames != NULL )
7643  {
7644  assert(varnames[expr->data.intval] != NULL);
7645  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", varnames[expr->data.intval]);
7646  }
7647  else
7648  {
7649  SCIPmessageFPrintInfo(messagehdlr, file, "var%d", expr->data.intval);
7650  }
7651  break;
7652 
7653  case SCIP_EXPR_PARAM:
7654  if( paramnames != NULL )
7655  {
7656  assert(paramnames[expr->data.intval] != NULL);
7657  SCIPmessageFPrintInfo(messagehdlr, file, "%s", paramnames[expr->data.intval]);
7658  }
7659  else
7660  {
7661  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", expr->data.intval );
7662  }
7663  if( paramvals != NULL )
7664  {
7665  SCIPmessageFPrintInfo(messagehdlr, file, "[%g]", paramvals[expr->data.intval] );
7666  }
7667  break;
7668 
7669  case SCIP_EXPR_CONST:
7670  if (expr->data.dbl < 0.0 )
7671  SCIPmessageFPrintInfo(messagehdlr, file, "(%lf)", expr->data.dbl );
7672  else
7673  SCIPmessageFPrintInfo(messagehdlr, file, "%lf", expr->data.dbl );
7674  break;
7675 
7676  case SCIP_EXPR_PLUS:
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_MINUS:
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_MUL:
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_DIV:
7701  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7702  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
7703  SCIPmessageFPrintInfo(messagehdlr, file, " / ");
7704  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
7705  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7706  break;
7707 
7708  case SCIP_EXPR_REALPOWER:
7709  case SCIP_EXPR_SIGNPOWER:
7710  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
7711  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
7712  SCIPmessageFPrintInfo(messagehdlr, file, ", %g)", expr->data.dbl);
7713  break;
7714 
7715  case SCIP_EXPR_INTPOWER:
7716  SCIPmessageFPrintInfo(messagehdlr, file, "power(");
7717  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
7718  SCIPmessageFPrintInfo(messagehdlr, file, ", %d)", expr->data.intval);
7719  break;
7720 
7721  case SCIP_EXPR_SQUARE:
7722  case SCIP_EXPR_SQRT:
7723  case SCIP_EXPR_EXP:
7724  case SCIP_EXPR_LOG:
7725  case SCIP_EXPR_SIN:
7726  case SCIP_EXPR_COS:
7727  case SCIP_EXPR_TAN:
7728  /* case SCIP_EXPR_ERF: */
7729  /* case SCIP_EXPR_ERFI: */
7730  case SCIP_EXPR_MIN:
7731  case SCIP_EXPR_MAX:
7732  case SCIP_EXPR_ABS:
7733  case SCIP_EXPR_SIGN:
7734  {
7735  int i;
7736 
7737  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
7738 
7739  for( i = 0; i < expr->nchildren; ++i )
7740  {
7741  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
7742  if( i + 1 < expr->nchildren )
7743  {
7744  SCIPmessageFPrintInfo(messagehdlr, file, ", ");
7745  }
7746  }
7747 
7748  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7749  break;
7750  }
7751 
7752  case SCIP_EXPR_SUM:
7753  case SCIP_EXPR_PRODUCT:
7754  {
7755  switch( expr->nchildren )
7756  {
7757  case 0:
7758  SCIPmessageFPrintInfo(messagehdlr, file, expr->op == SCIP_EXPR_SUM ? "0" : "1");
7759  break;
7760  case 1:
7761  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
7762  break;
7763  default:
7764  {
7765  int i;
7766  const char* opstr = expr->op == SCIP_EXPR_SUM ? " + " : " * ";
7767 
7768  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7769  for( i = 0; i < expr->nchildren; ++i )
7770  {
7771  if( i > 0 )
7772  {
7773  SCIPmessageFPrintInfo(messagehdlr, file, opstr);
7774  }
7775  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
7776  }
7777  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7778  }
7779  }
7780  break;
7781  }
7782 
7783  case SCIP_EXPR_LINEAR:
7784  {
7785  SCIP_Real constant;
7786  int i;
7787 
7788  constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
7789 
7790  if( expr->nchildren == 0 )
7791  {
7792  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
7793  break;
7794  }
7795 
7796  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7797 
7798  if( constant != 0.0 )
7799  {
7800  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
7801  }
7802 
7803  for( i = 0; i < expr->nchildren; ++i )
7804  {
7805  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", ((SCIP_Real*)expr->data.data)[i]);
7806  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
7807  }
7808 
7809  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7810  break;
7811  }
7812 
7813  case SCIP_EXPR_QUADRATIC:
7814  {
7815  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7816  int i;
7817 
7818  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7819  assert(quadraticdata != NULL);
7820 
7821  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7822 
7823  if( quadraticdata->constant != 0.0 )
7824  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->constant);
7825 
7826  if( quadraticdata->lincoefs != NULL )
7827  for( i = 0; i < expr->nchildren; ++i )
7828  {
7829  if( quadraticdata->lincoefs[i] == 0.0 )
7830  continue;
7831  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->lincoefs[i]);
7832  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
7833  }
7834 
7835  for( i = 0; i < quadraticdata->nquadelems; ++i )
7836  {
7837  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->quadelems[i].coef);
7838  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
7839  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
7840  {
7841  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
7842  }
7843  else
7844  {
7845  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
7846  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
7847  }
7848  }
7849 
7850  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7851  break;
7852  }
7853 
7854  case SCIP_EXPR_POLYNOMIAL:
7855  {
7856  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7857  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7858  int i;
7859  int j;
7860 
7861  SCIPmessageFPrintInfo(messagehdlr, file, "(");
7862 
7863  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7864  assert(polynomialdata != NULL);
7865 
7866  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
7867  {
7868  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", polynomialdata->constant);
7869  }
7870 
7871  for( i = 0; i < polynomialdata->nmonomials; ++i )
7872  {
7873  monomialdata = polynomialdata->monomials[i];
7874  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g", monomialdata->coef);
7875 
7876  for( j = 0; j < monomialdata->nfactors; ++j )
7877  {
7878  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
7879 
7880  SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
7881  if( monomialdata->exponents[j] < 0.0 )
7882  {
7883  SCIPmessageFPrintInfo(messagehdlr, file, "^(%.20g)", monomialdata->exponents[j]);
7884  }
7885  else if( monomialdata->exponents[j] != 1.0 )
7886  {
7887  SCIPmessageFPrintInfo(messagehdlr, file, "^%.20g", monomialdata->exponents[j]);
7888  }
7889  }
7890  }
7891 
7892  SCIPmessageFPrintInfo(messagehdlr, file, ")");
7893  break;
7894  }
7895 
7896  case SCIP_EXPR_LAST:
7897  SCIPerrorMessage("invalid expression\n");
7898  SCIPABORT();
7899  }
7900 }
7901 
7902 /** parses an expression from a string */
7904  BMS_BLKMEM* blkmem, /**< block memory data structure */
7905  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7906  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
7907  const char* str, /**< pointer to the string to be parsed */
7908  const char* lastchar, /**< pointer to the last char of str that should be parsed */
7909  int* nvars, /**< buffer to store number of variables */
7910  int* varnames /**< buffer to store variable names, prefixed by index (as int) */
7911  )
7912 {
7913  SCIP_HASHTABLE* vartable;
7914  SCIP_RETCODE retcode;
7915 
7916  assert(blkmem != NULL);
7917  assert(expr != NULL);
7918  assert(str != NULL);
7919  assert(lastchar != NULL);
7920  assert(nvars != NULL);
7921  assert(varnames != NULL);
7922 
7923  *nvars = 0;
7924 
7925  /* create a hash table for variable names and corresponding expression index
7926  * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
7927  */
7928  SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) );
7929 
7930  retcode = exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames, vartable, 0);
7931 
7932  SCIPhashtableFree(&vartable);
7933 
7934  return retcode;
7935 }
7936 
7937 
7938 /**@} */
7939 
7940 /**@name Expression tree methods */
7941 /**@{ */
7942 
7943 /* In debug mode, the following methods are implemented as function calls to ensure
7944  * type validity.
7945  * In optimized mode, the methods are implemented as defines to improve performance.
7946  * However, we want to have them in the library anyways, so we have to undef the defines.
7947  */
7948 
7949 #undef SCIPexprtreeGetRoot
7950 #undef SCIPexprtreeGetNVars
7951 #undef SCIPexprtreeGetNParams
7952 #undef SCIPexprtreeGetParamVals
7953 #undef SCIPexprtreeSetParamVal
7954 #undef SCIPexprtreeGetInterpreterData
7955 #undef SCIPexprtreeSetInterpreterData
7956 #undef SCIPexprtreeFreeInterpreterData
7957 #undef SCIPexprtreeHasParam
7958 #undef SCIPexprtreeGetMaxDegree
7959 #undef SCIPexprtreeEval
7960 #undef SCIPexprtreeEvalInt
7961 #undef SCIPexprtreePrint
7962 
7963 /** returns root expression of an expression tree */
7965  SCIP_EXPRTREE* tree /**< expression tree */
7966  )
7967 {
7968  assert(tree != NULL);
7969 
7970  return tree->root;
7971 }
7972 
7973 /** returns number of variables in expression tree */
7975  SCIP_EXPRTREE* tree /**< expression tree */
7976  )
7977 {
7978  assert(tree != NULL);
7979 
7980  return tree->nvars;
7981 }
7982 
7983 /** returns number of parameters in expression tree */
7985  SCIP_EXPRTREE* tree /**< expression tree */
7986  )
7987 {
7988  assert(tree != NULL);
7989 
7990  return tree->nparams;
7991 }
7992 
7993 /** returns values of parameters or NULL if none */
7995  SCIP_EXPRTREE* tree /**< expression tree */
7996  )
7997 {
7998  assert(tree != NULL);
7999 
8000  return tree->params;
8001 }
8002 
8003 /** sets value of a single parameter in expression tree */
8005  SCIP_EXPRTREE* tree, /**< expression tree */
8006  int paramidx, /**< index of parameter */
8007  SCIP_Real paramval /**< new value of parameter */
8008  )
8009 {
8010  assert(tree != NULL);
8011  assert(paramidx >= 0);
8012  assert(paramidx < tree->nparams);
8013  assert(tree->params != NULL);
8014 
8015  tree->params[paramidx] = paramval;
8016 }
8017 
8018 /** gets data of expression tree interpreter, or NULL if not set */
8020  SCIP_EXPRTREE* tree /**< expression tree */
8021  )
8022 {
8023  assert(tree != NULL);
8024 
8025  return tree->interpreterdata;
8026 }
8027 
8028 /** sets data of expression tree interpreter */
8030  SCIP_EXPRTREE* tree, /**< expression tree */
8031  SCIP_EXPRINTDATA* interpreterdata /**< expression interpreter data */
8032  )
8033 {
8034  assert(tree != NULL);
8035  assert(interpreterdata != NULL);
8036  assert(tree->interpreterdata == NULL);
8037 
8038  tree->interpreterdata = interpreterdata;
8039 }
8040 
8041 /** frees data of expression tree interpreter, if any */
8043  SCIP_EXPRTREE* tree /**< expression tree */
8044  )
8045 {
8046  if( tree->interpreterdata != NULL )
8047  {
8049  assert(tree->interpreterdata == NULL);
8050  }
8051 
8052  return SCIP_OKAY;
8053 }
8054 
8055 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
8057  SCIP_EXPRTREE* tree /**< expression tree */
8058  )
8059 {
8060  assert(tree != NULL);
8061 
8062  return SCIPexprHasParam(tree->root);
8063 }
8064 
8065 /** Gives maximal degree of expression in expression tree.
8066  *
8067  * If constant expression, gives 0,
8068  * if linear expression, gives 1,
8069  * if polynomial expression, gives its maximal degree,
8070  * otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8071  */
8073  SCIP_EXPRTREE* tree, /**< expression tree */
8074  int* maxdegree /**< buffer to store maximal degree */
8075  )
8076 {
8077  assert(tree != NULL);
8078 
8079  SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8080 
8081  return SCIP_OKAY;
8082 }
8083 
8084 /** evaluates an expression tree w.r.t. a point */
8086  SCIP_EXPRTREE* tree, /**< expression tree */
8087  SCIP_Real* varvals, /**< values for variables */
8088  SCIP_Real* val /**< buffer to store expression tree value */
8089  )
8090 {
8091  assert(tree != NULL);
8092  assert(varvals != NULL || tree->nvars == 0);
8093  assert(val != NULL);
8094 
8095  SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8096 
8097  return SCIP_OKAY;
8098 }
8099 
8100 /** evaluates an expression tree w.r.t. an interval */
8102  SCIP_EXPRTREE* tree, /**< expression tree */
8103  SCIP_Real infinity, /**< value for infinity */
8104  SCIP_INTERVAL* varvals, /**< intervals for variables */
8105  SCIP_INTERVAL* val /**< buffer to store expression tree value */
8106  )
8107 {
8108  assert(tree != NULL);
8109  assert(varvals != NULL || tree->nvars == 0);
8110  assert(val != NULL);
8111 
8112  SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8113 
8114  return SCIP_OKAY;
8115 }
8116 
8117 /** prints an expression tree */
8119  SCIP_EXPRTREE* tree, /**< expression tree */
8120  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8121  FILE* file, /**< file for printing, or NULL for stdout */
8122  const char** varnames, /**< names of variables, or NULL for default names */
8123  const char** paramnames /**< names of parameters, or NULL for default names */
8124  )
8125 {
8126  assert(tree != NULL);
8127 
8128  SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8129 }
8130 
8131 
8132 /** creates an expression tree */
8134  BMS_BLKMEM* blkmem, /**< block memory data structure */
8135  SCIP_EXPRTREE** tree, /**< buffer to store address of created expression tree */
8136  SCIP_EXPR* root, /**< pointer to root expression, not copied deep !, can be NULL */
8137  int nvars, /**< number of variables in variable mapping */
8138  int nparams, /**< number of parameters in expression */
8139  SCIP_Real* params /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8140  )
8141 {
8142  assert(blkmem != NULL);
8143  assert(tree != NULL);
8144 
8145  SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8146 
8147  (*tree)->blkmem = blkmem;
8148  (*tree)->root = root;
8149  (*tree)->nvars = nvars;
8150  (*tree)->vars = NULL;
8151  (*tree)->nparams = nparams;
8152  (*tree)->interpreterdata = NULL;
8153 
8154  if( params != NULL )
8155  {
8156  assert(nparams > 0);
8157  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8158  }
8159  else if( nparams > 0 )
8160  {
8161  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8162  BMSclearMemoryArray((*tree)->params, nparams);
8163  }
8164  else
8165  {
8166  assert(nparams == 0);
8167  (*tree)->params = NULL;
8168  }
8169 
8170  return SCIP_OKAY;
8171 }
8172 
8173 /** copies an expression tree */
8175  BMS_BLKMEM* blkmem, /**< block memory that should be used in new expression tree */
8176  SCIP_EXPRTREE** targettree, /**< buffer to store address of copied expression tree */
8177  SCIP_EXPRTREE* sourcetree /**< expression tree to copy */
8178  )
8179 {
8180  assert(blkmem != NULL);
8181  assert(targettree != NULL);
8182  assert(sourcetree != NULL);
8183 
8184  /* copy expression tree "header" */
8185  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8186 
8187  /* we may have a new block memory; and we do not want to keep the others interpreter data */
8188  (*targettree)->blkmem = blkmem;
8189  (*targettree)->interpreterdata = NULL;
8190 
8191  /* copy variables, if any */
8192  if( sourcetree->vars != NULL )
8193  {
8194  assert(sourcetree->nvars > 0);
8195 
8196  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8197  }
8198 
8199  /* copy parameters, if any */
8200  if( sourcetree->params != NULL )
8201  {
8202  assert(sourcetree->nparams > 0);
8203 
8204  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8205  }
8206 
8207  /* copy expression */
8208  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8209 
8210  return SCIP_OKAY;
8211 }
8212 
8213 /** frees an expression tree */
8215  SCIP_EXPRTREE** tree /**< pointer to expression tree that is freed */
8216  )
8217 {
8218  assert( tree != NULL);
8219  assert(*tree != NULL);
8220 
8222 
8223  if( (*tree)->root != NULL )
8224  {
8225  SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8226  assert((*tree)->root == NULL);
8227  }
8228 
8229  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars, (*tree)->nvars );
8230  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8231 
8232  BMSfreeBlockMemory((*tree)->blkmem, tree);
8233 
8234  return SCIP_OKAY;
8235 }
8236 
8237 /** sets number and values of all parameters in expression tree */
8239  SCIP_EXPRTREE* tree, /**< expression tree */
8240  int nparams, /**< number of parameters */
8241  SCIP_Real* paramvals /**< values of parameters, can be NULL if nparams == 0 */
8242  )
8243 {
8244  assert(tree != NULL);
8245  assert(paramvals != NULL || nparams == 0);
8246 
8247  if( nparams == 0 )
8248  {
8249  BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8250  }
8251  else if( tree->params != NULL )
8252  {
8253  SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8254  BMScopyMemoryArray(tree->params, paramvals, nparams);
8255  }
8256  else
8257  {
8258  SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8259  }
8260 
8261  tree->nparams = nparams;
8262  assert(tree->params != NULL || tree->nparams == 0);
8263 
8264  return SCIP_OKAY;
8265 }
8266 
8267 
8268 /** gives the number of usages for each variable in the expression tree */
8270  SCIP_EXPRTREE* tree, /**< expression tree */
8271  int* varsusage /**< array where to store for each variable how often it is used in the tree */
8272  )
8273 {
8274  assert(tree != NULL);
8275  assert(varsusage != NULL);
8276 
8277  if( tree->nvars == 0 )
8278  return;
8279 
8280  BMSclearMemoryArray(varsusage, tree->nvars);
8281  SCIPexprGetVarsUsage(tree->root, varsusage);
8282 }
8283 
8284 /** aims at simplifying an expression and splitting of a linear expression
8285  *
8286  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
8287  */
8289  SCIP_EXPRTREE* tree, /**< expression tree */
8290  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8291  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
8292  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8293  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8294  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8295  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
8296  )
8297 {
8298 #ifndef NDEBUG
8299  SCIP_Real* testx;
8300  SCIP_Real testval_before;
8301  SCIP_Real testval_after;
8302  int i;
8303  unsigned int seed;
8304 #endif
8305 
8306  assert(tree != NULL);
8307 
8308 #ifndef NDEBUG
8309  seed = 42;
8310  SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) ); /*lint !e666*/
8311  for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8312  testx[i] = SCIPgetRandomReal(-100.0, 100.0, &seed); /*lint !e644*/
8313  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8314 #endif
8315 
8316  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8317  SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8318 
8319 #ifndef NDEBUG
8320  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8321  if( nlinvars != NULL && testval_before == testval_before ) /*lint !e777*/
8322  for( i = 0; i < *nlinvars; ++i )
8323  testval_after += lincoefs[i] * testx[linidxs[i]];
8324  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
8325  BMSfreeMemoryArray(&testx);
8326 #endif
8327 
8328  /* removing something from the the tree may invalidate the interpreter data */
8329  if( nlinvars != NULL && *nlinvars > 0 )
8331 
8332  return SCIP_OKAY;
8333 }
8334 
8335 /** adds an expression to the root expression of the tree
8336  *
8337  * 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.
8338  */
8340  SCIP_EXPRTREE* tree, /**< expression tree */
8341  SCIP_EXPR* expr, /**< expression to add to tree */
8342  SCIP_Bool copyexpr /**< whether expression should be copied */
8343  )
8344 {
8345  assert(tree != NULL);
8346  assert(tree->root != NULL);
8347 
8348  /* adding something to the tree may invalidate the interpreter data */
8350 
8351  if( copyexpr )
8352  {
8353  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &expr, expr) );
8354  }
8355 
8356  SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
8357 
8358  return SCIP_OKAY;
8359 }
8360 
8361 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
8363  SCIP_EXPRTREE* tree, /**< expression tree */
8364  SCIP_Real infinity, /**< value for infinity */
8365  SCIP_INTERVAL* varbounds, /**< domains of variables */
8366  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8367  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression, or NULL if not needed */
8368  )
8369 {
8370  SCIP_INTERVAL exprbounds;
8371 
8372  assert(tree != NULL);
8373  assert(tree->root != NULL);
8374 
8375  SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
8376 
8377  if( bounds != NULL )
8378  *bounds = exprbounds;
8379 
8380  return SCIP_OKAY;
8381 }
8382 
8383 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
8384  *
8385  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL.
8386  * If substexprs[i] == NULL, then the variable expression i is not touched.
8387  */
8389  SCIP_EXPRTREE* tree, /**< expression tree */
8390  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8391  )
8392 {
8393  assert(tree != NULL);
8394  assert(tree->root != NULL);
8395 
8396  if( tree->root->op == SCIP_EXPR_VARIDX )
8397  {
8398  int varidx;
8399 
8400  varidx = tree->root->data.intval;
8401  assert(varidx >= 0);
8402  if( substexprs[varidx] != NULL )
8403  {
8404  /* substitute root expression */
8405  SCIPexprFreeDeep(tree->blkmem, &tree->root);
8406  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
8407  }
8408  }
8409  else
8410  {
8411  /* check children (and grandchildren and so on...) of root expression */
8412  SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
8413  }
8414 
8415  /* substitution of variables should invalidate interpreter data */
8417 
8418  return SCIP_OKAY;
8419 }
8420 
8421 /**@} */
8422 
8423 /**@name Quadratic element methods */
8424 /**@{ */
8425 
8426 /** comparing two quadratic elements
8427  *
8428  * 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
8429  */
8430 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
8431 
8432 /** swaps two quadratic elements */
8433 #define QUADELEMS_SWAP(x,y) \
8434  { \
8435  SCIP_QUADELEM temp = x; \
8436  x = y; \
8437  y = temp; \
8438  }
8439 
8440 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
8441 static
8443  SCIP_QUADELEM* elems, /**< array to be sorted */
8444  int start, /**< starting index */
8445  int end /**< ending index */
8446  )
8447 {
8448  assert(start <= end);
8449 
8450  /* use quick sort for long lists */
8451  while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
8452  {
8453  SCIP_QUADELEM pivotkey;
8454  int lo;
8455  int hi;
8456  int mid;
8457 
8458  /* select pivot element */
8459  mid = (start+end)/2;
8460  pivotkey = elems[mid];
8461 
8462  /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
8463  lo = start;
8464  hi = end;
8465  for( ;; )
8466  {
8467  while( lo < end && QUADELEMS_ISBETTER(elems[lo], pivotkey) )
8468  lo++;
8469  while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
8470  hi--;
8471 
8472  if( lo >= hi )
8473  break;
8474 
8475  QUADELEMS_SWAP(elems[lo], elems[hi]);
8476 
8477  lo++;
8478  hi--;
8479  }
8480  assert(hi == lo-1 || hi == start);
8481 
8482  /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
8483  while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
8484  lo++;
8485 
8486  /* make sure that we have at least one element in the smaller partition */
8487  if( lo == start )
8488  {
8489  /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
8490  assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
8491  assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
8492  QUADELEMS_SWAP(elems[lo], elems[mid]);
8493  lo++;
8494  }
8495 
8496  /* sort the smaller partition by a recursive call, sort the larger part without recursion */
8497  if( hi - start <= end - lo )
8498  {
8499  /* sort [start,hi] with a recursive call */
8500  if( start < hi )
8501  quadelemsQuickSort(elems, start, hi);
8502 
8503  /* now focus on the larger part [lo,end] */
8504  start = lo;
8505  }
8506  else
8507  {
8508  /* sort [lo,end] with a recursive call */
8509  if( lo < end )
8510  quadelemsQuickSort(elems, lo, end);
8511 
8512  /* now focus on the larger part [start,hi] */
8513  end = hi;
8514  }
8515  }
8516 
8517  /* use shell sort on the remaining small list */
8518  if( end - start >= 1 )
8519  {
8520  static const int incs[3] = {1, 5, 19}; /* sequence of increments */
8521  int k;
8522 
8523  for( k = 2; k >= 0; --k )
8524  {
8525  int h;
8526  int i;
8527 
8528  for( h = incs[k], i = h + start; i <= end; ++i )
8529  {
8530  int j;
8531  SCIP_QUADELEM tempkey = elems[i];
8532 
8533  j = i;
8534  while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
8535  {
8536  elems[j] = elems[j-h];
8537  j -= h;
8538  }
8539 
8540  elems[j] = tempkey;
8541  }
8542  }
8543  }
8544 }
8545 
8546 /** sorts an array of quadratic elements
8547  *
8548  * The elements are sorted such that the first index is increasing and
8549  * such that among elements with the same first index, the second index is increasing.
8550  * For elements with same first and second index, the order is not defined.
8551  */
8553  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
8554  int nquadelems /**< number of quadratic elements */
8555  )
8556 {
8557  if( nquadelems == 0 )
8558  return;
8559 
8560 #ifndef NDEBUG
8561  {
8562  int i;
8563  for( i = 0; i < nquadelems; ++i )
8564  assert(quadelems[i].idx1 <= quadelems[i].idx2);
8565  }
8566 #endif
8567 
8568  quadelemsQuickSort(quadelems, 0, nquadelems-1);
8569 }
8570 
8571 /** Finds an index pair in a sorted array of quadratic elements.
8572  *
8573  * If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
8574  * 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.
8575  * Assumes that idx1 <= idx2.
8576  */
8578  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
8579  int idx1, /**< index of first variable in element to search for */
8580  int idx2, /**< index of second variable in element to search for */
8581  int nquadelems, /**< number of quadratic elements in array */
8582  int* pos /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
8583  )
8584 {
8585  int left;
8586  int right;
8587 
8588  assert(quadelems != NULL || nquadelems == 0);
8589  assert(idx1 <= idx2);
8590 
8591  if( nquadelems == 0 )
8592  {
8593  if( pos != NULL )
8594  *pos = 0;
8595  return FALSE;
8596  }
8597 
8598  left = 0;
8599  right = nquadelems - 1;
8600  while( left <= right )
8601  {
8602  int middle;
8603 
8604  middle = (left+right)/2;
8605  assert(0 <= middle && middle < nquadelems);
8606 
8607  if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) ) /*lint !e613*/
8608  right = middle - 1;
8609  else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) ) /*lint !e613*/
8610  left = middle + 1;
8611  else
8612  {
8613  if( pos != NULL )
8614  *pos = middle;
8615  return TRUE;
8616  }
8617  }
8618  assert(left == right+1);
8619 
8620  if( pos != NULL )
8621  *pos = left;
8622  return FALSE;
8623 }
8624 
8625 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
8626  *
8627  * Assumes that elements have been sorted before.
8628  */
8630  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
8631  int nquadelems, /**< number of quadratic elements */
8632  int* nquadelemsnew /**< pointer to store new (reduced) number of quadratic elements */
8633  )
8634 {
8635  int i;
8636  int next;
8637 
8638  assert(quadelems != NULL);
8639  assert(nquadelemsnew != NULL);
8640  assert(nquadelems >= 0);
8641 
8642  i = 0;
8643  next = 0;
8644  while( next < nquadelems )
8645  {
8646  /* assert that array is sorted */
8647  assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
8648  (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
8649 
8650  /* skip elements with coefficient 0.0 */
8651  if( quadelems[next].coef == 0.0 )
8652  {
8653  ++next;
8654  continue;
8655  }
8656 
8657  /* if next element has same index as previous one, add it to the previous one */
8658  if( i >= 1 &&
8659  quadelems[i-1].idx1 == quadelems[next].idx1 &&
8660  quadelems[i-1].idx2 == quadelems[next].idx2 )
8661  {
8662  quadelems[i-1].coef += quadelems[next].coef;
8663  ++next;
8664  continue;
8665  }
8666 
8667  /* otherwise, move next element to current position */
8668  quadelems[i] = quadelems[next];
8669  ++i;
8670  ++next;
8671  }
8672  assert(next == nquadelems);
8673 
8674  /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
8675  *nquadelemsnew = i;
8676 }
8677 
8678 /**@} */
8679 
8680 /**@name Expression graph node private methods */
8681 /**@{ */
8682 
8683 /** adds a parent to an expression graph node */
8684 static
8686  BMS_BLKMEM* blkmem, /**< block memory */
8687  SCIP_EXPRGRAPHNODE* node, /**< expression graph node where to add a parent */
8688  SCIP_EXPRGRAPHNODE* parent /**< parent node */
8689  )
8690 {
8691  assert(blkmem != NULL);
8692  assert(node != NULL);
8693  assert(node->depth >= 0);
8694  assert(node->pos >= 0);
8695  assert(parent != NULL);
8696  assert(parent->depth >= 0);
8697  assert(parent->pos >= 0);
8698  assert(parent->depth > node->depth); /* a parent node need to have larger depth */
8699 
8700  ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
8701  assert(node->nparents < node->parentssize);
8702 
8703  node->parents[node->nparents] = parent;
8704  ++node->nparents;
8705 
8706  /* update sorted flag */
8707  node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (node->parents[node->nparents-2] <= parent));
8708 
8709  return SCIP_OKAY;
8710 }
8711 
8712 /** ensures that array of parents in a node is sorted */
8713 static
8715  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
8716  )
8717 {
8718  assert(node != NULL);
8719 
8720  if( node->parentssorted )
8721  {
8722 #ifndef NDEBUG
8723  int i;
8724  for( i = 1; i < node->nparents; ++i )
8725  assert(ptrcomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
8726 #endif
8727  return;
8728  }
8729 
8730  SCIPsortPtr((void**)node->parents, ptrcomp, node->nparents);
8731 
8732  node->parentssorted = TRUE;
8733 }
8734 
8735 /** removes a parent from an expression graph node
8736  *
8737  * If the node is not used and has no other parents, then it is freed.
8738  */
8739 static
8741  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
8742  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to remove a parent, *node will be set to NULL */
8743  SCIP_EXPRGRAPHNODE* parent /**< parent node to remove */
8744  )
8745 {
8746  SCIP_EXPRGRAPHNODE* node_;
8747  int pos;
8748 
8749  assert(exprgraph != NULL);
8750  assert(node != NULL);
8751  assert(*node != NULL);
8752  assert((*node)->depth >= 0);
8753  assert((*node)->pos >= 0);
8754  assert((*node)->nparents > 0);
8755  assert(parent != NULL);
8756  assert(parent->depth >= 0);
8757  assert(parent->pos >= 0);
8758  assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
8759 
8760  /* find parent */
8761  exprgraphNodeSortParents(*node);
8762  (void) SCIPsortedvecFindPtr((void**)(*node)->parents, ptrcomp, (void*)parent, (*node)->nparents, &pos);
8763  assert(pos >= 0);
8764  assert(pos < (*node)->nparents);
8765  assert((*node)->parents[pos] == parent);
8766 
8767  /* move last parent to pos, if pos is before last
8768  * update sorted flag */
8769  if( pos < (*node)->nparents-1 )
8770  {
8771  (*node)->parents[pos] = (*node)->parents[(*node)->nparents-1];
8772  (*node)->parentssorted = ((*node)->nparents <= 2);
8773  }
8774  --(*node)->nparents;
8775 
8776  /* keep pointer to *node in case it is still used */
8777  node_ = (*node)->nuses > 0 ? *node : NULL;
8778 
8779  /* capture and release node so it is freed if possible */
8780  SCIPexprgraphCaptureNode(*node);
8781  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
8782 
8783  /* restore pointer, if node still exists */
8784  *node = node_;
8785 
8786  return SCIP_OKAY;
8787 }
8788 
8789 /** checks if a node is parent of a node */
8790 static
8792  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
8793  SCIP_EXPRGRAPHNODE* parent /**< parent to look for */
8794  )
8795 {
8796  int pos;
8797 
8798  assert(node != NULL);
8799  assert(parent != NULL);
8800 
8801  /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
8802  if( node->depth >= parent->depth || node->nparents == 0 )
8803  return FALSE;
8804  assert(node->parents != NULL);
8805 
8806  /* ensure parents array is sorted */
8808 
8809  return SCIPsortedvecFindPtr((void**)node->parents, ptrcomp, (void*)parent, node->nparents, &pos);
8810 }
8811 
8812 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
8813  *
8814  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
8815  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
8816  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
8817  *
8818  * It is assumed that node and all exprs are in the expression graph already.
8819  * It is assumed that all expressions that are added have lower depth than node.
8820  */
8821 static
8823  BMS_BLKMEM* blkmem, /**< block memory */
8824  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
8825  int nexprs, /**< number of children to add */
8826  SCIP_EXPRGRAPHNODE** exprs, /**< children nodes to add */
8827  int* childmap /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
8828  )
8829 {
8830  int i;
8831  int j;
8832  int orignchildren;
8833  SCIP_Bool existsalready;
8834 
8835  assert(blkmem != NULL);
8836  assert(node != NULL);
8837  assert(node->depth > 0);
8838  assert(node->pos >= 0);
8839  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);
8840  assert(exprs != NULL || nexprs == 0);
8841 
8842  if( nexprs == 0 )
8843  return SCIP_OKAY;
8844 
8845  orignchildren = node->nchildren;
8846  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
8847 
8848  for( i = 0; i < nexprs; ++i )
8849  {
8850  assert(exprs[i]->depth >= 0); /*lint !e613*/
8851  assert(exprs[i]->pos >= 0); /*lint !e613*/
8852  assert(exprs[i]->depth < node->depth); /*lint !e613*/
8853 
8854  /* check if exprs[i] is a child already, if not SUM or PRODUCT */
8855  existsalready = FALSE;
8856  if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
8857  for( j = 0; j < orignchildren; ++j )
8858  /* during simplification of polynomials, their may be NULL's in children array */
8859  if( node->children[j] != NULL && node->children[j] == exprs[i] ) /*lint !e613*/
8860  {
8861  existsalready = TRUE;
8862  break;
8863  }
8864 
8865  if( !existsalready )
8866  {
8867  /* add exprs[i] to children array */
8868  node->children[node->nchildren] = exprs[i]; /*lint !e613*/
8869  SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) ); /*lint !e613*/
8870  if( childmap != NULL )
8871  childmap[i] = node->nchildren;
8872  ++node->nchildren;
8873  }
8874  else
8875  {
8876  if( childmap != NULL )
8877  childmap[i] = j; /*lint !e644*/
8878  if( node->op == SCIP_EXPR_LINEAR )
8879  {
8880  /* if linear expression, increase coefficient by 1.0 */
8881  ((SCIP_Real*)node->data.data)[j] += 1.0;
8882  }
8883  }
8884  }
8885 
8886  /* shrink children array to actually used size */
8887  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
8888 
8889  if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
8890  {
8891  /* if linear expression, then add 1.0 coefficients for new expressions */
8892  SCIP_Real* data;
8893 
8894  data = (SCIP_Real*)node->data.data;
8895  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
8896  data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
8897  for( i = orignchildren; i < node->nchildren; ++i )
8898  data[i] = 1.0;
8899  node->data.data = (void*)data;
8900  }
8901  else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
8902  {
8903  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
8905 
8906  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
8907  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
8908  BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren); /*lint !e866*/
8909  }
8910 
8911  node->simplified = FALSE;
8912 
8913  return SCIP_OKAY;
8914 }
8915 
8916 /** replaces a child node by another node
8917  *
8918  * Assumes that both nodes represent the same expression.
8919  * If this node was the last parent of oldchild and oldchild is not in use, then it is freed.
8920  * newchild must have deeper depth than node.
8921  */
8922 static
8924  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
8925  SCIP_EXPRGRAPHNODE* node, /**< pointer to expression graph node */
8926  SCIP_EXPRGRAPHNODE** oldchild, /**< child node that should be replaced, it may be freed */
8927  SCIP_EXPRGRAPHNODE* newchild /**< node that should take position of oldchild */
8928  )
8929 {
8930  int i;
8931 
8932  assert(exprgraph != NULL);
8933  assert(node != NULL);
8934  assert(oldchild != NULL);
8935  assert(*oldchild != NULL);
8936  assert(newchild != NULL);
8937 
8938  if( *oldchild == newchild )
8939  return SCIP_OKAY;
8940 
8941  SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
8942 
8943  /* search for oldchild in children array */
8944  for( i = 0; i < node->nchildren; ++i )
8945  {
8946  if( node->children[i] == *oldchild )
8947  {
8948  /* add as parent to newchild */
8949  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
8950 
8951  /* remove as parent from oldchild */
8952  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
8953 
8954  /* set newchild as child i */
8955  node->children[i] = newchild;
8956 
8957  /* we're done */
8958  break;
8959  }
8960  }
8961  assert(i < node->nchildren); /* assert that oldchild has been found in children array */
8962 
8963  node->simplified = FALSE;
8964 
8965  return SCIP_OKAY;
8966 }
8967 
8968 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
8969  *
8970  * A node is larger than another node, if their corresponding constants are related that way.
8971  */
8972 static
8973 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
8974 {
8975  assert(elem1 != NULL);
8976  assert(elem2 != NULL);
8977  assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
8978  assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
8979  assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
8980  assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
8981 
8982  if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
8983  return 1;
8984  else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
8985  return -1;
8986  else
8987  return 0;
8988 }
8989 
8990 /** sort array of nodes that holds constants */
8991 static
8993  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
8994  )
8995 {
8996  assert(exprgraph != NULL);
8997 
8998  if( exprgraph->constssorted )
8999  return;
9000 
9001  SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
9002 
9003  exprgraph->constssorted = TRUE;
9004 }
9005 
9006 /** finds position of expression graph node corresponding to a constant in constnodes array */
9007 static
9009  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9010  SCIP_EXPRGRAPHNODE* node, /**< node to search for */
9011  int* pos /**< buffer to store position of node, if found */
9012  )
9013 {
9014  int left;
9015  int right;
9016  int middle;
9017 
9018  assert(exprgraph != NULL);
9019  assert(node != NULL);
9020  assert(node->op == SCIP_EXPR_CONST);
9021  assert(node->depth == 0);
9022  assert(node->pos >= 0);
9023  assert(pos != NULL);
9024 
9025  exprgraphSortConstNodes(exprgraph);
9026  assert(exprgraph->constssorted);
9027 
9028  /* find a node with constant node->data.dbl using binary search */
9029  left = 0;
9030  right = exprgraph->nconsts-1;
9031  *pos = -1;
9032  while( left <= right )
9033  {
9034  middle = (left+right)/2;
9035  assert(0 <= middle && middle < exprgraph->nconsts);
9036 
9037  if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9038  right = middle - 1;
9039  else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9040  left = middle + 1;
9041  else
9042  {
9043  *pos = middle;
9044  break;
9045  }
9046  }
9047  assert(left == right+1 || *pos >= 0);
9048  if( left == right+1 )
9049  return FALSE;
9050 
9051  /* search left of *pos to find node */
9052  while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl ) /*lint !e777*/
9053  --*pos;
9054  /* search right of *pos to find node */
9055  while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl ) /*lint !e777*/
9056  ++*pos;
9057 
9058  return exprgraph->constnodes[*pos] == node;
9059 }
9060 
9061 /** creates an expression graph node */
9062 static
9064  BMS_BLKMEM* blkmem, /**< block memory */
9065  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
9066  SCIP_EXPROP op, /**< operator type of expression */
9067  SCIP_EXPROPDATA opdata /**< operator data of expression */
9068  )
9069 {
9070  assert(blkmem != NULL);
9071  assert(node != NULL);
9072 
9073  SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9074  BMSclearMemory(*node);
9075 
9076  (*node)->op = op;
9077  (*node)->data = opdata;
9078 
9079  /* mark graph position as not in graph yet */
9080  (*node)->depth = -1;
9081  (*node)->pos = -1;
9082 
9083  /* arrays of length 0 are trivially sorted */
9084  (*node)->parentssorted = TRUE;
9085 
9086  /* set bounds interval to entire */
9087  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9088  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9089 
9090  /* set initial value to invalid */
9091  (*node)->value = SCIP_INVALID;
9092 
9093  /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9094  if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9095  (*node)->curv = SCIP_EXPRCURV_LINEAR;
9096  else
9097  (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9098 
9099  /* per default, a node is enabled */
9100  (*node)->enabled = TRUE;
9101 
9102  return SCIP_OKAY;
9103 }
9104 
9105 /** prints the expression corresponding to a node (not recursively) */
9106 static
9108  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9109  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9110  FILE* file, /**< file to print to, or NULL for stdout */
9111  const char** varnames, /**< variable names, or NULL for generic names */
9112  SCIP_Bool printchildrenbounds /**< whether to print bounds of children */
9113  )
9114 {
9115  int i;
9116 
9117  assert(node != NULL);
9118 
9119  switch( node->op )
9120  {
9121  case SCIP_EXPR_VARIDX:
9122  if( varnames != NULL )
9123  {
9124  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9125  }
9126  else
9127  SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9128  break;
9129 
9130  case SCIP_EXPR_CONST:
9131  SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9132  break;
9133 
9134  case SCIP_EXPR_PARAM:
9135  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9136  break;
9137 
9138  case SCIP_EXPR_PLUS:
9139  if( printchildrenbounds )
9140  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9141  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9142  if( printchildrenbounds )
9143  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9144  break;
9145 
9146  case SCIP_EXPR_MINUS:
9147  if( printchildrenbounds )
9148  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9149  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9150  if( printchildrenbounds )
9151  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9152  break;
9153 
9154  case SCIP_EXPR_MUL:
9155  if( printchildrenbounds )
9156  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9157  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9158  if( printchildrenbounds )
9159  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9160  break;
9161 
9162  case SCIP_EXPR_DIV:
9163  if( printchildrenbounds )
9164  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9165  SCIPmessageFPrintInfo(messagehdlr, file, "/");
9166  if( printchildrenbounds )
9167  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9168  break;
9169 
9170  case SCIP_EXPR_SQUARE:
9171  if( printchildrenbounds )
9172  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9173  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9174  break;
9175 
9176  case SCIP_EXPR_REALPOWER:
9177  if( printchildrenbounds )
9178  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9179  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9180  break;
9181 
9182  case SCIP_EXPR_SIGNPOWER:
9183  if( printchildrenbounds )
9184  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9185  node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9186  else
9187  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9188  break;
9189 
9190  case SCIP_EXPR_INTPOWER:
9191  SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9192  if( printchildrenbounds )
9193  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9194  SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9195  break;
9196 
9197  case SCIP_EXPR_SQRT:
9198  case SCIP_EXPR_EXP:
9199  case SCIP_EXPR_LOG:
9200  case SCIP_EXPR_SIN:
9201  case SCIP_EXPR_COS:
9202  case SCIP_EXPR_TAN:
9203  /* SCIP_EXPR_ERF = 20, */ /**< gaussian error function (1 operand) */
9204  /* SCIP_EXPR_ERFI = 21, */ /**< imaginary part of gaussian error function (1 operand) */
9205  case SCIP_EXPR_MIN:
9206  case SCIP_EXPR_MAX:
9207  case SCIP_EXPR_ABS:
9208  case SCIP_EXPR_SIGN:
9209  SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9210  if( printchildrenbounds )
9211  {
9212  SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9213  if( node->nchildren == 2 )
9214  SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9215  SCIPmessageFPrintInfo(messagehdlr, file, ")");
9216  }
9217  break;
9218 
9219  case SCIP_EXPR_SUM:
9220  if( printchildrenbounds )
9221  for( i = 0; i < node->nchildren; ++i )
9222  {
9223  if( i > 0 )
9224  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9225  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9226  }
9227  else
9228  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9229  break;
9230 
9231  case SCIP_EXPR_PRODUCT:
9232  if( printchildrenbounds )
9233  for( i = 0; i < node->nchildren; ++i )
9234  {
9235  if( i > 0 )
9236  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9237  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9238  }
9239  else
9240  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9241  break;
9242 
9243  case SCIP_EXPR_LINEAR:
9244  {
9245  SCIP_Real constant;
9246 
9247  constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9248 
9249  if( constant != 0.0 || node->nchildren == 0 )
9250  SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9251 
9252  for( i = 0; i < node->nchildren; ++i )
9253  {
9254  if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9255  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9256  else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9257  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9258  else
9259  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9260  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9261  if( printchildrenbounds )
9262  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9263  }
9264 
9265  break;
9266  }
9267 
9268  case SCIP_EXPR_QUADRATIC:
9269  {
9270  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9271 
9272  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9273  assert(quadraticdata != NULL);
9274 
9275  if( quadraticdata->constant != 0.0 )
9276  SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9277 
9278  if( quadraticdata->lincoefs != NULL )
9279  for( i = 0; i < node->nchildren; ++i )
9280  {
9281  if( quadraticdata->lincoefs[i] == 0.0 )
9282  continue;
9283  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9284  if( printchildrenbounds )
9285  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9286  }
9287 
9288  for( i = 0; i < quadraticdata->nquadelems; ++i )
9289  {
9290  if( quadraticdata->quadelems[i].coef == 1.0 )
9291  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9292  else if( quadraticdata->quadelems[i].coef == -1.0 )
9293  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9294  else
9295  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9296  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9297  if( printchildrenbounds )
9298  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9299  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9300  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9301  else
9302  {
9303  SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9304  if( printchildrenbounds )
9305  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9306  }
9307  }
9308 
9309  break;
9310  }
9311 
9312  case SCIP_EXPR_POLYNOMIAL:
9313  {
9314  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9315  SCIP_EXPRDATA_MONOMIAL* monomialdata;
9316  int j;
9317 
9318  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9319  assert(polynomialdata != NULL);
9320 
9321  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
9322  {
9323  SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
9324  }
9325 
9326  for( i = 0; i < polynomialdata->nmonomials; ++i )
9327  {
9328  monomialdata = polynomialdata->monomials[i];
9329  if( monomialdata->coef == 1.0 )
9330  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9331  else if( monomialdata->coef == -1.0 )
9332  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9333  else
9334  SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
9335 
9336  for( j = 0; j < monomialdata->nfactors; ++j )
9337  {
9338  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
9339  if( printchildrenbounds )
9340  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
9341  if( monomialdata->exponents[j] < 0.0 )
9342  SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
9343  else if( monomialdata->exponents[j] != 1.0 )
9344  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
9345  }
9346  }
9347 
9348  break;
9349  }
9350 
9351  case SCIP_EXPR_LAST:
9352  default:
9353  SCIPmessageFPrintInfo(messagehdlr, file, SCIPexpropGetName(node->op));
9354  break;
9355  }
9356 }
9357 
9358 /** prints a node of an expression graph */
9359 static
9361  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9362  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9363  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9364  FILE* file, /**< file to print to, or NULL for stdout */
9365  const char** varnames /**< variable names, or NULL for generic names */
9366  )
9367 {
9368  SCIP_Real color;
9369  int i;
9370 
9371  assert(exprgraph != NULL);
9372  assert(node != NULL);
9373  assert(file != NULL);
9374 
9375  color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
9376  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
9377 
9378  exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
9379 
9380  SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
9382  SCIPmessageFPrintInfo(messagehdlr, file, "!");
9384  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9386  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9387 
9388  SCIPmessageFPrintInfo(messagehdlr, file, "\"");
9389 
9390  if( !node->enabled )
9391  SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
9392 
9393  SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
9394 
9395  /* add edges from node to children */
9396  for( i = 0; i < node->nchildren; ++i )
9397  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);
9398 }
9399 
9400 /** evaluate node of expression graph w.r.t. values stored in children */
9401 static
9403  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9404  SCIP_Real* varvals /**< values for variables */
9405  )
9406 {
9407  int i;
9409  SCIP_Real* buf;
9410 
9411  assert(node != NULL);
9412 
9413  /* if many children, get large enough memory to store argument values */
9415  {
9416  SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
9417  }
9418  else
9419  {
9420  buf = staticbuf;
9421  }
9422 
9423  /* get values of children */
9424  for( i = 0; i < node->nchildren; ++i )
9425  {
9426  assert(node->children[i]->value != SCIP_INVALID); /*lint !e777*/
9427  buf[i] = node->children[i]->value; /*lint !e644*/
9428  }
9429 
9430  /* evaluate this expression */
9431  assert(exprOpTable[node->op].eval != NULL);
9432  SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
9433  assert(node->value != SCIP_INVALID); /*lint !e777*/
9434 
9435  /* free memory, if allocated before */
9436  if( staticbuf != buf )
9437  {
9438  BMSfreeMemoryArray(&buf);
9439  }
9440 
9441  return SCIP_OKAY;
9442 }
9443 
9444 /** evaluates node including subtree */
9445 static
9447  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9448  SCIP_Real* varvals /**< values for variables */
9449  )
9450 {
9451  int i;
9452 
9453  assert(node != NULL);
9454 
9455  for( i = 0; i < node->nchildren; ++i )
9456  {
9457  SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
9458  }
9459 
9460  SCIP_CALL( exprgraphNodeEval(node, varvals) );
9461 
9462  return SCIP_OKAY;
9463 }
9464 
9465 /** updates bounds of a node if a children has changed its bounds */
9466 static
9468  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9469  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
9470  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
9471  SCIP_Bool parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
9472  )
9473 {
9474  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
9475  SCIP_INTERVAL* childbounds;
9476  SCIP_INTERVAL newbounds;
9477  int i;
9478 
9479  assert(node != NULL);
9480  assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
9481  assert(node->pos >= 0); /* node should be in graph */
9482  assert(node->op != SCIP_EXPR_VARIDX);
9483  assert(node->op != SCIP_EXPR_PARAM);
9484 
9485  /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
9486  * if node is disabled, then also do nothing */
9487  if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
9488  return SCIP_OKAY;
9489 
9490  /* if many children, get large enough memory to store children bounds */
9492  {
9493  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
9494  }
9495  else
9496  {
9497  childbounds = childboundsstatic;
9498  }
9499 
9500  /* assemble bounds of children */
9501  for( i = 0; i < node->nchildren; ++i )
9502  {
9503  /* child should have valid and non-empty bounds */
9505  assert(!SCIPintervalIsEmpty(node->children[i]->bounds));
9506 
9507  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
9508  }
9509 
9510  /* call interval evaluation function for this operand */
9511  assert( exprOpTable[node->op].inteval != NULL );
9512  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
9513 
9514  /* free memory, if allocated before */
9515  if( childbounds != childboundsstatic )
9516  {
9517  BMSfreeMemoryArray(&childbounds);
9518  }
9519 
9520  /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
9521 
9522  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
9523  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
9524  *
9525  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
9526  *
9527  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
9528  */
9529  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
9530  ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
9531  {
9532  for( i = 0; i < node->nparents; ++i )
9534 
9535  node->bounds = newbounds;
9536  }
9537  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
9538  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
9539  {
9540  for( i = 0; i < node->nparents; ++i )
9542 
9543  node->bounds = newbounds;
9544  }
9545  else
9546  {
9547  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
9548  }
9549 
9550  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);
9551 
9552  /* node now has valid bounds */
9554 
9555  return SCIP_OKAY;
9556 }
9557 
9558 /** propagate bounds of a node into children by reverting the nodes expression */
9559 static
9561  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9562  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
9563  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
9564  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
9565  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
9566  )
9567 {
9568  SCIP_INTERVAL childbounds;
9569  int i;
9570 
9571  assert(exprgraph != NULL);
9572  assert(node != NULL);
9573  assert(node->depth >= 0); /* node should be in graph */
9574  assert(node->pos >= 0); /* node should be in graph */
9575  assert(minstrength >= 0.0);
9576  assert(cutoff != NULL);
9577  assert(!SCIPintervalIsEmpty(node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
9578  assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
9579 
9580  /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
9582  return;
9583 
9584  /* if node is not enabled, then do nothing */
9585  if( !node->enabled )
9586  return;
9587 
9588  /* tell children that they should propagate their bounds even if not tightened */
9590  minstrength = -1.0;
9591 
9592  /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
9594 
9595  /* 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);
9596  * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
9597  * SCIPdebugPrintf("\n");
9598  */
9599 
9600  /* @todo add callback to exprOpTable for this */
9601 
9602  switch( node->op )
9603  {
9604  case SCIP_EXPR_VARIDX:
9605  case SCIP_EXPR_CONST:
9606  case SCIP_EXPR_PARAM:
9607  /* cannot propagate bound changes further */
9608  break;
9609 
9610  case SCIP_EXPR_PLUS:
9611  {
9612  assert(node->nchildren == 2);
9613  /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
9614 
9615  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
9616  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9617 
9618  if( *cutoff )
9619  break;
9620 
9621  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
9622  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9623 
9624  break;
9625  }
9626 
9627  case SCIP_EXPR_MINUS:
9628  {
9629  assert(node->nchildren == 2);
9630  /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
9631 
9632  SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
9633  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9634 
9635  if( *cutoff )
9636  break;
9637 
9638  SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
9639  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9640 
9641  break;
9642  }
9643 
9644  case SCIP_EXPR_MUL:
9645  {
9646  assert(node->nchildren == 2);
9647  /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
9648 
9649  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
9650  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9651 
9652  if( *cutoff )
9653  break;
9654 
9655  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
9656  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9657 
9658  break;
9659  }
9660 
9661  case SCIP_EXPR_DIV:
9662  {
9663  assert(node->nchildren == 2);
9664  /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
9665 
9666  SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
9667  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9668 
9669  if( *cutoff )
9670  break;
9671 
9672  SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
9673  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9674 
9675  break;
9676  }
9677 
9678  case SCIP_EXPR_SQUARE:
9679  {
9680  assert(node->nchildren == 1);
9681  /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
9682 
9683  if( node->bounds.sup < 0.0 )
9684  {
9685  *cutoff = TRUE;
9686  break;
9687  }
9688 
9689  SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
9690  if( node->children[0]->bounds.inf <= -childbounds.inf )
9691  SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
9692  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9693 
9694  break;
9695  }
9696 
9697  case SCIP_EXPR_SQRT:
9698  {
9699  assert(node->nchildren == 1);
9700  /* f = sqrt(c0) -> c0 = f^2 */
9701 
9702  SCIPintervalSquare(infinity, &childbounds, node->bounds);
9703  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9704 
9705  break;
9706  }
9707 
9708  case SCIP_EXPR_REALPOWER:
9709  {
9710  assert(node->nchildren == 1);
9711 
9712  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
9713 
9714  if( SCIPintervalIsEmpty(childbounds) )
9715  {
9716  *cutoff = TRUE;
9717  break;
9718  }
9719  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9720 
9721  break;
9722  }
9723 
9724  case SCIP_EXPR_SIGNPOWER:
9725  {
9726  assert(node->nchildren == 1);
9727 
9728  if( node->data.dbl != 0.0 )
9729  {
9730  SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
9731  }
9732  else
9733  {
9734  /* behaves like SCIP_EXPR_SIGN */
9735  SCIPintervalSetBounds(&childbounds,
9736  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
9737  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
9738  }
9739 
9740  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9741 
9742  break;
9743  }
9744 
9745  case SCIP_EXPR_INTPOWER:
9746  {
9747  assert(node->nchildren == 1);
9748 
9749  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
9750 
9751  if( SCIPintervalIsEmpty(childbounds) )
9752  {
9753  *cutoff = TRUE;
9754  break;
9755  }
9756  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9757 
9758  break;
9759  }
9760 
9761  case SCIP_EXPR_EXP:
9762  {
9763  assert(node->nchildren == 1);
9764  /* f = exp(c0) -> c0 = log(f) */
9765 
9766  if( node->bounds.sup < 0.0 )
9767  {
9768  *cutoff = TRUE;
9769  break;
9770  }
9771 
9772  SCIPintervalLog(infinity, &childbounds, node->bounds);
9773  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9774 
9775  break;
9776  }
9777 
9778  case SCIP_EXPR_LOG:
9779  {
9780  assert(node->nchildren == 1);
9781  /* f = log(c0) -> c0 = exp(f) */
9782 
9783  SCIPintervalExp(infinity, &childbounds, node->bounds);
9784  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9785 
9786  break;
9787  }
9788 
9789  case SCIP_EXPR_SIN:
9790  case SCIP_EXPR_COS:
9791  case SCIP_EXPR_TAN:
9792  /* case SCIP_EXPR_ERF: */
9793  /* case SCIP_EXPR_ERFI: */
9794  {
9795  assert(node->nchildren == 1);
9796 
9797  /* @todo implement */
9798 
9799  break;
9800  }
9801 
9802  case SCIP_EXPR_ABS:
9803  {
9804  assert(node->nchildren == 1);
9805  /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
9806 
9807  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
9808  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9809 
9810  break;
9811  }
9812 
9813  case SCIP_EXPR_SIGN:
9814  {
9815  assert(node->nchildren == 1);
9816  /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
9817 
9818  SCIPintervalSetBounds(&childbounds,
9819  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
9820  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
9821  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9822 
9823  break;
9824  }
9825 
9826  case SCIP_EXPR_MIN:
9827  {
9828  assert(node->nchildren == 2);
9829  /* f = min(c0,c1) -> f <= c0, f <= c1
9830  * if c1 > f -> c0 = f
9831  * if c0 > f -> c1 = f
9832  */
9833 
9834  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
9835  node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
9836  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9837 
9838  if( *cutoff )
9839  break;
9840 
9841  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
9842  node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
9843  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9844 
9845  break;
9846  }
9847 
9848  case SCIP_EXPR_MAX:
9849  {
9850  assert(node->nchildren == 2);
9851  /* f = max(c0, c1) -> f >= c0, f >= c1
9852  * if c1 < f -> c0 = f
9853  * if c0 < f -> c1 = f
9854  */
9855 
9856  SCIPintervalSetBounds(&childbounds,
9857  node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
9858  node->bounds.sup);
9859  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
9860 
9861  SCIPintervalSetBounds(&childbounds,
9862  node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
9863  node->bounds.sup);
9864  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
9865 
9866  break;
9867  }
9868 
9869  case SCIP_EXPR_SUM:
9870  {
9871  SCIP_ROUNDMODE prevroundmode;
9872 
9873  /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
9874 
9875  SCIP_Real minlinactivity;
9876  SCIP_Real maxlinactivity;
9877  int minlinactivityinf;
9878  int maxlinactivityinf;
9879 
9880  if( node->nchildren == 0 )
9881  break;
9882 
9883  if( SCIPintervalIsEntire(infinity, node->bounds) )
9884  break;
9885 
9886  minlinactivity = 0.0;
9887  maxlinactivity = 0.0;
9888  minlinactivityinf = 0;
9889  maxlinactivityinf = 0;
9890 
9891  prevroundmode = SCIPintervalGetRoundingMode();
9893 
9894  for( i = 0; i < node->nchildren; ++i )
9895  {
9896  assert(!SCIPintervalIsEmpty(node->children[i]->bounds));
9897 
9898  /* minimal activity is only useful if node has a finite upper bound */
9899  if( node->bounds.sup < infinity )
9900  {
9901  if( node->children[i]->bounds.inf <= -infinity )
9902  {
9903  ++minlinactivityinf;
9904  }
9905  else
9906  {
9907  assert(node->children[i]->bounds.inf < infinity);
9908  minlinactivity += node->children[i]->bounds.inf;
9909  }
9910  }
9911 
9912  /* maximal activity is only useful if node has a finite lower bound
9913  * we compute negated maximal activity here so we can keep downward rounding
9914  */
9915  if( node->bounds.inf > -infinity )
9916  {
9917  if( node->children[i]->bounds.sup >= infinity )
9918  {
9919  ++maxlinactivityinf;
9920  }
9921  else
9922  {
9923  assert(node->children[i]->bounds.sup > -infinity);
9924  maxlinactivity -= node->children[i]->bounds.sup;
9925  }
9926  }
9927  }
9928  maxlinactivity = -maxlinactivity; /* correct sign */
9929 
9930  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
9931  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
9932  ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
9933  )
9934  {
9935  SCIPintervalSetRoundingMode(prevroundmode);
9936  break;
9937  }
9938 
9939  for( i = 0; i < node->nchildren && !*cutoff; ++i )
9940  {
9941  /* upper bounds of c_i is
9942  * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
9943  * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
9944  */
9945  SCIPintervalSetEntire(infinity, &childbounds);
9946  if( node->bounds.sup < infinity )
9947  {
9948  /* we are still in downward rounding mode, so negate and negate to get upward rounding */
9949  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
9950  {
9951  assert(minlinactivityinf == 1);
9952  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
9953  }
9954  else if( minlinactivityinf == 0 )
9955  {
9956  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
9957  }
9958  }
9959 
9960  /* lower bounds of c_i is
9961  * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
9962  * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
9963  */
9964  if( node->bounds.inf > -infinity )
9965  {
9966  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
9967  {
9968  assert(maxlinactivityinf == 1);
9969  childbounds.inf = node->bounds.inf - maxlinactivity;
9970  }
9971  else
9972  {
9973  childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
9974  }
9975  }
9976 
9977  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, cutoff);
9978  }
9979 
9980  SCIPintervalSetRoundingMode(prevroundmode);
9981 
9982  break;
9983  }
9984 
9985  case SCIP_EXPR_PRODUCT:
9986  {
9987  int j;
9988  /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
9989 
9990  /* too expensive (runtime here is quadratic in number of children) */
9991  if( node->nchildren > 10 )
9992  break;
9993 
9994  /* useless */
9995  if( SCIPintervalIsEntire(infinity, node->bounds) )
9996  break;
9997 
9998  for( i = 0; i < node->nchildren && !*cutoff; ++i )
9999  {
10000  /* compute prod_{j:j!=i} c_j */
10001  SCIPintervalSet(&childbounds, 1.0);
10002  for( j = 0; j < node->nchildren; ++j )
10003  {
10004  if( i == j )
10005  continue;
10006  SCIPintervalMul(infinity, &childbounds, childbounds, node->children[i]->bounds);
10007 
10008  /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
10009  if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
10010  break;
10011  }
10012 
10013  if( j == node->nchildren )
10014  {
10015  SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
10016  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, cutoff);
10017  }
10018  }
10019 
10020  break;
10021  }
10022 
10023  case SCIP_EXPR_LINEAR:
10024  {
10025  SCIP_ROUNDMODE prevroundmode;
10026  SCIP_Real* coefs;
10027 
10028  /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10029 
10030  SCIP_Real minlinactivity;
10031  SCIP_Real maxlinactivity;
10032  int minlinactivityinf;
10033  int maxlinactivityinf;
10034 
10035  if( node->nchildren == 0 )
10036  break;
10037 
10038  if( SCIPintervalIsEntire(infinity, node->bounds) )
10039  break;
10040 
10041  coefs = (SCIP_Real*)node->data.data;
10042 
10043  minlinactivity = coefs[node->nchildren];
10044  maxlinactivity = -coefs[node->nchildren];
10045  minlinactivityinf = 0;
10046  maxlinactivityinf = 0;
10047 
10048  prevroundmode = SCIPintervalGetRoundingMode();
10050 
10051  for( i = 0; i < node->nchildren; ++i )
10052  {
10053  assert(!SCIPintervalIsEmpty(node->children[i]->bounds));
10054 
10055  /* minimal activity is only useful if node has a finite upper bound */
10056  if( node->bounds.sup < infinity )
10057  {
10058  if( coefs[i] >= 0.0 )
10059  {
10060  if( node->children[i]->bounds.inf <= -infinity )
10061  {
10062  ++minlinactivityinf;
10063  }
10064  else
10065  {
10066  assert(node->children[i]->bounds.inf < infinity);
10067  minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10068  }
10069  }
10070  else
10071  {
10072  if( node->children[i]->bounds.sup >= infinity )
10073  {
10074  ++minlinactivityinf;
10075  }
10076  else
10077  {
10078  assert(node->children[i]->bounds.sup > -infinity);
10079  minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10080  }
10081  }
10082  }
10083 
10084  /* maximal activity is only useful if node has a finite lower bound
10085  * we compute negated maximal activity here so we can keep downward rounding
10086  */
10087  if( node->bounds.inf > -infinity )
10088  {
10089  if( coefs[i] >= 0.0 )
10090  {
10091  if( node->children[i]->bounds.sup >= infinity )
10092  {
10093  ++maxlinactivityinf;
10094  }
10095  else
10096  {
10097  assert(node->children[i]->bounds.sup > -infinity);
10098  maxlinactivity -= coefs[i] * node->children[i]->bounds.sup;
10099  }
10100  }
10101  else
10102  {
10103  if( node->children[i]->bounds.inf <= -infinity )
10104  {
10105  ++maxlinactivityinf;
10106  }
10107  else
10108  {
10109  assert(node->children[i]->bounds.inf < infinity);
10110  maxlinactivity -= coefs[i] * node->children[i]->bounds.inf;
10111  }
10112  }
10113  }
10114  }
10115  maxlinactivity = -maxlinactivity; /* correct sign */
10116 
10117  SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf);
10118 
10119  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10120  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10121  (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10122  )
10123  {
10124  SCIPintervalSetRoundingMode(prevroundmode);
10125  break;
10126  }
10127 
10128  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10129  {
10130  SCIP_INTERVAL ac;
10131 
10132  if( coefs[i] == 0.0 )
10133  continue;
10134 
10135  /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10136  SCIPintervalSet(&ac, 0.0);
10137  if( coefs[i] >= 0.0 )
10138  {
10139  if( node->children[i]->bounds.inf > -infinity )
10140  ac.inf = coefs[i] * node->children[i]->bounds.inf;
10141  if( node->children[i]->bounds.sup < infinity )
10143  }
10144  else
10145  {
10146  if( node->children[i]->bounds.sup < infinity )
10147  ac.inf = coefs[i] * node->children[i]->bounds.sup;
10148  if( node->children[i]->bounds.inf > -infinity )
10149  ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10150  }
10151 
10152  SCIPintervalSetEntire(infinity, &childbounds);
10153  if( coefs[i] > 0.0 )
10154  {
10155  /* upper bounds of c_i is
10156  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10157  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10158  */
10159  if( node->bounds.sup < infinity )
10160  {
10161  /* we are still in downward rounding mode, so negate to get upward rounding */
10162  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10163  {
10164  assert(minlinactivityinf == 1);
10165  childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10166  }
10167  else if( minlinactivityinf == 0 )
10168  {
10169  childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10170  }
10171  }
10172 
10173  /* lower bounds of c_i is
10174  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10175  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10176  */
10177  if( node->bounds.inf > -infinity )
10178  {
10179  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10180  {
10181  assert(maxlinactivityinf == 1);
10182  childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10183  }
10184  else if( maxlinactivityinf == 0 )
10185  {
10186  childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10187  }
10188  }
10189  }
10190  else
10191  {
10192  /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10193  * thus, we do (b-a)/(-c) in downward rounding
10194  */
10195  /* lower bounds of c_i is
10196  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10197  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10198  */
10199  if( node->bounds.sup < infinity )
10200  {
10201  if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10202  {
10203  assert(minlinactivityinf == 1);
10204  childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10205  }
10206  else if( minlinactivityinf == 0 )
10207  {
10208  childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10209  }
10210  }
10211 
10212  /* upper bounds of c_i is
10213  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10214  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10215  */
10216  if( node->bounds.inf > -infinity )
10217  {
10218  /* we are still in downward rounding mode, so negate to get upward rounding */
10219  if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10220  {
10221  assert(maxlinactivityinf == 1);
10222  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10223  }
10224  else if( maxlinactivityinf == 0 )
10225  {
10226  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10227  }
10228  }
10229  }
10230 
10231  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, cutoff);
10232  }
10233 
10234  SCIPintervalSetRoundingMode(prevroundmode);
10235 
10236  break;
10237  }
10238 
10239  case SCIP_EXPR_QUADRATIC:
10240  {
10241  SCIP_EXPRDATA_QUADRATIC* quaddata;
10242  SCIP_INTERVAL tmp;
10243  SCIP_INTERVAL a;
10244  SCIP_INTERVAL b;
10245  SCIP_INTERVAL c;
10246  SCIP_QUADELEM* quadelems;
10247  int nquadelems;
10248  SCIP_Real* lincoefs;
10249  int k;
10250 
10251  /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10252  * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10253  */
10254 
10255  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10256  quadelems = quaddata->quadelems;
10257  nquadelems = quaddata->nquadelems;
10258  lincoefs = quaddata->lincoefs;
10259 
10260  /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10261  if( nquadelems > 10 )
10262  break;
10263 
10264  if( SCIPintervalIsEntire(infinity, node->bounds) )
10265  break;
10266 
10267  if( node->nchildren == 2 && nquadelems > 0 )
10268  {
10269  /* if it's a bivariate quadratic expression with bilinear term, do something special */
10270  SCIP_Real ax; /* square coefficient of first child */
10271  SCIP_Real ay; /* square coefficient of second child */
10272  SCIP_Real axy; /* bilinear coefficient */
10273 
10274  ax = 0.0;
10275  ay = 0.0;
10276  axy = 0.0;
10277  for( i = 0; i < nquadelems; ++i )
10278  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10279  ax += quadelems[i].coef;
10280  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10281  ay += quadelems[i].coef;
10282  else
10283  axy += quadelems[i].coef;
10284 
10285  c = node->bounds;
10286  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10287 
10288  /* compute bounds for x */
10290  infinity, &childbounds, ax, ay, axy,
10291  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10292  c, node->children[0]->bounds, node->children[1]->bounds
10293  );
10294  if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10295  {
10296  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",
10297  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10298  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10299  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(childbounds)
10300  );
10301  }
10302 
10303  if( SCIPintervalIsEmpty(childbounds) )
10304  *cutoff = TRUE;
10305  else
10306  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, cutoff);
10307  if( *cutoff )
10308  break;
10309 
10310  /* compute bounds for y */
10312  infinity, &childbounds, ay, ax, axy,
10313  lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
10314  c, node->children[1]->bounds, node->children[0]->bounds
10315  );
10316 
10317  if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
10318  {
10319  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",
10320  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10321  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10322  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(childbounds)
10323  );
10324  }
10325 
10326  if( SCIPintervalIsEmpty(childbounds) )
10327  *cutoff = TRUE;
10328  else
10329  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, cutoff);
10330  if( *cutoff )
10331  break;
10332 
10333  break;
10334  }
10335 
10336  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10337  {
10338  SCIPintervalSet(&a, 0.0);
10339  SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
10340  c = node->bounds;
10341  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10342 
10343  /* move linear terms not corresponding to i into c
10344  * @todo do this faster, see EXPR_LINEAR
10345  */
10346  if( lincoefs != NULL )
10347  for( k = 0; k < node->nchildren; ++k )
10348  if( i != k && lincoefs[k] != 0.0 )
10349  {
10350  SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
10351  SCIPintervalSub(infinity, &c, c, tmp);
10352  }
10353 
10354  for( k = 0; k < nquadelems; ++k )
10355  {
10356  if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
10357  {
10358  SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
10359  }
10360  else if( quadelems[k].idx1 == i )
10361  {
10362  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
10363  SCIPintervalAdd(infinity, &b, b, tmp);
10364  }
10365  else if( quadelems[k].idx2 == i )
10366  {
10367  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
10368  SCIPintervalAdd(infinity, &b, b, tmp);
10369  }
10370  else if( quadelems[k].idx1 == quadelems[k].idx2 )
10371  {
10372  SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
10373  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
10374  SCIPintervalSub(infinity, &c, c, tmp);
10375  }
10376  else
10377  {
10378  SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
10379  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
10380  SCIPintervalSub(infinity, &c, c, tmp);
10381  }
10382  }
10383 
10384  SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
10385  a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
10386  SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c);
10387  if( SCIPintervalIsEmpty(childbounds) )
10388  *cutoff = TRUE;
10389  else
10390  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, cutoff);
10391  }
10392 
10393  break;
10394  }
10395 
10396  case SCIP_EXPR_POLYNOMIAL:
10397  {
10398  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
10399  SCIP_EXPRDATA_MONOMIAL** monomials;
10400  SCIP_EXPRDATA_MONOMIAL* monomial;
10401  int nmonomials;
10402  int j;
10403  int k;
10404  SCIP_Real n;
10405  int nexpisdoublen;
10406  int nexpishalfn;
10407  char abc_flag;
10408 
10409  SCIP_INTERVAL monomialcoef;
10410  SCIP_INTERVAL tmp;
10411  SCIP_INTERVAL a;
10412  SCIP_INTERVAL b;
10413  SCIP_INTERVAL c;
10414 
10415  /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
10416  * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
10417  *
10418  * we determine n by setting n to the first exponent of x that we see
10419  * then we count how often we see x^(2n) and x^(n/2)
10420  * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
10421  */
10422 
10423  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
10424  monomials = polynomialdata->monomials;
10425  nmonomials = polynomialdata->nmonomials;
10426 
10427  if( SCIPintervalIsEntire(infinity, node->bounds) )
10428  break;
10429 
10430  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10431  {
10432  n = 0.0;
10433  nexpisdoublen = 0;
10434  nexpishalfn = 0;
10435  for( j = 0; j < nmonomials; ++j )
10436  {
10437  monomial = monomials[j];
10438  for( k = 0; k < monomial->nfactors; ++k )
10439  {
10440  if( monomial->childidxs[k] == i )
10441  {
10442  if( n == 0.0 )
10443  n = monomial->exponents[k];
10444  else if( n == 2*monomial->exponents[k] ) /*lint !e777*/
10445  ++nexpishalfn;
10446  else if( 2*n == monomial->exponents[k] ) /*lint !e777*/
10447  ++nexpisdoublen;
10448  }
10449  }
10450  }
10451 
10452  if( n == 0.0 )
10453  {
10454  /* child does not appear in polynomial -> cannot deduce bound */
10455  continue;
10456  }
10457 
10458  /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
10459  if( nexpishalfn > nexpisdoublen )
10460  n /= 2.0;
10461 
10462  SCIPintervalSet(&a, 0.0);
10463  SCIPintervalSet(&b, 0.0);
10464  SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
10465 
10466  for( j = 0; j < nmonomials; ++j )
10467  {
10468  monomial = monomials[j];
10469  SCIPintervalSet(&monomialcoef, monomial->coef);
10470  abc_flag = 'c';
10471  for( k = 0; k < monomial->nfactors; ++k )
10472  {
10473  if( monomial->childidxs[k] == i )
10474  {
10475  assert(abc_flag == 'c'); /* child should appear only once per monom */
10476  if( n > 0.0 )
10477  {
10478  if( monomial->exponents[k] > 2.0*n )
10479  {
10480  abc_flag = 'a';
10481  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
10482  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10483  }
10484  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
10485  {
10486  abc_flag = 'a';
10487  }
10488  else if( monomial->exponents[k] > n )
10489  {
10490  abc_flag = 'b';
10491  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
10492  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10493  }
10494  else if( monomial->exponents[k] == n ) /*lint !e777*/
10495  {
10496  abc_flag = 'b';
10497  }
10498  else
10499  {
10500  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
10501  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10502  }
10503  }
10504  else
10505  {
10506  assert(n < 0.0);
10507  if( monomial->exponents[k] < 2.0*n )
10508  {
10509  abc_flag = 'a';
10510  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
10511  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10512  }
10513  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
10514  {
10515  abc_flag = 'a';
10516  }
10517  else if( monomial->exponents[k] < n )
10518  {
10519  abc_flag = 'b';
10520  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
10521  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10522  }
10523  else if( monomial->exponents[k] == n ) /*lint !e777*/
10524  {
10525  abc_flag = 'b';
10526  }
10527  else
10528  {
10529  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
10530  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10531  }
10532  }
10533  }
10534  else
10535  {
10536  SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
10537  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10538  }
10539  }
10540 
10541  if( abc_flag == 'a' )
10542  SCIPintervalAdd(infinity, &a, a, monomialcoef);
10543  else if( abc_flag == 'b' )
10544  SCIPintervalAdd(infinity, &b, b, monomialcoef);
10545  else
10546  SCIPintervalSub(infinity, &c, c, monomialcoef);
10547  }
10548 
10549  /* now have equation a*child^(2n) + b*child^n = c
10550  * solve a*y^2 + b*y = c, then child^n = y
10551  */
10552  SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g]",
10553  a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup);
10554  SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c);
10555  SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
10556 
10557  if( SCIPintervalIsEmpty(tmp) )
10558  {
10559  *cutoff = TRUE;
10560  break;
10561  }
10562 
10563  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
10564  SCIPdebugPrintf(" -> c%d = [%10g, %10g]\n", i, childbounds.inf, childbounds.sup);
10565  if( SCIPintervalIsEmpty(childbounds) )
10566  {
10567  SCIPdebugMessage(" -> cutoff\n");
10568  *cutoff = TRUE;
10569  break;
10570  }
10571 
10572  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, cutoff);
10573 
10574  /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
10575  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10576  SCIPdebugPrintf("\n"); */
10577  }
10578 
10579  break;
10580  }
10581 
10582  case SCIP_EXPR_LAST:
10583  default:
10584  SCIPerrorMessage("unknown or unexpected operand: %d\n", node->op);
10585  SCIPABORT();
10586  }
10587 }
10588 
10589 /** removes duplicate children in a polynomial expression node
10590  *
10591  * Leaves NULL's in children array.
10592  */
10593 static
10595  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10596  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
10597  )
10598 {
10599  SCIP_Bool foundduplicates;
10600  int* childmap;
10601  int i;
10602  int j;
10603 
10604  assert(exprgraph != NULL);
10605  assert(node != NULL);
10606  assert(node->op == SCIP_EXPR_POLYNOMIAL);
10607 
10608  if( node->nchildren == 0 )
10609  return SCIP_OKAY;
10610 
10611  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
10612 
10613  foundduplicates = FALSE;
10614  for( i = 0; i < node->nchildren; ++i )
10615  {
10616  if( node->children[i] == NULL )
10617  continue;
10618  childmap[i] = i; /*lint !e644*/
10619 
10620  for( j = i+1; j < node->nchildren; ++j )
10621  {
10622  if( node->children[j] == NULL )
10623  continue;
10624 
10625  if( node->children[i] == node->children[j] )
10626  {
10627  /* node should be parent of children[j] at least twice,
10628  * so we remove it once
10629  */
10630  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
10631  node->children[j] = NULL;
10632  assert(exprgraphNodeIsParent(node->children[i], node));
10633 
10634  childmap[j] = i;
10635  foundduplicates = TRUE;
10636  }
10637  }
10638  }
10639 
10640  /* apply childmap to monomials */
10641  if( foundduplicates )
10643 
10644  /* free childmap */
10645  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
10646 
10647  return SCIP_OKAY;
10648 }
10649 
10650 /** eliminates NULL's in children array and shrinks it to actual size */
10651 static
10653  BMS_BLKMEM* blkmem, /**< block memory */
10654  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
10655  )
10656 {
10657  int* childmap;
10658  int lastnonnull;
10659  int i;
10660 
10661  assert(blkmem != NULL);
10662  assert(node != NULL);
10663  assert(node->op == SCIP_EXPR_POLYNOMIAL);
10664 
10665  if( node->nchildren == 0 )
10666  return SCIP_OKAY;
10667 
10668  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
10669 
10670  /* close gaps in children array */
10671  lastnonnull = node->nchildren-1;
10672  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
10673  --lastnonnull;
10674  for( i = 0; i <= lastnonnull; ++i )
10675  {
10676  if( node->children[i] != NULL )
10677  {
10678  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
10679  continue;
10680  }
10681  assert(node->children[lastnonnull] != NULL);
10682 
10683  /* move child at lastnonnull to position i */
10684  node->children[i] = node->children[lastnonnull];
10685  node->children[lastnonnull] = NULL;
10686  childmap[lastnonnull] = i;
10687 
10688  /* update lastnonnull */
10689  --lastnonnull;
10690  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
10691  --lastnonnull;
10692  }
10693  assert(i > lastnonnull);
10694 
10695  /* apply childmap to monomials */
10696  if( lastnonnull < node->nchildren-1 )
10698 
10699  BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
10700 
10701  /* shrink children array */
10702  if( lastnonnull >= 0 )
10703  {
10704  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
10705  node->nchildren = lastnonnull+1;
10706  }
10707  else
10708  {
10709  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
10710  node->nchildren = 0;
10711  }
10712 
10713  return SCIP_OKAY;
10714 }
10715 
10716 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
10717  *
10718  * Converts node into polynomial, if possible and not constant.
10719  */
10720 static
10722  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10723  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10724  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
10725  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
10726  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
10727  SCIP_Bool* havechange /**< flag to set if the node has been changed */
10728  )
10729 {
10730  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
10731  SCIP_EXPRDATA_MONOMIAL* monomial;
10732  BMS_BLKMEM* blkmem;
10733  SCIP_Bool removechild;
10734  SCIP_Bool* childinuse;
10735  int* childmap;
10736  int childmapsize;
10737  int i;
10738  int j;
10739  int orignchildren;
10740 
10741  assert(exprgraph != NULL);
10742  assert(node != NULL);
10743  assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
10744  assert(havechange != NULL);
10745 
10746  blkmem = exprgraph->blkmem;
10747  assert(blkmem != NULL);
10748 
10749  SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
10750 
10751  /* if all children are constants, then turn this node into constant */
10752  for( i = 0; i < node->nchildren; ++i )
10753  if( node->children[i]->op != SCIP_EXPR_CONST )
10754  break;
10755  if( node->nchildren > 0 && i == node->nchildren )
10756  {
10757  /* get value of node */
10759  assert(node->value != SCIP_INVALID); /*lint !e777*/
10760 
10761  SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
10762  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10763  SCIPdebugPrintf("\n");
10764 
10765  /* free expression data */
10766  if( exprOpTable[node->op].freedata != NULL )
10767  exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
10768 
10769  /* disconnect from children */
10770  for( i = 0; i < node->nchildren; ++i )
10771  {
10772  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
10773  }
10774  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
10775  node->nchildren = 0;
10776 
10777  /* turn into constant expression */
10778  node->op = SCIP_EXPR_CONST;
10779  node->data.dbl = node->value;
10780 
10781  *havechange = TRUE;
10782  node->simplified = TRUE;
10783 
10784  return SCIP_OKAY;
10785  }
10786 
10787  /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
10788  * @todo log(product) -> sum(log)
10789  * @todo product(exp) -> exp(sum)
10790  * @todo exp(x)^p -> exp(p*x)
10791  * @todo exp(const*log(x)) -> x^const
10792  */
10793 
10794  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
10795 
10796  if( node->op != SCIP_EXPR_POLYNOMIAL )
10797  {
10798  node->simplified = TRUE;
10799  return SCIP_OKAY;
10800  }
10801 
10802  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
10803  assert(polynomialdata != NULL);
10804 
10805  orignchildren = node->nchildren;
10806 
10807  /* check if we have duplicate children and merge */
10809  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
10810 
10811  SCIPdebugMessage("expand factors in expression node ");
10812  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
10813  SCIPdebugPrintf("\n");
10814 
10815  childmap = NULL;
10816  childmapsize = 0;
10817 
10818  /* resolve children that are constants
10819  * we do this first, because it reduces the degree and number of factors in the monomials,
10820  * 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
10821  */
10822  for( i = 0; i < node->nchildren; ++i )
10823  {
10824  if( node->children[i] == NULL )
10825  continue;
10826 
10827  /* convert children to polynomial, if not constant or polynomial
10828  * if child was simplified in this round, it may have already been converted, and then nothing happens
10829  * but if child was already simplified, then it was not converted, and thus we try it here
10830  */
10831  if( node->children[i]->op != SCIP_EXPR_CONST )
10832  continue;
10833 
10834  SCIPdebugMessage("expand child %d in expression node ", i);
10835  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
10836  SCIPdebugPrintf("\n\tchild = ");
10837  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
10838  SCIPdebugPrintf("\n");
10839 
10840  removechild = TRUE; /* we intend to release children[i] */
10841 
10842  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
10843 
10844  /* put constant of child i into every monomial where child i is used */
10845  for( j = 0; j < polynomialdata->nmonomials; ++j )
10846  {
10847  int factorpos;
10848 
10849  monomial = polynomialdata->monomials[j];
10850  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
10851  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
10852 
10853  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
10854  {
10855  assert(factorpos >= 0);
10856  assert(factorpos < monomial->nfactors);
10857  /* assert that factors have been merged */
10858  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
10859  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
10860 
10861  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
10862 
10863  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 ) /*lint !e835*/
10864  {
10865  /* if constant is negative and our exponent is not integer, then cannot do expansion */
10866  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
10867  removechild = FALSE;
10868  }
10869  else
10870  {
10871  monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
10872 
10873  /* move last factor to position factorpos */
10874  if( factorpos < monomial->nfactors-1 )
10875  {
10876  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
10877  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
10878  }
10879  --monomial->nfactors;
10880  monomial->sorted = FALSE;
10881  polynomialdata->sorted = FALSE;
10882 
10883  *havechange = TRUE;
10884  }
10885  }
10886  }
10887 
10888  /* forget about child i, if it is not used anymore */
10889  if( removechild )
10890  {
10891  /* remove node from list of parents of child i */
10892  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
10893  node->children[i] = NULL;
10894  }
10895 
10896  /* simplify current polynomial again */
10897  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
10898  }
10899 
10900  /* resolve children that are polynomials itself */
10901  for( i = 0; i < node->nchildren; ++i )
10902  {
10903  if( node->children[i] == NULL )
10904  continue;
10905 
10906  /* convert children to polynomial, if not constant or polynomial
10907  * if child was simplified in this round, it may have already been converted, and then nothing happens
10908  * but if child was already simplified, then it was not converted, and thus we try it here
10909  */
10910  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
10911 
10912  if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
10913  continue;
10914 
10915  SCIPdebugMessage("expand child %d in expression node ", i);
10916  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
10917  SCIPdebugPrintf("\n\tchild = ");
10918  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
10919  SCIPdebugPrintf("\n");
10920 
10921  removechild = TRUE; /* we intend to release children[i] */
10922 
10923  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
10924 
10925  /* add children of child i to node */
10926  SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
10927 
10928  /* put polynomial of child i into every monomial where child i is used */
10929  j = 0;
10930  while( j < polynomialdata->nmonomials )
10931  {
10932  int factorpos;
10933  SCIP_Bool success;
10934 
10935  monomial = polynomialdata->monomials[j];
10936  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
10937  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
10938 
10939  if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
10940  {
10941  ++j;
10942  continue;
10943  }
10944 
10945  assert(factorpos >= 0);
10946  assert(factorpos < monomial->nfactors);
10947  /* assert that factors have been merged */
10948  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
10949  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
10950 
10951  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
10952 
10953  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
10954  (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
10955 
10956  if( !success )
10957  {
10958  removechild = FALSE;
10959  ++j;
10960  }
10961  else
10962  *havechange = TRUE;
10963 
10964  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
10965  * we thus repeat with index j, if a factor was successfully expanded
10966  */
10967  }
10968 
10969  /* forget about child i, if it is not used anymore */
10970  if( removechild )
10971  {
10972  /* remove node from list of parents of child i */
10973  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
10974  node->children[i] = NULL;
10975  }
10976 
10977  /* simplify current polynomial again */
10978  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
10979  }
10980 
10981  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
10982 
10983  /* check which children are still in use */
10984  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
10985  BMSclearMemoryArray(childinuse, node->nchildren); /*lint !e644*/
10986  for( i = 0; i < polynomialdata->nmonomials; ++i )
10987  {
10988  monomial = polynomialdata->monomials[i];
10989  assert(monomial != NULL);
10990 
10991  for( j = 0; j < monomial->nfactors; ++j )
10992  {
10993  assert(monomial->childidxs[j] >= 0);
10994  assert(monomial->childidxs[j] < node->nchildren);
10995  childinuse[monomial->childidxs[j]] = TRUE;
10996  }
10997  }
10998 
10999  /* free children that are not used in any monomial */
11000  for( i = 0; i < node->nchildren; ++i )
11001  if( node->children[i] != NULL && !childinuse[i] )
11002  {
11003  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11004  node->children[i] = NULL;
11005  }
11006 
11007  BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
11008 
11009  /* remove NULLs from children array */
11011 
11012  /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
11013  if( node->nchildren == 0 )
11014  {
11015  SCIP_Real val;
11016 
11017  /* if no children, then it should also have no monomials */
11018  assert(polynomialdata->nmonomials == 0);
11019 
11020  val = polynomialdata->constant;
11021  polynomialdataFree(blkmem, &polynomialdata);
11022 
11023  node->op = SCIP_EXPR_CONST;
11024  node->data.dbl = val;
11025  node->value = val;
11026  }
11027 
11028  /* if no factor in a monomial was replaced, the number of children should not have changed
11029  * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11030  */
11031  *havechange |= (node->nchildren < orignchildren); /*lint !e514*/
11032 
11033  node->simplified = TRUE;
11034 
11035  SCIPdebugMessage("-> %p = ", (void*)node);
11036  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11037  SCIPdebugPrintf("\n");
11038 
11039  return SCIP_OKAY;
11040 }
11041 
11042 /** creates an expression from a given node in an expression graph
11043  *
11044  * Assembles mapping of variables from graph to tree.
11045  */
11046 static
11048  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11049  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which expression should be created */
11050  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
11051  int* nexprvars, /**< current number of variables in expression */
11052  int* varidx /**< current mapping of variable indices from graph to expression */
11053  )
11054 {
11055  SCIP_EXPR** childexprs;
11056  int i;
11057 
11058  assert(exprgraph != NULL);
11059  assert(node != NULL);
11060  assert(expr != NULL);
11061  assert(nexprvars != NULL);
11062  assert(*nexprvars >= 0);
11063  assert(varidx != NULL);
11064 
11065  childexprs = NULL;
11066  if( node->nchildren > 0 )
11067  {
11068  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11069  for( i = 0; i < node->nchildren; ++i )
11070  {
11071  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) ); /*lint !e613*/
11072  }
11073  }
11074 
11075  switch( node->op )
11076  {
11077  case SCIP_EXPR_VARIDX:
11078  {
11079  /* check if the variable already has an index assigned in the expression tree
11080  * if not, create one and increase nexprvars
11081  */
11082  assert(node->data.intval >= 0);
11083  assert(node->data.intval < exprgraph->nvars);
11084  assert(varidx[node->data.intval] >= -1);
11085  assert(varidx[node->data.intval] < *nexprvars);
11086  if( varidx[node->data.intval] == -1 )
11087  {
11088  varidx[node->data.intval] = *nexprvars;
11089  ++*nexprvars;
11090  }
11091 
11092  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11093  break;
11094  }
11095 
11096  case SCIP_EXPR_CONST:
11097  {
11098  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11099  break;
11100  }
11101 
11102  case SCIP_EXPR_REALPOWER:
11103  case SCIP_EXPR_SIGNPOWER:
11104  {
11105  assert(childexprs != NULL);
11106  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11107  break;
11108  }
11109 
11110  case SCIP_EXPR_INTPOWER:
11111  {
11112  assert(childexprs != NULL);
11113  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11114  break;
11115  }
11116 
11117  case SCIP_EXPR_PLUS:
11118  case SCIP_EXPR_MINUS:
11119  case SCIP_EXPR_MUL:
11120  case SCIP_EXPR_DIV:
11121  case SCIP_EXPR_MIN:
11122  case SCIP_EXPR_MAX:
11123  {
11124  assert(node->nchildren == 2);
11125  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11126  break;
11127  }
11128 
11129  case SCIP_EXPR_SQUARE:
11130  case SCIP_EXPR_SQRT:
11131  case SCIP_EXPR_EXP:
11132  case SCIP_EXPR_LOG:
11133  case SCIP_EXPR_SIN:
11134  case SCIP_EXPR_COS:
11135  case SCIP_EXPR_TAN:
11136  /* case SCIP_EXPR_ERF: */
11137  /* case SCIP_EXPR_ERFI: */
11138  case SCIP_EXPR_ABS:
11139  case SCIP_EXPR_SIGN:
11140  {
11141  assert(node->nchildren == 1);
11142  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11143  break;
11144  }
11145 
11146  case SCIP_EXPR_SUM:
11147  case SCIP_EXPR_PRODUCT:
11148  {
11149  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11150  break;
11151  }
11152 
11153  case SCIP_EXPR_LINEAR:
11154  {
11155  assert(node->data.data != NULL);
11156 
11157  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11158  break;
11159  }
11160 
11161  case SCIP_EXPR_QUADRATIC:
11162  {
11163  SCIP_EXPRDATA_QUADRATIC* quaddata;
11164 
11165  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11166  assert(quaddata != NULL);
11167 
11168  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11169  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11170  break;
11171  }
11172 
11173  case SCIP_EXPR_POLYNOMIAL:
11174  {
11175  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11176 
11177  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11178  assert(polynomialdata != NULL);
11179 
11180  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11181  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11182 
11183  break;
11184  }
11185 
11186  case SCIP_EXPR_LAST:
11187  case SCIP_EXPR_PARAM:
11188  default:
11189  {
11190  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11191  return SCIP_ERROR;
11192  }
11193  }
11194 
11195  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11196 
11197  return SCIP_OKAY;
11198 }
11199 
11200 /** counts how often expression graph variables are used in a subtree of the expression graph
11201  *
11202  * @note The function does not clear the array first, but only increases already existing counts.
11203  */
11204 static
11206  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11207  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11208  )
11209 {
11210  int i;
11211 
11212  assert(node != NULL);
11213  assert(varsusage != NULL);
11214 
11215  if( node->op == SCIP_EXPR_VARIDX )
11216  {
11217  ++varsusage[node->data.intval];
11218  return;
11219  }
11220 
11221  for( i = 0; i < node->nchildren; ++i )
11222  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
11223 }
11224 
11225 /** checks whether a node can be put into a component when checking block separability of an expression
11226  *
11227  * If a variable used by node is already in another component, components are merged and component number is updated.
11228  */
11229 static
11231  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
11232  int* compnr, /**< component number to assign, may be reduced if variables overlap */
11233  int nchildcomps, /**< number of entries for which childcomps have been set already */
11234  int* childcomps, /**< component numbers of children */
11235  int nvars, /**< number of variables */
11236  int* varcomps /**< component numbers of variables */
11237  )
11238 {
11239  int varidx;
11240  int i;
11241 
11242  assert(node != NULL);
11243  assert(compnr != NULL);
11244  assert(*compnr >= 0);
11245  assert(childcomps != NULL);
11246  assert(varcomps != NULL);
11247 
11248  if( node->op != SCIP_EXPR_VARIDX )
11249  {
11250  for( i = 0; i < node->nchildren; ++i )
11251  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
11252  return;
11253  }
11254 
11255  varidx = node->data.intval;
11256  assert(varidx >= 0);
11257  assert(varidx < nvars);
11258 
11259  if( varcomps[varidx] == -1 )
11260  {
11261  /* first time we get to this variable, so set it's component to compnr and we are done */
11262  varcomps[varidx] = *compnr;
11263  return;
11264  }
11265 
11266  if( varcomps[varidx] == *compnr )
11267  {
11268  /* variable is already in current component, that's also good and we are done */
11269  return;
11270  }
11271 
11272  /* variable is already in another component, so have to merge component compnr into that component
11273  * do this by updating varcomps and childcomps */
11274  for( i = 0; i < nvars; ++i )
11275  if( varcomps[i] == *compnr )
11276  varcomps[i] = varcomps[varidx];
11277  for( i = 0; i < nchildcomps; ++i )
11278  if( childcomps[i] == *compnr )
11279  childcomps[i] = varcomps[varidx];
11280  *compnr = varcomps[varidx];
11281 }
11282 
11283 /**@} */
11284 
11285 /**@name Expression graph private methods */
11286 /**@{ */
11287 
11288 /** assert that expression tree has at least a given depth */
11289 static
11291  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
11292  int mindepth /**< minimal depth that should be ensured */
11293  )
11294 {
11295  int olddepth;
11296 
11297  assert(exprgraph != NULL);
11298  assert(exprgraph->blkmem != NULL);
11299 
11300  if( mindepth <= exprgraph->depth )
11301  return SCIP_OKAY;
11302 
11303  olddepth = exprgraph->depth;
11304  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
11305  assert(exprgraph->depth >= mindepth);
11306 
11307  /* initialize new array entries to 0 and NULL, resp. */
11308  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11309  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11310  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11311 
11312  return SCIP_OKAY;
11313 }
11314 
11315 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
11316 static
11318  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11319  int varidx /**< variable index */
11320  )
11321 {
11322  SCIP_EXPRGRAPHNODE* varnode;
11323  void* var;
11324 
11325  assert(exprgraph != NULL);
11326  assert(varidx >= 0);
11327  assert(varidx < exprgraph->nvars);
11328 
11329  varnode = exprgraph->varnodes[varidx];
11330  assert(varnode->data.intval == varidx);
11331 
11332  var = exprgraph->vars[varidx];
11333 
11334  /* call varremove callback method, if set */
11335  if( exprgraph->exprgraphvarremove != NULL )
11336  {
11337  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
11338  }
11339 
11340  /* remove variable from hashmap */
11341  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
11342 
11343  /* move last variable to position varidx and give it the new index */
11344  if( varidx < exprgraph->nvars-1 )
11345  {
11346  /* call callback method, if set */
11347  if( exprgraph->exprgraphvarchgidx != NULL )
11348  {
11349  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
11350  }
11351 
11352  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
11353  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
11354  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
11355  exprgraph->varnodes[varidx]->data.intval = varidx;
11356  SCIP_CALL( SCIPhashmapSetImage(exprgraph->varidxs, exprgraph->vars[varidx], (void*)(size_t)(varidx)) );
11357  }
11358  --exprgraph->nvars;
11359 
11360  return SCIP_OKAY;
11361 }
11362 
11363 /** moves a node in an expression graph to a different depth
11364  *
11365  * New depth must be larger than children depth.
11366  * Moves parent nodes to higher depth, if needed.
11367  * Variable nodes cannot be moved.
11368  */
11369 static
11371  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11372  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
11373  int newdepth /**< new depth to which to move node */
11374  )
11375 {
11376  int olddepth;
11377  int oldpos;
11378  int i;
11379 
11380  assert(exprgraph != NULL);
11381  assert(node != NULL);
11382  assert(node->depth >= 0); /* node should be in graph */
11383  assert(newdepth >= 0);
11384 
11385  /* if already on aimed depth, then don't need to move */
11386  if( node->depth == newdepth )
11387  return SCIP_OKAY;
11388 
11389  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
11390 
11391 #ifndef NDEBUG
11392  /* assert that children are at lower depth than new depth */
11393  for( i = 0; i < node->nchildren; ++i )
11394  assert(node->children[i]->depth < newdepth);
11395 #endif
11396 
11397  /* move parents to higher depth, if needed */
11398  for( i = 0; i < node->nparents; ++i )
11399  {
11400  if( node->parents[i]->depth <= newdepth )
11401  {
11402  /* move parent to depth+1 */
11403  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
11404  assert(node->parents[i]->depth > newdepth);
11405  }
11406  }
11407 
11408  /* ensure that graph is deep enough */
11409  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
11410  assert(exprgraph->depth > newdepth);
11411 
11412  olddepth = node->depth;
11413  oldpos = node->pos;
11414 
11415  /* add node to new depth */
11416  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
11417  node->depth = newdepth;
11418  node->pos = exprgraph->nnodes[newdepth];
11419  exprgraph->nodes[newdepth][node->pos] = node;
11420  ++exprgraph->nnodes[newdepth];
11421 
11422  /* move last node at previous depth to previous position, if it wasn't last */
11423  if( oldpos < exprgraph->nnodes[olddepth]-1 )
11424  {
11425  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
11426  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
11427  }
11428  --exprgraph->nnodes[olddepth];
11429 
11430  if( node->depth == 0 )
11431  {
11432  /* if at depth 0, then it need to be a node for either a constant or a variable */
11433  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
11434  if( node->op == SCIP_EXPR_CONST )
11435  {
11436  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
11437  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
11438  exprgraph->constnodes[exprgraph->nconsts] = node;
11439  ++exprgraph->nconsts;
11440  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
11441  }
11442  else
11443  {
11444  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
11445  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
11446  return SCIP_ERROR;
11447  }
11448 
11449  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
11450  node->curv = SCIP_EXPRCURV_LINEAR;
11451  }
11452 
11453  return SCIP_OKAY;
11454 }
11455 
11456 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
11457 static
11459  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11460  int nchildren, /**< number of children */
11461  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
11462  SCIP_EXPROP op, /**< operator */
11463  SCIP_EXPROPDATA opdata, /**< operator data */
11464  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
11465  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
11466  )
11467 {
11468  SCIP_EXPRGRAPHNODE** parentcands;
11469  int nparentcands;
11470  int parentcandssize;
11471  int i;
11472  int p;
11473 
11474  assert(exprgraph != NULL);
11475  assert(nchildren > 0);
11476  assert(children != NULL);
11477  assert(parent != NULL);
11478 
11479  *parent = NULL;
11480 
11481  /* create initial set of parent candidates as
11482  * all parents of first child that have the same operator type and the same number of children
11483  * additionally, some easy conditions for complex expression types:
11484  * if expression type is int/real/signpower, then compare also exponent,
11485  * if expression type is linear, then compare also constant part,
11486  * if expression type is quadratic, then compare also number of quadratic elements,
11487  * if expression type is polynomial, then compare also number of monmials and constant part
11488  */
11489  parentcandssize = children[0]->nparents;
11490  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
11491  nparentcands = 0;
11492  for( p = 0; p < children[0]->nparents; ++p )
11493  if( children[0]->parents[p]->op == op &&
11494  children[0]->parents[p]->nchildren == nchildren &&
11495  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
11496  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
11497  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
11498  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
11499  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
11500  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
11501  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
11502  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
11503  )
11504  {
11505  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
11506  }
11507 
11508  /* for all remaining children, remove parent candidates, that are not in their list of parents */
11509  for( i = 1; i < nchildren && nparentcands > 0; ++i )
11510  {
11511  p = 0;
11512  while( p < nparentcands )
11513  {
11514  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
11515  * otherwise keep candidate and check next one
11516  */
11517  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
11518  {
11519  parentcands[p] = parentcands[nparentcands-1];
11520  --nparentcands;
11521  }
11522  else
11523  ++p;
11524  }
11525  }
11526 
11527  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
11528 
11529  if( nparentcands == 0 )
11530  {
11531  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
11532  return SCIP_OKAY;
11533  }
11534 
11535  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
11536  * check if there is also one which corresponds to same expression and store that one in *parent
11537  */
11538  switch( op )
11539  {
11540  /* commutative operands with no data */
11541  case SCIP_EXPR_PLUS :
11542  case SCIP_EXPR_MUL :
11543  case SCIP_EXPR_MIN :
11544  case SCIP_EXPR_MAX :
11545  case SCIP_EXPR_SUM :
11546  case SCIP_EXPR_PRODUCT:
11547  case SCIP_EXPR_SQUARE :
11548  case SCIP_EXPR_SQRT :
11549  case SCIP_EXPR_EXP :
11550  case SCIP_EXPR_LOG :
11551  case SCIP_EXPR_SIN :
11552  case SCIP_EXPR_COS :
11553  case SCIP_EXPR_TAN :
11554  /* case SCIP_EXPR_ERF : */
11555  /* case SCIP_EXPR_ERFI : */
11556  case SCIP_EXPR_ABS :
11557  case SCIP_EXPR_SIGN :
11558  {
11559  /* sort childnodes, if needed for later */
11560  if( nchildren > 2 )
11561  SCIPsortPtr((void**)children, ptrcomp, nchildren);
11562  for( p = 0; p < nparentcands; ++p )
11563  {
11564  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
11565  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
11566 
11567  if( nchildren == 1 )
11568  {
11569  assert(parentcands[p]->children[0] == children[0]);
11570  /* same operand, same child, so same expression */
11571  *parent = parentcands[p];
11572  break;
11573  }
11574  else if( nchildren == 2 )
11575  {
11576  /* We know that every node in children is also a child of parentcands[p].
11577  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
11578  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
11579  */
11580  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
11581  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
11582  {
11583  *parent = parentcands[p];
11584  break;
11585  }
11586  }
11587  else
11588  {
11589  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
11590 
11591  /* sort children of parent candidate */
11592  SCIPsortPtr((void**)parentcands[p]->children, ptrcomp, nchildren);
11593 
11594  /* check if childnodes and parentcands[p]->children are the same */
11595  for( i = 0; i < nchildren; ++i )
11596  if( children[i] != parentcands[p]->children[i] )
11597  break;
11598  if( i == nchildren )
11599  {
11600  /* yeah, found an exact match */
11601  *parent = parentcands[p];
11602  break;
11603  }
11604  }
11605  }
11606 
11607  break;
11608  }
11609 
11610  /* non-commutative operands with two children */
11611  case SCIP_EXPR_MINUS :
11612  case SCIP_EXPR_DIV :
11613  {
11614  for( p = 0; p < nparentcands; ++p )
11615  {
11616  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
11617  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
11618  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
11619  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
11620  {
11621  /* yeah, found one */
11622  *parent = parentcands[p];
11623  break;
11624  }
11625  }
11626 
11627  break;
11628  }
11629 
11630  /* operands with one child and data */
11631  case SCIP_EXPR_INTPOWER:
11632  {
11633  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
11634  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
11635  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
11636  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
11637 
11638  /* yeah, have one with same exponent */
11639  *parent = parentcands[0];
11640 
11641  break;
11642  }
11643 
11644  case SCIP_EXPR_REALPOWER:
11645  case SCIP_EXPR_SIGNPOWER:
11646  {
11647  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
11648  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
11649  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
11650  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
11651 
11652  /* yeah, have one with same exponent */
11653  *parent = parentcands[0];
11654 
11655  break;
11656  }
11657 
11658  /* commutative operands with n children and data */
11659  case SCIP_EXPR_LINEAR:
11660  {
11661  SCIP_Real* exprcoef;
11662  SCIP_Real* candcoef;
11663 
11664  exprcoef = (SCIP_Real*)opdata.data;
11665  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
11666  if( exprchildren != NULL )
11667  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, ptrcomp, nchildren);
11668  else
11669  SCIPsortPtrReal((void**)children, exprcoef, ptrcomp, nchildren);
11670  for( p = 0; p < nparentcands; ++p )
11671  {
11672  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
11673  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
11674 
11675  candcoef = (SCIP_Real*)parentcands[p]->data.data;
11676  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
11677 
11678  /* sort children of parent candidate */
11679  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, ptrcomp, nchildren);
11680 
11681  /* check if children and coefficients in parent candidate and expression are the same */
11682  for( i = 0; i < nchildren; ++i )
11683  {
11684  if( children[i] != parentcands[p]->children[i] )
11685  break;
11686  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
11687  break;
11688  }
11689  if( i < nchildren )
11690  continue;
11691 
11692  /* yeah, found an exact match */
11693  *parent = parentcands[p];
11694  break;
11695  }
11696 
11697  break;
11698  }
11699 
11700  case SCIP_EXPR_QUADRATIC:
11701  {
11702  SCIP_EXPRDATA_QUADRATIC* exprdata;
11703  SCIP_Real* exprlincoef;
11704  SCIP_Real* candlincoef;
11705  SCIP_EXPRDATA_QUADRATIC* canddata;
11706  int* perm;
11707  int* invperm;
11708 
11709  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
11710  exprlincoef = exprdata->lincoefs;
11711 
11712  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
11713 
11714  /* sort expr->children and childnodes and store inverse permutation in invperm */
11715  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
11716  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
11717  for( i = 0; i < nchildren; ++i )
11718  invperm[i] = i; /*lint !e644*/
11719 
11720  if( exprlincoef != NULL )
11721  if( exprchildren != NULL )
11722  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, ptrcomp, nchildren);
11723  else
11724  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, ptrcomp, nchildren);
11725  else
11726  if( exprchildren != NULL )
11727  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, ptrcomp, nchildren);
11728  else
11729  SCIPsortPtrInt((void**)children, invperm, ptrcomp, nchildren);
11730 
11731  /* compute permutation from its inverse */
11732  for( i = 0; i < nchildren; ++i )
11733  perm[invperm[i]] = i; /*lint !e644*/
11734 
11735  /* apply permuation to exprdata->quadelems and sort again */
11736  for( i = 0; i < exprdata->nquadelems; ++i )
11737  {
11738  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
11739  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
11740  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
11741  {
11742  int tmp;
11743  tmp = exprdata->quadelems[i].idx1;
11744  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
11745  exprdata->quadelems[i].idx2 = tmp;
11746  }
11747  }
11748  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
11749  exprdata->sorted = TRUE;
11750 
11751  for( p = 0; p < nparentcands; ++p )
11752  {
11753  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
11754  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
11755 
11756  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
11757  candlincoef = canddata->lincoefs;
11758  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
11759  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
11760 
11761  /* sort parentcands[p]->children and store inverse permutation in invperm */
11762  for( i = 0; i < nchildren; ++i )
11763  invperm[i] = i;
11764 
11765  if( candlincoef != NULL )
11766  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, ptrcomp, parentcands[p]->nchildren);
11767  else
11768  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, ptrcomp, nchildren);
11769 
11770  /* compute permutation from its inverse */
11771  for( i = 0; i < nchildren; ++i )
11772  perm[invperm[i]] = i;
11773 
11774  /* apply permutation to canddata->quadelems */
11775  for( i = 0; i < canddata->nquadelems; ++i )
11776  {
11777  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
11778  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
11779  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
11780  {
11781  int tmp;
11782  tmp = canddata->quadelems[i].idx1;
11783  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
11784  canddata->quadelems[i].idx2 = tmp;
11785  }
11786  }
11787  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
11788  canddata->sorted = TRUE;
11789 
11790  /* check if children and linear coefficients in parent candidate and expression are the same */
11791  for( i = 0; i < nchildren; ++i )
11792  {
11793  if( children[i] != parentcands[p]->children[i] )
11794  break;
11795  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
11796  break;
11797  }
11798  if( i < nchildren )
11799  continue;
11800 
11801  assert(exprdata->nquadelems == canddata->nquadelems);
11802  for( i = 0; i < exprdata->nquadelems; ++i )
11803  {
11804  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
11805  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
11806  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
11807  break;
11808  }
11809  if( i == exprdata->nquadelems )
11810  {
11811  /* yeah, parentcands[p] is same quadratic expression as expr */
11812  *parent = parentcands[p];
11813  break;
11814  }
11815  }
11816 
11817  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
11818  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
11819 
11820  break;
11821  }
11822 
11823  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
11824  case SCIP_EXPR_POLYNOMIAL:
11825  {
11826  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
11827  SCIP_EXPRDATA_POLYNOMIAL* canddata;
11828  int* perm;
11829  int* invperm;
11830 
11831  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
11832 
11833  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
11834 
11835  /* sort exprchildren and childnodes and store inverse permutation in invperm */
11836  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
11837  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
11838  for( i = 0; i < nchildren; ++i )
11839  invperm[i] = i; /*lint !e644*/
11840 
11841  if( exprchildren != NULL )
11842  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, ptrcomp, nchildren);
11843  else
11844  SCIPsortPtrInt((void**)children, invperm, ptrcomp, nchildren);
11845 
11846  /* compute permutation from its inverse */
11847  for( i = 0; i < nchildren; ++i )
11848  perm[invperm[i]] = i; /*lint !e644*/
11849 
11850  /* apply permutation to exprdata and sort again */
11851  polynomialdataApplyChildmap(exprdata, perm);
11852  polynomialdataSortMonomials(exprdata);
11853 
11854  for( p = 0; p < nparentcands; ++p )
11855  {
11856  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
11857  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
11858 
11859  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
11860  assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
11861  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
11862 
11863  /* sort parentcands[p]->children and store inverse permutation in invperm */
11864  for( i = 0; i < nchildren; ++i )
11865  invperm[i] = i;
11866 
11867  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, ptrcomp, nchildren);
11868 
11869  /* compute permutation from its inverse */
11870  for( i = 0; i < nchildren; ++i )
11871  perm[invperm[i]] = i;
11872 
11873  /* apply permutation to canddata and sort again */
11874  polynomialdataApplyChildmap(canddata, perm);
11875  polynomialdataSortMonomials(canddata);
11876 
11877  /* check if children are equal */
11878  for( i = 0; i < nchildren; ++i )
11879  if( children[i] != parentcands[p]->children[i] )
11880  break;
11881  if( i < nchildren )
11882  continue;
11883 
11884  /* check if monomials are equal */
11885  for( i = 0; i < exprdata->nmonomials; ++i )
11886  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
11887  break;
11888  if( i == exprdata->nmonomials )
11889  {
11890  /* yeah, parentcands[p] is same polynomial expression as expr */
11891  *parent = parentcands[p];
11892  break;
11893  }
11894  }
11895 
11896  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
11897  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
11898 
11899  break;
11900  }
11901 
11902  case SCIP_EXPR_VARIDX:
11903  case SCIP_EXPR_PARAM:
11904  case SCIP_EXPR_CONST:
11905  case SCIP_EXPR_LAST:
11906  default:
11907  SCIPerrorMessage("expression operand %d unexpected here\n", op);
11908  return SCIP_ERROR;
11909  }
11910 
11911  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
11912 
11913  return SCIP_OKAY;
11914 }
11915 
11916 /** adds an expression into an expression graph
11917  *
11918  * Enables corresponding nodes.
11919  */
11920 static
11922  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11923  SCIP_EXPR* expr, /**< expression to add */
11924  void** vars, /**< variables corresponding to VARIDX expressions */
11925  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
11926  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
11927  )
11928 {
11929  SCIP_EXPRGRAPHNODE** childnodes;
11930  SCIP_Bool childisnew;
11931  SCIP_Bool nochildisnew;
11932  SCIP_EXPROPDATA opdata;
11933  int i;
11934 
11935  assert(exprgraph != NULL);
11936  assert(expr != NULL);
11937  assert(exprnode != NULL);
11938  assert(exprnodeisnew != NULL);
11939 
11940  if( expr->op == SCIP_EXPR_VARIDX )
11941  {
11942  /* find node corresponding to variable and add if not existing yet */
11943  assert(expr->nchildren == 0);
11944 
11945  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
11946  assert(*exprnode != NULL);
11947  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
11948  assert((*exprnode)->data.intval >= 0);
11949  assert((*exprnode)->data.intval < exprgraph->nvars);
11950  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
11951 
11952  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
11953 
11954  return SCIP_OKAY;
11955  }
11956 
11957  if( expr->op == SCIP_EXPR_CONST )
11958  {
11959  /* find node corresponding to constant and add if not existing yet */
11960  assert(expr->nchildren == 0);
11961 
11962  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
11963  assert(*exprnode != NULL);
11964  assert((*exprnode)->op == SCIP_EXPR_CONST);
11965  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
11966 
11967  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
11968 
11969  return SCIP_OKAY;
11970  }
11971 
11972  /* expression should be variable or constant or have children, i.e., parameters are not allowed here (so far) */
11973  assert(expr->nchildren > 0);
11974 
11975  /* add children expressions into expression graph
11976  * check if we can find a common parent
11977  */
11978  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
11979  nochildisnew = TRUE;
11980  for( i = 0; i < expr->nchildren; ++i )
11981  {
11982  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, &childnodes[i], &childisnew) ); /*lint !e644*/
11983  assert(childnodes[i] != NULL);
11984  nochildisnew &= !childisnew; /*lint !e514*/
11985  }
11986 
11987  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
11988  if( nochildisnew )
11989  {
11990  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
11991 
11992  if( *exprnode != NULL )
11993  {
11994  /* node already existing, make sure it is enabled */
11995  (*exprnode)->enabled = TRUE;
11996  *exprnodeisnew = FALSE;
11997 
11998  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
11999  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12000  * SCIPdebugPrintf("\n");
12001  */
12002 
12003  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12004  return SCIP_OKAY;
12005  }
12006  }
12007 
12008  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12009 
12010  /* copy expression data */
12011  if( exprOpTable[expr->op].copydata != NULL )
12012  {
12013  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12014  }
12015  else
12016  {
12017  opdata = expr->data;
12018  }
12019 
12020  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12021  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12022  *exprnodeisnew = TRUE;
12023 
12024  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12025 
12026  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12027  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12028  * SCIPdebugPrintf("\n");
12029  */
12030 
12031  return SCIP_OKAY;
12032 }
12033 
12034 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12035 static
12037  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12038  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12039  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12040  )
12041 {
12042  SCIP_EXPRGRAPHNODE* node;
12043  int i;
12044  int p;
12045 
12046  assert(exprgraph != NULL);
12047  assert(clearreverseprop != NULL);
12048  assert(boundchanged != NULL);
12049 
12050  *boundchanged = FALSE;
12051  for( i = 0; i < exprgraph->nvars; ++i )
12052  {
12053  node = exprgraph->varnodes[i];
12054 
12055  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12056  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12057  {
12059  continue;
12060  }
12061 
12062  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12063  {
12064  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12065  SCIP_Real tmp;
12066 
12067  tmp = exprgraph->varbounds[i].inf;
12068  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12069  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12070  }
12071 
12072  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12073  +exprgraph->varbounds[i].sup > node->bounds.sup )
12074  {
12075  for( p = 0; p < node->nparents; ++p )
12077 
12078  node->bounds = exprgraph->varbounds[i];
12079  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12080 
12081  *boundchanged = TRUE;
12082 
12083  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12084  *clearreverseprop = TRUE;
12085  }
12086  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12087  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12088  {
12089  for( p = 0; p < node->nparents; ++p )
12091 
12092  node->bounds = exprgraph->varbounds[i];
12093  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12094 
12095  *boundchanged = TRUE;
12096  }
12097  else
12098  {
12099  node->bounds = exprgraph->varbounds[i];
12100  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12101  }
12102 
12104  }
12105 }
12106 
12107 /**@} */
12108 
12109 /**@name Expression graph node methods */
12110 /**@{ */
12111 
12112 /* In debug mode, the following methods are implemented as function calls to ensure
12113  * type validity.
12114  * In optimized mode, the methods are implemented as defines to improve performance.
12115  * However, we want to have them in the library anyways, so we have to undef the defines.
12116  */
12117 
12118 #undef SCIPexprgraphCaptureNode
12119 #undef SCIPexprgraphIsNodeEnabled
12120 #undef SCIPexprgraphGetNodeNChildren
12121 #undef SCIPexprgraphGetNodeChildren
12122 #undef SCIPexprgraphGetNodeNParents
12123 #undef SCIPexprgraphGetNodeParents
12124 #undef SCIPexprgraphGetNodeDepth
12125 #undef SCIPexprgraphGetNodePosition
12126 #undef SCIPexprgraphGetNodeOperator
12127 #undef SCIPexprgraphGetNodeOperatorIndex
12128 #undef SCIPexprgraphGetNodeOperatorReal
12129 #undef SCIPexprgraphGetNodeVar
12130 #undef SCIPexprgraphGetNodeRealPowerExponent
12131 #undef SCIPexprgraphGetNodeIntPowerExponent
12132 #undef SCIPexprgraphGetNodeSignPowerExponent
12133 #undef SCIPexprgraphGetNodeLinearCoefs
12134 #undef SCIPexprgraphGetNodeLinearConstant
12135 #undef SCIPexprgraphGetNodeQuadraticConstant
12136 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12137 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12138 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12139 #undef SCIPexprgraphGetNodePolynomialMonomials
12140 #undef SCIPexprgraphGetNodePolynomialNMonomials
12141 #undef SCIPexprgraphGetNodePolynomialConstant
12142 #undef SCIPexprgraphGetNodeBounds
12143 #undef SCIPexprgraphGetNodeVal
12144 #undef SCIPexprgraphGetNodeCurvature
12145 
12146 /** captures node, i.e., increases number of uses */
12148  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12149  )
12150 {
12151  assert(node->nuses >= 0);
12152 
12153  SCIPdebugMessage("capture node %p\n", (void*)node);
12154 
12155  ++node->nuses;
12156 }
12157 
12158 /** returns whether a node is currently enabled */
12160  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12161  )
12162 {
12163  assert(node != NULL);
12164 
12165  return node->enabled;
12166 }
12167 
12168 /** gets number of children of a node in an expression graph */
12170  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12171  )
12172 {
12173  assert(node != NULL);
12174 
12175  return node->nchildren;
12176 }
12177 
12178 /** gets children of a node in an expression graph */
12180  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12181  )
12182 {
12183  assert(node != NULL);
12184 
12185  return node->children;
12186 }
12187 
12188 /** gets number of parents of a node in an expression graph */
12190  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12191  )
12192 {
12193  assert(node != NULL);
12194 
12195  return node->nparents;
12196 }
12197 
12198 /** gets parents of a node in an expression graph */
12200  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12201  )
12202 {
12203  assert(node != NULL);
12204 
12205  return node->parents;
12206 }
12207 
12208 /** gets depth of node in expression graph */
12210  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12211  )
12212 {
12213  assert(node != NULL);
12214 
12215  return node->depth;
12216 }
12217 
12218 /** gets position of node in expression graph at its depth level */
12220  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12221  )
12222 {
12223  assert(node != NULL);
12224 
12225  return node->pos;
12226 }
12227 
12228 /** gets operator of a node in an expression graph */
12230  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12231  )
12232 {
12233  assert(node != NULL);
12234 
12235  return node->op;
12236 }
12237 
12238 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
12240  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12241  )
12242 {
12243  assert(node != NULL);
12244  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
12245 
12246  return node->data.intval;
12247 }
12248 
12249 /** gives real belonging to a SCIP_EXPR_CONST operand */
12251  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12252  )
12253 {
12254  assert(node != NULL);
12255  assert(node->op == SCIP_EXPR_CONST);
12256 
12257  return node->data.dbl;
12258 }
12259 
12260 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
12262  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12263  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12264  )
12265 {
12266  assert(exprgraph != NULL);
12267  assert(node != NULL);
12268  assert(node->op == SCIP_EXPR_VARIDX);
12269  assert(node->data.intval >= 0);
12270  assert(node->data.intval < exprgraph->nvars);
12271 
12272  return exprgraph->vars[node->data.intval];
12273 }
12274 
12275 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
12277  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12278  )
12279 {
12280  assert(node != NULL);
12281  assert(node->op == SCIP_EXPR_REALPOWER);
12282 
12283  return node->data.dbl;
12284 }
12285 
12286 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
12288  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12289  )
12290 {
12291  assert(node != NULL);
12292  assert(node->op == SCIP_EXPR_INTPOWER);
12293 
12294  return node->data.intval;
12295 }
12296 
12297 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
12299  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12300  )
12301 {
12302  assert(node != NULL);
12303  assert(node->op == SCIP_EXPR_SIGNPOWER);
12304 
12305  return node->data.dbl;
12306 }
12307 
12308 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
12310  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12311  )
12312 {
12313  assert(node != NULL);
12314  assert(node->op == SCIP_EXPR_LINEAR);
12315 
12316  return (SCIP_Real*)node->data.data;
12317 }
12318 
12319 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
12321  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12322  )
12323 {
12324  assert(node != NULL);
12325  assert(node->op == SCIP_EXPR_LINEAR);
12326  assert(node->data.data != NULL);
12327 
12328  return ((SCIP_Real*)node->data.data)[node->nchildren];
12329 }
12330 
12331 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
12333  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12334  )
12335 {
12336  assert(node != NULL);
12337  assert(node->op == SCIP_EXPR_QUADRATIC);
12338  assert(node->data.data != NULL);
12339 
12340  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
12341 }
12342 
12343 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
12345  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12346  )
12347 {
12348  assert(node != NULL);
12349  assert(node->op == SCIP_EXPR_QUADRATIC);
12350  assert(node->data.data != NULL);
12351 
12352  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
12353 }
12354 
12355 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
12357  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12358  )
12359 {
12360  assert(node != NULL);
12361  assert(node->op == SCIP_EXPR_QUADRATIC);
12362  assert(node->data.data != NULL);
12363 
12364  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
12365 }
12366 
12367 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
12369  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12370  )
12371 {
12372  assert(node != NULL);
12373  assert(node->op == SCIP_EXPR_QUADRATIC);
12374  assert(node->data.data != NULL);
12375 
12376  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
12377 }
12378 
12379 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
12381  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12382  )
12383 {
12384  assert(node != NULL);
12385  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12386  assert(node->data.data != NULL);
12387 
12388  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
12389 }
12390 
12391 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
12393  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12394  )
12395 {
12396  assert(node != NULL);
12397  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12398  assert(node->data.data != NULL);
12399 
12400  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
12401 }
12402 
12403 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
12405  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12406  )
12407 {
12408  assert(node != NULL);
12409  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12410  assert(node->data.data != NULL);
12411 
12412  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
12413 }
12414 
12415 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
12416  *
12417  * Assumes that curvature of children and bounds of children and node itself are valid.
12418  */
12420  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
12421  int monomialidx, /**< index of monomial */
12422  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
12423  )
12424 {
12425  SCIP_EXPRDATA_MONOMIAL* monomial;
12426  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
12427  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
12428  SCIP_INTERVAL* childbounds;
12429  SCIP_EXPRCURV* childcurv;
12430  SCIP_EXPRGRAPHNODE* child;
12431  int i;
12432 
12433  assert(node != NULL);
12434  assert(node->depth >= 0); /* node should be in graph */
12435  assert(node->pos >= 0); /* node should be in graph */
12436  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
12437  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
12438  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12439  assert(node->data.data != NULL);
12440  assert(monomialidx >= 0);
12441  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
12442  assert(curv != NULL);
12443 
12444  if( SCIPintervalIsEmpty(node->bounds) )
12445  {
12446  *curv = SCIP_EXPRCURV_LINEAR;
12447  return SCIP_OKAY;
12448  }
12449 
12450  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
12451  assert(monomial != NULL);
12452 
12453  /* if many children, get large enough memory to store children bounds */
12454  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
12455  {
12456  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
12457  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, monomial->nfactors) );
12458  }
12459  else
12460  {
12461  childbounds = childboundsstatic;
12462  childcurv = childcurvstatic;
12463  }
12464 
12465  /* assemble bounds and curvature of children */
12466  for( i = 0; i < monomial->nfactors; ++i )
12467  {
12468  child = node->children[monomial->childidxs[i]];
12469  assert(child != NULL);
12470 
12471  /* child should have valid and non-empty bounds */
12472  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
12473  assert(!SCIPintervalIsEmpty(child->bounds));
12474  /* nodes at depth 0 are always linear */
12475  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
12476 
12477  childbounds[i] = child->bounds; /*lint !e644*/
12478  childcurv[i] = child->curv; /*lint !e644*/
12479  }
12480 
12481  /* check curvature */
12482  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
12483  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
12484 
12485  /* free memory, if allocated before */
12486  if( childbounds != childboundsstatic )
12487  {
12488  BMSfreeMemoryArray(&childbounds);
12489  BMSfreeMemoryArray(&childcurv);
12490  }
12491 
12492  return SCIP_OKAY;
12493 }
12494 
12495 /** gets bounds of a node in an expression graph */
12497  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12498  )
12499 {
12500  assert(node != NULL);
12501 
12502  return node->bounds;
12503 }
12504 
12505 /** gets value of expression associated to node from last evaluation call */
12507  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12508  )
12509 {
12510  assert(node != NULL);
12511 
12512  return node->value;
12513 }
12514 
12515 /** gets curvature of expression associated to node from last curvature check call */
12517  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12518  )
12519 {
12520  assert(node != NULL);
12521 
12522  return node->curv;
12523 }
12524 
12525 /** creates an expression graph node */
12527  BMS_BLKMEM* blkmem, /**< block memory */
12528  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
12529  SCIP_EXPROP op, /**< operator type of expression */
12530  ...
12531  )
12532 {
12533  va_list ap;
12534  SCIP_EXPROPDATA opdata;
12535 
12536  assert(blkmem != NULL);
12537  assert(node != NULL);
12538 
12539  *node = NULL;
12540 
12541  switch( op )
12542  {
12543  case SCIP_EXPR_VARIDX :
12544  case SCIP_EXPR_PARAM :
12545  case SCIP_EXPR_CONST :
12546  case SCIP_EXPR_LINEAR :
12547  case SCIP_EXPR_QUADRATIC :
12548  case SCIP_EXPR_POLYNOMIAL:
12549  {
12550  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
12551  SCIPABORT();
12552  return SCIP_ERROR; /*lint !e527*/
12553  }
12554 
12555  /* operands without data */
12556  case SCIP_EXPR_PLUS :
12557  case SCIP_EXPR_MINUS :
12558  case SCIP_EXPR_MUL :
12559  case SCIP_EXPR_DIV :
12560  case SCIP_EXPR_MIN :
12561  case SCIP_EXPR_MAX :
12562  case SCIP_EXPR_SQUARE :
12563  case SCIP_EXPR_SQRT :
12564  case SCIP_EXPR_EXP :
12565  case SCIP_EXPR_LOG :
12566  case SCIP_EXPR_SIN :
12567  case SCIP_EXPR_COS :
12568  case SCIP_EXPR_TAN :
12569  /* case SCIP_EXPR_ERF : */
12570  /* case SCIP_EXPR_ERFI: */
12571  case SCIP_EXPR_ABS :
12572  case SCIP_EXPR_SIGN :
12573  case SCIP_EXPR_SUM :
12574  case SCIP_EXPR_PRODUCT:
12575  opdata.data = NULL;
12576  break;
12577 
12578  case SCIP_EXPR_REALPOWER:
12579  case SCIP_EXPR_SIGNPOWER:
12580  {
12581  va_start(ap, op ); /*lint !e826*/
12582  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
12583  va_end( ap ); /*lint !e826*/
12584 
12585  break;
12586  }
12587 
12588  case SCIP_EXPR_INTPOWER:
12589  {
12590  va_start(ap, op ); /*lint !e826*/
12591  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
12592  va_end( ap ); /*lint !e826*/
12593 
12594  break;
12595  }
12596 
12597  case SCIP_EXPR_LAST:
12598  default:
12599  SCIPerrorMessage("unknown operand: %d\n", op);
12600  return SCIP_INVALIDDATA;
12601  }
12602 
12603  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) );
12604 
12605  return SCIP_OKAY;
12606 }
12607 
12608 /** creates an expression graph node for a linear expression */
12610  BMS_BLKMEM* blkmem, /**< block memory */
12611  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
12612  int ncoefs, /**< number of coefficients */
12613  SCIP_Real* coefs, /**< coefficients of linear expression */
12614  SCIP_Real constant /**< constant of linear expression */
12615  )
12616 {
12617  SCIP_EXPROPDATA opdata;
12618  SCIP_Real* data;
12619 
12620  assert(blkmem != NULL);
12621  assert(node != NULL);
12622 
12623  /* we store the coefficients and the constant in a single array and make this our operand data */
12624  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
12625  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
12626  data[ncoefs] = constant;
12627 
12628  opdata.data = data;
12629  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
12630 
12631  return SCIP_OKAY;
12632 }
12633 
12634 /** creates an expression graph node for a quadratic expression */
12636  BMS_BLKMEM* blkmem, /**< block memory */
12637  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
12638  int nchildren, /**< number of children */
12639  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
12640  int nquadelems, /**< number of quadratic elements */
12641  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
12642  SCIP_Real constant /**< constant */
12643  )
12644 {
12645  SCIP_EXPROPDATA opdata;
12647 
12648  assert(blkmem != NULL);
12649  assert(node != NULL);
12650  assert(quadelems != NULL || nquadelems == 0);
12651 
12652  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
12653 
12654  opdata.data = data;
12655  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
12656 
12657  return SCIP_OKAY;
12658 }
12659 
12660 /** creates an expression graph node for a polynomial expression */
12662  BMS_BLKMEM* blkmem, /**< block memory */
12663  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
12664  int nmonomials, /**< number of monomials */
12665  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
12666  SCIP_Real constant, /**< constant of polynomial */
12667  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
12668  )
12669 {
12670  SCIP_EXPROPDATA opdata;
12672 
12673  assert(blkmem != NULL);
12674  assert(node != NULL);
12675  assert(monomials != NULL || nmonomials == 0);
12676 
12677  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
12678 
12679  opdata.data = data;
12680  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
12681 
12682  return SCIP_OKAY;
12683 }
12684 
12685 /** adds monomials to an expression graph node that is a polynomial expression */
12687  BMS_BLKMEM* blkmem, /**< block memory */
12688  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
12689  int nmonomials, /**< number of monomials */
12690  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
12691  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
12692  )
12693 {
12694  assert(blkmem != NULL);
12695  assert(node != NULL);
12697  assert(monomials != NULL || nmonomials == 0);
12698 
12699  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
12700 
12701  return SCIP_OKAY;
12702 }
12703 
12704 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
12705  *
12706  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
12707  * If the node is a linear expression, it may be freed.
12708  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
12709  * It is assumed that the user had captured the node.
12710  * It is assumed that the expression graph has been simplified before.
12711  */
12713  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12714  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
12715  int linvarssize, /**< length of linvars and lincoefs arrays */
12716  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
12717  void** linvars, /**< buffer to store variables of linear part */
12718  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
12719  SCIP_Real* constant /**< buffer to store constant part */
12720  )
12721 {
12722  int orignvars;
12723  int* varsusage;
12724  SCIP_EXPRGRAPHNODE* orignode;
12725  SCIP_Bool havechange;
12726  int i;
12727 
12728  assert(exprgraph != NULL);
12729  assert(node != NULL);
12730  assert(*node != NULL);
12731  assert((*node)->nuses > 0);
12732  assert(nlinvars != NULL);
12733  assert(linvars != NULL || linvarssize == 0);
12734  assert(lincoefs != NULL || linvarssize == 0);
12735  assert(constant != NULL);
12736 
12737  *constant = 0.0;
12738  *nlinvars = 0;
12739 
12740  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
12741 
12742  /* do some obvious and easy cases */
12743  switch( (*node)->op )
12744  {
12745  case SCIP_EXPR_VARIDX:
12746  {
12747  if( linvarssize >= 1 )
12748  {
12749  *nlinvars = 1;
12750  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
12751  lincoefs[0] = 1.0; /*lint !e613*/
12752 
12753  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12754  }
12755  return SCIP_OKAY;
12756  }
12757 
12758  case SCIP_EXPR_CONST:
12759  {
12760  *constant = (*node)->data.dbl;
12761  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12762 
12763  return SCIP_OKAY;
12764  }
12765 
12766  case SCIP_EXPR_REALPOWER:
12767  case SCIP_EXPR_SIGNPOWER:
12768  {
12769  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12770  {
12771  *nlinvars = 1;
12772  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12773  lincoefs[0] = 1.0; /*lint !e613*/
12774 
12775  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12776  }
12777  return SCIP_OKAY;
12778  }
12779 
12780  case SCIP_EXPR_INTPOWER:
12781  {
12782  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12783  {
12784  *nlinvars = 1;
12785  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12786  lincoefs[0] = 1.0; /*lint !e613*/
12787 
12788  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12789  }
12790  return SCIP_OKAY;
12791  }
12792 
12793  case SCIP_EXPR_PLUS:
12794  {
12795  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12796  {
12797  *constant = (*node)->children[0]->data.dbl;
12798  *nlinvars = 1;
12799  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
12800  lincoefs[0] = 1.0; /*lint !e613*/
12801 
12802  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12803 
12804  return SCIP_OKAY;
12805  }
12806  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12807  {
12808  *constant = (*node)->children[1]->data.dbl;
12809  *nlinvars = 1;
12810  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12811  lincoefs[0] = 1.0; /*lint !e613*/
12812 
12813  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12814 
12815  return SCIP_OKAY;
12816  }
12817  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
12818  {
12819  *nlinvars = 2;
12820  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12821  lincoefs[0] = 1.0; /*lint !e613*/
12822  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
12823  lincoefs[1] = 1.0; /*lint !e613*/
12824 
12825  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12826 
12827  return SCIP_OKAY;
12828  }
12829  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
12830  {
12831  /* handle this one later */
12832  break;
12833  }
12834  return SCIP_OKAY;
12835  }
12836 
12837  case SCIP_EXPR_MINUS:
12838  {
12839  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12840  {
12841  *constant = (*node)->children[0]->data.dbl;
12842  *nlinvars = 1;
12843  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
12844  lincoefs[0] = -1.0; /*lint !e613*/
12845 
12846  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12847 
12848  return SCIP_OKAY;
12849  }
12850  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12851  {
12852  *constant = -(*node)->children[1]->data.dbl;
12853  *nlinvars = 1;
12854  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12855  lincoefs[0] = 1.0; /*lint !e613*/
12856 
12857  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12858 
12859  return SCIP_OKAY;
12860  }
12861  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
12862  {
12863  *nlinvars = 2;
12864  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12865  lincoefs[0] = 1.0; /*lint !e613*/
12866  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
12867  lincoefs[1] = -1.0; /*lint !e613*/
12868 
12869  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12870 
12871  return SCIP_OKAY;
12872  }
12873  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
12874  {
12875  /* handle this one later */
12876  break;
12877  }
12878  return SCIP_OKAY;
12879  }
12880 
12881  case SCIP_EXPR_MUL:
12882  {
12883  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12884  {
12885  *nlinvars = 1;
12886  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
12887  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
12888 
12889  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12890  }
12891  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12892  {
12893  *nlinvars = 1;
12894  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12895  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
12896 
12897  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12898  }
12899  return SCIP_OKAY;
12900  }
12901 
12902  case SCIP_EXPR_DIV:
12903  {
12904  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
12905  return SCIP_OKAY;
12906 
12907  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
12908  {
12909  *nlinvars = 1;
12910  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
12911  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
12912 
12913  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
12914  }
12915  return SCIP_OKAY;
12916  }
12917 
12918  case SCIP_EXPR_SQUARE:
12919  case SCIP_EXPR_SQRT:
12920  case SCIP_EXPR_EXP:
12921  case SCIP_EXPR_LOG:
12922  case SCIP_EXPR_SIN:
12923  case SCIP_EXPR_COS:
12924  case SCIP_EXPR_TAN:
12925  /* case SCIP_EXPR_ERF: */
12926  /* case SCIP_EXPR_ERFI: */
12927  case SCIP_EXPR_ABS:
12928  case SCIP_EXPR_SIGN:
12929  case SCIP_EXPR_MIN:
12930  case SCIP_EXPR_MAX:
12931  return SCIP_OKAY;
12932 
12933  case SCIP_EXPR_PRODUCT:
12934  return SCIP_OKAY;
12935 
12936  case SCIP_EXPR_SUM:
12937  case SCIP_EXPR_LINEAR:
12938  case SCIP_EXPR_QUADRATIC:
12939  case SCIP_EXPR_POLYNOMIAL:
12940  default:
12941  {
12942  /* check if there is a child that is a variable */
12943  for( i = 0; i < (*node)->nchildren; ++i )
12944  {
12945  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
12946  break;
12947  }
12948 
12949  if( i == (*node)->nchildren )
12950  return SCIP_OKAY;
12951 
12952  break;
12953  }
12954  } /*lint !e788*/
12955 
12956  /* count how often variables are used in this expression */
12957  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
12958  orignvars = exprgraph->nvars;
12959  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
12960  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
12961 
12962  exprgraphNodeGetVarsUsage(*node, varsusage);
12963 
12964  /* duplicate node if it has parents or more than one user */
12965  orignode = NULL;
12966  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
12967  {
12968  SCIP_EXPROPDATA data;
12969 
12970  orignode = *node;
12971 
12972  if( exprOpTable[orignode->op].copydata != NULL )
12973  {
12974  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
12975  }
12976  else
12977  data = orignode->data;
12978 
12979  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
12980  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
12981  SCIPexprgraphCaptureNode(*node);
12982  }
12983 
12984  havechange = FALSE;
12985  /* split up constant and linear part */
12986  switch( (*node)->op )
12987  {
12988  case SCIP_EXPR_PLUS:
12989  case SCIP_EXPR_MINUS:
12990  {
12991  SCIP_EXPRGRAPHNODE* varchild;
12992  SCIP_EXPRGRAPHNODE* otherchild;
12993  int varidx;
12994 
12995  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
12996  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
12997  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
12998  assert(linvarssize >= 1);
12999 
13000  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13001  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13002  varidx = varchild->data.intval;
13003  /* if variable is used in other child (which should be nonlinear), we don't take it */
13004  if( varsusage[varidx] > 1 )
13005  break;
13006 
13007  /* add to linear variables */
13008  *nlinvars = 1;
13009  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13010  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13011  lincoefs[0] = -1.0; /*lint !e613*/
13012  else
13013  lincoefs[0] = 1.0; /*lint !e613*/
13014 
13015  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13016  {
13017  /* replace *node by otherchild */
13018  SCIPexprgraphCaptureNode(otherchild);
13019  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13020  *node = otherchild;
13021  }
13022  else
13023  {
13024  SCIP_Real* lindata;
13025 
13026  /* turn *node into linear expression -1.0 * otherchild */
13027 
13028  /* reduce to one child */
13029  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13030  (*node)->children[0] = otherchild;
13031  (*node)->nchildren = 1;
13032  (*node)->op = SCIP_EXPR_LINEAR;
13033 
13034  /* setup linear data -1.0 * child0 + 0.0 */
13035  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13036  lindata[0] = -1.0;
13037  lindata[1] = 0.0;
13038  (*node)->data.data = (void*)lindata;
13039 
13040  /* remove *node as parent of varchild */
13041  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13042  }
13043 
13044  havechange = TRUE;
13045 
13046  break;
13047  }
13048 
13049  case SCIP_EXPR_SUM:
13050  {
13051  int nchildren;
13052 
13053  i = 0;
13054  nchildren = (*node)->nchildren;
13055  while( i < nchildren )
13056  {
13057  /* sort out constants */
13058  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13059  {
13060  *constant += (*node)->children[i]->data.dbl;
13061  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13062 
13063  if( i < nchildren-1 )
13064  {
13065  (*node)->children[i] = (*node)->children[nchildren-1];
13066  (*node)->children[nchildren-1] = NULL;
13067  }
13068  --nchildren;
13069 
13070  continue;
13071  }
13072 
13073  /* keep every child that is not a constant or variable */
13074  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13075  {
13076  ++i;
13077  continue;
13078  }
13079 
13080  /* skip variables that are used in other parts of the expression */
13081  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13082  {
13083  ++i;
13084  continue;
13085  }
13086 
13087  /* move variable into linear part, if still space */
13088  if( *nlinvars < linvarssize )
13089  {
13090  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13091  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13092  ++*nlinvars;
13093 
13094  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13095  if( i < nchildren-1 )
13096  {
13097  (*node)->children[i] = (*node)->children[nchildren-1];
13098  (*node)->children[nchildren-1] = NULL;
13099  }
13100  --nchildren;
13101 
13102  continue;
13103  }
13104  }
13105  assert(i == nchildren);
13106 
13107  if( nchildren == 0 )
13108  {
13109  /* all children were removed */
13110  havechange = TRUE;
13111  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13112  (*node)->nchildren = 0;
13113  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13114  break;
13115  }
13116 
13117  if( nchildren < (*node)->nchildren )
13118  {
13119  /* some children were removed */
13120  havechange = TRUE;
13121  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13122  (*node)->nchildren = nchildren;
13123  }
13124 
13125  if( havechange && (*node)->nchildren == 1 )
13126  {
13127  /* replace node by its child */
13128  SCIP_EXPRGRAPHNODE* child;
13129 
13130  child = (*node)->children[0];
13131  SCIPexprgraphCaptureNode(child);
13132  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13133  *node = child;
13134 
13135  break;
13136  }
13137 
13138  break;
13139  }
13140 
13141  case SCIP_EXPR_LINEAR:
13142  {
13143  int nchildren;
13144  SCIP_Real* coefs;
13145 
13146  coefs = (SCIP_Real*)(*node)->data.data;
13147  assert(coefs != NULL);
13148 
13149  /* remove constant, if nonzero */
13150  if( coefs[(*node)->nchildren] != 0.0 )
13151  {
13152  *constant = coefs[(*node)->nchildren];
13153  coefs[(*node)->nchildren] = 0.0;
13154  havechange = TRUE;
13155  }
13156 
13157  i = 0;
13158  nchildren = (*node)->nchildren;
13159  while( i < nchildren )
13160  {
13161  /* sort out constants */
13162  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13163  {
13164  *constant += coefs[i] * (*node)->children[i]->data.dbl;
13165  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13166 
13167  if( i < nchildren-1 )
13168  {
13169  (*node)->children[i] = (*node)->children[nchildren-1];
13170  (*node)->children[nchildren-1] = NULL;
13171  coefs[i] = coefs[nchildren-1];
13172  coefs[nchildren-1] = 0.0;
13173  }
13174  --nchildren;
13175 
13176  continue;
13177  }
13178 
13179  /* keep everything that is not a constant or variable */
13180  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13181  {
13182  ++i;
13183  continue;
13184  }
13185 
13186  /* skip variables that are used in other parts of the expression */
13187  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13188  {
13189  ++i;
13190  continue;
13191  }
13192 
13193  /* move variable into linear part, if still space */
13194  if( *nlinvars < linvarssize )
13195  {
13196  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13197  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
13198  ++*nlinvars;
13199 
13200  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13201  if( i < nchildren-1 )
13202  {
13203  (*node)->children[i] = (*node)->children[nchildren-1];
13204  (*node)->children[nchildren-1] = NULL;
13205  coefs[i] = coefs[nchildren-1];
13206  coefs[nchildren-1] = 0.0;
13207  }
13208  --nchildren;
13209 
13210  continue;
13211  }
13212  }
13213  assert(i == nchildren);
13214 
13215  if( nchildren == 0 )
13216  {
13217  /* all children were removed */
13218  havechange = TRUE;
13219  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13220  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
13221  (*node)->data.data = NULL;
13222  (*node)->nchildren = 0;
13223  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
13224  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13225  break;
13226  }
13227 
13228  if( nchildren < (*node)->nchildren )
13229  {
13230  /* some children were removed */
13231  havechange = TRUE;
13232  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13233  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
13234  coefs[nchildren] = 0.0;
13235  (*node)->data.data = (void*)coefs;
13236  (*node)->nchildren = nchildren;
13237  }
13238 
13239  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
13240  {
13241  /* replace node by its child */
13242  SCIP_EXPRGRAPHNODE* child;
13243 
13244  child = (*node)->children[0];
13245  SCIPexprgraphCaptureNode(child);
13246  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13247  *node = child;
13248 
13249  break;
13250  }
13251 
13252  break;
13253  }
13254 
13255  case SCIP_EXPR_QUADRATIC:
13256  {
13257  SCIP_EXPRDATA_QUADRATIC* quaddata;
13258  SCIP_Bool* childused;
13259  int* childmap;
13260  int nchildren;
13261 
13262  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
13263  assert(quaddata != NULL);
13264 
13265  /* remove constant, if nonzero */
13266  if( quaddata->constant != 0.0 )
13267  {
13268  *constant = quaddata->constant;
13269  quaddata->constant = 0.0;
13270  havechange = TRUE;
13271  }
13272 
13273  /* if there is no linear part or no space left for linear variables, then stop */
13274  if( quaddata->lincoefs != NULL || linvarssize == 0 )
13275  break;
13276 
13277  /* check which childs are used in quadratic terms */
13278  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
13279  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
13280 
13281  for( i = 0; i < quaddata->nquadelems; ++i )
13282  {
13283  childused[quaddata->quadelems[i].idx1] = TRUE;
13284  childused[quaddata->quadelems[i].idx2] = TRUE;
13285  }
13286 
13287  /* alloc space for mapping of children indices */
13288  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
13289 
13290  nchildren = (*node)->nchildren;
13291  for( i = 0; i < nchildren; ++i )
13292  {
13293  childmap[i] = i; /*lint !e644*/
13294  if( *nlinvars >= linvarssize )
13295  continue;
13296  /* skip child if not variable or also used in quadratic part or other parts of expression */
13297  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13298  continue;
13299  if( childused[i] )
13300  continue;
13301  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13302  continue;
13303 
13304  /* put variable into linear part */
13305  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13306  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
13307  quaddata->lincoefs[i] = 0.0;
13308  ++*nlinvars;
13309 
13310  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13311 
13312  /* move last child to position i */
13313  if( i < nchildren-1 )
13314  {
13315  (*node)->children[i] = (*node)->children[nchildren-1];
13316  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
13317  childused[i] = childused[nchildren-1];
13318  childmap[nchildren-1] = i;
13319  }
13320  --nchildren;
13321  childmap[i] = -1;
13322 
13323  havechange = TRUE;
13324  --i; /* look at i again */
13325  }
13326 
13327  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
13328 
13329  if( nchildren < (*node)->nchildren )
13330  {
13331  /* apply childmap to quadratic term */
13332  for( i = 0; i < quaddata->nquadelems; ++i )
13333  {
13334  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
13335  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
13336  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
13337  {
13338  int tmp;
13339  tmp = quaddata->quadelems[i].idx1;
13340  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
13341  quaddata->quadelems[i].idx2 = tmp;
13342  }
13343  }
13344  quaddata->sorted = FALSE;
13345  }
13346  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
13347 
13348  if( nchildren == 0 )
13349  {
13350  /* all children were removed (so it was actually a linear expression) */
13351  havechange = TRUE;
13352  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13353  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
13354  (*node)->data.data = NULL;
13355  (*node)->nchildren = 0;
13356  (*node)->op = SCIP_EXPR_SUM;
13357  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13358  break;
13359  }
13360 
13361  if( nchildren < (*node)->nchildren )
13362  {
13363  /* reduce number of children */
13364  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13365  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
13366  (*node)->nchildren = nchildren;
13367  }
13368 
13369  break;
13370  }
13371 
13372  case SCIP_EXPR_POLYNOMIAL:
13373  {
13374  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
13375  SCIP_EXPRDATA_MONOMIAL* monomial;
13376  SCIP_Bool* childused;
13377  int childidx;
13378  int j;
13379 
13380  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
13381  assert(polynomialdata != NULL);
13382 
13383  /* make sure linear monomials are merged */
13384  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
13385 
13386  /* remove constant, if nonzero */
13387  if( polynomialdata->constant != 0.0 )
13388  {
13389  *constant = polynomialdata->constant;
13390  polynomialdata->constant = 0.0;
13391  havechange = TRUE;
13392  }
13393 
13394  /* if there is no space for linear variables, then stop */
13395  if( linvarssize == 0 )
13396  break;
13397 
13398  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
13399  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
13400  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
13401  for( i = 0; i < polynomialdata->nmonomials; ++i )
13402  {
13403  monomial = polynomialdata->monomials[i];
13404  assert(monomial != NULL);
13405  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
13406  continue;
13407  for( j = 0; j < monomial->nfactors; ++j )
13408  {
13409  assert(monomial->childidxs[j] >= 0);
13410  assert(monomial->childidxs[j] < (*node)->nchildren);
13411  childused[monomial->childidxs[j]] = TRUE;
13412  }
13413  }
13414 
13415  /* move linear monomials out of polynomial */
13416  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
13417  {
13418  monomial = polynomialdata->monomials[i];
13419  assert(monomial != NULL);
13420 
13421  /* sort out constants */
13422  if( monomial->nfactors == 0 )
13423  {
13424  if( monomial->coef != 0.0 )
13425  {
13426  *constant += monomial->coef;
13427  havechange = TRUE;
13428  }
13429  continue;
13430  }
13431 
13432  if( monomial->nfactors != 1 )
13433  continue;
13434  if( monomial->exponents[0] != 1.0 )
13435  continue;
13436  childidx = monomial->childidxs[0];
13437  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
13438  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
13439  continue;
13440  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
13441  continue;
13442 
13443  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
13444 
13445  /* put variable into linear part */
13446  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
13447  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
13448  ++*nlinvars;
13449 
13450  monomial->coef = 0.0;
13451  monomial->nfactors = 0;
13452  polynomialdata->sorted = FALSE;
13453 
13454  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
13455  (*node)->children[childidx] = NULL;
13456 
13457  havechange = TRUE;
13458  }
13459 
13460  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
13461 
13462  if( *nlinvars > 0 )
13463  {
13464  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
13465  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
13467  }
13468 
13469  if( (*node)->nchildren == 0 )
13470  {
13471  assert(polynomialdata->nmonomials == 0);
13472  assert(polynomialdata->constant == 0.0);
13473  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13474  havechange = TRUE;
13475  break;
13476  }
13477 
13478  break;
13479  }
13480 
13481  default: ;
13482  } /*lint !e788*/
13483 
13484  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
13485 
13486  if( orignode != NULL )
13487  {
13488  /* if node was duplicated, we need to forget about original or duplicate */
13489  if( !havechange )
13490  {
13491  /* if nothing has changed, then forget about duplicate */
13492  assert(*constant == 0.0);
13493  assert(*nlinvars == 0);
13494  assert(*node != NULL);
13495  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13496  *node = orignode;
13497  }
13498  else
13499  {
13500  /* if something changed, then release original node */
13501  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
13502  }
13503  }
13504  else if( havechange && *node != NULL )
13505  {
13506  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
13507  (*node)->value = SCIP_INVALID;
13508  (*node)->simplified = FALSE;
13509  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
13510  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
13511  exprgraph->needvarboundprop = TRUE;
13512  }
13513 
13514  return SCIP_OKAY;
13515 }
13516 
13517 /** moves parents from a one node to another node
13518  *
13519  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
13520  * srcnode may be freed, if not captured.
13521  * It is assumed that targetnode represents the same expression as srcnode.
13522  */
13524  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13525  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
13526  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
13527  )
13528 {
13529  assert(exprgraph != NULL);
13530  assert(srcnode != NULL);
13531  assert(*srcnode != NULL);
13532  assert(targetnode != NULL);
13533 
13534  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
13535  {
13536  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
13537  {
13538  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
13539  }
13540  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
13541  }
13542  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
13543 
13544  return SCIP_OKAY;
13545 }
13546 
13547 /** releases node, i.e., decreases number of uses
13548  *
13549  * node is freed if no parents and no other uses.
13550  * Children are recursively released if they have no other parents.
13551  * Nodes that are removed are also freed.
13552  * If node correspond to a variable, then the variable is removed from the expression graph;
13553  * similarly for constants.
13554  */
13556  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13557  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
13558  )
13559 {
13560  int i;
13561 
13562  assert(exprgraph != NULL);
13563  assert(node != NULL);
13564  assert(*node != NULL);
13565  assert((*node)->depth >= 0); /* node should be in graph */
13566  assert((*node)->pos >= 0); /* node should be in graph */
13567  assert((*node)->depth < exprgraph->depth);
13568  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
13569  assert((*node)->nuses >= 1);
13570  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
13571 
13572  SCIPdebugMessage("release node %p\n", (void*)*node);
13573 
13574  --(*node)->nuses;
13575 
13576  /* do nothing if node still has parents or is still in use */
13577  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
13578  {
13579  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);
13580  *node = NULL;
13581  return SCIP_OKAY;
13582  }
13583 
13584  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
13585 
13586  /* notify children about removal of its parent
13587  * they are also freed, if possible */
13588  for( i = 0; i < (*node)->nchildren; ++i )
13589  {
13590  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13591  (*node)->children[i] = NULL;
13592  }
13593 
13594  if( (*node)->op == SCIP_EXPR_VARIDX )
13595  {
13596  assert((*node)->depth == 0);
13597  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
13598  }
13599  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
13600  {
13601  int constidx;
13602 
13603  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
13604  assert(constidx >= 0);
13605  assert(constidx < exprgraph->nconsts);
13606  assert(exprgraph->constnodes[constidx] == *node);
13607 
13608  /* move last constant to position constidx */
13609  if( constidx < exprgraph->nconsts-1 )
13610  {
13611  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
13612  exprgraph->constssorted = (exprgraph->nconsts <= 2);
13613  }
13614  --exprgraph->nconsts;
13615  }
13616  else
13617  {
13618  /* only variables and constants are allowed at depth 0 */
13619  assert((*node)->depth > 0);
13620  }
13621 
13622  /* remove node from nodes array in expression graph */
13623  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
13624  {
13625  /* move last node at depth of *node to position of *node */
13626  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
13627  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
13628  }
13629  --exprgraph->nnodes[(*node)->depth];
13630 
13631  /* node is now not in graph anymore */
13632  (*node)->depth = -1;
13633  (*node)->pos = -1;
13634 
13635  /* free node */
13636  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
13637 
13638  *node = NULL;
13639 
13640  return SCIP_OKAY;
13641 }
13642 
13643 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
13644 /** frees a node of an expression graph */
13646  BMS_BLKMEM* blkmem, /**< block memory */
13647  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
13648  )
13649 {
13650  assert(blkmem != NULL);
13651  assert( node != NULL);
13652  assert(*node != NULL);
13653  assert((*node)->depth == -1); /* node should not be in graph anymore */
13654  assert((*node)->pos == -1); /* node should not be in graph anymore */
13655  assert((*node)->nuses == 0); /* node should not be in use */
13656 
13657  /* free operator data, if needed */
13658  if( exprOpTable[(*node)->op].freedata != NULL )
13659  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
13660 
13661  /* free arrays of children and parent nodes */
13662  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
13663  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
13664 
13665  /* free node struct */
13666  BMSfreeBlockMemory(blkmem, node);
13667 }
13668 
13669 /** enables a node and recursively all its children in an expression graph */
13671  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13672  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
13673  )
13674 {
13675  int i;
13676 
13677  assert(exprgraph != NULL);
13678  assert(node != NULL);
13679  assert(node->depth >= 0);
13680  assert(node->pos >= 0);
13681 
13682  if( node->enabled )
13683  return;
13684 
13685  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
13686 
13687  node->enabled = TRUE;
13688  for( i = 0; i < node->nchildren; ++i )
13689  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
13690 
13691  /* make sure bounds are updated in next bound propagation round */
13693  exprgraph->needvarboundprop = TRUE;
13694 }
13695 
13696 /** disables a node and recursively all children which have no enabled parents in an expression graph */
13698  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13699  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
13700  )
13701 {
13702  int i;
13703 
13704  assert(exprgraph != NULL);
13705  assert(node != NULL);
13706  assert(node->depth >= 0);
13707  assert(node->pos >= 0);
13708 
13709  if( !node->enabled )
13710  return;
13711 
13712  /* if all parents of node are disabled, then also node can be disabled */
13713  node->enabled = FALSE;
13714  for( i = 0; i < node->nparents; ++i )
13715  if( node->parents[i]->enabled )
13716  {
13717  node->enabled = TRUE;
13718  return;
13719  }
13720 
13721  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
13722 
13723  for( i = 0; i < node->nchildren; ++i )
13724  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
13725 }
13726 
13727 /** returns whether the node has siblings in the expression graph */
13729  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13730  )
13731 {
13732  int p;
13733 
13734  assert(node != NULL);
13735 
13736  for( p = 0; p < node->nparents; ++p )
13737  if( node->parents[p]->nchildren > 1 )
13738  return TRUE;
13739 
13740  return FALSE;
13741 }
13742 
13743 /** returns whether all children of an expression graph node are variable nodes
13744  *
13745  * Returns TRUE for nodes without children.
13746  */
13748  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13749  )
13750 {
13751  int i;
13752 
13753  assert(node != NULL);
13754 
13755  for( i = 0; i < node->nchildren; ++i )
13756  if( node->children[i]->op != SCIP_EXPR_VARIDX )
13757  return FALSE;
13758 
13759  return TRUE;
13760 }
13761 
13762 /** returns whether the node has an ancestor which has a nonlinear expression operand */
13764  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13765  )
13766 {
13767  int p;
13768 
13769  for( p = 0; p < node->nparents; ++p )
13770  {
13771  assert(node->parents[p]->depth > node->depth);
13772  switch( node->parents[p]->op )
13773  {
13774  case SCIP_EXPR_PLUS:
13775  case SCIP_EXPR_MINUS:
13776  case SCIP_EXPR_SUM:
13777  case SCIP_EXPR_LINEAR:
13779  return TRUE;
13780  break;
13781 
13782 #ifndef NDEBUG
13783  case SCIP_EXPR_VARIDX:
13784  case SCIP_EXPR_CONST:
13785  case SCIP_EXPR_PARAM:
13786  assert(0); /* these expressions cannot have children */
13787  break;
13788 #endif
13789 
13790  default:
13791  /* parent has nonlinear expression operand */
13792  return TRUE;
13793  }/*lint !e788*/
13794  }
13795 
13796  return FALSE;
13797 }
13798 
13799 /** prints an expression graph node */
13801  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13802  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
13803  FILE* file /**< file to print to, or NULL for stdout */
13804  )
13805 {
13806  assert(node != NULL);
13807 
13808  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
13809 }
13810 
13811 /** tightens the bounds in a node of the graph
13812  *
13813  * Preparation for reverse propagation.
13814  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
13815  */
13817  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13818  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
13819  SCIP_INTERVAL nodebounds, /**< new bounds for node */
13820  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) */
13821  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
13822  )
13823 {
13824  assert(exprgraph != NULL);
13825  assert(node != NULL);
13826  assert(node->depth >= 0);
13827  assert(node->pos >= 0);
13828  assert(!SCIPintervalIsEmpty(nodebounds));
13829  assert(cutoff != NULL);
13830 
13831  *cutoff = FALSE;
13832 
13833  /* if node is disabled, then ignore new bounds */
13834  if( !node->enabled )
13835  {
13836  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
13837  return;
13838  }
13839 
13840  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
13841  (void*)node, node->depth, node->pos,
13842  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
13843 
13844  /* bounds in node should be valid */
13846 
13847  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
13848  {
13849  *cutoff = TRUE;
13850  SCIPdebugPrintf(" -> cutoff\n");
13851  return;
13852  }
13853 
13854  /* if minstrength is negative, always mark that node has recently tightened bounds,
13855  * if bounds are considerably improved or tightening leads to an empty interval,
13856  * mark that node has recently tightened bounds
13857  * if bounds are only slightly improved, set the status to tightened by parent,
13858  * so next propagateVarBound round will reset the bounds
13859  */
13860  if( minstrength < 0.0 )
13862  else if(
13863  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
13864  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
13866  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
13868 
13869  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
13870  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
13871 }
13872 
13873 /** ensures that bounds and curvature information in a node is uptodate
13874  *
13875  * Assumes that bounds and curvature in children are uptodate.
13876  */
13878  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13879  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
13880  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
13881  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
13882  )
13883 {
13884  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13885  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13886  SCIP_INTERVAL* childbounds;
13887  SCIP_EXPRCURV* childcurv;
13888  int i;
13889 
13890  assert(node != NULL);
13891  assert(node->depth >= 0); /* node should be in graph */
13892  assert(node->pos >= 0); /* node should be in graph */
13893  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13894 
13895  if( node->depth == 0 )
13896  {
13897  /* we cannot update bound tightenings in variable nodes here */
13898  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
13899  return SCIP_OKAY;
13900  }
13901 
13902  assert(node->op != SCIP_EXPR_VARIDX);
13903  assert(node->op != SCIP_EXPR_PARAM);
13904 
13905  /* if many children, get large enough memory to store children bounds */
13907  {
13908  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
13909  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, node->nchildren) );
13910  }
13911  else
13912  {
13913  childbounds = childboundsstatic;
13914  childcurv = childcurvstatic;
13915  }
13916 
13917  /* assemble bounds and curvature of children */
13918  for( i = 0; i < node->nchildren; ++i )
13919  {
13920  /* child should have valid and non-empty bounds */
13922  assert(!SCIPintervalIsEmpty(node->children[i]->bounds));
13923  /* nodes at depth 0 are always linear */
13924  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
13925 
13926  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
13927  childcurv[i] = node->children[i]->curv; /*lint !e644*/
13928  }
13929 
13930  /* if we do not have valid bounds, then update
13931  * code below is copied from exprgraphNodeUpdateBounds */
13933  {
13934  SCIP_INTERVAL newbounds;
13935 
13936  /* calling interval evaluation function for this operand */
13937  assert( exprOpTable[node->op].inteval != NULL );
13938  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
13939 
13940  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
13941  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
13942  *
13943  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
13944  *
13945  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
13946  */
13947  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
13949  {
13950  for( i = 0; i < node->nparents; ++i )
13952 
13953  node->bounds = newbounds;
13954  }
13955  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
13956  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
13957  {
13958  for( i = 0; i < node->nparents; ++i )
13960 
13961  node->bounds = newbounds;
13962  }
13963  else
13964  {
13965  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
13966  }
13967 
13968  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);
13969 
13970  /* node now has valid bounds */
13972  }
13973 
13974  /* update curvature */
13975  if( SCIPintervalIsEmpty(node->bounds) )
13976  {
13977  node->curv = SCIP_EXPRCURV_LINEAR;
13978 
13979  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
13980  }
13981  else
13982  {
13983  SCIP_CALL( exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv) );
13984 
13985  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
13986  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
13987  * SCIPdebugPrintf("\n");
13988  */
13989  }
13990 
13991  /* free memory, if allocated before */
13992  if( childbounds != childboundsstatic )
13993  {
13994  BMSfreeMemoryArray(&childbounds);
13995  BMSfreeMemoryArray(&childcurv);
13996  }
13997 
13998  return SCIP_OKAY;
13999 }
14000 
14001 /**@} */
14002 
14003 /**@name Expression graph methods */
14004 /**@{ */
14005 
14006 /* In debug mode, the following methods are implemented as function calls to ensure
14007  * type validity.
14008  * In optimized mode, the methods are implemented as defines to improve performance.
14009  * However, we want to have them in the library anyways, so we have to undef the defines.
14010  */
14011 
14012 #undef SCIPexprgraphGetDepth
14013 #undef SCIPexprgraphGetNNodes
14014 #undef SCIPexprgraphGetNodes
14015 #undef SCIPexprgraphGetNVars
14016 #undef SCIPexprgraphGetVars
14017 #undef SCIPexprgraphGetVarNodes
14018 #undef SCIPexprgraphSetVarNodeValue
14019 #undef SCIPexprgraphSetVarsBounds
14020 #undef SCIPexprgraphSetVarBounds
14021 #undef SCIPexprgraphSetVarNodeBounds
14022 #undef SCIPexprgraphSetVarNodeLb
14023 #undef SCIPexprgraphSetVarNodeUb
14024 #undef SCIPexprgraphGetVarsBounds
14025 
14026 /** get current maximal depth of expression graph */
14028  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14029  )
14030 {
14031  assert(exprgraph != NULL);
14032 
14033  return exprgraph->depth;
14034 }
14035 
14036 /** gets array with number of nodes at each depth of expression graph */
14038  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14039  )
14040 {
14041  assert(exprgraph != NULL);
14042 
14043  return exprgraph->nnodes;
14044 }
14045 
14046 /** gets nodes of expression graph, one array per depth */
14048  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14049  )
14050 {
14051  assert(exprgraph != NULL);
14052 
14053  return exprgraph->nodes;
14054 }
14055 
14056 /** gets number of variables in expression graph */
14058  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14059  )
14060 {
14061  assert(exprgraph != NULL);
14062 
14063  return exprgraph->nvars;
14064 }
14065 
14066 /** gets array of variables in expression graph */
14068  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14069  )
14070 {
14071  assert(exprgraph != NULL);
14072 
14073  return exprgraph->vars;
14074 }
14075 
14076 /** gets array of expression graph nodes corresponding to variables */
14078  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14079  )
14080 {
14081  assert(exprgraph != NULL);
14082 
14083  return exprgraph->varnodes;
14084 }
14085 
14086 /** sets value for a single variable given as expression graph node */
14088  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14089  SCIP_Real value /**< new value for variable */
14090  )
14091 {
14092  assert(varnode != NULL);
14093  assert(varnode->op == SCIP_EXPR_VARIDX);
14094 
14095  varnode->value = value;
14096 }
14097 
14098 /** sets bounds for variables */
14100  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14101  SCIP_INTERVAL* varbounds /**< new bounds for variables */
14102  )
14103 {
14104  assert(exprgraph != NULL);
14105  assert(varbounds != NULL || exprgraph->nvars == 0);
14106 
14107  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
14108 }
14109 
14110 /** sets bounds for a single variable */
14112  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14113  void* var, /**< variable */
14114  SCIP_INTERVAL varbounds /**< new bounds of variable */
14115  )
14116 {
14117  int pos;
14118 
14119  assert(exprgraph != NULL);
14120  assert(var != NULL);
14121  assert(SCIPhashmapExists(exprgraph->varidxs, var));
14122 
14123  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
14124  assert(pos < exprgraph->nvars);
14125  assert(exprgraph->vars[pos] == var);
14126 
14127  exprgraph->varbounds[pos] = varbounds;
14128 }
14129 
14130 /** sets bounds for a single variable given as expression graph node */
14132  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14133  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14134  SCIP_INTERVAL varbounds /**< new bounds of variable */
14135  )
14136 {
14137  int pos;
14138 
14139  assert(exprgraph != NULL);
14140  assert(varnode != NULL);
14141 
14142  pos = varnode->data.intval;
14143  assert(pos >= 0);
14144  assert(pos < exprgraph->nvars);
14145  assert(exprgraph->varnodes[pos] == varnode);
14146 
14147  exprgraph->varbounds[pos] = varbounds;
14148 }
14149 
14150 /** sets lower bound for a single variable given as expression graph node */
14152  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14153  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14154  SCIP_Real lb /**< new lower bound for variable */
14155  )
14156 {
14157  int pos;
14158 
14159  assert(exprgraph != NULL);
14160  assert(varnode != NULL);
14161 
14162  pos = varnode->data.intval;
14163  assert(pos >= 0);
14164  assert(pos < exprgraph->nvars);
14165  assert(exprgraph->varnodes[pos] == varnode);
14166 
14167  exprgraph->varbounds[pos].inf = lb;
14168 }
14169 
14170 /** sets upper bound for a single variable given as expression graph node */
14172  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14173  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14174  SCIP_Real ub /**< new upper bound for variable */
14175  )
14176 {
14177  int pos;
14178 
14179  assert(exprgraph != NULL);
14180  assert(varnode != NULL);
14181 
14182  pos = varnode->data.intval;
14183  assert(pos >= 0);
14184  assert(pos < exprgraph->nvars);
14185  assert(exprgraph->varnodes[pos] == varnode);
14186 
14187  exprgraph->varbounds[pos].sup = ub;
14188 }
14189 
14190 /** gets bounds that are stored for all variables */
14192  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14193  )
14194 {
14195  return exprgraph->varbounds;
14196 }
14197 
14198 /** creates an empty expression graph */
14200  BMS_BLKMEM* blkmem, /**< block memory */
14201  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
14202  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
14203  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
14204  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /** callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
14205  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /** callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
14206  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /** callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
14207  void* userdata /**< user data to pass to callback functions */
14208  )
14209 {
14210  assert(blkmem != NULL);
14211  assert(exprgraph != NULL);
14212 
14213  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
14214  BMSclearMemory(*exprgraph);
14215  (*exprgraph)->blkmem = blkmem;
14216 
14217  /* create nodes's arrays */
14218  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
14219  assert((*exprgraph)->depth >= 1);
14220 
14221  /* create var's arrays and hashmap */
14222  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
14223  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, SCIPcalcHashtableSize(5 * (*exprgraph)->varssize)) );
14224 
14225  /* empty array of constants is sorted */
14226  (*exprgraph)->constssorted = TRUE;
14227 
14228  /* store callback functions and user data */
14229  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
14230  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
14231  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
14232  (*exprgraph)->userdata = userdata;
14233 
14234  return SCIP_OKAY;
14235 }
14236 
14237 /** frees an expression graph */
14239  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
14240  )
14241 {
14242  BMS_BLKMEM* blkmem;
14243  int d;
14244 
14245  assert( exprgraph != NULL);
14246  assert(*exprgraph != NULL);
14247  assert((*exprgraph)->nvars == 0);
14248  assert((*exprgraph)->nconsts == 0);
14249 
14250  blkmem = (*exprgraph)->blkmem;
14251  assert(blkmem != NULL);
14252 
14253  /* free nodes arrays */
14254  for( d = 0; d < (*exprgraph)->depth; ++d )
14255  {
14256  assert((*exprgraph)->nnodes[d] == 0);
14257  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
14258  }
14259  assert((*exprgraph)->nodes != NULL);
14260  assert((*exprgraph)->nnodes != NULL);
14261  assert((*exprgraph)->nodessize != NULL);
14262  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
14263  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
14264  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
14265 
14266  /* free variables arrays and hashmap */
14267  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
14268  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
14269  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
14270  SCIPhashmapFree(&(*exprgraph)->varidxs);
14271 
14272  /* free constants array */
14273  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
14274 
14275  /* free graph struct */
14276  BMSfreeBlockMemory(blkmem, exprgraph);
14277 
14278  return SCIP_OKAY;
14279 }
14280 
14281 /** adds an expression graph node to an expression graph
14282  *
14283  * Expression graph assumes ownership of node.
14284  * Children are notified about new parent.
14285  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
14286  */
14288  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14289  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
14290  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
14291  int nchildren, /**< number of children */
14292  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
14293  )
14294 {
14295  SCIP_Bool childvalsvalid;
14296  int depth;
14297  int i;
14298 
14299  assert(exprgraph != NULL);
14300  assert(node != NULL);
14301  assert(node->pos < 0); /* node should have no position in graph yet */
14302  assert(node->depth < 0); /* node should have no position in graph yet */
14303  assert(node->nchildren == 0); /* node should not have stored children yet */
14304  assert(node->children == NULL); /* node should not have stored children yet */
14305  assert(node->nparents == 0); /* node should not have parents stored yet */
14306  assert(children != NULL || nchildren == 0);
14307 
14308  /* choose depth as maximal depth of children + 1, and at least mindepth */
14309  depth = MAX(0, mindepth);
14310  for( i = 0; i < nchildren; ++i )
14311  {
14312  if( children[i]->depth >= depth ) /*lint !e613*/
14313  depth = children[i]->depth + 1; /*lint !e613*/
14314  }
14315 
14316  /* ensure that expression graph is deep enough */
14317  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
14318  assert(exprgraph->depth > depth);
14319 
14320  /* ensure enough space for nodes at depth depth */
14321  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
14322 
14323  /* add node to graph */
14324  node->depth = depth;
14325  node->pos = exprgraph->nnodes[depth];
14326  exprgraph->nodes[depth][node->pos] = node;
14327  ++exprgraph->nnodes[depth];
14328 
14329  /* add as parent to children
14330  * and check if children has valid values */
14331  childvalsvalid = TRUE;
14332  for( i = 0; i < nchildren; ++i )
14333  {
14334  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
14335  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
14336  }
14337  /* store children */
14338  if( nchildren > 0 )
14339  {
14340  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
14341  node->nchildren = nchildren;
14342  }
14343 
14344  if( node->op == SCIP_EXPR_CONST )
14345  {
14346  /* set bounds to constant value of node */
14348  SCIPintervalSet(&node->bounds, node->data.dbl);
14349  }
14350  else
14351  {
14352  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
14355  exprgraph->needvarboundprop = TRUE;
14356  }
14357 
14358  /* if not a variable, set value of node according to values of children (if all have valid values) */
14359  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
14360  {
14361  SCIP_CALL( exprgraphNodeEval(node, NULL) );
14362  }
14363 
14364  return SCIP_OKAY;
14365 }
14366 
14367 /** adds variables to an expression graph, if not existing yet
14368  *
14369  * Also already existing nodes are enabled.
14370  */
14372  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14373  int nvars, /**< number of variables to add */
14374  void** vars, /**< variables to add */
14375  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
14376  )
14377 {
14378  SCIP_EXPRGRAPHNODE* node;
14379  SCIP_EXPROPDATA opdata;
14380  int i;
14381 
14382  assert(exprgraph != NULL);
14383  assert(exprgraph->depth >= 1);
14384  assert(vars != NULL || nvars == 0);
14385 
14386  /* 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 */
14387  if( exprgraph->nvars == 0 )
14388  {
14389  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
14390  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
14391  }
14392 
14393  for( i = 0; i < nvars; ++i )
14394  {
14395  /* skip variables that exist already */
14396  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
14397  {
14398  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
14399  assert(node != NULL);
14400 
14401  /* enable node */
14402  node->enabled = TRUE;
14403 
14404  if( varnodes != NULL )
14405  varnodes[i] = node;
14406 
14407  continue;
14408  }
14409 
14410  /* create new variable expression */
14411  opdata.intval = exprgraph->nvars;
14412  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
14413 
14414  /* add expression node to expression graph at depth 0 */
14415  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
14416 
14417  /* add variable node to vars arrays and hashmap */
14418  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
14419  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
14420  exprgraph->varnodes[exprgraph->nvars] = node;
14421  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
14422  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[i], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
14423  ++exprgraph->nvars;
14424 
14425  if( varnodes != NULL )
14426  varnodes[i] = node;
14427 
14428  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
14429 
14430  /* call callback method, if set */
14431  if( exprgraph->exprgraphvaradded != NULL )
14432  {
14433  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
14434  }
14435  }
14436 
14437  return SCIP_OKAY;
14438 }
14439 
14440 /** adds a constant to an expression graph, if not existing yet
14441  *
14442  * Also already existing nodes are enabled.
14443  */
14445  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14446  SCIP_Real constant, /**< constant to add */
14447  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
14448  )
14449 {
14450  SCIP_EXPROPDATA opdata;
14451 
14452  assert(exprgraph != NULL);
14453  assert(constnode != NULL);
14454 
14455  /* check if there is already an expression for this constant */
14456  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
14457  {
14458  assert(*constnode != NULL);
14459  assert((*constnode)->op == SCIP_EXPR_CONST);
14460  assert((*constnode)->data.dbl == constant); /*lint !e777*/
14461  (*constnode)->enabled = TRUE;
14462  return SCIP_OKAY;
14463  }
14464 
14465  /* create new node for constant */
14466  opdata.dbl = constant;
14467  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
14468 
14469  /* add node to expression graph at depth 0 */
14470  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
14471  assert((*constnode)->depth == 0);
14472  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
14473 
14474  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
14475  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
14476  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
14477  ++exprgraph->nconsts;
14478  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
14479 
14480  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
14481 
14482  return SCIP_OKAY;
14483 }
14484 
14485 /** adds sum of expression trees into expression graph
14486  *
14487  * node will also be captured.
14488  */
14490  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14491  int nexprtrees, /**< number of expression trees to add */
14492  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
14493  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
14494  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
14495  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) */
14496  )
14497 {
14498  SCIP_Bool allone;
14499 
14500  assert(exprgraph != NULL);
14501  assert(nexprtrees > 0);
14502  assert(exprtrees != NULL);
14503  assert(rootnode != NULL);
14504  assert(rootnodeisnew != NULL);
14505 
14506  *rootnode = NULL;
14507 
14508  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
14509  {
14510  assert(exprtrees[0] != NULL);
14511  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
14512 
14513  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, rootnode, rootnodeisnew) );
14514  }
14515  else
14516  {
14517  SCIP_EXPROP op;
14518  SCIP_EXPRGRAPHNODE** rootnodes;
14519  SCIP_Bool rootnodeisnew_;
14520  int i;
14521 
14522  *rootnodeisnew = TRUE;
14523  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
14524 
14525  allone = TRUE;
14526  for( i = 0; i < nexprtrees; ++i )
14527  {
14528  assert(exprtrees[i] != NULL);
14529  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
14530 
14531  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
14532  assert(rootnodes[i] != NULL);
14533  *rootnodeisnew &= rootnodeisnew_;
14534 
14535  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
14536  }
14537 
14538  /* decide which operand we want to use for the root node */
14539  if( coefs == NULL || allone )
14540  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
14541  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
14542  op = SCIP_EXPR_MINUS;
14543  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
14544  {
14545  SCIP_EXPRGRAPHNODE* tmp;
14546 
14547  tmp = rootnodes[0];
14548  rootnodes[0] = rootnodes[1];
14549  rootnodes[1] = tmp;
14550  op = SCIP_EXPR_MINUS;
14551  }
14552  else
14553  op = SCIP_EXPR_LINEAR;
14554 
14555  if( op != SCIP_EXPR_LINEAR )
14556  {
14557  SCIP_EXPROPDATA data;
14558  data.data = NULL;
14559 
14560  if( !*rootnodeisnew )
14561  {
14562  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
14563  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
14564  }
14565 
14566  if( *rootnode == NULL )
14567  {
14568  /* create new node for sum of rootnodes and add to exprgraph */
14569  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
14570  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
14571  *rootnodeisnew = TRUE;
14572  }
14573  else
14574  {
14575  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
14576  *rootnodeisnew = FALSE;
14577  }
14578  }
14579  else
14580  {
14581  SCIP_EXPROPDATA data;
14582  SCIP_Real* lindata;
14583 
14584  assert(op == SCIP_EXPR_LINEAR);
14585 
14586  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
14587  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
14588  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
14589  lindata[nexprtrees] = 0.0;
14590  data.data = lindata;
14591 
14592  if( !*rootnodeisnew )
14593  {
14594  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
14595  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
14596  }
14597 
14598  if( *rootnode == NULL )
14599  {
14600  /* create new node for linear combination of rootnodes and add to exprgraph */
14601  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
14602  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
14603  *rootnodeisnew = TRUE;
14604  }
14605  else
14606  {
14607  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
14608  *rootnodeisnew = FALSE;
14609  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
14610  }
14611  }
14612 
14613  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
14614  }
14615  assert(*rootnode != NULL);
14616 
14617  SCIPexprgraphCaptureNode(*rootnode);
14618 
14619  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
14620  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
14621 
14622  return SCIP_OKAY;
14623 }
14624 
14625 /** replaces variable in expression graph by a linear sum of variables
14626  *
14627  * Variables will be added if not in the graph yet.
14628  */
14630  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14631  void* var, /**< variable to replace */
14632  int ncoefs, /**< number of coefficients in linear term */
14633  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
14634  void** vars, /**< variables in linear term */
14635  SCIP_Real constant /**< constant offset */
14636  )
14637 {
14638  SCIP_EXPRGRAPHNODE* varnode;
14639  SCIP_Real* lindata;
14640  int varidx;
14641  int i;
14642 
14643  assert(exprgraph != NULL);
14644  assert(var != NULL);
14645  assert(SCIPhashmapExists(exprgraph->varidxs, var));
14646  assert(coefs != NULL || ncoefs == 0);
14647  assert(vars != NULL || ncoefs == 0);
14648 
14649  varidx = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
14650  assert(varidx < exprgraph->nvars);
14651  assert(exprgraph->vars[varidx] == var);
14652  varnode = exprgraph->varnodes[varidx];
14653  assert(varnode != NULL);
14654  assert(varnode->data.intval == varidx);
14655 
14656  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
14657  {
14658  /* variable is replaced by constant or variable */
14659  SCIP_EXPRGRAPHNODE* node;
14660 
14661  /* check if there is already a node for this constant or variable */
14662  node = NULL;
14663  if( ncoefs == 0 )
14664  {
14665  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
14666  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
14667  }
14668  else
14669  {
14670  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
14671  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
14672  }
14673 
14674  if( node != NULL )
14675  {
14676  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
14677 
14678  /* tell parents of varnode to replace child varnode by node, this may free varnode */
14679  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
14680 
14681  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
14682  if( varnode != NULL )
14683  {
14684  assert(varnode->nuses > 0);
14685  assert(varnode->nparents == 0);
14686 
14687  /* remove variable (but don't free it's node) from graph */
14688  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
14689 
14690  /* move varnode up to depth 1 */
14691  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
14692 
14693  /* turn into EXPR_SUM expression */
14694  varnode->op = SCIP_EXPR_SUM;
14695  varnode->data.data = NULL;
14696  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
14697  varnode->children[0] = node;
14698  varnode->nchildren = 1;
14699  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
14700 
14701  varnode->value = node->value;
14702  varnode->bounds = node->bounds;
14704  }
14705  }
14706  else if( ncoefs == 0 )
14707  {
14708  /* turn node into EXPR_CONST node */
14709 
14710  /* remove variable (but don't free it's node) from graph */
14711  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
14712 
14713  /* convert into EXPR_CONST node */
14714  varnode->op = SCIP_EXPR_CONST;
14715  varnode->data.dbl = constant;
14716 
14717  varnode->value = constant;
14718  SCIPintervalSet(&varnode->bounds, constant);
14720 
14721  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
14722  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
14723  exprgraph->constnodes[exprgraph->nconsts] = varnode;
14724  ++exprgraph->nconsts;
14725  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
14726  }
14727  else
14728  {
14729  /* turn node into EXPR_VARIDX node for new variable */
14730 
14731  /* remove variable (but don't free it's node) from graph */
14732  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
14733 
14734  varnode->data.intval = exprgraph->nvars;
14735 
14736  /* add variable node to vars arrays and hashmap */
14737  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
14738  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
14739  exprgraph->varnodes[exprgraph->nvars] = varnode;
14740  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
14741  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[0], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
14742  ++exprgraph->nvars;
14743 
14744  /* call callback method, if set */
14745  if( exprgraph->exprgraphvaradded != NULL )
14746  {
14747  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
14748  }
14749  }
14750 
14751  /* mark varnode and its parents as not simplified */
14752  if( varnode != NULL )
14753  {
14754  varnode->simplified = FALSE;
14755  for( i = 0; i < varnode->nparents; ++i )
14756  varnode->parents[i]->simplified = FALSE;
14757  }
14758 
14759  return SCIP_OKAY;
14760  }
14761 
14762  /* turn varnode into EXPR_LINEAR */
14763 
14764  /* remove variable (but don't free it's node) from graph */
14765  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
14766 
14767  /* move varnode up to depth 1 */
14768  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
14769 
14770  /* convert into EXPR_LINEAR node */
14771  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
14772  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
14773  lindata[ncoefs] = constant;
14774  varnode->data.data = (void*)lindata;
14775  varnode->op = SCIP_EXPR_LINEAR;
14776 
14777  /* add nodes corresponding to vars to expression graph, if not existing yet */
14778  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
14779  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
14780  varnode->nchildren = ncoefs;
14781 
14782  /* notify vars about new parent varnode */
14783  for( i = 0; i < ncoefs; ++i )
14784  {
14785  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
14786  }
14787 
14788  /* set value and bounds to invalid, curvature can remain (still linear) */
14789  varnode->value = SCIP_INVALID;
14791 
14792  /* mark varnode and its parents as not simplified */
14793  varnode->simplified = FALSE;
14794  for( i = 0; i < varnode->nparents; ++i )
14795  varnode->parents[i]->simplified = FALSE;
14796 
14797  return SCIP_OKAY;
14798 }
14799 
14800 /** finds expression graph node corresponding to a variable */
14802  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14803  void* var, /**< variable to search for */
14804  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
14805  )
14806 {
14807  int pos;
14808 
14809  assert(exprgraph != NULL);
14810  assert(var != NULL);
14811  assert(varnode != NULL);
14812 
14813  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
14814  {
14815  *varnode = NULL;
14816  return FALSE;
14817  }
14818 
14819  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
14820  assert(pos < exprgraph->nvars);
14821 
14822  *varnode = exprgraph->varnodes[pos];
14823  assert(*varnode != NULL);
14824  assert((*varnode)->op == SCIP_EXPR_VARIDX);
14825 
14826  return TRUE;
14827 }
14828 
14829 /** finds expression graph node corresponding to a constant */
14831  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14832  SCIP_Real constant, /**< constant to search for */
14833  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
14834  )
14835 {
14836  int left;
14837  int right;
14838  int middle;
14839 
14840  assert(exprgraph != NULL);
14841  assert(constnode != NULL);
14842  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
14843 
14844  exprgraphSortConstNodes(exprgraph);
14845  assert(exprgraph->constssorted);
14846 
14847  /* find node using binary search */
14848  left = 0;
14849  right = exprgraph->nconsts-1;
14850  *constnode = NULL;
14851 
14852  while( left <= right )
14853  {
14854  middle = (left+right)/2;
14855  assert(0 <= middle && middle < exprgraph->nconsts);
14856 
14857  if( constant < exprgraph->constnodes[middle]->data.dbl )
14858  right = middle - 1;
14859  else if( constant > exprgraph->constnodes[middle]->data.dbl )
14860  left = middle + 1;
14861  else
14862  {
14863  *constnode = exprgraph->constnodes[middle];
14864  break;
14865  }
14866  }
14867  assert(left == right+1 || *constnode != NULL);
14868  if( left == right+1 )
14869  return FALSE;
14870 
14871  assert((*constnode)->op == SCIP_EXPR_CONST);
14872  assert((*constnode)->data.dbl == constant); /*lint !e777*/
14873 
14874  return TRUE;
14875 }
14876 
14877 /** prints an expression graph in dot format */
14879  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14880  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14881  FILE* file, /**< file to print to, or NULL for stdout */
14882  const char** varnames /**< variable names, or NULL for generic names */
14883  )
14884 {
14885  int d;
14886  int i;
14887 
14888  assert(exprgraph != NULL);
14889 
14890  if( file == NULL )
14891  file = stdout;
14892 
14893  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
14894  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
14895 
14896  for( d = 0; d < exprgraph->depth; ++d )
14897  {
14898  if( exprgraph->nnodes[d] == 0 )
14899  continue;
14900 
14901  for( i = 0; i < exprgraph->nnodes[d]; ++i )
14902  {
14903  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
14904  }
14905  }
14906 
14907  /* tell dot that all nodes of depth 0 have the same rank */
14908  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
14909  for( i = 0; i < exprgraph->nnodes[0]; ++i )
14910  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
14911  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
14912 
14913  /* tell dot that all nodes without parent have the same rank */
14914  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
14915  for( d = 0; d < exprgraph->depth; ++d )
14916  for( i = 0; i < exprgraph->nnodes[d]; ++i )
14917  if( exprgraph->nodes[d][i]->nparents == 0 )
14918  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
14919  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
14920 
14921  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
14922 
14923  return SCIP_OKAY;
14924 }
14925 
14926 /** evaluates nodes of expression graph for given values of variables */
14928  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14929  SCIP_Real* varvals /**< values for variables */
14930  )
14931 {
14932  int d;
14933  int i;
14934 
14935  assert(exprgraph != NULL);
14936  assert(varvals != NULL || exprgraph->nvars == 0);
14937 
14938  for( d = 0; d < exprgraph->depth; ++d )
14939  for( i = 0; i < exprgraph->nnodes[d]; ++i )
14940  {
14941  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
14942  }
14943 
14944  return SCIP_OKAY;
14945 }
14946 
14947 /** propagates bound changes in variables forward through the expression graph */
14949  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14950  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14951  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
14952  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
14953  )
14954 {
14955  SCIP_EXPRGRAPHNODE* node;
14956  SCIP_Bool boundchanged;
14957  int d;
14958  int i;
14959 
14960  assert(exprgraph != NULL);
14961  assert(domainerror != NULL);
14962 
14963  *domainerror = FALSE;
14964 
14965  /* update bounds in varnodes of expression graph */
14966  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
14967 
14968  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
14969  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
14970  {
14971  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
14972  return SCIP_OKAY;
14973  }
14974 
14975  /* propagate bound changes, interrupt if we get to a node with empty bounds */
14976  for( d = 1; d < exprgraph->depth; ++d )
14977  {
14978  for( i = 0; i < exprgraph->nnodes[d]; ++i )
14979  {
14980  node = exprgraph->nodes[d][i];
14981  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
14982  if( SCIPintervalIsEmpty(node->bounds) )
14983  {
14984  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
14985  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
14986  *domainerror = TRUE;
14987  return SCIP_OKAY;
14988  }
14989  }
14990  }
14991 
14992  exprgraph->needvarboundprop = FALSE;
14993 
14994  return SCIP_OKAY;
14995 }
14996 
14997 /** propagates bound changes in nodes backward through the graph
14998  *
14999  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15000  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15001  */
15003  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15004  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15005  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15006  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15007  )
15008 {
15009  SCIP_EXPRGRAPHNODE* node;
15010  int d;
15011  int i;
15012 
15013  assert(exprgraph != NULL);
15014  assert(cutoff != NULL);
15015 
15016  *cutoff = FALSE;
15017 
15018  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15019  {
15020  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15021  {
15022  node = exprgraph->nodes[d][i];
15023  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15024  }
15025  }
15026  if( *cutoff )
15027  return;
15028 }
15029 
15030 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15031  *
15032  * Implies update of bounds in expression graph.
15033  */
15035  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15036  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15037  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15038  )
15039 {
15040  SCIP_EXPRGRAPHNODE* node;
15041  SCIP_Bool boundchanged;
15042  int d;
15043  int i;
15044 
15045  assert(exprgraph != NULL);
15046 
15047  /* update bounds in varnodes of expression graph */
15048  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15049 
15050 #ifndef NDEBUG
15051  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15052  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15053 #endif
15054 
15055  for( d = 1; d < exprgraph->depth; ++d )
15056  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15057  {
15058  node = exprgraph->nodes[d][i];
15059  assert(node != NULL);
15060 
15061  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15062 
15063  if( SCIPintervalIsEmpty(node->bounds) )
15064  {
15065  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15066  return SCIP_OKAY;
15067  }
15068  }
15069 
15070  return SCIP_OKAY;
15071 }
15072 
15073 /** aims at simplifying an expression graph
15074  *
15075  * 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)).
15076  */
15078  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15079  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15080  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15081  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15082  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15083  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15084  )
15085 {
15086  SCIP_EXPRGRAPHNODE* node;
15087  SCIP_Bool havechangenode;
15088  SCIP_Bool allsimplified;
15089  int d;
15090  int i;
15091  int j;
15092 
15093 #ifndef NDEBUG
15094  SCIP_Real* testx;
15095  SCIP_HASHMAP* testvalidx;
15096  SCIP_Real* testvals;
15097  int testvalssize;
15098  int ntestvals;
15099  unsigned int seed;
15100 #endif
15101 
15102  assert(exprgraph != NULL);
15103  assert(eps >= 0.0);
15104  assert(havechange != NULL);
15105  assert(domainerror != NULL);
15106 
15107 #ifndef NDEBUG
15108  seed = 42;
15109  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
15110  testvals = NULL;
15111  ntestvals = 0;
15112  testvalssize = 0;
15113 
15114  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
15115  for( i = 0; i < exprgraph->nvars; ++i )
15116  testx[i] = SCIPgetRandomReal(-100.0, 100.0, &seed); /*lint !e644*/
15117  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
15118  for( d = 1; d < exprgraph->depth; ++d )
15119  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15120  {
15121  node = exprgraph->nodes[d][i];
15122  assert(node != NULL);
15123 
15124  /* 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 */
15125  if( node->nuses > 0 )
15126  {
15127  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
15128  SCIP_CALL( SCIPhashmapInsert(testvalidx, (void*)node, (void*)(size_t)ntestvals) );
15129  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
15130  ++ntestvals;
15131  }
15132  }
15133 #endif
15134 
15135 #ifdef SCIP_OUTPUT
15136  {
15137  FILE* file;
15138  file = fopen("exprgraph_beforesimplify.dot", "w");
15139  if( file != NULL )
15140  {
15141  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
15142  fclose(file);
15143  }
15144  }
15145 #endif
15146 
15147  *havechange = FALSE; /* we have not changed any node yet */
15148  *domainerror = FALSE; /* no domain errors encountered so far */
15149  allsimplified = TRUE; /* all nodes we looked at are simplified */
15150 
15151  /* call node simplifier from bottom up
15152  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
15153  */
15154  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
15155  {
15156  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15157  {
15158  node = exprgraph->nodes[d][i];
15159  assert(node != NULL);
15160 
15161  havechangenode = FALSE; /* node did not change yet */
15162 
15163  if( node->op != SCIP_EXPR_CONST )
15164  {
15165  /* skip nodes that are already simplified */
15166  if( node->simplified )
15167  continue;
15168 
15169  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
15170 
15171  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
15172  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
15173  assert(node->simplified == TRUE);
15174  *havechange |= havechangenode;
15175  }
15176 
15177  /* if node was or has been converted into constant, may move to depth 0 */
15178  if( node->op == SCIP_EXPR_CONST )
15179  {
15180  SCIP_EXPRGRAPHNODE* constnode;
15181 
15182  if( node->value != node->value ) /*lint !e777*/
15183  {
15184  SCIPdebugMessage("Expression graph simplify turned node into NaN.\n");
15185  *domainerror = TRUE;
15186  break;
15187  }
15188 
15189  /* check if there is already a node for this constant */
15190  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
15191  {
15192  assert(constnode->op == SCIP_EXPR_CONST);
15193  assert(constnode->data.dbl == node->value); /*lint !e777*/
15194 
15195  if( node->nparents > 0 )
15196  {
15197  /* move parents of this node to constnode, node may be freed if not in use */
15198  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
15199  /* node should have no parents anymore, so it should have been freed if not in use */
15200  assert(node == NULL || node->nuses > 0);
15201  havechangenode = TRUE;
15202 
15203  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
15204  if( node == NULL )
15205  {
15206  --i;
15207  continue;
15208  }
15209  }
15210  assert(node != NULL);
15211  assert(node->nuses > 0);
15212 
15213  if( constnode->nuses == 0 )
15214  {
15215  /* move node to depth 0, adding it to constnodes */
15216  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
15217 
15218  /* move parents of constnode to node, so constnode is freed */
15219  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
15220  assert(constnode == NULL);
15221  havechangenode = TRUE;
15222 
15223  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
15224  --i;
15225  continue;
15226  }
15227  }
15228  else
15229  {
15230  /* move to depth 0, adding it to constnodes */
15231  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
15232 
15233  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
15234  --i;
15235  }
15236  }
15237 
15238  /* if there was a change, mark parents as not simplified */
15239  if( havechangenode )
15240  for( j = 0; j < node->nparents; ++j )
15241  node->parents[j]->simplified = FALSE;
15242  }
15243  } /*lint !e850*/
15244 
15245  /* if we did nothing, clean up and escape from here */
15246  if( allsimplified || *domainerror )
15247  goto EXPRGRAPHSIMPLIFY_CLEANUP;
15248 
15249  /* @todo find duplicate subexpressions in expression graph */
15250 
15251  /* unconvert polynomials into simpler expressions, where possible */
15252  for( d = 1; d < exprgraph->depth; ++d )
15253  {
15254  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15255  {
15256  node = exprgraph->nodes[d][i];
15257  assert(node != NULL);
15258 
15259  if( node->op != SCIP_EXPR_POLYNOMIAL )
15260  continue;
15261 
15262  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
15263 
15264  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
15265  {
15266  /* node is identity w.r.t only child
15267  * replace node as child of parents by child of node
15268  */
15269 
15270  for( j = 0; node != NULL && j < node->nparents; ++j )
15271  {
15272  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
15273  }
15274  /* node should have no parents anymore, so it should have been freed if not in use */
15275  assert(node == NULL || node->nuses > 0);
15276 
15277  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
15278  if( node == NULL )
15279  --i;
15280  }
15281  }
15282  } /*lint !e850*/
15283 
15284 #ifdef SCIP_OUTPUT
15285  {
15286  FILE* file;
15287  file = fopen("exprgraph_aftersimplify.dot", "w");
15288  if( file != NULL )
15289  {
15290  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
15291  fclose(file);
15292  }
15293  }
15294 #endif
15295 
15296 #ifndef NDEBUG
15297  for( d = 1; d < exprgraph->depth; ++d )
15298  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15299  {
15300  int idx;
15301  SCIP_Real testval_before;
15302  SCIP_Real testval_after;
15303 
15304  node = exprgraph->nodes[d][i];
15305  assert(node != NULL);
15306 
15307  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15308 
15309  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
15310  if( node->nuses > 0 )
15311  {
15312  assert(SCIPhashmapExists(testvalidx, (void*)node));
15313 
15314  idx = (int)(size_t)(void*)SCIPhashmapGetImage(testvalidx, (void*)node);
15315  assert(idx < ntestvals);
15316 
15317  testval_before = testvals[idx]; /*lint !e613*/
15318  testval_after = SCIPexprgraphGetNodeVal(node);
15319 
15320  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
15321  }
15322  }
15323 #endif
15324 
15325  EXPRGRAPHSIMPLIFY_CLEANUP:
15326 #ifndef NDEBUG
15327  BMSfreeMemoryArray(&testx);
15328  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
15329  SCIPhashmapFree(&testvalidx);
15330 #endif
15331 
15332  return SCIP_OKAY;
15333 }
15334 
15335 /** creates an expression tree from a given node in an expression graph */
15337  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15338  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
15339  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
15340  )
15341 {
15342  SCIP_EXPR* root;
15343  int nexprvars;
15344  int* varidx;
15345  int i;
15346 
15347  assert(exprgraph != NULL);
15348  assert(rootnode != NULL);
15349  assert(rootnode->depth >= 0);
15350  assert(rootnode->pos >= 0);
15351  assert(exprtree != NULL);
15352 
15353  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
15354  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
15355 
15356  /* initially, no variable appears in the expression tree */
15357  for( i = 0; i < exprgraph->nvars; ++i )
15358  varidx[i] = -1; /*lint !e644*/
15359  nexprvars = 0;
15360 
15361  /* create expression from the subgraph that has rootnode as root */
15362  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
15363 
15364  /* create expression tree for this expression */
15365  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
15366 
15367  /* copy variables into expression tree */
15368  if( nexprvars > 0 )
15369  {
15370  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
15371  for( i = 0; i < exprgraph->nvars; ++i )
15372  {
15373  assert(varidx[i] >= -1);
15374  assert(varidx[i] < nexprvars);
15375  if( varidx[i] >= 0 )
15376  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
15377  }
15378  }
15379 
15380  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
15381 
15382  return SCIP_OKAY;
15383 }
15384 
15385 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
15386  *
15387  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
15388  */
15390  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15391  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
15392  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
15393  int* nexprtrees, /**< buffer to store number of expression trees */
15394  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
15395  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
15396  )
15397 {
15398  int ncomponents;
15399  int* childcomp;
15400  int* varcomp;
15401  int compnr;
15402  SCIP_Bool haveoverlap;
15403  int i;
15404  int j;
15405  int k;
15406 
15407  SCIP_EXPR** exprs;
15408  int nexprs;
15409  int* childmap;
15410  int* childmapinv;
15411  int* varidx;
15412  int nexprvars;
15413 
15414  assert(exprgraph != NULL);
15415  assert(node != NULL);
15416  assert(node->depth >= 0);
15417  assert(node->pos >= 0);
15418  assert(exprtreessize > 0);
15419  assert(nexprtrees != NULL);
15420  assert(exprtrees != NULL);
15421  assert(exprtreecoefs != NULL);
15422 
15423  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
15424  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
15425  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
15426  ( node->op != SCIP_EXPR_PLUS &&
15427  node->op != SCIP_EXPR_MINUS &&
15428  node->op != SCIP_EXPR_SUM &&
15429  node->op != SCIP_EXPR_LINEAR &&
15430  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
15431  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
15432  {
15433  *nexprtrees = 1;
15434  exprtreecoefs[0] = 1.0;
15435  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
15436 
15437  return SCIP_OKAY;
15438  }
15439 
15440  /* find components in node->children <-> variables graph */
15441  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
15442  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
15443  for( i = 0; i < exprgraph->nvars; ++i )
15444  varcomp[i] = -1; /*lint !e644*/
15445 
15446  haveoverlap = FALSE;
15447  for( i = 0; i < node->nchildren; ++i )
15448  {
15449  compnr = i;
15450  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
15451  assert(compnr >= 0);
15452  assert(compnr < node->nchildren);
15453  childcomp[i] = compnr;
15454 
15455  /* remember if component number was changed by CheckComponent */
15456  if( compnr != i )
15457  haveoverlap = TRUE;
15458  }
15459 
15460  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
15461 
15462  if( node->op == SCIP_EXPR_QUADRATIC )
15463  {
15464  /* merge components for products of children from different components */
15466 
15467  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
15468  assert(data != NULL);
15469 
15470  for( i = 0; i < data->nquadelems; ++i )
15471  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
15472  {
15473  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
15474  compnr = childcomp[data->quadelems[i].idx2];
15475  for( j = 0; j < node->nchildren; ++j )
15476  if( childcomp[j] == compnr )
15477  childcomp[j] = childcomp[data->quadelems[i].idx1];
15478  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
15479  haveoverlap = TRUE;
15480  }
15481  }
15482  else if( node->op == SCIP_EXPR_POLYNOMIAL )
15483  {
15484  /* merge components for monomials of children from different components */
15486 
15487  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
15488  assert(data != NULL);
15489 
15490  for( i = 0; i < data->nmonomials; ++i )
15491  for( j = 1; j < data->monomials[i]->nfactors; ++j )
15492  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
15493  {
15494  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
15495  compnr = childcomp[data->monomials[i]->childidxs[j]];
15496  for( k = 0; k < node->nchildren; ++k )
15497  if( childcomp[k] == compnr )
15498  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
15499  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
15500  haveoverlap = TRUE;
15501  }
15502  }
15503 
15504  if( haveoverlap )
15505  {
15506  /* some component numbers are unused, thus relabel and count final number of components */
15507  int* compmap;
15508 
15509  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
15510  for( i = 0; i < node->nchildren; ++i )
15511  compmap[i] = -1; /*lint !e644*/
15512 
15513  ncomponents = 0;
15514  for( i = 0; i < node->nchildren; ++i )
15515  {
15516  if( compmap[childcomp[i]] == -1 )
15517  compmap[childcomp[i]] = ncomponents++;
15518  childcomp[i] = compmap[childcomp[i]];
15519  }
15520 
15521  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
15522  }
15523  else
15524  {
15525  ncomponents = node->nchildren;
15526  }
15527 
15528  if( ncomponents == 1 )
15529  {
15530  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
15531  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
15532 
15533  *nexprtrees = 1;
15534  exprtreecoefs[0] = 1.0;
15535  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
15536 
15537  return SCIP_OKAY;
15538  }
15539 
15540  if( ncomponents > exprtreessize )
15541  {
15542  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
15543  for( i = 0; i < node->nchildren; ++i )
15544  if( childcomp[i] >= exprtreessize )
15545  childcomp[i] = exprtreessize-1;
15546  ncomponents = exprtreessize;
15547  }
15548 
15549  assert(ncomponents >= 2);
15550 
15551  /* setup expression trees for each component */
15552  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
15553  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
15554  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
15555  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
15556  for( i = 0; i < ncomponents; ++i )
15557  {
15558  /* initially, no variable appears in the expression tree */
15559  for( j = 0; j < exprgraph->nvars; ++j )
15560  varidx[j] = -1; /*lint !e644*/
15561  nexprvars = 0;
15562 
15563  /* collect expressions from children belonging to component i */
15564  nexprs = 0;
15565  for( j = 0; j < node->nchildren; ++j )
15566  {
15567  assert(childcomp[j] >= 0);
15568  assert(childcomp[j] < ncomponents);
15569  if( childcomp[j] != i )
15570  continue;
15571 
15572  /* create expression from the subgraph that has child j as root */
15573  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
15574  childmap[j] = nexprs; /*lint !e644*/
15575  childmapinv[nexprs] = j; /*lint !e644*/
15576  ++nexprs;
15577  }
15578 
15579  /* setup expression tree for component i */
15580  switch( node->op )
15581  {
15582  case SCIP_EXPR_PLUS:
15583  {
15584  assert(ncomponents == 2);
15585  assert(nexprs == 1);
15586 
15587  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
15588  exprtreecoefs[i] = 1.0;
15589 
15590  break;
15591  }
15592 
15593  case SCIP_EXPR_MINUS:
15594  {
15595  assert(ncomponents == 2);
15596  assert(nexprs == 1);
15597 
15598  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
15599  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
15600  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
15601  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
15602 
15603  break;
15604  }
15605 
15606  case SCIP_EXPR_SUM:
15607  {
15608  if( nexprs == 1 )
15609  {
15610  /* component corresponds to exactly one child of node */
15611  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
15612  }
15613  else
15614  {
15615  /* component corresponds to a sum of children of node */
15616  SCIP_EXPR* sumexpr;
15617 
15618  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
15619  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
15620  }
15621  exprtreecoefs[i] = 1.0;
15622 
15623  break;
15624  }
15625 
15626  case SCIP_EXPR_LINEAR:
15627  {
15628  SCIP_Real* nodecoefs;
15629  SCIP_EXPR* sumexpr;
15630 
15631  nodecoefs = (SCIP_Real*)node->data.data;
15632 
15633  /* if there is a constant, then we put it into the expression of the first component */
15634  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
15635  {
15636  /* component corresponds to exactly one child of node */
15637  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
15638  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
15639  }
15640  else if( nexprs == 1 )
15641  {
15642  /* component corresponds to a sum of one child and a constant */
15643  assert(i == 0);
15644  assert(nodecoefs[node->nchildren] != 0.0);
15645  assert(nodecoefs[childmapinv[0]] != 0.0);
15646  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
15647  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
15648  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
15649  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
15650  }
15651  else
15652  {
15653  /* component corresponds to a linear combination of children of node */
15654 
15655  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
15656  {
15657  /* if two expressions with equal sign, then create PLUS expression */
15658  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
15659  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
15660  }
15661  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
15662  {
15663  /* if two expressions with opposite sign, then create MINUS expression */
15664  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
15665  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
15666  }
15667  else
15668  {
15669  /* assemble coefficents and create SUM or LINEAR expression */
15670  SCIP_Real* coefs;
15671  SCIP_Bool allcoefsequal;
15672 
15673  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
15674  allcoefsequal = TRUE;
15675  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
15676  for( j = 0; j < nexprs; ++j )
15677  {
15678  coefs[j] = nodecoefs[childmapinv[j]];
15679  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
15680  }
15681 
15682  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
15683  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
15684  {
15685  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
15686  exprtreecoefs[i] = coefs[0];
15687  }
15688  else
15689  {
15690  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
15691  exprtreecoefs[i] = 1.0;
15692  }
15693 
15694  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
15695  }
15696 
15697  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
15698  }
15699 
15700  break;
15701  }
15702 
15703  case SCIP_EXPR_QUADRATIC:
15704  {
15705  SCIP_EXPR* quadexpr;
15706  SCIP_EXPRDATA_QUADRATIC* nodedata;
15707  SCIP_Real* lincoefs;
15708  SCIP_QUADELEM* quadelems;
15709  int nquadelems;
15710 
15711  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
15712 
15713  exprtreecoefs[i] = 1.0;
15714 
15715  /* assemble coefficients corresponding to component i */
15716  if( nodedata->lincoefs != NULL )
15717  {
15718  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
15719  for( j = 0; j < nexprs; ++j )
15720  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
15721  }
15722  else
15723  lincoefs = NULL;
15724 
15725  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
15726  nquadelems = 0;
15727  for( j = 0; j < nodedata->nquadelems; ++j )
15728  {
15729  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
15730  if( childcomp[nodedata->quadelems[j].idx1] != i )
15731  continue;
15732  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
15733  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
15734  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
15735  ++nquadelems;
15736  }
15737 
15738  /* put constant into first component */
15739  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
15740  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
15741 
15742  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
15743  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
15744 
15745  break;
15746  }
15747 
15748  case SCIP_EXPR_POLYNOMIAL:
15749  {
15750  SCIP_EXPR* polyexpr;
15751  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
15752  SCIP_EXPRDATA_MONOMIAL** monomials;
15753  SCIP_Real constant;
15754  int nmonomials;
15755 
15756  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
15757 
15758  constant = nodedata->constant;
15759  exprtreecoefs[i] = 1.0;
15760 
15761  /* collect monomials belonging to component i */
15762  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
15763  nmonomials = 0;
15764  for( j = 0; j < nodedata->nmonomials; ++j )
15765  {
15766  if( nodedata->monomials[j]->nfactors == 0 )
15767  {
15768  constant += nodedata->monomials[j]->coef;
15769  continue;
15770  }
15771  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
15772  continue;
15773 
15774  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
15775  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
15776  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
15777  {
15778  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
15779  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
15780  }
15781  ++nmonomials;
15782  }
15783 
15784  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
15785  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
15786 
15787  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
15788 
15789  break;
15790  }
15791 
15792  default:
15793  SCIPerrorMessage("unexpected operator type %d\n", node->op);
15794  return SCIP_ERROR;
15795  } /*lint !e788*/
15796 
15797  /* copy variables into expression tree */
15798  if( nexprvars > 0 )
15799  {
15800  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
15801  for( j = 0; j < exprgraph->nvars; ++j )
15802  {
15803  assert(varidx[j] >= -1);
15804  assert(varidx[j] < nexprvars);
15805  if( varidx[j] >= 0 )
15806  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
15807  }
15808  }
15809  }
15810 
15811  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
15812  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
15813  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
15814  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
15815  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
15816 
15817  *nexprtrees = ncomponents;
15818 
15819  return SCIP_OKAY;
15820 }
15821 
15822 /** returns how often expression graph variables are used in a subtree of the expression graph */
15824  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15825  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
15826  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
15827  )
15828 {
15829  assert(exprgraph != NULL);
15830  assert(node != NULL);
15831  assert(varsusage != NULL);
15832 
15833  BMSclearMemoryArray(varsusage, exprgraph->nvars);
15834 
15835  exprgraphNodeGetVarsUsage(node, varsusage);
15836 }
15837 
15838 /** gives the number of summands which the expression of an expression graph node consists of */
15840  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
15841  )
15842 {
15843  switch( node->op )
15844  {
15845  case SCIP_EXPR_PLUS:
15846  case SCIP_EXPR_MINUS:
15847  return 2;
15848 
15849  case SCIP_EXPR_SUM:
15850  case SCIP_EXPR_LINEAR:
15851  return node->nchildren;
15852 
15853  case SCIP_EXPR_QUADRATIC:
15854  {
15855  SCIP_EXPRDATA_QUADRATIC* nodedata;
15856 
15857  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
15858  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
15859  }
15860 
15861  case SCIP_EXPR_POLYNOMIAL:
15862  {
15863  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
15864 
15865  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
15866  return nodedata->nmonomials;
15867  }
15868 
15869  default:
15870  return 1;
15871  } /*lint !e788*/
15872 }
15873 
15874 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
15876  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15877  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
15878  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
15879  int* nexprtrees, /**< buffer to store number of expression trees */
15880  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
15881  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
15882  )
15883 {
15884  int* varidx;
15885  int nexprvars;
15886  int i;
15887 
15888  assert(exprgraph != NULL);
15889  assert(node != NULL);
15890  assert(node->depth >= 0);
15891  assert(node->pos >= 0);
15892  assert(exprtreessize > 0);
15893  assert(nexprtrees != NULL);
15894  assert(exprtrees != NULL);
15895  assert(exprtreecoefs != NULL);
15896 
15897  /* if node is not separable, fallback to SCIPexprgraphGetTree */
15898  if( node->op != SCIP_EXPR_PLUS &&
15899  node->op != SCIP_EXPR_MINUS &&
15900  node->op != SCIP_EXPR_SUM &&
15901  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
15902  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
15903  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
15904  {
15905  *nexprtrees = 1;
15906  exprtreecoefs[0] = 1.0;
15907  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
15908 
15909  return SCIP_OKAY;
15910  }
15911 
15912  switch( node->op )
15913  {
15914  case SCIP_EXPR_PLUS:
15915  {
15916  assert(exprtreessize >= 2);
15917 
15918  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
15919  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
15920 
15921  exprtreecoefs[0] = 1.0;
15922  exprtreecoefs[1] = 1.0;
15923 
15924  *nexprtrees = 2;
15925  break;
15926  }
15927 
15928  case SCIP_EXPR_MINUS:
15929  {
15930  assert(exprtreessize >= 2);
15931 
15932  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
15933  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
15934 
15935  exprtreecoefs[0] = 1.0;
15936  exprtreecoefs[1] = -1.0;
15937 
15938  *nexprtrees = 2;
15939  break;
15940  }
15941 
15942  case SCIP_EXPR_SUM:
15943  {
15944  assert(exprtreessize >= node->nchildren);
15945 
15946  for( i = 0; i < node->nchildren; ++i )
15947  {
15948  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
15949  exprtreecoefs[i] = 1.0;
15950  }
15951 
15952  *nexprtrees = node->nchildren;
15953  break;
15954  }
15955 
15956  case SCIP_EXPR_LINEAR:
15957  {
15958  SCIP_Real* nodecoefs;
15959 
15960  assert(exprtreessize >= node->nchildren);
15961  assert(node->nchildren > 0);
15962 
15963  nodecoefs = (SCIP_Real*)node->data.data;
15964  assert(nodecoefs != NULL);
15965 
15966  for( i = 0; i < node->nchildren; ++i )
15967  {
15968  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
15969  exprtreecoefs[i] = nodecoefs[i];
15970  }
15971 
15972  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
15973  if( nodecoefs[node->nchildren] != 0.0 )
15974  {
15975  SCIP_EXPR* constexpr_;
15976 
15977  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
15978  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
15979  }
15980 
15981  *nexprtrees = node->nchildren;
15982  break;
15983  }
15984 
15985  case SCIP_EXPR_QUADRATIC:
15986  {
15987  SCIP_EXPRDATA_QUADRATIC* nodedata;
15988  SCIP_Real* lincoefs;
15989  SCIP_QUADELEM* quadelems;
15990  int nquadelems;
15991  SCIP_EXPR* expr;
15992  int j;
15993 
15994  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
15995  lincoefs = nodedata->lincoefs;
15996  quadelems = nodedata->quadelems;
15997  nquadelems = nodedata->nquadelems;
15998 
15999  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16000  assert(node->nchildren > 0);
16001 
16002  *nexprtrees = 0;
16003  if( lincoefs != NULL )
16004  {
16005  for( i = 0; i < node->nchildren; ++i )
16006  {
16007  if( lincoefs[i] == 0.0 )
16008  continue;
16009  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16010  exprtreecoefs[*nexprtrees] = lincoefs[i];
16011  ++*nexprtrees;
16012  }
16013  }
16014 
16015  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16016  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16017 
16018  for( i = 0; i < nquadelems; ++i )
16019  {
16020  /* initially, no variable appears in the expression tree */
16021  for( j = 0; j < exprgraph->nvars; ++j )
16022  varidx[j] = -1; /*lint !e644*/
16023  nexprvars = 0;
16024 
16025  /* create expression from the subgraph at quadelems[i].idx1 */
16026  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16027 
16028  if( quadelems[i].idx1 == quadelems[i].idx2 )
16029  {
16030  /* create expression for square of expr */
16031  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16032  }
16033  else
16034  {
16035  SCIP_EXPR* expr2;
16036 
16037  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16038  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16039  /* create expression for product */
16040  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16041  }
16042 
16043  /* create expression tree for expr */
16044  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16045 
16046  /* copy variables into expression tree */
16047  if( nexprvars > 0 )
16048  {
16049  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16050  for( j = 0; j < exprgraph->nvars; ++j )
16051  {
16052  assert(varidx[j] >= -1);
16053  assert(varidx[j] < nexprvars);
16054  if( varidx[j] >= 0 )
16055  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16056  }
16057  }
16058 
16059  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16060 
16061  ++*nexprtrees;
16062  }
16063 
16064  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16065  if( nodedata->constant != 0.0 )
16066  {
16067  SCIP_EXPR* constexpr_;
16068 
16069  assert(*nexprtrees > 0);
16070  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16071  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16072  }
16073 
16074  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16075 
16076  break;
16077  }
16078 
16079  case SCIP_EXPR_POLYNOMIAL:
16080  {
16081  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
16082  SCIP_EXPRDATA_MONOMIAL** monomials;
16083  SCIP_Real constant;
16084  int nmonomials;
16085  SCIP_EXPR* expr;
16086  int* childidxs;
16087  int j;
16088 
16089  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16090  monomials = nodedata->monomials;
16091  nmonomials = nodedata->nmonomials;
16092  constant = nodedata->constant;
16093 
16094  assert(exprtreessize >= nmonomials);
16095  assert(node->nchildren > 0);
16096 
16097  *nexprtrees = 0;
16098 
16099  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16100  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16101 
16102  for( i = 0; i < nmonomials; ++i )
16103  {
16104  /* initially, no variable appears in the expression tree */
16105  for( j = 0; j < exprgraph->nvars; ++j )
16106  varidx[j] = -1;
16107  nexprvars = 0;
16108 
16109  if( monomials[i]->nfactors == 1 )
16110  {
16111  /* create expression from the subgraph at only factor */
16112  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16113 
16114  /* put exponent in, if not 1.0 */
16115  if( monomials[i]->exponents[0] == 1.0 )
16116  ;
16117  else if( monomials[i]->exponents[0] == 2.0 )
16118  {
16119  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16120  }
16121  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
16122  {
16123  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
16124  }
16125  else
16126  {
16127  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
16128  }
16129  }
16130  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
16131  {
16132  SCIP_EXPR* expr2;
16133 
16134  /* create expressions for both factors */
16135  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16136  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
16137 
16138  /* create expression for product of factors */
16139  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16140  }
16141  else
16142  {
16143  SCIP_EXPRDATA_MONOMIAL* monomial;
16144  SCIP_EXPR** exprs;
16145  int f;
16146 
16147  /* create expression for each factor, assemble varidx and nexprvars
16148  * create child indices (= identity) */
16149  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
16150  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
16151  for( f = 0; f < monomials[i]->nfactors; ++f )
16152  {
16153  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
16154  childidxs[f] = f; /*lint !e644*/
16155  }
16156 
16157  /* create monomial and polynomial expression for this monomial
16158  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
16159  */
16160  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
16161  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
16162  constant = 0.0;
16163 
16164  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
16165  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
16166  }
16167 
16168  /* create expression tree for expr */
16169  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16170 
16171  /* copy variables into expression tree */
16172  if( nexprvars > 0 )
16173  {
16174  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16175  for( j = 0; j < exprgraph->nvars; ++j )
16176  {
16177  assert(varidx[j] >= -1);
16178  assert(varidx[j] < nexprvars);
16179  if( varidx[j] >= 0 )
16180  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16181  }
16182  }
16183 
16184  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
16185 
16186  ++*nexprtrees;
16187  }
16188 
16189  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
16190  if( constant != 0.0 )
16191  {
16192  SCIP_EXPR* constexpr_;
16193 
16194  assert(*nexprtrees > 0);
16195  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
16196  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16197  }
16198 
16199  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16200 
16201  break;
16202  }
16203 
16204  default:
16205  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16206  return SCIP_ERROR;
16207  } /*lint !e788*/
16208 
16209  return SCIP_OKAY;
16210 }
16211 
16212 /**@} */
void SCIPintervalSignPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
static SCIP_RETCODE exprparseReadVariable(BMS_BLKMEM *blkmem, const char **str, SCIP_EXPR **expr, int *nvars, int **varnames, SCIP_HASHTABLE *vartable, SCIP_Real coefficient, const char *varnameendptr)
Definition: expr.c:4781
#define SCIP_EXPRBOUNDSTATUS_CHILDRELAXED
Definition: type_expr.h:208
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12506
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:14948
void SCIPexprFreeDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:5805
void SCIPexprtreeGetVarsUsage(SCIP_EXPRTREE *tree, int *varsusage)
Definition: expr.c:8269
void SCIPquadelemSort(SCIP_QUADELEM *quadelems, int nquadelems)
Definition: expr.c:8552
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:14629
void SCIPexprSortMonomials(SCIP_EXPR *expr)
Definition: expr.c:6645
void SCIPintervalSubScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
void SCIPintervalAbs(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define exprcurvSin
Definition: expr.c:2055
#define QUADELEMS_SWAP(x, y)
Definition: expr.c:8433
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:424
SCIP_EXPROPDATA data
Definition: struct_expr.h:51
static void exprgraphSortConstNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:8992
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14087
static SCIP_RETCODE exprgraphNodeAddParent(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:8685
SCIP_RETCODE SCIPexprSubstituteVars(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR **substexprs)
Definition: expr.c:7544
static SCIP_RETCODE exprsimplifyConvertToPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4122
SCIP_RETCODE SCIPexprgraphAddNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int mindepth, int nchildren, SCIP_EXPRGRAPHNODE **children)
Definition: expr.c:14287
#define QUADELEMS_ISBETTER(a, b)
Definition: expr.c:8430
static SCIP_RETCODE eval(SCIP_EXPR *expr, const vector< Type > &x, SCIP_Real *param, Type &val)
static SCIP_RETCODE exprsimplifyRemoveDuplicatePolynomialChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps)
Definition: expr.c:4146
SCIP_RETCODE SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:15875
SCIP_RETCODE SCIPexprtreeEvalInt(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_INTERVAL *val)
Definition: expr.c:8101
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:14371
methods to interpret (evaluate) an expression tree "fast"
void SCIPexprtreePrint(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, const char **paramnames)
Definition: expr.c:8118
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5577
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:13877
static SCIP_RETCODE polynomialdataMultiplyByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:938
static SCIP_RETCODE exprUnconvertPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren, void **children)
Definition: expr.c:3625
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1374
SCIP_Bool constssorted
Definition: struct_expr.h:158
static SCIP_RETCODE exprgraphNodeAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nexprs, SCIP_EXPRGRAPHNODE **exprs, int *childmap)
Definition: expr.c:8822
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12169
static SCIP_RETCODE exprgraphNodeCreateExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPR **expr, int *nexprvars, int *varidx)
Definition: expr.c:11047
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5350
void SCIPexprPrint(SCIP_EXPR *expr, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, const char **paramnames, SCIP_Real *paramvals)
Definition: expr.c:7624
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14057
static SCIP_RETCODE exprgraphEnsureDepth(SCIP_EXPRGRAPH *exprgraph, int mindepth)
Definition: expr.c:11290
void SCIPsortPtrPtrRealInt(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_MAXSTRLEN
Definition: def.h:196
static void polynomialdataSortMonomials(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata)
Definition: expr.c:783
static SCIP_RETCODE exprgraphNodeSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange)
Definition: expr.c:10721
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_VARTYPE_INTEGER_CHAR
Definition: def.h:94
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
SCIP_Real * exponents
Definition: struct_expr.h:95
#define NULL
Definition: lpi_spx.cpp:129
int SCIPexprgraphGetDepth(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14027
static SCIP_RETCODE polynomialdataMultiplyByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *factordata, int *childmap)
Definition: expr.c:982
static SCIP_RETCODE exprgraphNodeRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:10652
const char * SCIPexpropGetName(SCIP_EXPROP op)
Definition: expr.c:3125
void SCIPexprChgPolynomialConstant(SCIP_EXPR *expr, SCIP_Real constant)
Definition: expr.c:6311
SCIP_RETCODE SCIPexprgraphAddConst(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:14444
SCIP_Bool SCIPintervalIsEmpty(SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprtreeGetMaxDegree(SCIP_EXPRTREE *tree, int *maxdegree)
Definition: expr.c:8072
SCIP_Real * SCIPexprtreeGetParamVals(SCIP_EXPRTREE *tree)
Definition: expr.c:7994
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:14131
SCIP_RETCODE SCIPexprCreateMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial, SCIP_Real coef, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:6657
void SCIPexprgraphCaptureNode(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12147
SCIP_RETCODE SCIPexprgraphCreateNodeQuadratic(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nchildren, SCIP_Real *lincoefs, int nquadelems, SCIP_QUADELEM *quadelems, SCIP_Real constant)
Definition: expr.c:12635
static SCIP_DECL_EXPRFREEDATA(exprFreeDataLinear)
Definition: expr.c:2519
SCIP_Real SCIPexprGetRealPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5413
SCIP_EXPROP op
Definition: struct_expr.h:48
int SCIPexprGetOpIndex(SCIP_EXPR *expr)
Definition: expr.c:5380
SCIP_RETCODE SCIPexprintFreeData(SCIP_EXPRINTDATA **interpreterdata)
data definitions for expressions and expression trees
SCIP_RETCODE SCIPexprSimplify(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR *expr, SCIP_Real eps, int maxexpansionexponent, int nvars, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:7346
SCIP_RETCODE SCIPexprPolynomialPower(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int exponent)
Definition: expr.c:6407
void SCIPexprChgMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real newcoef)
Definition: expr.c:6473
SCIP_Bool SCIPexprHasParam(SCIP_EXPR *expr)
Definition: expr.c:6775
SCIPInterval cos(const SCIPInterval &x)
SCIP_Real SCIPexprGetPolynomialConstant(SCIP_EXPR *expr)
Definition: expr.c:5545
SCIP_EXPRBOUNDSTATUS boundstatus
Definition: struct_expr.h:122
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
void SCIPexprgraphPropagateNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:15002
#define FALSE
Definition: def.h:52
void SCIPintervalMul(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:1864
#define EPSEQ(x, y, eps)
Definition: def.h:147
#define EPSISINT(x, eps)
Definition: def.h:159
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT
Definition: type_expr.h:209
SCIP_Bool SCIPexprAreEqual(SCIP_EXPR *expr1, SCIP_EXPR *expr2, SCIP_Real eps)
Definition: expr.c:7142
void SCIPexprMonomialPower(SCIP_EXPRDATA_MONOMIAL *monomial, int exponent)
Definition: expr.c:6548
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14077
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:7860
static SCIP_RETCODE exprgraphAddExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPR *expr, void **vars, SCIP_EXPRGRAPHNODE **exprnode, SCIP_Bool *exprnodeisnew)
Definition: expr.c:11921
static void exprgraphNodeCheckSeparabilityComponent(SCIP_EXPRGRAPHNODE *node, int *compnr, int nchildcomps, int *childcomps, int nvars, int *varcomps)
Definition: expr.c:11230
static SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:10594
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12298
#define TRUE
Definition: def.h:51
#define SCIPdebug(x)
Definition: pub_message.h:74
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static int calcGrowSize(int num)
Definition: expr.c:105
static SCIP_RETCODE exprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op, int nchildren, SCIP_EXPR **children, SCIP_EXPROPDATA opdata)
Definition: expr.c:3154
static SCIP_RETCODE exprParse(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR **expr, const char *str, int length, const char *lastchar, int *nvars, int **varnames, SCIP_HASHTABLE *vartable, int recursiondepth)
Definition: expr.c:4908
void SCIPsortPtrPtrInt(void **ptrarray1, void **ptrarray2, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPexprtreeCopy(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **targettree, SCIP_EXPRTREE *sourcetree)
Definition: expr.c:8174
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12189
void SCIPexprGetVarsUsage(SCIP_EXPR *expr, int *varsusage)
Definition: expr.c:7119
SCIP_INTERVAL SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12496
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:14927
void SCIPexprReindexVars(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:7582
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
void SCIPintervalPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int * SCIPexprgraphGetNNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14037
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:76
SCIP_RETCODE SCIPexprEvalInt(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7439
#define EPSGE(x, y, eps)
Definition: def.h:151
void SCIPexprSortMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:6738
static void polynomialdataApplyChildmap(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int *childmap)
Definition: expr.c:1141
#define SCIPdebugMessage
Definition: pub_message.h:77
static SCIP_DECL_EXPRCURV(exprcurvDefault)
Definition: expr.c:1401
SCIP_EXPRDATA_MONOMIAL ** monomials
Definition: struct_expr.h:80
static struct exprOpTableElement exprOpTable[]
Definition: expr.c:3079
#define SIGN(x)
Definition: expr.c:45
#define BMSduplicateBlockMemory(mem, ptr, source)
Definition: memory.h:411
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:14489
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:1923
SCIP_RETCODE SCIPexprMultiplyMonomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6513
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8133
SCIP_Bool SCIPquadelemSortedFind(SCIP_QUADELEM *quadelems, int idx1, int idx2, int nquadelems, int *pos)
Definition: expr.c:8577
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8004
BMS_BLKMEM * blkmem
Definition: struct_expr.h:141
SCIP_EXPRCURV curv
Definition: struct_expr.h:128
SCIP_EXPR * root
Definition: struct_expr.h:58
#define exprevalIntTan
Definition: expr.c:2099
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:14238
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12392
int nchildren
Definition: struct_expr.h:49
static void exprgraphPrintNodeDot(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:9360
#define SCIP_EXPRESSION_MAXCHILDEST
Definition: expr.c:39
static void exprgraphUpdateVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Bool *clearreverseprop, SCIP_Bool *boundchanged)
Definition: expr.c:12036
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:13523
SCIP_EXPRCURV SCIPexprcurvMonomial(int nfactors, SCIP_Real *exponents, int *factoridxs, SCIP_EXPRCURV *factorcurv, SCIP_INTERVAL *factorbounds)
Definition: expr.c:344
SCIP_EXPRDATA_MONOMIAL ** SCIPexprGetMonomials(SCIP_EXPR *expr)
Definition: expr.c:5521
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:1287
static SCIP_DECL_EXPREVAL(exprevalVar)
Definition: expr.c:1410
public methods for expressions, expression trees, expression graphs, and related stuff ...
void SCIPintervalMin(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_EXPRCURV SCIPexprcurvMultiply(SCIP_Real factor, SCIP_EXPRCURV curvature)
Definition: expr.c:223
int SCIPexprGetMonomialNFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5567
int SCIPexprGetIntPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5424
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:1966
SCIP_RETCODE SCIPexprtreeCheckCurvature(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:8362
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12229
static SCIP_RETCODE exprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op, SCIP_EXPROPDATA opdata)
Definition: expr.c:9063
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12380
SCIP_RETCODE SCIPexprgraphCreate(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPH **exprgraph, int varssizeinit, int depthinit, SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), void *userdata)
Definition: expr.c:14199
#define SCIP_DECL_EXPRGRAPHVARADDED(x)
Definition: type_expr.h:178
SCIP_HASHMAP * varidxs
Definition: struct_expr.h:153
int SCIPexprgraphGetNodeOperatorIndex(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12239
SCIP_Real coef
Definition: type_expr.h:101
SCIP_Real inf
Definition: intervalarith.h:38
const char * SCIPexprcurvGetName(SCIP_EXPRCURV curv)
Definition: expr.c:457
SCIP_Real SCIPexprgraphGetNodeLinearConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12320
#define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize)
Definition: expr.c:86
SCIP_Real * params
Definition: struct_expr.h:62
#define BMSduplicateBlockMemoryArray(mem, ptr, source, num)
Definition: memory.h:414
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12404
SCIP_RETCODE SCIPexprAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:6289
SCIP_Bool SCIPexprgraphHasNodeNonlinearAncestor(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13763
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12516
SCIP_Bool simplified
Definition: struct_expr.h:132
SCIP_RETCODE SCIPexprCreateQuadratic(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real constant, SCIP_Real *lincoefs, int nquadelems, SCIP_QUADELEM *quadelems)
Definition: expr.c:6206
SCIP_Bool SCIPexprgraphFindConstNode(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:14830
SCIP_Bool SCIPintervalIsEntire(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprEval(SCIP_EXPR *expr, SCIP_Real *varvals, SCIP_Real *param, SCIP_Real *val)
Definition: expr.c:7398
void SCIPexprgraphSetVarsBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_INTERVAL *varbounds)
Definition: expr.c:14099
union SCIP_ExprOpData SCIP_EXPROPDATA
Definition: type_expr.h:89
static SCIP_Bool isUbBetter(SCIP_Real minstrength, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:152
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:120
SCIP_RETCODE SCIPexprgraphCheckCurvature(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop)
Definition: expr.c:15034
SCIP_RETCODE SCIPexprGetMaxDegree(SCIP_EXPR *expr, int *maxdegree)
Definition: expr.c:6794
static void polynomialdataMultiplyByConstant(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_Real factor)
Definition: expr.c:908
#define SCIPerrorMessage
Definition: pub_message.h:45
enum SCIP_ExprOp SCIP_EXPROP
Definition: type_expr.h:88
interval arithmetics for provable bounds
#define SCIPdebugPrintf
Definition: pub_message.h:80
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
void SCIPsortPtrRealInt(void **ptrarray, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Real * SCIPexprGetQuadLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5497
SCIP_EXPRGRAPHNODE *** SCIPexprgraphGetNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14047
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:15839
SCIP_INTERVAL bounds
Definition: struct_expr.h:121
static SCIP_RETCODE exprsimplifyRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4200
void SCIPintervalLog(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprCopyDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **targetexpr, SCIP_EXPR *sourceexpr)
Definition: expr.c:5763
static const char * curvnames[4]
Definition: expr.c:177
int SCIPcalcHashtableSize(int minsize)
Definition: misc.c:964
SCIPInterval sqrt(const SCIPInterval &x)
static SCIP_DECL_EXPRCOPYDATA(exprCopyDataLinear)
Definition: expr.c:2501
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
static SCIP_RETCODE quadraticdataCreate(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_QUADRATIC **quadraticdata, SCIP_Real constant, int nchildren, SCIP_Real *lincoefs, int nquadelems, SCIP_QUADELEM *quadelems)
Definition: expr.c:473
SCIPInterval sign(const SCIPInterval &x)
SCIP_EXPRCURV SCIPexprcurvPower(SCIP_INTERVAL basebounds, SCIP_EXPRCURV basecurv, SCIP_Real exponent)
Definition: expr.c:236
SCIP_Real SCIPexprGetQuadConstant(SCIP_EXPR *expr)
Definition: expr.c:5484
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:1882
static SCIP_RETCODE exprgraphNodeReplaceChild(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE **oldchild, SCIP_EXPRGRAPHNODE *newchild)
Definition: expr.c:8923
void SCIPmessagePrintWarning(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:411
SCIP_EXPRGRAPHNODE *** nodes
Definition: struct_expr.h:146
#define EXPROPEMPTY
Definition: expr.c:3075
static SCIP_Bool exprgraphNodeIsParent(SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:8791
static void polynomialdataFree(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata)
Definition: expr.c:695
#define REALABS(x)
Definition: def.h:146
void SCIPexprMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:6427
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:7974
SCIP_Bool SCIPexprAreMonomialsEqual(SCIP_EXPRDATA_MONOMIAL *monomial1, SCIP_EXPRDATA_MONOMIAL *monomial2, SCIP_Real eps)
Definition: expr.c:6442
SCIP_EXPRGRAPHNODE ** varnodes
Definition: struct_expr.h:151
SCIP_RETCODE SCIPexprgraphCreateNodeLinear(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int ncoefs, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:12609
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:15389
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_CALL(x)
Definition: def.h:258
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12159
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14191
SCIP_RETCODE SCIPexprParse(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR **expr, const char *str, const char *lastchar, int *nvars, int *varnames)
Definition: expr.c:7903
SCIP_RETCODE SCIPexprCreatePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:6254
SCIP_RETCODE SCIPexprCheckCurvature(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_Real *param, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:7481
SCIP_Real sup
Definition: intervalarith.h:39
void SCIPmessagePrintInfo(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:578
void SCIPexprMultiplyPolynomialByConstant(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real factor)
Definition: expr.c:6324
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
static SCIP_RETCODE exprsimplifyUnconvertPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4747
static SCIP_RETCODE exprgraphNodeUpdateBounds(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool parenttightenisinvalid)
Definition: expr.c:9467
void SCIPexprFreeMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial)
Definition: expr.c:6714
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_EXPRCURV *curv)
Definition: expr.c:12419
SCIP_RETCODE SCIPexprMulConstant(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPR *term, SCIP_Real factor)
Definition: expr.c:6026
SCIP_EXPR * SCIPexprtreeGetRoot(SCIP_EXPRTREE *tree)
Definition: expr.c:7964
SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
SCIP_Bool SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13728
SCIP_Real SCIPexprgraphGetNodeOperatorReal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12250
#define SCIP_EXPRBOUNDSTATUS_VALID
Definition: type_expr.h:206
SCIP_RETCODE SCIPexprAdd(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_Real coef1, SCIP_EXPR *term1, SCIP_Real coef2, SCIP_EXPR *term2, SCIP_Real constant)
Definition: expr.c:5868
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12332
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:417
SCIP_RETCODE SCIPexprMultiplyPolynomialByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR *factor, int *childmap)
Definition: expr.c:6361
void SCIPexprMergeMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real eps)
Definition: expr.c:6578
public data structures and miscellaneous methods
static void polynomialdataMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:816
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:5370
SCIP_Real SCIPexprGetSignPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5435
SCIP_EXPRGRAPHNODE ** children
Definition: struct_expr.h:112
#define SCIP_Bool
Definition: def.h:49
void ** vars
Definition: struct_expr.h:60
SCIP_Bool needvarboundprop
Definition: struct_expr.h:165
static SCIP_RETCODE exprgraphNodeEval(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:9402
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13747
SCIPInterval sin(const SCIPInterval &x)
#define BMSallocBlockMemoryArray(mem, ptr, num)
Definition: memory.h:386
void SCIPexprSortQuadElems(SCIP_EXPR *expr)
Definition: expr.c:6242
static SCIP_RETCODE monomialdataEnsureFactorsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomialdata, int minsize)
Definition: expr.c:586
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:14151
static SCIP_RETCODE exprsimplifyFlattenPolynomials(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR *expr, SCIP_Real eps, int maxexpansionexponent)
Definition: expr.c:4317
static SCIP_RETCODE exprgraphNodeRemoveParent(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:8740
BMS_BLKMEM * blkmem
Definition: struct_expr.h:57
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8019
void SCIPintervalSign(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprtreeFreeInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8042
void SCIPintervalSolveBivariateQuadExpressionAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
#define BMSfreeBlockMemoryArray(mem, ptr, num)
Definition: memory.h:421
void SCIPquadelemSqueeze(SCIP_QUADELEM *quadelems, int nquadelems, int *nquadelemsnew)
Definition: expr.c:8629
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:7650
void SCIPintervalSquareRoot(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalQuadBivar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
SCIP_EXPR ** children
Definition: struct_expr.h:50
SCIP_INTERVAL * varbounds
Definition: struct_expr.h:152
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:5360
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:15823
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:14171
static SCIP_Bool exprgraphFindConstNodePos(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *pos)
Definition: expr.c:9008
void SCIPintervalSquare(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprgraphNodeSplitOffLinear(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, int linvarssize, int *nlinvars, void **linvars, SCIP_Real *lincoefs, SCIP_Real *constant)
Definition: expr.c:12712
SCIP_RETCODE SCIPexprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op,...)
Definition: expr.c:5597
void SCIPintervalScalprodScalars(SCIP_Real infinity, SCIP_INTERVAL *resultant, int length, SCIP_INTERVAL *operand1, SCIP_Real *operand2)
SCIP_RETCODE SCIPexprtreeFree(SCIP_EXPRTREE **tree)
Definition: expr.c:8214
SCIP_Bool SCIPexprFindMonomialFactor(SCIP_EXPRDATA_MONOMIAL *monomial, int childidx, int *pos)
Definition: expr.c:6758
static SCIP_DECL_EXPRINTEVAL(exprevalIntDefault)
Definition: expr.c:1392
#define EPSLE(x, y, eps)
Definition: def.h:149
void SCIPintervalMax(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
void SCIPexprgraphFreeNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:13645
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static void exprgraphNodePropagateBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:9560
#define SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED
Definition: type_expr.h:207
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13697
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:102
SCIPInterval log(const SCIPInterval &x)
SCIP_RETCODE SCIPexprtreeAddExpr(SCIP_EXPRTREE *tree, SCIP_EXPR *expr, SCIP_Bool copyexpr)
Definition: expr.c:8339
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:1434
#define SCIP_EXPR_DEGREEINFINITY
Definition: type_expr.h:111
SCIP_EXPROPDATA data
Definition: struct_expr.h:104
SCIP_EXPRGRAPHNODE ** parents
Definition: struct_expr.h:117
#define BMSclearMemory(ptr)
Definition: memory.h:97
SCIP_Real SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5557
static SCIP_RETCODE polynomialdataCopy(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *sourcepolynomialdata)
Definition: expr.c:658
static SCIP_DECL_SORTPTRCOMP(ptrcomp)
Definition: expr.c:121
static SCIP_RETCODE polynomialdataExpandMonomialFactor(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int monomialpos, int factorpos, SCIP_EXPRDATA_POLYNOMIAL *factorpolynomial, int *childmap, int maxexpansionexponent, SCIP_Bool *success)
Definition: expr.c:1170
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12261
void * SCIPexprGetOpData(SCIP_EXPR *expr)
Definition: expr.c:5402
SCIP_EXPROP op
Definition: struct_expr.h:103
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12344
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:1317
#define SCIP_REAL_MAX
Definition: def.h:124
static SCIP_RETCODE exprConvertToPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren)
Definition: expr.c:3185
SCIP_Real SCIPgetRandomReal(SCIP_Real minrandval, SCIP_Real maxrandval, unsigned int *seedp)
Definition: misc.c:7231
int SCIPexprgraphGetNodeIntPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12287
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12199
SCIP_QUADELEM * quadelems
Definition: struct_expr.h:71
static void exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:8714
#define EPSLT(x, y, eps)
Definition: def.h:148
#define SCIP_DECL_EXPRGRAPHVARREMOVE(x)
Definition: type_expr.h:188
static SCIP_RETCODE polynomialdataAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:741
#define EPSGT(x, y, eps)
Definition: def.h:150
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:92
int SCIPexpropGetNChildren(SCIP_EXPROP op)
Definition: expr.c:3135
static void quadraticdataSort(SCIP_EXPRDATA_QUADRATIC *quadraticdata)
Definition: expr.c:511
#define SCIP_VARTYPE_IMPLINT_CHAR
Definition: def.h:95
SCIP_EXPRINTDATA * interpreterdata
Definition: struct_expr.h:63
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:1984
void SCIPexprgraphTightenNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_INTERVAL nodebounds, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:13816
#define exprcurvCos
Definition: expr.c:2084
SCIP_Bool SCIPexprgraphFindVarNode(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_EXPRGRAPHNODE **varnode)
Definition: expr.c:14801
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:7603
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12309
SCIP_Real * SCIPexprGetLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5446
SCIP_Bool SCIPexprtreeHasParam(SCIP_EXPRTREE *tree)
Definition: expr.c:8056
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Real SCIPexprGetOpReal(SCIP_EXPR *expr)
Definition: expr.c:5391
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12219
static SCIP_Bool isLbBetter(SCIP_Real minstrength, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:132
SCIP_RETCODE SCIPexprgraphNodePolynomialAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:12686
SCIP_Bool parentssorted
Definition: struct_expr.h:118
#define SCIP_VARTYPE_CONTINUOUS_CHAR
Definition: def.h:96
SCIP_EXPRGRAPHNODE ** constnodes
Definition: struct_expr.h:157
void SCIPexprFreeShallow(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:5843
SCIP_QUADELEM * SCIPexprGetQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5472
SCIP_RETCODE SCIPexprgraphCreateNodePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:12661
void SCIPintervalExp(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
public methods for message output
static SCIP_RETCODE exprsimplifySeparateLinearFromPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps, int nvars, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:4646
SCIP_RETCODE SCIPexprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op,...)
Definition: expr.c:12526
SCIP_RETCODE SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:13555
int SCIPexprGetNMonomials(SCIP_EXPR *expr)
Definition: expr.c:5533
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE
Definition: type_expr.h:211
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:602
SCIP_RETCODE SCIPhashmapSetImage(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:1944
SCIP_RETCODE SCIPexprtreeSimplify(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:8288
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:15336
#define SCIP_Real
Definition: def.h:123
#define EPSROUND(x, eps)
Definition: def.h:157
#define MIN(x, y)
Definition: memory.c:59
void SCIPintervalIntersect(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE polynomialdataCreate(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:611
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12179
#define SCIP_INVALID
Definition: def.h:142
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPexprAddMonomialFactors(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:6484
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5587
void SCIPexprgraphPrintNode(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: expr.c:13800
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:8388
#define SCIPisFinite(x)
Definition: pub_misc.h:4984
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:9446
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:93
int SCIPexprtreeGetNParams(SCIP_EXPRTREE *tree)
Definition: expr.c:7984
SCIP_RETCODE SCIPexprgraphSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange, SCIP_Bool *domainerror)
Definition: expr.c:15077
int SCIP_ROUNDMODE
Definition: intervalarith.h:45
static SCIP_RETCODE exprsimplifyRemovePolynomialUnusedChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4266
#define exprcurvTan
Definition: expr.c:2102
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE exprgraphMoveNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int newdepth)
Definition: expr.c:11370
static SCIP_RETCODE exprparseFindClosingParenthesis(const char *str, const char **endptr, int length)
Definition: expr.c:4874
SCIP_RETCODE SCIPexprAddToLinear(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nchildren, SCIP_Real *coefs, SCIP_EXPR **children, SCIP_Real constant)
Definition: expr.c:6161
static SCIP_RETCODE exprsimplifyAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nexprs, SCIP_EXPR **exprs, SCIP_Bool comparechildren, SCIP_Real eps, int *childmap)
Definition: expr.c:4003
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:404
SCIP_RETCODE SCIPexprMultiplyPolynomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6338
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12276
#define EPSFLOOR(x, eps)
Definition: def.h:155
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:1901
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:98
static SCIP_DECL_HASHGETKEY(exprparseVarTableGetKey)
Definition: expr.c:4771
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:371
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12368
static SCIP_RETCODE polynomialdataPower(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int exponent)
Definition: expr.c:1071
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14067
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT
Definition: type_expr.h:210
SCIP_RETCODE SCIPexprCreateLinear(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:6124
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_ALLOC(x)
Definition: def.h:269
#define SCIPABORT()
Definition: def.h:230
SCIP_Real SCIPexprGetLinearConstant(SCIP_EXPR *expr)
Definition: expr.c:5459
void SCIPexprtreeSetInterpreterData(SCIP_EXPRTREE *tree, SCIP_EXPRINTDATA *interpreterdata)
Definition: expr.c:8029
SCIP_EXPRCURV SCIPexprcurvAdd(SCIP_EXPRCURV curv1, SCIP_EXPRCURV curv2)
Definition: expr.c:188
struct SCIP_ExprIntData SCIP_EXPRINTDATA
static void quadelemsQuickSort(SCIP_QUADELEM *elems, int start, int end)
Definition: expr.c:8442
static SCIP_RETCODE polynomialdataEnsureMonomialsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int minsize)
Definition: expr.c:724
SCIP_RETCODE SCIPexprtreeSetParams(SCIP_EXPRTREE *tree, int nparams, SCIP_Real *paramvals)
Definition: expr.c:8238
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
int SCIPexprGetNQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5509
static void exprgraphPrintNodeExpression(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, SCIP_Bool printchildrenbounds)
Definition: expr.c:9107
static SCIP_RETCODE exprgraphFindParentByOperator(SCIP_EXPRGRAPH *exprgraph, int nchildren, SCIP_EXPRGRAPHNODE **children, SCIP_EXPROP op, SCIP_EXPROPDATA opdata, SCIP_EXPR **exprchildren, SCIP_EXPRGRAPHNODE **parent)
Definition: expr.c:11458
static void exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:11205
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:14878
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:390
void SCIPintervalSetRoundingModeDownwards(void)
#define EPSZ(x, eps)
Definition: def.h:152
void SCIPintervalPowerScalarInverse(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL basedomain, SCIP_Real exponent, SCIP_INTERVAL image)
int SCIPexprgraphGetNodeDepth(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12209
#define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize)
Definition: expr.c:51
SCIP_EXPRCURV SCIPexprcurvNegate(SCIP_EXPRCURV curvature)
Definition: expr.c:197
SCIP_RETCODE SCIPexprtreeEval(SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
Definition: expr.c:8085
void SCIPexprgraphSetVarBounds(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_INTERVAL varbounds)
Definition: expr.c:14111
void SCIPsortIntReal(int *intarray, SCIP_Real *realarray, int len)
static SCIP_RETCODE exprgraphRemoveVar(SCIP_EXPRGRAPH *exprgraph, int varidx)
Definition: expr.c:11317
#define SCIP_DECL_EXPRGRAPHVARCHGIDX(x)
Definition: type_expr.h:200
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
void SCIPexprgraphEnableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13670
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12356