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-2016 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(infinity, 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(infinity, 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(infinity, 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(infinity, 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(infinity, 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(infinity, 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(infinity, 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 /** point evaluation for user expression */
3064 static
3065 SCIP_DECL_EXPREVAL( exprevalUser )
3066 { /*lint --e{715}*/
3067  SCIP_EXPRDATA_USER* exprdata;
3068 
3069  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3070 
3071  SCIP_CALL( exprdata->eval(exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3072 
3073  return SCIP_OKAY;
3074 }
3075 
3076 /** interval evaluation for user expression */
3077 static
3078 SCIP_DECL_EXPRINTEVAL( exprevalIntUser )
3079 { /*lint --e{715}*/
3080  SCIP_EXPRDATA_USER* exprdata;
3081 
3082  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3083 
3084  if( exprdata->inteval != NULL )
3085  {
3086  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3087  }
3088  else
3089  {
3090  /* if user does not provide interval evaluation, then return a result that is always correct */
3091  SCIPintervalSetEntire(infinity, result);
3092  }
3093 
3094  return SCIP_OKAY;
3095 }
3096 
3097 /** curvature check for user expression */
3098 static
3099 SCIP_DECL_EXPRCURV( exprcurvUser )
3100 {
3101  SCIP_EXPRDATA_USER* exprdata;
3102 
3103  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3104 
3105  if( exprdata->curv != NULL )
3106  {
3107  SCIP_CALL( exprdata->curv(infinity, exprdata->userdata, nargs, argbounds, argcurv, result) );
3108  }
3109  else
3110  {
3111  /* if user does not provide curvature check, then return unknown (which is handled like indefinite) */
3112  *result = SCIP_EXPRCURV_UNKNOWN;
3113  }
3114 
3115  return SCIP_OKAY;
3116 }
3117 
3118 /** data copy for user expression */
3119 static
3120 SCIP_DECL_EXPRCOPYDATA( exprCopyDataUser )
3121 {
3122  SCIP_EXPRDATA_USER* exprdatasource;
3123  SCIP_EXPRDATA_USER* exprdatatarget;
3124 
3125  assert(blkmem != NULL);
3126  assert(opdatatarget != NULL);
3127 
3128  exprdatasource = (SCIP_EXPRDATA_USER*)opdatasource.data;
3129  assert(exprdatasource != NULL);
3130 
3131  /* duplicate expression data */
3132  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, &exprdatatarget, exprdatasource) );
3133 
3134  /* duplicate user expression data, if any */
3135  if( exprdatasource->copydata != NULL )
3136  {
3137  SCIP_CALL( exprdatasource->copydata(blkmem, nchildren, exprdatasource->userdata, &exprdatatarget->userdata) );
3138  }
3139  else
3140  {
3141  /* if no copy function for data, then there has to be no data */
3142  assert(exprdatatarget->userdata == NULL);
3143  }
3144 
3145  opdatatarget->data = (void*)exprdatatarget;
3146 
3147  return SCIP_OKAY;
3148 }
3149 
3150 /** data free for user expression */
3151 static
3152 SCIP_DECL_EXPRFREEDATA( exprFreeDataUser )
3153 {
3154  SCIP_EXPRDATA_USER* exprdata;
3155 
3156  assert(blkmem != NULL);
3157 
3158  exprdata = (SCIP_EXPRDATA_USER*)opdata.data;
3159 
3160  /* free user expression data, if any */
3161  if( exprdata->freedata != NULL )
3162  {
3163  exprdata->freedata(blkmem, nchildren, exprdata->userdata);
3164  }
3165  else
3166  {
3167  assert(exprdata->userdata == NULL);
3168  }
3169 
3170  /* free expression data */
3171  BMSfreeBlockMemory(blkmem, &exprdata);
3172 }
3173 
3174 /** element in table of expression operands */
3175 struct exprOpTableElement
3176 {
3177  const char* name; /**< name of operand (used for printing) */
3178  int nargs; /**< number of arguments (negative if not fixed) */
3179  SCIP_DECL_EXPREVAL ((*eval)); /**< evaluation function */
3180  SCIP_DECL_EXPRINTEVAL ((*inteval)); /**< interval evaluation function */
3181  SCIP_DECL_EXPRCURV ((*curv)); /**< curvature check function */
3182  SCIP_DECL_EXPRCOPYDATA ((*copydata)); /**< expression data copy function, or NULL to only opdata union */
3183  SCIP_DECL_EXPRFREEDATA ((*freedata)); /**< expression data free function, or NULL if nothing to free */
3184 };
3185 
3186 #define EXPROPEMPTY {NULL, -1, NULL, NULL, NULL, NULL, NULL}
3187 
3188 /** table containing for each operand the name, the number of children, and some evaluation functions */
3189 static
3190 struct exprOpTableElement exprOpTable[] =
3191  {
3192  EXPROPEMPTY,
3193  { "variable", 0, exprevalVar, exprevalIntVar, exprcurvVar, NULL, NULL },
3194  { "constant", 0, exprevalConst, exprevalIntConst, exprcurvConst, NULL, NULL },
3195  { "parameter", 0, exprevalParam, exprevalIntParam, exprcurvParam, NULL, NULL },
3197  { "plus", 2, exprevalPlus, exprevalIntPlus, exprcurvPlus, NULL, NULL },
3198  { "minus", 2, exprevalMinus, exprevalIntMinus, exprcurvMinus, NULL, NULL },
3199  { "mul", 2, exprevalMult, exprevalIntMult, exprcurvMult, NULL, NULL },
3200  { "div", 2, exprevalDiv, exprevalIntDiv, exprcurvDiv, NULL, NULL },
3201  { "sqr", 1, exprevalSquare, exprevalIntSquare, exprcurvSquare, NULL, NULL },
3202  { "sqrt", 1, exprevalSquareRoot, exprevalIntSquareRoot, exprcurvSquareRoot, NULL, NULL },
3203  { "realpower", 1, exprevalRealPower, exprevalIntRealPower, exprcurvRealPower, NULL, NULL },
3204  { "intpower", 1, exprevalIntPower, exprevalIntIntPower, exprcurvIntPower, NULL, NULL },
3205  { "signpower", 1, exprevalSignPower, exprevalIntSignPower, exprcurvSignPower, NULL, NULL },
3206  { "exp", 1, exprevalExp, exprevalIntExp, exprcurvExp, NULL, NULL },
3207  { "log", 1, exprevalLog, exprevalIntLog, exprcurvLog, NULL, NULL },
3208  { "sin", 1, exprevalSin, exprevalIntSin, exprcurvSin, NULL, NULL },
3209  { "cos", 1, exprevalCos, exprevalIntCos, exprcurvCos, NULL, NULL },
3210  { "tan", 1, exprevalTan, exprevalIntTan, exprcurvTan, NULL, NULL },
3211  /* { "erf", 1, exprevalErf, exprevalIntErf, exprcurvErf, NULL, NULL }, */
3212  /* { "erfi", 1, exprevalErfi, exprevalIntErfi exprcurvErfi, NULL, NULL }, */
3214  { "min", 2, exprevalMin, exprevalIntMin, exprcurvMin, NULL, NULL },
3215  { "max", 2, exprevalMax, exprevalIntMax, exprcurvMax, NULL, NULL },
3216  { "abs", 1, exprevalAbs, exprevalIntAbs, exprcurvAbs, NULL, NULL },
3217  { "sign", 1, exprevalSign, exprevalIntSign, exprcurvSign, NULL, NULL },
3223  { "sum", -2, exprevalSum, exprevalIntSum, exprcurvSum, NULL, NULL },
3224  { "prod", -2, exprevalProduct, exprevalIntProduct, exprcurvProduct, NULL, NULL },
3225  { "linear", -2, exprevalLinear, exprevalIntLinear, exprcurvLinear, exprCopyDataLinear, exprFreeDataLinear },
3226  { "quadratic", -2, exprevalQuadratic, exprevalIntQuadratic, exprcurvQuadratic, exprCopyDataQuadratic, exprFreeDataQuadratic },
3227  { "polynomial", -2, exprevalPolynomial, exprevalIntPolynomial, exprcurvPolynomial, exprCopyDataPolynomial, exprFreeDataPolynomial },
3228  { "user", -2, exprevalUser, exprevalIntUser, exprcurvUser, exprCopyDataUser, exprFreeDataUser }
3229  };
3230 
3231 /**@} */
3232 
3233 /**@name Expression operand methods */
3234 /**@{ */
3235 
3236 /** gives the name of an operand as string */
3237 const char* SCIPexpropGetName(
3238  SCIP_EXPROP op /**< expression operand */
3239  )
3240 {
3241  assert(op < SCIP_EXPR_LAST);
3242 
3243  return exprOpTable[op].name;
3244 }
3245 
3246 /** gives the number of children of a simple operand */
3248  SCIP_EXPROP op /**< expression operand */
3249  )
3250 {
3251  assert(op < SCIP_EXPR_LAST);
3252 
3253  return exprOpTable[op].nargs;
3254 }
3255 
3256 /**@} */
3257 
3258 /**@name Expressions private methods */
3259 /**@{ */
3260 
3261 /** creates an expression
3262  *
3263  * Note, that the expression is allocated but for the children only the pointer is copied.
3264  */
3265 static
3267  BMS_BLKMEM* blkmem, /**< block memory data structure */
3268  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
3269  SCIP_EXPROP op, /**< operand of expression */
3270  int nchildren, /**< number of children */
3271  SCIP_EXPR** children, /**< children */
3272  SCIP_EXPROPDATA opdata /**< operand data */
3273  )
3274 {
3275  assert(blkmem != NULL);
3276  assert(expr != NULL);
3277  assert(children != NULL || nchildren == 0);
3278  assert(children == NULL || nchildren > 0);
3279 
3280  SCIP_ALLOC( BMSallocBlockMemory(blkmem, expr) );
3281 
3282  (*expr)->op = op;
3283  (*expr)->nchildren = nchildren;
3284  (*expr)->children = children;
3285  (*expr)->data = opdata;
3286 
3287  return SCIP_OKAY;
3288 }
3289 
3290 /** tries to convert a given (operator,operatordata) pair into a polynomial operator with corresponding data
3291  *
3292  * Does not do this for constants.
3293  * If conversion is not possible or operator is already polynomial, *op and *data are
3294  * left untouched.
3295  */
3296 static
3298  BMS_BLKMEM* blkmem, /**< block memory */
3299  SCIP_EXPROP* op, /**< pointer to expression operator */
3300  SCIP_EXPROPDATA* data, /**< pointer to expression data */
3301  int nchildren /**< number of children of operator */
3302  )
3303 {
3304  assert(blkmem != NULL);
3305  assert(op != NULL);
3306  assert(data != NULL);
3307 
3308  switch( *op )
3309  {
3310  case SCIP_EXPR_VARIDX:
3311  case SCIP_EXPR_PARAM:
3312  case SCIP_EXPR_CONST:
3313  break;
3314 
3315  case SCIP_EXPR_PLUS:
3316  {
3317  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3318  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3319  int childidx;
3320  SCIP_Real exponent;
3321 
3322  assert(nchildren == 2);
3323 
3324  /* create monomial for first child */
3325  childidx = 0;
3326  exponent = 1.0;
3327  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3328 
3329  /* create monomial for second child */
3330  childidx = 1;
3331  exponent = 1.0;
3332  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], 1.0, 1, &childidx, &exponent) );
3333 
3334  /* create polynomial for sum of children */
3335  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3336 
3337  *op = SCIP_EXPR_POLYNOMIAL;
3338  data->data = (void*)polynomialdata;
3339 
3340  break;
3341  }
3342 
3343  case SCIP_EXPR_MINUS:
3344  {
3345  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3346  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3347  int childidx;
3348  SCIP_Real exponent;
3349 
3350  assert(nchildren == 2);
3351 
3352  /* create monomial for first child */
3353  childidx = 0;
3354  exponent = 1.0;
3355  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3356 
3357  /* create monomial for second child */
3358  childidx = 1;
3359  exponent = 1.0;
3360  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], -1.0, 1, &childidx, &exponent) );
3361 
3362  /* create polynomial for difference of children */
3363  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3364 
3365  *op = SCIP_EXPR_POLYNOMIAL;
3366  data->data = (void*)polynomialdata;
3367 
3368  break;
3369  }
3370 
3371  case SCIP_EXPR_MUL:
3372  {
3373  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3374  SCIP_EXPRDATA_MONOMIAL* monomial;
3375  int childidx[2];
3376  SCIP_Real exponent[2];
3377 
3378  assert(nchildren == 2);
3379 
3380  /* create monomial for product of children */
3381  childidx[0] = 0;
3382  childidx[1] = 1;
3383  exponent[0] = 1.0;
3384  exponent[1] = 1.0;
3385  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3386 
3387  /* create polynomial */
3388  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3389 
3390  *op = SCIP_EXPR_POLYNOMIAL;
3391  data->data = (void*)polynomialdata;
3392 
3393  break;
3394  }
3395 
3396  case SCIP_EXPR_DIV:
3397  {
3398  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3399  SCIP_EXPRDATA_MONOMIAL* monomial;
3400  int childidx[2];
3401  SCIP_Real exponent[2];
3402 
3403  assert(nchildren == 2);
3404 
3405  /* create monomial for division of children */
3406  childidx[0] = 0;
3407  childidx[1] = 1;
3408  exponent[0] = 1.0;
3409  exponent[1] = -1.0;
3410  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3411 
3412  /* create polynomial */
3413  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3414 
3415  *op = SCIP_EXPR_POLYNOMIAL;
3416  data->data = (void*)polynomialdata;
3417 
3418  break;
3419  }
3420 
3421  case SCIP_EXPR_SQUARE:
3422  {
3423  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3424  SCIP_EXPRDATA_MONOMIAL* monomial;
3425  int childidx;
3426  SCIP_Real exponent;
3427 
3428  assert(nchildren == 1);
3429 
3430  /* create monomial for square of child */
3431  childidx = 0;
3432  exponent = 2.0;
3433  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3434 
3435  /* create polynomial */
3436  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3437 
3438  *op = SCIP_EXPR_POLYNOMIAL;
3439  data->data = (void*)polynomialdata;
3440 
3441  break;
3442  }
3443 
3444  case SCIP_EXPR_SQRT:
3445  {
3446  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3447  SCIP_EXPRDATA_MONOMIAL* monomial;
3448  int childidx;
3449  SCIP_Real exponent;
3450 
3451  assert(nchildren == 1);
3452 
3453  /* create monomial for square root of child */
3454  childidx = 0;
3455  exponent = 0.5;
3456  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3457 
3458  /* create polynomial */
3459  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3460 
3461  *op = SCIP_EXPR_POLYNOMIAL;
3462  data->data = (void*)polynomialdata;
3463 
3464  break;
3465  }
3466 
3467  case SCIP_EXPR_REALPOWER:
3468  {
3469  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3470  SCIP_EXPRDATA_MONOMIAL* monomial;
3471  int childidx;
3472 
3473  assert(nchildren == 1);
3474 
3475  /* convert to child0 to the power of exponent */
3476 
3477  /* create monomial for power of first child */
3478  childidx = 0;
3479  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &data->dbl) );
3480 
3481  /* create polynomial */
3482  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3483 
3484  *op = SCIP_EXPR_POLYNOMIAL;
3485  data->data = (void*)polynomialdata;
3486 
3487  break;
3488  }
3489 
3490  case SCIP_EXPR_SIGNPOWER:
3491  {
3492  SCIP_Real exponent;
3493 
3494  assert(nchildren == 1);
3495 
3496  /* check if exponent is an odd integer */
3497  exponent = data->dbl;
3498  if( EPSISINT(exponent, 0.0) && (int)exponent % 2 != 0 ) /*lint !e835*/
3499  {
3500  /* convert to child0 to the power of exponent, since sign is kept by taking power */
3501  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3502  SCIP_EXPRDATA_MONOMIAL* monomial;
3503  int childidx;
3504 
3505  /* create monomial for power of first child */
3506  childidx = 0;
3507  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3508 
3509  /* create polynomial */
3510  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3511 
3512  *op = SCIP_EXPR_POLYNOMIAL;
3513  data->data = (void*)polynomialdata;
3514  }
3515  /* if exponent is not an odd integer constant, then keep it as signpower expression */
3516  break;
3517  }
3518 
3519  case SCIP_EXPR_INTPOWER:
3520  {
3521  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3522  SCIP_EXPRDATA_MONOMIAL* monomial;
3523  int childidx;
3524  SCIP_Real exponent;
3525 
3526  assert(nchildren == 1);
3527 
3528  /* create monomial for power of child */
3529  childidx = 0;
3530  exponent = data->intval;
3531  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3532 
3533  /* create polynomial */
3534  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3535 
3536  *op = SCIP_EXPR_POLYNOMIAL;
3537  data->data = (void*)polynomialdata;
3538 
3539  break;
3540  }
3541 
3542  case SCIP_EXPR_EXP:
3543  case SCIP_EXPR_LOG:
3544  case SCIP_EXPR_SIN:
3545  case SCIP_EXPR_COS:
3546  case SCIP_EXPR_TAN:
3547  /* case SCIP_EXPR_ERF: */
3548  /* case SCIP_EXPR_ERFI: */
3549  case SCIP_EXPR_MIN:
3550  case SCIP_EXPR_MAX:
3551  case SCIP_EXPR_ABS:
3552  case SCIP_EXPR_SIGN:
3553  case SCIP_EXPR_USER:
3554  break;
3555 
3556  case SCIP_EXPR_SUM:
3557  {
3558  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3559  SCIP_EXPRDATA_MONOMIAL* monomial;
3560  int childidx;
3561  int i;
3562  SCIP_Real exponent;
3563 
3564  /* create empty polynomial */
3565  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, 0.0, FALSE) );
3566  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3567  assert(polynomialdata->monomialssize >= nchildren);
3568 
3569  /* add summands as monomials */
3570  childidx = 0;
3571  exponent = 1.0;
3572  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3573  for( i = 0; i < nchildren; ++i )
3574  {
3575  monomial->childidxs[0] = i;
3576  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3577  }
3578  SCIPexprFreeMonomial(blkmem, &monomial);
3579 
3580  *op = SCIP_EXPR_POLYNOMIAL;
3581  data->data = (void*)polynomialdata;
3582 
3583  break;
3584  }
3585 
3586  case SCIP_EXPR_PRODUCT:
3587  {
3588  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3589  SCIP_EXPRDATA_MONOMIAL* monomial;
3590  int childidx;
3591  int i;
3592  SCIP_Real exponent;
3593 
3594  /* create monomial */
3595  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 0, NULL, NULL) );
3596  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, nchildren) );
3597  exponent = 1.0;
3598  for( i = 0; i < nchildren; ++i )
3599  {
3600  childidx = i;
3601  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
3602  }
3603 
3604  /* create polynomial */
3605  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3606 
3607  *op = SCIP_EXPR_POLYNOMIAL;
3608  data->data = (void*)polynomialdata;
3609 
3610  break;
3611  }
3612 
3613  case SCIP_EXPR_LINEAR:
3614  {
3615  SCIP_Real* lineardata;
3616  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3617  SCIP_EXPRDATA_MONOMIAL* monomial;
3618  int childidx;
3619  int i;
3620  SCIP_Real exponent;
3621 
3622  /* get coefficients of linear term */
3623  lineardata = (SCIP_Real*)data->data;
3624  assert(lineardata != NULL);
3625 
3626  /* create polynomial consisting of constant from linear term */
3627  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, lineardata[nchildren], FALSE) );
3628  /* ensure space for linear coefficients */
3629  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3630  assert(polynomialdata->monomialssize >= nchildren);
3631 
3632  /* add summands as monomials */
3633  childidx = 0;
3634  exponent = 1.0;
3635  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3636  for( i = 0; i < nchildren; ++i )
3637  {
3638  monomial->coef = lineardata[i];
3639  monomial->childidxs[0] = i;
3640  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3641  }
3642  SCIPexprFreeMonomial(blkmem, &monomial);
3643 
3644  /* free linear expression data */
3645  exprFreeDataLinear(blkmem, nchildren, *data);
3646 
3647  *op = SCIP_EXPR_POLYNOMIAL;
3648  data->data = (void*)polynomialdata;
3649 
3650  break;
3651  }
3652 
3653  case SCIP_EXPR_QUADRATIC:
3654  {
3655  SCIP_EXPRDATA_QUADRATIC* quaddata;
3656  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3657  SCIP_EXPRDATA_MONOMIAL* squaremonomial;
3658  SCIP_EXPRDATA_MONOMIAL* bilinmonomial;
3659  SCIP_EXPRDATA_MONOMIAL* linmonomial;
3660  int childidx[2];
3661  SCIP_Real exponent[2];
3662  int i;
3663 
3664  /* get data of quadratic expression */
3665  quaddata = (SCIP_EXPRDATA_QUADRATIC*)data->data;
3666  assert(quaddata != NULL);
3667 
3668  /* create empty polynomial */
3669  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, quaddata->constant, FALSE) );
3670  /* ensure space for linear and quadratic terms */
3671  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, (quaddata->lincoefs != NULL ? nchildren : 0) + quaddata->nquadelems) );
3672  assert(polynomialdata->monomialssize >= quaddata->nquadelems);
3673 
3674  childidx[0] = 0;
3675  childidx[1] = 0;
3676 
3677  /* create monomial templates */
3678  exponent[0] = 2.0;
3679  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &squaremonomial, 1.0, 1, childidx, exponent) );
3680  exponent[0] = 1.0;
3681  exponent[1] = 1.0;
3682  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &bilinmonomial, 1.0, 2, childidx, exponent) );
3683  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &linmonomial, 1.0, 1, childidx, exponent) );
3684 
3685  /* add linear terms as monomials */
3686  if( quaddata->lincoefs != NULL )
3687  for( i = 0; i < nchildren; ++i )
3688  if( quaddata->lincoefs[i] != 0.0 )
3689  {
3690  linmonomial->childidxs[0] = i;
3691  linmonomial->coef = quaddata->lincoefs[i];
3692  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &linmonomial, TRUE) );
3693  }
3694 
3695  /* add quadratic terms as monomials */
3696  for( i = 0; i < quaddata->nquadelems; ++i )
3697  {
3698  if( quaddata->quadelems[i].idx1 == quaddata->quadelems[i].idx2 )
3699  {
3700  squaremonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3701  squaremonomial->coef = quaddata->quadelems[i].coef;
3702  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &squaremonomial, TRUE) );
3703  }
3704  else
3705  {
3706  bilinmonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3707  bilinmonomial->childidxs[1] = quaddata->quadelems[i].idx2;
3708  bilinmonomial->coef = quaddata->quadelems[i].coef;
3709  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &bilinmonomial, TRUE) );
3710  }
3711  }
3712  SCIPexprFreeMonomial(blkmem, &squaremonomial);
3713  SCIPexprFreeMonomial(blkmem, &bilinmonomial);
3714  SCIPexprFreeMonomial(blkmem, &linmonomial);
3715 
3716  /* free quadratic expression data */
3717  exprFreeDataQuadratic(blkmem, nchildren, *data);
3718 
3719  *op = SCIP_EXPR_POLYNOMIAL;
3720  data->data = (void*)polynomialdata;
3721 
3722  break;
3723  }
3724 
3725  case SCIP_EXPR_POLYNOMIAL:
3726  case SCIP_EXPR_LAST:
3727  break;
3728  } /*lint !e788*/
3729 
3730  return SCIP_OKAY;
3731 }
3732 
3733 /** converts polynomial expression back into simpler expression, if possible */
3734 static
3736  BMS_BLKMEM* blkmem, /**< block memory data structure */
3737  SCIP_EXPROP* op, /**< pointer to expression operator */
3738  SCIP_EXPROPDATA* data, /**< pointer to expression data holding polynomial data */
3739  int nchildren, /**< number of children of operator */
3740  void** children /**< children array */
3741  )
3742 {
3743  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3744  SCIP_EXPRDATA_MONOMIAL* monomial;
3745  int maxdegree;
3746  int nlinmonomials;
3747  int i;
3748  int j;
3749 
3750  assert(blkmem != NULL);
3751  assert(op != NULL);
3752  assert(*op == SCIP_EXPR_POLYNOMIAL);
3753  assert(data != NULL);
3754  assert(children != NULL || nchildren == 0);
3755 
3756  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)data->data;
3757  assert(polynomialdata != NULL);
3758 
3759  /* make sure monomials are sorted and merged */
3760  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
3761 
3762  /* if no monomials, then leave as it is */
3763  if( polynomialdata->nmonomials == 0 )
3764  return SCIP_OKAY;
3765 
3766  /* check maximal degree of polynomial only - not considering children expressions
3767  * check number of linear monomials */
3768  maxdegree = 0;
3769  nlinmonomials = 0;
3770  for( i = 0; i < polynomialdata->nmonomials; ++i )
3771  {
3772  int monomialdegree;
3773 
3774  monomial = polynomialdata->monomials[i];
3775  assert(monomial != NULL);
3776 
3777  monomialdegree = 0;
3778  for(j = 0; j < monomial->nfactors; ++j )
3779  {
3780  if( !EPSISINT(monomial->exponents[j], 0.0) || monomial->exponents[j] < 0.0 ) /*lint !e835*/
3781  {
3782  monomialdegree = SCIP_EXPR_DEGREEINFINITY;
3783  break;
3784  }
3785 
3786  monomialdegree += (int)EPSROUND(monomial->exponents[j], 0.0); /*lint !e835*/
3787  }
3788 
3789  if( monomialdegree == SCIP_EXPR_DEGREEINFINITY )
3790  {
3791  maxdegree = SCIP_EXPR_DEGREEINFINITY;
3792  break;
3793  }
3794 
3795  if( monomialdegree == 1 )
3796  ++nlinmonomials;
3797 
3798  if( monomialdegree > maxdegree )
3799  maxdegree = monomialdegree;
3800  }
3801  assert(maxdegree > 0 );
3802 
3803  if( maxdegree == 1 )
3804  {
3805  /* polynomial is a linear expression in children */
3806 
3807  /* polynomial simplification and monomial merging should ensure that monomial i corresponds to child i and that there are not unused children */
3808  assert(polynomialdata->nmonomials == nchildren);
3809  assert(polynomialdata->nmonomials == nlinmonomials);
3810 
3811  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3812  {
3813  /* polynomial is addition of two expressions, so turn into SCIP_EXPR_PLUS */
3814  assert(polynomialdata->monomials[0]->nfactors == 1);
3815  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3816  assert(polynomialdata->monomials[1]->nfactors == 1);
3817  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3818 
3819  polynomialdataFree(blkmem, &polynomialdata);
3820  data->data = NULL;
3821 
3822  /* change operator type to PLUS */
3823  *op = SCIP_EXPR_PLUS;
3824 
3825  return SCIP_OKAY;
3826  }
3827 
3828  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == -1.0 )
3829  {
3830  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3831  assert(polynomialdata->monomials[0]->nfactors == 1);
3832  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3833  assert(polynomialdata->monomials[1]->nfactors == 1);
3834  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3835 
3836  polynomialdataFree(blkmem, &polynomialdata);
3837  data->data = NULL;
3838 
3839  /* change operator type to MINUS */
3840  *op = SCIP_EXPR_MINUS;
3841 
3842  return SCIP_OKAY;
3843  }
3844 
3845  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == -1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3846  {
3847  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3848  void* tmp;
3849 
3850  assert(polynomialdata->monomials[0]->nfactors == 1);
3851  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3852  assert(polynomialdata->monomials[1]->nfactors == 1);
3853  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3854 
3855  polynomialdataFree(blkmem, &polynomialdata);
3856  data->data = NULL;
3857 
3858  /* swap children */
3859  tmp = children[1]; /*lint !e613*/
3860  children[1] = children[0]; /*lint !e613*/
3861  children[0] = tmp; /*lint !e613*/
3862 
3863  /* change operator type to MINUS */
3864  *op = SCIP_EXPR_MINUS;
3865 
3866  return SCIP_OKAY;
3867  }
3868 
3869  if( polynomialdata->constant == 0.0 )
3870  {
3871  /* check if all monomials have coefficient 1.0 */
3872  for( i = 0; i < polynomialdata->nmonomials; ++i )
3873  if( polynomialdata->monomials[i]->coef != 1.0 )
3874  break;
3875 
3876  if( i == polynomialdata->nmonomials )
3877  {
3878  /* polynomial is sum of children, so turn into SCIP_EXPR_SUM */
3879 
3880  polynomialdataFree(blkmem, &polynomialdata);
3881  data->data = NULL;
3882 
3883  /* change operator type to MINUS */
3884  *op = SCIP_EXPR_SUM;
3885 
3886  return SCIP_OKAY;
3887  }
3888  }
3889 
3890  /* turn polynomial into linear expression */
3891  {
3892  SCIP_Real* lindata;
3893 
3894  /* monomial merging should ensure that each child appears in at most one monomial,
3895  * that monomials are ordered according to the child index, and that constant monomials have been removed
3896  */
3897 
3898  /* setup data of linear expression */
3899  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &lindata, polynomialdata->nmonomials + 1) );
3900 
3901  for( i = 0; i < polynomialdata->nmonomials; ++i )
3902  {
3903  assert(polynomialdata->monomials[i]->childidxs[0] == i);
3904  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3905  lindata[i] = polynomialdata->monomials[i]->coef; /*lint !e644*/
3906  }
3907  lindata[i] = polynomialdata->constant;
3908 
3909  polynomialdataFree(blkmem, &polynomialdata);
3910  *op = SCIP_EXPR_LINEAR;
3911  data->data = (void*)lindata;
3912 
3913  return SCIP_OKAY;
3914  }
3915  }
3916 
3917  if( maxdegree == 2 && (polynomialdata->nmonomials > 1 || polynomialdata->constant != 0.0 || polynomialdata->monomials[0]->coef != 1.0) )
3918  {
3919  /* 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 */
3920  SCIP_EXPRDATA_QUADRATIC* quaddata;
3921  int quadelemidx;
3922 
3923  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &quaddata) );
3924  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->quadelems, polynomialdata->nmonomials - nlinmonomials) );
3925  quaddata->nquadelems = polynomialdata->nmonomials - nlinmonomials;
3926  quaddata->constant = polynomialdata->constant;
3927  quaddata->sorted = FALSE; /* quadratic data is sorted different than polynomials */
3928 
3929  if( nlinmonomials > 0 )
3930  {
3931  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->lincoefs, nchildren) );
3932  BMSclearMemoryArray(quaddata->lincoefs, nchildren);
3933  }
3934  else
3935  quaddata->lincoefs = NULL;
3936 
3937  quadelemidx = 0;
3938  for( i = 0; i < polynomialdata->nmonomials; ++i )
3939  {
3940  assert(polynomialdata->monomials[i]->nfactors == 1 || polynomialdata->monomials[i]->nfactors == 2);
3941  if( polynomialdata->monomials[i]->nfactors == 1 )
3942  {
3943  if( polynomialdata->monomials[i]->exponents[0] == 1.0 )
3944  {
3945  /* monomial is a linear term */
3946  assert(quaddata->lincoefs != NULL);
3947  quaddata->lincoefs[polynomialdata->monomials[i]->childidxs[0]] += polynomialdata->monomials[i]->coef;
3948  }
3949  else
3950  {
3951  /* monomial should be a square term */
3952  assert(polynomialdata->monomials[i]->exponents[0] == 2.0);
3953  assert(quadelemidx < quaddata->nquadelems);
3954  quaddata->quadelems[quadelemidx].idx1 = polynomialdata->monomials[i]->childidxs[0];
3955  quaddata->quadelems[quadelemidx].idx2 = polynomialdata->monomials[i]->childidxs[0];
3956  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3957  ++quadelemidx;
3958  }
3959  }
3960  else
3961  {
3962  /* monomial should be a bilinear term */
3963  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3964  assert(polynomialdata->monomials[i]->exponents[1] == 1.0);
3965  assert(quadelemidx < quaddata->nquadelems);
3966  quaddata->quadelems[quadelemidx].idx1 = MIN(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3967  quaddata->quadelems[quadelemidx].idx2 = MAX(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3968  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3969  ++quadelemidx;
3970  }
3971  }
3972  assert(quadelemidx == quaddata->nquadelems);
3973 
3974  polynomialdataFree(blkmem, &polynomialdata);
3975 
3976  *op = SCIP_EXPR_QUADRATIC;
3977  data->data = (void*)quaddata;
3978 
3979  return SCIP_OKAY;
3980  }
3981 
3982  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 1 && polynomialdata->monomials[0]->coef == 1.0 )
3983  {
3984  /* polynomial is product of children */
3985  monomial = polynomialdata->monomials[0];
3986 
3987  if( monomial->nfactors == 1 )
3988  {
3989  /* polynomial is x^k for some k */
3990  assert(monomial->exponents[0] != 1.0); /* should have been handled before */
3991 
3992  if( monomial->exponents[0] == 2.0 )
3993  {
3994  /* polynomial is x^2, so turn into SCIP_EXPR_SQUARE */
3995 
3996  polynomialdataFree(blkmem, &polynomialdata);
3997  data->data = NULL;
3998 
3999  *op = SCIP_EXPR_SQUARE;
4000 
4001  return SCIP_OKAY;
4002  }
4003 
4004  if( EPSISINT(monomial->exponents[0], 0.0) ) /*lint !e835*/
4005  {
4006  /* k is an integer, so turn into SCIP_EXPR_INTPOWER */
4007  int exponent;
4008 
4009  exponent = (int)EPSROUND(monomial->exponents[0], 0.0); /*lint !e835*/
4010 
4011  polynomialdataFree(blkmem, &polynomialdata);
4012 
4013  *op = SCIP_EXPR_INTPOWER;
4014  data->intval = exponent;
4015 
4016  return SCIP_OKAY;
4017  }
4018 
4019  if( monomial->exponents[0] == 0.5 )
4020  {
4021  /* polynomial is sqrt(x), so turn into SCIP_EXPR_SQRT */
4022 
4023  polynomialdataFree(blkmem, &polynomialdata);
4024  data->data = NULL;
4025 
4026  *op = SCIP_EXPR_SQRT;
4027 
4028  return SCIP_OKAY;
4029  }
4030 
4031  {
4032  /* polynomial is x^a with a some real number, so turn into SCIP_EXPR_REALPOWER */
4033  SCIP_Real exponent;
4034 
4035  exponent = monomial->exponents[0];
4036 
4037  polynomialdataFree(blkmem, &polynomialdata);
4038 
4039  *op = SCIP_EXPR_REALPOWER;
4040  data->dbl = exponent;
4041 
4042  return SCIP_OKAY;
4043  }
4044  }
4045 
4046  if( maxdegree == 2 && monomial->nfactors == 2 )
4047  {
4048  /* polynomial is product of two children, so turn into SCIP_EXPR_MUL */
4049  assert(monomial->exponents[0] == 1.0);
4050  assert(monomial->exponents[1] == 1.0);
4051 
4052  polynomialdataFree(blkmem, &polynomialdata);
4053  data->data = NULL;
4054 
4055  *op = SCIP_EXPR_MUL;
4056 
4057  return SCIP_OKAY;
4058  }
4059 
4060  if( maxdegree == monomial->nfactors )
4061  {
4062  /* polynomial is a product of n children, so turn into SCIP_EXPR_PRODUCT */
4063 
4064  polynomialdataFree(blkmem, &polynomialdata);
4065  data->data = NULL;
4066 
4067  *op = SCIP_EXPR_PRODUCT;
4068 
4069  return SCIP_OKAY;
4070  }
4071 
4072  if( monomial->nfactors == 2 && monomial->exponents[0] == 1.0 && monomial->exponents[1] == -1.0 )
4073  {
4074  /* polynomial is x/y, so turn into SCIP_EXPR_DIV */
4075 
4076  polynomialdataFree(blkmem, &polynomialdata);
4077  data->data = NULL;
4078 
4079  *op = SCIP_EXPR_DIV;
4080 
4081  return SCIP_OKAY;
4082  }
4083 
4084  if( monomial->nfactors == 2 && monomial->exponents[0] == -1.0 && monomial->exponents[1] == 1.0 )
4085  {
4086  /* polynomial is y/x, so turn into SCIP_EXPR_DIV */
4087  void* tmp;
4088 
4089  polynomialdataFree(blkmem, &polynomialdata);
4090  data->data = NULL;
4091 
4092  /* swap children */
4093  tmp = children[1]; /*lint !e613*/
4094  children[1] = children[0]; /*lint !e613*/
4095  children[0] = tmp; /*lint !e613*/
4096 
4097  *op = SCIP_EXPR_DIV;
4098 
4099  return SCIP_OKAY;
4100  }
4101  }
4102 
4103  return SCIP_OKAY;
4104 }
4105 
4106 /** adds copies of expressions to the array of children of a sum, product, linear, quadratic, or polynomial expression
4107  *
4108  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
4109  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
4110  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
4111  */
4112 static
4114  BMS_BLKMEM* blkmem, /**< block memory */
4115  SCIP_EXPR* expr, /**< quadratic or polynomial expression */
4116  int nexprs, /**< number of expressions to add */
4117  SCIP_EXPR** exprs, /**< expressions to add */
4118  SCIP_Bool comparechildren, /**< whether to compare expressions with already existing children (no effect for sum and product) */
4119  SCIP_Real eps, /**< which epsilon to use when comparing expressions */
4120  int* childmap /**< array where to store mapping of indices from exprs to children array in expr, or NULL if not of interest */
4121  )
4122 {
4123  int i;
4124 
4125  assert(blkmem != NULL);
4126  assert(expr != NULL);
4127  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);
4128  assert(exprs != NULL || nexprs == 0);
4129 
4130  if( nexprs == 0 )
4131  return SCIP_OKAY;
4132 
4133  switch( expr->op )
4134  {
4135  case SCIP_EXPR_SUM:
4136  case SCIP_EXPR_PRODUCT:
4137  {
4138  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4139  for( i = 0; i < nexprs; ++i )
4140  {
4141  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren + i], exprs[i]) ); /*lint !e613*/
4142  if( childmap != NULL )
4143  childmap[i] = expr->nchildren + i;
4144  }
4145  expr->nchildren += nexprs;
4146 
4147  break;
4148  }
4149 
4150  case SCIP_EXPR_LINEAR:
4151  case SCIP_EXPR_QUADRATIC:
4152  case SCIP_EXPR_POLYNOMIAL:
4153  {
4154  int j;
4155  int orignchildren;
4156  SCIP_Bool existsalready;
4157 
4158  orignchildren = expr->nchildren;
4159  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4160 
4161  for( i = 0; i < nexprs; ++i )
4162  {
4163  existsalready = FALSE;
4164  if( comparechildren )
4165  for( j = 0; j < orignchildren; ++j )
4166  /* during simplification of polynomials, their may be NULL's in children array */
4167  if( expr->children[j] != NULL && SCIPexprAreEqual(expr->children[j], exprs[i], eps) ) /*lint !e613*/
4168  {
4169  existsalready = TRUE;
4170  break;
4171  }
4172 
4173  if( !existsalready )
4174  {
4175  /* add copy of exprs[j] to children array */
4176  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren], exprs[i]) ); /*lint !e613*/
4177  if( childmap != NULL )
4178  childmap[i] = expr->nchildren;
4179  ++expr->nchildren;
4180  }
4181  else
4182  {
4183  if( childmap != NULL )
4184  childmap[i] = j; /*lint !e644*/
4185  if( expr->op == SCIP_EXPR_LINEAR )
4186  {
4187  /* if linear expression, increase coefficient by 1.0 */
4188  ((SCIP_Real*)expr->data.data)[j] += 1.0;
4189  }
4190  }
4191  }
4192 
4193  /* shrink children array to actually used size */
4194  assert(comparechildren || expr->nchildren == orignchildren + nexprs);
4195  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, orignchildren + nexprs, expr->nchildren) );
4196 
4197  if( expr->op == SCIP_EXPR_LINEAR && expr->nchildren > orignchildren )
4198  {
4199  /* if linear expression, then add 1.0 coefficients for new expressions */
4200  SCIP_Real* data;
4201 
4202  data = (SCIP_Real*)expr->data.data;
4203  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, expr->nchildren + 1) );
4204  data[expr->nchildren] = data[orignchildren]; /* move constant from old end to new end */
4205  for( i = orignchildren; i < expr->nchildren; ++i )
4206  data[i] = 1.0;
4207  expr->data.data = (void*)data;
4208  }
4209  else if( expr->op == SCIP_EXPR_QUADRATIC && expr->nchildren > orignchildren )
4210  {
4211  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
4213 
4214  data = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
4215  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, expr->nchildren) );
4216  BMSclearMemoryArray(&data->lincoefs[orignchildren], expr->nchildren - orignchildren); /*lint !e866*/
4217  }
4218 
4219  break;
4220  }
4221 
4222  default:
4223  SCIPerrorMessage("exprsimplifyAddChildren cannot be called for operand %d\n", expr->op);
4224  return SCIP_INVALIDDATA;
4225  } /*lint !e788*/
4226 
4227  return SCIP_OKAY;
4228 }
4229 
4230 /** converts expressions into polynomials, where possible and obvious */
4231 static
4233  BMS_BLKMEM* blkmem, /**< block memory data structure */
4234  SCIP_EXPR* expr /**< expression to convert */
4235  )
4236 {
4237  int i;
4238 
4239  assert(expr != NULL);
4240 
4241  for( i = 0; i < expr->nchildren; ++i )
4242  {
4244  }
4245 
4246  SCIP_CALL( exprConvertToPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren) );
4247 
4248  return SCIP_OKAY;
4249 }
4250 
4251 /** removes duplicate children in a polynomial expression
4252  *
4253  * Leaves NULL's in children array.
4254  */
4255 static
4257  BMS_BLKMEM* blkmem, /**< block memory data structure */
4258  SCIP_EXPR* expr, /**< expression */
4259  SCIP_Real eps /**< threshold for zero */
4260  )
4261 {
4262  SCIP_Bool foundduplicates;
4263  int* childmap;
4264  int i;
4265  int j;
4266 
4267  assert(blkmem != NULL);
4268  assert(expr != NULL);
4269  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4270 
4271  if( expr->nchildren == 0 )
4272  return SCIP_OKAY;
4273 
4274  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4275 
4276  foundduplicates = FALSE;
4277  for( i = 0; i < expr->nchildren; ++i )
4278  {
4279  if( expr->children[i] == NULL )
4280  continue;
4281  childmap[i] = i; /*lint !e644*/
4282 
4283  for( j = i+1; j < expr->nchildren; ++j )
4284  {
4285  if( expr->children[j] == NULL )
4286  continue;
4287 
4288  if( SCIPexprAreEqual(expr->children[i], expr->children[j], eps) )
4289  {
4290  /* forget about expr j and remember that is to be replaced by i */
4291  SCIPexprFreeDeep(blkmem, &expr->children[j]);
4292  childmap[j] = i;
4293  foundduplicates = TRUE;
4294  }
4295  }
4296  }
4297 
4298  /* apply childmap to monomials */
4299  if( foundduplicates )
4301 
4302  /* free childmap */
4303  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4304 
4305  return SCIP_OKAY;
4306 }
4307 
4308 /** eliminates NULL's in children array and shrinks it to actual size */
4309 static
4311  BMS_BLKMEM* blkmem, /**< block memory data structure */
4312  SCIP_EXPR* expr /**< expression */
4313  )
4314 {
4315  int* childmap;
4316  int lastnonnull;
4317  int i;
4318 
4319  assert(blkmem != NULL);
4320  assert(expr != NULL);
4321  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4322 
4323  if( expr->nchildren == 0 )
4324  return SCIP_OKAY;
4325 
4326  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4327 
4328  /* close gaps in children array */
4329  lastnonnull = expr->nchildren-1;
4330  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4331  --lastnonnull;
4332  for( i = 0; i <= lastnonnull; ++i )
4333  {
4334  if( expr->children[i] != NULL )
4335  {
4336  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
4337  continue;
4338  }
4339  assert(expr->children[lastnonnull] != NULL);
4340 
4341  /* move child at lastnonnull to position i */
4342  expr->children[i] = expr->children[lastnonnull];
4343  expr->children[lastnonnull] = NULL;
4344  childmap[lastnonnull] = i;
4345 
4346  /* update lastnonnull */
4347  --lastnonnull;
4348  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4349  --lastnonnull;
4350  }
4351  assert(i > lastnonnull);
4352 
4353  /* apply childmap to monomials */
4354  if( lastnonnull < expr->nchildren-1 )
4356 
4357  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4358 
4359  /* shrink children array */
4360  if( lastnonnull >= 0 )
4361  {
4362  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, lastnonnull+1) );
4363  expr->nchildren = lastnonnull+1;
4364  }
4365  else
4366  {
4367  BMSfreeBlockMemoryArray(blkmem, &expr->children, expr->nchildren);
4368  expr->nchildren = 0;
4369  }
4370 
4371  return SCIP_OKAY;
4372 }
4373 
4374 /** checks which children are still in use and frees those which are not */
4375 static
4377  BMS_BLKMEM* blkmem, /**< block memory data structure */
4378  SCIP_EXPR* expr /**< polynomial expression */
4379  )
4380 {
4381  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4382  SCIP_EXPRDATA_MONOMIAL* monomial;
4383  SCIP_Bool* childinuse;
4384  int i;
4385  int j;
4386 
4387  assert(blkmem != NULL);
4388  assert(expr != NULL);
4389 
4390  if( expr->nchildren == 0 )
4391  return SCIP_OKAY;
4392 
4393  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4394  assert(polynomialdata != NULL);
4395 
4396  /* check which children are still in use */
4397  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, expr->nchildren) );
4398  BMSclearMemoryArray(childinuse, expr->nchildren); /*lint !e644*/
4399  for( i = 0; i < polynomialdata->nmonomials; ++i )
4400  {
4401  monomial = polynomialdata->monomials[i];
4402  assert(monomial != NULL);
4403 
4404  for( j = 0; j < monomial->nfactors; ++j )
4405  {
4406  assert(monomial->childidxs[j] >= 0);
4407  assert(monomial->childidxs[j] < expr->nchildren);
4408  childinuse[monomial->childidxs[j]] = TRUE;
4409  }
4410  }
4411 
4412  /* free children that are not used in any monomial */
4413  for( i = 0; i < expr->nchildren; ++i )
4414  if( expr->children[i] != NULL && !childinuse[i] )
4415  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4416 
4417  BMSfreeBlockMemoryArray(blkmem, &childinuse, expr->nchildren);
4418 
4419  return SCIP_OKAY;
4420 }
4421 
4422 /** flattens polynomials in polynomials, check for constants in non-polynomials expressions
4423  *
4424  * exprsimplifyConvertToPolynomials should have been called before to eliminate simple polynomial operands.
4425  */
4426 static
4428  BMS_BLKMEM* blkmem, /**< block memory data structure */
4429  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4430  SCIP_EXPR* expr, /**< expression */
4431  SCIP_Real eps, /**< threshold, under which values are treat as 0 */
4432  int maxexpansionexponent/**< maximal exponent for which we still expand non-monomial polynomials */
4433  )
4434 {
4435  int i;
4436 
4437  assert(expr != NULL);
4438 
4439  for( i = 0; i < expr->nchildren; ++i )
4440  {
4441  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr->children[i], eps, maxexpansionexponent) );
4442  }
4443 
4444  switch( SCIPexprGetOperator(expr) )
4445  {
4446  case SCIP_EXPR_VARIDX:
4447  case SCIP_EXPR_CONST:
4448  case SCIP_EXPR_PARAM:
4449  case SCIP_EXPR_PLUS:
4450  case SCIP_EXPR_MINUS:
4451  case SCIP_EXPR_MUL:
4452  case SCIP_EXPR_DIV:
4453  case SCIP_EXPR_SQUARE:
4454  case SCIP_EXPR_SQRT:
4455  case SCIP_EXPR_INTPOWER:
4456  case SCIP_EXPR_REALPOWER:
4457  case SCIP_EXPR_SIGNPOWER:
4458  break;
4459 
4460  case SCIP_EXPR_EXP:
4461  case SCIP_EXPR_LOG:
4462  case SCIP_EXPR_SIN:
4463  case SCIP_EXPR_COS:
4464  case SCIP_EXPR_TAN:
4465  /* case SCIP_EXPR_ERF: */
4466  /* case SCIP_EXPR_ERFI: */
4467  case SCIP_EXPR_ABS:
4468  case SCIP_EXPR_SIGN:
4469  {
4470  /* check if argument is a constant */
4471  if( (expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) ||
4472  expr->children[0]->op == SCIP_EXPR_CONST )
4473  {
4474  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4475  SCIP_Real exprval;
4476 
4477  /* since child0 has no children and it's polynomial was flattened, it should have no monomials */
4478  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4479 
4480  /* evaluate expression in constant polynomial */
4481  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4482 
4483  /* create polynomial */
4484  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4485 
4486  expr->op = SCIP_EXPR_POLYNOMIAL;
4487  expr->data.data = (void*)polynomialdata;
4488 
4489  /* forget child */
4490  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4491  BMSfreeBlockMemoryArray(blkmem, &expr->children, 1);
4492  expr->nchildren = 0;
4493  }
4494 
4495  break;
4496  }
4497 
4498  case SCIP_EXPR_MIN:
4499  case SCIP_EXPR_MAX:
4500  {
4501  /* check if both arguments are constants */
4502  if( ((expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) || expr->children[0]->op == SCIP_EXPR_CONST) &&
4503  ((expr->children[1]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[1]) == 0) || expr->children[1]->op == SCIP_EXPR_CONST) )
4504  {
4505  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4506  SCIP_Real exprval;
4507 
4508  /* since children have no children and it's polynomial was flattened, it should have no monomials */
4509  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4510  assert(expr->children[1]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[1]) == 0);
4511 
4512  /* evaluate expression in constants */
4513  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4514 
4515  /* create polynomial */
4516  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4517 
4518  expr->op = SCIP_EXPR_POLYNOMIAL;
4519  expr->data.data = (void*)polynomialdata;
4520 
4521  /* forget children */
4522  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4523  SCIPexprFreeDeep(blkmem, &expr->children[1]);
4524  BMSfreeBlockMemoryArray(blkmem, &expr->children, 2);
4525  expr->nchildren = 0;
4526  }
4527 
4528  break;
4529  }
4530 
4531  case SCIP_EXPR_SUM:
4532  case SCIP_EXPR_PRODUCT:
4533  case SCIP_EXPR_LINEAR:
4534  case SCIP_EXPR_QUADRATIC:
4535  case SCIP_EXPR_USER:
4536  break;
4537 
4538  case SCIP_EXPR_POLYNOMIAL:
4539  {
4540  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4541  SCIP_EXPRDATA_MONOMIAL* monomial;
4542  SCIP_Bool removechild;
4543  int* childmap;
4544  int childmapsize;
4545  int j;
4546 
4547  /* simplify current polynomial */
4549  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4550 
4551  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4552  assert(polynomialdata != NULL);
4553 
4554  SCIPdebugMessage("expand factors in expression ");
4555  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4556  SCIPdebugPrintf("\n");
4557 
4558  childmap = NULL;
4559  childmapsize = 0;
4560 
4561  /* resolve children that are constants
4562  * we do this first, because it reduces the degree and number of factors in the monomials,
4563  * 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
4564  */
4565  for( i = 0; i < expr->nchildren; ++i )
4566  {
4567  if( expr->children[i] == NULL )
4568  continue;
4569 
4570  if( SCIPexprGetOperator(expr->children[i]) != SCIP_EXPR_CONST )
4571  continue;
4572 
4573  removechild = TRUE; /* we intend to delete children[i] */
4574 
4575  if( childmapsize < expr->children[i]->nchildren )
4576  {
4577  int newsize;
4578 
4579  newsize = calcGrowSize(expr->children[i]->nchildren);
4580  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4581  childmapsize = newsize;
4582  }
4583 
4584  /* put constant of child i into every monomial where child i is used */
4585  for( j = 0; j < polynomialdata->nmonomials; ++j )
4586  {
4587  int factorpos;
4588  SCIP_Bool success;
4589 
4590  monomial = polynomialdata->monomials[j];
4591  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4592  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4593 
4594  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4595  {
4596  assert(factorpos >= 0);
4597  assert(factorpos < monomial->nfactors);
4598  /* assert that factors have been merged */
4599  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4600  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4601 
4602  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4603  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4604  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4605 
4606  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && SCIPexprGetOpReal(expr->children[i]) < 0.0 ) /*lint !e835*/
4607  {
4608  /* if constant is negative and our exponent is not integer, then cannot do expansion */
4609  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n",
4610  SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4611  success = FALSE;
4612  }
4613  else
4614  {
4615  monomial->coef *= pow(SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4616 
4617  /* move last factor to position factorpos */
4618  if( factorpos < monomial->nfactors-1 )
4619  {
4620  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
4621  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
4622  }
4623  --monomial->nfactors;
4624  monomial->sorted = FALSE;
4625  polynomialdata->sorted = FALSE;
4626 
4627  success = TRUE;
4628  }
4629 
4630  if( !success )
4631  removechild = FALSE;
4632  }
4633  }
4634 
4635  /* forget about child i, if it is not used anymore */
4636  if( removechild )
4637  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4638 
4639  /* simplify current polynomial again */
4640  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4641  }
4642 
4643  /* try to resolve children that are polynomials itself */
4644  for( i = 0; i < expr->nchildren; ++i )
4645  {
4646  if( expr->children[i] == NULL )
4647  continue;
4648 
4650  continue;
4651 
4652  removechild = TRUE; /* we intend to delete children[i] */
4653 
4654  if( childmapsize < expr->children[i]->nchildren )
4655  {
4656  int newsize;
4657 
4658  newsize = calcGrowSize(expr->children[i]->nchildren);
4659  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4660  childmapsize = newsize;
4661  }
4662 
4663  /* add children of child i */
4664  SCIP_CALL( exprsimplifyAddChildren(blkmem, expr, expr->children[i]->nchildren, expr->children[i]->children, TRUE, eps, childmap) );
4665 
4666  /* put polynomial of child i into every monomial where child i is used */
4667  j = 0;
4668  while( j < polynomialdata->nmonomials )
4669  {
4670  int factorpos;
4671  SCIP_Bool success;
4672 
4673  monomial = polynomialdata->monomials[j];
4674  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4675  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4676 
4677  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4678  {
4679  assert(factorpos >= 0);
4680  assert(factorpos < monomial->nfactors);
4681  /* assert that factors have been merged */
4682  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4683  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4684 
4685  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4686  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4687  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4688 
4689  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
4690  (SCIP_EXPRDATA_POLYNOMIAL*)expr->children[i]->data.data, childmap, maxexpansionexponent, &success) );
4691 
4692  if( !success )
4693  {
4694  removechild = FALSE;
4695  ++j;
4696  }
4697  }
4698  else
4699  ++j;
4700 
4701  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
4702  * we thus repeat with index j, if a factor was successfully expanded
4703  */
4704  }
4705 
4706  /* forget about child i, if it is not used anymore */
4707  if( removechild )
4708  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4709 
4710  /* simplify current polynomial again */
4711  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4712  }
4713 
4714  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
4715 
4716  /* free children that are not in use anymore */
4718 
4719  /* remove NULLs from children array */
4721 
4722  /* if no children left, then it's a constant polynomial -> change into EXPR_CONST */
4723  if( expr->nchildren == 0 )
4724  {
4725  SCIP_Real val;
4726 
4727  /* if no children, then it should also have no monomials */
4728  assert(polynomialdata->nmonomials == 0);
4729 
4730  val = polynomialdata->constant;
4731  polynomialdataFree(blkmem, &polynomialdata);
4732 
4733  expr->op = SCIP_EXPR_CONST;
4734  expr->data.dbl = val;
4735  }
4736 
4737  SCIPdebugMessage("-> ");
4738  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4739  SCIPdebugPrintf("\n");
4740 
4741  break;
4742  }
4743 
4744  case SCIP_EXPR_LAST:
4745  break;
4746  } /*lint !e788*/
4747 
4748  return SCIP_OKAY;
4749 }
4750 
4751 /** separates linear monomials from an expression, if it is a polynomial expression
4752  *
4753  * Separates only those linear terms whose variable is not used otherwise in the expression.
4754  */
4755 static
4757  BMS_BLKMEM* blkmem, /**< block memory data structure */
4758  SCIP_EXPR* expr, /**< expression */
4759  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
4760  int nvars, /**< number of variables in expression */
4761  int* nlinvars, /**< buffer to store number of linear variables in linear part */
4762  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part */
4763  SCIP_Real* lincoefs /**< array to store coefficients of linear part */
4764  )
4765 {
4766  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4767  SCIP_EXPRDATA_MONOMIAL* monomial;
4768  int* varsusage;
4769  int* childusage;
4770  int childidx;
4771  int i;
4772  int j;
4773 
4774  assert(blkmem != NULL);
4775  assert(expr != NULL);
4776  assert(nlinvars != NULL);
4777  assert(linidxs != NULL);
4778  assert(lincoefs != NULL);
4779 
4780  *nlinvars = 0;
4781 
4783  return SCIP_OKAY;
4784 
4785  if( SCIPexprGetNChildren(expr) == 0 )
4786  return SCIP_OKAY;
4787 
4788  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4789  assert(polynomialdata != NULL);
4790 
4791  /* get variable usage */
4792  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &varsusage, nvars) );
4793  BMSclearMemoryArray(varsusage, nvars); /*lint !e644*/
4794  SCIPexprGetVarsUsage(expr, varsusage);
4795 
4796  /* get child usage: how often each child is used in the polynomial */
4797  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childusage, expr->nchildren) );
4798  BMSclearMemoryArray(childusage, expr->nchildren); /*lint !e644*/
4799  for( i = 0; i < polynomialdata->nmonomials; ++i )
4800  {
4801  monomial = polynomialdata->monomials[i];
4802  assert(monomial != NULL);
4803  for( j = 0; j < monomial->nfactors; ++j )
4804  {
4805  assert(monomial->childidxs[j] >= 0);
4806  assert(monomial->childidxs[j] < expr->nchildren);
4807  ++childusage[monomial->childidxs[j]];
4808  }
4809  }
4810 
4811  /* move linear monomials out of polynomial */
4812  for( i = 0; i < polynomialdata->nmonomials; ++i )
4813  {
4814  monomial = polynomialdata->monomials[i];
4815  assert(monomial != NULL);
4816  if( monomial->nfactors != 1 )
4817  continue;
4818  if( monomial->exponents[0] != 1.0 )
4819  continue;
4820  childidx = monomial->childidxs[0];
4821  if( SCIPexprGetOperator(expr->children[childidx]) != SCIP_EXPR_VARIDX )
4822  continue;
4823 
4824  /* we are at a linear monomial in a variable */
4825  assert(SCIPexprGetOpIndex(expr->children[childidx]) < nvars);
4826  if( childusage[childidx] == 1 && varsusage[SCIPexprGetOpIndex(expr->children[childidx])] == 1 )
4827  {
4828  /* if the child expression is not used in another monomial (which would due to merging be not linear)
4829  * and if the variable is not used somewhere else in the tree,
4830  * then move this monomial into linear part and free child
4831  */
4832  linidxs[*nlinvars] = SCIPexprGetOpIndex(expr->children[childidx]);
4833  lincoefs[*nlinvars] = monomial->coef;
4834  ++*nlinvars;
4835 
4836  SCIPexprFreeDeep(blkmem, &expr->children[childidx]);
4837  monomial->coef = 0.0;
4838  monomial->nfactors = 0;
4839  }
4840  }
4841 
4842  BMSfreeBlockMemoryArray(blkmem, &varsusage, nvars);
4843  BMSfreeBlockMemoryArray(blkmem, &childusage, expr->nchildren);
4844 
4845  if( *nlinvars > 0 )
4846  {
4847  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
4848  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, FALSE);
4850  }
4851 
4852  return SCIP_OKAY;
4853 }
4854 
4855 /** converts polynomial expressions back into simpler expressions, where possible */
4856 static
4858  BMS_BLKMEM* blkmem, /**< block memory data structure */
4859  SCIP_EXPR* expr /**< expression to convert back */
4860  )
4861 {
4862  int i;
4863 
4864  assert(blkmem != NULL);
4865  assert(expr != NULL);
4866 
4867  for( i = 0; i < expr->nchildren; ++i )
4868  {
4870  }
4871 
4872  if( expr->op != SCIP_EXPR_POLYNOMIAL )
4873  return SCIP_OKAY;
4874 
4875  SCIP_CALL( exprUnconvertPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren, (void**)expr->children) );
4876 
4877  return SCIP_OKAY;
4878 }
4879 
4880 static
4881 SCIP_DECL_HASHGETKEY( exprparseVarTableGetKey )
4882 { /*lint --e{715}*/
4883  return (void*)((char*)elem + sizeof(int));
4884 }
4885 
4886 /** parses a variable name from a string and creates corresponding expression
4887  *
4888  * Creates a new variable index if variable not seen before, updates varnames and vartable structures.
4889  */
4890 static
4892  BMS_BLKMEM* blkmem, /**< block memory data structure */
4893  const char** str, /**< pointer to the string to be parsed */
4894  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
4895  int* nvars, /**< running number of encountered variables so far */
4896  int** varnames, /**< pointer to buffer to store new variable names */
4897  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
4898  SCIP_Real coefficient, /**< coefficient to be used when creating the expression */
4899  const char* varnameendptr /**< if a <varname> should be parsed, set this to NULL. Then, str points to the '<'
4900  else, str should point to the first letter of the varname, and varnameendptr should
4901  point one char behind the last char of the variable name */
4902  )
4903 {
4904  int namelength;
4905  int varidx;
4906  char varname[SCIP_MAXSTRLEN];
4907  void* element;
4908 
4909  assert(blkmem != NULL);
4910  assert(str != NULL);
4911  assert(expr != NULL);
4912  assert(nvars != NULL);
4913  assert(varnames != NULL);
4914  assert(vartable != NULL);
4915 
4916  if( varnameendptr == NULL )
4917  {
4918  ++*str;
4919  varnameendptr = *str;
4920  while( varnameendptr[0] != '>' )
4921  ++varnameendptr;
4922  }
4923 
4924  namelength = varnameendptr - *str; /*lint !e712*/
4925  if( namelength >= SCIP_MAXSTRLEN )
4926  {
4927  SCIPerrorMessage("Variable name %.*s is too long for buffer in exprparseReadVariable.\n", namelength, str);
4928  return SCIP_READERROR;
4929  }
4930 
4931  memcpy(varname, *str, namelength * sizeof(char));
4932  varname[namelength] = '\0';
4933 
4934  element = SCIPhashtableRetrieve(vartable, varname);
4935  if( element != NULL )
4936  {
4937  /* variable is old friend */
4938  assert(strcmp((char*)element + sizeof(int), varname) == 0);
4939 
4940  varidx = *(int*)element;
4941  }
4942  else
4943  {
4944  /* variable is new */
4945  varidx = *nvars;
4946 
4947  /* store index of variable and variable name in varnames buffer */
4948  **varnames = varidx;
4949  strcpy((char*)(*varnames + 1), varname);
4950 
4951  /* insert variable into hashtable */
4952  SCIP_CALL( SCIPhashtableInsert(vartable, (void*)*varnames) );
4953 
4954  ++*nvars;
4955  *varnames += 1 + (strlen(varname) + 1) / sizeof(int) + 1;
4956  }
4957 
4958  /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
4959  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_VARIDX, varidx) ); /*lint !e613*/
4960  if( coefficient != 1.0 )
4961  {
4962  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, expr, &coefficient, 0.0) );
4963  }
4964 
4965  /* Move pointer to char behind end of variable */
4966  *str = varnameendptr + 1;
4967 
4968  /* consprint sometimes prints a variable type identifier which we don't need */
4969  if( (*str)[0] == '[' && (*str)[2] == ']' &&
4970  ((*str)[1] == SCIP_VARTYPE_BINARY_CHAR ||
4971  (*str)[1] == SCIP_VARTYPE_INTEGER_CHAR ||
4972  (*str)[1] == SCIP_VARTYPE_IMPLINT_CHAR ||
4973  (*str)[1] == SCIP_VARTYPE_CONTINUOUS_CHAR ) )
4974  *str += 3;
4975 
4976  return SCIP_OKAY;
4977 }
4978 
4979 /** if str[0] points to an opening parenthesis, this function sets endptr to point to the matching closing bracket in str
4980  *
4981  * Searches for at most length characters.
4982  */
4983 static
4985  const char* str, /**< pointer to the string to be parsed */
4986  const char** endptr, /**< pointer to point to the closing parenthesis */
4987  int length /**< length of the string to be parsed */
4988  )
4989 {
4990  int nopenbrackets;
4991 
4992  assert(str[0] == '(');
4993 
4994  *endptr = str;
4995 
4996  /* find the end of this expression */
4997  nopenbrackets = 0;
4998  while( (*endptr - str ) < length && !(nopenbrackets == 1 && *endptr[0] == ')') )
4999  {
5000  if( *endptr[0] == '(')
5001  ++nopenbrackets;
5002  if( *endptr[0] == ')')
5003  --nopenbrackets;
5004  ++*endptr;
5005  }
5006 
5007  if( *endptr[0] != ')' )
5008  {
5009  SCIPerrorMessage("unable to find closing parenthesis in unbalanced expression %.*s\n", length, str);
5010  return SCIP_READERROR;
5011  }
5012 
5013  return SCIP_OKAY;
5014 }
5015 
5016 /** this function sets endptr to point to the next separating comma in str
5017  *
5018  * That is, for a given string like "x+f(x,y),z", endptr will point to the comma before "z"
5019  *
5020  * Searches for at most length characters.
5021  */
5022 static
5024  const char* str, /**< pointer to the string to be parsed */
5025  const char** endptr, /**< pointer to point to the comma */
5026  int length /**< length of the string to be parsed */
5027  )
5028 {
5029  int nopenbrackets;
5030 
5031  *endptr = str;
5032 
5033  /* find a comma without open brackets */
5034  nopenbrackets = 0;
5035  while( (*endptr - str ) < length && !(nopenbrackets == 0 && *endptr[0] == ',') )
5036  {
5037  if( *endptr[0] == '(')
5038  ++nopenbrackets;
5039  if( *endptr[0] == ')')
5040  --nopenbrackets;
5041  ++*endptr;
5042  }
5043 
5044  if( *endptr[0] != ',' )
5045  {
5046  SCIPerrorMessage("unable to find separating comma in unbalanced expression %.*s\n", length, str);
5047  return SCIP_READERROR;
5048  }
5049 
5050  return SCIP_OKAY;
5051 }
5052 
5053 /** parses an expression from a string */
5054 static
5056  BMS_BLKMEM* blkmem, /**< block memory data structure */
5057  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
5058  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
5059  const char* str, /**< pointer to the string to be parsed */
5060  int length, /**< length of the string to be parsed */
5061  const char* lastchar, /**< pointer to the last char of str that should be parsed */
5062  int* nvars, /**< running number of encountered variables so far */
5063  int** varnames, /**< pointer to buffer to store new variable names */
5064  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
5065  int recursiondepth /**< current recursion depth */
5066  )
5067 { /*lint --e{712,747}*/
5068  SCIP_EXPR* arg1;
5069  SCIP_EXPR* arg2;
5070  const char* subexpptr;
5071  const char* subexpendptr;
5072  const char* strstart;
5073  const char* endptr;
5074  char* nonconstendptr;
5075  SCIP_Real number;
5076  int subexplength;
5077  int nopenbrackets;
5078 
5079  assert(blkmem != NULL);
5080  assert(expr != NULL);
5081  assert(str != NULL);
5082  assert(lastchar >= str);
5083  assert(nvars != NULL);
5084  assert(varnames != NULL);
5085  assert(vartable != NULL);
5086 
5087  assert(recursiondepth < 100);
5088 
5089  strstart = str; /* might be needed for error message... */
5090 
5091  SCIPdebugMessage("exprParse (%i): parsing %.*s\n", recursiondepth, (int) (lastchar-str + 1), str);
5092 
5093  /* ignore whitespace */
5094  while( isspace((unsigned char)*str) )
5095  ++str;
5096 
5097  /* look for a sum or difference not contained in brackets */
5098  subexpptr = str;
5099  nopenbrackets = 0;
5100 
5101  /* find the end of this expression
5102  * a '+' right at the beginning indicates a coefficient, not treated here, or a summation
5103  */
5104  while( subexpptr != lastchar && !(nopenbrackets == 0 && (subexpptr[0] == '+' || subexpptr[0] == '-') && subexpptr != str) )
5105  {
5106  if( subexpptr[0] == '(')
5107  ++nopenbrackets;
5108  if( subexpptr[0] == ')')
5109  --nopenbrackets;
5110  ++subexpptr;
5111  }
5112 
5113  if( subexpptr != lastchar )
5114  {
5115  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str, (int) ((subexpptr - 1) - str + 1), subexpptr - 1, nvars, varnames, vartable, recursiondepth + 1) );
5116 
5117  if( subexpptr[0] == '+' )
5118  ++subexpptr;
5119  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, subexpptr , (int) (lastchar - (subexpptr ) + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5120 
5121  /* make new expression from two arguments
5122  * we always use add, because we leave the operator between the found expressions in the second argument
5123  * this way, we do not have to worry about ''minus brackets'' in the case of more then two summands:
5124  * a - b - c = a + (-b -c)
5125  */
5126  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5127 
5128  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5129  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5130  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5131 
5132  return SCIP_OKAY;
5133  }
5134 
5135  /* check for a bracketed subexpression */
5136  if( str[0] == '(' )
5137  {
5138  nopenbrackets = 0;
5139 
5140  subexplength = -1; /* we do not want the closing bracket in the string */
5141  subexpptr = str + 1; /* leave out opening bracket */
5142 
5143  /* find the end of this expression */
5144  while( subexplength < length && !(nopenbrackets == 1 && str[0] == ')') )
5145  {
5146  if( str[0] == '(' )
5147  ++nopenbrackets;
5148  if( str[0] == ')' )
5149  --nopenbrackets;
5150  ++str;
5151  ++subexplength;
5152  }
5153  subexpendptr = str - 1; /* leave out closing bracket */
5154 
5155  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, subexpptr, subexplength, subexpendptr, nvars, varnames, vartable, recursiondepth + 1) );
5156  ++str;
5157  }
5158  else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5159  {
5160  /* there is a number coming */
5161  if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5162  {
5163  SCIPerrorMessage("error parsing number from <%s>\n", str);
5164  return SCIP_READERROR;
5165  }
5166  str = nonconstendptr;
5167 
5168  /* ignore whitespace */
5169  while( isspace((unsigned char)*str) && str != lastchar )
5170  ++str;
5171 
5172  if( str[0] != '*' && str[0] != '/' && str[0] != '+' && str[0] != '-' && str[0] != '/' && str[0] != '^' )
5173  {
5174  if( str < lastchar )
5175  {
5176  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, str, (int)(lastchar - str) + 1, lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5177  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, *expr, number) );
5178  }
5179  else
5180  {
5181  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5182  }
5183  str = lastchar + 1;
5184  }
5185  else
5186  {
5187  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5188  }
5189  }
5190  else if( str[0] == '<' )
5191  {
5192  /* check if expressions begins with a variable */
5193  SCIP_CALL( exprparseReadVariable(blkmem, &str, expr, nvars, varnames, vartable, 1.0, NULL) );
5194  }
5195  /* four character operators */
5196  else if( strncmp(str, "sqrt", 4) == 0 )
5197  {
5198  str += 4;
5199  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5200  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5201  str = endptr + 1;
5202 
5203  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQRT, arg1) );
5204  }
5205  /* three character operators */
5206  else if(
5207  strncmp(str, "abs", 3) == 0 ||
5208  strncmp(str, "cos", 3) == 0 ||
5209  strncmp(str, "exp", 3) == 0 ||
5210  strncmp(str, "log", 3) == 0 ||
5211  strncmp(str, "sin", 3) == 0 ||
5212  strncmp(str, "sqr", 3) == 0 ||
5213  strncmp(str, "tan", 3) == 0 )
5214  {
5215  const char* opname = str;
5216 
5217  str += 3;
5218  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5219  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5220  str = endptr + 1;
5221 
5222  if( strncmp(opname, "abs", 3) == 0 )
5223  {
5224  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_ABS, arg1) );
5225  }
5226  else if( strncmp(opname, "cos", 3) == 0 )
5227  {
5228  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_COS, arg1) );
5229  }
5230  else if( strncmp(opname, "exp", 3) == 0 )
5231  {
5232  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, arg1) );
5233  }
5234  else if( strncmp(opname, "log", 3) == 0 )
5235  {
5236  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5237  }
5238  else if( strncmp(opname, "sin", 3) == 0 )
5239  {
5240  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIN, arg1) );
5241  }
5242  else if( strncmp(opname, "sqr", 3) == 0 )
5243  {
5244  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQUARE, arg1) );
5245  }
5246  else
5247  {
5248  assert(strncmp(opname, "tan", 3) == 0);
5249  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_TAN, arg1) );
5250  }
5251  }
5252  else if( strncmp(str, "power", 5) == 0 )
5253  {
5254  /* we have a string of the form "power(...,integer)" (thus, intpower)
5255  * first find the closing parenthesis, then the comma
5256  */
5257  const char* comma;
5258  int exponent;
5259 
5260  str += 5;
5261  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5262 
5263  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5264 
5265  /* parse first argument [str+1..comma-1] */
5266  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames, vartable, recursiondepth + 1) );
5267 
5268  ++comma;
5269  /* parse second argument [comma, endptr-1]: it needs to be an integer */
5270  while( comma < endptr && *comma == ' ' )
5271  ++comma;
5272  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5273  {
5274  SCIPerrorMessage("error parsing integer exponent from <%s>\n", comma);
5275  }
5276  if( !SCIPstrToIntValue(comma, &exponent, &nonconstendptr) )
5277  {
5278  SCIPerrorMessage("error parsing integer from <%s>\n", comma);
5279  return SCIP_READERROR;
5280  }
5281 
5282  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, exponent) );
5283 
5284  str = endptr + 1;
5285  }
5286  else if( strncmp(str, "realpower", 9) == 0 || strncmp(str, "signpower", 9) == 0 )
5287  {
5288  /* we have a string of the form "realpower(...,double)" or "signpower(...,double)"
5289  * first find the closing parenthesis, then the comma
5290  */
5291  const char* opname = str;
5292  const char* comma;
5293 
5294  str += 9;
5295  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5296 
5297  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5298 
5299  /* parse first argument [str+1..comma-1] */
5300  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames, vartable, recursiondepth + 1) );
5301 
5302  ++comma;
5303  /* parse second argument [comma, endptr-1]: it needs to be an number */
5304  while( comma < endptr && *comma == ' ' )
5305  ++comma;
5306  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5307  {
5308  SCIPerrorMessage("error parsing number exponent from <%s>\n", comma);
5309  }
5310  if( !SCIPstrToRealValue(comma, &number, &nonconstendptr) )
5311  {
5312  SCIPerrorMessage("error parsing number from <%s>\n", comma);
5313  return SCIP_READERROR;
5314  }
5315 
5316  if( strncmp(opname, "realpower", 9) == 0 )
5317  {
5318  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, number) );
5319  }
5320  else
5321  {
5322  assert(strncmp(opname, "signpower", 9) == 0);
5323  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIGNPOWER, arg1, number) );
5324  }
5325 
5326  str = endptr + 1;
5327  }
5328  else if( isalpha(*str) || *str == '_' || *str == '#' )
5329  {
5330  /* check for a variable, that was not recognized earlier because somebody omitted the '<' and '>' we need for
5331  * SCIPparseVarName, making everyones life harder;
5332  * we allow only variable names starting with a character or underscore here
5333  */
5334  const char* varnamestartptr = str;
5335 
5336  /* allow only variable names containing characters, digits, hash marks, and underscores here */
5337  while( isalnum(str[0]) || str[0] == '_' || str[0] == '#' )
5338  ++str;
5339 
5340  SCIP_CALL( exprparseReadVariable(blkmem, &varnamestartptr, expr, nvars, varnames, vartable, 1.0, str) );
5341  }
5342  else
5343  {
5344  SCIPerrorMessage("parsing of invalid expression %.*s.\n", (int) (lastchar - str + 1), str);
5345  return SCIP_READERROR;
5346  }
5347 
5348  /* if we are one char behind lastchar, we are done */
5349  if( str == lastchar + 1)
5350  {
5351  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5352  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5353  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5354 
5355  return SCIP_OKAY;
5356  }
5357 
5358  /* check if we are still in bounds */
5359  if( str > lastchar + 1)
5360  {
5361  SCIPerrorMessage("error finding first expression in \"%.*s\" took us outside of given subexpression length\n", length, strstart);
5362  return SCIP_READERROR;
5363  }
5364 
5365  /* ignore whitespace */
5366  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5367  ++str;
5368 
5369  /* maybe now we're done? */
5370  if( str >= lastchar + 1)
5371  {
5372  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5373  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5374  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5375 
5376  return SCIP_OKAY;
5377  }
5378 
5379  if( str[0] == '^' )
5380  {
5381  /* a '^' behind the found expression indicates a constant power */
5382  SCIP_Real constant;
5383 
5384  arg1 = *expr;
5385  ++str;
5386 
5387  if( str[0] == '(' )
5388  {
5389  /* we use exprParse to evaluate the bracketed argument */
5390  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5391  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5392 
5393  /* everything else should be written as (int|real|sign)power(a,b)... */
5394  assert(SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST);
5395 
5396  str = endptr + 1;
5397  }
5398  else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5399  {
5400  /* there is a number coming */
5401  if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5402  {
5403  SCIPerrorMessage("error parsing number from <%s>\n", str);
5404  return SCIP_READERROR;
5405  }
5406 
5407  SCIP_CALL( SCIPexprCreate(blkmem, &arg2, SCIP_EXPR_CONST, number) );
5408  str = nonconstendptr;
5409  }
5410  else
5411  {
5412  SCIPerrorMessage("unexpected string following ^ in %.*s\n", length, str);
5413  return SCIP_READERROR;
5414  }
5415 
5416  constant = SCIPexprGetOpReal(arg2);
5417 
5418  /* expr^number is intpower or realpower */
5419  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5420  {
5421  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)SCIPexprGetOpReal(arg2)) );
5422  }
5423  else
5424  {
5425  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, SCIPexprGetOpReal(arg2)) );
5426  }
5427 
5428  /* ignore whitespace */
5429  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5430  ++str;
5431  }
5432 
5433  /* check for a two argument operator that is not a multiplication */
5434  if( str[0] == '+' || str[0] == '-' || str[0] == '/' || str[0] == '^' )
5435  {
5436  char op;
5437 
5438  op = str[0];
5439  arg1 = *expr;
5440 
5441  /* step forward over the operator to go to the beginning of the second argument */
5442  ++str;
5443 
5444  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5445  str = lastchar + 1;
5446 
5447  /* make new expression from two arguments */
5448  if( op == '+')
5449  {
5450  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5451  }
5452  else if( op == '-')
5453  {
5454  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, -1.0, arg2, 0.0) );
5455  }
5456  else if( op == '*' )
5457  {
5458  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5459  {
5460  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5461  }
5462  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5463  {
5464  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5465  }
5466  else
5467  {
5468  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5469  }
5470  }
5471  else
5472  {
5473  assert(op == '/');
5474 
5475  if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5476  {
5477  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, 1.0 / SCIPexprGetOpReal(arg2)) );
5478  }
5479  else
5480  {
5481  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_DIV, arg1, arg2) );
5482  }
5483  }
5484  }
5485 
5486  /* ignore whitespace */
5487  while( isspace((unsigned char)*str) )
5488  ++str;
5489 
5490  /* we are either done or we have a multiplication? */
5491  if( str >= lastchar + 1)
5492  {
5493  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5494  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5495  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5496 
5497  return SCIP_OKAY;
5498  }
5499 
5500  /* if there is a part of the string left to be parsed, we assume that this as a multiplication */
5501  arg1 = *expr;
5502 
5503  /* stepping over multiplication operator if needed */
5504  if( str[0] == '*' )
5505  {
5506  ++str;
5507  }
5508  else if( str[0] != '(' )
5509  {
5510  SCIPdebugMessage("No operator found, assuming a multiplication before %.*s\n", (int) (lastchar - str + 1), str);
5511  }
5512 
5513  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5514 
5515  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5516  {
5517  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5518  }
5519  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5520  {
5521  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5522  }
5523  else
5524  {
5525  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5526  }
5527 
5528  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5529  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5530  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5531 
5532  return SCIP_OKAY;
5533 }
5534 
5535 /**@} */
5536 
5537 /**@name Expression methods */
5538 /**@{ */
5539 
5540 /* In debug mode, the following methods are implemented as function calls to ensure
5541  * type validity.
5542  * In optimized mode, the methods are implemented as defines to improve performance.
5543  * However, we want to have them in the library anyways, so we have to undef the defines.
5544  */
5545 
5546 #undef SCIPexprGetOperator
5547 #undef SCIPexprGetNChildren
5548 #undef SCIPexprGetChildren
5549 #undef SCIPexprGetOpIndex
5550 #undef SCIPexprGetOpReal
5551 #undef SCIPexprGetOpData
5552 #undef SCIPexprGetRealPowerExponent
5553 #undef SCIPexprGetIntPowerExponent
5554 #undef SCIPexprGetSignPowerExponent
5555 #undef SCIPexprGetLinearCoefs
5556 #undef SCIPexprGetLinearConstant
5557 #undef SCIPexprGetQuadElements
5558 #undef SCIPexprGetQuadConstant
5559 #undef SCIPexprGetQuadLinearCoefs
5560 #undef SCIPexprGetNQuadElements
5561 #undef SCIPexprGetMonomials
5562 #undef SCIPexprGetNMonomials
5563 #undef SCIPexprGetPolynomialConstant
5564 #undef SCIPexprGetMonomialCoef
5565 #undef SCIPexprGetMonomialNFactors
5566 #undef SCIPexprGetMonomialChildIndices
5567 #undef SCIPexprGetMonomialExponents
5568 #undef SCIPexprGetUserData
5569 #undef SCIPexprHasUserEstimator
5570 #undef SCIPexprGetUserEvalCapability
5571 
5572 /** gives operator of expression */
5574  SCIP_EXPR* expr /**< expression */
5575  )
5576 {
5577  assert(expr != NULL);
5578 
5579  return expr->op;
5580 }
5581 
5582 /** gives number of children of an expression */
5584  SCIP_EXPR* expr /**< expression */
5585  )
5586 {
5587  assert(expr != NULL);
5588 
5589  return expr->nchildren;
5590 }
5591 
5592 /** gives pointer to array with children of an expression */
5594  SCIP_EXPR* expr /**< expression */
5595  )
5596 {
5597  assert(expr != NULL);
5598 
5599  return expr->children;
5600 }
5601 
5602 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
5604  SCIP_EXPR* expr /**< expression */
5605  )
5606 {
5607  assert(expr != NULL);
5608  assert(expr->op == SCIP_EXPR_VARIDX || expr->op == SCIP_EXPR_PARAM);
5609 
5610  return expr->data.intval;
5611 }
5612 
5613 /** gives real belonging to a SCIP_EXPR_CONST operand */
5615  SCIP_EXPR* expr /**< expression */
5616  )
5617 {
5618  assert(expr != NULL);
5619  assert(expr->op == SCIP_EXPR_CONST);
5620 
5621  return expr->data.dbl;
5622 }
5623 
5624 /** gives void* belonging to a complex operand */
5626  SCIP_EXPR* expr /**< expression */
5627  )
5628 {
5629  assert(expr != NULL);
5630  assert(expr->op >= SCIP_EXPR_SUM); /* only complex operands store their data as void* */
5631 
5632  return expr->data.data;
5633 }
5634 
5635 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
5637  SCIP_EXPR* expr /**< expression */
5638  )
5639 {
5640  assert(expr != NULL);
5641  assert(expr->op == SCIP_EXPR_REALPOWER);
5642 
5643  return expr->data.dbl;
5644 }
5645 
5646 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
5648  SCIP_EXPR* expr /**< expression */
5649  )
5650 {
5651  assert(expr != NULL);
5652  assert(expr->op == SCIP_EXPR_INTPOWER);
5653 
5654  return expr->data.intval;
5655 }
5656 
5657 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
5659  SCIP_EXPR* expr /**< expression */
5660  )
5661 {
5662  assert(expr != NULL);
5663  assert(expr->op == SCIP_EXPR_SIGNPOWER);
5664 
5665  return expr->data.dbl;
5666 }
5667 
5668 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
5670  SCIP_EXPR* expr /**< expression */
5671  )
5672 {
5673  assert(expr != NULL);
5674  assert(expr->op == SCIP_EXPR_LINEAR);
5675  assert(expr->data.data != NULL);
5676 
5677  /* the coefficients are stored in the first nchildren elements of the array stored as expression data */
5678  return (SCIP_Real*)expr->data.data;
5679 }
5680 
5681 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
5683  SCIP_EXPR* expr /**< expression */
5684  )
5685 {
5686  assert(expr != NULL);
5687  assert(expr->op == SCIP_EXPR_LINEAR);
5688  assert(expr->data.data != NULL);
5689 
5690  /* the constant is stored in the nchildren's element of the array stored as expression data */
5691  return ((SCIP_Real*)expr->data.data)[expr->nchildren];
5692 }
5693 
5694 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5696  SCIP_EXPR* expr /**< quadratic expression */
5697  )
5698 {
5699  assert(expr != NULL);
5700  assert(expr->op == SCIP_EXPR_QUADRATIC);
5701  assert(expr->data.data != NULL);
5702 
5703  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->quadelems;
5704 }
5705 
5706 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
5708  SCIP_EXPR* expr /**< quadratic expression */
5709  )
5710 {
5711  assert(expr != NULL);
5712  assert(expr->op == SCIP_EXPR_QUADRATIC);
5713  assert(expr->data.data != NULL);
5714 
5715  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->constant;
5716 }
5717 
5718 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression
5719  * can be NULL if all coefficients are 0.0 */
5721  SCIP_EXPR* expr /**< quadratic expression */
5722  )
5723 {
5724  assert(expr != NULL);
5725  assert(expr->op == SCIP_EXPR_QUADRATIC);
5726  assert(expr->data.data != NULL);
5727 
5728  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->lincoefs;
5729 }
5730 
5731 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5733  SCIP_EXPR* expr /**< quadratic expression */
5734  )
5735 {
5736  assert(expr != NULL);
5737  assert(expr->op == SCIP_EXPR_QUADRATIC);
5738  assert(expr->data.data != NULL);
5739 
5740  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->nquadelems;
5741 }
5742 
5743 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5745  SCIP_EXPR* expr /**< expression */
5746  )
5747 {
5748  assert(expr != NULL);
5749  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5750  assert(expr->data.data != NULL);
5751 
5752  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->monomials;
5753 }
5754 
5755 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5757  SCIP_EXPR* expr /**< expression */
5758  )
5759 {
5760  assert(expr != NULL);
5761  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5762  assert(expr->data.data != NULL);
5763 
5764  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->nmonomials;
5765 }
5766 
5767 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
5769  SCIP_EXPR* expr /**< expression */
5770  )
5771 {
5772  assert(expr != NULL);
5773  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5774  assert(expr->data.data != NULL);
5775 
5776  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant;
5777 }
5778 
5779 /** gets coefficient of a monomial */
5781  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5782  )
5783 {
5784  assert(monomial != NULL);
5785 
5786  return monomial->coef;
5787 }
5788 
5789 /** gets number of factors of a monomial */
5791  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5792  )
5793 {
5794  assert(monomial != NULL);
5795 
5796  return monomial->nfactors;
5797 }
5798 
5799 /** gets indices of children corresponding to factors of a monomial */
5801  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5802  )
5803 {
5804  assert(monomial != NULL);
5805 
5806  return monomial->childidxs;
5807 }
5808 
5809 /** gets exponents in factors of a monomial */
5811  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5812  )
5813 {
5814  assert(monomial != NULL);
5815 
5816  return monomial->exponents;
5817 }
5818 
5819 /** gets user data of a user expression */
5821  SCIP_EXPR* expr
5822  )
5823 {
5824  assert(expr != NULL);
5825  assert(expr->data.data != NULL);
5826 
5827  return ((SCIP_EXPRDATA_USER*)expr->data.data)->userdata;
5828 }
5829 
5830 /** indicates whether a user expression has the estimator callback defined */
5832  SCIP_EXPR* expr
5833  )
5834 {
5835  assert(expr != NULL);
5836  assert(expr->data.data != NULL);
5837 
5838  return ((SCIP_EXPRDATA_USER*)expr->data.data)->estimate != NULL;
5839 }
5840 
5841 /** gives the evaluation capability of a user expression */
5843  SCIP_EXPR* expr
5844  )
5845 {
5846  assert(expr != NULL);
5847  assert(expr->data.data != NULL);
5848 
5849  return ((SCIP_EXPRDATA_USER*)expr->data.data)->evalcapability;
5850 }
5851 
5852 /** creates a simple expression */
5854  BMS_BLKMEM* blkmem, /**< block memory data structure */
5855  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
5856  SCIP_EXPROP op, /**< operand of expression */
5857  ... /**< arguments of operand */
5858  )
5859 {
5860  va_list ap;
5861  SCIP_EXPR** children;
5862  SCIP_EXPROPDATA opdata;
5863 
5864  assert(blkmem != NULL);
5865  assert(expr != NULL);
5866 
5867  switch( op )
5868  {
5869  case SCIP_EXPR_VARIDX:
5870  case SCIP_EXPR_PARAM:
5871  {
5872  va_start( ap, op ); /*lint !e838*/
5873  opdata.intval = va_arg( ap, int ); /*lint !e416 !e826*/
5874  va_end( ap ); /*lint !e826*/
5875 
5876  assert( opdata.intval >= 0 );
5877 
5878  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5879  break;
5880  }
5881 
5882  case SCIP_EXPR_CONST:
5883  {
5884  va_start(ap, op ); /*lint !e838*/
5885  opdata.dbl = va_arg( ap, SCIP_Real ); /*lint !e416 !e826*/
5886  va_end( ap ); /*lint !e826*/
5887 
5888  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5889  break;
5890  }
5891 
5892  /* operands with two children */
5893  case SCIP_EXPR_PLUS :
5894  case SCIP_EXPR_MINUS :
5895  case SCIP_EXPR_MUL :
5896  case SCIP_EXPR_DIV :
5897  case SCIP_EXPR_MIN :
5898  case SCIP_EXPR_MAX :
5899  {
5900  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 2) ); /*lint !e506*/
5901 
5902  va_start(ap, op ); /*lint !e838*/
5903  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5904  children[1] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5905  assert(children[0] != NULL);
5906  assert(children[1] != NULL);
5907  va_end( ap ); /*lint !e826*/
5908  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
5909 
5910  SCIP_CALL( exprCreate( blkmem, expr, op, 2, children, opdata ) );
5911  break;
5912  }
5913 
5914  /* operands with one child */
5915  case SCIP_EXPR_SQUARE:
5916  case SCIP_EXPR_SQRT :
5917  case SCIP_EXPR_EXP :
5918  case SCIP_EXPR_LOG :
5919  case SCIP_EXPR_SIN :
5920  case SCIP_EXPR_COS :
5921  case SCIP_EXPR_TAN :
5922  /* case SCIP_EXPR_ERF : */
5923  /* case SCIP_EXPR_ERFI : */
5924  case SCIP_EXPR_ABS :
5925  case SCIP_EXPR_SIGN :
5926  {
5927  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
5928 
5929  va_start(ap, op ); /*lint !e838*/
5930  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5931  assert(children[0] != NULL);
5932  va_end( ap ); /*lint !e826*/
5933  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
5934 
5935  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
5936  break;
5937  }
5938 
5939  case SCIP_EXPR_REALPOWER:
5940  case SCIP_EXPR_SIGNPOWER:
5941  {
5942  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
5943 
5944  va_start(ap, op ); /*lint !e838*/
5945  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5946  assert(children[0] != NULL);
5947  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
5948  va_end( ap ); /*lint !e826*/
5949 
5950  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
5951  break;
5952  }
5953 
5954  case SCIP_EXPR_INTPOWER:
5955  {
5956  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
5957 
5958  va_start(ap, op ); /*lint !e838*/
5959  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
5960  assert(children[0] != NULL);
5961  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
5962  va_end( ap ); /*lint !e826*/
5963 
5964  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
5965  break;
5966  }
5967 
5968  /* complex operands */
5969  case SCIP_EXPR_SUM :
5970  case SCIP_EXPR_PRODUCT:
5971  {
5972  int nchildren;
5973  SCIP_EXPR** childrenarg;
5974 
5975  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
5976 
5977  va_start(ap, op ); /*lint !e838*/
5978  /* first argument should be number of children */
5979  nchildren = va_arg( ap, int ); /*lint !e416 !e826*/
5980  assert(nchildren >= 0);
5981 
5982  /* for a sum or product of 0 terms we can finish here */
5983  if( nchildren == 0 )
5984  {
5985  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata) );
5986  va_end( ap ); /*lint !e826*/
5987  break;
5988  }
5989 
5990  /* next argument should be array of children expressions */
5991  childrenarg = va_arg( ap, SCIP_EXPR** ); /*lint !e416 !e826*/
5992  assert(childrenarg != NULL);
5993  va_end( ap ); /*lint !e826*/
5994 
5995  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &children, childrenarg, nchildren) );
5996 
5997  SCIP_CALL( exprCreate( blkmem, expr, op, nchildren, children, opdata) );
5998  break;
5999  }
6000 
6001  case SCIP_EXPR_LINEAR :
6002  case SCIP_EXPR_QUADRATIC:
6003  case SCIP_EXPR_POLYNOMIAL:
6004  case SCIP_EXPR_USER:
6005  {
6006  SCIPerrorMessage("cannot create complex expression linear, quadratic, polynomial, or user with SCIPexprCreate\n");
6007  return SCIP_INVALIDDATA;
6008  }
6009 
6010  case SCIP_EXPR_LAST:
6011  SCIPABORT();
6012  break;
6013  }
6014 
6015  return SCIP_OKAY;
6016 }
6017 
6018 /** copies an expression including its children */
6020  BMS_BLKMEM* blkmem, /**< block memory data structure */
6021  SCIP_EXPR** targetexpr, /**< buffer to store pointer to copied expression */
6022  SCIP_EXPR* sourceexpr /**< expression to copy */
6023  )
6024 {
6025  assert(blkmem != NULL);
6026  assert(targetexpr != NULL);
6027  assert(sourceexpr != NULL);
6028 
6029  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targetexpr, sourceexpr) );
6030 
6031  if( sourceexpr->nchildren )
6032  {
6033  int i;
6034 
6035  /* alloc memory for children expressions */
6036  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetexpr)->children, sourceexpr->nchildren) );
6037 
6038  /* copy children expressions */
6039  for( i = 0; i < sourceexpr->nchildren; ++i )
6040  {
6041  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targetexpr)->children[i], sourceexpr->children[i]) );
6042  }
6043  }
6044  else
6045  {
6046  assert((*targetexpr)->children == NULL); /* otherwise, sourceexpr->children was not NULL, which is wrong */
6047  }
6048 
6049  /* call operands data copy callback for complex operands
6050  * for simple operands BMSduplicate above should have done the job
6051  */
6052  if( exprOpTable[sourceexpr->op].copydata != NULL )
6053  {
6054  SCIP_CALL( exprOpTable[sourceexpr->op].copydata(blkmem, sourceexpr->nchildren, sourceexpr->data, &(*targetexpr)->data) );
6055  }
6056 
6057  return SCIP_OKAY;
6058 }
6059 
6060 /** frees an expression including its children */
6062  BMS_BLKMEM* blkmem, /**< block memory data structure */
6063  SCIP_EXPR** expr /**< pointer to expression to free */
6064  )
6065 {
6066  assert(blkmem != NULL);
6067  assert(expr != NULL);
6068  assert(*expr != NULL);
6069 
6070  /* call operands data free callback, if given */
6071  if( exprOpTable[(*expr)->op].freedata != NULL )
6072  {
6073  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6074  }
6075 
6076  if( (*expr)->nchildren )
6077  {
6078  int i;
6079 
6080  assert( (*expr)->children != NULL );
6081 
6082  for( i = 0; i < (*expr)->nchildren; ++i )
6083  {
6084  SCIPexprFreeDeep(blkmem, &(*expr)->children[i]);
6085  assert((*expr)->children[i] == NULL);
6086  }
6087 
6088  BMSfreeBlockMemoryArray(blkmem, &(*expr)->children, (*expr)->nchildren);
6089  }
6090  else
6091  {
6092  assert( (*expr)->children == NULL );
6093  }
6094 
6095  BMSfreeBlockMemory(blkmem, expr);
6096 }
6097 
6098 /** frees an expression but not its children */
6100  BMS_BLKMEM* blkmem, /**< block memory data structure */
6101  SCIP_EXPR** expr /**< pointer to expression to free */
6102  )
6103 {
6104  assert(blkmem != NULL);
6105  assert(expr != NULL);
6106  assert(*expr != NULL);
6107 
6108  /* call operands data free callback, if given */
6109  if( exprOpTable[(*expr)->op].freedata != NULL )
6110  {
6111  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6112  }
6113 
6114  BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->nchildren);
6115 
6116  BMSfreeBlockMemory(blkmem, expr);
6117 }
6118 
6119 /** creates an expression from the addition of two given expression, with coefficients, and a constant
6120  *
6121  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6122  * Favors creation and maintaining of SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6123  */
6125  BMS_BLKMEM* blkmem, /**< block memory data structure */
6126  SCIP_EXPR** expr, /**< pointer to store pointer to created expression */
6127  SCIP_Real coef1, /**< coefficient of first term */
6128  SCIP_EXPR* term1, /**< expression of first term, or NULL */
6129  SCIP_Real coef2, /**< coefficient of second term */
6130  SCIP_EXPR* term2, /**< expression of second term, or NULL */
6131  SCIP_Real constant /**< constant term to add */
6132  )
6133 {
6134  assert(blkmem != NULL);
6135  assert(expr != NULL);
6136 
6137  /* @todo could do something special with quadratic and polynomial expressions */
6138 
6139  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_CONST )
6140  {
6141  constant += coef1 * SCIPexprGetOpReal(term1);
6142  SCIPexprFreeDeep(blkmem, &term1);
6143  }
6144 
6145  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_CONST )
6146  {
6147  constant += coef2 * SCIPexprGetOpReal(term2);
6148  SCIPexprFreeDeep(blkmem, &term2);
6149  }
6150 
6151  if( term1 == NULL && term2 == NULL )
6152  {
6153  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, constant) );
6154  return SCIP_OKAY;
6155  }
6156 
6157  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && coef1 != 1.0 )
6158  {
6159  /* multiply coefficients and constant of linear expression term1 by coef1 */
6160  SCIP_Real* data;
6161  int i;
6162 
6163  data = (SCIP_Real*)term1->data.data;
6164  assert(data != NULL);
6165 
6166  /* loop one more index to multiply also constant of linear expression */
6167  for( i = 0; i <= term1->nchildren; ++i )
6168  data[i] *= coef1;
6169 
6170  coef1 = 1.0;
6171  }
6172 
6173  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR && coef2 != 1.0 )
6174  {
6175  /* multiply coefficients and constant of linear expression term2 by coef2 */
6176  SCIP_Real* data;
6177  int i;
6178 
6179  data = (SCIP_Real*)term2->data.data;
6180  assert(data != NULL);
6181 
6182  /* loop one more index to multiply also constant of linear expression */
6183  for( i = 0; i <= term2->nchildren; ++i )
6184  data[i] *= coef2;
6185 
6186  coef2 = 1.0;
6187  }
6188 
6189  if( term1 == NULL || term2 == NULL )
6190  {
6191  if( term1 == NULL )
6192  {
6193  term1 = term2;
6194  coef1 = coef2;
6195  }
6196  if( constant != 0.0 || coef1 != 1.0 )
6197  {
6198  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6199  {
6200  assert(coef1 == 1.0);
6201 
6202  /* add constant to existing linear expression */
6203  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 0, NULL, NULL, constant) );
6204  *expr = term1;
6205  }
6206  else
6207  {
6208  /* create new linear expression for coef1 * term1 + constant */
6209  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term1, &coef1, constant) );
6210  }
6211  }
6212  else
6213  {
6214  assert(constant == 0.0);
6215  assert(coef1 == 1.0);
6216  *expr = term1;
6217  }
6218 
6219  return SCIP_OKAY;
6220  }
6221 
6223  {
6224  /* add 2nd linear expression to first one */
6225  assert(coef1 == 1.0);
6226  assert(coef2 == 1.0);
6227 
6229  SCIPexprFreeShallow(blkmem, &term2);
6230 
6231  *expr = term1;
6232 
6233  return SCIP_OKAY;
6234  }
6235 
6236  if( SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
6237  {
6238  /* if only term2 is linear, then swap */
6239  SCIP_EXPR* tmp;
6240 
6241  tmp = term2;
6242  assert(coef2 == 1.0);
6243 
6244  term2 = term1;
6245  coef2 = coef1;
6246  term1 = tmp;
6247  coef1 = 1.0;
6248  }
6249 
6250  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6251  {
6252  /* add coef2*term2 as extra child to linear expression term1 */
6253  assert(coef1 == 1.0);
6254 
6255  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 1, &coef2, &term2, constant) );
6256  *expr = term1;
6257 
6258  return SCIP_OKAY;
6259  }
6260 
6261  /* both terms are not linear, then create new linear term for sum */
6262  {
6263  SCIP_Real coefs[2];
6264  SCIP_EXPR* children[2];
6265 
6266  coefs[0] = coef1;
6267  coefs[1] = coef2;
6268  children[0] = term1;
6269  children[1] = term2;
6270 
6271  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 2, children, coefs, constant) );
6272  }
6273 
6274  return SCIP_OKAY;
6275 }
6276 
6277 /** creates an expression from the multiplication of an expression with a constant
6278  *
6279  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6280  * Favors creation and maintaining SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6281  */
6283  BMS_BLKMEM* blkmem, /**< block memory data structure */
6284  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
6285  SCIP_EXPR* term, /**< term to multiply by factor */
6286  SCIP_Real factor /**< factor */
6287  )
6288 {
6289  assert(blkmem != NULL);
6290  assert(expr != NULL);
6291  assert(term != NULL);
6292 
6293  if( factor == 0.0 )
6294  {
6295  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, 0.0) );
6296 
6297  SCIPexprFreeDeep(blkmem, &term);
6298 
6299  return SCIP_OKAY;
6300  }
6301  if( factor == 1.0 )
6302  {
6303  *expr = term;
6304  return SCIP_OKAY;
6305  }
6306 
6307  switch( SCIPexprGetOperator(term) )
6308  {
6309  case SCIP_EXPR_CONST :
6310  {
6311  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, factor * SCIPexprGetOpReal(term)) );
6312  SCIPexprFreeDeep(blkmem, &term);
6313  break;
6314  }
6315 
6316  case SCIP_EXPR_LINEAR :
6317  {
6318  SCIP_Real* data;
6319  int i;
6320 
6321  data = (SCIP_Real*)term->data.data;
6322  assert(data != NULL);
6323 
6324  /* loop one more index to multiply also constant of linear expression */
6325  for( i = 0; i <= SCIPexprGetNChildren(term); ++i )
6326  data[i] *= factor;
6327 
6328  *expr = term;
6329  break;
6330  }
6331 
6332  case SCIP_EXPR_QUADRATIC :
6333  {
6335  int i;
6336 
6337  data = (SCIP_EXPRDATA_QUADRATIC*)term->data.data;
6338 
6339  data->constant *= factor;
6340 
6341  if( data->lincoefs != NULL )
6342  for( i = 0; i < term->nchildren; ++i )
6343  data->lincoefs[i] *= factor;
6344 
6345  for( i = 0; i < data->nquadelems; ++i )
6346  data->quadelems[i].coef *= factor;
6347 
6348  *expr = term;
6349  break;
6350  }
6351 
6352  case SCIP_EXPR_POLYNOMIAL :
6353  {
6355  int i;
6356 
6357  data = (SCIP_EXPRDATA_POLYNOMIAL*)term->data.data;
6358 
6359  data->constant *= factor;
6360 
6361  for( i = 0; i < data->nmonomials; ++i )
6362  data->monomials[i]->coef *= factor;
6363 
6364  *expr = term;
6365  break;
6366  }
6367 
6368  default:
6369  {
6370  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term, &factor, 0.0) );
6371  break;
6372  }
6373 
6374  } /*lint !e788 */
6375 
6376  return SCIP_OKAY;
6377 }
6378 
6379 /** creates a SCIP_EXPR_LINEAR expression that is (affine) linear in its children: constant + sum_i coef_i child_i */
6381  BMS_BLKMEM* blkmem, /**< block memory data structure */
6382  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6383  int nchildren, /**< number of children */
6384  SCIP_EXPR** children, /**< children of expression */
6385  SCIP_Real* coefs, /**< coefficients of children */
6386  SCIP_Real constant /**< constant part */
6387  )
6388 {
6389  SCIP_EXPROPDATA opdata;
6390  SCIP_EXPR** childrencopy;
6391  SCIP_Real* data;
6392 
6393  assert(nchildren >= 0);
6394  assert(children != NULL || nchildren == 0);
6395  assert(coefs != NULL || nchildren == 0);
6396 
6397  if( nchildren > 0 )
6398  {
6399  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6400  }
6401  else
6402  childrencopy = NULL;
6403 
6404  /* we store the coefficients and the constant in a single array and make this our operand data */
6405  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, nchildren + 1) );
6406  BMScopyMemoryArray(data, coefs, nchildren); /*lint !e644*/
6407  data[nchildren] = constant;
6408 
6409  opdata.data = (void*)data;
6410 
6411  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_LINEAR, nchildren, childrencopy, opdata) );
6412 
6413  return SCIP_OKAY;
6414 }
6415 
6416 /** adds new terms to a linear expression */
6418  BMS_BLKMEM* blkmem, /**< block memory */
6419  SCIP_EXPR* expr, /**< linear expression */
6420  int nchildren, /**< number of children to add */
6421  SCIP_Real* coefs, /**< coefficients of additional children */
6422  SCIP_EXPR** children, /**< additional children expressions */
6423  SCIP_Real constant /**< constant to add */
6424  )
6425 {
6426  SCIP_Real* data;
6427 
6428  assert(blkmem != NULL);
6429  assert(expr != NULL);
6430  assert(expr->op == SCIP_EXPR_LINEAR);
6431  assert(nchildren >= 0);
6432  assert(coefs != NULL || nchildren == 0);
6433  assert(children != NULL || nchildren == 0);
6434 
6435  data = (SCIP_Real*)expr->data.data;
6436  assert(data != NULL);
6437 
6438  /* handle simple case of adding a constant */
6439  if( nchildren == 0 )
6440  {
6441  data[expr->nchildren] += constant;
6442 
6443  return SCIP_OKAY;
6444  }
6445 
6446  /* add new children to expr's children array */
6447  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nchildren) );
6448  BMScopyMemoryArray(&expr->children[expr->nchildren], children, nchildren); /*lint !e866*/
6449 
6450  /* add constant and new coefs to expr's data array */
6451  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, expr->nchildren + 1, expr->nchildren + nchildren + 1) );
6452  data[expr->nchildren + nchildren] = data[expr->nchildren] + constant;
6453  BMScopyMemoryArray(&data[expr->nchildren], coefs, nchildren); /*lint !e866*/
6454  expr->data.data = (void*)data;
6455 
6456  expr->nchildren += nchildren;
6457 
6458  return SCIP_OKAY;
6459 }
6460 
6461 /** creates a SCIP_EXPR_QUADRATIC expression: constant + sum_i coef_i child_i + sum_i coef_i child1_i child2_i */
6463  BMS_BLKMEM* blkmem, /**< block memory data structure */
6464  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6465  int nchildren, /**< number of children */
6466  SCIP_EXPR** children, /**< children of expression */
6467  SCIP_Real constant, /**< constant */
6468  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
6469  int nquadelems, /**< number of quadratic elements */
6470  SCIP_QUADELEM* quadelems /**< quadratic elements specifying coefficients and child indices */
6471  )
6472 {
6473  SCIP_EXPROPDATA opdata;
6474  SCIP_EXPR** childrencopy;
6476 
6477  assert(nchildren >= 0);
6478  assert(children != NULL || nchildren == 0);
6479  assert(quadelems != NULL || nquadelems == 0);
6480 
6481  if( nchildren > 0 )
6482  {
6483  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6484  }
6485  else
6486  childrencopy = NULL;
6487 
6488  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
6489 
6490  opdata.data = (void*)data;
6491 
6492  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_QUADRATIC, nchildren, childrencopy, opdata) );
6493 
6494  return SCIP_OKAY;
6495 }
6496 
6497 /** ensures that quadratic elements of a quadratic expression are sorted */
6499  SCIP_EXPR* expr /**< quadratic expression */
6500  )
6501 {
6502  assert(expr != NULL);
6503  assert(expr->op == SCIP_EXPR_QUADRATIC);
6504  assert(expr->data.data != NULL);
6505 
6507 }
6508 
6509 /** creates a SCIP_EXPR_POLYNOMIAL expression from an array of monomials: constant + sum_i monomial_i */
6511  BMS_BLKMEM* blkmem, /**< block memory data structure */
6512  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6513  int nchildren, /**< number of children */
6514  SCIP_EXPR** children, /**< children of expression */
6515  int nmonomials, /**< number of monomials */
6516  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
6517  SCIP_Real constant, /**< constant part */
6518  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6519  )
6520 {
6521  SCIP_EXPROPDATA opdata;
6522  SCIP_EXPR** childrencopy;
6524 
6525  assert(nchildren >= 0);
6526  assert(children != NULL || nchildren == 0);
6527  assert(monomials != NULL || nmonomials == 0);
6528 
6529  if( nchildren > 0 )
6530  {
6531  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6532  }
6533  else
6534  childrencopy = NULL;
6535 
6536  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
6537  opdata.data = (void*)data;
6538 
6539  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_POLYNOMIAL, nchildren, childrencopy, opdata) );
6540 
6541  return SCIP_OKAY;
6542 }
6543 
6544 /** adds an array of monomials to a SCIP_EXPR_POLYNOMIAL expression */
6546  BMS_BLKMEM* blkmem, /**< block memory of expression */
6547  SCIP_EXPR* expr, /**< expression */
6548  int nmonomials, /**< number of monomials to add */
6549  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
6550  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6551  )
6552 {
6553  assert(blkmem != NULL);
6554  assert(expr != NULL);
6555  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6556  assert(monomials != NULL || nmonomials == 0);
6557 
6558  if( nmonomials == 0 )
6559  return SCIP_OKAY;
6560 
6561  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, nmonomials, monomials, copymonomials) );
6562 
6563  return SCIP_OKAY;
6564 }
6565 
6566 /** changes the constant in a SCIP_EXPR_POLYNOMIAL expression */
6568  SCIP_EXPR* expr, /**< expression */
6569  SCIP_Real constant /**< new value for constant */
6570  )
6571 {
6572  assert(expr != NULL);
6573  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6574  assert(expr->data.data != NULL);
6575 
6576  ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant = constant;
6577 }
6578 
6579 /** multiplies each summand of a polynomial by a given constant */
6581  BMS_BLKMEM* blkmem, /**< block memory */
6582  SCIP_EXPR* expr, /**< polynomial expression */
6583  SCIP_Real factor /**< constant factor */
6584  )
6585 {
6586  assert(expr != NULL);
6587  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6588  assert(expr->data.data != NULL);
6589 
6590  polynomialdataMultiplyByConstant(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor);
6591 }
6592 
6593 /** multiplies each summand of a polynomial by a given monomial */
6595  BMS_BLKMEM* blkmem, /**< block memory */
6596  SCIP_EXPR* expr, /**< polynomial expression */
6597  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
6598  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6599  )
6600 {
6601  assert(blkmem != NULL);
6602  assert(factor != NULL);
6603  assert(expr != NULL);
6604  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6605  assert(expr->data.data != NULL);
6606 
6607  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor, childmap) );
6608 
6609  return SCIP_OKAY;
6610 }
6611 
6612 /** multiplies this polynomial by a polynomial
6613  *
6614  * Factor needs to be different from expr.
6615  * Children of factor need to be children of expr already, w.r.t. an optional mapping of child indices.
6616  */
6618  BMS_BLKMEM* blkmem, /**< block memory */
6619  SCIP_EXPR* expr, /**< polynomial expression */
6620  SCIP_EXPR* factor, /**< polynomial factor */
6621  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6622  )
6623 {
6624  assert(blkmem != NULL);
6625  assert(expr != NULL);
6626  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6627  assert(expr->data.data != NULL);
6628  assert(factor != NULL);
6629  assert(factor->op == SCIP_EXPR_POLYNOMIAL);
6630  assert(factor->data.data != NULL);
6631  assert(expr != factor);
6632 
6633 #ifndef NDEBUG
6634  if( childmap == NULL )
6635  {
6636  int i;
6637  assert(factor->nchildren == expr->nchildren);
6638  for( i = 0; i < factor->nchildren; ++i )
6639  assert(SCIPexprAreEqual(expr->children[i], factor->children[i], 0.0));
6640  }
6641  else
6642  {
6643  int i;
6644  for( i = 0; i < factor->nchildren; ++i )
6645  {
6646  assert(childmap[i] >= 0);
6647  assert(childmap[i] < expr->nchildren);
6648  assert(SCIPexprAreEqual(expr->children[childmap[i]], factor->children[i], 0.0));
6649  }
6650  }
6651 #endif
6652 
6654 
6655  return SCIP_OKAY;
6656 }
6657 
6658 /** takes a power of the polynomial
6659  *
6660  * Exponent need to be an integer.
6661  * Polynomial needs to be a monomial, if exponent is negative.
6662  */
6664  BMS_BLKMEM* blkmem, /**< block memory */
6665  SCIP_EXPR* expr, /**< polynomial expression */
6666  int exponent /**< exponent of power operation */
6667  )
6668 {
6669  assert(blkmem != NULL);
6670  assert(expr != NULL);
6671  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6672  assert(expr->data.data != NULL);
6673 
6674  SCIP_CALL( polynomialdataPower(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, exponent) );
6675 
6676  return SCIP_OKAY;
6677 }
6678 
6679 /** merges monomials in a polynomial expression that differ only in coefficient into a single monomial
6680  *
6681  * Eliminates monomials with coefficient between -eps and eps.
6682  */
6684  BMS_BLKMEM* blkmem, /**< block memory */
6685  SCIP_EXPR* expr, /**< polynomial expression */
6686  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
6687  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
6688  )
6689 {
6690  assert(expr != NULL);
6691  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6692  assert(expr->data.data != NULL);
6693 
6694  polynomialdataMergeMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, eps, mergefactors);
6695 }
6696 
6697 /** checks if two monomials are equal */
6699  SCIP_EXPRDATA_MONOMIAL* monomial1, /**< first monomial */
6700  SCIP_EXPRDATA_MONOMIAL* monomial2, /**< second monomial */
6701  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6702  )
6703 {
6704  int i;
6705 
6706  assert(monomial1 != NULL);
6707  assert(monomial2 != NULL);
6708 
6709  if( monomial1->nfactors != monomial2->nfactors )
6710  return FALSE;
6711 
6712  if( !EPSEQ(monomial1->coef, monomial2->coef, eps) )
6713  return FALSE;
6714 
6715  SCIPexprSortMonomialFactors(monomial1);
6716  SCIPexprSortMonomialFactors(monomial2);
6717 
6718  for( i = 0; i < monomial1->nfactors; ++i )
6719  {
6720  if( monomial1->childidxs[i] != monomial2->childidxs[i] ||
6721  !EPSEQ(monomial1->exponents[i], monomial2->exponents[i], eps) )
6722  return FALSE;
6723  }
6724 
6725  return TRUE;
6726 }
6727 
6728 /** changes coefficient of monomial */
6730  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6731  SCIP_Real newcoef /**< new coefficient */
6732  )
6733 {
6734  assert(monomial != NULL);
6735 
6736  monomial->coef = newcoef;
6737 }
6738 
6739 /** adds factors to a monomial */
6741  BMS_BLKMEM* blkmem, /**< block memory */
6742  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6743  int nfactors, /**< number of factors to add */
6744  int* childidxs, /**< indices of children corresponding to factors */
6745  SCIP_Real* exponents /**< exponent in each factor */
6746  )
6747 {
6748  assert(monomial != NULL);
6749  assert(nfactors >= 0);
6750  assert(childidxs != NULL || nfactors == 0);
6751  assert(exponents != NULL || nfactors == 0);
6752 
6753  if( nfactors == 0 )
6754  return SCIP_OKAY;
6755 
6756  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + nfactors) );
6757  assert(monomial->nfactors + nfactors <= monomial->factorssize);
6758 
6759  BMScopyMemoryArray(&monomial->childidxs[monomial->nfactors], childidxs, nfactors); /*lint !e866*/
6760  BMScopyMemoryArray(&monomial->exponents[monomial->nfactors], exponents, nfactors); /*lint !e866*/
6761 
6762  monomial->nfactors += nfactors;
6763  monomial->sorted = (monomial->nfactors <= 1);
6764 
6765  return SCIP_OKAY;
6766 }
6767 
6768 /** multiplies a monomial with a monomial */
6770  BMS_BLKMEM* blkmem, /**< block memory */
6771  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6772  SCIP_EXPRDATA_MONOMIAL* factor, /**< factor monomial */
6773  int* childmap /**< map to apply to children in factor, or NULL for 1:1 */
6774  )
6775 {
6776  assert(monomial != NULL);
6777  assert(factor != NULL);
6778 
6779  if( factor->coef == 0.0 )
6780  {
6781  monomial->nfactors = 0;
6782  monomial->coef = 0.0;
6783  return SCIP_OKAY;
6784  }
6785 
6786  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, factor->nfactors, factor->childidxs, factor->exponents) );
6787 
6788  if( childmap != NULL )
6789  {
6790  int i;
6791  for( i = monomial->nfactors - factor->nfactors; i < monomial->nfactors; ++i )
6792  monomial->childidxs[i] = childmap[monomial->childidxs[i]];
6793  }
6794 
6795  monomial->coef *= factor->coef;
6796 
6797  return SCIP_OKAY;
6798 }
6799 
6800 /** replaces the monomial by a power of the monomial
6801  *
6802  * Allows only integers as exponent.
6803  */
6805  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6806  int exponent /**< integer exponent of power operation */
6807  )
6808 {
6809  int i;
6810 
6811  assert(monomial != NULL);
6812 
6813  if( exponent == 1 )
6814  return;
6815 
6816  if( exponent == 0 )
6817  {
6818  /* x^0 = 1, unless x = 0; 0^0 = 0 */
6819  if( monomial->coef != 0.0 )
6820  monomial->coef = 1.0;
6821  monomial->nfactors = 0;
6822  return;
6823  }
6824 
6825  monomial->coef = pow(monomial->coef, (SCIP_Real)exponent);
6826  for( i = 0; i < monomial->nfactors; ++i )
6827  monomial->exponents[i] *= exponent;
6828 }
6829 
6830 /** merges factors that correspond to the same child by adding exponents
6831  *
6832  * Eliminates factors with exponent between -eps and eps.
6833  */
6835  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6836  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6837  )
6838 {
6839  int i;
6840  int offset;
6841 
6842  assert(monomial != NULL);
6843  assert(eps >= 0.0);
6844 
6845  SCIPexprSortMonomialFactors(monomial);
6846 
6847  /* merge factors with same child index by adding up their exponents
6848  * delete factors with exponent 0.0 */
6849  offset = 0;
6850  i = 0;
6851  while( i + offset < monomial->nfactors )
6852  {
6853  if( offset > 0 )
6854  {
6855  assert(monomial->childidxs[i] == -1);
6856  assert(monomial->childidxs[i+offset] >= 0);
6857  monomial->childidxs[i] = monomial->childidxs[i+offset];
6858  monomial->exponents[i] = monomial->exponents[i+offset];
6859 #ifndef NDEBUG
6860  monomial->childidxs[i+offset] = -1;
6861 #endif
6862  }
6863 
6864  while( i+offset+1 < monomial->nfactors && monomial->childidxs[i] == monomial->childidxs[i+offset+1] )
6865  {
6866  monomial->exponents[i] += monomial->exponents[i+offset+1];
6867 #ifndef NDEBUG
6868  monomial->childidxs[i+offset+1] = -1;
6869 #endif
6870  ++offset;
6871  }
6872 
6873  if( EPSZ(monomial->exponents[i], eps) )
6874  {
6875 #ifndef NDEBUG
6876  monomial->childidxs[i] = -1;
6877 #endif
6878  ++offset;
6879  continue;
6880  }
6881  else if( EPSISINT(monomial->exponents[i], eps) )
6882  monomial->exponents[i] = EPSROUND(monomial->exponents[i], eps);
6883 
6884  ++i;
6885  }
6886 
6887 #ifndef NDEBUG
6888  while( i < monomial->nfactors )
6889  assert(monomial->childidxs[i++] == -1);
6890 #endif
6891 
6892  monomial->nfactors -= offset;
6893 
6894  if( EPSEQ(monomial->coef, 1.0, eps) )
6895  monomial->coef = 1.0;
6896  else if( EPSEQ(monomial->coef, -1.0, eps) )
6897  monomial->coef = -1.0;
6898 }
6899 
6900 /** ensures that monomials of a polynomial are sorted */
6902  SCIP_EXPR* expr /**< polynomial expression */
6903  )
6904 {
6905  assert(expr != NULL);
6906  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6907  assert(expr->data.data != NULL);
6908 
6910 }
6911 
6912 /** creates a monomial */
6914  BMS_BLKMEM* blkmem, /**< block memory */
6915  SCIP_EXPRDATA_MONOMIAL** monomial, /**< buffer where to store pointer to new monomial */
6916  SCIP_Real coef, /**< coefficient of monomial */
6917  int nfactors, /**< number of factors in monomial */
6918  int* childidxs, /**< indices of children corresponding to factors, or NULL if identity */
6919  SCIP_Real* exponents /**< exponent in each factor, or NULL if all 1.0 */
6920  )
6921 {
6922  assert(blkmem != NULL);
6923  assert(monomial != NULL);
6924 
6925  SCIP_ALLOC( BMSallocBlockMemory(blkmem, monomial) );
6926 
6927  (*monomial)->coef = coef;
6928  (*monomial)->nfactors = nfactors;
6929  (*monomial)->factorssize = nfactors;
6930  (*monomial)->sorted = (nfactors <= 1);
6931 
6932  if( nfactors > 0 )
6933  {
6934  if( childidxs != NULL )
6935  {
6936  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->childidxs, childidxs, nfactors) );
6937  }
6938  else
6939  {
6940  int i;
6941 
6942  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->childidxs, nfactors) );
6943  for( i = 0; i < nfactors; ++i )
6944  (*monomial)->childidxs[i] = i;
6945  }
6946 
6947  if( exponents != NULL )
6948  {
6949  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->exponents, exponents, nfactors) );
6950  }
6951  else
6952  {
6953  int i;
6954 
6955  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->exponents, nfactors) );
6956  for( i = 0; i < nfactors; ++i )
6957  (*monomial)->exponents[i] = 1.0;
6958  }
6959  }
6960  else
6961  {
6962  (*monomial)->childidxs = NULL;
6963  (*monomial)->exponents = NULL;
6964  }
6965 
6966  return SCIP_OKAY;
6967 }
6968 
6969 /** frees a monomial */
6971  BMS_BLKMEM* blkmem, /**< block memory */
6972  SCIP_EXPRDATA_MONOMIAL** monomial /**< pointer to monomial that should be freed */
6973  )
6974 {
6975  assert(blkmem != NULL);
6976  assert( monomial != NULL);
6977  assert(*monomial != NULL);
6978 
6979  if( (*monomial)->factorssize > 0 )
6980  {
6981  assert((*monomial)->childidxs != NULL);
6982  assert((*monomial)->exponents != NULL);
6983 
6984  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->childidxs, (*monomial)->factorssize);
6985  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->exponents, (*monomial)->factorssize);
6986  }
6987  assert((*monomial)->childidxs == NULL);
6988  assert((*monomial)->exponents == NULL);
6989 
6990  BMSfreeBlockMemory(blkmem, monomial);
6991 }
6992 
6993 /** ensures that factors in a monomial are sorted */
6995  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
6996  )
6997 {
6998  assert(monomial != NULL);
6999 
7000  if( monomial->sorted )
7001  return;
7002 
7003  if( monomial->nfactors > 0 )
7004  SCIPsortIntReal(monomial->childidxs, monomial->exponents, monomial->nfactors);
7005 
7006  monomial->sorted = TRUE;
7007 }
7008 
7009 /** finds a factor corresponding to a given child index in a monomial
7010  *
7011  * Note that if the factors have not been merged, the position of some factor corresponding to a given child is given.
7012  * Returns TRUE if a factor is found, FALSE if not.
7013  */
7015  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
7016  int childidx, /**< index of the child which factor to search for */
7017  int* pos /**< buffer to store position of factor */
7018  )
7019 {
7020  assert(monomial != NULL);
7021 
7022  if( monomial->nfactors == 0 )
7023  return FALSE;
7024 
7025  SCIPexprSortMonomialFactors(monomial);
7026 
7027  return SCIPsortedvecFindInt(monomial->childidxs, childidx, monomial->nfactors, pos);
7028 }
7029 
7030 /** creates a user expression */
7032  BMS_BLKMEM* blkmem, /**< block memory data structure */
7033  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
7034  int nchildren, /**< number of children */
7035  SCIP_EXPR** children, /**< children of expression */
7036  SCIP_USEREXPRDATA* data, /**< user data for expression, expression assumes ownership */
7037  SCIP_EXPRINTCAPABILITY evalcapability, /**< capability of evaluation functions (partially redundant, currently) */
7038  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
7039  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function, or NULL if not implemented */
7040  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
7041  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function, or NULL if not implemented */
7042  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
7043  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
7044  SCIP_DECL_USEREXPRFREEDATA ((*freedata)) /**< expression data free function, or NULL if nothing to free */
7045  )
7046 {
7047  SCIP_EXPROPDATA opdata;
7048  SCIP_EXPRDATA_USER* userexprdata;
7049  SCIP_EXPR** childrencopy;
7050 
7051  assert(blkmem != NULL);
7052  assert(expr != NULL);
7053  assert(children != NULL || nchildren == 0);
7054  assert(eval != NULL);
7055  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
7056  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
7057  assert(curv != NULL);
7058  assert(copydata != NULL || data == NULL);
7059  assert(freedata != NULL || data == NULL);
7060 
7061  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &userexprdata) );
7062 
7063  userexprdata->userdata = data;
7064  userexprdata->evalcapability = evalcapability;
7065  userexprdata->eval = eval;
7066  userexprdata->inteval = inteval;
7067  userexprdata->curv = curv;
7068  userexprdata->prop = prop;
7069  userexprdata->estimate = estimate;
7070  userexprdata->copydata = copydata;
7071  userexprdata->freedata = freedata;
7072 
7073  opdata.data = (void*) userexprdata;
7074 
7075  if( nchildren == 0 )
7076  {
7077  SCIP_CALL( exprCreate(blkmem, expr, SCIP_EXPR_USER, 0, NULL, opdata) );
7078  return SCIP_OKAY;
7079  }
7080 
7081  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
7082 
7083  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_USER, nchildren, childrencopy, opdata) );
7084 
7085  return SCIP_OKAY;
7086 }
7087 
7088 /** indicates whether the expression contains a SCIP_EXPR_PARAM */
7090  SCIP_EXPR* expr /**< expression */
7091  )
7092 {
7093  int i;
7094 
7095  assert(expr != NULL);
7096 
7097  if( expr->op == SCIP_EXPR_PARAM )
7098  return TRUE;
7099 
7100  for( i = 0; i < expr->nchildren; ++i )
7101  if( SCIPexprHasParam(expr->children[i]) )
7102  return TRUE;
7103 
7104  return FALSE;
7105 }
7106 
7107 /** gets maximal degree of expression, or SCIP_EXPR_DEGREEINFINITY if not a polynomial */
7109  SCIP_EXPR* expr, /**< expression */
7110  int* maxdegree /**< buffer to store maximal degree */
7111  )
7112 {
7113  int child1;
7114  int child2;
7115 
7116  assert(expr != NULL);
7117  assert(maxdegree != NULL);
7118 
7119  switch( expr->op )
7120  {
7121  case SCIP_EXPR_VARIDX:
7122  *maxdegree = 1;
7123  break;
7124 
7125  case SCIP_EXPR_CONST:
7126  case SCIP_EXPR_PARAM:
7127  *maxdegree = 0;
7128  break;
7129 
7130  case SCIP_EXPR_PLUS:
7131  case SCIP_EXPR_MINUS:
7132  {
7133  assert(expr->children[0] != NULL);
7134  assert(expr->children[1] != NULL);
7135 
7136  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7137  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7138 
7139  *maxdegree = MAX(child1, child2);
7140  break;
7141  }
7142 
7143  case SCIP_EXPR_MUL:
7144  {
7145  assert(expr->children[0] != NULL);
7146  assert(expr->children[1] != NULL);
7147 
7148  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7149  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7150 
7151  *maxdegree = child1 + child2;
7152  break;
7153  }
7154 
7155  case SCIP_EXPR_DIV:
7156  {
7157  assert(expr->children[0] != NULL);
7158  assert(expr->children[1] != NULL);
7159 
7160  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7161  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7162 
7163  /* if not division by constant, then it is not a polynomial */
7164  *maxdegree = (child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : child1;
7165  break;
7166  }
7167 
7168  case SCIP_EXPR_SQUARE:
7169  {
7170  assert(expr->children[0] != NULL);
7171 
7172  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7173 
7174  *maxdegree = 2 * child1;
7175  break;
7176  }
7177 
7178  case SCIP_EXPR_SQRT:
7179  {
7180  assert(expr->children[0] != NULL);
7181 
7182  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7183 
7184  /* if not squareroot of constant, then no polynomial */
7185  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7186  break;
7187  }
7188 
7189  case SCIP_EXPR_REALPOWER:
7190  {
7191  assert(expr->children[0] != NULL);
7192 
7193  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7194 
7195  /* constant ^ constant has degree 0 */
7196  if( child1 == 0 )
7197  {
7198  *maxdegree = 0;
7199  break;
7200  }
7201 
7202  /* non-polynomial ^ constant is not a polynomial */
7203  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7204  {
7205  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7206  break;
7207  }
7208 
7209  /* so it is polynomial ^ constant
7210  * let's see whether the constant is integral */
7211 
7212  if( expr->data.dbl == 0.0 ) /* polynomial ^ 0 == 0 */
7213  *maxdegree = 0;
7214  else if( expr->data.dbl > 0.0 && (int)expr->data.dbl == expr->data.dbl ) /* natural exponent gives polynomial again */ /*lint !e777*/
7215  *maxdegree = child1 * (int)expr->data.dbl;
7216  else /* negative or nonintegral exponent does not give polynomial */
7217  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7218 
7219  break;
7220  }
7221 
7222  case SCIP_EXPR_INTPOWER:
7223  {
7224  assert(expr->children[0] != NULL);
7225 
7226  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7227 
7228  /* constant ^ integer or something ^ 0 has degree 0 */
7229  if( child1 == 0 || expr->data.intval == 0 )
7230  {
7231  *maxdegree = 0;
7232  break;
7233  }
7234 
7235  /* non-polynomial ^ integer or something ^ negative is not a polynomial */
7236  if( child1 >= SCIP_EXPR_DEGREEINFINITY || expr->data.intval < 0 )
7237  {
7238  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7239  break;
7240  }
7241 
7242  /* so it is polynomial ^ natural, which gives a polynomial again */
7243  *maxdegree = child1 * expr->data.intval;
7244 
7245  break;
7246  }
7247 
7248  case SCIP_EXPR_SIGNPOWER:
7249  {
7250  assert(expr->children[0] != NULL);
7251 
7252  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7253 
7254  /* if child is not constant, then it is no polynomial */
7255  *maxdegree = child1 != 0 ? SCIP_EXPR_DEGREEINFINITY : 0;
7256  break;
7257  }
7258 
7259  case SCIP_EXPR_EXP:
7260  case SCIP_EXPR_LOG:
7261  case SCIP_EXPR_SIN:
7262  case SCIP_EXPR_COS:
7263  case SCIP_EXPR_TAN:
7264  /* case SCIP_EXPR_ERF: */
7265  /* case SCIP_EXPR_ERFI: */
7266  case SCIP_EXPR_ABS:
7267  case SCIP_EXPR_SIGN:
7268  case SCIP_EXPR_USER:
7269  {
7270  assert(expr->children[0] != NULL);
7271 
7272  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7273 
7274  /* if argument is not a constant, then no polynomial, otherwise it is a constant */
7275  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7276  break;
7277  }
7278 
7279  case SCIP_EXPR_MIN:
7280  case SCIP_EXPR_MAX:
7281  {
7282  assert(expr->children[0] != NULL);
7283  assert(expr->children[1] != NULL);
7284 
7285  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7286  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7287 
7288  /* if any of the operands is not constant, then it is no polynomial */
7289  *maxdegree = (child1 != 0 || child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7290  break;
7291  }
7292 
7293  case SCIP_EXPR_SUM:
7294  case SCIP_EXPR_LINEAR:
7295  {
7296  int i;
7297 
7298  *maxdegree = 0;
7299  for( i = 0; i < expr->nchildren && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7300  {
7301  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7302  if( child1 > *maxdegree )
7303  *maxdegree = child1;
7304  }
7305 
7306  break;
7307  }
7308 
7309  case SCIP_EXPR_PRODUCT:
7310  {
7311  int i;
7312 
7313  *maxdegree = 0;
7314  for( i = 0; i < expr->nchildren; ++i )
7315  {
7316  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7317  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7318  {
7319  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7320  break;
7321  }
7322  *maxdegree += child1;
7323  }
7324 
7325  break;
7326  }
7327 
7328  case SCIP_EXPR_QUADRATIC:
7329  {
7330  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7331  int childidx;
7332  int quadidx;
7333 
7334  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7335 
7336  /* make sure quadratic elements are sorted */
7337  quadraticdataSort(quadraticdata);
7338 
7339  *maxdegree = 0;
7340  quadidx = 0;
7341  for( childidx = 0; childidx < expr->nchildren; ++childidx )
7342  {
7343  /* if no linear or no quadratic coefficient with current child on first position, then nothing to do */
7344  if( (quadraticdata->lincoefs == NULL || quadraticdata->lincoefs[childidx] == 0.0) &&
7345  (quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 > childidx) )
7346  continue;
7347 
7348  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[childidx], &child1) );
7349  if( child1 == SCIP_EXPR_DEGREEINFINITY )
7350  {
7351  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7352  break;
7353  }
7354 
7355  while( quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 == childidx )
7356  {
7357  if( quadraticdata->quadelems[quadidx].idx2 == childidx )
7358  {
7359  /* square term */
7360  if( 2*child1 > *maxdegree )
7361  *maxdegree = 2*child1;
7362  }
7363  else
7364  {
7365  /* bilinear term */
7366  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[quadraticdata->quadelems[quadidx].idx2], &child2) );
7367  if( child2 == SCIP_EXPR_DEGREEINFINITY )
7368  {
7369  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7370  break;
7371  }
7372  if( child1 + child2 > *maxdegree )
7373  *maxdegree = child1 + child2;
7374  }
7375  ++quadidx;
7376  }
7377  if( *maxdegree == SCIP_EXPR_DEGREEINFINITY )
7378  break;
7379  }
7380 
7381  break;
7382  }
7383 
7384  case SCIP_EXPR_POLYNOMIAL:
7385  {
7386  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7387  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7388  int monomialdegree;
7389  int i;
7390  int j;
7391 
7392  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7393 
7394  *maxdegree = 0;
7395  for( i = 0; i < polynomialdata->nmonomials && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7396  {
7397  monomialdata = polynomialdata->monomials[i];
7398  assert(monomialdata != NULL);
7399 
7400  /* compute degree of monomial = sum of degree of factors */
7401  monomialdegree = 0;
7402  for( j = 0; j < monomialdata->nfactors; ++j )
7403  {
7404  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[monomialdata->childidxs[j]], &child1) );
7405 
7406  /* if the exponent of the factor is not a natural number and the child is not constant (degree 0),
7407  * then we report that we are not really a polynomial */
7408  if( child1 != 0 && (monomialdata->exponents[j] < 0.0 || (int)monomialdata->exponents[j] != monomialdata->exponents[j]) )
7409  {
7410  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7411  break;
7412  }
7413 
7414  monomialdegree += child1 * (int)monomialdata->exponents[j];
7415  }
7416 
7417  if( monomialdegree > *maxdegree )
7418  *maxdegree = monomialdegree;
7419  }
7420 
7421  break;
7422  }
7423 
7424  case SCIP_EXPR_LAST:
7425  SCIPABORT();
7426  break;
7427  }
7428 
7429  return SCIP_OKAY;
7430 }
7431 
7432 /** counts usage of variables in expression */
7434  SCIP_EXPR* expr, /**< expression to update */
7435  int* varsusage /**< array with counters of variable usage */
7436  )
7437 {
7438  int i;
7439 
7440  assert(expr != NULL);
7441  assert(varsusage != NULL);
7442 
7443  if( expr->op == SCIP_EXPR_VARIDX )
7444  {
7445  ++varsusage[expr->data.intval];
7446  }
7447 
7448  for( i = 0; i < expr->nchildren; ++i )
7449  SCIPexprGetVarsUsage(expr->children[i], varsusage);
7450 }
7451 
7452 /** compares whether two expressions are the same
7453  *
7454  * Inconclusive, i.e., may give FALSE even if expressions are equivalent (x*y != y*x).
7455  */
7457  SCIP_EXPR* expr1, /**< first expression */
7458  SCIP_EXPR* expr2, /**< second expression */
7459  SCIP_Real eps /**< threshold under which numbers are assumed to be zero */
7460  )
7461 {
7462  assert(expr1 != NULL);
7463  assert(expr2 != NULL);
7464 
7465  if( expr1 == expr2 )
7466  return TRUE;
7467 
7468  if( expr1->op != expr2->op )
7469  return FALSE;
7470 
7471  switch( expr1->op )
7472  {
7473  case SCIP_EXPR_VARIDX:
7474  case SCIP_EXPR_PARAM:
7475  return expr1->data.intval == expr2->data.intval;
7476 
7477  case SCIP_EXPR_CONST:
7478  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps);
7479 
7480  /* operands with two children */
7481  case SCIP_EXPR_PLUS :
7482  case SCIP_EXPR_MINUS :
7483  case SCIP_EXPR_MUL :
7484  case SCIP_EXPR_DIV :
7485  case SCIP_EXPR_MIN :
7486  case SCIP_EXPR_MAX :
7487  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps) && SCIPexprAreEqual(expr1->children[1], expr2->children[1], eps);
7488 
7489  /* operands with one child */
7490  case SCIP_EXPR_SQUARE:
7491  case SCIP_EXPR_SQRT :
7492  case SCIP_EXPR_EXP :
7493  case SCIP_EXPR_LOG :
7494  case SCIP_EXPR_SIN :
7495  case SCIP_EXPR_COS :
7496  case SCIP_EXPR_TAN :
7497  /* case SCIP_EXPR_ERF : */
7498  /* case SCIP_EXPR_ERFI : */
7499  case SCIP_EXPR_ABS :
7500  case SCIP_EXPR_SIGN :
7501  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7502 
7503  case SCIP_EXPR_REALPOWER:
7504  case SCIP_EXPR_SIGNPOWER:
7505  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps) && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7506 
7507  case SCIP_EXPR_INTPOWER:
7508  return expr1->data.intval == expr2->data.intval && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7509 
7510  /* complex operands */
7511  case SCIP_EXPR_SUM :
7512  case SCIP_EXPR_PRODUCT:
7513  {
7514  int i;
7515 
7516  /* @todo sort children and have sorted flag in data? */
7517 
7518  if( expr1->nchildren != expr2->nchildren )
7519  return FALSE;
7520 
7521  for( i = 0; i < expr1->nchildren; ++i )
7522  {
7523  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7524  return FALSE;
7525  }
7526 
7527  return TRUE;
7528  }
7529 
7530  case SCIP_EXPR_LINEAR :
7531  {
7532  SCIP_Real* data1;
7533  SCIP_Real* data2;
7534  int i;
7535 
7536  /* @todo sort children and have sorted flag in data? */
7537 
7538  if( expr1->nchildren != expr2->nchildren )
7539  return FALSE;
7540 
7541  data1 = (SCIP_Real*)expr1->data.data;
7542  data2 = (SCIP_Real*)expr2->data.data;
7543 
7544  /* check if constant and coefficients are equal */
7545  for( i = 0; i < expr1->nchildren + 1; ++i )
7546  if( !EPSEQ(data1[i], data2[i], eps) )
7547  return FALSE;
7548 
7549  /* check if children are equal */
7550  for( i = 0; i < expr1->nchildren; ++i )
7551  {
7552  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7553  return FALSE;
7554  }
7555 
7556  return TRUE;
7557  }
7558 
7559  case SCIP_EXPR_QUADRATIC:
7560  {
7561  SCIP_EXPRDATA_QUADRATIC* data1;
7562  SCIP_EXPRDATA_QUADRATIC* data2;
7563  int i;
7564 
7565  if( expr1->nchildren != expr2->nchildren )
7566  return FALSE;
7567 
7568  data1 = (SCIP_EXPRDATA_QUADRATIC*)expr1->data.data;
7569  data2 = (SCIP_EXPRDATA_QUADRATIC*)expr2->data.data;
7570 
7571  if( data1->nquadelems != data2->nquadelems )
7572  return FALSE;
7573 
7574  if( !EPSEQ(data1->constant, data2->constant, eps) )
7575  return FALSE;
7576 
7577  /* check if linear part is equal */
7578  if( data1->lincoefs != NULL || data2->lincoefs != NULL )
7579  for( i = 0; i < expr1->nchildren; ++i )
7580  {
7581  if( data1->lincoefs == NULL && !EPSZ(data2->lincoefs[i], eps) )
7582  return FALSE;
7583  if( data2->lincoefs == NULL && !EPSZ(data1->lincoefs[i], eps) )
7584  return FALSE;
7585  if( !EPSEQ(data1->lincoefs[i], data2->lincoefs[i], eps) )
7586  return FALSE;
7587  }
7588 
7589  SCIPexprSortQuadElems(expr1);
7590  SCIPexprSortQuadElems(expr2);
7591 
7592  /* check if quadratic elements are equal */
7593  for( i = 0; i < data1->nquadelems; ++i )
7594  if( data1->quadelems[i].idx1 != data2->quadelems[i].idx1 ||
7595  data1->quadelems[i].idx2 != data2->quadelems[i].idx2 ||
7596  !EPSEQ(data1->quadelems[i].coef, data2->quadelems[i].coef, eps) )
7597  return FALSE;
7598 
7599  /* check if children are equal */
7600  for( i = 0; i < expr1->nchildren; ++i )
7601  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7602  return FALSE;
7603 
7604  return TRUE;
7605  }
7606 
7607  case SCIP_EXPR_POLYNOMIAL:
7608  {
7609  SCIP_EXPRDATA_POLYNOMIAL* data1;
7610  SCIP_EXPRDATA_POLYNOMIAL* data2;
7611  int i;
7612 
7613  if( expr1->nchildren != expr2->nchildren )
7614  return FALSE;
7615 
7616  data1 = (SCIP_EXPRDATA_POLYNOMIAL*)expr1->data.data;
7617  data2 = (SCIP_EXPRDATA_POLYNOMIAL*)expr2->data.data;
7618 
7619  if( data1->nmonomials != data2->nmonomials )
7620  return FALSE;
7621 
7622  if( !EPSEQ(data1->constant, data2->constant, eps) )
7623  return FALSE;
7624 
7625  /* make sure polynomials are sorted */
7626  SCIPexprSortMonomials(expr1);
7627  SCIPexprSortMonomials(expr2);
7628 
7629  /* check if monomials are equal */
7630  for( i = 0; i < data1->nmonomials; ++i )
7631  {
7632  if( !SCIPexprAreMonomialsEqual(data1->monomials[i], data2->monomials[i], eps) )
7633  return FALSE;
7634  }
7635 
7636  /* check if children are equal */
7637  for( i = 0; i < expr1->nchildren; ++i )
7638  {
7639  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7640  return FALSE;
7641  }
7642 
7643  return TRUE;
7644  }
7645 
7646  case SCIP_EXPR_USER:
7647  {
7648  /* @todo could implement this via another user callback */
7649  return FALSE;
7650  }
7651 
7652  case SCIP_EXPR_LAST:
7653  break;
7654  }
7655 
7656  SCIPerrorMessage("this should never happen\n");
7657  SCIPABORT();
7658  return FALSE; /*lint !e527*/
7659 }
7660 
7661 /** aims at simplifying an expression and splitting of a linear expression
7662  *
7663  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
7664  */
7666  BMS_BLKMEM* blkmem, /**< block memory data structure */
7667  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7668  SCIP_EXPR* expr, /**< expression */
7669  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
7670  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
7671  int nvars, /**< number of variables in expression */
7672  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
7673  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
7674  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
7675  )
7676 {
7677  assert(blkmem != NULL);
7678  assert(expr != NULL);
7679  assert(eps >= 0.0);
7680 
7681  SCIPdebugMessage("simplify expression: ");
7682  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7683  SCIPdebugPrintf("\n");
7684 
7686 
7687  SCIPdebugMessage("converted to polynomials: ");
7688  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7689  SCIPdebugPrintf("\n");
7690 
7691  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr, eps, maxexpansionexponent) );
7692 
7693  SCIPdebugMessage("polynomials flattened: ");
7694  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7695  SCIPdebugPrintf("\n");
7696 
7697  if( nlinvars != NULL )
7698  {
7699  /* separate linear part from root polynomial */
7700  SCIP_CALL( exprsimplifySeparateLinearFromPolynomial(blkmem, expr, eps, nvars, nlinvars, linidxs, lincoefs) );
7701 
7702  SCIPdebugMessage("separated linear part: ");
7703  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7704  SCIPdebugPrintf("\n");
7705  }
7706 
7708 
7709  SCIPdebugMessage("converted back from polynomials: ");
7710  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7711  SCIPdebugPrintf("\n");
7712 
7713  return SCIP_OKAY;
7714 }
7715 
7716 /** evaluates an expression w.r.t. given values for children expressions */
7718  SCIP_EXPR* expr, /**< expression */
7719  SCIP_Real* argvals, /**< values for children, can be NULL if the expression has no children */
7720  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression operand is not a variable */
7721  SCIP_Real* param, /**< values for parameters, can be NULL if the expression operand is not a parameter */
7722  SCIP_Real* val /**< buffer to store value */
7723  )
7724 {
7725  assert(expr != NULL);
7726  assert(argvals != NULL || expr->nchildren == 0);
7727 
7728  /* evaluate this expression */
7729  assert( exprOpTable[expr->op].eval != NULL );
7730  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, argvals, varvals, param, val) );
7731 
7732  return SCIP_OKAY;
7733 }
7734 
7735 /** evaluates an expression w.r.t. a point */
7737  SCIP_EXPR* expr, /**< expression */
7738  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression is constant */
7739  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7740  SCIP_Real* val /**< buffer to store value */
7741  )
7742 {
7743  int i;
7745  SCIP_Real* buf;
7746 
7747  /* if many children, get large enough memory to store argument values */
7749  {
7750  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7751  }
7752  else
7753  {
7754  buf = staticbuf;
7755  }
7756 
7757  /* evaluate children */
7758  for( i = 0; i < expr->nchildren; ++i )
7759  {
7760  SCIP_CALL( SCIPexprEval(expr->children[i], varvals, param, &buf[i]) ); /*lint !e644*/
7761  }
7762 
7763  /* evaluate this expression */
7764  assert( exprOpTable[expr->op].eval != NULL );
7765  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, buf, varvals, param, val) );
7766 
7767  /* free memory, if allocated before */
7768  if( staticbuf != buf )
7769  {
7770  BMSfreeMemoryArray(&buf);
7771  }
7772 
7773  return SCIP_OKAY;
7774 }
7775 
7776 /** evaluates an expression w.r.t. given interval values for children expressions */
7778  SCIP_EXPR* expr, /**< expression */
7779  SCIP_Real infinity, /**< value to use for infinity */
7780  SCIP_INTERVAL* argvals, /**< interval values for children, can be NULL if the expression has no children */
7781  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7782  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7783  SCIP_INTERVAL* val /**< buffer to store value */
7784  )
7785 {
7786  assert(expr != NULL);
7787  assert(argvals != NULL || expr->nchildren == 0);
7788 
7789  /* evaluate this expression */
7790  assert( exprOpTable[expr->op].inteval != NULL );
7791  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, argvals, varvals, param, val) );
7792 
7793  return SCIP_OKAY;
7794 }
7795 
7796 /** evaluates an expression w.r.t. an interval */
7798  SCIP_EXPR* expr, /**< expression */
7799  SCIP_Real infinity, /**< value to use for infinity */
7800  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7801  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7802  SCIP_INTERVAL* val /**< buffer to store value */
7803  )
7804 {
7805  int i;
7807  SCIP_INTERVAL* buf;
7808 
7809  /* if many children, get large enough memory to store argument values */
7811  {
7812  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7813  }
7814  else
7815  {
7816  buf = staticbuf;
7817  }
7818 
7819  /* evaluate children */
7820  for( i = 0; i < expr->nchildren; ++i )
7821  {
7822  SCIP_CALL( SCIPexprEvalInt(expr->children[i], infinity, varvals, param, &buf[i]) ); /*lint !e644*/
7823  }
7824 
7825  /* evaluate this expression */
7826  assert( exprOpTable[expr->op].inteval != NULL );
7827  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, buf, varvals, param, val) );
7828 
7829  /* free memory, if allocated before */
7830  if( staticbuf != buf )
7831  {
7832  BMSfreeMemoryArray(&buf);
7833  }
7834 
7835  return SCIP_OKAY;
7836 }
7837 
7838 /** evaluates a user expression w.r.t. given values for children expressions */
7840  SCIP_EXPR* expr, /**< expression */
7841  SCIP_Real* argvals, /**< values for children */
7842  SCIP_Real* val, /**< buffer to store function value */
7843  SCIP_Real* gradient, /**< buffer to store gradient values, or NULL if not requested */
7844  SCIP_Real* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7845  )
7846 {
7847  SCIP_EXPRDATA_USER* exprdata;
7848 
7849  assert(expr != NULL);
7850  assert(expr->op == SCIP_EXPR_USER);
7851  assert(argvals != NULL || expr->nchildren == 0);
7852 
7853  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7854  assert(exprdata->eval != NULL);
7855 
7856  SCIP_CALL( exprdata->eval(exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7857 
7858  return SCIP_OKAY;
7859 }
7860 
7861 /** evaluates a user expression w.r.t. an interval */
7863  SCIP_EXPR* expr, /**< expression */
7864  SCIP_Real infinity, /**< value to use for infinity */
7865  SCIP_INTERVAL* argvals, /**< values for children */
7866  SCIP_INTERVAL* val, /**< buffer to store value */
7867  SCIP_INTERVAL* gradient, /**< buffer to store gradient values, or NULL if not requested */
7868  SCIP_INTERVAL* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7869  )
7870 {
7871  SCIP_EXPRDATA_USER* exprdata;
7872 
7873  assert(expr != NULL);
7874  assert(expr->op == SCIP_EXPR_USER);
7875  assert(argvals != NULL || expr->nchildren == 0);
7876 
7877  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7878 
7879  if( exprdata->inteval == NULL )
7880  {
7881  int i;
7882 
7883  for( i = 0; i < expr->nchildren; ++i )
7884  SCIPintervalSetEntire(infinity, &argvals[i]); /*lint !e613*/
7885  }
7886  else
7887  {
7888  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7889  }
7890 
7891  return SCIP_OKAY;
7892 }
7893 
7894 /** tries to determine the curvature type of an expression w.r.t. given variable domains */
7896  SCIP_EXPR* expr, /**< expression to check */
7897  SCIP_Real infinity, /**< value to use for infinity */
7898  SCIP_INTERVAL* varbounds, /**< domains of variables */
7899  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7900  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
7901  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
7902  )
7903 {
7905  SCIP_INTERVAL* childbounds;
7907  SCIP_EXPRCURV* childcurv;
7908  int i;
7909 
7910  assert(expr != NULL);
7911  assert(curv != NULL);
7912  assert(bounds != NULL);
7913 
7914  /* if many children, get large enough memory to store argument values */
7916  {
7917  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, expr->nchildren) );
7918  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, expr->nchildren) );
7919  }
7920  else
7921  {
7922  childbounds = childboundsbuf;
7923  childcurv = childcurvbuf;
7924  }
7925 
7926  /* check curvature and compute bounds of children
7927  * constant children can be considered as always linear */
7928  for( i = 0; i < expr->nchildren; ++i )
7929  {
7930  SCIP_CALL( SCIPexprCheckCurvature(expr->children[i], infinity, varbounds, param, &childcurv[i], &childbounds[i]) ); /*lint !e644*/
7931  if( childbounds[i].inf == childbounds[i].sup ) /*lint !e777*/
7932  childcurv[i] = SCIP_EXPRCURV_LINEAR;
7933  }
7934 
7935  /* get curvature and bounds of expr */
7936  assert(exprOpTable[expr->op].curv != NULL);
7937  assert(exprOpTable[expr->op].inteval != NULL);
7938 
7939  SCIP_CALL( exprOpTable[expr->op].curv(infinity, expr->data, expr->nchildren, childbounds, childcurv, curv) );
7940  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, childbounds, varbounds, param, bounds) );
7941 
7942  /* free memory, if allocated before */
7943  if( childboundsbuf != childbounds )
7944  {
7945  BMSfreeMemoryArray(&childcurv);
7946  BMSfreeMemoryArray(&childbounds);
7947  }
7948 
7949  return SCIP_OKAY;
7950 }
7951 
7952 /** under-/overestimates a user expression w.r.t. to given values and bounds for children expressions */
7954  SCIP_EXPR* expr, /**< expression */
7955  SCIP_Real infinity, /**< value to use for infinity */
7956  SCIP_Real* argvals, /**< values for children */
7957  SCIP_INTERVAL* argbounds, /**< bounds for children */
7958  SCIP_Bool overestimate, /**< whether to overestimate the expression */
7959  SCIP_Real* coeffs, /**< buffer to store the linear coefficients for each child expression that gives a valid under-/overestimator */
7960  SCIP_Real* constant, /**< buffer to store the constant value of the linear under-/overestimator */
7961  SCIP_Bool* success /**< buffer to store whether an estimator was successfully computed */
7962  )
7963 {
7964  SCIP_EXPRDATA_USER* exprdata;
7965 
7966  assert(expr != NULL);
7967  assert(expr->op == SCIP_EXPR_USER);
7968  assert(argvals != NULL || expr->nchildren == 0);
7969  assert(argbounds != NULL || expr->nchildren == 0);
7970 
7971  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7972 
7973  if( exprdata->estimate != NULL )
7974  {
7975  SCIP_CALL( exprdata->estimate(infinity, exprdata->userdata, expr->nchildren, argvals, argbounds, overestimate, coeffs, constant, success ) );
7976  }
7977  else
7978  {
7979  *success = FALSE;
7980  }
7981 
7982  return SCIP_OKAY;
7983 }
7984 
7985 /** substitutes variables (SCIP_EXPR_VARIDX) by expressions
7986  *
7987  * Note that only the children of the given expr are checked!
7988  * A variable with index i is replaced by a copy of substexprs[i], if the latter is not NULL.
7989  * If substexprs[i] == NULL, then the variable expression i is not touched.
7990  */
7992  BMS_BLKMEM* blkmem, /**< block memory data structure */
7993  SCIP_EXPR* expr, /**< expression, which of the children may be replaced */
7994  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
7995  )
7996 {
7997  int i;
7998 
7999  assert(blkmem != NULL);
8000  assert(expr != NULL);
8001  assert(substexprs != NULL);
8002 
8003  for( i = 0; i < expr->nchildren; ++i )
8004  {
8005  if( expr->children[i]->op == SCIP_EXPR_VARIDX )
8006  {
8007  int varidx;
8008  varidx = expr->children[i]->data.intval;
8009 
8010  assert(varidx >= 0);
8011  if( substexprs[varidx] != NULL )
8012  {
8013  /* replace child i by copy of substexprs[expr->children[i]->opdata.intval] */
8014  SCIPexprFreeDeep(blkmem, &expr->children[i]);
8015  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[i], substexprs[varidx]) );
8016  }
8017  }
8018  else
8019  {
8020  /* call recursively */
8021  SCIP_CALL( SCIPexprSubstituteVars(blkmem, expr->children[i], substexprs) );
8022  }
8023  }
8024 
8025  return SCIP_OKAY;
8026 }
8027 
8028 /** updates variable indices in expression tree */
8030  SCIP_EXPR* expr, /**< expression to update */
8031  int* newindices /**< new indices of variables */
8032  )
8033 {
8034  int i;
8035 
8036  assert(expr != NULL);
8037  assert(newindices != NULL);
8038 
8039  if( expr->op == SCIP_EXPR_VARIDX )
8040  {
8041  expr->data.intval = newindices[expr->data.intval];
8042  assert(expr->data.intval >= 0);
8043  }
8044 
8045  for( i = 0; i < expr->nchildren; ++i )
8046  SCIPexprReindexVars(expr->children[i], newindices);
8047 }
8048 
8049 /** updates parameter indices in expression tree */
8051  SCIP_EXPR* expr, /**< expression to update */
8052  int* newindices /**< new indices of variables */
8053  )
8054 {
8055  int i;
8056 
8057  assert(expr != NULL);
8058  assert(newindices != NULL);
8059 
8060  if( expr->op == SCIP_EXPR_PARAM )
8061  {
8062  expr->data.intval = newindices[expr->data.intval];
8063  assert(expr->data.intval >= 0);
8064  }
8065 
8066  for( i = 0; i < expr->nchildren; ++i )
8067  SCIPexprReindexParams(expr->children[i], newindices);
8068 }
8069 
8070 /** prints an expression */
8072  SCIP_EXPR* expr, /**< expression */
8073  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8074  FILE* file, /**< file for printing, or NULL for stdout */
8075  const char** varnames, /**< names of variables, or NULL for default names */
8076  const char** paramnames, /**< names of parameters, or NULL for default names */
8077  SCIP_Real* paramvals /**< values of parameters, or NULL for not printing */
8078  )
8079 {
8080  assert( expr != NULL );
8081 
8082  switch( expr->op )
8083  {
8084  /* @Note: 'expr->data.intval' is either between 0 and number of variables-1, if it uses the varnames array, or
8085  * between 0 and number of params in the expression tree, if it uses the paramnames array
8086  * because, here, we cannot get the values above we cannot assert them
8087  */
8088  case SCIP_EXPR_VARIDX:
8089  if( varnames != NULL )
8090  {
8091  assert(varnames[expr->data.intval] != NULL);
8092  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", varnames[expr->data.intval]);
8093  }
8094  else
8095  {
8096  SCIPmessageFPrintInfo(messagehdlr, file, "var%d", expr->data.intval);
8097  }
8098  break;
8099 
8100  case SCIP_EXPR_PARAM:
8101  if( paramnames != NULL )
8102  {
8103  assert(paramnames[expr->data.intval] != NULL);
8104  SCIPmessageFPrintInfo(messagehdlr, file, "%s", paramnames[expr->data.intval]);
8105  }
8106  else
8107  {
8108  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", expr->data.intval );
8109  }
8110  if( paramvals != NULL )
8111  {
8112  SCIPmessageFPrintInfo(messagehdlr, file, "[%g]", paramvals[expr->data.intval] );
8113  }
8114  break;
8115 
8116  case SCIP_EXPR_CONST:
8117  if (expr->data.dbl < 0.0 )
8118  SCIPmessageFPrintInfo(messagehdlr, file, "(%lf)", expr->data.dbl );
8119  else
8120  SCIPmessageFPrintInfo(messagehdlr, file, "%lf", expr->data.dbl );
8121  break;
8122 
8123  case SCIP_EXPR_PLUS:
8124  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8125  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8126  SCIPmessageFPrintInfo(messagehdlr, file, " + ");
8127  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8128  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8129  break;
8130 
8131  case SCIP_EXPR_MINUS:
8132  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8133  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8134  SCIPmessageFPrintInfo(messagehdlr, file, " - ");
8135  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8136  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8137  break;
8138 
8139  case SCIP_EXPR_MUL:
8140  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8141  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8142  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8143  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8144  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8145  break;
8146 
8147  case SCIP_EXPR_DIV:
8148  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8149  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8150  SCIPmessageFPrintInfo(messagehdlr, file, " / ");
8151  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8152  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8153  break;
8154 
8155  case SCIP_EXPR_REALPOWER:
8156  case SCIP_EXPR_SIGNPOWER:
8157  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8158  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8159  SCIPmessageFPrintInfo(messagehdlr, file, ", %g)", expr->data.dbl);
8160  break;
8161 
8162  case SCIP_EXPR_INTPOWER:
8163  SCIPmessageFPrintInfo(messagehdlr, file, "power(");
8164  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8165  SCIPmessageFPrintInfo(messagehdlr, file, ", %d)", expr->data.intval);
8166  break;
8167 
8168  case SCIP_EXPR_SQUARE:
8169  case SCIP_EXPR_SQRT:
8170  case SCIP_EXPR_EXP:
8171  case SCIP_EXPR_LOG:
8172  case SCIP_EXPR_SIN:
8173  case SCIP_EXPR_COS:
8174  case SCIP_EXPR_TAN:
8175  /* case SCIP_EXPR_ERF: */
8176  /* case SCIP_EXPR_ERFI: */
8177  case SCIP_EXPR_MIN:
8178  case SCIP_EXPR_MAX:
8179  case SCIP_EXPR_ABS:
8180  case SCIP_EXPR_SIGN:
8181  {
8182  int i;
8183 
8184  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8185 
8186  for( i = 0; i < expr->nchildren; ++i )
8187  {
8188  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8189  if( i + 1 < expr->nchildren )
8190  {
8191  SCIPmessageFPrintInfo(messagehdlr, file, ", ");
8192  }
8193  }
8194 
8195  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8196  break;
8197  }
8198 
8199  case SCIP_EXPR_SUM:
8200  case SCIP_EXPR_PRODUCT:
8201  {
8202  switch( expr->nchildren )
8203  {
8204  case 0:
8205  SCIPmessageFPrintInfo(messagehdlr, file, expr->op == SCIP_EXPR_SUM ? "0" : "1");
8206  break;
8207  case 1:
8208  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8209  break;
8210  default:
8211  {
8212  int i;
8213  const char* opstr = expr->op == SCIP_EXPR_SUM ? " + " : " * ";
8214 
8215  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8216  for( i = 0; i < expr->nchildren; ++i )
8217  {
8218  if( i > 0 )
8219  {
8220  SCIPmessageFPrintInfo(messagehdlr, file, opstr);
8221  }
8222  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8223  }
8224  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8225  }
8226  }
8227  break;
8228  }
8229 
8230  case SCIP_EXPR_LINEAR:
8231  {
8232  SCIP_Real constant;
8233  int i;
8234 
8235  constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
8236 
8237  if( expr->nchildren == 0 )
8238  {
8239  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
8240  break;
8241  }
8242 
8243  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8244 
8245  if( constant != 0.0 )
8246  {
8247  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
8248  }
8249 
8250  for( i = 0; i < expr->nchildren; ++i )
8251  {
8252  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", ((SCIP_Real*)expr->data.data)[i]);
8253  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8254  }
8255 
8256  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8257  break;
8258  }
8259 
8260  case SCIP_EXPR_QUADRATIC:
8261  {
8262  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
8263  int i;
8264 
8265  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
8266  assert(quadraticdata != NULL);
8267 
8268  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8269 
8270  if( quadraticdata->constant != 0.0 )
8271  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->constant);
8272 
8273  if( quadraticdata->lincoefs != NULL )
8274  for( i = 0; i < expr->nchildren; ++i )
8275  {
8276  if( quadraticdata->lincoefs[i] == 0.0 )
8277  continue;
8278  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->lincoefs[i]);
8279  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8280  }
8281 
8282  for( i = 0; i < quadraticdata->nquadelems; ++i )
8283  {
8284  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->quadelems[i].coef);
8285  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
8286  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
8287  {
8288  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
8289  }
8290  else
8291  {
8292  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8293  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
8294  }
8295  }
8296 
8297  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8298  break;
8299  }
8300 
8301  case SCIP_EXPR_POLYNOMIAL:
8302  {
8303  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
8304  SCIP_EXPRDATA_MONOMIAL* monomialdata;
8305  int i;
8306  int j;
8307 
8308  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8309 
8310  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
8311  assert(polynomialdata != NULL);
8312 
8313  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
8314  {
8315  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", polynomialdata->constant);
8316  }
8317 
8318  for( i = 0; i < polynomialdata->nmonomials; ++i )
8319  {
8320  monomialdata = polynomialdata->monomials[i];
8321  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g", monomialdata->coef);
8322 
8323  for( j = 0; j < monomialdata->nfactors; ++j )
8324  {
8325  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8326 
8327  SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
8328  if( monomialdata->exponents[j] < 0.0 )
8329  {
8330  SCIPmessageFPrintInfo(messagehdlr, file, "^(%.20g)", monomialdata->exponents[j]);
8331  }
8332  else if( monomialdata->exponents[j] != 1.0 )
8333  {
8334  SCIPmessageFPrintInfo(messagehdlr, file, "^%.20g", monomialdata->exponents[j]);
8335  }
8336  }
8337  }
8338 
8339  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8340  break;
8341  }
8342 
8343  case SCIP_EXPR_USER:
8344  {
8345  /* @todo allow for user printing callback
8346  SCIP_EXPRDATA_USER* exprdata;
8347 
8348  exprdata = (SCIP_EXPRDATA_USER*)expr->data.data;
8349  assert(exprdata != NULL);
8350 
8351  if( exprdata->print != NULL )
8352  {
8353  exprdata->print(messagehdlr, file, )
8354  }
8355  */
8356  int i;
8357 
8358  SCIPmessageFPrintInfo(messagehdlr, file, "user(");
8359  for( i = 0; i < expr->nchildren; ++i )
8360  {
8361  if( i > 0 )
8362  {
8363  SCIPmessageFPrintInfo(messagehdlr, file, ",");
8364  }
8365  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8366  }
8367  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8368 
8369  break;
8370  }
8371 
8372  case SCIP_EXPR_LAST:
8373  {
8374  SCIPerrorMessage("invalid expression\n");
8375  SCIPABORT();
8376  }
8377  }
8378 }
8379 
8380 /** parses an expression from a string */
8382  BMS_BLKMEM* blkmem, /**< block memory data structure */
8383  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8384  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
8385  const char* str, /**< pointer to the string to be parsed */
8386  const char* lastchar, /**< pointer to the last char of str that should be parsed */
8387  int* nvars, /**< buffer to store number of variables */
8388  int* varnames /**< buffer to store variable names, prefixed by index (as int) */
8389  )
8390 {
8391  SCIP_HASHTABLE* vartable;
8392  SCIP_RETCODE retcode;
8393 
8394  assert(blkmem != NULL);
8395  assert(expr != NULL);
8396  assert(str != NULL);
8397  assert(lastchar != NULL);
8398  assert(nvars != NULL);
8399  assert(varnames != NULL);
8400 
8401  *nvars = 0;
8402 
8403  /* create a hash table for variable names and corresponding expression index
8404  * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
8405  */
8406  SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) );
8407 
8408  retcode = exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames, vartable, 0);
8409 
8410  SCIPhashtableFree(&vartable);
8411 
8412  return retcode;
8413 }
8414 
8415 
8416 /**@} */
8417 
8418 /**@name Expression tree methods */
8419 /**@{ */
8420 
8421 /* In debug mode, the following methods are implemented as function calls to ensure
8422  * type validity.
8423  * In optimized mode, the methods are implemented as defines to improve performance.
8424  * However, we want to have them in the library anyways, so we have to undef the defines.
8425  */
8426 
8427 #undef SCIPexprtreeGetRoot
8428 #undef SCIPexprtreeGetNVars
8429 #undef SCIPexprtreeGetNParams
8430 #undef SCIPexprtreeGetParamVals
8431 #undef SCIPexprtreeSetParamVal
8432 #undef SCIPexprtreeGetInterpreterData
8433 #undef SCIPexprtreeSetInterpreterData
8434 #undef SCIPexprtreeFreeInterpreterData
8435 #undef SCIPexprtreeHasParam
8436 #undef SCIPexprtreeGetMaxDegree
8437 #undef SCIPexprtreeEval
8438 #undef SCIPexprtreeEvalInt
8439 #undef SCIPexprtreePrint
8440 
8441 /** returns root expression of an expression tree */
8443  SCIP_EXPRTREE* tree /**< expression tree */
8444  )
8445 {
8446  assert(tree != NULL);
8447 
8448  return tree->root;
8449 }
8450 
8451 /** returns number of variables in expression tree */
8453  SCIP_EXPRTREE* tree /**< expression tree */
8454  )
8455 {
8456  assert(tree != NULL);
8457 
8458  return tree->nvars;
8459 }
8460 
8461 /** returns number of parameters in expression tree */
8463  SCIP_EXPRTREE* tree /**< expression tree */
8464  )
8465 {
8466  assert(tree != NULL);
8467 
8468  return tree->nparams;
8469 }
8470 
8471 /** returns values of parameters or NULL if none */
8473  SCIP_EXPRTREE* tree /**< expression tree */
8474  )
8475 {
8476  assert(tree != NULL);
8477 
8478  return tree->params;
8479 }
8480 
8481 /** sets value of a single parameter in expression tree */
8483  SCIP_EXPRTREE* tree, /**< expression tree */
8484  int paramidx, /**< index of parameter */
8485  SCIP_Real paramval /**< new value of parameter */
8486  )
8487 {
8488  assert(tree != NULL);
8489  assert(paramidx >= 0);
8490  assert(paramidx < tree->nparams);
8491  assert(tree->params != NULL);
8492 
8493  tree->params[paramidx] = paramval;
8494 }
8495 
8496 /** gets data of expression tree interpreter, or NULL if not set */
8498  SCIP_EXPRTREE* tree /**< expression tree */
8499  )
8500 {
8501  assert(tree != NULL);
8502 
8503  return tree->interpreterdata;
8504 }
8505 
8506 /** sets data of expression tree interpreter */
8508  SCIP_EXPRTREE* tree, /**< expression tree */
8509  SCIP_EXPRINTDATA* interpreterdata /**< expression interpreter data */
8510  )
8511 {
8512  assert(tree != NULL);
8513  assert(interpreterdata != NULL);
8514  assert(tree->interpreterdata == NULL);
8515 
8516  tree->interpreterdata = interpreterdata;
8517 }
8518 
8519 /** frees data of expression tree interpreter, if any */
8521  SCIP_EXPRTREE* tree /**< expression tree */
8522  )
8523 {
8524  if( tree->interpreterdata != NULL )
8525  {
8527  assert(tree->interpreterdata == NULL);
8528  }
8529 
8530  return SCIP_OKAY;
8531 }
8532 
8533 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
8535  SCIP_EXPRTREE* tree /**< expression tree */
8536  )
8537 {
8538  assert(tree != NULL);
8539 
8540  return SCIPexprHasParam(tree->root);
8541 }
8542 
8543 /** Gives maximal degree of expression in expression tree.
8544  *
8545  * If constant expression, gives 0,
8546  * if linear expression, gives 1,
8547  * if polynomial expression, gives its maximal degree,
8548  * otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8549  */
8551  SCIP_EXPRTREE* tree, /**< expression tree */
8552  int* maxdegree /**< buffer to store maximal degree */
8553  )
8554 {
8555  assert(tree != NULL);
8556 
8557  SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8558 
8559  return SCIP_OKAY;
8560 }
8561 
8562 /** evaluates an expression tree w.r.t. a point */
8564  SCIP_EXPRTREE* tree, /**< expression tree */
8565  SCIP_Real* varvals, /**< values for variables */
8566  SCIP_Real* val /**< buffer to store expression tree value */
8567  )
8568 {
8569  assert(tree != NULL);
8570  assert(varvals != NULL || tree->nvars == 0);
8571  assert(val != NULL);
8572 
8573  SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8574 
8575  return SCIP_OKAY;
8576 }
8577 
8578 /** evaluates an expression tree w.r.t. an interval */
8580  SCIP_EXPRTREE* tree, /**< expression tree */
8581  SCIP_Real infinity, /**< value for infinity */
8582  SCIP_INTERVAL* varvals, /**< intervals for variables */
8583  SCIP_INTERVAL* val /**< buffer to store expression tree value */
8584  )
8585 {
8586  assert(tree != NULL);
8587  assert(varvals != NULL || tree->nvars == 0);
8588  assert(val != NULL);
8589 
8590  SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8591 
8592  return SCIP_OKAY;
8593 }
8594 
8595 /** prints an expression tree */
8597  SCIP_EXPRTREE* tree, /**< expression tree */
8598  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8599  FILE* file, /**< file for printing, or NULL for stdout */
8600  const char** varnames, /**< names of variables, or NULL for default names */
8601  const char** paramnames /**< names of parameters, or NULL for default names */
8602  )
8603 {
8604  assert(tree != NULL);
8605 
8606  SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8607 }
8608 
8609 
8610 /** creates an expression tree */
8612  BMS_BLKMEM* blkmem, /**< block memory data structure */
8613  SCIP_EXPRTREE** tree, /**< buffer to store address of created expression tree */
8614  SCIP_EXPR* root, /**< pointer to root expression, not copied deep !, can be NULL */
8615  int nvars, /**< number of variables in variable mapping */
8616  int nparams, /**< number of parameters in expression */
8617  SCIP_Real* params /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8618  )
8619 {
8620  assert(blkmem != NULL);
8621  assert(tree != NULL);
8622 
8623  SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8624 
8625  (*tree)->blkmem = blkmem;
8626  (*tree)->root = root;
8627  (*tree)->nvars = nvars;
8628  (*tree)->vars = NULL;
8629  (*tree)->nparams = nparams;
8630  (*tree)->interpreterdata = NULL;
8631 
8632  if( params != NULL )
8633  {
8634  assert(nparams > 0);
8635  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8636  }
8637  else if( nparams > 0 )
8638  {
8639  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8640  BMSclearMemoryArray((*tree)->params, nparams);
8641  }
8642  else
8643  {
8644  assert(nparams == 0);
8645  (*tree)->params = NULL;
8646  }
8647 
8648  return SCIP_OKAY;
8649 }
8650 
8651 /** copies an expression tree */
8653  BMS_BLKMEM* blkmem, /**< block memory that should be used in new expression tree */
8654  SCIP_EXPRTREE** targettree, /**< buffer to store address of copied expression tree */
8655  SCIP_EXPRTREE* sourcetree /**< expression tree to copy */
8656  )
8657 {
8658  assert(blkmem != NULL);
8659  assert(targettree != NULL);
8660  assert(sourcetree != NULL);
8661 
8662  /* copy expression tree "header" */
8663  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8664 
8665  /* we may have a new block memory; and we do not want to keep the others interpreter data */
8666  (*targettree)->blkmem = blkmem;
8667  (*targettree)->interpreterdata = NULL;
8668 
8669  /* copy variables, if any */
8670  if( sourcetree->vars != NULL )
8671  {
8672  assert(sourcetree->nvars > 0);
8673 
8674  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8675  }
8676 
8677  /* copy parameters, if any */
8678  if( sourcetree->params != NULL )
8679  {
8680  assert(sourcetree->nparams > 0);
8681 
8682  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8683  }
8684 
8685  /* copy expression */
8686  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8687 
8688  return SCIP_OKAY;
8689 }
8690 
8691 /** frees an expression tree */
8693  SCIP_EXPRTREE** tree /**< pointer to expression tree that is freed */
8694  )
8695 {
8696  assert( tree != NULL);
8697  assert(*tree != NULL);
8698 
8700 
8701  if( (*tree)->root != NULL )
8702  {
8703  SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8704  assert((*tree)->root == NULL);
8705  }
8706 
8707  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars, (*tree)->nvars );
8708  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8709 
8710  BMSfreeBlockMemory((*tree)->blkmem, tree);
8711 
8712  return SCIP_OKAY;
8713 }
8714 
8715 /** sets number and values of all parameters in expression tree */
8717  SCIP_EXPRTREE* tree, /**< expression tree */
8718  int nparams, /**< number of parameters */
8719  SCIP_Real* paramvals /**< values of parameters, can be NULL if nparams == 0 */
8720  )
8721 {
8722  assert(tree != NULL);
8723  assert(paramvals != NULL || nparams == 0);
8724 
8725  if( nparams == 0 )
8726  {
8727  BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8728  }
8729  else if( tree->params != NULL )
8730  {
8731  SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8732  BMScopyMemoryArray(tree->params, paramvals, nparams);
8733  }
8734  else
8735  {
8736  SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8737  }
8738 
8739  tree->nparams = nparams;
8740  assert(tree->params != NULL || tree->nparams == 0);
8741 
8742  return SCIP_OKAY;
8743 }
8744 
8745 
8746 /** gives the number of usages for each variable in the expression tree */
8748  SCIP_EXPRTREE* tree, /**< expression tree */
8749  int* varsusage /**< array where to store for each variable how often it is used in the tree */
8750  )
8751 {
8752  assert(tree != NULL);
8753  assert(varsusage != NULL);
8754 
8755  if( tree->nvars == 0 )
8756  return;
8757 
8758  BMSclearMemoryArray(varsusage, tree->nvars);
8759  SCIPexprGetVarsUsage(tree->root, varsusage);
8760 }
8761 
8762 /** aims at simplifying an expression and splitting of a linear expression
8763  *
8764  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
8765  */
8767  SCIP_EXPRTREE* tree, /**< expression tree */
8768  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8769  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
8770  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8771  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8772  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8773  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
8774  )
8775 {
8776 #ifndef NDEBUG
8777  SCIP_Real* testx;
8778  SCIP_Real testval_before;
8779  SCIP_Real testval_after;
8780  int i;
8781  unsigned int seed;
8782 #endif
8783 
8784  assert(tree != NULL);
8785 
8786 #ifndef NDEBUG
8787  seed = 42;
8788  SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) ); /*lint !e666*/
8789  for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8790  testx[i] = SCIPgetRandomReal(-100.0, 100.0, &seed); /*lint !e644*/
8791  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8792 #endif
8793 
8794  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8795  SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8796 
8797 #ifndef NDEBUG
8798  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8799  if( nlinvars != NULL && testval_before == testval_before ) /*lint !e777*/
8800  for( i = 0; i < *nlinvars; ++i )
8801  testval_after += lincoefs[i] * testx[linidxs[i]];
8802  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
8803  BMSfreeMemoryArray(&testx);
8804 #endif
8805 
8806  /* removing something from the the tree may invalidate the interpreter data */
8807  if( nlinvars != NULL && *nlinvars > 0 )
8809 
8810  return SCIP_OKAY;
8811 }
8812 
8813 /** adds an expression to the root expression of the tree
8814  *
8815  * 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.
8816  */
8818  SCIP_EXPRTREE* tree, /**< expression tree */
8819  SCIP_EXPR* expr, /**< expression to add to tree */
8820  SCIP_Bool copyexpr /**< whether expression should be copied */
8821  )
8822 {
8823  assert(tree != NULL);
8824  assert(tree->root != NULL);
8825 
8826  /* adding something to the tree may invalidate the interpreter data */
8828 
8829  if( copyexpr )
8830  {
8831  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &expr, expr) );
8832  }
8833 
8834  SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
8835 
8836  return SCIP_OKAY;
8837 }
8838 
8839 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
8841  SCIP_EXPRTREE* tree, /**< expression tree */
8842  SCIP_Real infinity, /**< value for infinity */
8843  SCIP_INTERVAL* varbounds, /**< domains of variables */
8844  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8845  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression, or NULL if not needed */
8846  )
8847 {
8848  SCIP_INTERVAL exprbounds;
8849 
8850  assert(tree != NULL);
8851  assert(tree->root != NULL);
8852 
8853  SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
8854 
8855  if( bounds != NULL )
8856  *bounds = exprbounds;
8857 
8858  return SCIP_OKAY;
8859 }
8860 
8861 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
8862  *
8863  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL.
8864  * If substexprs[i] == NULL, then the variable expression i is not touched.
8865  */
8867  SCIP_EXPRTREE* tree, /**< expression tree */
8868  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8869  )
8870 {
8871  assert(tree != NULL);
8872  assert(tree->root != NULL);
8873 
8874  if( tree->root->op == SCIP_EXPR_VARIDX )
8875  {
8876  int varidx;
8877 
8878  varidx = tree->root->data.intval;
8879  assert(varidx >= 0);
8880  if( substexprs[varidx] != NULL )
8881  {
8882  /* substitute root expression */
8883  SCIPexprFreeDeep(tree->blkmem, &tree->root);
8884  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
8885  }
8886  }
8887  else
8888  {
8889  /* check children (and grandchildren and so on...) of root expression */
8890  SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
8891  }
8892 
8893  /* substitution of variables should invalidate interpreter data */
8895 
8896  return SCIP_OKAY;
8897 }
8898 
8899 /**@} */
8900 
8901 /**@name Quadratic element methods */
8902 /**@{ */
8903 
8904 /** comparing two quadratic elements
8905  *
8906  * 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
8907  */
8908 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
8909 
8910 /** swaps two quadratic elements */
8911 #define QUADELEMS_SWAP(x,y) \
8912  { \
8913  SCIP_QUADELEM temp = x; \
8914  x = y; \
8915  y = temp; \
8916  }
8917 
8918 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
8919 static
8921  SCIP_QUADELEM* elems, /**< array to be sorted */
8922  int start, /**< starting index */
8923  int end /**< ending index */
8924  )
8925 {
8926  assert(start <= end);
8927 
8928  /* use quick sort for long lists */
8929  while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
8930  {
8931  SCIP_QUADELEM pivotkey;
8932  int lo;
8933  int hi;
8934  int mid;
8935 
8936  /* select pivot element */
8937  mid = (start+end)/2;
8938  pivotkey = elems[mid];
8939 
8940  /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
8941  lo = start;
8942  hi = end;
8943  for( ;; )
8944  {
8945  while( lo < end && QUADELEMS_ISBETTER(elems[lo], pivotkey) )
8946  lo++;
8947  while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
8948  hi--;
8949 
8950  if( lo >= hi )
8951  break;
8952 
8953  QUADELEMS_SWAP(elems[lo], elems[hi]);
8954 
8955  lo++;
8956  hi--;
8957  }
8958  assert(hi == lo-1 || hi == start);
8959 
8960  /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
8961  while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
8962  lo++;
8963 
8964  /* make sure that we have at least one element in the smaller partition */
8965  if( lo == start )
8966  {
8967  /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
8968  assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
8969  assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
8970  QUADELEMS_SWAP(elems[lo], elems[mid]);
8971  lo++;
8972  }
8973 
8974  /* sort the smaller partition by a recursive call, sort the larger part without recursion */
8975  if( hi - start <= end - lo )
8976  {
8977  /* sort [start,hi] with a recursive call */
8978  if( start < hi )
8979  quadelemsQuickSort(elems, start, hi);
8980 
8981  /* now focus on the larger part [lo,end] */
8982  start = lo;
8983  }
8984  else
8985  {
8986  /* sort [lo,end] with a recursive call */
8987  if( lo < end )
8988  quadelemsQuickSort(elems, lo, end);
8989 
8990  /* now focus on the larger part [start,hi] */
8991  end = hi;
8992  }
8993  }
8994 
8995  /* use shell sort on the remaining small list */
8996  if( end - start >= 1 )
8997  {
8998  static const int incs[3] = {1, 5, 19}; /* sequence of increments */
8999  int k;
9000 
9001  for( k = 2; k >= 0; --k )
9002  {
9003  int h;
9004  int i;
9005 
9006  for( h = incs[k], i = h + start; i <= end; ++i )
9007  {
9008  int j;
9009  SCIP_QUADELEM tempkey = elems[i];
9010 
9011  j = i;
9012  while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
9013  {
9014  elems[j] = elems[j-h];
9015  j -= h;
9016  }
9017 
9018  elems[j] = tempkey;
9019  }
9020  }
9021  }
9022 }
9023 
9024 /** sorts an array of quadratic elements
9025  *
9026  * The elements are sorted such that the first index is increasing and
9027  * such that among elements with the same first index, the second index is increasing.
9028  * For elements with same first and second index, the order is not defined.
9029  */
9031  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9032  int nquadelems /**< number of quadratic elements */
9033  )
9034 {
9035  if( nquadelems == 0 )
9036  return;
9037 
9038 #ifndef NDEBUG
9039  {
9040  int i;
9041  for( i = 0; i < nquadelems; ++i )
9042  assert(quadelems[i].idx1 <= quadelems[i].idx2);
9043  }
9044 #endif
9045 
9046  quadelemsQuickSort(quadelems, 0, nquadelems-1);
9047 }
9048 
9049 /** Finds an index pair in a sorted array of quadratic elements.
9050  *
9051  * If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
9052  * 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.
9053  * Assumes that idx1 <= idx2.
9054  */
9056  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9057  int idx1, /**< index of first variable in element to search for */
9058  int idx2, /**< index of second variable in element to search for */
9059  int nquadelems, /**< number of quadratic elements in array */
9060  int* pos /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
9061  )
9062 {
9063  int left;
9064  int right;
9065 
9066  assert(quadelems != NULL || nquadelems == 0);
9067  assert(idx1 <= idx2);
9068 
9069  if( nquadelems == 0 )
9070  {
9071  if( pos != NULL )
9072  *pos = 0;
9073  return FALSE;
9074  }
9075 
9076  left = 0;
9077  right = nquadelems - 1;
9078  while( left <= right )
9079  {
9080  int middle;
9081 
9082  middle = (left+right)/2;
9083  assert(0 <= middle && middle < nquadelems);
9084 
9085  if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) ) /*lint !e613*/
9086  right = middle - 1;
9087  else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) ) /*lint !e613*/
9088  left = middle + 1;
9089  else
9090  {
9091  if( pos != NULL )
9092  *pos = middle;
9093  return TRUE;
9094  }
9095  }
9096  assert(left == right+1);
9097 
9098  if( pos != NULL )
9099  *pos = left;
9100  return FALSE;
9101 }
9102 
9103 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
9104  *
9105  * Assumes that elements have been sorted before.
9106  */
9108  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9109  int nquadelems, /**< number of quadratic elements */
9110  int* nquadelemsnew /**< pointer to store new (reduced) number of quadratic elements */
9111  )
9112 {
9113  int i;
9114  int next;
9115 
9116  assert(quadelems != NULL);
9117  assert(nquadelemsnew != NULL);
9118  assert(nquadelems >= 0);
9119 
9120  i = 0;
9121  next = 0;
9122  while( next < nquadelems )
9123  {
9124  /* assert that array is sorted */
9125  assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
9126  (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
9127 
9128  /* skip elements with coefficient 0.0 */
9129  if( quadelems[next].coef == 0.0 )
9130  {
9131  ++next;
9132  continue;
9133  }
9134 
9135  /* if next element has same index as previous one, add it to the previous one */
9136  if( i >= 1 &&
9137  quadelems[i-1].idx1 == quadelems[next].idx1 &&
9138  quadelems[i-1].idx2 == quadelems[next].idx2 )
9139  {
9140  quadelems[i-1].coef += quadelems[next].coef;
9141  ++next;
9142  continue;
9143  }
9144 
9145  /* otherwise, move next element to current position */
9146  quadelems[i] = quadelems[next];
9147  ++i;
9148  ++next;
9149  }
9150  assert(next == nquadelems);
9151 
9152  /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
9153  *nquadelemsnew = i;
9154 }
9155 
9156 /**@} */
9157 
9158 /**@name Expression graph node private methods */
9159 /**@{ */
9160 
9161 /** adds a parent to an expression graph node */
9162 static
9164  BMS_BLKMEM* blkmem, /**< block memory */
9165  SCIP_EXPRGRAPHNODE* node, /**< expression graph node where to add a parent */
9166  SCIP_EXPRGRAPHNODE* parent /**< parent node */
9167  )
9168 {
9169  assert(blkmem != NULL);
9170  assert(node != NULL);
9171  assert(node->depth >= 0);
9172  assert(node->pos >= 0);
9173  assert(parent != NULL);
9174  assert(parent->depth >= 0);
9175  assert(parent->pos >= 0);
9176  assert(parent->depth > node->depth); /* a parent node need to have larger depth */
9177 
9178  ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
9179  assert(node->nparents < node->parentssize);
9180 
9181  node->parents[node->nparents] = parent;
9182  ++node->nparents;
9183 
9184  /* update sorted flag */
9185  node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (node->parents[node->nparents-2] <= parent));
9186 
9187  return SCIP_OKAY;
9188 }
9189 
9190 /** ensures that array of parents in a node is sorted */
9191 static
9193  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
9194  )
9195 {
9196  assert(node != NULL);
9197 
9198  if( node->parentssorted )
9199  {
9200 #ifndef NDEBUG
9201  int i;
9202  for( i = 1; i < node->nparents; ++i )
9203  assert(ptrcomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
9204 #endif
9205  return;
9206  }
9207 
9208  SCIPsortPtr((void**)node->parents, ptrcomp, node->nparents);
9209 
9210  node->parentssorted = TRUE;
9211 }
9212 
9213 /** removes a parent from an expression graph node
9214  *
9215  * If the node is not used and has no other parents, then it is freed.
9216  */
9217 static
9219  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9220  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to remove a parent, *node will be set to NULL */
9221  SCIP_EXPRGRAPHNODE* parent /**< parent node to remove */
9222  )
9223 {
9224  SCIP_EXPRGRAPHNODE* node_;
9225  int pos;
9226 
9227  assert(exprgraph != NULL);
9228  assert(node != NULL);
9229  assert(*node != NULL);
9230  assert((*node)->depth >= 0);
9231  assert((*node)->pos >= 0);
9232  assert((*node)->nparents > 0);
9233  assert(parent != NULL);
9234  assert(parent->depth >= 0);
9235  assert(parent->pos >= 0);
9236  assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
9237 
9238  /* find parent */
9239  exprgraphNodeSortParents(*node);
9240  (void) SCIPsortedvecFindPtr((void**)(*node)->parents, ptrcomp, (void*)parent, (*node)->nparents, &pos);
9241  assert(pos >= 0);
9242  assert(pos < (*node)->nparents);
9243  assert((*node)->parents[pos] == parent);
9244 
9245  /* move last parent to pos, if pos is before last
9246  * update sorted flag */
9247  if( pos < (*node)->nparents-1 )
9248  {
9249  (*node)->parents[pos] = (*node)->parents[(*node)->nparents-1];
9250  (*node)->parentssorted = ((*node)->nparents <= 2);
9251  }
9252  --(*node)->nparents;
9253 
9254  /* keep pointer to *node in case it is still used */
9255  node_ = (*node)->nuses > 0 ? *node : NULL;
9256 
9257  /* capture and release node so it is freed if possible */
9258  SCIPexprgraphCaptureNode(*node);
9259  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
9260 
9261  /* restore pointer, if node still exists */
9262  *node = node_;
9263 
9264  return SCIP_OKAY;
9265 }
9266 
9267 /** checks if a node is parent of a node */
9268 static
9270  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9271  SCIP_EXPRGRAPHNODE* parent /**< parent to look for */
9272  )
9273 {
9274  int pos;
9275 
9276  assert(node != NULL);
9277  assert(parent != NULL);
9278 
9279  /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
9280  if( node->depth >= parent->depth || node->nparents == 0 )
9281  return FALSE;
9282  assert(node->parents != NULL);
9283 
9284  /* ensure parents array is sorted */
9286 
9287  return SCIPsortedvecFindPtr((void**)node->parents, ptrcomp, (void*)parent, node->nparents, &pos);
9288 }
9289 
9290 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
9291  *
9292  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
9293  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
9294  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
9295  *
9296  * It is assumed that node and all exprs are in the expression graph already.
9297  * It is assumed that all expressions that are added have lower depth than node.
9298  */
9299 static
9301  BMS_BLKMEM* blkmem, /**< block memory */
9302  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9303  int nexprs, /**< number of children to add */
9304  SCIP_EXPRGRAPHNODE** exprs, /**< children nodes to add */
9305  int* childmap /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
9306  )
9307 {
9308  int i;
9309  int j;
9310  int orignchildren;
9311  SCIP_Bool existsalready;
9312 
9313  assert(blkmem != NULL);
9314  assert(node != NULL);
9315  assert(node->depth > 0);
9316  assert(node->pos >= 0);
9317  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);
9318  assert(exprs != NULL || nexprs == 0);
9319 
9320  if( nexprs == 0 )
9321  return SCIP_OKAY;
9322 
9323  orignchildren = node->nchildren;
9324  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
9325 
9326  for( i = 0; i < nexprs; ++i )
9327  {
9328  assert(exprs[i]->depth >= 0); /*lint !e613*/
9329  assert(exprs[i]->pos >= 0); /*lint !e613*/
9330  assert(exprs[i]->depth < node->depth); /*lint !e613*/
9331 
9332  /* check if exprs[i] is a child already, if not SUM or PRODUCT */
9333  existsalready = FALSE;
9334  if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
9335  for( j = 0; j < orignchildren; ++j )
9336  /* during simplification of polynomials, their may be NULL's in children array */
9337  if( node->children[j] != NULL && node->children[j] == exprs[i] ) /*lint !e613*/
9338  {
9339  existsalready = TRUE;
9340  break;
9341  }
9342 
9343  if( !existsalready )
9344  {
9345  /* add exprs[i] to children array */
9346  node->children[node->nchildren] = exprs[i]; /*lint !e613*/
9347  SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) ); /*lint !e613*/
9348  if( childmap != NULL )
9349  childmap[i] = node->nchildren;
9350  ++node->nchildren;
9351  }
9352  else
9353  {
9354  if( childmap != NULL )
9355  childmap[i] = j; /*lint !e644*/
9356  if( node->op == SCIP_EXPR_LINEAR )
9357  {
9358  /* if linear expression, increase coefficient by 1.0 */
9359  ((SCIP_Real*)node->data.data)[j] += 1.0;
9360  }
9361  }
9362  }
9363 
9364  /* shrink children array to actually used size */
9365  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
9366 
9367  if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
9368  {
9369  /* if linear expression, then add 1.0 coefficients for new expressions */
9370  SCIP_Real* data;
9371 
9372  data = (SCIP_Real*)node->data.data;
9373  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
9374  data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
9375  for( i = orignchildren; i < node->nchildren; ++i )
9376  data[i] = 1.0;
9377  node->data.data = (void*)data;
9378  }
9379  else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
9380  {
9381  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
9383 
9384  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9385  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
9386  BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren); /*lint !e866*/
9387  }
9388 
9389  node->simplified = FALSE;
9390 
9391  return SCIP_OKAY;
9392 }
9393 
9394 /** replaces a child node by another node
9395  *
9396  * Assumes that both nodes represent the same expression.
9397  * If this node was the last parent of oldchild and oldchild is not in use, then it is freed.
9398  * newchild must have deeper depth than node.
9399  */
9400 static
9402  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9403  SCIP_EXPRGRAPHNODE* node, /**< pointer to expression graph node */
9404  SCIP_EXPRGRAPHNODE** oldchild, /**< child node that should be replaced, it may be freed */
9405  SCIP_EXPRGRAPHNODE* newchild /**< node that should take position of oldchild */
9406  )
9407 {
9408  int i;
9409 
9410  assert(exprgraph != NULL);
9411  assert(node != NULL);
9412  assert(oldchild != NULL);
9413  assert(*oldchild != NULL);
9414  assert(newchild != NULL);
9415 
9416  if( *oldchild == newchild )
9417  return SCIP_OKAY;
9418 
9419  SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
9420 
9421  /* search for oldchild in children array */
9422  for( i = 0; i < node->nchildren; ++i )
9423  {
9424  if( node->children[i] == *oldchild )
9425  {
9426  /* add as parent to newchild */
9427  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
9428 
9429  /* remove as parent from oldchild */
9430  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
9431 
9432  /* set newchild as child i */
9433  node->children[i] = newchild;
9434 
9435  /* we're done */
9436  break;
9437  }
9438  }
9439  assert(i < node->nchildren); /* assert that oldchild has been found in children array */
9440 
9441  node->simplified = FALSE;
9442 
9443  return SCIP_OKAY;
9444 }
9445 
9446 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
9447  *
9448  * A node is larger than another node, if their corresponding constants are related that way.
9449  */
9450 static
9451 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
9452 {
9453  assert(elem1 != NULL);
9454  assert(elem2 != NULL);
9455  assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
9456  assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
9457  assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9458  assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9459 
9460  if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9461  return 1;
9462  else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9463  return -1;
9464  else
9465  return 0;
9466 }
9467 
9468 /** sort array of nodes that holds constants */
9469 static
9471  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
9472  )
9473 {
9474  assert(exprgraph != NULL);
9475 
9476  if( exprgraph->constssorted )
9477  return;
9478 
9479  SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
9480 
9481  exprgraph->constssorted = TRUE;
9482 }
9483 
9484 /** finds position of expression graph node corresponding to a constant in constnodes array */
9485 static
9487  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9488  SCIP_EXPRGRAPHNODE* node, /**< node to search for */
9489  int* pos /**< buffer to store position of node, if found */
9490  )
9491 {
9492  int left;
9493  int right;
9494  int middle;
9495 
9496  assert(exprgraph != NULL);
9497  assert(node != NULL);
9498  assert(node->op == SCIP_EXPR_CONST);
9499  assert(node->depth == 0);
9500  assert(node->pos >= 0);
9501  assert(pos != NULL);
9502 
9503  exprgraphSortConstNodes(exprgraph);
9504  assert(exprgraph->constssorted);
9505 
9506  /* find a node with constant node->data.dbl using binary search */
9507  left = 0;
9508  right = exprgraph->nconsts-1;
9509  *pos = -1;
9510  while( left <= right )
9511  {
9512  middle = (left+right)/2;
9513  assert(0 <= middle && middle < exprgraph->nconsts);
9514 
9515  if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9516  right = middle - 1;
9517  else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9518  left = middle + 1;
9519  else
9520  {
9521  *pos = middle;
9522  break;
9523  }
9524  }
9525  assert(left == right+1 || *pos >= 0);
9526  if( left == right+1 )
9527  return FALSE;
9528 
9529  /* search left of *pos to find node */
9530  while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl ) /*lint !e777*/
9531  --*pos;
9532  /* search right of *pos to find node */
9533  while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl ) /*lint !e777*/
9534  ++*pos;
9535 
9536  return exprgraph->constnodes[*pos] == node;
9537 }
9538 
9539 /** creates an expression graph node */
9540 static
9542  BMS_BLKMEM* blkmem, /**< block memory */
9543  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
9544  SCIP_EXPROP op, /**< operator type of expression */
9545  SCIP_EXPROPDATA opdata /**< operator data of expression */
9546  )
9547 {
9548  assert(blkmem != NULL);
9549  assert(node != NULL);
9550 
9551  SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9552  BMSclearMemory(*node);
9553 
9554  (*node)->op = op;
9555  (*node)->data = opdata;
9556 
9557  /* mark graph position as not in graph yet */
9558  (*node)->depth = -1;
9559  (*node)->pos = -1;
9560 
9561  /* arrays of length 0 are trivially sorted */
9562  (*node)->parentssorted = TRUE;
9563 
9564  /* set bounds interval to entire */
9565  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9566  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9567 
9568  /* set initial value to invalid */
9569  (*node)->value = SCIP_INVALID;
9570 
9571  /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9572  if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9573  (*node)->curv = SCIP_EXPRCURV_LINEAR;
9574  else
9575  (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9576 
9577  /* per default, a node is enabled */
9578  (*node)->enabled = TRUE;
9579 
9580  return SCIP_OKAY;
9581 }
9582 
9583 /** prints the expression corresponding to a node (not recursively) */
9584 static
9586  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9587  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9588  FILE* file, /**< file to print to, or NULL for stdout */
9589  const char** varnames, /**< variable names, or NULL for generic names */
9590  SCIP_Bool printchildrenbounds /**< whether to print bounds of children */
9591  )
9592 {
9593  int i;
9594 
9595  assert(node != NULL);
9596 
9597  switch( node->op )
9598  {
9599  case SCIP_EXPR_VARIDX:
9600  if( varnames != NULL )
9601  {
9602  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9603  }
9604  else
9605  SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9606  break;
9607 
9608  case SCIP_EXPR_CONST:
9609  SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9610  break;
9611 
9612  case SCIP_EXPR_PARAM:
9613  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9614  break;
9615 
9616  case SCIP_EXPR_PLUS:
9617  if( printchildrenbounds )
9618  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9619  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9620  if( printchildrenbounds )
9621  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9622  break;
9623 
9624  case SCIP_EXPR_MINUS:
9625  if( printchildrenbounds )
9626  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9627  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9628  if( printchildrenbounds )
9629  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9630  break;
9631 
9632  case SCIP_EXPR_MUL:
9633  if( printchildrenbounds )
9634  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9635  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9636  if( printchildrenbounds )
9637  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9638  break;
9639 
9640  case SCIP_EXPR_DIV:
9641  if( printchildrenbounds )
9642  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9643  SCIPmessageFPrintInfo(messagehdlr, file, "/");
9644  if( printchildrenbounds )
9645  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9646  break;
9647 
9648  case SCIP_EXPR_SQUARE:
9649  if( printchildrenbounds )
9650  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9651  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9652  break;
9653 
9654  case SCIP_EXPR_REALPOWER:
9655  if( printchildrenbounds )
9656  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9657  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9658  break;
9659 
9660  case SCIP_EXPR_SIGNPOWER:
9661  if( printchildrenbounds )
9662  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9663  node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9664  else
9665  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9666  break;
9667 
9668  case SCIP_EXPR_INTPOWER:
9669  SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9670  if( printchildrenbounds )
9671  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9672  SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9673  break;
9674 
9675  case SCIP_EXPR_SQRT:
9676  case SCIP_EXPR_EXP:
9677  case SCIP_EXPR_LOG:
9678  case SCIP_EXPR_SIN:
9679  case SCIP_EXPR_COS:
9680  case SCIP_EXPR_TAN:
9681  /* SCIP_EXPR_ERF = 20, */ /**< gaussian error function (1 operand) */
9682  /* SCIP_EXPR_ERFI = 21, */ /**< imaginary part of gaussian error function (1 operand) */
9683  case SCIP_EXPR_MIN:
9684  case SCIP_EXPR_MAX:
9685  case SCIP_EXPR_ABS:
9686  case SCIP_EXPR_SIGN:
9687  SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9688  if( printchildrenbounds )
9689  {
9690  SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9691  if( node->nchildren == 2 )
9692  SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9693  SCIPmessageFPrintInfo(messagehdlr, file, ")");
9694  }
9695  break;
9696 
9697  case SCIP_EXPR_SUM:
9698  if( printchildrenbounds )
9699  for( i = 0; i < node->nchildren; ++i )
9700  {
9701  if( i > 0 )
9702  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9703  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9704  }
9705  else
9706  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9707  break;
9708 
9709  case SCIP_EXPR_PRODUCT:
9710  if( printchildrenbounds )
9711  for( i = 0; i < node->nchildren; ++i )
9712  {
9713  if( i > 0 )
9714  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9715  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9716  }
9717  else
9718  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9719  break;
9720 
9721  case SCIP_EXPR_LINEAR:
9722  {
9723  SCIP_Real constant;
9724 
9725  constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9726 
9727  if( constant != 0.0 || node->nchildren == 0 )
9728  SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9729 
9730  for( i = 0; i < node->nchildren; ++i )
9731  {
9732  if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9733  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9734  else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9735  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9736  else
9737  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9738  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9739  if( printchildrenbounds )
9740  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9741  }
9742 
9743  break;
9744  }
9745 
9746  case SCIP_EXPR_QUADRATIC:
9747  {
9748  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9749 
9750  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9751  assert(quadraticdata != NULL);
9752 
9753  if( quadraticdata->constant != 0.0 )
9754  SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9755 
9756  if( quadraticdata->lincoefs != NULL )
9757  for( i = 0; i < node->nchildren; ++i )
9758  {
9759  if( quadraticdata->lincoefs[i] == 0.0 )
9760  continue;
9761  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9762  if( printchildrenbounds )
9763  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9764  }
9765 
9766  for( i = 0; i < quadraticdata->nquadelems; ++i )
9767  {
9768  if( quadraticdata->quadelems[i].coef == 1.0 )
9769  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9770  else if( quadraticdata->quadelems[i].coef == -1.0 )
9771  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9772  else
9773  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9774  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9775  if( printchildrenbounds )
9776  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9777  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9778  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9779  else
9780  {
9781  SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9782  if( printchildrenbounds )
9783  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9784  }
9785  }
9786 
9787  break;
9788  }
9789 
9790  case SCIP_EXPR_POLYNOMIAL:
9791  {
9792  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9793  SCIP_EXPRDATA_MONOMIAL* monomialdata;
9794  int j;
9795 
9796  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9797  assert(polynomialdata != NULL);
9798 
9799  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
9800  {
9801  SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
9802  }
9803 
9804  for( i = 0; i < polynomialdata->nmonomials; ++i )
9805  {
9806  monomialdata = polynomialdata->monomials[i];
9807  if( monomialdata->coef == 1.0 )
9808  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9809  else if( monomialdata->coef == -1.0 )
9810  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9811  else
9812  SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
9813 
9814  for( j = 0; j < monomialdata->nfactors; ++j )
9815  {
9816  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
9817  if( printchildrenbounds )
9818  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
9819  if( monomialdata->exponents[j] < 0.0 )
9820  SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
9821  else if( monomialdata->exponents[j] != 1.0 )
9822  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
9823  }
9824  }
9825 
9826  break;
9827  }
9828 
9829  case SCIP_EXPR_LAST:
9830  SCIPABORT();
9831  break;
9832 
9833  default:
9834  SCIPmessageFPrintInfo(messagehdlr, file, SCIPexpropGetName(node->op));
9835  break;
9836  } /*lint !e788*/
9837 }
9838 
9839 /** prints a node of an expression graph */
9840 static
9842  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9843  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9844  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9845  FILE* file, /**< file to print to, or NULL for stdout */
9846  const char** varnames /**< variable names, or NULL for generic names */
9847  )
9848 {
9849  SCIP_Real color;
9850  int i;
9851 
9852  assert(exprgraph != NULL);
9853  assert(node != NULL);
9854  assert(file != NULL);
9855 
9856  color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
9857  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
9858 
9859  exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
9860 
9861  SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
9863  SCIPmessageFPrintInfo(messagehdlr, file, "!");
9865  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9867  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9868 
9869  SCIPmessageFPrintInfo(messagehdlr, file, "\"");
9870 
9871  if( !node->enabled )
9872  SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
9873 
9874  SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
9875 
9876  /* add edges from node to children */
9877  for( i = 0; i < node->nchildren; ++i )
9878  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);
9879 }
9880 
9881 /** evaluate node of expression graph w.r.t. values stored in children */
9882 static
9884  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9885  SCIP_Real* varvals /**< values for variables */
9886  )
9887 {
9888  int i;
9890  SCIP_Real* buf;
9891 
9892  assert(node != NULL);
9893 
9894  /* if many children, get large enough memory to store argument values */
9896  {
9897  SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
9898  }
9899  else
9900  {
9901  buf = staticbuf;
9902  }
9903 
9904  /* get values of children */
9905  for( i = 0; i < node->nchildren; ++i )
9906  {
9907  assert(node->children[i]->value != SCIP_INVALID); /*lint !e777*/
9908  buf[i] = node->children[i]->value; /*lint !e644*/
9909  }
9910 
9911  /* evaluate this expression */
9912  assert(exprOpTable[node->op].eval != NULL);
9913  SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
9914  assert(node->value != SCIP_INVALID); /*lint !e777*/
9915 
9916  /* free memory, if allocated before */
9917  if( staticbuf != buf )
9918  {
9919  BMSfreeMemoryArray(&buf);
9920  }
9921 
9922  return SCIP_OKAY;
9923 }
9924 
9925 /** evaluates node including subtree */
9926 static
9928  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9929  SCIP_Real* varvals /**< values for variables */
9930  )
9931 {
9932  int i;
9933 
9934  assert(node != NULL);
9935 
9936  for( i = 0; i < node->nchildren; ++i )
9937  {
9938  SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
9939  }
9940 
9941  SCIP_CALL( exprgraphNodeEval(node, varvals) );
9942 
9943  return SCIP_OKAY;
9944 }
9945 
9946 /** updates bounds of a node if a children has changed its bounds */
9947 static
9949  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9950  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
9951  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
9952  SCIP_Bool parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
9953  )
9954 {
9955  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
9956  SCIP_INTERVAL* childbounds;
9957  SCIP_INTERVAL newbounds;
9958  int i;
9959 
9960  assert(node != NULL);
9961  assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
9962  assert(node->pos >= 0); /* node should be in graph */
9963  assert(node->op != SCIP_EXPR_VARIDX);
9964  assert(node->op != SCIP_EXPR_PARAM);
9965 
9966  /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
9967  * if node is disabled, then also do nothing */
9968  if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
9969  return SCIP_OKAY;
9970 
9971  /* if many children, get large enough memory to store children bounds */
9973  {
9974  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
9975  }
9976  else
9977  {
9978  childbounds = childboundsstatic;
9979  }
9980 
9981  /* assemble bounds of children */
9982  for( i = 0; i < node->nchildren; ++i )
9983  {
9984  /* child should have valid and non-empty bounds */
9986  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
9987 
9988  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
9989  }
9990 
9991  /* call interval evaluation function for this operand */
9992  assert( exprOpTable[node->op].inteval != NULL );
9993  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
9994 
9995  /* free memory, if allocated before */
9996  if( childbounds != childboundsstatic )
9997  {
9998  BMSfreeMemoryArray(&childbounds);
9999  }
10000 
10001  /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
10002 
10003  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
10004  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
10005  *
10006  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
10007  *
10008  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
10009  */
10010  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
10011  ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
10012  {
10013  for( i = 0; i < node->nparents; ++i )
10015 
10016  node->bounds = newbounds;
10017  }
10018  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
10019  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
10020  {
10021  for( i = 0; i < node->nparents; ++i )
10023 
10024  node->bounds = newbounds;
10025  }
10026  else
10027  {
10028  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
10029  }
10030 
10031  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);
10032 
10033  /* node now has valid bounds */
10035 
10036  return SCIP_OKAY;
10037 }
10038 
10039 /** propagate bounds of a node into children by reverting the nodes expression */
10040 static
10042  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10043  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
10044  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10045  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
10046  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
10047  )
10048 {
10049  SCIP_INTERVAL childbounds;
10050  int i;
10051 
10052  assert(exprgraph != NULL);
10053  assert(node != NULL);
10054  assert(node->depth >= 0); /* node should be in graph */
10055  assert(node->pos >= 0); /* node should be in graph */
10056  assert(minstrength >= 0.0);
10057  assert(cutoff != NULL);
10058  assert(!SCIPintervalIsEmpty(infinity, node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
10059  assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
10060 
10061  /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
10063  return;
10064 
10065  /* if node is not enabled, then do nothing */
10066  if( !node->enabled )
10067  return;
10068 
10069  /* tell children that they should propagate their bounds even if not tightened */
10071  minstrength = -1.0;
10072 
10073  /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
10075 
10076  /* 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);
10077  * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10078  * SCIPdebugPrintf("\n");
10079  */
10080 
10081  /* @todo add callback to exprOpTable for this */
10082 
10083  switch( node->op )
10084  {
10085  case SCIP_EXPR_VARIDX:
10086  case SCIP_EXPR_CONST:
10087  case SCIP_EXPR_PARAM:
10088  /* cannot propagate bound changes further */
10089  break;
10090 
10091  case SCIP_EXPR_PLUS:
10092  {
10093  assert(node->nchildren == 2);
10094  /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
10095 
10096  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10097  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10098 
10099  if( *cutoff )
10100  break;
10101 
10102  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10103  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10104 
10105  break;
10106  }
10107 
10108  case SCIP_EXPR_MINUS:
10109  {
10110  assert(node->nchildren == 2);
10111  /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
10112 
10113  SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10114  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10115 
10116  if( *cutoff )
10117  break;
10118 
10119  SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10120  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10121 
10122  break;
10123  }
10124 
10125  case SCIP_EXPR_MUL:
10126  {
10127  assert(node->nchildren == 2);
10128  /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
10129 
10130  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10131  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10132 
10133  if( *cutoff )
10134  break;
10135 
10136  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10137  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10138 
10139  break;
10140  }
10141 
10142  case SCIP_EXPR_DIV:
10143  {
10144  assert(node->nchildren == 2);
10145  /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
10146 
10147  SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10148  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10149 
10150  if( *cutoff )
10151  break;
10152 
10153  SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10154  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10155 
10156  break;
10157  }
10158 
10159  case SCIP_EXPR_SQUARE:
10160  {
10161  assert(node->nchildren == 1);
10162  /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
10163 
10164  if( node->bounds.sup < 0.0 )
10165  {
10166  *cutoff = TRUE;
10167  break;
10168  }
10169 
10170  SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
10171  if( node->children[0]->bounds.inf <= -childbounds.inf )
10172  SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
10173  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10174 
10175  break;
10176  }
10177 
10178  case SCIP_EXPR_SQRT:
10179  {
10180  assert(node->nchildren == 1);
10181  /* f = sqrt(c0) -> c0 = f^2 */
10182 
10183  SCIPintervalSquare(infinity, &childbounds, node->bounds);
10184  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10185 
10186  break;
10187  }
10188 
10189  case SCIP_EXPR_REALPOWER:
10190  {
10191  assert(node->nchildren == 1);
10192 
10193  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
10194 
10195  if( SCIPintervalIsEmpty(infinity, childbounds) )
10196  {
10197  *cutoff = TRUE;
10198  break;
10199  }
10200  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10201 
10202  break;
10203  }
10204 
10205  case SCIP_EXPR_SIGNPOWER:
10206  {
10207  assert(node->nchildren == 1);
10208 
10209  if( node->data.dbl != 0.0 )
10210  {
10211  SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
10212  }
10213  else
10214  {
10215  /* behaves like SCIP_EXPR_SIGN */
10216  SCIPintervalSetBounds(&childbounds,
10217  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10218  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10219  }
10220 
10221  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10222 
10223  break;
10224  }
10225 
10226  case SCIP_EXPR_INTPOWER:
10227  {
10228  assert(node->nchildren == 1);
10229 
10230  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
10231 
10232  if( SCIPintervalIsEmpty(infinity, childbounds) )
10233  {
10234  *cutoff = TRUE;
10235  break;
10236  }
10237  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10238 
10239  break;
10240  }
10241 
10242  case SCIP_EXPR_EXP:
10243  {
10244  assert(node->nchildren == 1);
10245  /* f = exp(c0) -> c0 = log(f) */
10246 
10247  if( node->bounds.sup < 0.0 )
10248  {
10249  *cutoff = TRUE;
10250  break;
10251  }
10252 
10253  SCIPintervalLog(infinity, &childbounds, node->bounds);
10254  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10255 
10256  break;
10257  }
10258 
10259  case SCIP_EXPR_LOG:
10260  {
10261  assert(node->nchildren == 1);
10262  /* f = log(c0) -> c0 = exp(f) */
10263 
10264  SCIPintervalExp(infinity, &childbounds, node->bounds);
10265  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10266 
10267  break;
10268  }
10269 
10270  case SCIP_EXPR_SIN:
10271  case SCIP_EXPR_COS:
10272  case SCIP_EXPR_TAN:
10273  /* case SCIP_EXPR_ERF: */
10274  /* case SCIP_EXPR_ERFI: */
10275  {
10276  assert(node->nchildren == 1);
10277 
10278  /* @todo implement */
10279 
10280  break;
10281  }
10282 
10283  case SCIP_EXPR_ABS:
10284  {
10285  assert(node->nchildren == 1);
10286  /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
10287 
10288  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
10289  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10290 
10291  break;
10292  }
10293 
10294  case SCIP_EXPR_SIGN:
10295  {
10296  assert(node->nchildren == 1);
10297  /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
10298 
10299  SCIPintervalSetBounds(&childbounds,
10300  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10301  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10302  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10303 
10304  break;
10305  }
10306 
10307  case SCIP_EXPR_MIN:
10308  {
10309  assert(node->nchildren == 2);
10310  /* f = min(c0,c1) -> f <= c0, f <= c1
10311  * if c1 > f -> c0 = f
10312  * if c0 > f -> c1 = f
10313  */
10314 
10315  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10316  node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10317  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10318 
10319  if( *cutoff )
10320  break;
10321 
10322  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10323  node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10324  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10325 
10326  break;
10327  }
10328 
10329  case SCIP_EXPR_MAX:
10330  {
10331  assert(node->nchildren == 2);
10332  /* f = max(c0, c1) -> f >= c0, f >= c1
10333  * if c1 < f -> c0 = f
10334  * if c0 < f -> c1 = f
10335  */
10336 
10337  SCIPintervalSetBounds(&childbounds,
10338  node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10339  node->bounds.sup);
10340  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10341 
10342  SCIPintervalSetBounds(&childbounds,
10343  node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10344  node->bounds.sup);
10345  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10346 
10347  break;
10348  }
10349 
10350  case SCIP_EXPR_SUM:
10351  {
10352  SCIP_ROUNDMODE prevroundmode;
10353 
10354  /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
10355 
10356  SCIP_Real minlinactivity;
10357  SCIP_Real maxlinactivity;
10358  int minlinactivityinf;
10359  int maxlinactivityinf;
10360 
10361  if( node->nchildren == 0 )
10362  break;
10363 
10364  if( SCIPintervalIsEntire(infinity, node->bounds) )
10365  break;
10366 
10367  minlinactivity = 0.0;
10368  maxlinactivity = 0.0;
10369  minlinactivityinf = 0;
10370  maxlinactivityinf = 0;
10371 
10372  prevroundmode = SCIPintervalGetRoundingMode();
10374 
10375  for( i = 0; i < node->nchildren; ++i )
10376  {
10377  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10378 
10379  /* minimal activity is only useful if node has a finite upper bound */
10380  if( node->bounds.sup < infinity )
10381  {
10382  if( node->children[i]->bounds.inf <= -infinity )
10383  {
10384  ++minlinactivityinf;
10385  }
10386  else
10387  {
10388  assert(node->children[i]->bounds.inf < infinity);
10389  minlinactivity += node->children[i]->bounds.inf;
10390  }
10391  }
10392 
10393  /* maximal activity is only useful if node has a finite lower bound
10394  * we compute negated maximal activity here so we can keep downward rounding
10395  */
10396  if( node->bounds.inf > -infinity )
10397  {
10398  if( node->children[i]->bounds.sup >= infinity )
10399  {
10400  ++maxlinactivityinf;
10401  }
10402  else
10403  {
10404  assert(node->children[i]->bounds.sup > -infinity);
10405  maxlinactivity -= node->children[i]->bounds.sup;
10406  }
10407  }
10408  }
10409  maxlinactivity = -maxlinactivity; /* correct sign */
10410 
10411  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10412  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10413  ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10414  )
10415  {
10416  SCIPintervalSetRoundingMode(prevroundmode);
10417  break;
10418  }
10419 
10420  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10421  {
10422  /* upper bounds of c_i is
10423  * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
10424  * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
10425  */
10426  SCIPintervalSetEntire(infinity, &childbounds);
10427  if( node->bounds.sup < infinity )
10428  {
10429  /* we are still in downward rounding mode, so negate and negate to get upward rounding */
10430  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10431  {
10432  assert(minlinactivityinf == 1);
10433  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
10434  }
10435  else if( minlinactivityinf == 0 )
10436  {
10437  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
10438  }
10439  }
10440 
10441  /* lower bounds of c_i is
10442  * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
10443  * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
10444  */
10445  if( node->bounds.inf > -infinity )
10446  {
10447  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10448  {
10449  assert(maxlinactivityinf == 1);
10450  childbounds.inf = node->bounds.inf - maxlinactivity;
10451  }
10452  else
10453  {
10454  childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
10455  }
10456  }
10457 
10458  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10459  }
10460 
10461  SCIPintervalSetRoundingMode(prevroundmode);
10462 
10463  break;
10464  }
10465 
10466  case SCIP_EXPR_PRODUCT:
10467  {
10468  int j;
10469  /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
10470 
10471  /* too expensive (runtime here is quadratic in number of children) */
10472  if( node->nchildren > 10 )
10473  break;
10474 
10475  /* useless */
10476  if( SCIPintervalIsEntire(infinity, node->bounds) )
10477  break;
10478 
10479  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10480  {
10481  /* compute prod_{j:j!=i} c_j */
10482  SCIPintervalSet(&childbounds, 1.0);
10483  for( j = 0; j < node->nchildren; ++j )
10484  {
10485  if( i == j )
10486  continue;
10487  SCIPintervalMul(infinity, &childbounds, childbounds, node->children[i]->bounds);
10488 
10489  /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
10490  if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
10491  break;
10492  }
10493 
10494  if( j == node->nchildren )
10495  {
10496  SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
10497  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10498  }
10499  }
10500 
10501  break;
10502  }
10503 
10504  case SCIP_EXPR_LINEAR:
10505  {
10506  SCIP_ROUNDMODE prevroundmode;
10507  SCIP_Real* coefs;
10508 
10509  /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10510 
10511  SCIP_Real minlinactivity;
10512  SCIP_Real maxlinactivity;
10513  int minlinactivityinf;
10514  int maxlinactivityinf;
10515 
10516  if( node->nchildren == 0 )
10517  break;
10518 
10519  if( SCIPintervalIsEntire(infinity, node->bounds) )
10520  break;
10521 
10522  coefs = (SCIP_Real*)node->data.data;
10523 
10524  minlinactivity = coefs[node->nchildren];
10525  maxlinactivity = -coefs[node->nchildren];
10526  minlinactivityinf = 0;
10527  maxlinactivityinf = 0;
10528 
10529  prevroundmode = SCIPintervalGetRoundingMode();
10531 
10532  for( i = 0; i < node->nchildren; ++i )
10533  {
10534  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10535 
10536  /* minimal activity is only useful if node has a finite upper bound */
10537  if( node->bounds.sup < infinity )
10538  {
10539  if( coefs[i] >= 0.0 )
10540  {
10541  if( node->children[i]->bounds.inf <= -infinity )
10542  {
10543  ++minlinactivityinf;
10544  }
10545  else
10546  {
10547  assert(node->children[i]->bounds.inf < infinity);
10548  minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10549  }
10550  }
10551  else
10552  {
10553  if( node->children[i]->bounds.sup >= infinity )
10554  {
10555  ++minlinactivityinf;
10556  }
10557  else
10558  {
10559  assert(node->children[i]->bounds.sup > -infinity);
10560  minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10561  }
10562  }
10563  }
10564 
10565  /* maximal activity is only useful if node has a finite lower bound
10566  * we compute negated maximal activity here so we can keep downward rounding
10567  */
10568  if( node->bounds.inf > -infinity )
10569  {
10570  if( coefs[i] >= 0.0 )
10571  {
10572  if( node->children[i]->bounds.sup >= infinity )
10573  {
10574  ++maxlinactivityinf;
10575  }
10576  else
10577  {
10578  assert(node->children[i]->bounds.sup > -infinity);
10579  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.sup;
10580  }
10581  }
10582  else
10583  {
10584  if( node->children[i]->bounds.inf <= -infinity )
10585  {
10586  ++maxlinactivityinf;
10587  }
10588  else
10589  {
10590  assert(node->children[i]->bounds.inf < infinity);
10591  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.inf;
10592  }
10593  }
10594  }
10595  }
10596  maxlinactivity = SCIPintervalNegateReal(maxlinactivity); /* correct sign */
10597 
10598  /* SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]; bounds = [%10g,%10g]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf, node->bounds.inf, node->bounds.sup); */
10599 
10600  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10601  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10602  (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10603  )
10604  {
10605  SCIPintervalSetRoundingMode(prevroundmode);
10606  break;
10607  }
10608 
10609  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10610  {
10611  SCIP_INTERVAL ac;
10612 
10613  if( coefs[i] == 0.0 )
10614  continue;
10615 
10616  /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10617  SCIPintervalSet(&ac, 0.0);
10618  if( coefs[i] >= 0.0 )
10619  {
10620  if( node->children[i]->bounds.inf > -infinity )
10621  ac.inf = coefs[i] * node->children[i]->bounds.inf;
10622  if( node->children[i]->bounds.sup < infinity )
10624  }
10625  else
10626  {
10627  if( node->children[i]->bounds.sup < infinity )
10628  ac.inf = coefs[i] * node->children[i]->bounds.sup;
10629  if( node->children[i]->bounds.inf > -infinity )
10630  ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10631  }
10632 
10633  SCIPintervalSetEntire(infinity, &childbounds);
10634  if( coefs[i] > 0.0 )
10635  {
10636  /* upper bounds of c_i is
10637  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10638  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10639  */
10640  if( node->bounds.sup < infinity )
10641  {
10642  /* we are still in downward rounding mode, so negate to get upward rounding */
10643  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10644  {
10645  assert(minlinactivityinf == 1);
10646  childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10647  }
10648  else if( minlinactivityinf == 0 )
10649  {
10650  childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10651  }
10652  }
10653 
10654  /* lower bounds of c_i is
10655  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10656  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10657  */
10658  if( node->bounds.inf > -infinity )
10659  {
10660  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10661  {
10662  assert(maxlinactivityinf == 1);
10663  childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10664  }
10665  else if( maxlinactivityinf == 0 )
10666  {
10667  childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10668  }
10669  }
10670  }
10671  else
10672  {
10673  /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10674  * thus, we do (b-a)/(-c) in downward rounding
10675  */
10676  /* lower bounds of c_i is
10677  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10678  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10679  */
10680  if( node->bounds.sup < infinity )
10681  {
10682  if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10683  {
10684  assert(minlinactivityinf == 1);
10685  childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10686  }
10687  else if( minlinactivityinf == 0 )
10688  {
10689  childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10690  }
10691  }
10692 
10693  /* upper bounds of c_i is
10694  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10695  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10696  */
10697  if( node->bounds.inf > -infinity )
10698  {
10699  /* we are still in downward rounding mode, so negate to get upward rounding */
10700  if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10701  {
10702  assert(maxlinactivityinf == 1);
10703  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10704  }
10705  else if( maxlinactivityinf == 0 )
10706  {
10707  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10708  }
10709  }
10710  }
10711 
10712  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10713  }
10714 
10715  SCIPintervalSetRoundingMode(prevroundmode);
10716 
10717  break;
10718  }
10719 
10720  case SCIP_EXPR_QUADRATIC:
10721  {
10722  SCIP_EXPRDATA_QUADRATIC* quaddata;
10723  SCIP_INTERVAL tmp;
10724  SCIP_INTERVAL a;
10725  SCIP_INTERVAL b;
10726  SCIP_INTERVAL c;
10727  SCIP_QUADELEM* quadelems;
10728  int nquadelems;
10729  SCIP_Real* lincoefs;
10730  int k;
10731 
10732  /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10733  * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10734  */
10735 
10736  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10737  quadelems = quaddata->quadelems;
10738  nquadelems = quaddata->nquadelems;
10739  lincoefs = quaddata->lincoefs;
10740 
10741  /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10742  if( nquadelems > 10 )
10743  break;
10744 
10745  if( SCIPintervalIsEntire(infinity, node->bounds) )
10746  break;
10747 
10748  if( node->nchildren == 2 && nquadelems > 0 )
10749  {
10750  /* if it's a bivariate quadratic expression with bilinear term, do something special */
10751  SCIP_Real ax; /* square coefficient of first child */
10752  SCIP_Real ay; /* square coefficient of second child */
10753  SCIP_Real axy; /* bilinear coefficient */
10754 
10755  ax = 0.0;
10756  ay = 0.0;
10757  axy = 0.0;
10758  for( i = 0; i < nquadelems; ++i )
10759  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10760  ax += quadelems[i].coef;
10761  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10762  ay += quadelems[i].coef;
10763  else
10764  axy += quadelems[i].coef;
10765 
10766  c = node->bounds;
10767  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10768 
10769  /* compute bounds for x */
10771  infinity, &childbounds, ax, ay, axy,
10772  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10773  c, node->children[0]->bounds, node->children[1]->bounds
10774  );
10775  if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10776  {
10777  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",
10778  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10779  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10780  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10781  );
10782  }
10783 
10784  if( SCIPintervalIsEmpty(infinity, childbounds) )
10785  *cutoff = TRUE;
10786  else
10787  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10788  if( *cutoff )
10789  break;
10790 
10791  /* compute bounds for y */
10793  infinity, &childbounds, ay, ax, axy,
10794  lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
10795  c, node->children[1]->bounds, node->children[0]->bounds
10796  );
10797 
10798  if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
10799  {
10800  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",
10801  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10802  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10803  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10804  );
10805  }
10806 
10807  if( SCIPintervalIsEmpty(infinity, childbounds) )
10808  *cutoff = TRUE;
10809  else
10810  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10811  if( *cutoff )
10812  break;
10813 
10814  break;
10815  }
10816 
10817  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10818  {
10819  SCIPintervalSet(&a, 0.0);
10820  SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
10821  c = node->bounds;
10822  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10823 
10824  /* move linear terms not corresponding to i into c
10825  * @todo do this faster, see EXPR_LINEAR
10826  */
10827  if( lincoefs != NULL )
10828  for( k = 0; k < node->nchildren; ++k )
10829  if( i != k && lincoefs[k] != 0.0 )
10830  {
10831  SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
10832  SCIPintervalSub(infinity, &c, c, tmp);
10833  }
10834 
10835  for( k = 0; k < nquadelems; ++k )
10836  {
10837  if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
10838  {
10839  SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
10840  }
10841  else if( quadelems[k].idx1 == i )
10842  {
10843  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
10844  SCIPintervalAdd(infinity, &b, b, tmp);
10845  }
10846  else if( quadelems[k].idx2 == i )
10847  {
10848  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
10849  SCIPintervalAdd(infinity, &b, b, tmp);
10850  }
10851  else if( quadelems[k].idx1 == quadelems[k].idx2 )
10852  {
10853  SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
10854  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
10855  SCIPintervalSub(infinity, &c, c, tmp);
10856  }
10857  else
10858  {
10859  SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
10860  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
10861  SCIPintervalSub(infinity, &c, c, tmp);
10862  }
10863  }
10864 
10865  SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
10866  a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
10867  SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c);
10868  if( SCIPintervalIsEmpty(infinity, childbounds) )
10869  *cutoff = TRUE;
10870  else
10871  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10872  }
10873 
10874  break;
10875  }
10876 
10877  case SCIP_EXPR_POLYNOMIAL:
10878  {
10879  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
10880  SCIP_EXPRDATA_MONOMIAL** monomials;
10881  SCIP_EXPRDATA_MONOMIAL* monomial;
10882  int nmonomials;
10883  int j;
10884  int k;
10885  SCIP_Real n;
10886  int nexpisdoublen;
10887  int nexpishalfn;
10888  char abc_flag;
10889 
10890  SCIP_INTERVAL monomialcoef;
10891  SCIP_INTERVAL tmp;
10892  SCIP_INTERVAL a;
10893  SCIP_INTERVAL b;
10894  SCIP_INTERVAL c;
10895 
10896  /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
10897  * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
10898  *
10899  * we determine n by setting n to the first exponent of x that we see
10900  * then we count how often we see x^(2n) and x^(n/2)
10901  * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
10902  */
10903 
10904  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
10905  monomials = polynomialdata->monomials;
10906  nmonomials = polynomialdata->nmonomials;
10907 
10908  if( SCIPintervalIsEntire(infinity, node->bounds) )
10909  break;
10910 
10911  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10912  {
10913  n = 0.0;
10914  nexpisdoublen = 0;
10915  nexpishalfn = 0;
10916  for( j = 0; j < nmonomials; ++j )
10917  {
10918  monomial = monomials[j];
10919  for( k = 0; k < monomial->nfactors; ++k )
10920  {
10921  if( monomial->childidxs[k] == i )
10922  {
10923  if( n == 0.0 )
10924  n = monomial->exponents[k];
10925  else if( n == 2*monomial->exponents[k] ) /*lint !e777*/
10926  ++nexpishalfn;
10927  else if( 2*n == monomial->exponents[k] ) /*lint !e777*/
10928  ++nexpisdoublen;
10929  }
10930  }
10931  }
10932 
10933  if( n == 0.0 )
10934  {
10935  /* child does not appear in polynomial -> cannot deduce bound */
10936  continue;
10937  }
10938 
10939  /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
10940  if( nexpishalfn > nexpisdoublen )
10941  n /= 2.0;
10942 
10943  SCIPintervalSet(&a, 0.0);
10944  SCIPintervalSet(&b, 0.0);
10945  SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
10946 
10947  for( j = 0; j < nmonomials; ++j )
10948  {
10949  monomial = monomials[j];
10950  SCIPintervalSet(&monomialcoef, monomial->coef);
10951  abc_flag = 'c';
10952  for( k = 0; k < monomial->nfactors; ++k )
10953  {
10954  if( monomial->childidxs[k] == i )
10955  {
10956  assert(abc_flag == 'c'); /* child should appear only once per monom */
10957  if( n > 0.0 )
10958  {
10959  if( monomial->exponents[k] > 2.0*n )
10960  {
10961  abc_flag = 'a';
10962  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
10963  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10964  }
10965  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
10966  {
10967  abc_flag = 'a';
10968  }
10969  else if( monomial->exponents[k] > n )
10970  {
10971  abc_flag = 'b';
10972  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
10973  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10974  }
10975  else if( monomial->exponents[k] == n ) /*lint !e777*/
10976  {
10977  abc_flag = 'b';
10978  }
10979  else
10980  {
10981  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
10982  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10983  }
10984  }
10985  else
10986  {
10987  assert(n < 0.0);
10988  if( monomial->exponents[k] < 2.0*n )
10989  {
10990  abc_flag = 'a';
10991  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
10992  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
10993  }
10994  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
10995  {
10996  abc_flag = 'a';
10997  }
10998  else if( monomial->exponents[k] < n )
10999  {
11000  abc_flag = 'b';
11001  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11002  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11003  }
11004  else if( monomial->exponents[k] == n ) /*lint !e777*/
11005  {
11006  abc_flag = 'b';
11007  }
11008  else
11009  {
11010  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11011  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11012  }
11013  }
11014  }
11015  else
11016  {
11017  SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
11018  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11019  }
11020  }
11021 
11022  if( abc_flag == 'a' )
11023  SCIPintervalAdd(infinity, &a, a, monomialcoef);
11024  else if( abc_flag == 'b' )
11025  SCIPintervalAdd(infinity, &b, b, monomialcoef);
11026  else
11027  SCIPintervalSub(infinity, &c, c, monomialcoef);
11028  }
11029 
11030  /* now have equation a*child^(2n) + b*child^n = c
11031  * solve a*y^2 + b*y = c, then child^n = y
11032  */
11033  SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g]",
11034  a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup);
11035  SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c);
11036  SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
11037 
11038  if( SCIPintervalIsEmpty(infinity, tmp) )
11039  {
11040  *cutoff = TRUE;
11041  break;
11042  }
11043 
11044  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
11045  SCIPdebugPrintf(" -> c%d = [%10g, %10g]\n", i, childbounds.inf, childbounds.sup);
11046  if( SCIPintervalIsEmpty(infinity, childbounds) )
11047  {
11048  SCIPdebugMessage(" -> cutoff\n");
11049  *cutoff = TRUE;
11050  break;
11051  }
11052 
11053  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11054 
11055  /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
11056  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11057  SCIPdebugPrintf("\n"); */
11058  }
11059 
11060  break;
11061  }
11062 
11063  case SCIP_EXPR_USER:
11064  {
11065  SCIP_INTERVAL* childrenbounds;
11066  SCIP_EXPRDATA_USER* exprdata;
11067  int c;
11068 
11069  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11070 
11071  /* do nothing if callback not implemented */
11072  if( exprdata->prop == NULL )
11073  break;
11074 
11075  /* if only one child, do faster */
11076  if( node->nchildren == 1 )
11077  {
11078  childbounds = node->children[0]->bounds;
11079  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, 1, &childbounds, node->bounds, cutoff) );
11080 
11081  if( !*cutoff )
11082  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11083 
11084  break;
11085  }
11086 
11087  SCIP_ALLOC_ABORT( BMSallocBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren) );
11088  for( c = 0; c < node->nchildren; ++c )
11089  childrenbounds[c] = node->children[c]->bounds;
11090 
11091  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, node->nchildren, childrenbounds, node->bounds, cutoff) );
11092 
11093  for( c = 0; !*cutoff && c < node->nchildren; ++c )
11094  {
11095  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[c], childrenbounds[c], minstrength, infinity, cutoff);
11096  }
11097 
11098  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren);
11099 
11100  break;
11101  }
11102 
11103  case SCIP_EXPR_LAST:
11104  SCIPABORT();
11105  break;
11106  }
11107 }
11108 
11109 /** removes duplicate children in a polynomial expression node
11110  *
11111  * Leaves NULL's in children array.
11112  */
11113 static
11115  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11116  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11117  )
11118 {
11119  SCIP_Bool foundduplicates;
11120  int* childmap;
11121  int i;
11122  int j;
11123 
11124  assert(exprgraph != NULL);
11125  assert(node != NULL);
11126  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11127 
11128  if( node->nchildren == 0 )
11129  return SCIP_OKAY;
11130 
11131  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
11132 
11133  foundduplicates = FALSE;
11134  for( i = 0; i < node->nchildren; ++i )
11135  {
11136  if( node->children[i] == NULL )
11137  continue;
11138  childmap[i] = i; /*lint !e644*/
11139 
11140  for( j = i+1; j < node->nchildren; ++j )
11141  {
11142  if( node->children[j] == NULL )
11143  continue;
11144 
11145  if( node->children[i] == node->children[j] )
11146  {
11147  /* node should be parent of children[j] at least twice,
11148  * so we remove it once
11149  */
11150  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
11151  node->children[j] = NULL;
11152  assert(exprgraphNodeIsParent(node->children[i], node));
11153 
11154  childmap[j] = i;
11155  foundduplicates = TRUE;
11156  }
11157  }
11158  }
11159 
11160  /* apply childmap to monomials */
11161  if( foundduplicates )
11163 
11164  /* free childmap */
11165  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
11166 
11167  return SCIP_OKAY;
11168 }
11169 
11170 /** eliminates NULL's in children array and shrinks it to actual size */
11171 static
11173  BMS_BLKMEM* blkmem, /**< block memory */
11174  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11175  )
11176 {
11177  int* childmap;
11178  int lastnonnull;
11179  int i;
11180 
11181  assert(blkmem != NULL);
11182  assert(node != NULL);
11183  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11184 
11185  if( node->nchildren == 0 )
11186  return SCIP_OKAY;
11187 
11188  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
11189 
11190  /* close gaps in children array */
11191  lastnonnull = node->nchildren-1;
11192  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11193  --lastnonnull;
11194  for( i = 0; i <= lastnonnull; ++i )
11195  {
11196  if( node->children[i] != NULL )
11197  {
11198  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
11199  continue;
11200  }
11201  assert(node->children[lastnonnull] != NULL);
11202 
11203  /* move child at lastnonnull to position i */
11204  node->children[i] = node->children[lastnonnull];
11205  node->children[lastnonnull] = NULL;
11206  childmap[lastnonnull] = i;
11207 
11208  /* update lastnonnull */
11209  --lastnonnull;
11210  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11211  --lastnonnull;
11212  }
11213  assert(i > lastnonnull);
11214 
11215  /* apply childmap to monomials */
11216  if( lastnonnull < node->nchildren-1 )
11218 
11219  BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
11220 
11221  /* shrink children array */
11222  if( lastnonnull >= 0 )
11223  {
11224  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
11225  node->nchildren = lastnonnull+1;
11226  }
11227  else
11228  {
11229  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11230  node->nchildren = 0;
11231  }
11232 
11233  return SCIP_OKAY;
11234 }
11235 
11236 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
11237  *
11238  * Converts node into polynomial, if possible and not constant.
11239  */
11240 static
11242  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11243  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
11244  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
11245  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
11246  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
11247  SCIP_Bool* havechange /**< flag to set if the node has been changed */
11248  )
11249 {
11250  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11251  SCIP_EXPRDATA_MONOMIAL* monomial;
11252  BMS_BLKMEM* blkmem;
11253  SCIP_Bool removechild;
11254  SCIP_Bool* childinuse;
11255  int* childmap;
11256  int childmapsize;
11257  int i;
11258  int j;
11259  int orignchildren;
11260 
11261  assert(exprgraph != NULL);
11262  assert(node != NULL);
11263  assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
11264  assert(havechange != NULL);
11265 
11266  blkmem = exprgraph->blkmem;
11267  assert(blkmem != NULL);
11268 
11269  SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
11270 
11271  /* if all children are constants, then turn this node into constant */
11272  for( i = 0; i < node->nchildren; ++i )
11273  if( node->children[i]->op != SCIP_EXPR_CONST )
11274  break;
11275  if( node->nchildren > 0 && i == node->nchildren )
11276  {
11277  /* get value of node */
11279  assert(node->value != SCIP_INVALID); /*lint !e777*/
11280 
11281  SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
11282  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11283  SCIPdebugPrintf("\n");
11284 
11285  /* free expression data */
11286  if( exprOpTable[node->op].freedata != NULL )
11287  exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
11288 
11289  /* disconnect from children */
11290  for( i = 0; i < node->nchildren; ++i )
11291  {
11292  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11293  }
11294  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11295  node->nchildren = 0;
11296 
11297  /* turn into constant expression */
11298  node->op = SCIP_EXPR_CONST;
11299  node->data.dbl = node->value;
11300 
11301  *havechange = TRUE;
11302  node->simplified = TRUE;
11303 
11304  return SCIP_OKAY;
11305  }
11306 
11307  /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
11308  * @todo log(product) -> sum(log)
11309  * @todo product(exp) -> exp(sum)
11310  * @todo exp(x)^p -> exp(p*x)
11311  * @todo exp(const*log(x)) -> x^const
11312  */
11313 
11314  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
11315 
11316  if( node->op != SCIP_EXPR_POLYNOMIAL )
11317  {
11318  node->simplified = TRUE;
11319  return SCIP_OKAY;
11320  }
11321 
11322  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11323  assert(polynomialdata != NULL);
11324 
11325  orignchildren = node->nchildren;
11326 
11327  /* check if we have duplicate children and merge */
11329  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11330 
11331  SCIPdebugMessage("expand factors in expression node ");
11332  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11333  SCIPdebugPrintf("\n");
11334 
11335  childmap = NULL;
11336  childmapsize = 0;
11337 
11338  /* resolve children that are constants
11339  * we do this first, because it reduces the degree and number of factors in the monomials,
11340  * 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
11341  */
11342  for( i = 0; i < node->nchildren; ++i )
11343  {
11344  if( node->children[i] == NULL )
11345  continue;
11346 
11347  /* convert children to polynomial, if not constant or polynomial
11348  * if child was simplified in this round, it may have already been converted, and then nothing happens
11349  * but if child was already simplified, then it was not converted, and thus we try it here
11350  */
11351  if( node->children[i]->op != SCIP_EXPR_CONST )
11352  continue;
11353 
11354  SCIPdebugMessage("expand child %d in expression node ", i);
11355  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11356  SCIPdebugPrintf("\n\tchild = ");
11357  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11358  SCIPdebugPrintf("\n");
11359 
11360  removechild = TRUE; /* we intend to release children[i] */
11361 
11362  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11363 
11364  /* put constant of child i into every monomial where child i is used */
11365  for( j = 0; j < polynomialdata->nmonomials; ++j )
11366  {
11367  int factorpos;
11368 
11369  monomial = polynomialdata->monomials[j];
11370  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11371  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11372 
11373  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11374  {
11375  assert(factorpos >= 0);
11376  assert(factorpos < monomial->nfactors);
11377  /* assert that factors have been merged */
11378  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11379  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11380 
11381  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11382 
11383  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 ) /*lint !e835*/
11384  {
11385  /* if constant is negative and our exponent is not integer, then cannot do expansion */
11386  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
11387  removechild = FALSE;
11388  }
11389  else
11390  {
11391  monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
11392 
11393  /* move last factor to position factorpos */
11394  if( factorpos < monomial->nfactors-1 )
11395  {
11396  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
11397  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
11398  }
11399  --monomial->nfactors;
11400  monomial->sorted = FALSE;
11401  polynomialdata->sorted = FALSE;
11402 
11403  *havechange = TRUE;
11404  }
11405  }
11406  }
11407 
11408  /* forget about child i, if it is not used anymore */
11409  if( removechild )
11410  {
11411  /* remove node from list of parents of child i */
11412  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11413  node->children[i] = NULL;
11414  }
11415 
11416  /* simplify current polynomial again */
11417  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11418  }
11419 
11420  /* resolve children that are polynomials itself */
11421  for( i = 0; i < node->nchildren; ++i )
11422  {
11423  if( node->children[i] == NULL )
11424  continue;
11425 
11426  /* convert children to polynomial, if not constant or polynomial
11427  * if child was simplified in this round, it may have already been converted, and then nothing happens
11428  * but if child was already simplified, then it was not converted, and thus we try it here
11429  */
11430  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
11431 
11432  if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
11433  continue;
11434 
11435  SCIPdebugMessage("expand child %d in expression node ", i);
11436  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11437  SCIPdebugPrintf("\n\tchild = ");
11438  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11439  SCIPdebugPrintf("\n");
11440 
11441  removechild = TRUE; /* we intend to release children[i] */
11442 
11443  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11444 
11445  /* add children of child i to node */
11446  SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
11447 
11448  /* put polynomial of child i into every monomial where child i is used */
11449  j = 0;
11450  while( j < polynomialdata->nmonomials )
11451  {
11452  int factorpos;
11453  SCIP_Bool success;
11454 
11455  monomial = polynomialdata->monomials[j];
11456  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11457  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11458 
11459  if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11460  {
11461  ++j;
11462  continue;
11463  }
11464 
11465  assert(factorpos >= 0);
11466  assert(factorpos < monomial->nfactors);
11467  /* assert that factors have been merged */
11468  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11469  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11470 
11471  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11472 
11473  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
11474  (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
11475 
11476  if( !success )
11477  {
11478  removechild = FALSE;
11479  ++j;
11480  }
11481  else
11482  *havechange = TRUE;
11483 
11484  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
11485  * we thus repeat with index j, if a factor was successfully expanded
11486  */
11487  }
11488 
11489  /* forget about child i, if it is not used anymore */
11490  if( removechild )
11491  {
11492  /* remove node from list of parents of child i */
11493  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11494  node->children[i] = NULL;
11495  }
11496 
11497  /* simplify current polynomial again */
11498  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11499  }
11500 
11501  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
11502 
11503  /* check which children are still in use */
11504  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
11505  BMSclearMemoryArray(childinuse, node->nchildren); /*lint !e644*/
11506  for( i = 0; i < polynomialdata->nmonomials; ++i )
11507  {
11508  monomial = polynomialdata->monomials[i];
11509  assert(monomial != NULL);
11510 
11511  for( j = 0; j < monomial->nfactors; ++j )
11512  {
11513  assert(monomial->childidxs[j] >= 0);
11514  assert(monomial->childidxs[j] < node->nchildren);
11515  childinuse[monomial->childidxs[j]] = TRUE;
11516  }
11517  }
11518 
11519  /* free children that are not used in any monomial */
11520  for( i = 0; i < node->nchildren; ++i )
11521  if( node->children[i] != NULL && !childinuse[i] )
11522  {
11523  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11524  node->children[i] = NULL;
11525  }
11526 
11527  BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
11528 
11529  /* remove NULLs from children array */
11531 
11532  /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
11533  if( node->nchildren == 0 )
11534  {
11535  SCIP_Real val;
11536 
11537  /* if no children, then it should also have no monomials */
11538  assert(polynomialdata->nmonomials == 0);
11539 
11540  val = polynomialdata->constant;
11541  polynomialdataFree(blkmem, &polynomialdata);
11542 
11543  node->op = SCIP_EXPR_CONST;
11544  node->data.dbl = val;
11545  node->value = val;
11546  }
11547 
11548  /* if no factor in a monomial was replaced, the number of children should not have changed
11549  * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11550  */
11551  *havechange |= (node->nchildren < orignchildren); /*lint !e514*/
11552 
11553  node->simplified = TRUE;
11554 
11555  SCIPdebugMessage("-> %p = ", (void*)node);
11556  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11557  SCIPdebugPrintf("\n");
11558 
11559  return SCIP_OKAY;
11560 }
11561 
11562 /** creates an expression from a given node in an expression graph
11563  *
11564  * Assembles mapping of variables from graph to tree.
11565  */
11566 static
11568  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11569  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which expression should be created */
11570  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
11571  int* nexprvars, /**< current number of variables in expression */
11572  int* varidx /**< current mapping of variable indices from graph to expression */
11573  )
11574 {
11575  SCIP_EXPR** childexprs;
11576  int i;
11577 
11578  assert(exprgraph != NULL);
11579  assert(node != NULL);
11580  assert(expr != NULL);
11581  assert(nexprvars != NULL);
11582  assert(*nexprvars >= 0);
11583  assert(varidx != NULL);
11584 
11585  childexprs = NULL;
11586  if( node->nchildren > 0 )
11587  {
11588  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11589  for( i = 0; i < node->nchildren; ++i )
11590  {
11591  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) ); /*lint !e613*/
11592  }
11593  }
11594 
11595  switch( node->op )
11596  {
11597  case SCIP_EXPR_VARIDX:
11598  {
11599  /* check if the variable already has an index assigned in the expression tree
11600  * if not, create one and increase nexprvars
11601  */
11602  assert(node->data.intval >= 0);
11603  assert(node->data.intval < exprgraph->nvars);
11604  assert(varidx[node->data.intval] >= -1);
11605  assert(varidx[node->data.intval] < *nexprvars);
11606  if( varidx[node->data.intval] == -1 )
11607  {
11608  varidx[node->data.intval] = *nexprvars;
11609  ++*nexprvars;
11610  }
11611 
11612  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11613  break;
11614  }
11615 
11616  case SCIP_EXPR_CONST:
11617  {
11618  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11619  break;
11620  }
11621 
11622  case SCIP_EXPR_REALPOWER:
11623  case SCIP_EXPR_SIGNPOWER:
11624  {
11625  assert(childexprs != NULL);
11626  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11627  break;
11628  }
11629 
11630  case SCIP_EXPR_INTPOWER:
11631  {
11632  assert(childexprs != NULL);
11633  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11634  break;
11635  }
11636 
11637  case SCIP_EXPR_PLUS:
11638  case SCIP_EXPR_MINUS:
11639  case SCIP_EXPR_MUL:
11640  case SCIP_EXPR_DIV:
11641  case SCIP_EXPR_MIN:
11642  case SCIP_EXPR_MAX:
11643  {
11644  assert(node->nchildren == 2);
11645  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11646  break;
11647  }
11648 
11649  case SCIP_EXPR_SQUARE:
11650  case SCIP_EXPR_SQRT:
11651  case SCIP_EXPR_EXP:
11652  case SCIP_EXPR_LOG:
11653  case SCIP_EXPR_SIN:
11654  case SCIP_EXPR_COS:
11655  case SCIP_EXPR_TAN:
11656  /* case SCIP_EXPR_ERF: */
11657  /* case SCIP_EXPR_ERFI: */
11658  case SCIP_EXPR_ABS:
11659  case SCIP_EXPR_SIGN:
11660  {
11661  assert(node->nchildren == 1);
11662  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11663  break;
11664  }
11665 
11666  case SCIP_EXPR_SUM:
11667  case SCIP_EXPR_PRODUCT:
11668  {
11669  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11670  break;
11671  }
11672 
11673  case SCIP_EXPR_LINEAR:
11674  {
11675  assert(node->data.data != NULL);
11676 
11677  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11678  break;
11679  }
11680 
11681  case SCIP_EXPR_QUADRATIC:
11682  {
11683  SCIP_EXPRDATA_QUADRATIC* quaddata;
11684 
11685  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11686  assert(quaddata != NULL);
11687 
11688  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11689  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11690  break;
11691  }
11692 
11693  case SCIP_EXPR_POLYNOMIAL:
11694  {
11695  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11696 
11697  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11698  assert(polynomialdata != NULL);
11699 
11700  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11701  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11702 
11703  break;
11704  }
11705 
11706  case SCIP_EXPR_USER:
11707  {
11708  SCIP_EXPRDATA_USER* exprdata;
11709  SCIP_USEREXPRDATA* userdata;
11710 
11711  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11712  assert(exprdata != NULL);
11713 
11714  if( exprdata->copydata != NULL )
11715  {
11716  SCIP_CALL( exprdata->copydata(exprgraph->blkmem, node->nchildren, exprdata->userdata, &userdata) );
11717  }
11718  else
11719  userdata = exprdata->userdata;
11720 
11721  SCIP_CALL( SCIPexprCreateUser(exprgraph->blkmem, expr, node->nchildren, childexprs,
11722  userdata, exprdata->evalcapability, exprdata->eval, exprdata->inteval, exprdata->curv, exprdata->prop, exprdata->estimate, exprdata->copydata, exprdata->freedata) );
11723 
11724  break;
11725  }
11726 
11727  case SCIP_EXPR_LAST:
11728  case SCIP_EXPR_PARAM:
11729  {
11730  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11731  return SCIP_ERROR;
11732  }
11733  }
11734 
11735  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11736 
11737  return SCIP_OKAY;
11738 }
11739 
11740 /** counts how often expression graph variables are used in a subtree of the expression graph
11741  *
11742  * @note The function does not clear the array first, but only increases already existing counts.
11743  */
11744 static
11746  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11747  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11748  )
11749 {
11750  int i;
11751 
11752  assert(node != NULL);
11753  assert(varsusage != NULL);
11754 
11755  if( node->op == SCIP_EXPR_VARIDX )
11756  {
11757  ++varsusage[node->data.intval];
11758  return;
11759  }
11760 
11761  for( i = 0; i < node->nchildren; ++i )
11762  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
11763 }
11764 
11765 /** checks whether a node can be put into a component when checking block separability of an expression
11766  *
11767  * If a variable used by node is already in another component, components are merged and component number is updated.
11768  */
11769 static
11771  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
11772  int* compnr, /**< component number to assign, may be reduced if variables overlap */
11773  int nchildcomps, /**< number of entries for which childcomps have been set already */
11774  int* childcomps, /**< component numbers of children */
11775  int nvars, /**< number of variables */
11776  int* varcomps /**< component numbers of variables */
11777  )
11778 {
11779  int varidx;
11780  int i;
11781 
11782  assert(node != NULL);
11783  assert(compnr != NULL);
11784  assert(*compnr >= 0);
11785  assert(childcomps != NULL);
11786  assert(varcomps != NULL);
11787 
11788  if( node->op != SCIP_EXPR_VARIDX )
11789  {
11790  for( i = 0; i < node->nchildren; ++i )
11791  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
11792  return;
11793  }
11794 
11795  varidx = node->data.intval;
11796  assert(varidx >= 0);
11797  assert(varidx < nvars);
11798 
11799  if( varcomps[varidx] == -1 )
11800  {
11801  /* first time we get to this variable, so set it's component to compnr and we are done */
11802  varcomps[varidx] = *compnr;
11803  return;
11804  }
11805 
11806  if( varcomps[varidx] == *compnr )
11807  {
11808  /* variable is already in current component, that's also good and we are done */
11809  return;
11810  }
11811 
11812  /* variable is already in another component, so have to merge component compnr into that component
11813  * do this by updating varcomps and childcomps */
11814  for( i = 0; i < nvars; ++i )
11815  if( varcomps[i] == *compnr )
11816  varcomps[i] = varcomps[varidx];
11817  for( i = 0; i < nchildcomps; ++i )
11818  if( childcomps[i] == *compnr )
11819  childcomps[i] = varcomps[varidx];
11820  *compnr = varcomps[varidx];
11821 }
11822 
11823 /**@} */
11824 
11825 /**@name Expression graph private methods */
11826 /**@{ */
11827 
11828 /** assert that expression tree has at least a given depth */
11829 static
11831  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
11832  int mindepth /**< minimal depth that should be ensured */
11833  )
11834 {
11835  int olddepth;
11836 
11837  assert(exprgraph != NULL);
11838  assert(exprgraph->blkmem != NULL);
11839 
11840  if( mindepth <= exprgraph->depth )
11841  return SCIP_OKAY;
11842 
11843  olddepth = exprgraph->depth;
11844  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
11845  assert(exprgraph->depth >= mindepth);
11846 
11847  /* initialize new array entries to 0 and NULL, resp. */
11848  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11849  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11850  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11851 
11852  return SCIP_OKAY;
11853 }
11854 
11855 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
11856 static
11858  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11859  int varidx /**< variable index */
11860  )
11861 {
11862  SCIP_EXPRGRAPHNODE* varnode;
11863  void* var;
11864 
11865  assert(exprgraph != NULL);
11866  assert(varidx >= 0);
11867  assert(varidx < exprgraph->nvars);
11868 
11869  varnode = exprgraph->varnodes[varidx];
11870  assert(varnode->data.intval == varidx);
11871 
11872  var = exprgraph->vars[varidx];
11873 
11874  /* call varremove callback method, if set */
11875  if( exprgraph->exprgraphvarremove != NULL )
11876  {
11877  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
11878  }
11879 
11880  /* remove variable from hashmap */
11881  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
11882 
11883  /* move last variable to position varidx and give it the new index */
11884  if( varidx < exprgraph->nvars-1 )
11885  {
11886  /* call callback method, if set */
11887  if( exprgraph->exprgraphvarchgidx != NULL )
11888  {
11889  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
11890  }
11891 
11892  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
11893  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
11894  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
11895  exprgraph->varnodes[varidx]->data.intval = varidx;
11896  SCIP_CALL( SCIPhashmapSetImage(exprgraph->varidxs, exprgraph->vars[varidx], (void*)(size_t)(varidx)) );
11897  }
11898  --exprgraph->nvars;
11899 
11900  return SCIP_OKAY;
11901 }
11902 
11903 /** moves a node in an expression graph to a different depth
11904  *
11905  * New depth must be larger than children depth.
11906  * Moves parent nodes to higher depth, if needed.
11907  * Variable nodes cannot be moved.
11908  */
11909 static
11911  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11912  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
11913  int newdepth /**< new depth to which to move node */
11914  )
11915 {
11916  int olddepth;
11917  int oldpos;
11918  int i;
11919 
11920  assert(exprgraph != NULL);
11921  assert(node != NULL);
11922  assert(node->depth >= 0); /* node should be in graph */
11923  assert(newdepth >= 0);
11924 
11925  /* if already on aimed depth, then don't need to move */
11926  if( node->depth == newdepth )
11927  return SCIP_OKAY;
11928 
11929  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
11930 
11931 #ifndef NDEBUG
11932  /* assert that children are at lower depth than new depth */
11933  for( i = 0; i < node->nchildren; ++i )
11934  assert(node->children[i]->depth < newdepth);
11935 #endif
11936 
11937  /* move parents to higher depth, if needed */
11938  for( i = 0; i < node->nparents; ++i )
11939  {
11940  if( node->parents[i]->depth <= newdepth )
11941  {
11942  /* move parent to depth+1 */
11943  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
11944  assert(node->parents[i]->depth > newdepth);
11945  }
11946  }
11947 
11948  /* ensure that graph is deep enough */
11949  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
11950  assert(exprgraph->depth > newdepth);
11951 
11952  olddepth = node->depth;
11953  oldpos = node->pos;
11954 
11955  /* add node to new depth */
11956  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
11957  node->depth = newdepth;
11958  node->pos = exprgraph->nnodes[newdepth];
11959  exprgraph->nodes[newdepth][node->pos] = node;
11960  ++exprgraph->nnodes[newdepth];
11961 
11962  /* move last node at previous depth to previous position, if it wasn't last */
11963  if( oldpos < exprgraph->nnodes[olddepth]-1 )
11964  {
11965  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
11966  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
11967  }
11968  --exprgraph->nnodes[olddepth];
11969 
11970  if( node->depth == 0 )
11971  {
11972  /* if at depth 0, then it need to be a node for either a constant or a variable */
11973  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
11974  if( node->op == SCIP_EXPR_CONST )
11975  {
11976  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
11977  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
11978  exprgraph->constnodes[exprgraph->nconsts] = node;
11979  ++exprgraph->nconsts;
11980  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
11981  }
11982  else
11983  {
11984  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
11985  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
11986  return SCIP_ERROR;
11987  }
11988 
11989  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
11990  node->curv = SCIP_EXPRCURV_LINEAR;
11991  }
11992 
11993  return SCIP_OKAY;
11994 }
11995 
11996 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
11997 static
11999  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12000  int nchildren, /**< number of children */
12001  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
12002  SCIP_EXPROP op, /**< operator */
12003  SCIP_EXPROPDATA opdata, /**< operator data */
12004  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
12005  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
12006  )
12007 {
12008  SCIP_EXPRGRAPHNODE** parentcands;
12009  int nparentcands;
12010  int parentcandssize;
12011  int i;
12012  int p;
12013 
12014  assert(exprgraph != NULL);
12015  assert(nchildren > 0);
12016  assert(children != NULL);
12017  assert(parent != NULL);
12018 
12019  *parent = NULL;
12020 
12021  /* create initial set of parent candidates as
12022  * all parents of first child that have the same operator type and the same number of children
12023  * additionally, some easy conditions for complex expression types:
12024  * if expression type is int/real/signpower, then compare also exponent,
12025  * if expression type is linear, then compare also constant part,
12026  * if expression type is quadratic, then compare also number of quadratic elements,
12027  * if expression type is polynomial, then compare also number of monmials and constant part
12028  */
12029  parentcandssize = children[0]->nparents;
12030  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
12031  nparentcands = 0;
12032  for( p = 0; p < children[0]->nparents; ++p )
12033  if( children[0]->parents[p]->op == op &&
12034  children[0]->parents[p]->nchildren == nchildren &&
12035  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
12036  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12037  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12038  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
12039  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
12040  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
12041  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
12042  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
12043  )
12044  {
12045  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
12046  }
12047 
12048  /* for all remaining children, remove parent candidates, that are not in their list of parents */
12049  for( i = 1; i < nchildren && nparentcands > 0; ++i )
12050  {
12051  p = 0;
12052  while( p < nparentcands )
12053  {
12054  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
12055  * otherwise keep candidate and check next one
12056  */
12057  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
12058  {
12059  parentcands[p] = parentcands[nparentcands-1];
12060  --nparentcands;
12061  }
12062  else
12063  ++p;
12064  }
12065  }
12066 
12067  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
12068 
12069  if( nparentcands == 0 )
12070  {
12071  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
12072  return SCIP_OKAY;
12073  }
12074 
12075  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
12076  * check if there is also one which corresponds to same expression and store that one in *parent
12077  */
12078  switch( op )
12079  {
12080  /* commutative operands with no data */
12081  case SCIP_EXPR_PLUS :
12082  case SCIP_EXPR_MUL :
12083  case SCIP_EXPR_MIN :
12084  case SCIP_EXPR_MAX :
12085  case SCIP_EXPR_SUM :
12086  case SCIP_EXPR_PRODUCT:
12087  case SCIP_EXPR_SQUARE :
12088  case SCIP_EXPR_SQRT :
12089  case SCIP_EXPR_EXP :
12090  case SCIP_EXPR_LOG :
12091  case SCIP_EXPR_SIN :
12092  case SCIP_EXPR_COS :
12093  case SCIP_EXPR_TAN :
12094  /* case SCIP_EXPR_ERF : */
12095  /* case SCIP_EXPR_ERFI : */
12096  case SCIP_EXPR_ABS :
12097  case SCIP_EXPR_SIGN :
12098  {
12099  /* sort childnodes, if needed for later */
12100  if( nchildren > 2 )
12101  SCIPsortPtr((void**)children, ptrcomp, nchildren);
12102  for( p = 0; p < nparentcands; ++p )
12103  {
12104  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12105  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12106 
12107  if( nchildren == 1 )
12108  {
12109  assert(parentcands[p]->children[0] == children[0]);
12110  /* same operand, same child, so same expression */
12111  *parent = parentcands[p];
12112  break;
12113  }
12114  else if( nchildren == 2 )
12115  {
12116  /* We know that every node in children is also a child of parentcands[p].
12117  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
12118  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
12119  */
12120  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
12121  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
12122  {
12123  *parent = parentcands[p];
12124  break;
12125  }
12126  }
12127  else
12128  {
12129  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
12130 
12131  /* sort children of parent candidate */
12132  SCIPsortPtr((void**)parentcands[p]->children, ptrcomp, nchildren);
12133 
12134  /* check if childnodes and parentcands[p]->children are the same */
12135  for( i = 0; i < nchildren; ++i )
12136  if( children[i] != parentcands[p]->children[i] )
12137  break;
12138  if( i == nchildren )
12139  {
12140  /* yeah, found an exact match */
12141  *parent = parentcands[p];
12142  break;
12143  }
12144  }
12145  }
12146 
12147  break;
12148  }
12149 
12150  /* non-commutative operands with two children */
12151  case SCIP_EXPR_MINUS :
12152  case SCIP_EXPR_DIV :
12153  {
12154  for( p = 0; p < nparentcands; ++p )
12155  {
12156  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12157  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
12158  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
12159  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
12160  {
12161  /* yeah, found one */
12162  *parent = parentcands[p];
12163  break;
12164  }
12165  }
12166 
12167  break;
12168  }
12169 
12170  /* operands with one child and data */
12171  case SCIP_EXPR_INTPOWER:
12172  {
12173  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12174  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12175  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12176  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
12177 
12178  /* yeah, have one with same exponent */
12179  *parent = parentcands[0];
12180 
12181  break;
12182  }
12183 
12184  case SCIP_EXPR_REALPOWER:
12185  case SCIP_EXPR_SIGNPOWER:
12186  {
12187  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12188  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12189  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12190  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
12191 
12192  /* yeah, have one with same exponent */
12193  *parent = parentcands[0];
12194 
12195  break;
12196  }
12197 
12198  /* commutative operands with n children and data */
12199  case SCIP_EXPR_LINEAR:
12200  {
12201  SCIP_Real* exprcoef;
12202  SCIP_Real* candcoef;
12203 
12204  exprcoef = (SCIP_Real*)opdata.data;
12205  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
12206  if( exprchildren != NULL )
12207  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, ptrcomp, nchildren);
12208  else
12209  SCIPsortPtrReal((void**)children, exprcoef, ptrcomp, nchildren);
12210  for( p = 0; p < nparentcands; ++p )
12211  {
12212  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12213  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12214 
12215  candcoef = (SCIP_Real*)parentcands[p]->data.data;
12216  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12217 
12218  /* sort children of parent candidate */
12219  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, ptrcomp, nchildren);
12220 
12221  /* check if children and coefficients in parent candidate and expression are the same */
12222  for( i = 0; i < nchildren; ++i )
12223  {
12224  if( children[i] != parentcands[p]->children[i] )
12225  break;
12226  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
12227  break;
12228  }
12229  if( i < nchildren )
12230  continue;
12231 
12232  /* yeah, found an exact match */
12233  *parent = parentcands[p];
12234  break;
12235  }
12236 
12237  break;
12238  }
12239 
12240  case SCIP_EXPR_QUADRATIC:
12241  {
12242  SCIP_EXPRDATA_QUADRATIC* exprdata;
12243  SCIP_Real* exprlincoef;
12244  SCIP_Real* candlincoef;
12245  SCIP_EXPRDATA_QUADRATIC* canddata;
12246  int* perm;
12247  int* invperm;
12248 
12249  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
12250  exprlincoef = exprdata->lincoefs;
12251 
12252  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
12253 
12254  /* sort expr->children and childnodes and store inverse permutation in invperm */
12255  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12256  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12257  for( i = 0; i < nchildren; ++i )
12258  invperm[i] = i; /*lint !e644*/
12259 
12260  if( exprlincoef != NULL )
12261  if( exprchildren != NULL )
12262  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, ptrcomp, nchildren);
12263  else
12264  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, ptrcomp, nchildren);
12265  else
12266  if( exprchildren != NULL )
12267  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, ptrcomp, nchildren);
12268  else
12269  SCIPsortPtrInt((void**)children, invperm, ptrcomp, nchildren);
12270 
12271  /* compute permutation from its inverse */
12272  for( i = 0; i < nchildren; ++i )
12273  perm[invperm[i]] = i; /*lint !e644*/
12274 
12275  /* apply permuation to exprdata->quadelems and sort again */
12276  for( i = 0; i < exprdata->nquadelems; ++i )
12277  {
12278  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
12279  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
12280  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
12281  {
12282  int tmp;
12283  tmp = exprdata->quadelems[i].idx1;
12284  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
12285  exprdata->quadelems[i].idx2 = tmp;
12286  }
12287  }
12288  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
12289  exprdata->sorted = TRUE;
12290 
12291  for( p = 0; p < nparentcands; ++p )
12292  {
12293  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12294  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12295 
12296  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
12297  candlincoef = canddata->lincoefs;
12298  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
12299  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12300 
12301  /* sort parentcands[p]->children and store inverse permutation in invperm */
12302  for( i = 0; i < nchildren; ++i )
12303  invperm[i] = i;
12304 
12305  if( candlincoef != NULL )
12306  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, ptrcomp, parentcands[p]->nchildren);
12307  else
12308  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, ptrcomp, nchildren);
12309 
12310  /* compute permutation from its inverse */
12311  for( i = 0; i < nchildren; ++i )
12312  perm[invperm[i]] = i;
12313 
12314  /* apply permutation to canddata->quadelems */
12315  for( i = 0; i < canddata->nquadelems; ++i )
12316  {
12317  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
12318  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
12319  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
12320  {
12321  int tmp;
12322  tmp = canddata->quadelems[i].idx1;
12323  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
12324  canddata->quadelems[i].idx2 = tmp;
12325  }
12326  }
12327  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
12328  canddata->sorted = TRUE;
12329 
12330  /* check if children and linear coefficients in parent candidate and expression are the same */
12331  for( i = 0; i < nchildren; ++i )
12332  {
12333  if( children[i] != parentcands[p]->children[i] )
12334  break;
12335  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
12336  break;
12337  }
12338  if( i < nchildren )
12339  continue;
12340 
12341  assert(exprdata->nquadelems == canddata->nquadelems);
12342  for( i = 0; i < exprdata->nquadelems; ++i )
12343  {
12344  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
12345  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
12346  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
12347  break;
12348  }
12349  if( i == exprdata->nquadelems )
12350  {
12351  /* yeah, parentcands[p] is same quadratic expression as expr */
12352  *parent = parentcands[p];
12353  break;
12354  }
12355  }
12356 
12357  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12358  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12359 
12360  break;
12361  }
12362 
12363  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
12364  case SCIP_EXPR_POLYNOMIAL:
12365  {
12366  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
12367  SCIP_EXPRDATA_POLYNOMIAL* canddata;
12368  int* perm;
12369  int* invperm;
12370 
12371  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
12372 
12373  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
12374 
12375  /* sort exprchildren and childnodes and store inverse permutation in invperm */
12376  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12377  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12378  for( i = 0; i < nchildren; ++i )
12379  invperm[i] = i; /*lint !e644*/
12380 
12381  if( exprchildren != NULL )
12382  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, ptrcomp, nchildren);
12383  else
12384  SCIPsortPtrInt((void**)children, invperm, ptrcomp, nchildren);
12385 
12386  /* compute permutation from its inverse */
12387  for( i = 0; i < nchildren; ++i )
12388  perm[invperm[i]] = i; /*lint !e644*/
12389 
12390  /* apply permutation to exprdata and sort again */
12391  polynomialdataApplyChildmap(exprdata, perm);
12392  polynomialdataSortMonomials(exprdata);
12393 
12394  for( p = 0; p < nparentcands; ++p )
12395  {
12396  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12397  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12398 
12399  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
12400  assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
12401  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12402 
12403  /* sort parentcands[p]->children and store inverse permutation in invperm */
12404  for( i = 0; i < nchildren; ++i )
12405  invperm[i] = i;
12406 
12407  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, ptrcomp, nchildren);
12408 
12409  /* compute permutation from its inverse */
12410  for( i = 0; i < nchildren; ++i )
12411  perm[invperm[i]] = i;
12412 
12413  /* apply permutation to canddata and sort again */
12414  polynomialdataApplyChildmap(canddata, perm);
12415  polynomialdataSortMonomials(canddata);
12416 
12417  /* check if children are equal */
12418  for( i = 0; i < nchildren; ++i )
12419  if( children[i] != parentcands[p]->children[i] )
12420  break;
12421  if( i < nchildren )
12422  continue;
12423 
12424  /* check if monomials are equal */
12425  for( i = 0; i < exprdata->nmonomials; ++i )
12426  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
12427  break;
12428  if( i == exprdata->nmonomials )
12429  {
12430  /* yeah, parentcands[p] is same polynomial expression as expr */
12431  *parent = parentcands[p];
12432  break;
12433  }
12434  }
12435 
12436  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12437  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12438 
12439  break;
12440  }
12441 
12442  case SCIP_EXPR_USER:
12443  {
12444  /* @todo need comparison function on user data to decide whether a parent candidate fits */
12445  break;
12446  }
12447 
12448  case SCIP_EXPR_VARIDX:
12449  case SCIP_EXPR_PARAM:
12450  case SCIP_EXPR_CONST:
12451  case SCIP_EXPR_LAST:
12452  SCIPerrorMessage("expression operand %d unexpected here\n", op);
12453  return SCIP_ERROR;
12454  }
12455 
12456  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
12457 
12458  return SCIP_OKAY;
12459 }
12460 
12461 /** adds an expression into an expression graph
12462  *
12463  * Enables corresponding nodes.
12464  */
12465 static
12467  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12468  SCIP_EXPR* expr, /**< expression to add */
12469  void** vars, /**< variables corresponding to VARIDX expressions */
12470  SCIP_Real* params, /**< parameter values */
12471  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
12472  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12473  )
12474 {
12475  SCIP_EXPRGRAPHNODE** childnodes;
12476  SCIP_Bool childisnew;
12477  SCIP_Bool nochildisnew;
12478  SCIP_EXPROPDATA opdata;
12479  int i;
12480 
12481  assert(exprgraph != NULL);
12482  assert(expr != NULL);
12483  assert(exprnode != NULL);
12484  assert(exprnodeisnew != NULL);
12485 
12486  if( expr->op == SCIP_EXPR_VARIDX )
12487  {
12488  /* find node corresponding to variable and add if not existing yet */
12489  assert(expr->nchildren == 0);
12490 
12491  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12492  assert(*exprnode != NULL);
12493  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12494  assert((*exprnode)->data.intval >= 0);
12495  assert((*exprnode)->data.intval < exprgraph->nvars);
12496  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12497 
12498  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12499 
12500  return SCIP_OKAY;
12501  }
12502 
12503  if( expr->op == SCIP_EXPR_CONST )
12504  {
12505  /* find node corresponding to constant and add if not existing yet */
12506  assert(expr->nchildren == 0);
12507 
12508  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12509  assert(*exprnode != NULL);
12510  assert((*exprnode)->op == SCIP_EXPR_CONST);
12511  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
12512 
12513  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12514 
12515  return SCIP_OKAY;
12516  }
12517 
12518  if( expr->op == SCIP_EXPR_PARAM )
12519  {
12520  /* find node corresponding to constant corresponding to parameter and add if not existing yet */
12521  assert(expr->nchildren == 0);
12522  assert(params != NULL);
12523 
12524  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, params[expr->data.intval], exprnode) );
12525  assert(*exprnode != NULL);
12526  assert((*exprnode)->op == SCIP_EXPR_CONST);
12527  assert((*exprnode)->data.dbl == params[expr->data.intval]); /*lint !e777*/
12528 
12529  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12530 
12531  return SCIP_OKAY;
12532  }
12533 
12534  /* expression should be variable or constant or have children */
12535  assert(expr->nchildren > 0);
12536 
12537  /* add children expressions into expression graph
12538  * check if we can find a common parent
12539  */
12540  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12541  nochildisnew = TRUE;
12542  for( i = 0; i < expr->nchildren; ++i )
12543  {
12544  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, params, &childnodes[i], &childisnew) ); /*lint !e644*/
12545  assert(childnodes[i] != NULL);
12546  nochildisnew &= !childisnew; /*lint !e514*/
12547  }
12548 
12549  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12550  if( nochildisnew )
12551  {
12552  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12553 
12554  if( *exprnode != NULL )
12555  {
12556  /* node already existing, make sure it is enabled */
12557  (*exprnode)->enabled = TRUE;
12558  *exprnodeisnew = FALSE;
12559 
12560  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12561  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12562  * SCIPdebugPrintf("\n");
12563  */
12564 
12565  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12566  return SCIP_OKAY;
12567  }
12568  }
12569 
12570  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12571 
12572  /* copy expression data */
12573  if( exprOpTable[expr->op].copydata != NULL )
12574  {
12575  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12576  }
12577  else
12578  {
12579  opdata = expr->data;
12580  }
12581 
12582  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12583  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12584  *exprnodeisnew = TRUE;
12585 
12586  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12587 
12588  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12589  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12590  * SCIPdebugPrintf("\n");
12591  */
12592 
12593  return SCIP_OKAY;
12594 }
12595 
12596 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12597 static
12599  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12600  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12601  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12602  )
12603 {
12604  SCIP_EXPRGRAPHNODE* node;
12605  int i;
12606  int p;
12607 
12608  assert(exprgraph != NULL);
12609  assert(clearreverseprop != NULL);
12610  assert(boundchanged != NULL);
12611 
12612  *boundchanged = FALSE;
12613  for( i = 0; i < exprgraph->nvars; ++i )
12614  {
12615  node = exprgraph->varnodes[i];
12616 
12617  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12618  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12619  {
12621  continue;
12622  }
12623 
12624  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12625  {
12626  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12627  SCIP_Real tmp;
12628 
12629  tmp = exprgraph->varbounds[i].inf;
12630  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12631  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12632  }
12633 
12634  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12635  +exprgraph->varbounds[i].sup > node->bounds.sup )
12636  {
12637  for( p = 0; p < node->nparents; ++p )
12639 
12640  node->bounds = exprgraph->varbounds[i];
12641  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12642 
12643  *boundchanged = TRUE;
12644 
12645  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12646  *clearreverseprop = TRUE;
12647  }
12648  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12649  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12650  {
12651  for( p = 0; p < node->nparents; ++p )
12653 
12654  node->bounds = exprgraph->varbounds[i];
12655  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12656 
12657  *boundchanged = TRUE;
12658  }
12659  else
12660  {
12661  node->bounds = exprgraph->varbounds[i];
12662  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12663  }
12664 
12666  }
12667 }
12668 
12669 /**@} */
12670 
12671 /**@name Expression graph node methods */
12672 /**@{ */
12673 
12674 /* In debug mode, the following methods are implemented as function calls to ensure
12675  * type validity.
12676  * In optimized mode, the methods are implemented as defines to improve performance.
12677  * However, we want to have them in the library anyways, so we have to undef the defines.
12678  */
12679 
12680 #undef SCIPexprgraphCaptureNode
12681 #undef SCIPexprgraphIsNodeEnabled
12682 #undef SCIPexprgraphGetNodeNChildren
12683 #undef SCIPexprgraphGetNodeChildren
12684 #undef SCIPexprgraphGetNodeNParents
12685 #undef SCIPexprgraphGetNodeParents
12686 #undef SCIPexprgraphGetNodeDepth
12687 #undef SCIPexprgraphGetNodePosition
12688 #undef SCIPexprgraphGetNodeOperator
12689 #undef SCIPexprgraphGetNodeOperatorIndex
12690 #undef SCIPexprgraphGetNodeOperatorReal
12691 #undef SCIPexprgraphGetNodeVar
12692 #undef SCIPexprgraphGetNodeRealPowerExponent
12693 #undef SCIPexprgraphGetNodeIntPowerExponent
12694 #undef SCIPexprgraphGetNodeSignPowerExponent
12695 #undef SCIPexprgraphGetNodeLinearCoefs
12696 #undef SCIPexprgraphGetNodeLinearConstant
12697 #undef SCIPexprgraphGetNodeQuadraticConstant
12698 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12699 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12700 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12701 #undef SCIPexprgraphGetNodePolynomialMonomials
12702 #undef SCIPexprgraphGetNodePolynomialNMonomials
12703 #undef SCIPexprgraphGetNodePolynomialConstant
12704 #undef SCIPexprgraphGetNodeUserData
12705 #undef SCIPexprgraphHasNodeUserEstimator
12706 #undef SCIPexprgraphGetNodeBounds
12707 #undef SCIPexprgraphGetNodeVal
12708 #undef SCIPexprgraphGetNodeCurvature
12709 
12710 /** captures node, i.e., increases number of uses */
12712  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12713  )
12714 {
12715  assert(node->nuses >= 0);
12716 
12717  SCIPdebugMessage("capture node %p\n", (void*)node);
12718 
12719  ++node->nuses;
12720 }
12721 
12722 /** returns whether a node is currently enabled */
12724  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12725  )
12726 {
12727  assert(node != NULL);
12728 
12729  return node->enabled;
12730 }
12731 
12732 /** gets number of children of a node in an expression graph */
12734  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12735  )
12736 {
12737  assert(node != NULL);
12738 
12739  return node->nchildren;
12740 }
12741 
12742 /** gets children of a node in an expression graph */
12744  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12745  )
12746 {
12747  assert(node != NULL);
12748 
12749  return node->children;
12750 }
12751 
12752 /** gets number of parents of a node in an expression graph */
12754  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12755  )
12756 {
12757  assert(node != NULL);
12758 
12759  return node->nparents;
12760 }
12761 
12762 /** gets parents of a node in an expression graph */
12764  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12765  )
12766 {
12767  assert(node != NULL);
12768 
12769  return node->parents;
12770 }
12771 
12772 /** gets depth of node in expression graph */
12774  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12775  )
12776 {
12777  assert(node != NULL);
12778 
12779  return node->depth;
12780 }
12781 
12782 /** gets position of node in expression graph at its depth level */
12784  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12785  )
12786 {
12787  assert(node != NULL);
12788 
12789  return node->pos;
12790 }
12791 
12792 /** gets operator of a node in an expression graph */
12794  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12795  )
12796 {
12797  assert(node != NULL);
12798 
12799  return node->op;
12800 }
12801 
12802 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
12804  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12805  )
12806 {
12807  assert(node != NULL);
12808  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
12809 
12810  return node->data.intval;
12811 }
12812 
12813 /** gives real belonging to a SCIP_EXPR_CONST operand */
12815  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12816  )
12817 {
12818  assert(node != NULL);
12819  assert(node->op == SCIP_EXPR_CONST);
12820 
12821  return node->data.dbl;
12822 }
12823 
12824 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
12826  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12827  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12828  )
12829 {
12830  assert(exprgraph != NULL);
12831  assert(node != NULL);
12832  assert(node->op == SCIP_EXPR_VARIDX);
12833  assert(node->data.intval >= 0);
12834  assert(node->data.intval < exprgraph->nvars);
12835 
12836  return exprgraph->vars[node->data.intval];
12837 }
12838 
12839 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
12841  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12842  )
12843 {
12844  assert(node != NULL);
12845  assert(node->op == SCIP_EXPR_REALPOWER);
12846 
12847  return node->data.dbl;
12848 }
12849 
12850 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
12852  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12853  )
12854 {
12855  assert(node != NULL);
12856  assert(node->op == SCIP_EXPR_INTPOWER);
12857 
12858  return node->data.intval;
12859 }
12860 
12861 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
12863  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12864  )
12865 {
12866  assert(node != NULL);
12867  assert(node->op == SCIP_EXPR_SIGNPOWER);
12868 
12869  return node->data.dbl;
12870 }
12871 
12872 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
12874  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12875  )
12876 {
12877  assert(node != NULL);
12878  assert(node->op == SCIP_EXPR_LINEAR);
12879 
12880  return (SCIP_Real*)node->data.data;
12881 }
12882 
12883 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
12885  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12886  )
12887 {
12888  assert(node != NULL);
12889  assert(node->op == SCIP_EXPR_LINEAR);
12890  assert(node->data.data != NULL);
12891 
12892  return ((SCIP_Real*)node->data.data)[node->nchildren];
12893 }
12894 
12895 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
12897  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12898  )
12899 {
12900  assert(node != NULL);
12901  assert(node->op == SCIP_EXPR_QUADRATIC);
12902  assert(node->data.data != NULL);
12903 
12904  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
12905 }
12906 
12907 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
12909  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12910  )
12911 {
12912  assert(node != NULL);
12913  assert(node->op == SCIP_EXPR_QUADRATIC);
12914  assert(node->data.data != NULL);
12915 
12916  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
12917 }
12918 
12919 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
12921  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12922  )
12923 {
12924  assert(node != NULL);
12925  assert(node->op == SCIP_EXPR_QUADRATIC);
12926  assert(node->data.data != NULL);
12927 
12928  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
12929 }
12930 
12931 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
12933  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12934  )
12935 {
12936  assert(node != NULL);
12937  assert(node->op == SCIP_EXPR_QUADRATIC);
12938  assert(node->data.data != NULL);
12939 
12940  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
12941 }
12942 
12943 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
12945  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12946  )
12947 {
12948  assert(node != NULL);
12949  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12950  assert(node->data.data != NULL);
12951 
12952  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
12953 }
12954 
12955 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
12957  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12958  )
12959 {
12960  assert(node != NULL);
12961  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12962  assert(node->data.data != NULL);
12963 
12964  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
12965 }
12966 
12967 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
12969  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12970  )
12971 {
12972  assert(node != NULL);
12973  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12974  assert(node->data.data != NULL);
12975 
12976  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
12977 }
12978 
12979 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
12980  *
12981  * Assumes that curvature of children and bounds of children and node itself are valid.
12982  */
12984  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
12985  int monomialidx, /**< index of monomial */
12986  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
12987  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
12988  )
12989 {
12990  SCIP_EXPRDATA_MONOMIAL* monomial;
12991  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
12992  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
12993  SCIP_INTERVAL* childbounds;
12994  SCIP_EXPRCURV* childcurv;
12995  SCIP_EXPRGRAPHNODE* child;
12996  int i;
12997 
12998  assert(node != NULL);
12999  assert(node->depth >= 0); /* node should be in graph */
13000  assert(node->pos >= 0); /* node should be in graph */
13001  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13002  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
13003  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13004  assert(node->data.data != NULL);
13005  assert(monomialidx >= 0);
13006  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
13007  assert(curv != NULL);
13008 
13009  if( SCIPintervalIsEmpty(infinity, node->bounds) )
13010  {
13011  *curv = SCIP_EXPRCURV_LINEAR;
13012  return SCIP_OKAY;
13013  }
13014 
13015  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
13016  assert(monomial != NULL);
13017 
13018  /* if many children, get large enough memory to store children bounds */
13019  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13020  {
13021  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13022  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, monomial->nfactors) );
13023  }
13024  else
13025  {
13026  childbounds = childboundsstatic;
13027  childcurv = childcurvstatic;
13028  }
13029 
13030  /* assemble bounds and curvature of children */
13031  for( i = 0; i < monomial->nfactors; ++i )
13032  {
13033  child = node->children[monomial->childidxs[i]];
13034  assert(child != NULL);
13035 
13036  /* child should have valid and non-empty bounds */
13037  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13038  assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13039  /* nodes at depth 0 are always linear */
13040  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13041 
13042  childbounds[i] = child->bounds; /*lint !e644*/
13043  childcurv[i] = child->curv; /*lint !e644*/
13044  }
13045 
13046  /* check curvature */
13047  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13048  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13049 
13050  /* free memory, if allocated before */
13051  if( childbounds != childboundsstatic )
13052  {
13053  BMSfreeMemoryArray(&childbounds);
13054  BMSfreeMemoryArray(&childcurv);
13055  }
13056 
13057  return SCIP_OKAY;
13058 }
13059 
13060 /** gives the user data belonging to a SCIP_EXPR_USER expression */
13062  SCIP_EXPRGRAPHNODE* node
13063  )
13064 {
13065  assert(node != NULL);
13066  assert(node->op == SCIP_EXPR_USER);
13067  assert(node->data.data != NULL);
13068 
13069  return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13070 }
13071 
13072 /** indicates whether a user expression has the estimator callback defined */
13074  SCIP_EXPRGRAPHNODE* node
13075  )
13076 {
13077  assert(node != NULL);
13078  assert(node->op == SCIP_EXPR_USER);
13079  assert(node->data.data != NULL);
13080 
13081  return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13082 }
13083 
13084 /** gets bounds of a node in an expression graph */
13086  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13087  )
13088 {
13089  assert(node != NULL);
13090 
13091  return node->bounds;
13092 }
13093 
13094 /** gets value of expression associated to node from last evaluation call */
13096  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13097  )
13098 {
13099  assert(node != NULL);
13100 
13101  return node->value;
13102 }
13103 
13104 /** gets curvature of expression associated to node from last curvature check call */
13106  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13107  )
13108 {
13109  assert(node != NULL);
13110 
13111  return node->curv;
13112 }
13113 
13114 /** creates an expression graph node */
13116  BMS_BLKMEM* blkmem, /**< block memory */
13117  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13118  SCIP_EXPROP op, /**< operator type of expression */
13119  ...
13120  )
13121 {
13122  va_list ap;
13123  SCIP_EXPROPDATA opdata;
13124 
13125  assert(blkmem != NULL);
13126  assert(node != NULL);
13127 
13128  *node = NULL;
13129 
13130  switch( op )
13131  {
13132  case SCIP_EXPR_VARIDX :
13133  case SCIP_EXPR_PARAM :
13134  case SCIP_EXPR_CONST :
13135  case SCIP_EXPR_LINEAR :
13136  case SCIP_EXPR_QUADRATIC :
13137  case SCIP_EXPR_POLYNOMIAL:
13138  case SCIP_EXPR_USER :
13139  {
13140  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
13141  SCIPABORT();
13142  return SCIP_ERROR; /*lint !e527*/
13143  }
13144 
13145  /* operands without data */
13146  case SCIP_EXPR_PLUS :
13147  case SCIP_EXPR_MINUS :
13148  case SCIP_EXPR_MUL :
13149  case SCIP_EXPR_DIV :
13150  case SCIP_EXPR_MIN :
13151  case SCIP_EXPR_MAX :
13152  case SCIP_EXPR_SQUARE :
13153  case SCIP_EXPR_SQRT :
13154  case SCIP_EXPR_EXP :
13155  case SCIP_EXPR_LOG :
13156  case SCIP_EXPR_SIN :
13157  case SCIP_EXPR_COS :
13158  case SCIP_EXPR_TAN :
13159  /* case SCIP_EXPR_ERF : */
13160  /* case SCIP_EXPR_ERFI: */
13161  case SCIP_EXPR_ABS :
13162  case SCIP_EXPR_SIGN :
13163  case SCIP_EXPR_SUM :
13164  case SCIP_EXPR_PRODUCT:
13165  opdata.data = NULL;
13166  break;
13167 
13168  case SCIP_EXPR_REALPOWER:
13169  case SCIP_EXPR_SIGNPOWER:
13170  {
13171  va_start(ap, op ); /*lint !e838*/
13172  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
13173  va_end( ap ); /*lint !e826*/
13174 
13175  break;
13176  }
13177 
13178  case SCIP_EXPR_INTPOWER:
13179  {
13180  va_start(ap, op ); /*lint !e838*/
13181  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
13182  va_end( ap ); /*lint !e826*/
13183 
13184  break;
13185  }
13186 
13187  case SCIP_EXPR_LAST:
13188  SCIPABORT();
13189  return SCIP_INVALIDDATA; /*lint !e527*/
13190  }
13191 
13192  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13193 
13194  return SCIP_OKAY;
13195 }
13196 
13197 /** creates an expression graph node for a linear expression */
13199  BMS_BLKMEM* blkmem, /**< block memory */
13200  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13201  int ncoefs, /**< number of coefficients */
13202  SCIP_Real* coefs, /**< coefficients of linear expression */
13203  SCIP_Real constant /**< constant of linear expression */
13204  )
13205 {
13206  SCIP_EXPROPDATA opdata;
13207  SCIP_Real* data;
13208 
13209  assert(blkmem != NULL);
13210  assert(node != NULL);
13211 
13212  /* we store the coefficients and the constant in a single array and make this our operand data */
13213  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13214  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
13215  data[ncoefs] = constant;
13216 
13217  opdata.data = data;
13218  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13219 
13220  return SCIP_OKAY;
13221 }
13222 
13223 /** creates an expression graph node for a quadratic expression */
13225  BMS_BLKMEM* blkmem, /**< block memory */
13226  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13227  int nchildren, /**< number of children */
13228  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
13229  int nquadelems, /**< number of quadratic elements */
13230  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
13231  SCIP_Real constant /**< constant */
13232  )
13233 {
13234  SCIP_EXPROPDATA opdata;
13236 
13237  assert(blkmem != NULL);
13238  assert(node != NULL);
13239  assert(quadelems != NULL || nquadelems == 0);
13240 
13241  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13242 
13243  opdata.data = data;
13244  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13245 
13246  return SCIP_OKAY;
13247 }
13248 
13249 /** creates an expression graph node for a polynomial expression */
13251  BMS_BLKMEM* blkmem, /**< block memory */
13252  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13253  int nmonomials, /**< number of monomials */
13254  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13255  SCIP_Real constant, /**< constant of polynomial */
13256  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13257  )
13258 {
13259  SCIP_EXPROPDATA opdata;
13261 
13262  assert(blkmem != NULL);
13263  assert(node != NULL);
13264  assert(monomials != NULL || nmonomials == 0);
13265 
13266  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13267 
13268  opdata.data = data;
13269  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13270 
13271  return SCIP_OKAY;
13272 }
13273 
13274 /** adds monomials to an expression graph node that is a polynomial expression */
13276  BMS_BLKMEM* blkmem, /**< block memory */
13277  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
13278  int nmonomials, /**< number of monomials */
13279  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13280  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13281  )
13282 {
13283  assert(blkmem != NULL);
13284  assert(node != NULL);
13286  assert(monomials != NULL || nmonomials == 0);
13287 
13288  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13289 
13290  return SCIP_OKAY;
13291 }
13292 
13293 /** creates an expression graph node for a user expression */
13295  BMS_BLKMEM* blkmem, /**< block memory */
13296  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13297  SCIP_USEREXPRDATA* data, /**< user data for expression, node assumes ownership */
13298  SCIP_EXPRINTCAPABILITY evalcapability, /**< evaluation capability */
13299  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
13300  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function */
13301  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
13302  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function */
13303  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13304  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13305  SCIP_DECL_USEREXPRFREEDATA ((*freedata)) /**< expression data free function, or NULL if nothing to free */
13306  )
13307 {
13308  SCIP_EXPROPDATA opdata;
13309  SCIP_EXPRDATA_USER* exprdata;
13310 
13311  assert(blkmem != NULL);
13312  assert(node != NULL);
13313  assert(eval != NULL);
13314  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
13315  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13316  assert(copydata != NULL || data == NULL);
13317  assert(freedata != NULL || data == NULL);
13318 
13319  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13320 
13321  exprdata->userdata = data;
13322  exprdata->evalcapability = evalcapability;
13323  exprdata->eval = eval;
13324  exprdata->estimate = estimate;
13325  exprdata->inteval = inteval;
13326  exprdata->curv = curv;
13327  exprdata->prop = prop;
13328  exprdata->copydata = copydata;
13329  exprdata->freedata = freedata;
13330 
13331  opdata.data = (void*) exprdata;
13332 
13333  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13334 
13335  return SCIP_OKAY;
13336 }
13337 
13338 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13339  *
13340  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13341  * If the node is a linear expression, it may be freed.
13342  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13343  * It is assumed that the user had captured the node.
13344  * It is assumed that the expression graph has been simplified before.
13345  */
13347  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13348  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
13349  int linvarssize, /**< length of linvars and lincoefs arrays */
13350  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
13351  void** linvars, /**< buffer to store variables of linear part */
13352  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
13353  SCIP_Real* constant /**< buffer to store constant part */
13354  )
13355 {
13356  int orignvars;
13357  int* varsusage;
13358  SCIP_EXPRGRAPHNODE* orignode;
13359  SCIP_Bool havechange;
13360  int i;
13361 
13362  assert(exprgraph != NULL);
13363  assert(node != NULL);
13364  assert(*node != NULL);
13365  assert((*node)->nuses > 0);
13366  assert(nlinvars != NULL);
13367  assert(linvars != NULL || linvarssize == 0);
13368  assert(lincoefs != NULL || linvarssize == 0);
13369  assert(constant != NULL);
13370 
13371  *constant = 0.0;
13372  *nlinvars = 0;
13373 
13374  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13375 
13376  /* do some obvious and easy cases */
13377  switch( (*node)->op )
13378  {
13379  case SCIP_EXPR_VARIDX:
13380  {
13381  if( linvarssize >= 1 )
13382  {
13383  *nlinvars = 1;
13384  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
13385  lincoefs[0] = 1.0; /*lint !e613*/
13386 
13387  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13388  }
13389  return SCIP_OKAY;
13390  }
13391 
13392  case SCIP_EXPR_CONST:
13393  {
13394  *constant = (*node)->data.dbl;
13395  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13396 
13397  return SCIP_OKAY;
13398  }
13399 
13400  case SCIP_EXPR_REALPOWER:
13401  case SCIP_EXPR_SIGNPOWER:
13402  {
13403  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13404  {
13405  *nlinvars = 1;
13406  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13407  lincoefs[0] = 1.0; /*lint !e613*/
13408 
13409  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13410  }
13411  return SCIP_OKAY;
13412  }
13413 
13414  case SCIP_EXPR_INTPOWER:
13415  {
13416  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13417  {
13418  *nlinvars = 1;
13419  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13420  lincoefs[0] = 1.0; /*lint !e613*/
13421 
13422  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13423  }
13424  return SCIP_OKAY;
13425  }
13426 
13427  case SCIP_EXPR_PLUS:
13428  {
13429  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13430  {
13431  *constant = (*node)->children[0]->data.dbl;
13432  *nlinvars = 1;
13433  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13434  lincoefs[0] = 1.0; /*lint !e613*/
13435 
13436  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13437 
13438  return SCIP_OKAY;
13439  }
13440  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13441  {
13442  *constant = (*node)->children[1]->data.dbl;
13443  *nlinvars = 1;
13444  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13445  lincoefs[0] = 1.0; /*lint !e613*/
13446 
13447  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13448 
13449  return SCIP_OKAY;
13450  }
13451  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13452  {
13453  *nlinvars = 2;
13454  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13455  lincoefs[0] = 1.0; /*lint !e613*/
13456  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13457  lincoefs[1] = 1.0; /*lint !e613*/
13458 
13459  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13460 
13461  return SCIP_OKAY;
13462  }
13463  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13464  {
13465  /* handle this one later */
13466  break;
13467  }
13468  return SCIP_OKAY;
13469  }
13470 
13471  case SCIP_EXPR_MINUS:
13472  {
13473  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13474  {
13475  *constant = (*node)->children[0]->data.dbl;
13476  *nlinvars = 1;
13477  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13478  lincoefs[0] = -1.0; /*lint !e613*/
13479 
13480  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13481 
13482  return SCIP_OKAY;
13483  }
13484  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13485  {
13486  *constant = -(*node)->children[1]->data.dbl;
13487  *nlinvars = 1;
13488  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13489  lincoefs[0] = 1.0; /*lint !e613*/
13490 
13491  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13492 
13493  return SCIP_OKAY;
13494  }
13495  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13496  {
13497  *nlinvars = 2;
13498  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13499  lincoefs[0] = 1.0; /*lint !e613*/
13500  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13501  lincoefs[1] = -1.0; /*lint !e613*/
13502 
13503  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13504 
13505  return SCIP_OKAY;
13506  }
13507  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13508  {
13509  /* handle this one later */
13510  break;
13511  }
13512  return SCIP_OKAY;
13513  }
13514 
13515  case SCIP_EXPR_MUL:
13516  {
13517  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13518  {
13519  *nlinvars = 1;
13520  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13521  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
13522 
13523  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13524  }
13525  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13526  {
13527  *nlinvars = 1;
13528  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13529  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
13530 
13531  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13532  }
13533  return SCIP_OKAY;
13534  }
13535 
13536  case SCIP_EXPR_DIV:
13537  {
13538  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13539  return SCIP_OKAY;
13540 
13541  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13542  {
13543  *nlinvars = 1;
13544  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13545  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
13546 
13547  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13548  }
13549  return SCIP_OKAY;
13550  }
13551 
13552  case SCIP_EXPR_SQUARE:
13553  case SCIP_EXPR_SQRT:
13554  case SCIP_EXPR_EXP:
13555  case SCIP_EXPR_LOG:
13556  case SCIP_EXPR_SIN:
13557  case SCIP_EXPR_COS:
13558  case SCIP_EXPR_TAN:
13559  /* case SCIP_EXPR_ERF: */
13560  /* case SCIP_EXPR_ERFI: */
13561  case SCIP_EXPR_ABS:
13562  case SCIP_EXPR_SIGN:
13563  case SCIP_EXPR_MIN:
13564  case SCIP_EXPR_MAX:
13565  return SCIP_OKAY;
13566 
13567  case SCIP_EXPR_PRODUCT:
13568  case SCIP_EXPR_USER:
13569  return SCIP_OKAY;
13570 
13571  case SCIP_EXPR_SUM:
13572  case SCIP_EXPR_LINEAR:
13573  case SCIP_EXPR_QUADRATIC:
13574  case SCIP_EXPR_POLYNOMIAL:
13575  default:
13576  {
13577  /* check if there is a child that is a variable */
13578  for( i = 0; i < (*node)->nchildren; ++i )
13579  {
13580  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13581  break;
13582  }
13583 
13584  if( i == (*node)->nchildren )
13585  return SCIP_OKAY;
13586 
13587  break;
13588  }
13589  } /*lint !e788*/
13590 
13591  /* count how often variables are used in this expression */
13592  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13593  orignvars = exprgraph->nvars;
13594  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13595  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
13596 
13597  exprgraphNodeGetVarsUsage(*node, varsusage);
13598 
13599  /* duplicate node if it has parents or more than one user */
13600  orignode = NULL;
13601  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13602  {
13603  SCIP_EXPROPDATA data;
13604 
13605  orignode = *node;
13606 
13607  if( exprOpTable[orignode->op].copydata != NULL )
13608  {
13609  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13610  }
13611  else
13612  data = orignode->data;
13613 
13614  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13615  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13616  SCIPexprgraphCaptureNode(*node);
13617  }
13618 
13619  havechange = FALSE;
13620  /* split up constant and linear part */
13621  switch( (*node)->op )
13622  {
13623  case SCIP_EXPR_PLUS:
13624  case SCIP_EXPR_MINUS:
13625  {
13626  SCIP_EXPRGRAPHNODE* varchild;
13627  SCIP_EXPRGRAPHNODE* otherchild;
13628  int varidx;
13629 
13630  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13631  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13632  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13633  assert(linvarssize >= 1);
13634 
13635  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13636  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13637  varidx = varchild->data.intval;
13638  /* if variable is used in other child (which should be nonlinear), we don't take it */
13639  if( varsusage[varidx] > 1 )
13640  break;
13641 
13642  /* add to linear variables */
13643  *nlinvars = 1;
13644  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13645  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13646  lincoefs[0] = -1.0; /*lint !e613*/
13647  else
13648  lincoefs[0] = 1.0; /*lint !e613*/
13649 
13650  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13651  {
13652  /* replace *node by otherchild */
13653  SCIPexprgraphCaptureNode(otherchild);
13654  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13655  *node = otherchild;
13656  }
13657  else
13658  {
13659  SCIP_Real* lindata;
13660 
13661  /* turn *node into linear expression -1.0 * otherchild */
13662 
13663  /* reduce to one child */
13664  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13665  (*node)->children[0] = otherchild;
13666  (*node)->nchildren = 1;
13667  (*node)->op = SCIP_EXPR_LINEAR;
13668 
13669  /* setup linear data -1.0 * child0 + 0.0 */
13670  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13671  lindata[0] = -1.0;
13672  lindata[1] = 0.0;
13673  (*node)->data.data = (void*)lindata;
13674 
13675  /* remove *node as parent of varchild */
13676  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13677  }
13678 
13679  havechange = TRUE;
13680 
13681  break;
13682  }
13683 
13684  case SCIP_EXPR_SUM:
13685  {
13686  int nchildren;
13687 
13688  i = 0;
13689  nchildren = (*node)->nchildren;
13690  while( i < nchildren )
13691  {
13692  /* sort out constants */
13693  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13694  {
13695  *constant += (*node)->children[i]->data.dbl;
13696  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13697 
13698  if( i < nchildren-1 )
13699  {
13700  (*node)->children[i] = (*node)->children[nchildren-1];
13701  (*node)->children[nchildren-1] = NULL;
13702  }
13703  --nchildren;
13704 
13705  continue;
13706  }
13707 
13708  /* keep every child that is not a constant or variable */
13709  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13710  {
13711  ++i;
13712  continue;
13713  }
13714 
13715  /* skip variables that are used in other parts of the expression */
13716  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13717  {
13718  ++i;
13719  continue;
13720  }
13721 
13722  /* move variable into linear part, if still space */
13723  if( *nlinvars < linvarssize )
13724  {
13725  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13726  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13727  ++*nlinvars;
13728 
13729  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13730  if( i < nchildren-1 )
13731  {
13732  (*node)->children[i] = (*node)->children[nchildren-1];
13733  (*node)->children[nchildren-1] = NULL;
13734  }
13735  --nchildren;
13736 
13737  continue;
13738  }
13739  }
13740  assert(i == nchildren);
13741 
13742  if( nchildren == 0 )
13743  {
13744  /* all children were removed */
13745  havechange = TRUE;
13746  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13747  (*node)->nchildren = 0;
13748  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13749  break;
13750  }
13751 
13752  if( nchildren < (*node)->nchildren )
13753  {
13754  /* some children were removed */
13755  havechange = TRUE;
13756  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13757  (*node)->nchildren = nchildren;
13758  }
13759 
13760  if( havechange && (*node)->nchildren == 1 )
13761  {
13762  /* replace node by its child */
13763  SCIP_EXPRGRAPHNODE* child;
13764 
13765  child = (*node)->children[0];
13766  SCIPexprgraphCaptureNode(child);
13767  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13768  *node = child;
13769 
13770  break;
13771  }
13772 
13773  break;
13774  }
13775 
13776  case SCIP_EXPR_LINEAR:
13777  {
13778  int nchildren;
13779  SCIP_Real* coefs;
13780 
13781  coefs = (SCIP_Real*)(*node)->data.data;
13782  assert(coefs != NULL);
13783 
13784  /* remove constant, if nonzero */
13785  if( coefs[(*node)->nchildren] != 0.0 )
13786  {
13787  *constant = coefs[(*node)->nchildren];
13788  coefs[(*node)->nchildren] = 0.0;
13789  havechange = TRUE;
13790  }
13791 
13792  i = 0;
13793  nchildren = (*node)->nchildren;
13794  while( i < nchildren )
13795  {
13796  /* sort out constants */
13797  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13798  {
13799  *constant += coefs[i] * (*node)->children[i]->data.dbl;
13800  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13801 
13802  if( i < nchildren-1 )
13803  {
13804  (*node)->children[i] = (*node)->children[nchildren-1];
13805  (*node)->children[nchildren-1] = NULL;
13806  coefs[i] = coefs[nchildren-1];
13807  coefs[nchildren-1] = 0.0;
13808  }
13809  --nchildren;
13810 
13811  continue;
13812  }
13813 
13814  /* keep everything that is not a constant or variable */
13815  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13816  {
13817  ++i;
13818  continue;
13819  }
13820 
13821  /* skip variables that are used in other parts of the expression */
13822  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13823  {
13824  ++i;
13825  continue;
13826  }
13827 
13828  /* move variable into linear part, if still space */
13829  if( *nlinvars < linvarssize )
13830  {
13831  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13832  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
13833  ++*nlinvars;
13834 
13835  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13836  if( i < nchildren-1 )
13837  {
13838  (*node)->children[i] = (*node)->children[nchildren-1];
13839  (*node)->children[nchildren-1] = NULL;
13840  coefs[i] = coefs[nchildren-1];
13841  coefs[nchildren-1] = 0.0;
13842  }
13843  --nchildren;
13844 
13845  continue;
13846  }
13847  }
13848  assert(i == nchildren);
13849 
13850  if( nchildren == 0 )
13851  {
13852  /* all children were removed */
13853  havechange = TRUE;
13854  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13855  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
13856  (*node)->data.data = NULL;
13857  (*node)->nchildren = 0;
13858  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
13859  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13860  break;
13861  }
13862 
13863  if( nchildren < (*node)->nchildren )
13864  {
13865  /* some children were removed */
13866  havechange = TRUE;
13867  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13868  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
13869  coefs[nchildren] = 0.0;
13870  (*node)->data.data = (void*)coefs;
13871  (*node)->nchildren = nchildren;
13872  }
13873 
13874  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
13875  {
13876  /* replace node by its child */
13877  SCIP_EXPRGRAPHNODE* child;
13878 
13879  child = (*node)->children[0];
13880  SCIPexprgraphCaptureNode(child);
13881  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13882  *node = child;
13883 
13884  break;
13885  }
13886 
13887  break;
13888  }
13889 
13890  case SCIP_EXPR_QUADRATIC:
13891  {
13892  SCIP_EXPRDATA_QUADRATIC* quaddata;
13893  SCIP_Bool* childused;
13894  int* childmap;
13895  int nchildren;
13896 
13897  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
13898  assert(quaddata != NULL);
13899 
13900  /* remove constant, if nonzero */
13901  if( quaddata->constant != 0.0 )
13902  {
13903  *constant = quaddata->constant;
13904  quaddata->constant = 0.0;
13905  havechange = TRUE;
13906  }
13907 
13908  /* if there is no linear part or no space left for linear variables, then stop */
13909  if( quaddata->lincoefs != NULL || linvarssize == 0 )
13910  break;
13911 
13912  /* check which childs are used in quadratic terms */
13913  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
13914  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
13915 
13916  for( i = 0; i < quaddata->nquadelems; ++i )
13917  {
13918  childused[quaddata->quadelems[i].idx1] = TRUE;
13919  childused[quaddata->quadelems[i].idx2] = TRUE;
13920  }
13921 
13922  /* alloc space for mapping of children indices */
13923  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
13924 
13925  nchildren = (*node)->nchildren;
13926  for( i = 0; i < nchildren; ++i )
13927  {
13928  childmap[i] = i; /*lint !e644*/
13929  if( *nlinvars >= linvarssize )
13930  continue;
13931  /* skip child if not variable or also used in quadratic part or other parts of expression */
13932  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13933  continue;
13934  if( childused[i] )
13935  continue;
13936  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13937  continue;
13938 
13939  /* put variable into linear part */
13940  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13941  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
13942  quaddata->lincoefs[i] = 0.0;
13943  ++*nlinvars;
13944 
13945  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13946 
13947  /* move last child to position i */
13948  if( i < nchildren-1 )
13949  {
13950  (*node)->children[i] = (*node)->children[nchildren-1];
13951  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
13952  childused[i] = childused[nchildren-1];
13953  childmap[nchildren-1] = i;
13954  }
13955  --nchildren;
13956  childmap[i] = -1;
13957 
13958  havechange = TRUE;
13959  --i; /* look at i again */
13960  }
13961 
13962  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
13963 
13964  if( nchildren < (*node)->nchildren )
13965  {
13966  /* apply childmap to quadratic term */
13967  for( i = 0; i < quaddata->nquadelems; ++i )
13968  {
13969  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
13970  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
13971  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
13972  {
13973  int tmp;
13974  tmp = quaddata->quadelems[i].idx1;
13975  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
13976  quaddata->quadelems[i].idx2 = tmp;
13977  }
13978  }
13979  quaddata->sorted = FALSE;
13980  }
13981  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
13982 
13983  if( nchildren == 0 )
13984  {
13985  /* all children were removed (so it was actually a linear expression) */
13986  havechange = TRUE;
13987  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13988  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
13989  (*node)->data.data = NULL;
13990  (*node)->nchildren = 0;
13991  (*node)->op = SCIP_EXPR_SUM;
13992  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13993  break;
13994  }
13995 
13996  if( nchildren < (*node)->nchildren )
13997  {
13998  /* reduce number of children */
13999  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14000  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
14001  (*node)->nchildren = nchildren;
14002  }
14003 
14004  break;
14005  }
14006 
14007  case SCIP_EXPR_POLYNOMIAL:
14008  {
14009  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
14010  SCIP_EXPRDATA_MONOMIAL* monomial;
14011  SCIP_Bool* childused;
14012  int childidx;
14013  int j;
14014 
14015  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
14016  assert(polynomialdata != NULL);
14017 
14018  /* make sure linear monomials are merged */
14019  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14020 
14021  /* remove constant, if nonzero */
14022  if( polynomialdata->constant != 0.0 )
14023  {
14024  *constant = polynomialdata->constant;
14025  polynomialdata->constant = 0.0;
14026  havechange = TRUE;
14027  }
14028 
14029  /* if there is no space for linear variables, then stop */
14030  if( linvarssize == 0 )
14031  break;
14032 
14033  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14034  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14035  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14036  for( i = 0; i < polynomialdata->nmonomials; ++i )
14037  {
14038  monomial = polynomialdata->monomials[i];
14039  assert(monomial != NULL);
14040  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14041  continue;
14042  for( j = 0; j < monomial->nfactors; ++j )
14043  {
14044  assert(monomial->childidxs[j] >= 0);
14045  assert(monomial->childidxs[j] < (*node)->nchildren);
14046  childused[monomial->childidxs[j]] = TRUE;
14047  }
14048  }
14049 
14050  /* move linear monomials out of polynomial */
14051  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14052  {
14053  monomial = polynomialdata->monomials[i];
14054  assert(monomial != NULL);
14055 
14056  /* sort out constants */
14057  if( monomial->nfactors == 0 )
14058  {
14059  if( monomial->coef != 0.0 )
14060  {
14061  *constant += monomial->coef;
14062  havechange = TRUE;
14063  }
14064  continue;
14065  }
14066 
14067  if( monomial->nfactors != 1 )
14068  continue;
14069  if( monomial->exponents[0] != 1.0 )
14070  continue;
14071  childidx = monomial->childidxs[0];
14072  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14073  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14074  continue;
14075  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14076  continue;
14077 
14078  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14079 
14080  /* put variable into linear part */
14081  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
14082  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
14083  ++*nlinvars;
14084 
14085  monomial->coef = 0.0;
14086  monomial->nfactors = 0;
14087  polynomialdata->sorted = FALSE;
14088 
14089  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14090  (*node)->children[childidx] = NULL;
14091 
14092  havechange = TRUE;
14093  }
14094 
14095  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14096 
14097  if( *nlinvars > 0 )
14098  {
14099  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14100  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14102  }
14103 
14104  if( (*node)->nchildren == 0 )
14105  {
14106  assert(polynomialdata->nmonomials == 0);
14107  assert(polynomialdata->constant == 0.0);
14108  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14109  havechange = TRUE;
14110  break;
14111  }
14112 
14113  break;
14114  }
14115 
14116  default: ;
14117  } /*lint !e788*/
14118 
14119  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14120 
14121  if( orignode != NULL )
14122  {
14123  /* if node was duplicated, we need to forget about original or duplicate */
14124  if( !havechange )
14125  {
14126  /* if nothing has changed, then forget about duplicate */
14127  assert(*constant == 0.0);
14128  assert(*nlinvars == 0);
14129  assert(*node != NULL);
14130  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14131  *node = orignode;
14132  }
14133  else
14134  {
14135  /* if something changed, then release original node */
14136  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14137  }
14138  }
14139  else if( havechange && *node != NULL )
14140  {
14141  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14142  (*node)->value = SCIP_INVALID;
14143  (*node)->simplified = FALSE;
14144  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14145  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14146  exprgraph->needvarboundprop = TRUE;
14147  }
14148 
14149  return SCIP_OKAY;
14150 }
14151 
14152 /** moves parents from a one node to another node
14153  *
14154  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14155  * srcnode may be freed, if not captured.
14156  * It is assumed that targetnode represents the same expression as srcnode.
14157  */
14159  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14160  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
14161  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
14162  )
14163 {
14164  assert(exprgraph != NULL);
14165  assert(srcnode != NULL);
14166  assert(*srcnode != NULL);
14167  assert(targetnode != NULL);
14168 
14169  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14170  {
14171  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14172  {
14173  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14174  }
14175  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14176  }
14177  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14178 
14179  return SCIP_OKAY;
14180 }
14181 
14182 /** releases node, i.e., decreases number of uses
14183  *
14184  * node is freed if no parents and no other uses.
14185  * Children are recursively released if they have no other parents.
14186  * Nodes that are removed are also freed.
14187  * If node correspond to a variable, then the variable is removed from the expression graph;
14188  * similarly for constants.
14189  */
14191  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14192  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
14193  )
14194 {
14195  int i;
14196 
14197  assert(exprgraph != NULL);
14198  assert(node != NULL);
14199  assert(*node != NULL);
14200  assert((*node)->depth >= 0); /* node should be in graph */
14201  assert((*node)->pos >= 0); /* node should be in graph */
14202  assert((*node)->depth < exprgraph->depth);
14203  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14204  assert((*node)->nuses >= 1);
14205  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14206 
14207  SCIPdebugMessage("release node %p\n", (void*)*node);
14208 
14209  --(*node)->nuses;
14210 
14211  /* do nothing if node still has parents or is still in use */
14212  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14213  {
14214  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);
14215  *node = NULL;
14216  return SCIP_OKAY;
14217  }
14218 
14219  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14220 
14221  /* notify children about removal of its parent
14222  * they are also freed, if possible */
14223  for( i = 0; i < (*node)->nchildren; ++i )
14224  {
14225  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14226  (*node)->children[i] = NULL;
14227  }
14228 
14229  if( (*node)->op == SCIP_EXPR_VARIDX )
14230  {
14231  assert((*node)->depth == 0);
14232  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14233  }
14234  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14235  {
14236  int constidx;
14237 
14238  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14239  assert(constidx >= 0);
14240  assert(constidx < exprgraph->nconsts);
14241  assert(exprgraph->constnodes[constidx] == *node);
14242 
14243  /* move last constant to position constidx */
14244  if( constidx < exprgraph->nconsts-1 )
14245  {
14246  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14247  exprgraph->constssorted = (exprgraph->nconsts <= 2);
14248  }
14249  --exprgraph->nconsts;
14250  }
14251  else
14252  {
14253  /* only variables and constants are allowed at depth 0 */
14254  assert((*node)->depth > 0);
14255  }
14256 
14257  /* remove node from nodes array in expression graph */
14258  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14259  {
14260  /* move last node at depth of *node to position of *node */
14261  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14262  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14263  }
14264  --exprgraph->nnodes[(*node)->depth];
14265 
14266  /* node is now not in graph anymore */
14267  (*node)->depth = -1;
14268  (*node)->pos = -1;
14269 
14270  /* free node */
14271  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14272 
14273  *node = NULL;
14274 
14275  return SCIP_OKAY;
14276 }
14277 
14278 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14279 /** frees a node of an expression graph */
14281  BMS_BLKMEM* blkmem, /**< block memory */
14282  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
14283  )
14284 {
14285  assert(blkmem != NULL);
14286  assert( node != NULL);
14287  assert(*node != NULL);
14288  assert((*node)->depth == -1); /* node should not be in graph anymore */
14289  assert((*node)->pos == -1); /* node should not be in graph anymore */
14290  assert((*node)->nuses == 0); /* node should not be in use */
14291 
14292  /* free operator data, if needed */
14293  if( exprOpTable[(*node)->op].freedata != NULL )
14294  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14295 
14296  /* free arrays of children and parent nodes */
14297  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14298  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
14299 
14300  /* free node struct */
14301  BMSfreeBlockMemory(blkmem, node);
14302 }
14303 
14304 /** enables a node and recursively all its children in an expression graph */
14306  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14307  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14308  )
14309 {
14310  int i;
14311 
14312  assert(exprgraph != NULL);
14313  assert(node != NULL);
14314  assert(node->depth >= 0);
14315  assert(node->pos >= 0);
14316 
14317  if( node->enabled )
14318  return;
14319 
14320  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14321 
14322  node->enabled = TRUE;
14323  for( i = 0; i < node->nchildren; ++i )
14324  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14325 
14326  /* make sure bounds are updated in next bound propagation round */
14328  exprgraph->needvarboundprop = TRUE;
14329 }
14330 
14331 /** disables a node and recursively all children which have no enabled parents in an expression graph */
14333  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14334  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14335  )
14336 {
14337  int i;
14338 
14339  assert(exprgraph != NULL);
14340  assert(node != NULL);
14341  assert(node->depth >= 0);
14342  assert(node->pos >= 0);
14343 
14344  if( !node->enabled )
14345  return;
14346 
14347  /* if all parents of node are disabled, then also node can be disabled */
14348  node->enabled = FALSE;
14349  for( i = 0; i < node->nparents; ++i )
14350  if( node->parents[i]->enabled )
14351  {
14352  node->enabled = TRUE;
14353  return;
14354  }
14355 
14356  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14357 
14358  for( i = 0; i < node->nchildren; ++i )
14359  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14360 }
14361 
14362 /** returns whether the node has siblings in the expression graph */
14364  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14365  )
14366 {
14367  int p;
14368 
14369  assert(node != NULL);
14370 
14371  for( p = 0; p < node->nparents; ++p )
14372  if( node->parents[p]->nchildren > 1 )
14373  return TRUE;
14374 
14375  return FALSE;
14376 }
14377 
14378 /** returns whether all children of an expression graph node are variable nodes
14379  *
14380  * Returns TRUE for nodes without children.
14381  */
14383  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14384  )
14385 {
14386  int i;
14387 
14388  assert(node != NULL);
14389 
14390  for( i = 0; i < node->nchildren; ++i )
14391  if( node->children[i]->op != SCIP_EXPR_VARIDX )
14392  return FALSE;
14393 
14394  return TRUE;
14395 }
14396 
14397 /** returns whether the node has an ancestor which has a nonlinear expression operand */
14399  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14400  )
14401 {
14402  int p;
14403 
14404  for( p = 0; p < node->nparents; ++p )
14405  {
14406  assert(node->parents[p]->depth > node->depth);
14407  switch( node->parents[p]->op )
14408  {
14409  case SCIP_EXPR_PLUS:
14410  case SCIP_EXPR_MINUS:
14411  case SCIP_EXPR_SUM:
14412  case SCIP_EXPR_LINEAR:
14414  return TRUE;
14415  break;
14416 
14417 #ifndef NDEBUG
14418  case SCIP_EXPR_VARIDX:
14419  case SCIP_EXPR_CONST:
14420  case SCIP_EXPR_PARAM:
14421  assert(0); /* these expressions cannot have children */
14422  break;
14423 #endif
14424 
14425  default:
14426  /* parent has nonlinear expression operand */
14427  return TRUE;
14428  }/*lint !e788*/
14429  }
14430 
14431  return FALSE;
14432 }
14433 
14434 /** prints an expression graph node */
14436  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14437  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14438  FILE* file /**< file to print to, or NULL for stdout */
14439  )
14440 {
14441  assert(node != NULL);
14442 
14443  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14444 }
14445 
14446 /** tightens the bounds in a node of the graph
14447  *
14448  * Preparation for reverse propagation.
14449  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14450  */
14452  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14453  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
14454  SCIP_INTERVAL nodebounds, /**< new bounds for node */
14455  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) */
14456  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14457  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14458  )
14459 {
14460  assert(exprgraph != NULL);
14461  assert(node != NULL);
14462  assert(node->depth >= 0);
14463  assert(node->pos >= 0);
14464  assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14465  assert(cutoff != NULL);
14466 
14467  *cutoff = FALSE;
14468 
14469  /* if node is disabled, then ignore new bounds */
14470  if( !node->enabled )
14471  {
14472  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14473  return;
14474  }
14475 
14476  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14477  (void*)node, node->depth, node->pos,
14478  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14479 
14480  /* bounds in node should be valid */
14482 
14483  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14484  {
14485  *cutoff = TRUE;
14486  SCIPdebugPrintf(" -> cutoff\n");
14487  return;
14488  }
14489 
14490  /* if minstrength is negative, always mark that node has recently tightened bounds,
14491  * if bounds are considerably improved or tightening leads to an empty interval,
14492  * mark that node has recently tightened bounds
14493  * if bounds are only slightly improved, set the status to tightened by parent,
14494  * so next propagateVarBound round will reset the bounds
14495  */
14496  if( minstrength < 0.0 )
14498  else if(
14499  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14500  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14502  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14504 
14505  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14506  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14507 }
14508 
14509 /** ensures that bounds and curvature information in a node is uptodate
14510  *
14511  * Assumes that bounds and curvature in children are uptodate.
14512  */
14514  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14515  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14516  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14517  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14518  )
14519 {
14520  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14521  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14522  SCIP_INTERVAL* childbounds;
14523  SCIP_EXPRCURV* childcurv;
14524  int i;
14525 
14526  assert(node != NULL);
14527  assert(node->depth >= 0); /* node should be in graph */
14528  assert(node->pos >= 0); /* node should be in graph */
14529  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14530 
14531  if( node->depth == 0 )
14532  {
14533  /* we cannot update bound tightenings in variable nodes here */
14534  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14535  return SCIP_OKAY;
14536  }
14537 
14538  assert(node->op != SCIP_EXPR_VARIDX);
14539  assert(node->op != SCIP_EXPR_PARAM);
14540 
14541  /* if many children, get large enough memory to store children bounds */
14543  {
14544  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14545  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, node->nchildren) );
14546  }
14547  else
14548  {
14549  childbounds = childboundsstatic;
14550  childcurv = childcurvstatic;
14551  }
14552 
14553  /* assemble bounds and curvature of children */
14554  for( i = 0; i < node->nchildren; ++i )
14555  {
14556  /* child should have valid and non-empty bounds */
14558  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14559  /* nodes at depth 0 are always linear */
14560  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14561 
14562  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
14563  childcurv[i] = node->children[i]->curv; /*lint !e644*/
14564  }
14565 
14566  /* if we do not have valid bounds, then update
14567  * code below is copied from exprgraphNodeUpdateBounds */
14569  {
14570  SCIP_INTERVAL newbounds;
14571 
14572  /* calling interval evaluation function for this operand */
14573  assert( exprOpTable[node->op].inteval != NULL );
14574  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
14575 
14576  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14577  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14578  *
14579  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14580  *
14581  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14582  */
14583  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14585  {
14586  for( i = 0; i < node->nparents; ++i )
14588 
14589  node->bounds = newbounds;
14590  }
14591  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14592  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14593  {
14594  for( i = 0; i < node->nparents; ++i )
14596 
14597  node->bounds = newbounds;
14598  }
14599  else
14600  {
14601  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14602  }
14603 
14604  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);
14605 
14606  /* node now has valid bounds */
14608  }
14609 
14610  /* update curvature */
14611  if( SCIPintervalIsEmpty(infinity, node->bounds) )
14612  {
14613  node->curv = SCIP_EXPRCURV_LINEAR;
14614 
14615  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14616  }
14617  else
14618  {
14619  SCIP_CALL( exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv) );
14620 
14621  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14622  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14623  * SCIPdebugPrintf("\n");
14624  */
14625  }
14626 
14627  /* free memory, if allocated before */
14628  if( childbounds != childboundsstatic )
14629  {
14630  BMSfreeMemoryArray(&childbounds);
14631  BMSfreeMemoryArray(&childcurv);
14632  }
14633 
14634  return SCIP_OKAY;
14635 }
14636 
14637 /**@} */
14638 
14639 /**@name Expression graph methods */
14640 /**@{ */
14641 
14642 /* In debug mode, the following methods are implemented as function calls to ensure
14643  * type validity.
14644  * In optimized mode, the methods are implemented as defines to improve performance.
14645  * However, we want to have them in the library anyways, so we have to undef the defines.
14646  */
14647 
14648 #undef SCIPexprgraphGetDepth
14649 #undef SCIPexprgraphGetNNodes
14650 #undef SCIPexprgraphGetNodes
14651 #undef SCIPexprgraphGetNVars
14652 #undef SCIPexprgraphGetVars
14653 #undef SCIPexprgraphGetVarNodes
14654 #undef SCIPexprgraphSetVarNodeValue
14655 #undef SCIPexprgraphSetVarsBounds
14656 #undef SCIPexprgraphSetVarBounds
14657 #undef SCIPexprgraphSetVarNodeBounds
14658 #undef SCIPexprgraphSetVarNodeLb
14659 #undef SCIPexprgraphSetVarNodeUb
14660 #undef SCIPexprgraphGetVarsBounds
14661 
14662 /** get current maximal depth of expression graph */
14664  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14665  )
14666 {
14667  assert(exprgraph != NULL);
14668 
14669  return exprgraph->depth;
14670 }
14671 
14672 /** gets array with number of nodes at each depth of expression graph */
14674  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14675  )
14676 {
14677  assert(exprgraph != NULL);
14678 
14679  return exprgraph->nnodes;
14680 }
14681 
14682 /** gets nodes of expression graph, one array per depth */
14684  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14685  )
14686 {
14687  assert(exprgraph != NULL);
14688 
14689  return exprgraph->nodes;
14690 }
14691 
14692 /** gets number of variables in expression graph */
14694  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14695  )
14696 {
14697  assert(exprgraph != NULL);
14698 
14699  return exprgraph->nvars;
14700 }
14701 
14702 /** gets array of variables in expression graph */
14704  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14705  )
14706 {
14707  assert(exprgraph != NULL);
14708 
14709  return exprgraph->vars;
14710 }
14711 
14712 /** gets array of expression graph nodes corresponding to variables */
14714  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14715  )
14716 {
14717  assert(exprgraph != NULL);
14718 
14719  return exprgraph->varnodes;
14720 }
14721 
14722 /** sets value for a single variable given as expression graph node */
14724  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14725  SCIP_Real value /**< new value for variable */
14726  )
14727 {
14728  assert(varnode != NULL);
14729  assert(varnode->op == SCIP_EXPR_VARIDX);
14730 
14731  varnode->value = value;
14732 }
14733 
14734 /** sets bounds for variables */
14736  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14737  SCIP_INTERVAL* varbounds /**< new bounds for variables */
14738  )
14739 {
14740  assert(exprgraph != NULL);
14741  assert(varbounds != NULL || exprgraph->nvars == 0);
14742 
14743  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
14744 }
14745 
14746 /** sets bounds for a single variable */
14748  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14749  void* var, /**< variable */
14750  SCIP_INTERVAL varbounds /**< new bounds of variable */
14751  )
14752 {
14753  int pos;
14754 
14755  assert(exprgraph != NULL);
14756  assert(var != NULL);
14757  assert(SCIPhashmapExists(exprgraph->varidxs, var));
14758 
14759  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
14760  assert(pos < exprgraph->nvars);
14761  assert(exprgraph->vars[pos] == var);
14762 
14763  exprgraph->varbounds[pos] = varbounds;
14764 }
14765 
14766 /** sets bounds for a single variable given as expression graph node */
14768  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14769  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14770  SCIP_INTERVAL varbounds /**< new bounds of variable */
14771  )
14772 {
14773  int pos;
14774 
14775  assert(exprgraph != NULL);
14776  assert(varnode != NULL);
14777 
14778  pos = varnode->data.intval;
14779  assert(pos >= 0);
14780  assert(pos < exprgraph->nvars);
14781  assert(exprgraph->varnodes[pos] == varnode);
14782 
14783  exprgraph->varbounds[pos] = varbounds;
14784 }
14785 
14786 /** sets lower bound for a single variable given as expression graph node */
14788  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14789  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14790  SCIP_Real lb /**< new lower bound for variable */
14791  )
14792 {
14793  int pos;
14794 
14795  assert(exprgraph != NULL);
14796  assert(varnode != NULL);
14797 
14798  pos = varnode->data.intval;
14799  assert(pos >= 0);
14800  assert(pos < exprgraph->nvars);
14801  assert(exprgraph->varnodes[pos] == varnode);
14802 
14803  exprgraph->varbounds[pos].inf = lb;
14804 }
14805 
14806 /** sets upper bound for a single variable given as expression graph node */
14808  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14809  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14810  SCIP_Real ub /**< new upper bound for variable */
14811  )
14812 {
14813  int pos;
14814 
14815  assert(exprgraph != NULL);
14816  assert(varnode != NULL);
14817 
14818  pos = varnode->data.intval;
14819  assert(pos >= 0);
14820  assert(pos < exprgraph->nvars);
14821  assert(exprgraph->varnodes[pos] == varnode);
14822 
14823  exprgraph->varbounds[pos].sup = ub;
14824 }
14825 
14826 /** gets bounds that are stored for all variables */
14828  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14829  )
14830 {
14831  return exprgraph->varbounds;
14832 }
14833 
14834 /** creates an empty expression graph */
14836  BMS_BLKMEM* blkmem, /**< block memory */
14837  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
14838  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
14839  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
14840  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /**< callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
14841  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /**< callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
14842  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /**< callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
14843  void* userdata /**< user data to pass to callback functions */
14844  )
14845 {
14846  assert(blkmem != NULL);
14847  assert(exprgraph != NULL);
14848 
14849  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
14850  BMSclearMemory(*exprgraph);
14851  (*exprgraph)->blkmem = blkmem;
14852 
14853  /* create nodes's arrays */
14854  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
14855  assert((*exprgraph)->depth >= 1);
14856 
14857  /* create var's arrays and hashmap */
14858  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
14859  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, SCIPcalcHashtableSize(5 * (*exprgraph)->varssize)) );
14860 
14861  /* empty array of constants is sorted */
14862  (*exprgraph)->constssorted = TRUE;
14863 
14864  /* store callback functions and user data */
14865  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
14866  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
14867  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
14868  (*exprgraph)->userdata = userdata;
14869 
14870  return SCIP_OKAY;
14871 }
14872 
14873 /** frees an expression graph */
14875  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
14876  )
14877 {
14878  BMS_BLKMEM* blkmem;
14879  int d;
14880 
14881  assert( exprgraph != NULL);
14882  assert(*exprgraph != NULL);
14883  assert((*exprgraph)->nvars == 0);
14884  assert((*exprgraph)->nconsts == 0);
14885 
14886  blkmem = (*exprgraph)->blkmem;
14887  assert(blkmem != NULL);
14888 
14889  /* free nodes arrays */
14890  for( d = 0; d < (*exprgraph)->depth; ++d )
14891  {
14892  assert((*exprgraph)->nnodes[d] == 0);
14893  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
14894  }
14895  assert((*exprgraph)->nodes != NULL);
14896  assert((*exprgraph)->nnodes != NULL);
14897  assert((*exprgraph)->nodessize != NULL);
14898  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
14899  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
14900  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
14901 
14902  /* free variables arrays and hashmap */
14903  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
14904  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
14905  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
14906  SCIPhashmapFree(&(*exprgraph)->varidxs);
14907 
14908  /* free constants array */
14909  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
14910 
14911  /* free graph struct */
14912  BMSfreeBlockMemory(blkmem, exprgraph);
14913 
14914  return SCIP_OKAY;
14915 }
14916 
14917 /** adds an expression graph node to an expression graph
14918  *
14919  * Expression graph assumes ownership of node.
14920  * Children are notified about new parent.
14921  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
14922  */
14924  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14925  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
14926  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
14927  int nchildren, /**< number of children */
14928  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
14929  )
14930 {
14931  SCIP_Bool childvalsvalid;
14932  int depth;
14933  int i;
14934 
14935  assert(exprgraph != NULL);
14936  assert(node != NULL);
14937  assert(node->pos < 0); /* node should have no position in graph yet */
14938  assert(node->depth < 0); /* node should have no position in graph yet */
14939  assert(node->nchildren == 0); /* node should not have stored children yet */
14940  assert(node->children == NULL); /* node should not have stored children yet */
14941  assert(node->nparents == 0); /* node should not have parents stored yet */
14942  assert(children != NULL || nchildren == 0);
14943 
14944  /* choose depth as maximal depth of children + 1, and at least mindepth */
14945  depth = MAX(0, mindepth);
14946  for( i = 0; i < nchildren; ++i )
14947  {
14948  if( children[i]->depth >= depth ) /*lint !e613*/
14949  depth = children[i]->depth + 1; /*lint !e613*/
14950  }
14951 
14952  /* ensure that expression graph is deep enough */
14953  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
14954  assert(exprgraph->depth > depth);
14955 
14956  /* ensure enough space for nodes at depth depth */
14957  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
14958 
14959  /* add node to graph */
14960  node->depth = depth;
14961  node->pos = exprgraph->nnodes[depth];
14962  exprgraph->nodes[depth][node->pos] = node;
14963  ++exprgraph->nnodes[depth];
14964 
14965  /* add as parent to children
14966  * and check if children has valid values */
14967  childvalsvalid = TRUE;
14968  for( i = 0; i < nchildren; ++i )
14969  {
14970  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
14971  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
14972  }
14973  /* store children */
14974  if( nchildren > 0 )
14975  {
14976  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
14977  node->nchildren = nchildren;
14978  }
14979 
14980  if( node->op == SCIP_EXPR_CONST )
14981  {
14982  /* set bounds to constant value of node */
14984  SCIPintervalSet(&node->bounds, node->data.dbl);
14985  }
14986  else
14987  {
14988  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
14991  exprgraph->needvarboundprop = TRUE;
14992  }
14993 
14994  /* if not a variable, set value of node according to values of children (if all have valid values) */
14995  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
14996  {
14997  SCIP_CALL( exprgraphNodeEval(node, NULL) );
14998  }
14999 
15000  return SCIP_OKAY;
15001 }
15002 
15003 /** adds variables to an expression graph, if not existing yet
15004  *
15005  * Also already existing nodes are enabled.
15006  */
15008  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15009  int nvars, /**< number of variables to add */
15010  void** vars, /**< variables to add */
15011  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
15012  )
15013 {
15014  SCIP_EXPRGRAPHNODE* node;
15015  SCIP_EXPROPDATA opdata;
15016  int i;
15017 
15018  assert(exprgraph != NULL);
15019  assert(exprgraph->depth >= 1);
15020  assert(vars != NULL || nvars == 0);
15021 
15022  /* 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 */
15023  if( exprgraph->nvars == 0 )
15024  {
15025  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15026  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15027  }
15028 
15029  for( i = 0; i < nvars; ++i )
15030  {
15031  /* skip variables that exist already */
15032  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15033  {
15034  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
15035  assert(node != NULL);
15036 
15037  /* enable node */
15038  node->enabled = TRUE;
15039 
15040  if( varnodes != NULL )
15041  varnodes[i] = node;
15042 
15043  continue;
15044  }
15045 
15046  /* create new variable expression */
15047  opdata.intval = exprgraph->nvars;
15048  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15049 
15050  /* add expression node to expression graph at depth 0 */
15051  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15052 
15053  /* add variable node to vars arrays and hashmap */
15054  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15055  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
15056  exprgraph->varnodes[exprgraph->nvars] = node;
15057  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15058  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[i], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15059  ++exprgraph->nvars;
15060 
15061  if( varnodes != NULL )
15062  varnodes[i] = node;
15063 
15064  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15065 
15066  /* call callback method, if set */
15067  if( exprgraph->exprgraphvaradded != NULL )
15068  {
15069  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
15070  }
15071  }
15072 
15073  return SCIP_OKAY;
15074 }
15075 
15076 /** adds a constant to an expression graph, if not existing yet
15077  *
15078  * Also already existing nodes are enabled.
15079  */
15081  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15082  SCIP_Real constant, /**< constant to add */
15083  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
15084  )
15085 {
15086  SCIP_EXPROPDATA opdata;
15087 
15088  assert(exprgraph != NULL);
15089  assert(constnode != NULL);
15090 
15091  /* check if there is already an expression for this constant */
15092  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15093  {
15094  assert(*constnode != NULL);
15095  assert((*constnode)->op == SCIP_EXPR_CONST);
15096  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15097  (*constnode)->enabled = TRUE;
15098  return SCIP_OKAY;
15099  }
15100 
15101  /* create new node for constant */
15102  opdata.dbl = constant;
15103  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15104 
15105  /* add node to expression graph at depth 0 */
15106  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15107  assert((*constnode)->depth == 0);
15108  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
15109 
15110  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15111  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15112  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15113  ++exprgraph->nconsts;
15114  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15115 
15116  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15117 
15118  return SCIP_OKAY;
15119 }
15120 
15121 /** adds sum of expression trees into expression graph
15122  *
15123  * node will also be captured.
15124  *
15125  * @note Parameters will be converted into constants
15126  */
15128  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15129  int nexprtrees, /**< number of expression trees to add */
15130  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
15131  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
15132  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
15133  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) */
15134  )
15135 {
15136  SCIP_Bool allone;
15137 
15138  assert(exprgraph != NULL);
15139  assert(nexprtrees > 0);
15140  assert(exprtrees != NULL);
15141  assert(rootnode != NULL);
15142  assert(rootnodeisnew != NULL);
15143 
15144  *rootnode = NULL;
15145 
15146  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15147  {
15148  assert(exprtrees[0] != NULL);
15149  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15150 
15151  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, exprtrees[0]->params, rootnode, rootnodeisnew) );
15152  }
15153  else
15154  {
15155  SCIP_EXPROP op;
15156  SCIP_EXPRGRAPHNODE** rootnodes;
15157  SCIP_Bool rootnodeisnew_;
15158  int i;
15159 
15160  *rootnodeisnew = TRUE;
15161  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15162 
15163  allone = TRUE;
15164  for( i = 0; i < nexprtrees; ++i )
15165  {
15166  assert(exprtrees[i] != NULL);
15167  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15168 
15169  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, exprtrees[i]->params, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
15170  assert(rootnodes[i] != NULL);
15171  *rootnodeisnew &= rootnodeisnew_;
15172 
15173  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
15174  }
15175 
15176  /* decide which operand we want to use for the root node */
15177  if( coefs == NULL || allone )
15178  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15179  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15180  op = SCIP_EXPR_MINUS;
15181  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15182  {
15183  SCIP_EXPRGRAPHNODE* tmp;
15184 
15185  tmp = rootnodes[0];
15186  rootnodes[0] = rootnodes[1];
15187  rootnodes[1] = tmp;
15188  op = SCIP_EXPR_MINUS;
15189  }
15190  else
15191  op = SCIP_EXPR_LINEAR;
15192 
15193  if( op != SCIP_EXPR_LINEAR )
15194  {
15195  SCIP_EXPROPDATA data;
15196  data.data = NULL;
15197 
15198  if( !*rootnodeisnew )
15199  {
15200  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15201  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15202  }
15203 
15204  if( *rootnode == NULL )
15205  {
15206  /* create new node for sum of rootnodes and add to exprgraph */
15207  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15208  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15209  *rootnodeisnew = TRUE;
15210  }
15211  else
15212  {
15213  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15214  *rootnodeisnew = FALSE;
15215  }
15216  }
15217  else
15218  {
15219  SCIP_EXPROPDATA data;
15220  SCIP_Real* lindata;
15221 
15222  assert(op == SCIP_EXPR_LINEAR);
15223 
15224  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15225  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15226  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
15227  lindata[nexprtrees] = 0.0;
15228  data.data = lindata;
15229 
15230  if( !*rootnodeisnew )
15231  {
15232  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15233  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15234  }
15235 
15236  if( *rootnode == NULL )
15237  {
15238  /* create new node for linear combination of rootnodes and add to exprgraph */
15239  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15240  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15241  *rootnodeisnew = TRUE;
15242  }
15243  else
15244  {
15245  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15246  *rootnodeisnew = FALSE;
15247  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15248  }
15249  }
15250 
15251  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15252  }
15253  assert(*rootnode != NULL);
15254 
15255  SCIPexprgraphCaptureNode(*rootnode);
15256 
15257  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15258  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15259 
15260  return SCIP_OKAY;
15261 }
15262 
15263 /** replaces variable in expression graph by a linear sum of variables
15264  *
15265  * Variables will be added if not in the graph yet.
15266  */
15268  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15269  void* var, /**< variable to replace */
15270  int ncoefs, /**< number of coefficients in linear term */
15271  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
15272  void** vars, /**< variables in linear term */
15273  SCIP_Real constant /**< constant offset */
15274  )
15275 {
15276  SCIP_EXPRGRAPHNODE* varnode;
15277  SCIP_Real* lindata;
15278  int varidx;
15279  int i;
15280 
15281  assert(exprgraph != NULL);
15282  assert(var != NULL);
15283  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15284  assert(coefs != NULL || ncoefs == 0);
15285  assert(vars != NULL || ncoefs == 0);
15286 
15287  varidx = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15288  assert(varidx < exprgraph->nvars);
15289  assert(exprgraph->vars[varidx] == var);
15290  varnode = exprgraph->varnodes[varidx];
15291  assert(varnode != NULL);
15292  assert(varnode->data.intval == varidx);
15293 
15294  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
15295  {
15296  /* variable is replaced by constant or variable */
15297  SCIP_EXPRGRAPHNODE* node;
15298 
15299  /* check if there is already a node for this constant or variable */
15300  node = NULL;
15301  if( ncoefs == 0 )
15302  {
15303  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15304  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
15305  }
15306  else
15307  {
15308  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
15309  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
15310  }
15311 
15312  if( node != NULL )
15313  {
15314  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15315 
15316  /* tell parents of varnode to replace child varnode by node, this may free varnode */
15317  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15318 
15319  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15320  if( varnode != NULL )
15321  {
15322  assert(varnode->nuses > 0);
15323  assert(varnode->nparents == 0);
15324 
15325  /* remove variable (but don't free it's node) from graph */
15326  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15327 
15328  /* move varnode up to depth 1 */
15329  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15330 
15331  /* turn into EXPR_SUM expression */
15332  varnode->op = SCIP_EXPR_SUM;
15333  varnode->data.data = NULL;
15334  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
15335  varnode->children[0] = node;
15336  varnode->nchildren = 1;
15337  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15338 
15339  varnode->value = node->value;
15340  varnode->bounds = node->bounds;
15342  }
15343  }
15344  else if( ncoefs == 0 )
15345  {
15346  /* turn node into EXPR_CONST node */
15347 
15348  /* remove variable (but don't free it's node) from graph */
15349  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15350 
15351  /* convert into EXPR_CONST node */
15352  varnode->op = SCIP_EXPR_CONST;
15353  varnode->data.dbl = constant;
15354 
15355  varnode->value = constant;
15356  SCIPintervalSet(&varnode->bounds, constant);
15358 
15359  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15360  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15361  exprgraph->constnodes[exprgraph->nconsts] = varnode;
15362  ++exprgraph->nconsts;
15363  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15364  }
15365  else
15366  {
15367  /* turn node into EXPR_VARIDX node for new variable */
15368 
15369  /* remove variable (but don't free it's node) from graph */
15370  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15371 
15372  varnode->data.intval = exprgraph->nvars;
15373 
15374  /* add variable node to vars arrays and hashmap */
15375  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15376  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
15377  exprgraph->varnodes[exprgraph->nvars] = varnode;
15378  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15379  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[0], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15380  ++exprgraph->nvars;
15381 
15382  /* call callback method, if set */
15383  if( exprgraph->exprgraphvaradded != NULL )
15384  {
15385  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
15386  }
15387  }
15388 
15389  /* mark varnode and its parents as not simplified */
15390  if( varnode != NULL )
15391  {
15392  varnode->simplified = FALSE;
15393  for( i = 0; i < varnode->nparents; ++i )
15394  varnode->parents[i]->simplified = FALSE;
15395  }
15396 
15397  return SCIP_OKAY;
15398  }
15399 
15400  /* turn varnode into EXPR_LINEAR */
15401 
15402  /* remove variable (but don't free it's node) from graph */
15403  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15404 
15405  /* move varnode up to depth 1 */
15406  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15407 
15408  /* convert into EXPR_LINEAR node */
15409  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15410  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
15411  lindata[ncoefs] = constant;
15412  varnode->data.data = (void*)lindata;
15413  varnode->op = SCIP_EXPR_LINEAR;
15414 
15415  /* add nodes corresponding to vars to expression graph, if not existing yet */
15416  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15417  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15418  varnode->nchildren = ncoefs;
15419 
15420  /* notify vars about new parent varnode */
15421  for( i = 0; i < ncoefs; ++i )
15422  {
15423  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15424  }
15425 
15426  /* set value and bounds to invalid, curvature can remain (still linear) */
15427  varnode->value = SCIP_INVALID;
15429 
15430  /* mark varnode and its parents as not simplified */
15431  varnode->simplified = FALSE;
15432  for( i = 0; i < varnode->nparents; ++i )
15433  varnode->parents[i]->simplified = FALSE;
15434 
15435  return SCIP_OKAY;
15436 }
15437 
15438 /** finds expression graph node corresponding to a variable */
15440  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15441  void* var, /**< variable to search for */
15442  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15443  )
15444 {
15445  int pos;
15446 
15447  assert(exprgraph != NULL);
15448  assert(var != NULL);
15449  assert(varnode != NULL);
15450 
15451  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15452  {
15453  *varnode = NULL;
15454  return FALSE;
15455  }
15456 
15457  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15458  assert(pos < exprgraph->nvars);
15459 
15460  *varnode = exprgraph->varnodes[pos];
15461  assert(*varnode != NULL);
15462  assert((*varnode)->op == SCIP_EXPR_VARIDX);
15463 
15464  return TRUE;
15465 }
15466 
15467 /** finds expression graph node corresponding to a constant */
15469  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15470  SCIP_Real constant, /**< constant to search for */
15471  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15472  )
15473 {
15474  int left;
15475  int right;
15476  int middle;
15477 
15478  assert(exprgraph != NULL);
15479  assert(constnode != NULL);
15480  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
15481 
15482  exprgraphSortConstNodes(exprgraph);
15483  assert(exprgraph->constssorted);
15484 
15485  /* find node using binary search */
15486  left = 0;
15487  right = exprgraph->nconsts-1;
15488  *constnode = NULL;
15489 
15490  while( left <= right )
15491  {
15492  middle = (left+right)/2;
15493  assert(0 <= middle && middle < exprgraph->nconsts);
15494 
15495  if( constant < exprgraph->constnodes[middle]->data.dbl )
15496  right = middle - 1;
15497  else if( constant > exprgraph->constnodes[middle]->data.dbl )
15498  left = middle + 1;
15499  else
15500  {
15501  *constnode = exprgraph->constnodes[middle];
15502  break;
15503  }
15504  }
15505  assert(left == right+1 || *constnode != NULL);
15506  if( left == right+1 )
15507  return FALSE;
15508 
15509  assert((*constnode)->op == SCIP_EXPR_CONST);
15510  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15511 
15512  return TRUE;
15513 }
15514 
15515 /** prints an expression graph in dot format */
15517  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15518  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15519  FILE* file, /**< file to print to, or NULL for stdout */
15520  const char** varnames /**< variable names, or NULL for generic names */
15521  )
15522 {
15523  int d;
15524  int i;
15525 
15526  assert(exprgraph != NULL);
15527 
15528  if( file == NULL )
15529  file = stdout;
15530 
15531  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15532  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15533 
15534  for( d = 0; d < exprgraph->depth; ++d )
15535  {
15536  if( exprgraph->nnodes[d] == 0 )
15537  continue;
15538 
15539  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15540  {
15541  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15542  }
15543  }
15544 
15545  /* tell dot that all nodes of depth 0 have the same rank */
15546  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15547  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15548  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15549  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15550 
15551  /* tell dot that all nodes without parent have the same rank */
15552  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15553  for( d = 0; d < exprgraph->depth; ++d )
15554  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15555  if( exprgraph->nodes[d][i]->nparents == 0 )
15556  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15557  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15558 
15559  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15560 
15561  return SCIP_OKAY;
15562 }
15563 
15564 /** evaluates nodes of expression graph for given values of variables */
15566  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15567  SCIP_Real* varvals /**< values for variables */
15568  )
15569 {
15570  int d;
15571  int i;
15572 
15573  assert(exprgraph != NULL);
15574  assert(varvals != NULL || exprgraph->nvars == 0);
15575 
15576  for( d = 0; d < exprgraph->depth; ++d )
15577  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15578  {
15579  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15580  }
15581 
15582  return SCIP_OKAY;
15583 }
15584 
15585 /** propagates bound changes in variables forward through the expression graph */
15587  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15588  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15589  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
15590  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15591  )
15592 {
15593  SCIP_EXPRGRAPHNODE* node;
15594  SCIP_Bool boundchanged;
15595  int d;
15596  int i;
15597 
15598  assert(exprgraph != NULL);
15599  assert(domainerror != NULL);
15600 
15601  *domainerror = FALSE;
15602 
15603  /* update bounds in varnodes of expression graph */
15604  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15605 
15606  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15607  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15608  {
15609  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15610  return SCIP_OKAY;
15611  }
15612 
15613  /* propagate bound changes, interrupt if we get to a node with empty bounds */
15614  for( d = 1; d < exprgraph->depth; ++d )
15615  {
15616  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15617  {
15618  node = exprgraph->nodes[d][i];
15619  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15620  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15621  {
15622  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15623  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15624  *domainerror = TRUE;
15625  return SCIP_OKAY;
15626  }
15627  }
15628  }
15629 
15630  exprgraph->needvarboundprop = FALSE;
15631 
15632  return SCIP_OKAY;
15633 }
15634 
15635 /** propagates bound changes in nodes backward through the graph
15636  *
15637  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15638  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15639  */
15641  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15642  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15643  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15644  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15645  )
15646 {
15647  SCIP_EXPRGRAPHNODE* node;
15648  int d;
15649  int i;
15650 
15651  assert(exprgraph != NULL);
15652  assert(cutoff != NULL);
15653 
15654  *cutoff = FALSE;
15655 
15656  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15657  {
15658  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15659  {
15660  node = exprgraph->nodes[d][i];
15661  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15662  }
15663  }
15664  if( *cutoff )
15665  return;
15666 }
15667 
15668 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15669  *
15670  * Implies update of bounds in expression graph.
15671  */
15673  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15674  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15675  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15676  )
15677 {
15678  SCIP_EXPRGRAPHNODE* node;
15679  SCIP_Bool boundchanged;
15680  int d;
15681  int i;
15682 
15683  assert(exprgraph != NULL);
15684 
15685  /* update bounds in varnodes of expression graph */
15686  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15687 
15688 #ifndef NDEBUG
15689  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15690  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15691 #endif
15692 
15693  for( d = 1; d < exprgraph->depth; ++d )
15694  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15695  {
15696  node = exprgraph->nodes[d][i];
15697  assert(node != NULL);
15698 
15699  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15700 
15701  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15702  {
15703  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15704  return SCIP_OKAY;
15705  }
15706  }
15707 
15708  return SCIP_OKAY;
15709 }
15710 
15711 /** aims at simplifying an expression graph
15712  *
15713  * 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)).
15714  */
15716  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15717  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15718  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15719  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15720  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15721  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15722  )
15723 {
15724  SCIP_EXPRGRAPHNODE* node;
15725  SCIP_Bool havechangenode;
15726  SCIP_Bool allsimplified;
15727  int d;
15728  int i;
15729  int j;
15730 
15731 #ifndef NDEBUG
15732  SCIP_Real* testx;
15733  SCIP_HASHMAP* testvalidx;
15734  SCIP_Real* testvals;
15735  int testvalssize;
15736  int ntestvals;
15737  unsigned int seed;
15738 #endif
15739 
15740  assert(exprgraph != NULL);
15741  assert(eps >= 0.0);
15742  assert(havechange != NULL);
15743  assert(domainerror != NULL);
15744 
15745 #ifndef NDEBUG
15746  seed = 42;
15747  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
15748  testvals = NULL;
15749  ntestvals = 0;
15750  testvalssize = 0;
15751 
15752  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
15753  for( i = 0; i < exprgraph->nvars; ++i )
15754  testx[i] = SCIPgetRandomReal(-100.0, 100.0, &seed); /*lint !e644*/
15755  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
15756  for( d = 1; d < exprgraph->depth; ++d )
15757  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15758  {
15759  node = exprgraph->nodes[d][i];
15760  assert(node != NULL);
15761 
15762  /* 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 */
15763  if( node->nuses > 0 )
15764  {
15765  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
15766  SCIP_CALL( SCIPhashmapInsert(testvalidx, (void*)node, (void*)(size_t)ntestvals) );
15767  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
15768  ++ntestvals;
15769  }
15770  }
15771 #endif
15772 
15773 #ifdef SCIP_OUTPUT
15774  {
15775  FILE* file;
15776  file = fopen("exprgraph_beforesimplify.dot", "w");
15777  if( file != NULL )
15778  {
15779  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
15780  fclose(file);
15781  }
15782  }
15783 #endif
15784 
15785  *havechange = FALSE; /* we have not changed any node yet */
15786  *domainerror = FALSE; /* no domain errors encountered so far */
15787  allsimplified = TRUE; /* all nodes we looked at are simplified */
15788 
15789  /* call node simplifier from bottom up
15790  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
15791  */
15792  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
15793  {
15794  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15795  {
15796  node = exprgraph->nodes[d][i];
15797  assert(node != NULL);
15798 
15799  havechangenode = FALSE; /* node did not change yet */
15800 
15801  if( node->op != SCIP_EXPR_CONST )
15802  {
15803  /* skip nodes that are already simplified */
15804  if( node->simplified )
15805  continue;
15806 
15807  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
15808 
15809  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
15810  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
15811  assert(node->simplified == TRUE);
15812  *havechange |= havechangenode;
15813  }
15814 
15815  /* if node was or has been converted into constant, may move to depth 0 */
15816  if( node->op == SCIP_EXPR_CONST )
15817  {
15818  SCIP_EXPRGRAPHNODE* constnode;
15819 
15820  if( node->value != node->value ) /*lint !e777*/
15821  {
15822  SCIPdebugMessage("Expression graph simplify turned node into NaN.\n");
15823  *domainerror = TRUE;
15824  break;
15825  }
15826 
15827  /* check if there is already a node for this constant */
15828  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
15829  {
15830  assert(constnode->op == SCIP_EXPR_CONST);
15831  assert(constnode->data.dbl == node->value); /*lint !e777*/
15832 
15833  if( node->nparents > 0 )
15834  {
15835  /* move parents of this node to constnode, node may be freed if not in use */
15836  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
15837  /* node should have no parents anymore, so it should have been freed if not in use */
15838  assert(node == NULL || node->nuses > 0);
15839  havechangenode = TRUE;
15840 
15841  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
15842  if( node == NULL )
15843  {
15844  --i;
15845  continue;
15846  }
15847  }
15848  assert(node != NULL);
15849  assert(node->nuses > 0);
15850 
15851  if( constnode->nuses == 0 )
15852  {
15853  /* move node to depth 0, adding it to constnodes */
15854  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
15855 
15856  /* move parents of constnode to node, so constnode is freed */
15857  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
15858  assert(constnode == NULL);
15859  havechangenode = TRUE;
15860 
15861  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
15862  --i;
15863  continue;
15864  }
15865  }
15866  else
15867  {
15868  /* move to depth 0, adding it to constnodes */
15869  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
15870 
15871  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
15872  --i;
15873  }
15874  }
15875 
15876  /* if there was a change, mark parents as not simplified */
15877  if( havechangenode )
15878  for( j = 0; j < node->nparents; ++j )
15879  node->parents[j]->simplified = FALSE;
15880  }
15881  } /*lint !e850*/
15882 
15883  /* if we did nothing, clean up and escape from here */
15884  if( allsimplified || *domainerror )
15885  goto EXPRGRAPHSIMPLIFY_CLEANUP;
15886 
15887  /* @todo find duplicate subexpressions in expression graph */
15888 
15889  /* unconvert polynomials into simpler expressions, where possible */
15890  for( d = 1; d < exprgraph->depth; ++d )
15891  {
15892  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15893  {
15894  node = exprgraph->nodes[d][i];
15895  assert(node != NULL);
15896 
15897  if( node->op != SCIP_EXPR_POLYNOMIAL )
15898  continue;
15899 
15900  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
15901 
15902  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
15903  {
15904  /* node is identity w.r.t only child
15905  * replace node as child of parents by child of node
15906  */
15907 
15908  for( j = 0; node != NULL && j < node->nparents; ++j )
15909  {
15910  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
15911  }
15912  /* node should have no parents anymore, so it should have been freed if not in use */
15913  assert(node == NULL || node->nuses > 0);
15914 
15915  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
15916  if( node == NULL )
15917  --i;
15918  }
15919  }
15920  } /*lint !e850*/
15921 
15922 #ifdef SCIP_OUTPUT
15923  {
15924  FILE* file;
15925  file = fopen("exprgraph_aftersimplify.dot", "w");
15926  if( file != NULL )
15927  {
15928  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
15929  fclose(file);
15930  }
15931  }
15932 #endif
15933 
15934 #ifndef NDEBUG
15935  for( d = 1; d < exprgraph->depth; ++d )
15936  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15937  {
15938  int idx;
15939  SCIP_Real testval_before;
15940  SCIP_Real testval_after;
15941 
15942  node = exprgraph->nodes[d][i];
15943  assert(node != NULL);
15944 
15945  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15946 
15947  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
15948  if( node->nuses > 0 )
15949  {
15950  assert(SCIPhashmapExists(testvalidx, (void*)node));
15951 
15952  idx = (int)(size_t)(void*)SCIPhashmapGetImage(testvalidx, (void*)node);
15953  assert(idx < ntestvals);
15954 
15955  testval_before = testvals[idx]; /*lint !e613*/
15956  testval_after = SCIPexprgraphGetNodeVal(node);
15957 
15958  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
15959  }
15960  }
15961 #endif
15962 
15963  EXPRGRAPHSIMPLIFY_CLEANUP:
15964 #ifndef NDEBUG
15965  BMSfreeMemoryArray(&testx);
15966  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
15967  SCIPhashmapFree(&testvalidx);
15968 #endif
15969 
15970  return SCIP_OKAY;
15971 }
15972 
15973 /** creates an expression tree from a given node in an expression graph */
15975  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15976  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
15977  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
15978  )
15979 {
15980  SCIP_EXPR* root;
15981  int nexprvars;
15982  int* varidx;
15983  int i;
15984 
15985  assert(exprgraph != NULL);
15986  assert(rootnode != NULL);
15987  assert(rootnode->depth >= 0);
15988  assert(rootnode->pos >= 0);
15989  assert(exprtree != NULL);
15990 
15991  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
15992  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
15993 
15994  /* initially, no variable appears in the expression tree */
15995  for( i = 0; i < exprgraph->nvars; ++i )
15996  varidx[i] = -1; /*lint !e644*/
15997  nexprvars = 0;
15998 
15999  /* create expression from the subgraph that has rootnode as root */
16000  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
16001 
16002  /* create expression tree for this expression */
16003  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
16004 
16005  /* copy variables into expression tree */
16006  if( nexprvars > 0 )
16007  {
16008  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
16009  for( i = 0; i < exprgraph->nvars; ++i )
16010  {
16011  assert(varidx[i] >= -1);
16012  assert(varidx[i] < nexprvars);
16013  if( varidx[i] >= 0 )
16014  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
16015  }
16016  }
16017 
16018  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16019 
16020  return SCIP_OKAY;
16021 }
16022 
16023 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16024  *
16025  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16026  */
16028  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16029  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16030  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16031  int* nexprtrees, /**< buffer to store number of expression trees */
16032  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16033  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16034  )
16035 {
16036  int ncomponents;
16037  int* childcomp;
16038  int* varcomp;
16039  int compnr;
16040  SCIP_Bool haveoverlap;
16041  int i;
16042  int j;
16043  int k;
16044 
16045  SCIP_EXPR** exprs;
16046  int nexprs;
16047  int* childmap;
16048  int* childmapinv;
16049  int* varidx;
16050  int nexprvars;
16051 
16052  assert(exprgraph != NULL);
16053  assert(node != NULL);
16054  assert(node->depth >= 0);
16055  assert(node->pos >= 0);
16056  assert(exprtreessize > 0);
16057  assert(nexprtrees != NULL);
16058  assert(exprtrees != NULL);
16059  assert(exprtreecoefs != NULL);
16060 
16061  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16062  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16063  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16064  ( node->op != SCIP_EXPR_PLUS &&
16065  node->op != SCIP_EXPR_MINUS &&
16066  node->op != SCIP_EXPR_SUM &&
16067  node->op != SCIP_EXPR_LINEAR &&
16068  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16069  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16070  {
16071  *nexprtrees = 1;
16072  exprtreecoefs[0] = 1.0;
16073  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16074 
16075  return SCIP_OKAY;
16076  }
16077 
16078  /* find components in node->children <-> variables graph */
16079  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16080  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16081  for( i = 0; i < exprgraph->nvars; ++i )
16082  varcomp[i] = -1; /*lint !e644*/
16083 
16084  haveoverlap = FALSE;
16085  for( i = 0; i < node->nchildren; ++i )
16086  {
16087  compnr = i;
16088  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
16089  assert(compnr >= 0);
16090  assert(compnr < node->nchildren);
16091  childcomp[i] = compnr;
16092 
16093  /* remember if component number was changed by CheckComponent */
16094  if( compnr != i )
16095  haveoverlap = TRUE;
16096  }
16097 
16098  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16099 
16100  if( node->op == SCIP_EXPR_QUADRATIC )
16101  {
16102  /* merge components for products of children from different components */
16104 
16105  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16106  assert(data != NULL);
16107 
16108  for( i = 0; i < data->nquadelems; ++i )
16109  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16110  {
16111  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16112  compnr = childcomp[data->quadelems[i].idx2];
16113  for( j = 0; j < node->nchildren; ++j )
16114  if( childcomp[j] == compnr )
16115  childcomp[j] = childcomp[data->quadelems[i].idx1];
16116  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16117  haveoverlap = TRUE;
16118  }
16119  }
16120  else if( node->op == SCIP_EXPR_POLYNOMIAL )
16121  {
16122  /* merge components for monomials of children from different components */
16124 
16125  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16126  assert(data != NULL);
16127 
16128  for( i = 0; i < data->nmonomials; ++i )
16129  for( j = 1; j < data->monomials[i]->nfactors; ++j )
16130  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16131  {
16132  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16133  compnr = childcomp[data->monomials[i]->childidxs[j]];
16134  for( k = 0; k < node->nchildren; ++k )
16135  if( childcomp[k] == compnr )
16136  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16137  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16138  haveoverlap = TRUE;
16139  }
16140  }
16141 
16142  if( haveoverlap )
16143  {
16144  /* some component numbers are unused, thus relabel and count final number of components */
16145  int* compmap;
16146 
16147  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16148  for( i = 0; i < node->nchildren; ++i )
16149  compmap[i] = -1; /*lint !e644*/
16150 
16151  ncomponents = 0;
16152  for( i = 0; i < node->nchildren; ++i )
16153  {
16154  if( compmap[childcomp[i]] == -1 )
16155  compmap[childcomp[i]] = ncomponents++;
16156  childcomp[i] = compmap[childcomp[i]];
16157  }
16158 
16159  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16160  }
16161  else
16162  {
16163  ncomponents = node->nchildren;
16164  }
16165 
16166  if( ncomponents == 1 )
16167  {
16168  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16169  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16170 
16171  *nexprtrees = 1;
16172  exprtreecoefs[0] = 1.0;
16173  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16174 
16175  return SCIP_OKAY;
16176  }
16177 
16178  if( ncomponents > exprtreessize )
16179  {
16180  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16181  for( i = 0; i < node->nchildren; ++i )
16182  if( childcomp[i] >= exprtreessize )
16183  childcomp[i] = exprtreessize-1;
16184  ncomponents = exprtreessize;
16185  }
16186 
16187  assert(ncomponents >= 2);
16188 
16189  /* setup expression trees for each component */
16190  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16191  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16192  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16193  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16194  for( i = 0; i < ncomponents; ++i )
16195  {
16196  /* initially, no variable appears in the expression tree */
16197  for( j = 0; j < exprgraph->nvars; ++j )
16198  varidx[j] = -1; /*lint !e644*/
16199  nexprvars = 0;
16200 
16201  /* collect expressions from children belonging to component i */
16202  nexprs = 0;
16203  for( j = 0; j < node->nchildren; ++j )
16204  {
16205  assert(childcomp[j] >= 0);
16206  assert(childcomp[j] < ncomponents);
16207  if( childcomp[j] != i )
16208  continue;
16209 
16210  /* create expression from the subgraph that has child j as root */
16211  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
16212  childmap[j] = nexprs; /*lint !e644*/
16213  childmapinv[nexprs] = j; /*lint !e644*/
16214  ++nexprs;
16215  }
16216 
16217  /* setup expression tree for component i */
16218  switch( node->op )
16219  {
16220  case SCIP_EXPR_PLUS:
16221  {
16222  assert(ncomponents == 2);
16223  assert(nexprs == 1);
16224 
16225  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16226  exprtreecoefs[i] = 1.0;
16227 
16228  break;
16229  }
16230 
16231  case SCIP_EXPR_MINUS:
16232  {
16233  assert(ncomponents == 2);
16234  assert(nexprs == 1);
16235 
16236  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16237  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16238  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16239  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16240 
16241  break;
16242  }
16243 
16244  case SCIP_EXPR_SUM:
16245  {
16246  if( nexprs == 1 )
16247  {
16248  /* component corresponds to exactly one child of node */
16249  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16250  }
16251  else
16252  {
16253  /* component corresponds to a sum of children of node */
16254  SCIP_EXPR* sumexpr;
16255 
16256  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16257  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16258  }
16259  exprtreecoefs[i] = 1.0;
16260 
16261  break;
16262  }
16263 
16264  case SCIP_EXPR_LINEAR:
16265  {
16266  SCIP_Real* nodecoefs;
16267  SCIP_EXPR* sumexpr;
16268 
16269  nodecoefs = (SCIP_Real*)node->data.data;
16270 
16271  /* if there is a constant, then we put it into the expression of the first component */
16272  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16273  {
16274  /* component corresponds to exactly one child of node */
16275  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16276  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16277  }
16278  else if( nexprs == 1 )
16279  {
16280  /* component corresponds to a sum of one child and a constant */
16281  assert(i == 0);
16282  assert(nodecoefs[node->nchildren] != 0.0);
16283  assert(nodecoefs[childmapinv[0]] != 0.0);
16284  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16285  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16286  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16287  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16288  }
16289  else
16290  {
16291  /* component corresponds to a linear combination of children of node */
16292 
16293  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16294  {
16295  /* if two expressions with equal sign, then create PLUS expression */
16296  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16297  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16298  }
16299  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16300  {
16301  /* if two expressions with opposite sign, then create MINUS expression */
16302  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16303  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16304  }
16305  else
16306  {
16307  /* assemble coefficents and create SUM or LINEAR expression */
16308  SCIP_Real* coefs;
16309  SCIP_Bool allcoefsequal;
16310 
16311  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16312  allcoefsequal = TRUE;
16313  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
16314  for( j = 0; j < nexprs; ++j )
16315  {
16316  coefs[j] = nodecoefs[childmapinv[j]];
16317  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
16318  }
16319 
16320  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16321  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16322  {
16323  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16324  exprtreecoefs[i] = coefs[0];
16325  }
16326  else
16327  {
16328  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16329  exprtreecoefs[i] = 1.0;
16330  }
16331 
16332  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16333  }
16334 
16335  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16336  }
16337 
16338  break;
16339  }
16340 
16341  case SCIP_EXPR_QUADRATIC:
16342  {
16343  SCIP_EXPR* quadexpr;
16344  SCIP_EXPRDATA_QUADRATIC* nodedata;
16345  SCIP_Real* lincoefs;
16346  SCIP_QUADELEM* quadelems;
16347  int nquadelems;
16348 
16349  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16350 
16351  exprtreecoefs[i] = 1.0;
16352 
16353  /* assemble coefficients corresponding to component i */
16354  if( nodedata->lincoefs != NULL )
16355  {
16356  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16357  for( j = 0; j < nexprs; ++j )
16358  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
16359  }
16360  else
16361  lincoefs = NULL;
16362 
16363  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16364  nquadelems = 0;
16365  for( j = 0; j < nodedata->nquadelems; ++j )
16366  {
16367  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16368  if( childcomp[nodedata->quadelems[j].idx1] != i )
16369  continue;
16370  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
16371  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16372  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16373  ++nquadelems;
16374  }
16375 
16376  /* put constant into first component */
16377  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16378  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16379 
16380  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16381  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16382 
16383  break;
16384  }
16385 
16386  case SCIP_EXPR_POLYNOMIAL:
16387  {
16388  SCIP_EXPR* polyexpr;
16389  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
16390  SCIP_EXPRDATA_MONOMIAL** monomials;
16391  SCIP_Real constant;
16392  int nmonomials;
16393 
16394  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16395 
16396  constant = nodedata->constant;
16397  exprtreecoefs[i] = 1.0;
16398 
16399  /* collect monomials belonging to component i */
16400  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16401  nmonomials = 0;
16402  for( j = 0; j < nodedata->nmonomials; ++j )
16403  {
16404  if( nodedata->monomials[j]->nfactors == 0 )
16405  {
16406  constant += nodedata->monomials[j]->coef;
16407  continue;
16408  }
16409  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16410  continue;
16411 
16412  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16413  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
16414  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16415  {
16416  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16417  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16418  }
16419  ++nmonomials;
16420  }
16421 
16422  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16423  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16424 
16425  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16426 
16427  break;
16428  }
16429 
16430  default:
16431  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16432  return SCIP_ERROR;
16433  } /*lint !e788*/
16434 
16435  /* copy variables into expression tree */
16436  if( nexprvars > 0 )
16437  {
16438  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16439  for( j = 0; j < exprgraph->nvars; ++j )
16440  {
16441  assert(varidx[j] >= -1);
16442  assert(varidx[j] < nexprvars);
16443  if( varidx[j] >= 0 )
16444  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16445  }
16446  }
16447  }
16448 
16449  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16450  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16451  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16452  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16453  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16454 
16455  *nexprtrees = ncomponents;
16456 
16457  return SCIP_OKAY;
16458 }
16459 
16460 /** returns how often expression graph variables are used in a subtree of the expression graph */
16462  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16463  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
16464  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16465  )
16466 {
16467  assert(exprgraph != NULL);
16468  assert(node != NULL);
16469  assert(varsusage != NULL);
16470 
16471  BMSclearMemoryArray(varsusage, exprgraph->nvars);
16472 
16473  exprgraphNodeGetVarsUsage(node, varsusage);
16474 }
16475 
16476 /** gives the number of summands which the expression of an expression graph node consists of */
16478  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
16479  )
16480 {
16481  switch( node->op )
16482  {
16483  case SCIP_EXPR_PLUS:
16484  case SCIP_EXPR_MINUS:
16485  return 2;
16486 
16487  case SCIP_EXPR_SUM:
16488  case SCIP_EXPR_LINEAR:
16489  return node->nchildren;
16490 
16491  case SCIP_EXPR_QUADRATIC:
16492  {
16493  SCIP_EXPRDATA_QUADRATIC* nodedata;
16494 
16495  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16496  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16497  }
16498 
16499  case SCIP_EXPR_POLYNOMIAL:
16500  {
16501  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
16502 
16503  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16504  return nodedata->nmonomials;
16505  }
16506 
16507  default:
16508  return 1;
16509  } /*lint !e788*/
16510 }
16511 
16512 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
16514  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16515  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16516  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16517  int* nexprtrees, /**< buffer to store number of expression trees */
16518  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16519  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16520  )
16521 {
16522  int* varidx;
16523  int nexprvars;
16524  int i;
16525 
16526  assert(exprgraph != NULL);
16527  assert(node != NULL);
16528  assert(node->depth >= 0);
16529  assert(node->pos >= 0);
16530  assert(exprtreessize > 0);
16531  assert(nexprtrees != NULL);
16532  assert(exprtrees != NULL);
16533  assert(exprtreecoefs != NULL);
16534 
16535  /* if node is not separable, fallback to SCIPexprgraphGetTree */
16536  if( node->op != SCIP_EXPR_PLUS &&
16537  node->op != SCIP_EXPR_MINUS &&
16538  node->op != SCIP_EXPR_SUM &&
16539  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16540  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16541  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16542  {
16543  *nexprtrees = 1;
16544  exprtreecoefs[0] = 1.0;
16545  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16546 
16547  return SCIP_OKAY;
16548  }
16549 
16550  switch( node->op )
16551  {
16552  case SCIP_EXPR_PLUS:
16553  {
16554  assert(exprtreessize >= 2);
16555 
16556  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16557  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16558 
16559  exprtreecoefs[0] = 1.0;
16560  exprtreecoefs[1] = 1.0;
16561 
16562  *nexprtrees = 2;
16563  break;
16564  }
16565 
16566  case SCIP_EXPR_MINUS:
16567  {
16568  assert(exprtreessize >= 2);
16569 
16570  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16571  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16572 
16573  exprtreecoefs[0] = 1.0;
16574  exprtreecoefs[1] = -1.0;
16575 
16576  *nexprtrees = 2;
16577  break;
16578  }
16579 
16580  case SCIP_EXPR_SUM:
16581  {
16582  assert(exprtreessize >= node->nchildren);
16583 
16584  for( i = 0; i < node->nchildren; ++i )
16585  {
16586  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16587  exprtreecoefs[i] = 1.0;
16588  }
16589 
16590  *nexprtrees = node->nchildren;
16591  break;
16592  }
16593 
16594  case SCIP_EXPR_LINEAR:
16595  {
16596  SCIP_Real* nodecoefs;
16597 
16598  assert(exprtreessize >= node->nchildren);
16599  assert(node->nchildren > 0);
16600 
16601  nodecoefs = (SCIP_Real*)node->data.data;
16602  assert(nodecoefs != NULL);
16603 
16604  for( i = 0; i < node->nchildren; ++i )
16605  {
16606  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16607  exprtreecoefs[i] = nodecoefs[i];
16608  }
16609 
16610  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16611  if( nodecoefs[node->nchildren] != 0.0 )
16612  {
16613  SCIP_EXPR* constexpr_;
16614 
16615  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16616  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16617  }
16618 
16619  *nexprtrees = node->nchildren;
16620  break;
16621  }
16622 
16623  case SCIP_EXPR_QUADRATIC:
16624  {
16625  SCIP_EXPRDATA_QUADRATIC* nodedata;
16626  SCIP_Real* lincoefs;
16627  SCIP_QUADELEM* quadelems;
16628  int nquadelems;
16629  SCIP_EXPR* expr;
16630  int j;
16631 
16632  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16633  lincoefs = nodedata->lincoefs;
16634  quadelems = nodedata->quadelems;
16635  nquadelems = nodedata->nquadelems;
16636 
16637  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16638  assert(node->nchildren > 0);
16639 
16640  *nexprtrees = 0;
16641  if( lincoefs != NULL )
16642  {
16643  for( i = 0; i < node->nchildren; ++i )
16644  {
16645  if( lincoefs[i] == 0.0 )
16646  continue;
16647  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16648  exprtreecoefs[*nexprtrees] = lincoefs[i];
16649  ++*nexprtrees;
16650  }
16651  }
16652 
16653  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16654  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16655 
16656  for( i = 0; i < nquadelems; ++i )
16657  {
16658  /* initially, no variable appears in the expression tree */
16659  for( j = 0; j < exprgraph->nvars; ++j )
16660  varidx[j] = -1; /*lint !e644*/
16661  nexprvars = 0;
16662 
16663  /* create expression from the subgraph at quadelems[i].idx1 */
16664  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16665 
16666  if( quadelems[i].idx1 == quadelems[i].idx2 )
16667  {
16668  /* create expression for square of expr */
16669  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16670  }
16671  else
16672  {
16673  SCIP_EXPR* expr2;
16674 
16675  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16676  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16677  /* create expression for product */
16678  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16679  }
16680 
16681  /* create expression tree for expr */
16682  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16683 
16684  /* copy variables into expression tree */
16685  if( nexprvars > 0 )
16686  {
16687  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16688  for( j = 0; j < exprgraph->nvars; ++j )
16689  {
16690  assert(varidx[j] >= -1);
16691  assert(varidx[j] < nexprvars);
16692  if( varidx[j] >= 0 )
16693  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16694  }
16695  }
16696 
16697  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16698 
16699  ++*nexprtrees;
16700  }
16701 
16702  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16703  if( nodedata->constant != 0.0 )
16704  {
16705  SCIP_EXPR* constexpr_;
16706 
16707  assert(*nexprtrees > 0);
16708  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16709  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16710  }
16711 
16712  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16713 
16714  break;
16715  }
16716 
16717  case SCIP_EXPR_POLYNOMIAL:
16718  {
16719  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
16720  SCIP_EXPRDATA_MONOMIAL** monomials;
16721  SCIP_Real constant;
16722  int nmonomials;
16723  SCIP_EXPR* expr;
16724  int* childidxs;
16725  int j;
16726 
16727  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16728  monomials = nodedata->monomials;
16729  nmonomials = nodedata->nmonomials;
16730  constant = nodedata->constant;
16731 
16732  assert(exprtreessize >= nmonomials);
16733  assert(node->nchildren > 0);
16734 
16735  *nexprtrees = 0;
16736 
16737  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16738  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16739 
16740  for( i = 0; i < nmonomials; ++i )
16741  {
16742  /* initially, no variable appears in the expression tree */
16743  for( j = 0; j < exprgraph->nvars; ++j )
16744  varidx[j] = -1;
16745  nexprvars = 0;
16746 
16747  if( monomials[i]->nfactors == 1 )
16748  {
16749  /* create expression from the subgraph at only factor */
16750  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16751 
16752  /* put exponent in, if not 1.0 */
16753  if( monomials[i]->exponents[0] == 1.0 )
16754  ;
16755  else if( monomials[i]->exponents[0] == 2.0 )
16756  {
16757  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16758  }
16759  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
16760  {
16761  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
16762  }
16763  else
16764  {
16765  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
16766  }
16767  }
16768  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
16769  {
16770  SCIP_EXPR* expr2;
16771 
16772  /* create expressions for both factors */
16773  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16774  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
16775 
16776  /* create expression for product of factors */
16777  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16778  }
16779  else
16780  {
16781  SCIP_EXPRDATA_MONOMIAL* monomial;
16782  SCIP_EXPR** exprs;
16783  int f;
16784 
16785  /* create expression for each factor, assemble varidx and nexprvars
16786  * create child indices (= identity) */
16787  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
16788  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
16789  for( f = 0; f < monomials[i]->nfactors; ++f )
16790  {
16791  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
16792  childidxs[f] = f; /*lint !e644*/
16793  }
16794 
16795  /* create monomial and polynomial expression for this monomial
16796  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
16797  */
16798  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
16799  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
16800  constant = 0.0;
16801 
16802  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
16803  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
16804  }
16805 
16806  /* create expression tree for expr */
16807  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16808 
16809  /* copy variables into expression tree */
16810  if( nexprvars > 0 )
16811  {
16812  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16813  for( j = 0; j < exprgraph->nvars; ++j )
16814  {
16815  assert(varidx[j] >= -1);
16816  assert(varidx[j] < nexprvars);
16817  if( varidx[j] >= 0 )
16818  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16819  }
16820  }
16821 
16822  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
16823 
16824  ++*nexprtrees;
16825  }
16826 
16827  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
16828  if( constant != 0.0 )
16829  {
16830  SCIP_EXPR* constexpr_;
16831 
16832  assert(*nexprtrees > 0);
16833  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
16834  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16835  }
16836 
16837  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16838 
16839  break;
16840  }
16841 
16842  default:
16843  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16844  return SCIP_ERROR;
16845  } /*lint !e788*/
16846 
16847  return SCIP_OKAY;
16848 }
16849 
16850 /**@} */
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:4891
#define SCIP_EXPRBOUNDSTATUS_CHILDRELAXED
Definition: type_expr.h:211
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:102
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13095
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15586
void SCIPexprFreeDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6061
void SCIPexprtreeGetVarsUsage(SCIP_EXPRTREE *tree, int *varsusage)
Definition: expr.c:8747
void SCIPquadelemSort(SCIP_QUADELEM *quadelems, int nquadelems)
Definition: expr.c:9030
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15267
void SCIPexprSortMonomials(SCIP_EXPR *expr)
Definition: expr.c:6901
void SCIPintervalSubScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define exprcurvSin
Definition: expr.c:2055
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:406
void SCIPintervalMax(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:422
SCIP_EXPROPDATA data
Definition: struct_expr.h:51
static void exprgraphSortConstNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:9470
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14723
static SCIP_RETCODE exprgraphNodeAddParent(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9163
SCIP_RETCODE SCIPexprSubstituteVars(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR **substexprs)
Definition: expr.c:7991
static SCIP_RETCODE exprsimplifyConvertToPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4232
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprgraphAddNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int mindepth, int nchildren, SCIP_EXPRGRAPHNODE **children)
Definition: expr.c:14923
void SCIPintervalSign(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define QUADELEMS_ISBETTER(a, b)
Definition: expr.c:8908
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:4256
SCIP_RETCODE SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16513
SCIP_RETCODE SCIPexprtreeEvalInt(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_INTERVAL *val)
Definition: expr.c:8579
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:15007
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:8596
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5800
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:14513
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:3735
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1567
SCIP_Bool constssorted
Definition: struct_expr.h:173
static SCIP_RETCODE exprgraphNodeAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nexprs, SCIP_EXPRGRAPHNODE **exprs, int *childmap)
Definition: expr.c:9300
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12733
static SCIP_RETCODE exprgraphNodeCreateExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPR **expr, int *nexprvars, int *varidx)
Definition: expr.c:11567
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5573
struct SCIP_UserExprData SCIP_USEREXPRDATA
Definition: type_expr.h:219
void SCIPexprPrint(SCIP_EXPR *expr, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, const char **paramnames, SCIP_Real *paramvals)
Definition: expr.c:8071
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14693
static SCIP_RETCODE exprgraphEnsureDepth(SCIP_EXPRGRAPH *exprgraph, int mindepth)
Definition: expr.c:11830
void SCIPsortPtrPtrRealInt(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_MAXSTRLEN
Definition: def.h:201
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:11241
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_VARTYPE_INTEGER_CHAR
Definition: def.h:99
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
SCIP_Real * exponents
Definition: struct_expr.h:95
#define SCIP_DECL_USEREXPREVAL(x)
Definition: type_expr.h:246
#define NULL
Definition: lpi_spx.cpp:130
int SCIPexprgraphGetDepth(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14663
static SCIP_RETCODE polynomialdataMultiplyByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *factordata, int *childmap)
Definition: expr.c:982
static SCIP_RETCODE exprparseFindSeparatingComma(const char *str, const char **endptr, int length)
Definition: expr.c:5023
static SCIP_RETCODE exprgraphNodeRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11172
const char * SCIPexpropGetName(SCIP_EXPROP op)
Definition: expr.c:3237
SCIP_RETCODE SCIPexprgraphCreateNodeUser(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_USEREXPRDATA *data, SCIP_EXPRINTCAPABILITY evalcapability, SCIP_DECL_USEREXPREVAL((*eval)), SCIP_DECL_USEREXPRINTEVAL((*inteval)), SCIP_DECL_USEREXPRCURV((*curv)), SCIP_DECL_USEREXPRPROP((*prop)), SCIP_DECL_USEREXPRESTIMATE((*estimate)), SCIP_DECL_USEREXPRCOPYDATA((*copydata)), SCIP_DECL_USEREXPRFREEDATA((*freedata)))
Definition: expr.c:13294
void SCIPexprChgPolynomialConstant(SCIP_EXPR *expr, SCIP_Real constant)
Definition: expr.c:6567
SCIP_RETCODE SCIPexprgraphAddConst(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15080
SCIP_RETCODE SCIPexprtreeGetMaxDegree(SCIP_EXPRTREE *tree, int *maxdegree)
Definition: expr.c:8550
SCIP_Real * SCIPexprtreeGetParamVals(SCIP_EXPRTREE *tree)
Definition: expr.c:8472
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:14767
SCIP_RETCODE SCIPexprCreateMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial, SCIP_Real coef, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:6913
void SCIPexprgraphCaptureNode(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12711
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:13224
static SCIP_DECL_EXPRFREEDATA(exprFreeDataLinear)
Definition: expr.c:2519
SCIP_Real SCIPexprGetRealPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5636
SCIP_EXPROP op
Definition: struct_expr.h:48
int SCIPexprGetOpIndex(SCIP_EXPR *expr)
Definition: expr.c:5603
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:7665
SCIP_RETCODE SCIPexprPolynomialPower(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int exponent)
Definition: expr.c:6663
void SCIPexprChgMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real newcoef)
Definition: expr.c:6729
SCIP_Bool SCIPexprHasParam(SCIP_EXPR *expr)
Definition: expr.c:7089
SCIPInterval cos(const SCIPInterval &x)
#define BMSclearMemory(ptr)
Definition: memory.h:84
SCIP_Real SCIPexprGetPolynomialConstant(SCIP_EXPR *expr)
Definition: expr.c:5768
SCIP_EXPRBOUNDSTATUS boundstatus
Definition: struct_expr.h:137
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
void SCIPexprgraphPropagateNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:15640
#define FALSE
Definition: def.h:56
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:2057
#define EPSROUND(x, eps)
Definition: def.h:162
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT
Definition: type_expr.h:212
SCIP_Bool SCIPexprAreEqual(SCIP_EXPR *expr1, SCIP_EXPR *expr2, SCIP_Real eps)
Definition: expr.c:7456
void SCIPexprMonomialPower(SCIP_EXPRDATA_MONOMIAL *monomial, int exponent)
Definition: expr.c:6804
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14713
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:8455
static void exprgraphNodeCheckSeparabilityComponent(SCIP_EXPRGRAPHNODE *node, int *compnr, int nchildcomps, int *childcomps, int nvars, int *varcomps)
Definition: expr.c:11770
static SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11114
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12862
#define TRUE
Definition: def.h:55
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:3266
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:5055
#define SCIP_CALL(x)
Definition: def.h:266
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:8652
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12753
void SCIPexprGetVarsUsage(SCIP_EXPR *expr, int *varsusage)
Definition: expr.c:7433
void SCIPintervalMin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_INTERVAL SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13085
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15565
void SCIPexprReindexVars(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8029
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
#define SCIP_DECL_USEREXPRINTEVAL(x)
Definition: type_expr.h:259
void SCIPintervalPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int * SCIPexprgraphGetNNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14673
SCIP_RETCODE SCIPexprEvalInt(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7797
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:8214
void SCIPexprSortMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:6994
static void polynomialdataApplyChildmap(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int *childmap)
Definition: expr.c:1141
#define SCIPdebugMessage
Definition: pub_message.h:77
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
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:3190
#define SIGN(x)
Definition: expr.c:45
#define BMSduplicateBlockMemory(mem, ptr, source)
Definition: memory.h:414
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15127
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2116
SCIP_RETCODE SCIPexprMultiplyMonomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6769
SCIP_RETCODE SCIPexprCreateUser(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_USEREXPRDATA *data, SCIP_EXPRINTCAPABILITY evalcapability, SCIP_DECL_USEREXPREVAL((*eval)), SCIP_DECL_USEREXPRINTEVAL((*inteval)), SCIP_DECL_USEREXPRCURV((*curv)), SCIP_DECL_USEREXPRPROP((*prop)), SCIP_DECL_USEREXPRESTIMATE((*estimate)), SCIP_DECL_USEREXPRCOPYDATA((*copydata)), SCIP_DECL_USEREXPRFREEDATA((*freedata)))
Definition: expr.c:7031
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8611
SCIP_Bool SCIPquadelemSortedFind(SCIP_QUADELEM *quadelems, int idx1, int idx2, int nquadelems, int *pos)
Definition: expr.c:9055
unsigned int SCIP_EXPRINTCAPABILITY
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8482
BMS_BLKMEM * blkmem
Definition: struct_expr.h:156
SCIP_EXPRCURV curv
Definition: struct_expr.h:143
SCIP_EXPR * root
Definition: struct_expr.h:58
#define exprevalIntTan
Definition: expr.c:2099
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:14874
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12956
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:9841
#define SCIP_EXPRESSION_MAXCHILDEST
Definition: expr.c:39
static void exprgraphUpdateVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Bool *clearreverseprop, SCIP_Bool *boundchanged)
Definition: expr.c:12598
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:14158
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:5744
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:1480
static SCIP_DECL_EXPREVAL(exprevalVar)
Definition: expr.c:1410
#define EPSISINT(x, eps)
Definition: def.h:164
public methods for expressions, expression trees, expression graphs, and related stuff ...
SCIP_EXPRCURV SCIPexprcurvMultiply(SCIP_Real factor, SCIP_EXPRCURV curvature)
Definition: expr.c:223
int SCIPexprGetMonomialNFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5790
int SCIPexprGetIntPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5647
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2159
#define SCIP_EXPRINTCAPABILITY_INTFUNCVALUE
SCIP_RETCODE SCIPexprtreeCheckCurvature(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:8840
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12793
static SCIP_RETCODE exprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op, SCIP_EXPROPDATA opdata)
Definition: expr.c:9541
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12944
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:14835
#define SCIP_ALLOC_ABORT(x)
Definition: def.h:256
#define SCIP_DECL_EXPRGRAPHVARADDED(x)
Definition: type_expr.h:181
SCIP_HASHMAP * varidxs
Definition: struct_expr.h:168
int SCIPexprgraphGetNodeOperatorIndex(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12803
SCIP_Real coef
Definition: type_expr.h:102
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:12884
#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:416
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12968
SCIP_RETCODE SCIPexprAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:6545
SCIP_Bool SCIPexprgraphHasNodeNonlinearAncestor(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14398
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13105
SCIP_Bool simplified
Definition: struct_expr.h:147
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:6462
SCIP_Bool SCIPexprgraphFindConstNode(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15468
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:7736
void SCIPexprgraphSetVarsBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_INTERVAL *varbounds)
Definition: expr.c:14735
union SCIP_ExprOpData SCIP_EXPROPDATA
Definition: type_expr.h:90
static SCIP_Bool isUbBetter(SCIP_Real minstrength, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:152
SCIP_RETCODE SCIPexprgraphCheckCurvature(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop)
Definition: expr.c:15672
SCIP_RETCODE SCIPexprGetMaxDegree(SCIP_EXPR *expr, int *maxdegree)
Definition: expr.c:7108
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:89
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:5720
SCIP_EXPRGRAPHNODE *** SCIPexprgraphGetNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14683
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16477
SCIP_INTERVAL bounds
Definition: struct_expr.h:136
static SCIP_RETCODE exprsimplifyRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4310
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:6019
static const char * curvnames[4]
Definition: expr.c:177
int SCIPcalcHashtableSize(int minsize)
Definition: misc.c:1157
SCIPInterval sqrt(const SCIPInterval &x)
SCIP_Bool SCIPexprgraphHasNodeUserEstimator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13073
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:5707
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2075
static SCIP_RETCODE exprgraphNodeReplaceChild(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE **oldchild, SCIP_EXPRGRAPHNODE *newchild)
Definition: expr.c:9401
void SCIPmessagePrintWarning(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:411
SCIP_EXPRGRAPHNODE *** nodes
Definition: struct_expr.h:161
#define EXPROPEMPTY
Definition: expr.c:3186
#define EPSFLOOR(x, eps)
Definition: def.h:160
#define EPSLT(x, y, eps)
Definition: def.h:153
static SCIP_Bool exprgraphNodeIsParent(SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9269
static void polynomialdataFree(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata)
Definition: expr.c:695
void SCIPexprMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:6683
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:8452
SCIP_Bool SCIPexprAreMonomialsEqual(SCIP_EXPRDATA_MONOMIAL *monomial1, SCIP_EXPRDATA_MONOMIAL *monomial2, SCIP_Real eps)
Definition: expr.c:6698
SCIP_EXPRGRAPHNODE ** varnodes
Definition: struct_expr.h:166
SCIP_RETCODE SCIPexprgraphCreateNodeLinear(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int ncoefs, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:13198
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16027
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12723
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14827
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:8381
#define EPSGT(x, y, eps)
Definition: def.h:155
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:6510
SCIP_RETCODE SCIPexprCheckCurvature(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_Real *param, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:7895
SCIP_RETCODE SCIPexprEvalUser(SCIP_EXPR *expr, SCIP_Real *argvals, SCIP_Real *val, SCIP_Real *gradient, SCIP_Real *hessian)
Definition: expr.c:7839
SCIP_Real sup
Definition: intervalarith.h:39
void SCIPmessagePrintInfo(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:578
SCIP_RETCODE SCIPexprEvalShallow(SCIP_EXPR *expr, SCIP_Real *argvals, SCIP_Real *varvals, SCIP_Real *param, SCIP_Real *val)
Definition: expr.c:7717
void SCIPexprMultiplyPolynomialByConstant(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real factor)
Definition: expr.c:6580
void SCIPintervalSet(SCIP_INTERVAL *resultant, SCIP_Real value)
void SCIPexprgraphTightenNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_INTERVAL nodebounds, SCIP_Real minstrength, SCIP_Real infinity, SCIP_Bool *cutoff)
Definition: expr.c:14451
static SCIP_RETCODE exprsimplifyUnconvertPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4857
SCIP_RETCODE SCIPexprEstimateUser(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_Real *argvals, SCIP_INTERVAL *argbounds, SCIP_Bool overestimate, SCIP_Real *coeffs, SCIP_Real *constant, SCIP_Bool *success)
Definition: expr.c:7953
static SCIP_RETCODE exprgraphNodeUpdateBounds(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool parenttightenisinvalid)
Definition: expr.c:9948
#define SCIP_DECL_USEREXPRCURV(x)
Definition: type_expr.h:270
void SCIPexprFreeMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial)
Definition: expr.c:6970
SCIP_RETCODE SCIPexprMulConstant(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPR *term, SCIP_Real factor)
Definition: expr.c:6282
SCIP_EXPR * SCIPexprtreeGetRoot(SCIP_EXPRTREE *tree)
Definition: expr.c:8442
SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
SCIP_Bool SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14363
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:12983
#define SCIP_DECL_USEREXPRESTIMATE(x)
Definition: type_expr.h:234
#define SCIP_DECL_USEREXPRPROP(x)
Definition: type_expr.h:282
SCIP_Real SCIPexprgraphGetNodeOperatorReal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12814
#define SCIP_EXPRBOUNDSTATUS_VALID
Definition: type_expr.h:209
SCIP_RETCODE SCIPexprAdd(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_Real coef1, SCIP_EXPR *term1, SCIP_Real coef2, SCIP_EXPR *term2, SCIP_Real constant)
Definition: expr.c:6124
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12896
SCIP_RETCODE SCIPexprMultiplyPolynomialByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR *factor, int *childmap)
Definition: expr.c:6617
void SCIPexprMergeMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real eps)
Definition: expr.c:6834
SCIP_EXPRINTCAPABILITY SCIPexprGetUserEvalCapability(SCIP_EXPR *expr)
Definition: expr.c:5842
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:5593
SCIP_Real SCIPexprGetSignPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5658
SCIP_EXPRGRAPHNODE ** children
Definition: struct_expr.h:127
#define SCIP_Bool
Definition: def.h:53
void ** vars
Definition: struct_expr.h:60
SCIP_Bool needvarboundprop
Definition: struct_expr.h:180
static SCIP_RETCODE exprgraphNodeEval(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:9883
SCIP_USEREXPRDATA * userdata
Definition: struct_expr.h:103
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14382
SCIPInterval sin(const SCIPInterval &x)
#define BMSallocBlockMemoryArray(mem, ptr, num)
Definition: memory.h:408
void SCIPexprSortQuadElems(SCIP_EXPR *expr)
Definition: expr.c:6498
static SCIP_RETCODE monomialdataEnsureFactorsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomialdata, int minsize)
Definition: expr.c:586
#define EPSZ(x, eps)
Definition: def.h:157
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:14787
static SCIP_RETCODE exprsimplifyFlattenPolynomials(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR *expr, SCIP_Real eps, int maxexpansionexponent)
Definition: expr.c:4427
static SCIP_RETCODE exprgraphNodeRemoveParent(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9218
BMS_BLKMEM * blkmem
Definition: struct_expr.h:57
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8497
SCIP_RETCODE SCIPexprtreeFreeInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8520
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:9107
SCIP_Bool SCIPexprHasUserEstimator(SCIP_EXPR *expr)
Definition: expr.c:5831
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:8245
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:167
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:5583
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:16461
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:14807
static SCIP_Bool exprgraphFindConstNodePos(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *pos)
Definition: expr.c:9486
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:13346
SCIP_RETCODE SCIPexprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op,...)
Definition: expr.c:5853
void SCIPintervalScalprodScalars(SCIP_Real infinity, SCIP_INTERVAL *resultant, int length, SCIP_INTERVAL *operand1, SCIP_Real *operand2)
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:419
SCIP_RETCODE SCIPexprtreeFree(SCIP_EXPRTREE **tree)
Definition: expr.c:8692
SCIP_Bool SCIPexprFindMonomialFactor(SCIP_EXPRDATA_MONOMIAL *monomial, int childidx, int *pos)
Definition: expr.c:7014
static SCIP_DECL_EXPRINTEVAL(exprevalIntDefault)
Definition: expr.c:1392
void SCIPexprgraphFreeNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14280
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define EPSGE(x, y, eps)
Definition: def.h:156
static void exprgraphNodePropagateBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:10041
#define SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED
Definition: type_expr.h:210
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14332
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:89
SCIPInterval log(const SCIPInterval &x)
SCIP_USEREXPRDATA * SCIPexprGetUserData(SCIP_EXPR *expr)
Definition: expr.c:5820
SCIP_RETCODE SCIPexprtreeAddExpr(SCIP_EXPRTREE *tree, SCIP_EXPR *expr, SCIP_Bool copyexpr)
Definition: expr.c:8817
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:1627
#define SCIP_EXPR_DEGREEINFINITY
Definition: type_expr.h:114
SCIP_EXPROPDATA data
Definition: struct_expr.h:119
SCIP_EXPRGRAPHNODE ** parents
Definition: struct_expr.h:132
void SCIPintervalAbs(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_Real SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5780
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:12825
void * SCIPexprGetOpData(SCIP_EXPR *expr)
Definition: expr.c:5625
SCIP_EXPROP op
Definition: struct_expr.h:118
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12908
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:1510
#define SCIP_REAL_MAX
Definition: def.h:128
static SCIP_RETCODE exprConvertToPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren)
Definition: expr.c:3297
SCIP_Real SCIPgetRandomReal(SCIP_Real minrandval, SCIP_Real maxrandval, unsigned int *seedp)
Definition: misc.c:7719
SCIP_RETCODE SCIPexprEvalIntUser(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *val, SCIP_INTERVAL *gradient, SCIP_INTERVAL *hessian)
Definition: expr.c:7862
int SCIPexprgraphGetNodeIntPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12851
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12763
SCIP_QUADELEM * quadelems
Definition: struct_expr.h:71
static void exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:9192
#define SCIP_DECL_EXPRGRAPHVARREMOVE(x)
Definition: type_expr.h:191
static SCIP_RETCODE exprgraphAddExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPR *expr, void **vars, SCIP_Real *params, SCIP_EXPRGRAPHNODE **exprnode, SCIP_Bool *exprnodeisnew)
Definition: expr.c:12466
static SCIP_RETCODE polynomialdataAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:741
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:93
int SCIPexpropGetNChildren(SCIP_EXPROP op)
Definition: expr.c:3247
static void quadraticdataSort(SCIP_EXPRDATA_QUADRATIC *quadraticdata)
Definition: expr.c:511
#define SCIP_VARTYPE_IMPLINT_CHAR
Definition: def.h:100
SCIP_EXPRINTDATA * interpreterdata
Definition: struct_expr.h:63
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2177
#define exprcurvCos
Definition: expr.c:2084
SCIP_Bool SCIPexprgraphFindVarNode(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_EXPRGRAPHNODE **varnode)
Definition: expr.c:15439
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8050
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12873
#define SCIP_EXPRINTCAPABILITY_FUNCVALUE
SCIP_Real * SCIPexprGetLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5669
SCIP_Bool SCIPexprtreeHasParam(SCIP_EXPRTREE *tree)
Definition: expr.c:8534
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Real SCIPexprGetOpReal(SCIP_EXPR *expr)
Definition: expr.c:5614
#define REALABS(x)
Definition: def.h:151
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12783
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:13275
SCIP_Bool parentssorted
Definition: struct_expr.h:133
#define SCIP_VARTYPE_CONTINUOUS_CHAR
Definition: def.h:101
SCIP_EXPRGRAPHNODE ** constnodes
Definition: struct_expr.h:172
void SCIPexprFreeShallow(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6099
SCIP_QUADELEM * SCIPexprGetQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5695
SCIP_RETCODE SCIPexprgraphCreateNodePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:13250
void SCIPintervalExp(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
public methods for message output
SCIP_USEREXPRDATA * SCIPexprgraphGetNodeUserData(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13061
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:4756
SCIP_RETCODE SCIPexprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op,...)
Definition: expr.c:13115
SCIP_RETCODE SCIPexprEvalIntShallow(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7777
SCIP_RETCODE SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14190
int SCIPexprGetNMonomials(SCIP_EXPR *expr)
Definition: expr.c:5756
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE
Definition: type_expr.h:214
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:2137
SCIP_RETCODE SCIPexprtreeSimplify(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:8766
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:15974
#define SCIP_DECL_USEREXPRCOPYDATA(x)
Definition: type_expr.h:291
#define SCIP_Real
Definition: def.h:127
#define MIN(x, y)
Definition: memory.c:67
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:12743
#define SCIP_INVALID
Definition: def.h:147
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:6740
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5810
void SCIPexprgraphPrintNode(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: expr.c:14435
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:8866
#define SCIPisFinite(x)
Definition: pub_misc.h:5428
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:9927
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:98
int SCIPexprtreeGetNParams(SCIP_EXPRTREE *tree)
Definition: expr.c:8462
SCIP_RETCODE SCIPexprgraphSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange, SCIP_Bool *domainerror)
Definition: expr.c:15715
int SCIP_ROUNDMODE
Definition: intervalarith.h:45
static SCIP_RETCODE exprsimplifyRemovePolynomialUnusedChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4376
#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:11910
static SCIP_RETCODE exprparseFindClosingParenthesis(const char *str, const char **endptr, int length)
Definition: expr.c:4984
SCIP_RETCODE SCIPexprAddToLinear(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nchildren, SCIP_Real *coefs, SCIP_EXPR **children, SCIP_Real constant)
Definition: expr.c:6417
#define EPSLE(x, y, eps)
Definition: def.h:154
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:4113
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_RETCODE SCIPexprMultiplyPolynomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6594
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12840
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:78
#define EPSEQ(x, y, eps)
Definition: def.h:152
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2094
static SCIP_DECL_HASHGETKEY(exprparseVarTableGetKey)
Definition: expr.c:4881
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:392
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12932
static SCIP_RETCODE polynomialdataPower(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int exponent)
Definition: expr.c:1071
#define SCIP_CALL_ABORT(x)
Definition: def.h:245
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14703
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT
Definition: type_expr.h:213
SCIP_RETCODE SCIPexprCreateLinear(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:6380
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_ALLOC(x)
Definition: def.h:277
#define SCIPABORT()
Definition: def.h:238
SCIP_Real SCIPexprGetLinearConstant(SCIP_EXPR *expr)
Definition: expr.c:5682
void SCIPexprtreeSetInterpreterData(SCIP_EXPRTREE *tree, SCIP_EXPRINTDATA *interpreterdata)
Definition: expr.c:8507
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:8920
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:8716
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
int SCIPexprGetNQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5732
static void exprgraphPrintNodeExpression(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, SCIP_Bool printchildrenbounds)
Definition: expr.c:9585
#define SCIP_DECL_USEREXPRFREEDATA(x)
Definition: type_expr.h:299
#define QUADELEMS_SWAP(x, y)
Definition: expr.c:8911
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:11998
static void exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:11745
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15516
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:412
void SCIPintervalSetRoundingModeDownwards(void)
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:12773
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:8563
SCIP_EXPRINTCAPABILITY evalcapability
Definition: struct_expr.h:104
void SCIPexprgraphSetVarBounds(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_INTERVAL varbounds)
Definition: expr.c:14747
#define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize)
Definition: expr.c:51
void SCIPsortIntReal(int *intarray, SCIP_Real *realarray, int len)
static SCIP_RETCODE exprgraphRemoveVar(SCIP_EXPRGRAPH *exprgraph, int varidx)
Definition: expr.c:11857
#define SCIP_DECL_EXPRGRAPHVARCHGIDX(x)
Definition: type_expr.h:203
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
void SCIPexprgraphEnableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14305
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12920