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-2015 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_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
12471  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12472  )
12473 {
12474  SCIP_EXPRGRAPHNODE** childnodes;
12475  SCIP_Bool childisnew;
12476  SCIP_Bool nochildisnew;
12477  SCIP_EXPROPDATA opdata;
12478  int i;
12479 
12480  assert(exprgraph != NULL);
12481  assert(expr != NULL);
12482  assert(exprnode != NULL);
12483  assert(exprnodeisnew != NULL);
12484 
12485  if( expr->op == SCIP_EXPR_VARIDX )
12486  {
12487  /* find node corresponding to variable and add if not existing yet */
12488  assert(expr->nchildren == 0);
12489 
12490  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12491  assert(*exprnode != NULL);
12492  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12493  assert((*exprnode)->data.intval >= 0);
12494  assert((*exprnode)->data.intval < exprgraph->nvars);
12495  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12496 
12497  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12498 
12499  return SCIP_OKAY;
12500  }
12501 
12502  if( expr->op == SCIP_EXPR_CONST )
12503  {
12504  /* find node corresponding to constant and add if not existing yet */
12505  assert(expr->nchildren == 0);
12506 
12507  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12508  assert(*exprnode != NULL);
12509  assert((*exprnode)->op == SCIP_EXPR_CONST);
12510  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
12511 
12512  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12513 
12514  return SCIP_OKAY;
12515  }
12516 
12517  /* expression should be variable or constant or have children, i.e., parameters are not allowed here (so far) */
12518  assert(expr->nchildren > 0);
12519 
12520  /* add children expressions into expression graph
12521  * check if we can find a common parent
12522  */
12523  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12524  nochildisnew = TRUE;
12525  for( i = 0; i < expr->nchildren; ++i )
12526  {
12527  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, &childnodes[i], &childisnew) ); /*lint !e644*/
12528  assert(childnodes[i] != NULL);
12529  nochildisnew &= !childisnew; /*lint !e514*/
12530  }
12531 
12532  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12533  if( nochildisnew )
12534  {
12535  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12536 
12537  if( *exprnode != NULL )
12538  {
12539  /* node already existing, make sure it is enabled */
12540  (*exprnode)->enabled = TRUE;
12541  *exprnodeisnew = FALSE;
12542 
12543  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12544  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12545  * SCIPdebugPrintf("\n");
12546  */
12547 
12548  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12549  return SCIP_OKAY;
12550  }
12551  }
12552 
12553  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12554 
12555  /* copy expression data */
12556  if( exprOpTable[expr->op].copydata != NULL )
12557  {
12558  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12559  }
12560  else
12561  {
12562  opdata = expr->data;
12563  }
12564 
12565  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12566  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12567  *exprnodeisnew = TRUE;
12568 
12569  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12570 
12571  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12572  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12573  * SCIPdebugPrintf("\n");
12574  */
12575 
12576  return SCIP_OKAY;
12577 }
12578 
12579 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12580 static
12582  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12583  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12584  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12585  )
12586 {
12587  SCIP_EXPRGRAPHNODE* node;
12588  int i;
12589  int p;
12590 
12591  assert(exprgraph != NULL);
12592  assert(clearreverseprop != NULL);
12593  assert(boundchanged != NULL);
12594 
12595  *boundchanged = FALSE;
12596  for( i = 0; i < exprgraph->nvars; ++i )
12597  {
12598  node = exprgraph->varnodes[i];
12599 
12600  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12601  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12602  {
12604  continue;
12605  }
12606 
12607  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12608  {
12609  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12610  SCIP_Real tmp;
12611 
12612  tmp = exprgraph->varbounds[i].inf;
12613  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12614  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12615  }
12616 
12617  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12618  +exprgraph->varbounds[i].sup > node->bounds.sup )
12619  {
12620  for( p = 0; p < node->nparents; ++p )
12622 
12623  node->bounds = exprgraph->varbounds[i];
12624  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12625 
12626  *boundchanged = TRUE;
12627 
12628  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12629  *clearreverseprop = TRUE;
12630  }
12631  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12632  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12633  {
12634  for( p = 0; p < node->nparents; ++p )
12636 
12637  node->bounds = exprgraph->varbounds[i];
12638  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12639 
12640  *boundchanged = TRUE;
12641  }
12642  else
12643  {
12644  node->bounds = exprgraph->varbounds[i];
12645  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12646  }
12647 
12649  }
12650 }
12651 
12652 /**@} */
12653 
12654 /**@name Expression graph node methods */
12655 /**@{ */
12656 
12657 /* In debug mode, the following methods are implemented as function calls to ensure
12658  * type validity.
12659  * In optimized mode, the methods are implemented as defines to improve performance.
12660  * However, we want to have them in the library anyways, so we have to undef the defines.
12661  */
12662 
12663 #undef SCIPexprgraphCaptureNode
12664 #undef SCIPexprgraphIsNodeEnabled
12665 #undef SCIPexprgraphGetNodeNChildren
12666 #undef SCIPexprgraphGetNodeChildren
12667 #undef SCIPexprgraphGetNodeNParents
12668 #undef SCIPexprgraphGetNodeParents
12669 #undef SCIPexprgraphGetNodeDepth
12670 #undef SCIPexprgraphGetNodePosition
12671 #undef SCIPexprgraphGetNodeOperator
12672 #undef SCIPexprgraphGetNodeOperatorIndex
12673 #undef SCIPexprgraphGetNodeOperatorReal
12674 #undef SCIPexprgraphGetNodeVar
12675 #undef SCIPexprgraphGetNodeRealPowerExponent
12676 #undef SCIPexprgraphGetNodeIntPowerExponent
12677 #undef SCIPexprgraphGetNodeSignPowerExponent
12678 #undef SCIPexprgraphGetNodeLinearCoefs
12679 #undef SCIPexprgraphGetNodeLinearConstant
12680 #undef SCIPexprgraphGetNodeQuadraticConstant
12681 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12682 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12683 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12684 #undef SCIPexprgraphGetNodePolynomialMonomials
12685 #undef SCIPexprgraphGetNodePolynomialNMonomials
12686 #undef SCIPexprgraphGetNodePolynomialConstant
12687 #undef SCIPexprgraphGetNodeUserData
12688 #undef SCIPexprgraphHasNodeUserEstimator
12689 #undef SCIPexprgraphGetNodeBounds
12690 #undef SCIPexprgraphGetNodeVal
12691 #undef SCIPexprgraphGetNodeCurvature
12692 
12693 /** captures node, i.e., increases number of uses */
12695  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12696  )
12697 {
12698  assert(node->nuses >= 0);
12699 
12700  SCIPdebugMessage("capture node %p\n", (void*)node);
12701 
12702  ++node->nuses;
12703 }
12704 
12705 /** returns whether a node is currently enabled */
12707  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12708  )
12709 {
12710  assert(node != NULL);
12711 
12712  return node->enabled;
12713 }
12714 
12715 /** gets number of children of a node in an expression graph */
12717  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12718  )
12719 {
12720  assert(node != NULL);
12721 
12722  return node->nchildren;
12723 }
12724 
12725 /** gets children of a node in an expression graph */
12727  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12728  )
12729 {
12730  assert(node != NULL);
12731 
12732  return node->children;
12733 }
12734 
12735 /** gets number of parents of a node in an expression graph */
12737  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12738  )
12739 {
12740  assert(node != NULL);
12741 
12742  return node->nparents;
12743 }
12744 
12745 /** gets parents of a node in an expression graph */
12747  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12748  )
12749 {
12750  assert(node != NULL);
12751 
12752  return node->parents;
12753 }
12754 
12755 /** gets depth of node in expression graph */
12757  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12758  )
12759 {
12760  assert(node != NULL);
12761 
12762  return node->depth;
12763 }
12764 
12765 /** gets position of node in expression graph at its depth level */
12767  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12768  )
12769 {
12770  assert(node != NULL);
12771 
12772  return node->pos;
12773 }
12774 
12775 /** gets operator of a node in an expression graph */
12777  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12778  )
12779 {
12780  assert(node != NULL);
12781 
12782  return node->op;
12783 }
12784 
12785 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
12787  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12788  )
12789 {
12790  assert(node != NULL);
12791  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
12792 
12793  return node->data.intval;
12794 }
12795 
12796 /** gives real belonging to a SCIP_EXPR_CONST operand */
12798  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12799  )
12800 {
12801  assert(node != NULL);
12802  assert(node->op == SCIP_EXPR_CONST);
12803 
12804  return node->data.dbl;
12805 }
12806 
12807 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
12809  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12810  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12811  )
12812 {
12813  assert(exprgraph != NULL);
12814  assert(node != NULL);
12815  assert(node->op == SCIP_EXPR_VARIDX);
12816  assert(node->data.intval >= 0);
12817  assert(node->data.intval < exprgraph->nvars);
12818 
12819  return exprgraph->vars[node->data.intval];
12820 }
12821 
12822 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
12824  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12825  )
12826 {
12827  assert(node != NULL);
12828  assert(node->op == SCIP_EXPR_REALPOWER);
12829 
12830  return node->data.dbl;
12831 }
12832 
12833 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
12835  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12836  )
12837 {
12838  assert(node != NULL);
12839  assert(node->op == SCIP_EXPR_INTPOWER);
12840 
12841  return node->data.intval;
12842 }
12843 
12844 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
12846  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12847  )
12848 {
12849  assert(node != NULL);
12850  assert(node->op == SCIP_EXPR_SIGNPOWER);
12851 
12852  return node->data.dbl;
12853 }
12854 
12855 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
12857  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12858  )
12859 {
12860  assert(node != NULL);
12861  assert(node->op == SCIP_EXPR_LINEAR);
12862 
12863  return (SCIP_Real*)node->data.data;
12864 }
12865 
12866 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
12868  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12869  )
12870 {
12871  assert(node != NULL);
12872  assert(node->op == SCIP_EXPR_LINEAR);
12873  assert(node->data.data != NULL);
12874 
12875  return ((SCIP_Real*)node->data.data)[node->nchildren];
12876 }
12877 
12878 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
12880  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12881  )
12882 {
12883  assert(node != NULL);
12884  assert(node->op == SCIP_EXPR_QUADRATIC);
12885  assert(node->data.data != NULL);
12886 
12887  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
12888 }
12889 
12890 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
12892  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12893  )
12894 {
12895  assert(node != NULL);
12896  assert(node->op == SCIP_EXPR_QUADRATIC);
12897  assert(node->data.data != NULL);
12898 
12899  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
12900 }
12901 
12902 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
12904  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12905  )
12906 {
12907  assert(node != NULL);
12908  assert(node->op == SCIP_EXPR_QUADRATIC);
12909  assert(node->data.data != NULL);
12910 
12911  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
12912 }
12913 
12914 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
12916  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12917  )
12918 {
12919  assert(node != NULL);
12920  assert(node->op == SCIP_EXPR_QUADRATIC);
12921  assert(node->data.data != NULL);
12922 
12923  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
12924 }
12925 
12926 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
12928  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12929  )
12930 {
12931  assert(node != NULL);
12932  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12933  assert(node->data.data != NULL);
12934 
12935  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
12936 }
12937 
12938 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
12940  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12941  )
12942 {
12943  assert(node != NULL);
12944  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12945  assert(node->data.data != NULL);
12946 
12947  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
12948 }
12949 
12950 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
12952  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12953  )
12954 {
12955  assert(node != NULL);
12956  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12957  assert(node->data.data != NULL);
12958 
12959  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
12960 }
12961 
12962 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
12963  *
12964  * Assumes that curvature of children and bounds of children and node itself are valid.
12965  */
12967  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
12968  int monomialidx, /**< index of monomial */
12969  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
12970  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
12971  )
12972 {
12973  SCIP_EXPRDATA_MONOMIAL* monomial;
12974  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
12975  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
12976  SCIP_INTERVAL* childbounds;
12977  SCIP_EXPRCURV* childcurv;
12978  SCIP_EXPRGRAPHNODE* child;
12979  int i;
12980 
12981  assert(node != NULL);
12982  assert(node->depth >= 0); /* node should be in graph */
12983  assert(node->pos >= 0); /* node should be in graph */
12984  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
12985  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
12986  assert(node->op == SCIP_EXPR_POLYNOMIAL);
12987  assert(node->data.data != NULL);
12988  assert(monomialidx >= 0);
12989  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
12990  assert(curv != NULL);
12991 
12992  if( SCIPintervalIsEmpty(infinity, node->bounds) )
12993  {
12994  *curv = SCIP_EXPRCURV_LINEAR;
12995  return SCIP_OKAY;
12996  }
12997 
12998  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
12999  assert(monomial != NULL);
13000 
13001  /* if many children, get large enough memory to store children bounds */
13002  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13003  {
13004  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13005  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, monomial->nfactors) );
13006  }
13007  else
13008  {
13009  childbounds = childboundsstatic;
13010  childcurv = childcurvstatic;
13011  }
13012 
13013  /* assemble bounds and curvature of children */
13014  for( i = 0; i < monomial->nfactors; ++i )
13015  {
13016  child = node->children[monomial->childidxs[i]];
13017  assert(child != NULL);
13018 
13019  /* child should have valid and non-empty bounds */
13020  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13021  assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13022  /* nodes at depth 0 are always linear */
13023  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13024 
13025  childbounds[i] = child->bounds; /*lint !e644*/
13026  childcurv[i] = child->curv; /*lint !e644*/
13027  }
13028 
13029  /* check curvature */
13030  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13031  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13032 
13033  /* free memory, if allocated before */
13034  if( childbounds != childboundsstatic )
13035  {
13036  BMSfreeMemoryArray(&childbounds);
13037  BMSfreeMemoryArray(&childcurv);
13038  }
13039 
13040  return SCIP_OKAY;
13041 }
13042 
13043 /** gives the user data belonging to a SCIP_EXPR_USER expression */
13045  SCIP_EXPRGRAPHNODE* node
13046  )
13047 {
13048  assert(node != NULL);
13049  assert(node->op == SCIP_EXPR_USER);
13050  assert(node->data.data != NULL);
13051 
13052  return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13053 }
13054 
13055 /** indicates whether a user expression has the estimator callback defined */
13057  SCIP_EXPRGRAPHNODE* node
13058  )
13059 {
13060  assert(node != NULL);
13061  assert(node->op == SCIP_EXPR_USER);
13062  assert(node->data.data != NULL);
13063 
13064  return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13065 }
13066 
13067 /** gets bounds of a node in an expression graph */
13069  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13070  )
13071 {
13072  assert(node != NULL);
13073 
13074  return node->bounds;
13075 }
13076 
13077 /** gets value of expression associated to node from last evaluation call */
13079  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13080  )
13081 {
13082  assert(node != NULL);
13083 
13084  return node->value;
13085 }
13086 
13087 /** gets curvature of expression associated to node from last curvature check call */
13089  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13090  )
13091 {
13092  assert(node != NULL);
13093 
13094  return node->curv;
13095 }
13096 
13097 /** creates an expression graph node */
13099  BMS_BLKMEM* blkmem, /**< block memory */
13100  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13101  SCIP_EXPROP op, /**< operator type of expression */
13102  ...
13103  )
13104 {
13105  va_list ap;
13106  SCIP_EXPROPDATA opdata;
13107 
13108  assert(blkmem != NULL);
13109  assert(node != NULL);
13110 
13111  *node = NULL;
13112 
13113  switch( op )
13114  {
13115  case SCIP_EXPR_VARIDX :
13116  case SCIP_EXPR_PARAM :
13117  case SCIP_EXPR_CONST :
13118  case SCIP_EXPR_LINEAR :
13119  case SCIP_EXPR_QUADRATIC :
13120  case SCIP_EXPR_POLYNOMIAL:
13121  case SCIP_EXPR_USER :
13122  {
13123  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
13124  SCIPABORT();
13125  return SCIP_ERROR; /*lint !e527*/
13126  }
13127 
13128  /* operands without data */
13129  case SCIP_EXPR_PLUS :
13130  case SCIP_EXPR_MINUS :
13131  case SCIP_EXPR_MUL :
13132  case SCIP_EXPR_DIV :
13133  case SCIP_EXPR_MIN :
13134  case SCIP_EXPR_MAX :
13135  case SCIP_EXPR_SQUARE :
13136  case SCIP_EXPR_SQRT :
13137  case SCIP_EXPR_EXP :
13138  case SCIP_EXPR_LOG :
13139  case SCIP_EXPR_SIN :
13140  case SCIP_EXPR_COS :
13141  case SCIP_EXPR_TAN :
13142  /* case SCIP_EXPR_ERF : */
13143  /* case SCIP_EXPR_ERFI: */
13144  case SCIP_EXPR_ABS :
13145  case SCIP_EXPR_SIGN :
13146  case SCIP_EXPR_SUM :
13147  case SCIP_EXPR_PRODUCT:
13148  opdata.data = NULL;
13149  break;
13150 
13151  case SCIP_EXPR_REALPOWER:
13152  case SCIP_EXPR_SIGNPOWER:
13153  {
13154  va_start(ap, op ); /*lint !e838*/
13155  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
13156  va_end( ap ); /*lint !e826*/
13157 
13158  break;
13159  }
13160 
13161  case SCIP_EXPR_INTPOWER:
13162  {
13163  va_start(ap, op ); /*lint !e838*/
13164  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
13165  va_end( ap ); /*lint !e826*/
13166 
13167  break;
13168  }
13169 
13170  case SCIP_EXPR_LAST:
13171  SCIPABORT();
13172  return SCIP_INVALIDDATA; /*lint !e527*/
13173  }
13174 
13175  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13176 
13177  return SCIP_OKAY;
13178 }
13179 
13180 /** creates an expression graph node for a linear expression */
13182  BMS_BLKMEM* blkmem, /**< block memory */
13183  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13184  int ncoefs, /**< number of coefficients */
13185  SCIP_Real* coefs, /**< coefficients of linear expression */
13186  SCIP_Real constant /**< constant of linear expression */
13187  )
13188 {
13189  SCIP_EXPROPDATA opdata;
13190  SCIP_Real* data;
13191 
13192  assert(blkmem != NULL);
13193  assert(node != NULL);
13194 
13195  /* we store the coefficients and the constant in a single array and make this our operand data */
13196  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13197  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
13198  data[ncoefs] = constant;
13199 
13200  opdata.data = data;
13201  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13202 
13203  return SCIP_OKAY;
13204 }
13205 
13206 /** creates an expression graph node for a quadratic expression */
13208  BMS_BLKMEM* blkmem, /**< block memory */
13209  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13210  int nchildren, /**< number of children */
13211  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
13212  int nquadelems, /**< number of quadratic elements */
13213  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
13214  SCIP_Real constant /**< constant */
13215  )
13216 {
13217  SCIP_EXPROPDATA opdata;
13219 
13220  assert(blkmem != NULL);
13221  assert(node != NULL);
13222  assert(quadelems != NULL || nquadelems == 0);
13223 
13224  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13225 
13226  opdata.data = data;
13227  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13228 
13229  return SCIP_OKAY;
13230 }
13231 
13232 /** creates an expression graph node for a polynomial expression */
13234  BMS_BLKMEM* blkmem, /**< block memory */
13235  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13236  int nmonomials, /**< number of monomials */
13237  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13238  SCIP_Real constant, /**< constant of polynomial */
13239  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13240  )
13241 {
13242  SCIP_EXPROPDATA opdata;
13244 
13245  assert(blkmem != NULL);
13246  assert(node != NULL);
13247  assert(monomials != NULL || nmonomials == 0);
13248 
13249  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13250 
13251  opdata.data = data;
13252  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13253 
13254  return SCIP_OKAY;
13255 }
13256 
13257 /** adds monomials to an expression graph node that is a polynomial expression */
13259  BMS_BLKMEM* blkmem, /**< block memory */
13260  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
13261  int nmonomials, /**< number of monomials */
13262  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13263  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13264  )
13265 {
13266  assert(blkmem != NULL);
13267  assert(node != NULL);
13269  assert(monomials != NULL || nmonomials == 0);
13270 
13271  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13272 
13273  return SCIP_OKAY;
13274 }
13275 
13276 /** creates an expression graph node for a user expression */
13278  BMS_BLKMEM* blkmem, /**< block memory */
13279  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13280  SCIP_USEREXPRDATA* data, /**< user data for expression, node assumes ownership */
13281  SCIP_EXPRINTCAPABILITY evalcapability, /**< evaluation capability */
13282  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
13283  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function */
13284  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
13285  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function */
13286  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13287  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13288  SCIP_DECL_USEREXPRFREEDATA ((*freedata)) /**< expression data free function, or NULL if nothing to free */
13289  )
13290 {
13291  SCIP_EXPROPDATA opdata;
13292  SCIP_EXPRDATA_USER* exprdata;
13293 
13294  assert(blkmem != NULL);
13295  assert(node != NULL);
13296  assert(eval != NULL);
13297  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
13298  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13299  assert(copydata != NULL || data == NULL);
13300  assert(freedata != NULL || data == NULL);
13301 
13302  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13303 
13304  exprdata->userdata = data;
13305  exprdata->evalcapability = evalcapability;
13306  exprdata->eval = eval;
13307  exprdata->estimate = estimate;
13308  exprdata->inteval = inteval;
13309  exprdata->curv = curv;
13310  exprdata->prop = prop;
13311  exprdata->copydata = copydata;
13312  exprdata->freedata = freedata;
13313 
13314  opdata.data = (void*) exprdata;
13315 
13316  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13317 
13318  return SCIP_OKAY;
13319 }
13320 
13321 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13322  *
13323  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13324  * If the node is a linear expression, it may be freed.
13325  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13326  * It is assumed that the user had captured the node.
13327  * It is assumed that the expression graph has been simplified before.
13328  */
13330  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13331  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
13332  int linvarssize, /**< length of linvars and lincoefs arrays */
13333  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
13334  void** linvars, /**< buffer to store variables of linear part */
13335  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
13336  SCIP_Real* constant /**< buffer to store constant part */
13337  )
13338 {
13339  int orignvars;
13340  int* varsusage;
13341  SCIP_EXPRGRAPHNODE* orignode;
13342  SCIP_Bool havechange;
13343  int i;
13344 
13345  assert(exprgraph != NULL);
13346  assert(node != NULL);
13347  assert(*node != NULL);
13348  assert((*node)->nuses > 0);
13349  assert(nlinvars != NULL);
13350  assert(linvars != NULL || linvarssize == 0);
13351  assert(lincoefs != NULL || linvarssize == 0);
13352  assert(constant != NULL);
13353 
13354  *constant = 0.0;
13355  *nlinvars = 0;
13356 
13357  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13358 
13359  /* do some obvious and easy cases */
13360  switch( (*node)->op )
13361  {
13362  case SCIP_EXPR_VARIDX:
13363  {
13364  if( linvarssize >= 1 )
13365  {
13366  *nlinvars = 1;
13367  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
13368  lincoefs[0] = 1.0; /*lint !e613*/
13369 
13370  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13371  }
13372  return SCIP_OKAY;
13373  }
13374 
13375  case SCIP_EXPR_CONST:
13376  {
13377  *constant = (*node)->data.dbl;
13378  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13379 
13380  return SCIP_OKAY;
13381  }
13382 
13383  case SCIP_EXPR_REALPOWER:
13384  case SCIP_EXPR_SIGNPOWER:
13385  {
13386  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13387  {
13388  *nlinvars = 1;
13389  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13390  lincoefs[0] = 1.0; /*lint !e613*/
13391 
13392  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13393  }
13394  return SCIP_OKAY;
13395  }
13396 
13397  case SCIP_EXPR_INTPOWER:
13398  {
13399  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13400  {
13401  *nlinvars = 1;
13402  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13403  lincoefs[0] = 1.0; /*lint !e613*/
13404 
13405  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13406  }
13407  return SCIP_OKAY;
13408  }
13409 
13410  case SCIP_EXPR_PLUS:
13411  {
13412  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13413  {
13414  *constant = (*node)->children[0]->data.dbl;
13415  *nlinvars = 1;
13416  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13417  lincoefs[0] = 1.0; /*lint !e613*/
13418 
13419  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13420 
13421  return SCIP_OKAY;
13422  }
13423  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13424  {
13425  *constant = (*node)->children[1]->data.dbl;
13426  *nlinvars = 1;
13427  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13428  lincoefs[0] = 1.0; /*lint !e613*/
13429 
13430  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13431 
13432  return SCIP_OKAY;
13433  }
13434  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13435  {
13436  *nlinvars = 2;
13437  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13438  lincoefs[0] = 1.0; /*lint !e613*/
13439  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13440  lincoefs[1] = 1.0; /*lint !e613*/
13441 
13442  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13443 
13444  return SCIP_OKAY;
13445  }
13446  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13447  {
13448  /* handle this one later */
13449  break;
13450  }
13451  return SCIP_OKAY;
13452  }
13453 
13454  case SCIP_EXPR_MINUS:
13455  {
13456  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13457  {
13458  *constant = (*node)->children[0]->data.dbl;
13459  *nlinvars = 1;
13460  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13461  lincoefs[0] = -1.0; /*lint !e613*/
13462 
13463  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13464 
13465  return SCIP_OKAY;
13466  }
13467  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13468  {
13469  *constant = -(*node)->children[1]->data.dbl;
13470  *nlinvars = 1;
13471  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13472  lincoefs[0] = 1.0; /*lint !e613*/
13473 
13474  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13475 
13476  return SCIP_OKAY;
13477  }
13478  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13479  {
13480  *nlinvars = 2;
13481  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13482  lincoefs[0] = 1.0; /*lint !e613*/
13483  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13484  lincoefs[1] = -1.0; /*lint !e613*/
13485 
13486  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13487 
13488  return SCIP_OKAY;
13489  }
13490  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13491  {
13492  /* handle this one later */
13493  break;
13494  }
13495  return SCIP_OKAY;
13496  }
13497 
13498  case SCIP_EXPR_MUL:
13499  {
13500  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13501  {
13502  *nlinvars = 1;
13503  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13504  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
13505 
13506  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13507  }
13508  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13509  {
13510  *nlinvars = 1;
13511  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13512  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
13513 
13514  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13515  }
13516  return SCIP_OKAY;
13517  }
13518 
13519  case SCIP_EXPR_DIV:
13520  {
13521  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13522  return SCIP_OKAY;
13523 
13524  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13525  {
13526  *nlinvars = 1;
13527  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13528  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
13529 
13530  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13531  }
13532  return SCIP_OKAY;
13533  }
13534 
13535  case SCIP_EXPR_SQUARE:
13536  case SCIP_EXPR_SQRT:
13537  case SCIP_EXPR_EXP:
13538  case SCIP_EXPR_LOG:
13539  case SCIP_EXPR_SIN:
13540  case SCIP_EXPR_COS:
13541  case SCIP_EXPR_TAN:
13542  /* case SCIP_EXPR_ERF: */
13543  /* case SCIP_EXPR_ERFI: */
13544  case SCIP_EXPR_ABS:
13545  case SCIP_EXPR_SIGN:
13546  case SCIP_EXPR_MIN:
13547  case SCIP_EXPR_MAX:
13548  return SCIP_OKAY;
13549 
13550  case SCIP_EXPR_PRODUCT:
13551  case SCIP_EXPR_USER:
13552  return SCIP_OKAY;
13553 
13554  case SCIP_EXPR_SUM:
13555  case SCIP_EXPR_LINEAR:
13556  case SCIP_EXPR_QUADRATIC:
13557  case SCIP_EXPR_POLYNOMIAL:
13558  default:
13559  {
13560  /* check if there is a child that is a variable */
13561  for( i = 0; i < (*node)->nchildren; ++i )
13562  {
13563  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13564  break;
13565  }
13566 
13567  if( i == (*node)->nchildren )
13568  return SCIP_OKAY;
13569 
13570  break;
13571  }
13572  } /*lint !e788*/
13573 
13574  /* count how often variables are used in this expression */
13575  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13576  orignvars = exprgraph->nvars;
13577  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13578  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
13579 
13580  exprgraphNodeGetVarsUsage(*node, varsusage);
13581 
13582  /* duplicate node if it has parents or more than one user */
13583  orignode = NULL;
13584  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13585  {
13586  SCIP_EXPROPDATA data;
13587 
13588  orignode = *node;
13589 
13590  if( exprOpTable[orignode->op].copydata != NULL )
13591  {
13592  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13593  }
13594  else
13595  data = orignode->data;
13596 
13597  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13598  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13599  SCIPexprgraphCaptureNode(*node);
13600  }
13601 
13602  havechange = FALSE;
13603  /* split up constant and linear part */
13604  switch( (*node)->op )
13605  {
13606  case SCIP_EXPR_PLUS:
13607  case SCIP_EXPR_MINUS:
13608  {
13609  SCIP_EXPRGRAPHNODE* varchild;
13610  SCIP_EXPRGRAPHNODE* otherchild;
13611  int varidx;
13612 
13613  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13614  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13615  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13616  assert(linvarssize >= 1);
13617 
13618  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13619  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13620  varidx = varchild->data.intval;
13621  /* if variable is used in other child (which should be nonlinear), we don't take it */
13622  if( varsusage[varidx] > 1 )
13623  break;
13624 
13625  /* add to linear variables */
13626  *nlinvars = 1;
13627  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13628  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13629  lincoefs[0] = -1.0; /*lint !e613*/
13630  else
13631  lincoefs[0] = 1.0; /*lint !e613*/
13632 
13633  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13634  {
13635  /* replace *node by otherchild */
13636  SCIPexprgraphCaptureNode(otherchild);
13637  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13638  *node = otherchild;
13639  }
13640  else
13641  {
13642  SCIP_Real* lindata;
13643 
13644  /* turn *node into linear expression -1.0 * otherchild */
13645 
13646  /* reduce to one child */
13647  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13648  (*node)->children[0] = otherchild;
13649  (*node)->nchildren = 1;
13650  (*node)->op = SCIP_EXPR_LINEAR;
13651 
13652  /* setup linear data -1.0 * child0 + 0.0 */
13653  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13654  lindata[0] = -1.0;
13655  lindata[1] = 0.0;
13656  (*node)->data.data = (void*)lindata;
13657 
13658  /* remove *node as parent of varchild */
13659  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13660  }
13661 
13662  havechange = TRUE;
13663 
13664  break;
13665  }
13666 
13667  case SCIP_EXPR_SUM:
13668  {
13669  int nchildren;
13670 
13671  i = 0;
13672  nchildren = (*node)->nchildren;
13673  while( i < nchildren )
13674  {
13675  /* sort out constants */
13676  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13677  {
13678  *constant += (*node)->children[i]->data.dbl;
13679  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13680 
13681  if( i < nchildren-1 )
13682  {
13683  (*node)->children[i] = (*node)->children[nchildren-1];
13684  (*node)->children[nchildren-1] = NULL;
13685  }
13686  --nchildren;
13687 
13688  continue;
13689  }
13690 
13691  /* keep every child that is not a constant or variable */
13692  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13693  {
13694  ++i;
13695  continue;
13696  }
13697 
13698  /* skip variables that are used in other parts of the expression */
13699  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13700  {
13701  ++i;
13702  continue;
13703  }
13704 
13705  /* move variable into linear part, if still space */
13706  if( *nlinvars < linvarssize )
13707  {
13708  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13709  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13710  ++*nlinvars;
13711 
13712  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13713  if( i < nchildren-1 )
13714  {
13715  (*node)->children[i] = (*node)->children[nchildren-1];
13716  (*node)->children[nchildren-1] = NULL;
13717  }
13718  --nchildren;
13719 
13720  continue;
13721  }
13722  }
13723  assert(i == nchildren);
13724 
13725  if( nchildren == 0 )
13726  {
13727  /* all children were removed */
13728  havechange = TRUE;
13729  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13730  (*node)->nchildren = 0;
13731  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13732  break;
13733  }
13734 
13735  if( nchildren < (*node)->nchildren )
13736  {
13737  /* some children were removed */
13738  havechange = TRUE;
13739  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13740  (*node)->nchildren = nchildren;
13741  }
13742 
13743  if( havechange && (*node)->nchildren == 1 )
13744  {
13745  /* replace node by its child */
13746  SCIP_EXPRGRAPHNODE* child;
13747 
13748  child = (*node)->children[0];
13749  SCIPexprgraphCaptureNode(child);
13750  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13751  *node = child;
13752 
13753  break;
13754  }
13755 
13756  break;
13757  }
13758 
13759  case SCIP_EXPR_LINEAR:
13760  {
13761  int nchildren;
13762  SCIP_Real* coefs;
13763 
13764  coefs = (SCIP_Real*)(*node)->data.data;
13765  assert(coefs != NULL);
13766 
13767  /* remove constant, if nonzero */
13768  if( coefs[(*node)->nchildren] != 0.0 )
13769  {
13770  *constant = coefs[(*node)->nchildren];
13771  coefs[(*node)->nchildren] = 0.0;
13772  havechange = TRUE;
13773  }
13774 
13775  i = 0;
13776  nchildren = (*node)->nchildren;
13777  while( i < nchildren )
13778  {
13779  /* sort out constants */
13780  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13781  {
13782  *constant += coefs[i] * (*node)->children[i]->data.dbl;
13783  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13784 
13785  if( i < nchildren-1 )
13786  {
13787  (*node)->children[i] = (*node)->children[nchildren-1];
13788  (*node)->children[nchildren-1] = NULL;
13789  coefs[i] = coefs[nchildren-1];
13790  coefs[nchildren-1] = 0.0;
13791  }
13792  --nchildren;
13793 
13794  continue;
13795  }
13796 
13797  /* keep everything that is not a constant or variable */
13798  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13799  {
13800  ++i;
13801  continue;
13802  }
13803 
13804  /* skip variables that are used in other parts of the expression */
13805  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13806  {
13807  ++i;
13808  continue;
13809  }
13810 
13811  /* move variable into linear part, if still space */
13812  if( *nlinvars < linvarssize )
13813  {
13814  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13815  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
13816  ++*nlinvars;
13817 
13818  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13819  if( i < nchildren-1 )
13820  {
13821  (*node)->children[i] = (*node)->children[nchildren-1];
13822  (*node)->children[nchildren-1] = NULL;
13823  coefs[i] = coefs[nchildren-1];
13824  coefs[nchildren-1] = 0.0;
13825  }
13826  --nchildren;
13827 
13828  continue;
13829  }
13830  }
13831  assert(i == nchildren);
13832 
13833  if( nchildren == 0 )
13834  {
13835  /* all children were removed */
13836  havechange = TRUE;
13837  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13838  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
13839  (*node)->data.data = NULL;
13840  (*node)->nchildren = 0;
13841  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
13842  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13843  break;
13844  }
13845 
13846  if( nchildren < (*node)->nchildren )
13847  {
13848  /* some children were removed */
13849  havechange = TRUE;
13850  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13851  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
13852  coefs[nchildren] = 0.0;
13853  (*node)->data.data = (void*)coefs;
13854  (*node)->nchildren = nchildren;
13855  }
13856 
13857  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
13858  {
13859  /* replace node by its child */
13860  SCIP_EXPRGRAPHNODE* child;
13861 
13862  child = (*node)->children[0];
13863  SCIPexprgraphCaptureNode(child);
13864  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13865  *node = child;
13866 
13867  break;
13868  }
13869 
13870  break;
13871  }
13872 
13873  case SCIP_EXPR_QUADRATIC:
13874  {
13875  SCIP_EXPRDATA_QUADRATIC* quaddata;
13876  SCIP_Bool* childused;
13877  int* childmap;
13878  int nchildren;
13879 
13880  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
13881  assert(quaddata != NULL);
13882 
13883  /* remove constant, if nonzero */
13884  if( quaddata->constant != 0.0 )
13885  {
13886  *constant = quaddata->constant;
13887  quaddata->constant = 0.0;
13888  havechange = TRUE;
13889  }
13890 
13891  /* if there is no linear part or no space left for linear variables, then stop */
13892  if( quaddata->lincoefs != NULL || linvarssize == 0 )
13893  break;
13894 
13895  /* check which childs are used in quadratic terms */
13896  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
13897  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
13898 
13899  for( i = 0; i < quaddata->nquadelems; ++i )
13900  {
13901  childused[quaddata->quadelems[i].idx1] = TRUE;
13902  childused[quaddata->quadelems[i].idx2] = TRUE;
13903  }
13904 
13905  /* alloc space for mapping of children indices */
13906  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
13907 
13908  nchildren = (*node)->nchildren;
13909  for( i = 0; i < nchildren; ++i )
13910  {
13911  childmap[i] = i; /*lint !e644*/
13912  if( *nlinvars >= linvarssize )
13913  continue;
13914  /* skip child if not variable or also used in quadratic part or other parts of expression */
13915  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13916  continue;
13917  if( childused[i] )
13918  continue;
13919  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13920  continue;
13921 
13922  /* put variable into linear part */
13923  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13924  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
13925  quaddata->lincoefs[i] = 0.0;
13926  ++*nlinvars;
13927 
13928  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13929 
13930  /* move last child to position i */
13931  if( i < nchildren-1 )
13932  {
13933  (*node)->children[i] = (*node)->children[nchildren-1];
13934  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
13935  childused[i] = childused[nchildren-1];
13936  childmap[nchildren-1] = i;
13937  }
13938  --nchildren;
13939  childmap[i] = -1;
13940 
13941  havechange = TRUE;
13942  --i; /* look at i again */
13943  }
13944 
13945  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
13946 
13947  if( nchildren < (*node)->nchildren )
13948  {
13949  /* apply childmap to quadratic term */
13950  for( i = 0; i < quaddata->nquadelems; ++i )
13951  {
13952  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
13953  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
13954  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
13955  {
13956  int tmp;
13957  tmp = quaddata->quadelems[i].idx1;
13958  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
13959  quaddata->quadelems[i].idx2 = tmp;
13960  }
13961  }
13962  quaddata->sorted = FALSE;
13963  }
13964  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
13965 
13966  if( nchildren == 0 )
13967  {
13968  /* all children were removed (so it was actually a linear expression) */
13969  havechange = TRUE;
13970  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13971  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
13972  (*node)->data.data = NULL;
13973  (*node)->nchildren = 0;
13974  (*node)->op = SCIP_EXPR_SUM;
13975  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13976  break;
13977  }
13978 
13979  if( nchildren < (*node)->nchildren )
13980  {
13981  /* reduce number of children */
13982  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13983  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
13984  (*node)->nchildren = nchildren;
13985  }
13986 
13987  break;
13988  }
13989 
13990  case SCIP_EXPR_POLYNOMIAL:
13991  {
13992  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
13993  SCIP_EXPRDATA_MONOMIAL* monomial;
13994  SCIP_Bool* childused;
13995  int childidx;
13996  int j;
13997 
13998  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
13999  assert(polynomialdata != NULL);
14000 
14001  /* make sure linear monomials are merged */
14002  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14003 
14004  /* remove constant, if nonzero */
14005  if( polynomialdata->constant != 0.0 )
14006  {
14007  *constant = polynomialdata->constant;
14008  polynomialdata->constant = 0.0;
14009  havechange = TRUE;
14010  }
14011 
14012  /* if there is no space for linear variables, then stop */
14013  if( linvarssize == 0 )
14014  break;
14015 
14016  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14017  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14018  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14019  for( i = 0; i < polynomialdata->nmonomials; ++i )
14020  {
14021  monomial = polynomialdata->monomials[i];
14022  assert(monomial != NULL);
14023  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14024  continue;
14025  for( j = 0; j < monomial->nfactors; ++j )
14026  {
14027  assert(monomial->childidxs[j] >= 0);
14028  assert(monomial->childidxs[j] < (*node)->nchildren);
14029  childused[monomial->childidxs[j]] = TRUE;
14030  }
14031  }
14032 
14033  /* move linear monomials out of polynomial */
14034  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14035  {
14036  monomial = polynomialdata->monomials[i];
14037  assert(monomial != NULL);
14038 
14039  /* sort out constants */
14040  if( monomial->nfactors == 0 )
14041  {
14042  if( monomial->coef != 0.0 )
14043  {
14044  *constant += monomial->coef;
14045  havechange = TRUE;
14046  }
14047  continue;
14048  }
14049 
14050  if( monomial->nfactors != 1 )
14051  continue;
14052  if( monomial->exponents[0] != 1.0 )
14053  continue;
14054  childidx = monomial->childidxs[0];
14055  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14056  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14057  continue;
14058  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14059  continue;
14060 
14061  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14062 
14063  /* put variable into linear part */
14064  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
14065  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
14066  ++*nlinvars;
14067 
14068  monomial->coef = 0.0;
14069  monomial->nfactors = 0;
14070  polynomialdata->sorted = FALSE;
14071 
14072  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14073  (*node)->children[childidx] = NULL;
14074 
14075  havechange = TRUE;
14076  }
14077 
14078  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14079 
14080  if( *nlinvars > 0 )
14081  {
14082  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14083  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14085  }
14086 
14087  if( (*node)->nchildren == 0 )
14088  {
14089  assert(polynomialdata->nmonomials == 0);
14090  assert(polynomialdata->constant == 0.0);
14091  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14092  havechange = TRUE;
14093  break;
14094  }
14095 
14096  break;
14097  }
14098 
14099  default: ;
14100  } /*lint !e788*/
14101 
14102  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14103 
14104  if( orignode != NULL )
14105  {
14106  /* if node was duplicated, we need to forget about original or duplicate */
14107  if( !havechange )
14108  {
14109  /* if nothing has changed, then forget about duplicate */
14110  assert(*constant == 0.0);
14111  assert(*nlinvars == 0);
14112  assert(*node != NULL);
14113  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14114  *node = orignode;
14115  }
14116  else
14117  {
14118  /* if something changed, then release original node */
14119  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14120  }
14121  }
14122  else if( havechange && *node != NULL )
14123  {
14124  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14125  (*node)->value = SCIP_INVALID;
14126  (*node)->simplified = FALSE;
14127  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14128  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14129  exprgraph->needvarboundprop = TRUE;
14130  }
14131 
14132  return SCIP_OKAY;
14133 }
14134 
14135 /** moves parents from a one node to another node
14136  *
14137  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14138  * srcnode may be freed, if not captured.
14139  * It is assumed that targetnode represents the same expression as srcnode.
14140  */
14142  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14143  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
14144  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
14145  )
14146 {
14147  assert(exprgraph != NULL);
14148  assert(srcnode != NULL);
14149  assert(*srcnode != NULL);
14150  assert(targetnode != NULL);
14151 
14152  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14153  {
14154  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14155  {
14156  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14157  }
14158  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14159  }
14160  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14161 
14162  return SCIP_OKAY;
14163 }
14164 
14165 /** releases node, i.e., decreases number of uses
14166  *
14167  * node is freed if no parents and no other uses.
14168  * Children are recursively released if they have no other parents.
14169  * Nodes that are removed are also freed.
14170  * If node correspond to a variable, then the variable is removed from the expression graph;
14171  * similarly for constants.
14172  */
14174  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14175  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
14176  )
14177 {
14178  int i;
14179 
14180  assert(exprgraph != NULL);
14181  assert(node != NULL);
14182  assert(*node != NULL);
14183  assert((*node)->depth >= 0); /* node should be in graph */
14184  assert((*node)->pos >= 0); /* node should be in graph */
14185  assert((*node)->depth < exprgraph->depth);
14186  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14187  assert((*node)->nuses >= 1);
14188  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14189 
14190  SCIPdebugMessage("release node %p\n", (void*)*node);
14191 
14192  --(*node)->nuses;
14193 
14194  /* do nothing if node still has parents or is still in use */
14195  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14196  {
14197  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);
14198  *node = NULL;
14199  return SCIP_OKAY;
14200  }
14201 
14202  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14203 
14204  /* notify children about removal of its parent
14205  * they are also freed, if possible */
14206  for( i = 0; i < (*node)->nchildren; ++i )
14207  {
14208  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14209  (*node)->children[i] = NULL;
14210  }
14211 
14212  if( (*node)->op == SCIP_EXPR_VARIDX )
14213  {
14214  assert((*node)->depth == 0);
14215  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14216  }
14217  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14218  {
14219  int constidx;
14220 
14221  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14222  assert(constidx >= 0);
14223  assert(constidx < exprgraph->nconsts);
14224  assert(exprgraph->constnodes[constidx] == *node);
14225 
14226  /* move last constant to position constidx */
14227  if( constidx < exprgraph->nconsts-1 )
14228  {
14229  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14230  exprgraph->constssorted = (exprgraph->nconsts <= 2);
14231  }
14232  --exprgraph->nconsts;
14233  }
14234  else
14235  {
14236  /* only variables and constants are allowed at depth 0 */
14237  assert((*node)->depth > 0);
14238  }
14239 
14240  /* remove node from nodes array in expression graph */
14241  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14242  {
14243  /* move last node at depth of *node to position of *node */
14244  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14245  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14246  }
14247  --exprgraph->nnodes[(*node)->depth];
14248 
14249  /* node is now not in graph anymore */
14250  (*node)->depth = -1;
14251  (*node)->pos = -1;
14252 
14253  /* free node */
14254  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14255 
14256  *node = NULL;
14257 
14258  return SCIP_OKAY;
14259 }
14260 
14261 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14262 /** frees a node of an expression graph */
14264  BMS_BLKMEM* blkmem, /**< block memory */
14265  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
14266  )
14267 {
14268  assert(blkmem != NULL);
14269  assert( node != NULL);
14270  assert(*node != NULL);
14271  assert((*node)->depth == -1); /* node should not be in graph anymore */
14272  assert((*node)->pos == -1); /* node should not be in graph anymore */
14273  assert((*node)->nuses == 0); /* node should not be in use */
14274 
14275  /* free operator data, if needed */
14276  if( exprOpTable[(*node)->op].freedata != NULL )
14277  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14278 
14279  /* free arrays of children and parent nodes */
14280  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14281  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
14282 
14283  /* free node struct */
14284  BMSfreeBlockMemory(blkmem, node);
14285 }
14286 
14287 /** enables a node and recursively all its children in an expression graph */
14289  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14290  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14291  )
14292 {
14293  int i;
14294 
14295  assert(exprgraph != NULL);
14296  assert(node != NULL);
14297  assert(node->depth >= 0);
14298  assert(node->pos >= 0);
14299 
14300  if( node->enabled )
14301  return;
14302 
14303  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14304 
14305  node->enabled = TRUE;
14306  for( i = 0; i < node->nchildren; ++i )
14307  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14308 
14309  /* make sure bounds are updated in next bound propagation round */
14311  exprgraph->needvarboundprop = TRUE;
14312 }
14313 
14314 /** disables a node and recursively all children which have no enabled parents in an expression graph */
14316  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14317  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14318  )
14319 {
14320  int i;
14321 
14322  assert(exprgraph != NULL);
14323  assert(node != NULL);
14324  assert(node->depth >= 0);
14325  assert(node->pos >= 0);
14326 
14327  if( !node->enabled )
14328  return;
14329 
14330  /* if all parents of node are disabled, then also node can be disabled */
14331  node->enabled = FALSE;
14332  for( i = 0; i < node->nparents; ++i )
14333  if( node->parents[i]->enabled )
14334  {
14335  node->enabled = TRUE;
14336  return;
14337  }
14338 
14339  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14340 
14341  for( i = 0; i < node->nchildren; ++i )
14342  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14343 }
14344 
14345 /** returns whether the node has siblings in the expression graph */
14347  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14348  )
14349 {
14350  int p;
14351 
14352  assert(node != NULL);
14353 
14354  for( p = 0; p < node->nparents; ++p )
14355  if( node->parents[p]->nchildren > 1 )
14356  return TRUE;
14357 
14358  return FALSE;
14359 }
14360 
14361 /** returns whether all children of an expression graph node are variable nodes
14362  *
14363  * Returns TRUE for nodes without children.
14364  */
14366  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14367  )
14368 {
14369  int i;
14370 
14371  assert(node != NULL);
14372 
14373  for( i = 0; i < node->nchildren; ++i )
14374  if( node->children[i]->op != SCIP_EXPR_VARIDX )
14375  return FALSE;
14376 
14377  return TRUE;
14378 }
14379 
14380 /** returns whether the node has an ancestor which has a nonlinear expression operand */
14382  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14383  )
14384 {
14385  int p;
14386 
14387  for( p = 0; p < node->nparents; ++p )
14388  {
14389  assert(node->parents[p]->depth > node->depth);
14390  switch( node->parents[p]->op )
14391  {
14392  case SCIP_EXPR_PLUS:
14393  case SCIP_EXPR_MINUS:
14394  case SCIP_EXPR_SUM:
14395  case SCIP_EXPR_LINEAR:
14397  return TRUE;
14398  break;
14399 
14400 #ifndef NDEBUG
14401  case SCIP_EXPR_VARIDX:
14402  case SCIP_EXPR_CONST:
14403  case SCIP_EXPR_PARAM:
14404  assert(0); /* these expressions cannot have children */
14405  break;
14406 #endif
14407 
14408  default:
14409  /* parent has nonlinear expression operand */
14410  return TRUE;
14411  }/*lint !e788*/
14412  }
14413 
14414  return FALSE;
14415 }
14416 
14417 /** prints an expression graph node */
14419  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14420  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14421  FILE* file /**< file to print to, or NULL for stdout */
14422  )
14423 {
14424  assert(node != NULL);
14425 
14426  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14427 }
14428 
14429 /** tightens the bounds in a node of the graph
14430  *
14431  * Preparation for reverse propagation.
14432  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14433  */
14435  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14436  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
14437  SCIP_INTERVAL nodebounds, /**< new bounds for node */
14438  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) */
14439  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14440  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14441  )
14442 {
14443  assert(exprgraph != NULL);
14444  assert(node != NULL);
14445  assert(node->depth >= 0);
14446  assert(node->pos >= 0);
14447  assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14448  assert(cutoff != NULL);
14449 
14450  *cutoff = FALSE;
14451 
14452  /* if node is disabled, then ignore new bounds */
14453  if( !node->enabled )
14454  {
14455  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14456  return;
14457  }
14458 
14459  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14460  (void*)node, node->depth, node->pos,
14461  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14462 
14463  /* bounds in node should be valid */
14465 
14466  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14467  {
14468  *cutoff = TRUE;
14469  SCIPdebugPrintf(" -> cutoff\n");
14470  return;
14471  }
14472 
14473  /* if minstrength is negative, always mark that node has recently tightened bounds,
14474  * if bounds are considerably improved or tightening leads to an empty interval,
14475  * mark that node has recently tightened bounds
14476  * if bounds are only slightly improved, set the status to tightened by parent,
14477  * so next propagateVarBound round will reset the bounds
14478  */
14479  if( minstrength < 0.0 )
14481  else if(
14482  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14483  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14485  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14487 
14488  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14489  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14490 }
14491 
14492 /** ensures that bounds and curvature information in a node is uptodate
14493  *
14494  * Assumes that bounds and curvature in children are uptodate.
14495  */
14497  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14498  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14499  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14500  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14501  )
14502 {
14503  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14504  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14505  SCIP_INTERVAL* childbounds;
14506  SCIP_EXPRCURV* childcurv;
14507  int i;
14508 
14509  assert(node != NULL);
14510  assert(node->depth >= 0); /* node should be in graph */
14511  assert(node->pos >= 0); /* node should be in graph */
14512  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14513 
14514  if( node->depth == 0 )
14515  {
14516  /* we cannot update bound tightenings in variable nodes here */
14517  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14518  return SCIP_OKAY;
14519  }
14520 
14521  assert(node->op != SCIP_EXPR_VARIDX);
14522  assert(node->op != SCIP_EXPR_PARAM);
14523 
14524  /* if many children, get large enough memory to store children bounds */
14526  {
14527  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14528  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, node->nchildren) );
14529  }
14530  else
14531  {
14532  childbounds = childboundsstatic;
14533  childcurv = childcurvstatic;
14534  }
14535 
14536  /* assemble bounds and curvature of children */
14537  for( i = 0; i < node->nchildren; ++i )
14538  {
14539  /* child should have valid and non-empty bounds */
14541  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14542  /* nodes at depth 0 are always linear */
14543  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14544 
14545  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
14546  childcurv[i] = node->children[i]->curv; /*lint !e644*/
14547  }
14548 
14549  /* if we do not have valid bounds, then update
14550  * code below is copied from exprgraphNodeUpdateBounds */
14552  {
14553  SCIP_INTERVAL newbounds;
14554 
14555  /* calling interval evaluation function for this operand */
14556  assert( exprOpTable[node->op].inteval != NULL );
14557  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
14558 
14559  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14560  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14561  *
14562  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14563  *
14564  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14565  */
14566  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14568  {
14569  for( i = 0; i < node->nparents; ++i )
14571 
14572  node->bounds = newbounds;
14573  }
14574  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14575  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14576  {
14577  for( i = 0; i < node->nparents; ++i )
14579 
14580  node->bounds = newbounds;
14581  }
14582  else
14583  {
14584  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14585  }
14586 
14587  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);
14588 
14589  /* node now has valid bounds */
14591  }
14592 
14593  /* update curvature */
14594  if( SCIPintervalIsEmpty(infinity, node->bounds) )
14595  {
14596  node->curv = SCIP_EXPRCURV_LINEAR;
14597 
14598  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14599  }
14600  else
14601  {
14602  SCIP_CALL( exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv) );
14603 
14604  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14605  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14606  * SCIPdebugPrintf("\n");
14607  */
14608  }
14609 
14610  /* free memory, if allocated before */
14611  if( childbounds != childboundsstatic )
14612  {
14613  BMSfreeMemoryArray(&childbounds);
14614  BMSfreeMemoryArray(&childcurv);
14615  }
14616 
14617  return SCIP_OKAY;
14618 }
14619 
14620 /**@} */
14621 
14622 /**@name Expression graph methods */
14623 /**@{ */
14624 
14625 /* In debug mode, the following methods are implemented as function calls to ensure
14626  * type validity.
14627  * In optimized mode, the methods are implemented as defines to improve performance.
14628  * However, we want to have them in the library anyways, so we have to undef the defines.
14629  */
14630 
14631 #undef SCIPexprgraphGetDepth
14632 #undef SCIPexprgraphGetNNodes
14633 #undef SCIPexprgraphGetNodes
14634 #undef SCIPexprgraphGetNVars
14635 #undef SCIPexprgraphGetVars
14636 #undef SCIPexprgraphGetVarNodes
14637 #undef SCIPexprgraphSetVarNodeValue
14638 #undef SCIPexprgraphSetVarsBounds
14639 #undef SCIPexprgraphSetVarBounds
14640 #undef SCIPexprgraphSetVarNodeBounds
14641 #undef SCIPexprgraphSetVarNodeLb
14642 #undef SCIPexprgraphSetVarNodeUb
14643 #undef SCIPexprgraphGetVarsBounds
14644 
14645 /** get current maximal depth of expression graph */
14647  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14648  )
14649 {
14650  assert(exprgraph != NULL);
14651 
14652  return exprgraph->depth;
14653 }
14654 
14655 /** gets array with number of nodes at each depth of expression graph */
14657  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14658  )
14659 {
14660  assert(exprgraph != NULL);
14661 
14662  return exprgraph->nnodes;
14663 }
14664 
14665 /** gets nodes of expression graph, one array per depth */
14667  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14668  )
14669 {
14670  assert(exprgraph != NULL);
14671 
14672  return exprgraph->nodes;
14673 }
14674 
14675 /** gets number of variables in expression graph */
14677  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14678  )
14679 {
14680  assert(exprgraph != NULL);
14681 
14682  return exprgraph->nvars;
14683 }
14684 
14685 /** gets array of variables in expression graph */
14687  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14688  )
14689 {
14690  assert(exprgraph != NULL);
14691 
14692  return exprgraph->vars;
14693 }
14694 
14695 /** gets array of expression graph nodes corresponding to variables */
14697  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14698  )
14699 {
14700  assert(exprgraph != NULL);
14701 
14702  return exprgraph->varnodes;
14703 }
14704 
14705 /** sets value for a single variable given as expression graph node */
14707  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14708  SCIP_Real value /**< new value for variable */
14709  )
14710 {
14711  assert(varnode != NULL);
14712  assert(varnode->op == SCIP_EXPR_VARIDX);
14713 
14714  varnode->value = value;
14715 }
14716 
14717 /** sets bounds for variables */
14719  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14720  SCIP_INTERVAL* varbounds /**< new bounds for variables */
14721  )
14722 {
14723  assert(exprgraph != NULL);
14724  assert(varbounds != NULL || exprgraph->nvars == 0);
14725 
14726  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
14727 }
14728 
14729 /** sets bounds for a single variable */
14731  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14732  void* var, /**< variable */
14733  SCIP_INTERVAL varbounds /**< new bounds of variable */
14734  )
14735 {
14736  int pos;
14737 
14738  assert(exprgraph != NULL);
14739  assert(var != NULL);
14740  assert(SCIPhashmapExists(exprgraph->varidxs, var));
14741 
14742  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
14743  assert(pos < exprgraph->nvars);
14744  assert(exprgraph->vars[pos] == var);
14745 
14746  exprgraph->varbounds[pos] = varbounds;
14747 }
14748 
14749 /** sets bounds for a single variable given as expression graph node */
14751  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14752  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14753  SCIP_INTERVAL varbounds /**< new bounds of variable */
14754  )
14755 {
14756  int pos;
14757 
14758  assert(exprgraph != NULL);
14759  assert(varnode != NULL);
14760 
14761  pos = varnode->data.intval;
14762  assert(pos >= 0);
14763  assert(pos < exprgraph->nvars);
14764  assert(exprgraph->varnodes[pos] == varnode);
14765 
14766  exprgraph->varbounds[pos] = varbounds;
14767 }
14768 
14769 /** sets lower bound for a single variable given as expression graph node */
14771  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14772  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14773  SCIP_Real lb /**< new lower bound for variable */
14774  )
14775 {
14776  int pos;
14777 
14778  assert(exprgraph != NULL);
14779  assert(varnode != NULL);
14780 
14781  pos = varnode->data.intval;
14782  assert(pos >= 0);
14783  assert(pos < exprgraph->nvars);
14784  assert(exprgraph->varnodes[pos] == varnode);
14785 
14786  exprgraph->varbounds[pos].inf = lb;
14787 }
14788 
14789 /** sets upper bound for a single variable given as expression graph node */
14791  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14792  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14793  SCIP_Real ub /**< new upper bound for variable */
14794  )
14795 {
14796  int pos;
14797 
14798  assert(exprgraph != NULL);
14799  assert(varnode != NULL);
14800 
14801  pos = varnode->data.intval;
14802  assert(pos >= 0);
14803  assert(pos < exprgraph->nvars);
14804  assert(exprgraph->varnodes[pos] == varnode);
14805 
14806  exprgraph->varbounds[pos].sup = ub;
14807 }
14808 
14809 /** gets bounds that are stored for all variables */
14811  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14812  )
14813 {
14814  return exprgraph->varbounds;
14815 }
14816 
14817 /** creates an empty expression graph */
14819  BMS_BLKMEM* blkmem, /**< block memory */
14820  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
14821  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
14822  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
14823  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /** callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
14824  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /** callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
14825  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /** callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
14826  void* userdata /**< user data to pass to callback functions */
14827  )
14828 {
14829  assert(blkmem != NULL);
14830  assert(exprgraph != NULL);
14831 
14832  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
14833  BMSclearMemory(*exprgraph);
14834  (*exprgraph)->blkmem = blkmem;
14835 
14836  /* create nodes's arrays */
14837  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
14838  assert((*exprgraph)->depth >= 1);
14839 
14840  /* create var's arrays and hashmap */
14841  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
14842  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, SCIPcalcHashtableSize(5 * (*exprgraph)->varssize)) );
14843 
14844  /* empty array of constants is sorted */
14845  (*exprgraph)->constssorted = TRUE;
14846 
14847  /* store callback functions and user data */
14848  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
14849  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
14850  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
14851  (*exprgraph)->userdata = userdata;
14852 
14853  return SCIP_OKAY;
14854 }
14855 
14856 /** frees an expression graph */
14858  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
14859  )
14860 {
14861  BMS_BLKMEM* blkmem;
14862  int d;
14863 
14864  assert( exprgraph != NULL);
14865  assert(*exprgraph != NULL);
14866  assert((*exprgraph)->nvars == 0);
14867  assert((*exprgraph)->nconsts == 0);
14868 
14869  blkmem = (*exprgraph)->blkmem;
14870  assert(blkmem != NULL);
14871 
14872  /* free nodes arrays */
14873  for( d = 0; d < (*exprgraph)->depth; ++d )
14874  {
14875  assert((*exprgraph)->nnodes[d] == 0);
14876  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
14877  }
14878  assert((*exprgraph)->nodes != NULL);
14879  assert((*exprgraph)->nnodes != NULL);
14880  assert((*exprgraph)->nodessize != NULL);
14881  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
14882  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
14883  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
14884 
14885  /* free variables arrays and hashmap */
14886  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
14887  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
14888  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
14889  SCIPhashmapFree(&(*exprgraph)->varidxs);
14890 
14891  /* free constants array */
14892  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
14893 
14894  /* free graph struct */
14895  BMSfreeBlockMemory(blkmem, exprgraph);
14896 
14897  return SCIP_OKAY;
14898 }
14899 
14900 /** adds an expression graph node to an expression graph
14901  *
14902  * Expression graph assumes ownership of node.
14903  * Children are notified about new parent.
14904  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
14905  */
14907  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14908  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
14909  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
14910  int nchildren, /**< number of children */
14911  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
14912  )
14913 {
14914  SCIP_Bool childvalsvalid;
14915  int depth;
14916  int i;
14917 
14918  assert(exprgraph != NULL);
14919  assert(node != NULL);
14920  assert(node->pos < 0); /* node should have no position in graph yet */
14921  assert(node->depth < 0); /* node should have no position in graph yet */
14922  assert(node->nchildren == 0); /* node should not have stored children yet */
14923  assert(node->children == NULL); /* node should not have stored children yet */
14924  assert(node->nparents == 0); /* node should not have parents stored yet */
14925  assert(children != NULL || nchildren == 0);
14926 
14927  /* choose depth as maximal depth of children + 1, and at least mindepth */
14928  depth = MAX(0, mindepth);
14929  for( i = 0; i < nchildren; ++i )
14930  {
14931  if( children[i]->depth >= depth ) /*lint !e613*/
14932  depth = children[i]->depth + 1; /*lint !e613*/
14933  }
14934 
14935  /* ensure that expression graph is deep enough */
14936  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
14937  assert(exprgraph->depth > depth);
14938 
14939  /* ensure enough space for nodes at depth depth */
14940  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
14941 
14942  /* add node to graph */
14943  node->depth = depth;
14944  node->pos = exprgraph->nnodes[depth];
14945  exprgraph->nodes[depth][node->pos] = node;
14946  ++exprgraph->nnodes[depth];
14947 
14948  /* add as parent to children
14949  * and check if children has valid values */
14950  childvalsvalid = TRUE;
14951  for( i = 0; i < nchildren; ++i )
14952  {
14953  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
14954  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
14955  }
14956  /* store children */
14957  if( nchildren > 0 )
14958  {
14959  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
14960  node->nchildren = nchildren;
14961  }
14962 
14963  if( node->op == SCIP_EXPR_CONST )
14964  {
14965  /* set bounds to constant value of node */
14967  SCIPintervalSet(&node->bounds, node->data.dbl);
14968  }
14969  else
14970  {
14971  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
14974  exprgraph->needvarboundprop = TRUE;
14975  }
14976 
14977  /* if not a variable, set value of node according to values of children (if all have valid values) */
14978  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
14979  {
14980  SCIP_CALL( exprgraphNodeEval(node, NULL) );
14981  }
14982 
14983  return SCIP_OKAY;
14984 }
14985 
14986 /** adds variables to an expression graph, if not existing yet
14987  *
14988  * Also already existing nodes are enabled.
14989  */
14991  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14992  int nvars, /**< number of variables to add */
14993  void** vars, /**< variables to add */
14994  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
14995  )
14996 {
14997  SCIP_EXPRGRAPHNODE* node;
14998  SCIP_EXPROPDATA opdata;
14999  int i;
15000 
15001  assert(exprgraph != NULL);
15002  assert(exprgraph->depth >= 1);
15003  assert(vars != NULL || nvars == 0);
15004 
15005  /* 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 */
15006  if( exprgraph->nvars == 0 )
15007  {
15008  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15009  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15010  }
15011 
15012  for( i = 0; i < nvars; ++i )
15013  {
15014  /* skip variables that exist already */
15015  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15016  {
15017  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
15018  assert(node != NULL);
15019 
15020  /* enable node */
15021  node->enabled = TRUE;
15022 
15023  if( varnodes != NULL )
15024  varnodes[i] = node;
15025 
15026  continue;
15027  }
15028 
15029  /* create new variable expression */
15030  opdata.intval = exprgraph->nvars;
15031  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15032 
15033  /* add expression node to expression graph at depth 0 */
15034  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15035 
15036  /* add variable node to vars arrays and hashmap */
15037  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15038  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
15039  exprgraph->varnodes[exprgraph->nvars] = node;
15040  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15041  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[i], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15042  ++exprgraph->nvars;
15043 
15044  if( varnodes != NULL )
15045  varnodes[i] = node;
15046 
15047  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15048 
15049  /* call callback method, if set */
15050  if( exprgraph->exprgraphvaradded != NULL )
15051  {
15052  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
15053  }
15054  }
15055 
15056  return SCIP_OKAY;
15057 }
15058 
15059 /** adds a constant to an expression graph, if not existing yet
15060  *
15061  * Also already existing nodes are enabled.
15062  */
15064  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15065  SCIP_Real constant, /**< constant to add */
15066  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
15067  )
15068 {
15069  SCIP_EXPROPDATA opdata;
15070 
15071  assert(exprgraph != NULL);
15072  assert(constnode != NULL);
15073 
15074  /* check if there is already an expression for this constant */
15075  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15076  {
15077  assert(*constnode != NULL);
15078  assert((*constnode)->op == SCIP_EXPR_CONST);
15079  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15080  (*constnode)->enabled = TRUE;
15081  return SCIP_OKAY;
15082  }
15083 
15084  /* create new node for constant */
15085  opdata.dbl = constant;
15086  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15087 
15088  /* add node to expression graph at depth 0 */
15089  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15090  assert((*constnode)->depth == 0);
15091  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
15092 
15093  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15094  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15095  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15096  ++exprgraph->nconsts;
15097  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15098 
15099  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15100 
15101  return SCIP_OKAY;
15102 }
15103 
15104 /** adds sum of expression trees into expression graph
15105  *
15106  * node will also be captured.
15107  */
15109  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15110  int nexprtrees, /**< number of expression trees to add */
15111  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
15112  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
15113  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
15114  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) */
15115  )
15116 {
15117  SCIP_Bool allone;
15118 
15119  assert(exprgraph != NULL);
15120  assert(nexprtrees > 0);
15121  assert(exprtrees != NULL);
15122  assert(rootnode != NULL);
15123  assert(rootnodeisnew != NULL);
15124 
15125  *rootnode = NULL;
15126 
15127  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15128  {
15129  assert(exprtrees[0] != NULL);
15130  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15131 
15132  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, rootnode, rootnodeisnew) );
15133  }
15134  else
15135  {
15136  SCIP_EXPROP op;
15137  SCIP_EXPRGRAPHNODE** rootnodes;
15138  SCIP_Bool rootnodeisnew_;
15139  int i;
15140 
15141  *rootnodeisnew = TRUE;
15142  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15143 
15144  allone = TRUE;
15145  for( i = 0; i < nexprtrees; ++i )
15146  {
15147  assert(exprtrees[i] != NULL);
15148  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15149 
15150  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
15151  assert(rootnodes[i] != NULL);
15152  *rootnodeisnew &= rootnodeisnew_;
15153 
15154  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
15155  }
15156 
15157  /* decide which operand we want to use for the root node */
15158  if( coefs == NULL || allone )
15159  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15160  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15161  op = SCIP_EXPR_MINUS;
15162  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15163  {
15164  SCIP_EXPRGRAPHNODE* tmp;
15165 
15166  tmp = rootnodes[0];
15167  rootnodes[0] = rootnodes[1];
15168  rootnodes[1] = tmp;
15169  op = SCIP_EXPR_MINUS;
15170  }
15171  else
15172  op = SCIP_EXPR_LINEAR;
15173 
15174  if( op != SCIP_EXPR_LINEAR )
15175  {
15176  SCIP_EXPROPDATA data;
15177  data.data = NULL;
15178 
15179  if( !*rootnodeisnew )
15180  {
15181  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15182  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15183  }
15184 
15185  if( *rootnode == NULL )
15186  {
15187  /* create new node for sum of rootnodes and add to exprgraph */
15188  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15189  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15190  *rootnodeisnew = TRUE;
15191  }
15192  else
15193  {
15194  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15195  *rootnodeisnew = FALSE;
15196  }
15197  }
15198  else
15199  {
15200  SCIP_EXPROPDATA data;
15201  SCIP_Real* lindata;
15202 
15203  assert(op == SCIP_EXPR_LINEAR);
15204 
15205  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15206  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15207  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
15208  lindata[nexprtrees] = 0.0;
15209  data.data = lindata;
15210 
15211  if( !*rootnodeisnew )
15212  {
15213  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15214  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15215  }
15216 
15217  if( *rootnode == NULL )
15218  {
15219  /* create new node for linear combination of rootnodes and add to exprgraph */
15220  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15221  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15222  *rootnodeisnew = TRUE;
15223  }
15224  else
15225  {
15226  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15227  *rootnodeisnew = FALSE;
15228  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15229  }
15230  }
15231 
15232  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15233  }
15234  assert(*rootnode != NULL);
15235 
15236  SCIPexprgraphCaptureNode(*rootnode);
15237 
15238  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15239  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15240 
15241  return SCIP_OKAY;
15242 }
15243 
15244 /** replaces variable in expression graph by a linear sum of variables
15245  *
15246  * Variables will be added if not in the graph yet.
15247  */
15249  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15250  void* var, /**< variable to replace */
15251  int ncoefs, /**< number of coefficients in linear term */
15252  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
15253  void** vars, /**< variables in linear term */
15254  SCIP_Real constant /**< constant offset */
15255  )
15256 {
15257  SCIP_EXPRGRAPHNODE* varnode;
15258  SCIP_Real* lindata;
15259  int varidx;
15260  int i;
15261 
15262  assert(exprgraph != NULL);
15263  assert(var != NULL);
15264  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15265  assert(coefs != NULL || ncoefs == 0);
15266  assert(vars != NULL || ncoefs == 0);
15267 
15268  varidx = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15269  assert(varidx < exprgraph->nvars);
15270  assert(exprgraph->vars[varidx] == var);
15271  varnode = exprgraph->varnodes[varidx];
15272  assert(varnode != NULL);
15273  assert(varnode->data.intval == varidx);
15274 
15275  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
15276  {
15277  /* variable is replaced by constant or variable */
15278  SCIP_EXPRGRAPHNODE* node;
15279 
15280  /* check if there is already a node for this constant or variable */
15281  node = NULL;
15282  if( ncoefs == 0 )
15283  {
15284  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15285  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
15286  }
15287  else
15288  {
15289  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
15290  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
15291  }
15292 
15293  if( node != NULL )
15294  {
15295  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15296 
15297  /* tell parents of varnode to replace child varnode by node, this may free varnode */
15298  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15299 
15300  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15301  if( varnode != NULL )
15302  {
15303  assert(varnode->nuses > 0);
15304  assert(varnode->nparents == 0);
15305 
15306  /* remove variable (but don't free it's node) from graph */
15307  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15308 
15309  /* move varnode up to depth 1 */
15310  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15311 
15312  /* turn into EXPR_SUM expression */
15313  varnode->op = SCIP_EXPR_SUM;
15314  varnode->data.data = NULL;
15315  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
15316  varnode->children[0] = node;
15317  varnode->nchildren = 1;
15318  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15319 
15320  varnode->value = node->value;
15321  varnode->bounds = node->bounds;
15323  }
15324  }
15325  else if( ncoefs == 0 )
15326  {
15327  /* turn node into EXPR_CONST node */
15328 
15329  /* remove variable (but don't free it's node) from graph */
15330  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15331 
15332  /* convert into EXPR_CONST node */
15333  varnode->op = SCIP_EXPR_CONST;
15334  varnode->data.dbl = constant;
15335 
15336  varnode->value = constant;
15337  SCIPintervalSet(&varnode->bounds, constant);
15339 
15340  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15341  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15342  exprgraph->constnodes[exprgraph->nconsts] = varnode;
15343  ++exprgraph->nconsts;
15344  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15345  }
15346  else
15347  {
15348  /* turn node into EXPR_VARIDX node for new variable */
15349 
15350  /* remove variable (but don't free it's node) from graph */
15351  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15352 
15353  varnode->data.intval = exprgraph->nvars;
15354 
15355  /* add variable node to vars arrays and hashmap */
15356  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15357  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
15358  exprgraph->varnodes[exprgraph->nvars] = varnode;
15359  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15360  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[0], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15361  ++exprgraph->nvars;
15362 
15363  /* call callback method, if set */
15364  if( exprgraph->exprgraphvaradded != NULL )
15365  {
15366  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
15367  }
15368  }
15369 
15370  /* mark varnode and its parents as not simplified */
15371  if( varnode != NULL )
15372  {
15373  varnode->simplified = FALSE;
15374  for( i = 0; i < varnode->nparents; ++i )
15375  varnode->parents[i]->simplified = FALSE;
15376  }
15377 
15378  return SCIP_OKAY;
15379  }
15380 
15381  /* turn varnode into EXPR_LINEAR */
15382 
15383  /* remove variable (but don't free it's node) from graph */
15384  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15385 
15386  /* move varnode up to depth 1 */
15387  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15388 
15389  /* convert into EXPR_LINEAR node */
15390  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15391  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
15392  lindata[ncoefs] = constant;
15393  varnode->data.data = (void*)lindata;
15394  varnode->op = SCIP_EXPR_LINEAR;
15395 
15396  /* add nodes corresponding to vars to expression graph, if not existing yet */
15397  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15398  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15399  varnode->nchildren = ncoefs;
15400 
15401  /* notify vars about new parent varnode */
15402  for( i = 0; i < ncoefs; ++i )
15403  {
15404  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15405  }
15406 
15407  /* set value and bounds to invalid, curvature can remain (still linear) */
15408  varnode->value = SCIP_INVALID;
15410 
15411  /* mark varnode and its parents as not simplified */
15412  varnode->simplified = FALSE;
15413  for( i = 0; i < varnode->nparents; ++i )
15414  varnode->parents[i]->simplified = FALSE;
15415 
15416  return SCIP_OKAY;
15417 }
15418 
15419 /** finds expression graph node corresponding to a variable */
15421  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15422  void* var, /**< variable to search for */
15423  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15424  )
15425 {
15426  int pos;
15427 
15428  assert(exprgraph != NULL);
15429  assert(var != NULL);
15430  assert(varnode != NULL);
15431 
15432  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15433  {
15434  *varnode = NULL;
15435  return FALSE;
15436  }
15437 
15438  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15439  assert(pos < exprgraph->nvars);
15440 
15441  *varnode = exprgraph->varnodes[pos];
15442  assert(*varnode != NULL);
15443  assert((*varnode)->op == SCIP_EXPR_VARIDX);
15444 
15445  return TRUE;
15446 }
15447 
15448 /** finds expression graph node corresponding to a constant */
15450  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15451  SCIP_Real constant, /**< constant to search for */
15452  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15453  )
15454 {
15455  int left;
15456  int right;
15457  int middle;
15458 
15459  assert(exprgraph != NULL);
15460  assert(constnode != NULL);
15461  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
15462 
15463  exprgraphSortConstNodes(exprgraph);
15464  assert(exprgraph->constssorted);
15465 
15466  /* find node using binary search */
15467  left = 0;
15468  right = exprgraph->nconsts-1;
15469  *constnode = NULL;
15470 
15471  while( left <= right )
15472  {
15473  middle = (left+right)/2;
15474  assert(0 <= middle && middle < exprgraph->nconsts);
15475 
15476  if( constant < exprgraph->constnodes[middle]->data.dbl )
15477  right = middle - 1;
15478  else if( constant > exprgraph->constnodes[middle]->data.dbl )
15479  left = middle + 1;
15480  else
15481  {
15482  *constnode = exprgraph->constnodes[middle];
15483  break;
15484  }
15485  }
15486  assert(left == right+1 || *constnode != NULL);
15487  if( left == right+1 )
15488  return FALSE;
15489 
15490  assert((*constnode)->op == SCIP_EXPR_CONST);
15491  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15492 
15493  return TRUE;
15494 }
15495 
15496 /** prints an expression graph in dot format */
15498  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15499  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15500  FILE* file, /**< file to print to, or NULL for stdout */
15501  const char** varnames /**< variable names, or NULL for generic names */
15502  )
15503 {
15504  int d;
15505  int i;
15506 
15507  assert(exprgraph != NULL);
15508 
15509  if( file == NULL )
15510  file = stdout;
15511 
15512  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15513  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15514 
15515  for( d = 0; d < exprgraph->depth; ++d )
15516  {
15517  if( exprgraph->nnodes[d] == 0 )
15518  continue;
15519 
15520  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15521  {
15522  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15523  }
15524  }
15525 
15526  /* tell dot that all nodes of depth 0 have the same rank */
15527  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15528  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15529  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15530  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15531 
15532  /* tell dot that all nodes without parent have the same rank */
15533  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15534  for( d = 0; d < exprgraph->depth; ++d )
15535  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15536  if( exprgraph->nodes[d][i]->nparents == 0 )
15537  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15538  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15539 
15540  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15541 
15542  return SCIP_OKAY;
15543 }
15544 
15545 /** evaluates nodes of expression graph for given values of variables */
15547  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15548  SCIP_Real* varvals /**< values for variables */
15549  )
15550 {
15551  int d;
15552  int i;
15553 
15554  assert(exprgraph != NULL);
15555  assert(varvals != NULL || exprgraph->nvars == 0);
15556 
15557  for( d = 0; d < exprgraph->depth; ++d )
15558  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15559  {
15560  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15561  }
15562 
15563  return SCIP_OKAY;
15564 }
15565 
15566 /** propagates bound changes in variables forward through the expression graph */
15568  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15569  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15570  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
15571  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15572  )
15573 {
15574  SCIP_EXPRGRAPHNODE* node;
15575  SCIP_Bool boundchanged;
15576  int d;
15577  int i;
15578 
15579  assert(exprgraph != NULL);
15580  assert(domainerror != NULL);
15581 
15582  *domainerror = FALSE;
15583 
15584  /* update bounds in varnodes of expression graph */
15585  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15586 
15587  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15588  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15589  {
15590  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15591  return SCIP_OKAY;
15592  }
15593 
15594  /* propagate bound changes, interrupt if we get to a node with empty bounds */
15595  for( d = 1; d < exprgraph->depth; ++d )
15596  {
15597  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15598  {
15599  node = exprgraph->nodes[d][i];
15600  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15601  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15602  {
15603  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15604  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15605  *domainerror = TRUE;
15606  return SCIP_OKAY;
15607  }
15608  }
15609  }
15610 
15611  exprgraph->needvarboundprop = FALSE;
15612 
15613  return SCIP_OKAY;
15614 }
15615 
15616 /** propagates bound changes in nodes backward through the graph
15617  *
15618  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15619  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15620  */
15622  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15623  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15624  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15625  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15626  )
15627 {
15628  SCIP_EXPRGRAPHNODE* node;
15629  int d;
15630  int i;
15631 
15632  assert(exprgraph != NULL);
15633  assert(cutoff != NULL);
15634 
15635  *cutoff = FALSE;
15636 
15637  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15638  {
15639  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15640  {
15641  node = exprgraph->nodes[d][i];
15642  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15643  }
15644  }
15645  if( *cutoff )
15646  return;
15647 }
15648 
15649 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15650  *
15651  * Implies update of bounds in expression graph.
15652  */
15654  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15655  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15656  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15657  )
15658 {
15659  SCIP_EXPRGRAPHNODE* node;
15660  SCIP_Bool boundchanged;
15661  int d;
15662  int i;
15663 
15664  assert(exprgraph != NULL);
15665 
15666  /* update bounds in varnodes of expression graph */
15667  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15668 
15669 #ifndef NDEBUG
15670  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15671  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15672 #endif
15673 
15674  for( d = 1; d < exprgraph->depth; ++d )
15675  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15676  {
15677  node = exprgraph->nodes[d][i];
15678  assert(node != NULL);
15679 
15680  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15681 
15682  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15683  {
15684  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15685  return SCIP_OKAY;
15686  }
15687  }
15688 
15689  return SCIP_OKAY;
15690 }
15691 
15692 /** aims at simplifying an expression graph
15693  *
15694  * 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)).
15695  */
15697  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15698  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15699  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15700  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15701  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15702  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15703  )
15704 {
15705  SCIP_EXPRGRAPHNODE* node;
15706  SCIP_Bool havechangenode;
15707  SCIP_Bool allsimplified;
15708  int d;
15709  int i;
15710  int j;
15711 
15712 #ifndef NDEBUG
15713  SCIP_Real* testx;
15714  SCIP_HASHMAP* testvalidx;
15715  SCIP_Real* testvals;
15716  int testvalssize;
15717  int ntestvals;
15718  unsigned int seed;
15719 #endif
15720 
15721  assert(exprgraph != NULL);
15722  assert(eps >= 0.0);
15723  assert(havechange != NULL);
15724  assert(domainerror != NULL);
15725 
15726 #ifndef NDEBUG
15727  seed = 42;
15728  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
15729  testvals = NULL;
15730  ntestvals = 0;
15731  testvalssize = 0;
15732 
15733  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
15734  for( i = 0; i < exprgraph->nvars; ++i )
15735  testx[i] = SCIPgetRandomReal(-100.0, 100.0, &seed); /*lint !e644*/
15736  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
15737  for( d = 1; d < exprgraph->depth; ++d )
15738  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15739  {
15740  node = exprgraph->nodes[d][i];
15741  assert(node != NULL);
15742 
15743  /* 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 */
15744  if( node->nuses > 0 )
15745  {
15746  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
15747  SCIP_CALL( SCIPhashmapInsert(testvalidx, (void*)node, (void*)(size_t)ntestvals) );
15748  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
15749  ++ntestvals;
15750  }
15751  }
15752 #endif
15753 
15754 #ifdef SCIP_OUTPUT
15755  {
15756  FILE* file;
15757  file = fopen("exprgraph_beforesimplify.dot", "w");
15758  if( file != NULL )
15759  {
15760  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
15761  fclose(file);
15762  }
15763  }
15764 #endif
15765 
15766  *havechange = FALSE; /* we have not changed any node yet */
15767  *domainerror = FALSE; /* no domain errors encountered so far */
15768  allsimplified = TRUE; /* all nodes we looked at are simplified */
15769 
15770  /* call node simplifier from bottom up
15771  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
15772  */
15773  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
15774  {
15775  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15776  {
15777  node = exprgraph->nodes[d][i];
15778  assert(node != NULL);
15779 
15780  havechangenode = FALSE; /* node did not change yet */
15781 
15782  if( node->op != SCIP_EXPR_CONST )
15783  {
15784  /* skip nodes that are already simplified */
15785  if( node->simplified )
15786  continue;
15787 
15788  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
15789 
15790  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
15791  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
15792  assert(node->simplified == TRUE);
15793  *havechange |= havechangenode;
15794  }
15795 
15796  /* if node was or has been converted into constant, may move to depth 0 */
15797  if( node->op == SCIP_EXPR_CONST )
15798  {
15799  SCIP_EXPRGRAPHNODE* constnode;
15800 
15801  if( node->value != node->value ) /*lint !e777*/
15802  {
15803  SCIPdebugMessage("Expression graph simplify turned node into NaN.\n");
15804  *domainerror = TRUE;
15805  break;
15806  }
15807 
15808  /* check if there is already a node for this constant */
15809  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
15810  {
15811  assert(constnode->op == SCIP_EXPR_CONST);
15812  assert(constnode->data.dbl == node->value); /*lint !e777*/
15813 
15814  if( node->nparents > 0 )
15815  {
15816  /* move parents of this node to constnode, node may be freed if not in use */
15817  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
15818  /* node should have no parents anymore, so it should have been freed if not in use */
15819  assert(node == NULL || node->nuses > 0);
15820  havechangenode = TRUE;
15821 
15822  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
15823  if( node == NULL )
15824  {
15825  --i;
15826  continue;
15827  }
15828  }
15829  assert(node != NULL);
15830  assert(node->nuses > 0);
15831 
15832  if( constnode->nuses == 0 )
15833  {
15834  /* move node to depth 0, adding it to constnodes */
15835  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
15836 
15837  /* move parents of constnode to node, so constnode is freed */
15838  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
15839  assert(constnode == NULL);
15840  havechangenode = TRUE;
15841 
15842  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
15843  --i;
15844  continue;
15845  }
15846  }
15847  else
15848  {
15849  /* move to depth 0, adding it to constnodes */
15850  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
15851 
15852  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
15853  --i;
15854  }
15855  }
15856 
15857  /* if there was a change, mark parents as not simplified */
15858  if( havechangenode )
15859  for( j = 0; j < node->nparents; ++j )
15860  node->parents[j]->simplified = FALSE;
15861  }
15862  } /*lint !e850*/
15863 
15864  /* if we did nothing, clean up and escape from here */
15865  if( allsimplified || *domainerror )
15866  goto EXPRGRAPHSIMPLIFY_CLEANUP;
15867 
15868  /* @todo find duplicate subexpressions in expression graph */
15869 
15870  /* unconvert polynomials into simpler expressions, where possible */
15871  for( d = 1; d < exprgraph->depth; ++d )
15872  {
15873  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15874  {
15875  node = exprgraph->nodes[d][i];
15876  assert(node != NULL);
15877 
15878  if( node->op != SCIP_EXPR_POLYNOMIAL )
15879  continue;
15880 
15881  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
15882 
15883  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
15884  {
15885  /* node is identity w.r.t only child
15886  * replace node as child of parents by child of node
15887  */
15888 
15889  for( j = 0; node != NULL && j < node->nparents; ++j )
15890  {
15891  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
15892  }
15893  /* node should have no parents anymore, so it should have been freed if not in use */
15894  assert(node == NULL || node->nuses > 0);
15895 
15896  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
15897  if( node == NULL )
15898  --i;
15899  }
15900  }
15901  } /*lint !e850*/
15902 
15903 #ifdef SCIP_OUTPUT
15904  {
15905  FILE* file;
15906  file = fopen("exprgraph_aftersimplify.dot", "w");
15907  if( file != NULL )
15908  {
15909  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
15910  fclose(file);
15911  }
15912  }
15913 #endif
15914 
15915 #ifndef NDEBUG
15916  for( d = 1; d < exprgraph->depth; ++d )
15917  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15918  {
15919  int idx;
15920  SCIP_Real testval_before;
15921  SCIP_Real testval_after;
15922 
15923  node = exprgraph->nodes[d][i];
15924  assert(node != NULL);
15925 
15926  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15927 
15928  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
15929  if( node->nuses > 0 )
15930  {
15931  assert(SCIPhashmapExists(testvalidx, (void*)node));
15932 
15933  idx = (int)(size_t)(void*)SCIPhashmapGetImage(testvalidx, (void*)node);
15934  assert(idx < ntestvals);
15935 
15936  testval_before = testvals[idx]; /*lint !e613*/
15937  testval_after = SCIPexprgraphGetNodeVal(node);
15938 
15939  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
15940  }
15941  }
15942 #endif
15943 
15944  EXPRGRAPHSIMPLIFY_CLEANUP:
15945 #ifndef NDEBUG
15946  BMSfreeMemoryArray(&testx);
15947  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
15948  SCIPhashmapFree(&testvalidx);
15949 #endif
15950 
15951  return SCIP_OKAY;
15952 }
15953 
15954 /** creates an expression tree from a given node in an expression graph */
15956  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15957  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
15958  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
15959  )
15960 {
15961  SCIP_EXPR* root;
15962  int nexprvars;
15963  int* varidx;
15964  int i;
15965 
15966  assert(exprgraph != NULL);
15967  assert(rootnode != NULL);
15968  assert(rootnode->depth >= 0);
15969  assert(rootnode->pos >= 0);
15970  assert(exprtree != NULL);
15971 
15972  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
15973  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
15974 
15975  /* initially, no variable appears in the expression tree */
15976  for( i = 0; i < exprgraph->nvars; ++i )
15977  varidx[i] = -1; /*lint !e644*/
15978  nexprvars = 0;
15979 
15980  /* create expression from the subgraph that has rootnode as root */
15981  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
15982 
15983  /* create expression tree for this expression */
15984  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
15985 
15986  /* copy variables into expression tree */
15987  if( nexprvars > 0 )
15988  {
15989  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
15990  for( i = 0; i < exprgraph->nvars; ++i )
15991  {
15992  assert(varidx[i] >= -1);
15993  assert(varidx[i] < nexprvars);
15994  if( varidx[i] >= 0 )
15995  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
15996  }
15997  }
15998 
15999  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16000 
16001  return SCIP_OKAY;
16002 }
16003 
16004 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16005  *
16006  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16007  */
16009  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16010  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16011  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16012  int* nexprtrees, /**< buffer to store number of expression trees */
16013  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16014  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16015  )
16016 {
16017  int ncomponents;
16018  int* childcomp;
16019  int* varcomp;
16020  int compnr;
16021  SCIP_Bool haveoverlap;
16022  int i;
16023  int j;
16024  int k;
16025 
16026  SCIP_EXPR** exprs;
16027  int nexprs;
16028  int* childmap;
16029  int* childmapinv;
16030  int* varidx;
16031  int nexprvars;
16032 
16033  assert(exprgraph != NULL);
16034  assert(node != NULL);
16035  assert(node->depth >= 0);
16036  assert(node->pos >= 0);
16037  assert(exprtreessize > 0);
16038  assert(nexprtrees != NULL);
16039  assert(exprtrees != NULL);
16040  assert(exprtreecoefs != NULL);
16041 
16042  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16043  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16044  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16045  ( node->op != SCIP_EXPR_PLUS &&
16046  node->op != SCIP_EXPR_MINUS &&
16047  node->op != SCIP_EXPR_SUM &&
16048  node->op != SCIP_EXPR_LINEAR &&
16049  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16050  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16051  {
16052  *nexprtrees = 1;
16053  exprtreecoefs[0] = 1.0;
16054  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16055 
16056  return SCIP_OKAY;
16057  }
16058 
16059  /* find components in node->children <-> variables graph */
16060  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16061  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16062  for( i = 0; i < exprgraph->nvars; ++i )
16063  varcomp[i] = -1; /*lint !e644*/
16064 
16065  haveoverlap = FALSE;
16066  for( i = 0; i < node->nchildren; ++i )
16067  {
16068  compnr = i;
16069  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
16070  assert(compnr >= 0);
16071  assert(compnr < node->nchildren);
16072  childcomp[i] = compnr;
16073 
16074  /* remember if component number was changed by CheckComponent */
16075  if( compnr != i )
16076  haveoverlap = TRUE;
16077  }
16078 
16079  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16080 
16081  if( node->op == SCIP_EXPR_QUADRATIC )
16082  {
16083  /* merge components for products of children from different components */
16085 
16086  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16087  assert(data != NULL);
16088 
16089  for( i = 0; i < data->nquadelems; ++i )
16090  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16091  {
16092  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16093  compnr = childcomp[data->quadelems[i].idx2];
16094  for( j = 0; j < node->nchildren; ++j )
16095  if( childcomp[j] == compnr )
16096  childcomp[j] = childcomp[data->quadelems[i].idx1];
16097  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16098  haveoverlap = TRUE;
16099  }
16100  }
16101  else if( node->op == SCIP_EXPR_POLYNOMIAL )
16102  {
16103  /* merge components for monomials of children from different components */
16105 
16106  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16107  assert(data != NULL);
16108 
16109  for( i = 0; i < data->nmonomials; ++i )
16110  for( j = 1; j < data->monomials[i]->nfactors; ++j )
16111  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16112  {
16113  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16114  compnr = childcomp[data->monomials[i]->childidxs[j]];
16115  for( k = 0; k < node->nchildren; ++k )
16116  if( childcomp[k] == compnr )
16117  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16118  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16119  haveoverlap = TRUE;
16120  }
16121  }
16122 
16123  if( haveoverlap )
16124  {
16125  /* some component numbers are unused, thus relabel and count final number of components */
16126  int* compmap;
16127 
16128  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16129  for( i = 0; i < node->nchildren; ++i )
16130  compmap[i] = -1; /*lint !e644*/
16131 
16132  ncomponents = 0;
16133  for( i = 0; i < node->nchildren; ++i )
16134  {
16135  if( compmap[childcomp[i]] == -1 )
16136  compmap[childcomp[i]] = ncomponents++;
16137  childcomp[i] = compmap[childcomp[i]];
16138  }
16139 
16140  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16141  }
16142  else
16143  {
16144  ncomponents = node->nchildren;
16145  }
16146 
16147  if( ncomponents == 1 )
16148  {
16149  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16150  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16151 
16152  *nexprtrees = 1;
16153  exprtreecoefs[0] = 1.0;
16154  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16155 
16156  return SCIP_OKAY;
16157  }
16158 
16159  if( ncomponents > exprtreessize )
16160  {
16161  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16162  for( i = 0; i < node->nchildren; ++i )
16163  if( childcomp[i] >= exprtreessize )
16164  childcomp[i] = exprtreessize-1;
16165  ncomponents = exprtreessize;
16166  }
16167 
16168  assert(ncomponents >= 2);
16169 
16170  /* setup expression trees for each component */
16171  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16172  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16173  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16174  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16175  for( i = 0; i < ncomponents; ++i )
16176  {
16177  /* initially, no variable appears in the expression tree */
16178  for( j = 0; j < exprgraph->nvars; ++j )
16179  varidx[j] = -1; /*lint !e644*/
16180  nexprvars = 0;
16181 
16182  /* collect expressions from children belonging to component i */
16183  nexprs = 0;
16184  for( j = 0; j < node->nchildren; ++j )
16185  {
16186  assert(childcomp[j] >= 0);
16187  assert(childcomp[j] < ncomponents);
16188  if( childcomp[j] != i )
16189  continue;
16190 
16191  /* create expression from the subgraph that has child j as root */
16192  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
16193  childmap[j] = nexprs; /*lint !e644*/
16194  childmapinv[nexprs] = j; /*lint !e644*/
16195  ++nexprs;
16196  }
16197 
16198  /* setup expression tree for component i */
16199  switch( node->op )
16200  {
16201  case SCIP_EXPR_PLUS:
16202  {
16203  assert(ncomponents == 2);
16204  assert(nexprs == 1);
16205 
16206  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16207  exprtreecoefs[i] = 1.0;
16208 
16209  break;
16210  }
16211 
16212  case SCIP_EXPR_MINUS:
16213  {
16214  assert(ncomponents == 2);
16215  assert(nexprs == 1);
16216 
16217  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16218  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16219  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16220  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16221 
16222  break;
16223  }
16224 
16225  case SCIP_EXPR_SUM:
16226  {
16227  if( nexprs == 1 )
16228  {
16229  /* component corresponds to exactly one child of node */
16230  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16231  }
16232  else
16233  {
16234  /* component corresponds to a sum of children of node */
16235  SCIP_EXPR* sumexpr;
16236 
16237  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16238  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16239  }
16240  exprtreecoefs[i] = 1.0;
16241 
16242  break;
16243  }
16244 
16245  case SCIP_EXPR_LINEAR:
16246  {
16247  SCIP_Real* nodecoefs;
16248  SCIP_EXPR* sumexpr;
16249 
16250  nodecoefs = (SCIP_Real*)node->data.data;
16251 
16252  /* if there is a constant, then we put it into the expression of the first component */
16253  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16254  {
16255  /* component corresponds to exactly one child of node */
16256  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16257  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16258  }
16259  else if( nexprs == 1 )
16260  {
16261  /* component corresponds to a sum of one child and a constant */
16262  assert(i == 0);
16263  assert(nodecoefs[node->nchildren] != 0.0);
16264  assert(nodecoefs[childmapinv[0]] != 0.0);
16265  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16266  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16267  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16268  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16269  }
16270  else
16271  {
16272  /* component corresponds to a linear combination of children of node */
16273 
16274  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16275  {
16276  /* if two expressions with equal sign, then create PLUS expression */
16277  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16278  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16279  }
16280  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16281  {
16282  /* if two expressions with opposite sign, then create MINUS expression */
16283  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16284  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16285  }
16286  else
16287  {
16288  /* assemble coefficents and create SUM or LINEAR expression */
16289  SCIP_Real* coefs;
16290  SCIP_Bool allcoefsequal;
16291 
16292  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16293  allcoefsequal = TRUE;
16294  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
16295  for( j = 0; j < nexprs; ++j )
16296  {
16297  coefs[j] = nodecoefs[childmapinv[j]];
16298  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
16299  }
16300 
16301  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16302  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16303  {
16304  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16305  exprtreecoefs[i] = coefs[0];
16306  }
16307  else
16308  {
16309  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16310  exprtreecoefs[i] = 1.0;
16311  }
16312 
16313  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16314  }
16315 
16316  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16317  }
16318 
16319  break;
16320  }
16321 
16322  case SCIP_EXPR_QUADRATIC:
16323  {
16324  SCIP_EXPR* quadexpr;
16325  SCIP_EXPRDATA_QUADRATIC* nodedata;
16326  SCIP_Real* lincoefs;
16327  SCIP_QUADELEM* quadelems;
16328  int nquadelems;
16329 
16330  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16331 
16332  exprtreecoefs[i] = 1.0;
16333 
16334  /* assemble coefficients corresponding to component i */
16335  if( nodedata->lincoefs != NULL )
16336  {
16337  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16338  for( j = 0; j < nexprs; ++j )
16339  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
16340  }
16341  else
16342  lincoefs = NULL;
16343 
16344  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16345  nquadelems = 0;
16346  for( j = 0; j < nodedata->nquadelems; ++j )
16347  {
16348  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16349  if( childcomp[nodedata->quadelems[j].idx1] != i )
16350  continue;
16351  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
16352  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16353  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16354  ++nquadelems;
16355  }
16356 
16357  /* put constant into first component */
16358  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16359  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16360 
16361  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16362  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16363 
16364  break;
16365  }
16366 
16367  case SCIP_EXPR_POLYNOMIAL:
16368  {
16369  SCIP_EXPR* polyexpr;
16370  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
16371  SCIP_EXPRDATA_MONOMIAL** monomials;
16372  SCIP_Real constant;
16373  int nmonomials;
16374 
16375  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16376 
16377  constant = nodedata->constant;
16378  exprtreecoefs[i] = 1.0;
16379 
16380  /* collect monomials belonging to component i */
16381  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16382  nmonomials = 0;
16383  for( j = 0; j < nodedata->nmonomials; ++j )
16384  {
16385  if( nodedata->monomials[j]->nfactors == 0 )
16386  {
16387  constant += nodedata->monomials[j]->coef;
16388  continue;
16389  }
16390  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16391  continue;
16392 
16393  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16394  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
16395  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16396  {
16397  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16398  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16399  }
16400  ++nmonomials;
16401  }
16402 
16403  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16404  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16405 
16406  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16407 
16408  break;
16409  }
16410 
16411  default:
16412  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16413  return SCIP_ERROR;
16414  } /*lint !e788*/
16415 
16416  /* copy variables into expression tree */
16417  if( nexprvars > 0 )
16418  {
16419  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16420  for( j = 0; j < exprgraph->nvars; ++j )
16421  {
16422  assert(varidx[j] >= -1);
16423  assert(varidx[j] < nexprvars);
16424  if( varidx[j] >= 0 )
16425  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16426  }
16427  }
16428  }
16429 
16430  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16431  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16432  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16433  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16434  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16435 
16436  *nexprtrees = ncomponents;
16437 
16438  return SCIP_OKAY;
16439 }
16440 
16441 /** returns how often expression graph variables are used in a subtree of the expression graph */
16443  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16444  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
16445  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16446  )
16447 {
16448  assert(exprgraph != NULL);
16449  assert(node != NULL);
16450  assert(varsusage != NULL);
16451 
16452  BMSclearMemoryArray(varsusage, exprgraph->nvars);
16453 
16454  exprgraphNodeGetVarsUsage(node, varsusage);
16455 }
16456 
16457 /** gives the number of summands which the expression of an expression graph node consists of */
16459  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
16460  )
16461 {
16462  switch( node->op )
16463  {
16464  case SCIP_EXPR_PLUS:
16465  case SCIP_EXPR_MINUS:
16466  return 2;
16467 
16468  case SCIP_EXPR_SUM:
16469  case SCIP_EXPR_LINEAR:
16470  return node->nchildren;
16471 
16472  case SCIP_EXPR_QUADRATIC:
16473  {
16474  SCIP_EXPRDATA_QUADRATIC* nodedata;
16475 
16476  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16477  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16478  }
16479 
16480  case SCIP_EXPR_POLYNOMIAL:
16481  {
16482  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
16483 
16484  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16485  return nodedata->nmonomials;
16486  }
16487 
16488  default:
16489  return 1;
16490  } /*lint !e788*/
16491 }
16492 
16493 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
16495  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16496  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16497  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16498  int* nexprtrees, /**< buffer to store number of expression trees */
16499  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16500  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16501  )
16502 {
16503  int* varidx;
16504  int nexprvars;
16505  int i;
16506 
16507  assert(exprgraph != NULL);
16508  assert(node != NULL);
16509  assert(node->depth >= 0);
16510  assert(node->pos >= 0);
16511  assert(exprtreessize > 0);
16512  assert(nexprtrees != NULL);
16513  assert(exprtrees != NULL);
16514  assert(exprtreecoefs != NULL);
16515 
16516  /* if node is not separable, fallback to SCIPexprgraphGetTree */
16517  if( node->op != SCIP_EXPR_PLUS &&
16518  node->op != SCIP_EXPR_MINUS &&
16519  node->op != SCIP_EXPR_SUM &&
16520  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16521  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16522  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16523  {
16524  *nexprtrees = 1;
16525  exprtreecoefs[0] = 1.0;
16526  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16527 
16528  return SCIP_OKAY;
16529  }
16530 
16531  switch( node->op )
16532  {
16533  case SCIP_EXPR_PLUS:
16534  {
16535  assert(exprtreessize >= 2);
16536 
16537  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16538  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16539 
16540  exprtreecoefs[0] = 1.0;
16541  exprtreecoefs[1] = 1.0;
16542 
16543  *nexprtrees = 2;
16544  break;
16545  }
16546 
16547  case SCIP_EXPR_MINUS:
16548  {
16549  assert(exprtreessize >= 2);
16550 
16551  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16552  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16553 
16554  exprtreecoefs[0] = 1.0;
16555  exprtreecoefs[1] = -1.0;
16556 
16557  *nexprtrees = 2;
16558  break;
16559  }
16560 
16561  case SCIP_EXPR_SUM:
16562  {
16563  assert(exprtreessize >= node->nchildren);
16564 
16565  for( i = 0; i < node->nchildren; ++i )
16566  {
16567  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16568  exprtreecoefs[i] = 1.0;
16569  }
16570 
16571  *nexprtrees = node->nchildren;
16572  break;
16573  }
16574 
16575  case SCIP_EXPR_LINEAR:
16576  {
16577  SCIP_Real* nodecoefs;
16578 
16579  assert(exprtreessize >= node->nchildren);
16580  assert(node->nchildren > 0);
16581 
16582  nodecoefs = (SCIP_Real*)node->data.data;
16583  assert(nodecoefs != NULL);
16584 
16585  for( i = 0; i < node->nchildren; ++i )
16586  {
16587  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16588  exprtreecoefs[i] = nodecoefs[i];
16589  }
16590 
16591  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16592  if( nodecoefs[node->nchildren] != 0.0 )
16593  {
16594  SCIP_EXPR* constexpr_;
16595 
16596  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16597  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16598  }
16599 
16600  *nexprtrees = node->nchildren;
16601  break;
16602  }
16603 
16604  case SCIP_EXPR_QUADRATIC:
16605  {
16606  SCIP_EXPRDATA_QUADRATIC* nodedata;
16607  SCIP_Real* lincoefs;
16608  SCIP_QUADELEM* quadelems;
16609  int nquadelems;
16610  SCIP_EXPR* expr;
16611  int j;
16612 
16613  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16614  lincoefs = nodedata->lincoefs;
16615  quadelems = nodedata->quadelems;
16616  nquadelems = nodedata->nquadelems;
16617 
16618  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16619  assert(node->nchildren > 0);
16620 
16621  *nexprtrees = 0;
16622  if( lincoefs != NULL )
16623  {
16624  for( i = 0; i < node->nchildren; ++i )
16625  {
16626  if( lincoefs[i] == 0.0 )
16627  continue;
16628  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16629  exprtreecoefs[*nexprtrees] = lincoefs[i];
16630  ++*nexprtrees;
16631  }
16632  }
16633 
16634  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16635  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16636 
16637  for( i = 0; i < nquadelems; ++i )
16638  {
16639  /* initially, no variable appears in the expression tree */
16640  for( j = 0; j < exprgraph->nvars; ++j )
16641  varidx[j] = -1; /*lint !e644*/
16642  nexprvars = 0;
16643 
16644  /* create expression from the subgraph at quadelems[i].idx1 */
16645  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16646 
16647  if( quadelems[i].idx1 == quadelems[i].idx2 )
16648  {
16649  /* create expression for square of expr */
16650  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16651  }
16652  else
16653  {
16654  SCIP_EXPR* expr2;
16655 
16656  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16657  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16658  /* create expression for product */
16659  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16660  }
16661 
16662  /* create expression tree for expr */
16663  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16664 
16665  /* copy variables into expression tree */
16666  if( nexprvars > 0 )
16667  {
16668  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16669  for( j = 0; j < exprgraph->nvars; ++j )
16670  {
16671  assert(varidx[j] >= -1);
16672  assert(varidx[j] < nexprvars);
16673  if( varidx[j] >= 0 )
16674  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16675  }
16676  }
16677 
16678  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16679 
16680  ++*nexprtrees;
16681  }
16682 
16683  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16684  if( nodedata->constant != 0.0 )
16685  {
16686  SCIP_EXPR* constexpr_;
16687 
16688  assert(*nexprtrees > 0);
16689  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16690  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16691  }
16692 
16693  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16694 
16695  break;
16696  }
16697 
16698  case SCIP_EXPR_POLYNOMIAL:
16699  {
16700  SCIP_EXPRDATA_POLYNOMIAL* nodedata;
16701  SCIP_EXPRDATA_MONOMIAL** monomials;
16702  SCIP_Real constant;
16703  int nmonomials;
16704  SCIP_EXPR* expr;
16705  int* childidxs;
16706  int j;
16707 
16708  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16709  monomials = nodedata->monomials;
16710  nmonomials = nodedata->nmonomials;
16711  constant = nodedata->constant;
16712 
16713  assert(exprtreessize >= nmonomials);
16714  assert(node->nchildren > 0);
16715 
16716  *nexprtrees = 0;
16717 
16718  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16719  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16720 
16721  for( i = 0; i < nmonomials; ++i )
16722  {
16723  /* initially, no variable appears in the expression tree */
16724  for( j = 0; j < exprgraph->nvars; ++j )
16725  varidx[j] = -1;
16726  nexprvars = 0;
16727 
16728  if( monomials[i]->nfactors == 1 )
16729  {
16730  /* create expression from the subgraph at only factor */
16731  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16732 
16733  /* put exponent in, if not 1.0 */
16734  if( monomials[i]->exponents[0] == 1.0 )
16735  ;
16736  else if( monomials[i]->exponents[0] == 2.0 )
16737  {
16738  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16739  }
16740  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
16741  {
16742  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
16743  }
16744  else
16745  {
16746  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
16747  }
16748  }
16749  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
16750  {
16751  SCIP_EXPR* expr2;
16752 
16753  /* create expressions for both factors */
16754  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16755  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
16756 
16757  /* create expression for product of factors */
16758  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16759  }
16760  else
16761  {
16762  SCIP_EXPRDATA_MONOMIAL* monomial;
16763  SCIP_EXPR** exprs;
16764  int f;
16765 
16766  /* create expression for each factor, assemble varidx and nexprvars
16767  * create child indices (= identity) */
16768  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
16769  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
16770  for( f = 0; f < monomials[i]->nfactors; ++f )
16771  {
16772  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
16773  childidxs[f] = f; /*lint !e644*/
16774  }
16775 
16776  /* create monomial and polynomial expression for this monomial
16777  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
16778  */
16779  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
16780  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
16781  constant = 0.0;
16782 
16783  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
16784  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
16785  }
16786 
16787  /* create expression tree for expr */
16788  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16789 
16790  /* copy variables into expression tree */
16791  if( nexprvars > 0 )
16792  {
16793  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16794  for( j = 0; j < exprgraph->nvars; ++j )
16795  {
16796  assert(varidx[j] >= -1);
16797  assert(varidx[j] < nexprvars);
16798  if( varidx[j] >= 0 )
16799  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16800  }
16801  }
16802 
16803  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
16804 
16805  ++*nexprtrees;
16806  }
16807 
16808  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
16809  if( constant != 0.0 )
16810  {
16811  SCIP_EXPR* constexpr_;
16812 
16813  assert(*nexprtrees > 0);
16814  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
16815  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16816  }
16817 
16818  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16819 
16820  break;
16821  }
16822 
16823  default:
16824  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16825  return SCIP_ERROR;
16826  } /*lint !e788*/
16827 
16828  return SCIP_OKAY;
16829 }
16830 
16831 /**@} */
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)
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13078
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15567
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:15248
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 QUADELEMS_SWAP(x, y)
Definition: expr.c:8911
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:14706
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:14906
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:16494
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:14990
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:14496
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:1562
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:12716
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:14676
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:198
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:96
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:14646
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:13277
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:15063
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:14750
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:12694
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:13207
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)
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:15621
#define FALSE
Definition: def.h:53
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:2052
#define EPSEQ(x, y, eps)
Definition: def.h:149
#define EPSISINT(x, eps)
Definition: def.h:161
#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:14696
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:8450
static SCIP_RETCODE exprgraphAddExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPR *expr, void **vars, SCIP_EXPRGRAPHNODE **exprnode, SCIP_Bool *exprnodeisnew)
Definition: expr.c:12466
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:12845
#define TRUE
Definition: def.h:52
#define SCIPdebug(x)
Definition: pub_message.h:74
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static int calcGrowSize(int num)
Definition: expr.c:105
static SCIP_RETCODE exprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op, int nchildren, SCIP_EXPR **children, SCIP_EXPROPDATA opdata)
Definition: expr.c: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
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:12736
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:13068
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15546
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:14656
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:78
SCIP_RETCODE SCIPexprEvalInt(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7797
#define EPSGE(x, y, eps)
Definition: def.h:153
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:8209
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
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:15108
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2111
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:14857
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12939
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:12581
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:14141
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:1475
static SCIP_DECL_EXPREVAL(exprevalVar)
Definition: expr.c:1410
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:2154
#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:12776
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:12927
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:14818
#define SCIP_ALLOC_ABORT(x)
Definition: def.h:253
#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:12786
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:12867
#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:12951
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:14381
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13088
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:15449
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:14718
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
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:102
SCIP_RETCODE SCIPexprgraphCheckCurvature(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop)
Definition: expr.c:15653
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:14666
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16458
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:1152
SCIPInterval sqrt(const SCIPInterval &x)
SCIP_Bool SCIPexprgraphHasNodeUserEstimator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13056
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:2070
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
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
#define REALABS(x)
Definition: def.h:148
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:13181
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16008
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_CALL(x)
Definition: def.h:263
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12706
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14810
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
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:14434
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:14346
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:12966
#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:12797
#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:12879
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:419
SCIP_RETCODE SCIPexprMultiplyPolynomialByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR *factor, int *childmap)
Definition: expr.c: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:50
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:14365
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
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:14770
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:8240
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:16442
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:14790
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:13329
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)
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
#define EPSLE(x, y, eps)
Definition: def.h:151
void SCIPexprgraphFreeNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14263
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static void exprgraphNodePropagateBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:10041
#define SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED
Definition: type_expr.h:210
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14315
#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:1622
#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)
#define BMSclearMemory(ptr)
Definition: memory.h:84
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:12808
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:12891
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:1505
#define SCIP_REAL_MAX
Definition: def.h:125
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:7714
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:12834
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12746
SCIP_QUADELEM * quadelems
Definition: struct_expr.h:71
static void exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:9192
#define EPSLT(x, y, eps)
Definition: def.h:150
#define SCIP_DECL_EXPRGRAPHVARREMOVE(x)
Definition: type_expr.h:191
static SCIP_RETCODE polynomialdataAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:741
#define EPSGT(x, y, eps)
Definition: def.h:152
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:97
SCIP_EXPRINTDATA * interpreterdata
Definition: struct_expr.h:63
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2172
#define exprcurvCos
Definition: expr.c:2084
SCIP_Bool SCIPexprgraphFindVarNode(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_EXPRGRAPHNODE **varnode)
Definition: expr.c:15420
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8050
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12856
#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
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12766
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:13258
SCIP_Bool parentssorted
Definition: struct_expr.h:133
#define SCIP_VARTYPE_CONTINUOUS_CHAR
Definition: def.h:98
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:13233
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:13044
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:13098
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:14173
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:2132
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:15955
#define SCIP_DECL_USEREXPRCOPYDATA(x)
Definition: type_expr.h:291
#define SCIP_Real
Definition: def.h:124
#define EPSROUND(x, eps)
Definition: def.h:159
#define MIN(x, y)
Definition: memory.c:63
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:12726
#define SCIP_INVALID
Definition: def.h:144
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:14418
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:8866
#define SCIPisFinite(x)
Definition: pub_misc.h:5425
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:9927
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:95
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:15696
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
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 BMSallocBlockMemory(mem, ptr)
Definition: memory.h:406
SCIP_RETCODE SCIPexprMultiplyPolynomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6594
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12823
#define EPSFLOOR(x, eps)
Definition: def.h:157
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2089
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:85
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:12915
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:242
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14686
#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:274
#define SCIPABORT()
Definition: def.h:235
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
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:15497
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:412
void SCIPintervalSetRoundingModeDownwards(void)
#define EPSZ(x, eps)
Definition: def.h:154
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:12756
#define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize)
Definition: expr.c:51
SCIP_EXPRCURV SCIPexprcurvNegate(SCIP_EXPRCURV curvature)
Definition: expr.c:197
SCIP_RETCODE SCIPexprtreeEval(SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
Definition: expr.c:8563
SCIP_EXPRINTCAPABILITY evalcapability
Definition: struct_expr.h:104
void SCIPexprgraphSetVarBounds(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_INTERVAL varbounds)
Definition: expr.c:14730
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:14288
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12903