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-2019 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 visit 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/misc.h"
37 #include "scip/pub_message.h"
38 
39 
40 #define SCIP_EXPRESSION_MAXCHILDEST 16 /**< estimate on maximal number of children */
41 
42 /** sign of a value (-1 or +1)
43  *
44  * 0.0 has sign +1
45  */
46 #define SIGN(x) ((x) >= 0.0 ? 1.0 : -1.0)
47 
48 /** ensures that a block memory array has at least a given size
49  *
50  * if cursize is 0, then *array1 can be NULL
51  */
52 #define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize) \
53  do { \
54  int __newsize; \
55  assert((blkmem) != NULL); \
56  if( *(cursize) >= (minsize) ) \
57  break; \
58  __newsize = calcGrowSize(minsize); \
59  assert(__newsize >= (minsize)); \
60  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
61  *(cursize) = __newsize; \
62  } while( FALSE )
63 
64 #ifdef SCIP_DISABLED_CODE /* this macro is currently not used, which offends lint, so disable it */
65 /** ensures that two block memory arrays have at least a given size
66  *
67  * if cursize is 0, then arrays can be NULL
68  */
69 #define ensureBlockMemoryArraySize2(blkmem, array1, array2, cursize, minsize) \
70  do { \
71  int __newsize; \
72  assert((blkmem) != NULL); \
73  if( *(cursize) >= (minsize) ) \
74  break; \
75  __newsize = calcGrowSize(minsize); \
76  assert(__newsize >= (minsize)); \
77  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
78  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
79  *(cursize) = __newsize; \
80  } while( FALSE )
81 #endif
82 
83 /** ensures that three block memory arrays have at least a given size
84  *
85  * if cursize is 0, then arrays can be NULL
86  */
87 #define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize) \
88  do { \
89  int __newsize; \
90  assert((blkmem) != NULL); \
91  if( *(cursize) >= (minsize) ) \
92  break; \
93  __newsize = calcGrowSize(minsize); \
94  assert(__newsize >= (minsize)); \
95  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
96  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
97  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array3, *(cursize), __newsize) ); \
98  *(cursize) = __newsize; \
99  } while( FALSE )
100 
101 /**@name Miscellaneous private methods */
102 /**@{ */
103 
104 /** calculate memory size for dynamically allocated arrays (copied from scip/set.c) */
105 static
107  int num /**< minimum number of entries to store */
108  )
109 {
110  int size;
111 
112  /* calculate the size with this loop, such that the resulting numbers are always the same (-> block memory) */
113  size = 4;
114  while( size < num )
115  size = (int)(1.2 * size + 4);
116 
117  return size;
118 }
119 
120 /** expression graph nodes comparison to use in sorting methods
121  *
122  * The nodes need to have been added to the expression graph (depth,pos >= 0).
123  * The better node is the one with the lower depth and lower position, if depth is equal.
124  */
125 static
126 SCIP_DECL_SORTPTRCOMP(exprgraphnodecomp)
127 {
128  SCIP_EXPRGRAPHNODE* node1 = (SCIP_EXPRGRAPHNODE*)elem1;
129  SCIP_EXPRGRAPHNODE* node2 = (SCIP_EXPRGRAPHNODE*)elem2;
130 
131  assert(node1 != NULL);
132  assert(node2 != NULL);
133  assert(node1->depth >= 0);
134  assert(node1->pos >= 0);
135  assert(node2->depth >= 0);
136  assert(node2->pos >= 0);
137 
138  if( node1->depth != node2->depth )
139  return node1->depth - node2->depth;
140 
141  /* there should be no two nodes on the same position */
142  assert((node1->pos != node2->pos) || (node1 == node2));
143 
144  return node1->pos - node2->pos;
145 }
146 
147 /** 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) */
148 static
150  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
151  SCIP_Real newlb, /**< new lower bound */
152  SCIP_Real oldlb, /**< old lower bound */
153  SCIP_Real oldub /**< old upper bound */
154  )
155 {
156  SCIP_Real eps;
157 
158  /* nothing can be tighter than an empty interval */
159  if( oldlb > oldub )
160  return FALSE;
161 
162  eps = REALABS(oldlb);
163  eps = MIN(oldub - oldlb, eps);
164  return EPSGT(newlb, oldlb, minstrength * MAX(eps, 1e-3));
165 }
166 
167 /** 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) */
168 static
170  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
171  SCIP_Real newub, /**< new upper bound */
172  SCIP_Real oldlb, /**< old lower bound */
173  SCIP_Real oldub /**< old upper bound */
174  )
175 {
176  SCIP_Real eps;
177 
178  /* nothing can be tighter than an empty interval */
179  if( oldlb > oldub )
180  return FALSE;
181 
182  eps = REALABS(oldub);
183  eps = MIN(oldub - oldlb, eps);
184  return EPSLT(newub, oldub, minstrength * MAX(eps, 1e-3));
185 }
186 
187 /**@} */
188 
189 /**@name Expression curvature methods */
190 /**@{ */
191 
192 /** curvature names as strings */
193 static
194 const char* curvnames[4] =
195  {
196  "unknown",
197  "convex",
198  "concave",
199  "linear"
200  };
201 
202 #undef SCIPexprcurvAdd
203 
204 /** gives curvature for a sum of two functions with given curvature */
206  SCIP_EXPRCURV curv1, /**< curvature of first summand */
207  SCIP_EXPRCURV curv2 /**< curvature of second summand */
208  )
209 {
210  return (SCIP_EXPRCURV) (curv1 & curv2);
211 }
212 
213 /** gives the curvature for the negation of a function with given curvature */
215  SCIP_EXPRCURV curvature /**< curvature of function */
216  )
217 {
218  switch( curvature )
219  {
221  return SCIP_EXPRCURV_CONVEX;
222 
224  return SCIP_EXPRCURV_CONCAVE;
225 
228  /* can return curvature, do this below */
229  break;
230 
231  default:
232  SCIPerrorMessage("unknown curvature status.\n");
233  SCIPABORT();
234  }
235 
236  return curvature;
237 }
238 
239 /** gives curvature for a functions with given curvature multiplied by a constant factor */
241  SCIP_Real factor, /**< constant factor */
242  SCIP_EXPRCURV curvature /**< curvature of other factor */
243  )
244 {
245  if( factor == 0.0 )
246  return SCIP_EXPRCURV_LINEAR;
247  if( factor > 0.0 )
248  return curvature;
249  return SCIPexprcurvNegate(curvature);
250 }
251 
252 /** gives curvature for base^exponent for given bounds and curvature of base-function and constant exponent */
254  SCIP_INTERVAL basebounds, /**< bounds on base function */
255  SCIP_EXPRCURV basecurv, /**< curvature of base function */
256  SCIP_Real exponent /**< exponent */
257  )
258 {
259  SCIP_Bool expisint;
260 
261  assert(basebounds.inf <= basebounds.sup);
262 
263  if( exponent == 0.0 )
264  return SCIP_EXPRCURV_LINEAR;
265 
266  if( exponent == 1.0 )
267  return basecurv;
268 
269  expisint = EPSISINT(exponent, 0.0); /*lint !e835*/
270 
271  /* if exponent is fractional, then power is not defined for a negative base
272  * thus, consider only positive part of basebounds
273  */
274  if( !expisint && basebounds.inf < 0.0 )
275  {
276  basebounds.inf = 0.0;
277  if( basebounds.sup < 0.0 )
278  return SCIP_EXPRCURV_LINEAR;
279  }
280 
281  /* if basebounds contains 0.0, consider negative and positive interval separately, if possible */
282  if( basebounds.inf < 0.0 && basebounds.sup > 0.0 )
283  {
284  SCIP_INTERVAL leftbounds;
285  SCIP_INTERVAL rightbounds;
286 
287  /* 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 */
288  if( exponent < 0.0 )
289  return SCIP_EXPRCURV_UNKNOWN;
290 
291  SCIPintervalSetBounds(&leftbounds, basebounds.inf, 0.0);
292  SCIPintervalSetBounds(&rightbounds, 0.0, basebounds.sup);
293 
294  return (SCIP_EXPRCURV) (SCIPexprcurvPower(leftbounds, basecurv, exponent) & SCIPexprcurvPower(rightbounds, basecurv, exponent));
295  }
296  assert(basebounds.inf >= 0.0 || basebounds.sup <= 0.0);
297 
298  /* (base^exponent)'' = exponent * ( (exponent-1) base^(exponent-2) (base')^2 + base^(exponent-1) base'' )
299  *
300  * if base'' is positive, i.e., base is convex, then
301  * - for base > 0.0 and exponent > 1.0, the second deriv. is positive -> convex
302  * - for base < 0.0 and exponent > 1.0, we can't say (first and second summand opposite signs)
303  * - for base > 0.0 and 0.0 < exponent < 1.0, we can't say (first sommand negative, second summand positive)
304  * - for base > 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
305  * - for base < 0.0 and exponent < 0.0 and even, the second deriv. is positive -> convex
306  * - for base < 0.0 and exponent < 0.0 and odd, the second deriv. is negative -> concave
307  *
308  * if base'' is negative, i.e., base is concave, then
309  * - for base > 0.0 and exponent > 1.0, we can't say (first summand positive, second summand negative)
310  * - for base < 0.0 and exponent > 1.0 and even, the second deriv. is positive -> convex
311  * - for base < 0.0 and exponent > 1.0 and odd, the second deriv. is negative -> concave
312  * - for base > 0.0 and 0.0 < exponent < 1.0, the second deriv. is negative -> concave
313  * - for base > 0.0 and exponent < 0.0, the second deriv. is positive -> convex
314  * - for base < 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
315  *
316  * if base'' is zero, i.e., base is linear, then
317  * (base^exponent)'' = exponent * (exponent-1) base^(exponent-2) (base')^2
318  * - just multiply signs
319  */
320 
321  if( basecurv == SCIP_EXPRCURV_LINEAR )
322  {
323  SCIP_Real sign;
324 
325  /* base^(exponent-2) is negative, if base < 0.0 and exponent is odd */
326  sign = exponent * (exponent - 1.0);
327  assert(basebounds.inf >= 0.0 || expisint);
328  if( basebounds.inf < 0.0 && ((int)exponent)%2 != 0 )
329  sign *= -1.0;
330  assert(sign != 0.0);
331 
332  return sign > 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
333  }
334 
335  if( basecurv == SCIP_EXPRCURV_CONVEX )
336  {
337  if( basebounds.sup <= 0.0 && exponent < 0.0 && expisint )
338  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
339  if( basebounds.inf >= 0.0 && exponent > 1.0 )
340  return SCIP_EXPRCURV_CONVEX ;
341  return SCIP_EXPRCURV_UNKNOWN;
342  }
343 
344  if( basecurv == SCIP_EXPRCURV_CONCAVE )
345  {
346  if( basebounds.sup <= 0.0 && exponent > 1.0 && expisint )
347  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
348  if( basebounds.inf >= 0.0 && exponent < 1.0 )
349  return exponent < 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
350  return SCIP_EXPRCURV_UNKNOWN;
351  }
352 
353  return SCIP_EXPRCURV_UNKNOWN;
354 }
355 
356 /** gives curvature for a monomial with given curvatures and bounds for each factor
357  *
358  * See Maranas and Floudas, Finding All Solutions of Nonlinearly Constrained Systems of Equations, JOGO 7, 1995
359  * for the categorization in the case that all factors are linear.
360  */
362  int nfactors, /**< number of factors in monomial */
363  SCIP_Real* exponents, /**< exponents in monomial, or NULL if all 1.0 */
364  int* factoridxs, /**< indices of factors (but not exponents), or NULL if identity mapping */
365  SCIP_EXPRCURV* factorcurv, /**< curvature of each factor */
366  SCIP_INTERVAL* factorbounds /**< bounds of each factor */
367  )
368 {
369  SCIP_Real mult;
370  SCIP_Real e;
371  SCIP_EXPRCURV curv;
372  SCIP_EXPRCURV fcurv;
373  int nnegative;
374  int npositive;
375  SCIP_Real sum;
376  SCIP_Bool expcurvpos;
377  SCIP_Bool expcurvneg;
378  int j;
379  int f;
380 
381  assert(nfactors >= 0);
382  assert(factorcurv != NULL || nfactors == 0);
383  assert(factorbounds != NULL || nfactors == 0);
384 
385  if( nfactors == 0 )
386  return SCIP_EXPRCURV_LINEAR;
387 
388  if( nfactors == 1 )
389  {
390  f = factoridxs != NULL ? factoridxs[0] : 0;
391  e = exponents != NULL ? exponents[0] : 1.0;
392  /* SCIPdebugMessage("monomial [%g,%g]^%g is %s\n",
393  factorbounds[f].inf, factorbounds[f].sup, e,
394  SCIPexprcurvGetName(SCIPexprcurvPower(factorbounds[f], factorcurv[f], e))); */
395  return SCIPexprcurvPower(factorbounds[f], factorcurv[f], e); /*lint !e613*/
396  }
397 
398  mult = 1.0;
399 
400  nnegative = 0; /* number of negative exponents */
401  npositive = 0; /* number of positive exponents */
402  sum = 0.0; /* sum of exponents */
403  expcurvpos = TRUE; /* whether exp_j * f_j''(x) >= 0 for all factors (assuming f_j >= 0) */
404  expcurvneg = TRUE; /* whether exp_j * f_j''(x) <= 0 for all factors (assuming f_j >= 0) */
405 
406  for( j = 0; j < nfactors; ++j )
407  {
408  f = factoridxs != NULL ? factoridxs[j] : j;
409  if( factorcurv[f] == SCIP_EXPRCURV_UNKNOWN ) /*lint !e613*/
410  return SCIP_EXPRCURV_UNKNOWN;
411  if( factorbounds[f].inf < 0.0 && factorbounds[f].sup > 0.0 ) /*lint !e613*/
412  return SCIP_EXPRCURV_UNKNOWN;
413 
414  e = exponents != NULL ? exponents[j] : 1.0;
415  if( e < 0.0 )
416  ++nnegative;
417  else
418  ++npositive;
419  sum += e;
420 
421  if( factorbounds[f].inf < 0.0 ) /*lint !e613*/
422  {
423  /* if argument is negative, then exponent should be integer */
424  assert(EPSISINT(e, 0.0)); /*lint !e835*/
425 
426  /* flip j'th argument: (f_j)^(exp_j) = (-1)^(exp_j) (-f_j)^(exp_j) */
427 
428  /* -f_j has negated curvature of f_j */
429  fcurv = SCIPexprcurvNegate(factorcurv[f]); /*lint !e613*/
430 
431  /* negate monomial, if exponent is odd, i.e., (-1)^(exp_j) = -1 */
432  if( (int)e % 2 != 0 )
433  mult *= -1.0;
434  }
435  else
436  {
437  fcurv = factorcurv[f]; /*lint !e613*/
438  }
439 
440  /* check if exp_j * fcurv is convex (>= 0) and/or concave */
441  fcurv = SCIPexprcurvMultiply(e, fcurv);
442  if( !(fcurv & SCIP_EXPRCURV_CONVEX) )
443  expcurvpos = FALSE;
444  if( !(fcurv & SCIP_EXPRCURV_CONCAVE) )
445  expcurvneg = FALSE;
446  }
447 
448  /* if all factors are linear, then a product f_j^exp_j with f_j >= 0 is convex if
449  * - all exponents are negative, or
450  * - 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
451  * further, the product is concave if
452  * - all exponents are positive and the sum of exponents is <= 1.0
453  *
454  * if factors are nonlinear, then we require additionally, that for convexity
455  * - each factor is convex if exp_j >= 0, or concave if exp_j <= 0, i.e., exp_j*f_j'' >= 0
456  * and for concavity, we require that
457  * - all factors are concave, i.e., exp_j*f_j'' <= 0
458  */
459 
460  if( nnegative == nfactors && expcurvpos )
461  curv = SCIP_EXPRCURV_CONVEX;
462  else if( nnegative == nfactors-1 && EPSGE(sum, 1.0, 1e-9) && expcurvpos )
463  curv = SCIP_EXPRCURV_CONVEX;
464  else if( npositive == nfactors && EPSLE(sum, 1.0, 1e-9) && expcurvneg )
465  curv = SCIP_EXPRCURV_CONCAVE;
466  else
467  curv = SCIP_EXPRCURV_UNKNOWN;
468  curv = SCIPexprcurvMultiply(mult, curv);
469 
470  return curv;
471 }
472 
473 /** gives name as string for a curvature */
475  SCIP_EXPRCURV curv /**< curvature */
476  )
477 {
478  assert(curv <= SCIP_EXPRCURV_LINEAR); /*lint !e685*/
479 
480  return curvnames[curv];
481 }
482 
483 /**@} */
484 
485 /**@name Quadratic expression data private methods */
486 /**@{ */
487 
488 /** creates SCIP_EXPRDATA_QUADRATIC data structure from given quadratic elements */
489 static
491  BMS_BLKMEM* blkmem, /**< block memory data structure */
492  SCIP_EXPRDATA_QUADRATIC** quadraticdata, /**< buffer to store pointer to quadratic data */
493  SCIP_Real constant, /**< constant */
494  int nchildren, /**< number of children */
495  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
496  int nquadelems, /**< number of quadratic elements */
497  SCIP_QUADELEM* quadelems /**< quadratic elements */
498  )
499 {
500  assert(blkmem != NULL);
501  assert(quadraticdata != NULL);
502  assert(quadelems != NULL || nquadelems == 0);
503  assert(nchildren >= 0);
504 
505  SCIP_ALLOC( BMSallocBlockMemory(blkmem, quadraticdata) );
506 
507  (*quadraticdata)->constant = constant;
508  (*quadraticdata)->lincoefs = NULL;
509  (*quadraticdata)->nquadelems = nquadelems;
510  (*quadraticdata)->quadelems = NULL;
511  (*quadraticdata)->sorted = (nquadelems <= 1);
512 
513  if( lincoefs != NULL )
514  {
515  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->lincoefs, lincoefs, nchildren) );
516  }
517 
518  if( nquadelems > 0 )
519  {
520  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->quadelems, quadelems, nquadelems) );
521  }
522 
523  return SCIP_OKAY;
524 }
525 
526 /** sorts quadratic elements in a SCIP_EXPRDATA_QUADRATIC data structure */
527 static
529  SCIP_EXPRDATA_QUADRATIC* quadraticdata /**< quadratic data */
530  )
531 {
532  assert(quadraticdata != NULL);
533 
534  if( quadraticdata->sorted )
535  {
536 #ifndef NDEBUG
537  int i;
538  for( i = 1; i < quadraticdata->nquadelems; ++i )
539  {
540  assert(quadraticdata->quadelems[i].idx1 <= quadraticdata->quadelems[i].idx2);
541  assert(quadraticdata->quadelems[i-1].idx1 <= quadraticdata->quadelems[i].idx1);
542  assert(quadraticdata->quadelems[i-1].idx1 < quadraticdata->quadelems[i].idx1 ||
543  quadraticdata->quadelems[i-1].idx2 <= quadraticdata->quadelems[i].idx2);
544  }
545 #endif
546  return;
547  }
548 
549  if( quadraticdata->nquadelems > 0 )
550  SCIPquadelemSort(quadraticdata->quadelems, quadraticdata->nquadelems);
551 
552  quadraticdata->sorted = TRUE;
553 }
554 
555 /**@} */
556 
557 /**@name Polynomial expression data private methods */
558 /**@{ */
559 
560 /** compares two monomials
561  *
562  * gives 0 if monomials are equal */
563 static
564 SCIP_DECL_SORTPTRCOMP(monomialdataCompare)
565 {
566  SCIP_EXPRDATA_MONOMIAL* monomial1;
567  SCIP_EXPRDATA_MONOMIAL* monomial2;
568 
569  int i;
570 
571  assert(elem1 != NULL);
572  assert(elem2 != NULL);
573 
574  monomial1 = (SCIP_EXPRDATA_MONOMIAL*)elem1;
575  monomial2 = (SCIP_EXPRDATA_MONOMIAL*)elem2;
576 
577  /* make sure, both monomials are equal */
578  SCIPexprSortMonomialFactors(monomial1);
579  SCIPexprSortMonomialFactors(monomial2);
580 
581  /* for the first factor where both monomials differ,
582  * we return either the difference in the child indices, if children are different
583  * or the sign of the difference in the exponents
584  */
585  for( i = 0; i < monomial1->nfactors && i < monomial2->nfactors; ++i )
586  {
587  if( monomial1->childidxs[i] != monomial2->childidxs[i] )
588  return monomial1->childidxs[i] - monomial2->childidxs[i];
589  if( monomial1->exponents[i] > monomial2->exponents[i] )
590  return 1;
591  else if( monomial1->exponents[i] < monomial2->exponents[i] )
592  return -1;
593  }
594 
595  /* if the factors of one monomial are a proper subset of the factors of the other monomial,
596  * we return the difference in the number of monomials
597  */
598  return monomial1->nfactors - monomial2->nfactors;
599 }
600 
601 /** ensures that the factors arrays of a monomial have at least a given size */
602 static
604  BMS_BLKMEM* blkmem, /**< block memory data structure */
605  SCIP_EXPRDATA_MONOMIAL* monomialdata, /**< monomial data */
606  int minsize /**< minimal size of factors arrays */
607  )
608 {
609  assert(blkmem != NULL);
610  assert(monomialdata != NULL);
611 
612  if( minsize > monomialdata->factorssize )
613  {
614  int newsize;
615 
616  newsize = calcGrowSize(minsize);
617  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->childidxs, monomialdata->factorssize, newsize) );
618  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->exponents, monomialdata->factorssize, newsize) );
619  monomialdata->factorssize = newsize;
620  }
621  assert(minsize <= monomialdata->factorssize);
622 
623  return SCIP_OKAY;
624 }
625 
626 /** creates SCIP_EXPRDATA_POLYNOMIAL data structure from given monomials */
627 static
629  BMS_BLKMEM* blkmem, /**< block memory data structure */
630  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
631  int nmonomials, /**< number of monomials */
632  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
633  SCIP_Real constant, /**< constant part */
634  SCIP_Bool copymonomials /**< whether to copy monomials, or copy only given pointers, in which case polynomialdata assumes ownership of monomial structure */
635  )
636 {
637  assert(blkmem != NULL);
638  assert(polynomialdata != NULL);
639  assert(monomials != NULL || nmonomials == 0);
640 
641  SCIP_ALLOC( BMSallocBlockMemory(blkmem, polynomialdata) );
642 
643  (*polynomialdata)->constant = constant;
644  (*polynomialdata)->nmonomials = nmonomials;
645  (*polynomialdata)->monomialssize = nmonomials;
646  (*polynomialdata)->monomials = NULL;
647  (*polynomialdata)->sorted = (nmonomials <= 1);
648 
649  if( nmonomials > 0 )
650  {
651  int i;
652 
653  if( copymonomials )
654  {
655  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, nmonomials) );
656 
657  for( i = 0; i < nmonomials; ++i )
658  {
659  assert(monomials[i] != NULL); /*lint !e613*/
660  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i],
661  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
662  }
663  }
664  else
665  {
666  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, monomials, nmonomials) );
667  }
668  }
669 
670  return SCIP_OKAY;
671 }
672 
673 /** creates a copy of a SCIP_EXPRDATA_POLYNOMIAL data structure */
674 static
676  BMS_BLKMEM* blkmem, /**< block memory data structure */
677  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
678  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata /**< polynomial data to copy */
679  )
680 {
681  assert(blkmem != NULL);
682  assert(polynomialdata != NULL);
683  assert(sourcepolynomialdata != NULL);
684 
685  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, polynomialdata, sourcepolynomialdata) );
686 
687  (*polynomialdata)->monomialssize = sourcepolynomialdata->nmonomials;
688  if( sourcepolynomialdata->nmonomials > 0 )
689  {
690  int i;
691 
692  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize) );
693 
694  for( i = 0; i < sourcepolynomialdata->nmonomials; ++i )
695  {
696  assert(sourcepolynomialdata->monomials[i] != NULL); /*lint !e613*/
697  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i], sourcepolynomialdata->monomials[i]->coef,
698  sourcepolynomialdata->monomials[i]->nfactors, sourcepolynomialdata->monomials[i]->childidxs, sourcepolynomialdata->monomials[i]->exponents) );
699  (*polynomialdata)->monomials[i]->sorted = sourcepolynomialdata->monomials[i]->sorted;
700  }
701  }
702  else
703  {
704  (*polynomialdata)->monomials = NULL;
705  }
706 
707  return SCIP_OKAY;
708 }
709 
710 /** frees a SCIP_EXPRDATA_POLYNOMIAL data structure */
711 static
713  BMS_BLKMEM* blkmem, /**< block memory data structure */
714  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata /**< pointer to polynomial data to free */
715  )
716 {
717  assert(blkmem != NULL);
718  assert(polynomialdata != NULL);
719  assert(*polynomialdata != NULL);
720 
721  if( (*polynomialdata)->monomialssize > 0 )
722  {
723  int i;
724 
725  for( i = 0; i < (*polynomialdata)->nmonomials; ++i )
726  {
727  assert((*polynomialdata)->monomials[i] != NULL);
728  SCIPexprFreeMonomial(blkmem, &(*polynomialdata)->monomials[i]);
729  assert((*polynomialdata)->monomials[i] == NULL);
730  }
731 
732  BMSfreeBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize);
733  }
734  assert((*polynomialdata)->monomials == NULL);
735 
736  BMSfreeBlockMemory(blkmem, polynomialdata);
737 }
738 
739 /** ensures that the monomials array of a polynomial has at least a given size */
740 static
742  BMS_BLKMEM* blkmem, /**< block memory data structure */
743  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
744  int minsize /**< minimal size of monomials array */
745  )
746 {
747  assert(blkmem != NULL);
748  assert(polynomialdata != NULL);
749 
750  ensureBlockMemoryArraySize(blkmem, &polynomialdata->monomials, &polynomialdata->monomialssize, minsize);
751  assert(minsize <= polynomialdata->monomialssize);
752 
753  return SCIP_OKAY;
754 }
755 
756 /** adds an array of monomials to a polynomial */
757 static
759  BMS_BLKMEM* blkmem, /**< block memory of expression */
760  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
761  int nmonomials, /**< number of monomials to add */
762  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
763  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
764  )
765 {
766  int i;
767 
768  assert(blkmem != NULL);
769  assert(polynomialdata != NULL);
770  assert(monomials != NULL || nmonomials == 0);
771 
772  if( nmonomials == 0 )
773  return SCIP_OKAY;
774 
775  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials + nmonomials) );
776  assert(polynomialdata->monomialssize >= polynomialdata->nmonomials + nmonomials);
777 
778  if( copymonomials )
779  {
780  for( i = 0; i < nmonomials; ++i )
781  {
782  assert(monomials[i] != NULL); /*lint !e613*/
783  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials + i],
784  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
785  }
786  }
787  else
788  {
789  BMScopyMemoryArray(&polynomialdata->monomials[polynomialdata->nmonomials], monomials, nmonomials); /*lint !e866*/
790  }
791  polynomialdata->nmonomials += nmonomials;
792 
793  polynomialdata->sorted = (polynomialdata->nmonomials <= 1);
794 
795  return SCIP_OKAY;
796 }
797 
798 /** ensures that monomials of a polynomial are sorted */
799 static
801  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata /**< polynomial expression */
802  )
803 {
804  assert(polynomialdata != NULL);
805 
806  if( polynomialdata->sorted )
807  {
808 #ifndef NDEBUG
809  int i;
810 
811  /* a polynom with more than one monoms can only be sorted if its monoms are sorted */
812  for( i = 1; i < polynomialdata->nmonomials; ++i )
813  {
814  assert(polynomialdata->monomials[i-1]->sorted);
815  assert(polynomialdata->monomials[i]->sorted);
816  assert(monomialdataCompare(polynomialdata->monomials[i-1], polynomialdata->monomials[i]) <= 0);
817  }
818 #endif
819  return;
820  }
821 
822  if( polynomialdata->nmonomials > 0 )
823  SCIPsortPtr((void**)polynomialdata->monomials, monomialdataCompare, polynomialdata->nmonomials);
824 
825  polynomialdata->sorted = TRUE;
826 }
827 
828 /** merges monomials that differ only in coefficient into a single monomial
829  *
830  * Eliminates monomials with coefficient between -eps and eps.
831  */
832 static
834  BMS_BLKMEM* blkmem, /**< block memory */
835  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
836  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
837  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
838  )
839 {
840  int i;
841  int offset;
842  int oldnfactors;
843 
844  assert(polynomialdata != NULL);
845  assert(eps >= 0.0);
846 
847  polynomialdataSortMonomials(polynomialdata);
848 
849  /* merge monomials by adding their coefficients, eliminate monomials with no factors or zero coefficient*/
850  offset = 0;
851  i = 0;
852  while( i + offset < polynomialdata->nmonomials )
853  {
854  if( offset > 0 )
855  {
856  assert(polynomialdata->monomials[i] == NULL);
857  assert(polynomialdata->monomials[i+offset] != NULL);
858  polynomialdata->monomials[i] = polynomialdata->monomials[i+offset];
859 #ifndef NDEBUG
860  polynomialdata->monomials[i+offset] = NULL;
861 #endif
862  }
863 
864  if( mergefactors )
865  {
866  oldnfactors = polynomialdata->monomials[i]->nfactors;
867  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i], eps);
868 
869  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
870  if( oldnfactors != polynomialdata->monomials[i]->nfactors )
871  polynomialdata->sorted = FALSE;
872  }
873 
874  while( i+offset+1 < polynomialdata->nmonomials )
875  {
876  assert(polynomialdata->monomials[i+offset+1] != NULL);
877  if( mergefactors )
878  {
879  oldnfactors = polynomialdata->monomials[i+offset+1]->nfactors;
880  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i+offset+1], eps);
881 
882  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
883  if( oldnfactors != polynomialdata->monomials[i+offset+1]->nfactors )
884  polynomialdata->sorted = FALSE;
885  }
886  if( monomialdataCompare((void*)polynomialdata->monomials[i], (void*)polynomialdata->monomials[i+offset+1]) != 0 )
887  break;
888  polynomialdata->monomials[i]->coef += polynomialdata->monomials[i+offset+1]->coef;
889  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i+offset+1]);
890  ++offset;
891  }
892 
893  if( polynomialdata->monomials[i]->nfactors == 0 )
894  {
895  /* constant monomial */
896  polynomialdata->constant += polynomialdata->monomials[i]->coef;
897  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
898  ++offset;
899  continue;
900  }
901 
902  if( EPSZ(polynomialdata->monomials[i]->coef, eps) )
903  {
904  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
905  ++offset;
906  continue;
907  }
908 
909  ++i;
910  }
911 
912 #ifndef NDEBUG
913  for( ; i < polynomialdata->nmonomials; ++i )
914  assert(polynomialdata->monomials[i] == NULL);
915 #endif
916 
917  polynomialdata->nmonomials -= offset;
918 
919  if( EPSZ(polynomialdata->constant, eps) )
920  polynomialdata->constant = 0.0;
921 }
922 
923 /** multiplies each summand of a polynomial by a given constant */
924 static
926  BMS_BLKMEM* blkmem, /**< block memory */
927  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
928  SCIP_Real factor /**< constant factor */
929  )
930 {
931  int i;
932 
933  assert(polynomialdata != NULL);
934 
935  if( factor == 1.0 )
936  return;
937 
938  if( factor == 0.0 )
939  {
940  for( i = 0; i < polynomialdata->nmonomials; ++i )
941  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
942  polynomialdata->nmonomials = 0;
943  }
944  else
945  {
946  for( i = 0; i < polynomialdata->nmonomials; ++i )
947  SCIPexprChgMonomialCoef(polynomialdata->monomials[i], polynomialdata->monomials[i]->coef * factor);
948  }
949 
950  polynomialdata->constant *= factor;
951 }
952 
953 /** multiplies each summand of a polynomial by a given monomial */
954 static
956  BMS_BLKMEM* blkmem, /**< block memory */
957  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
958  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
959  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
960  )
961 {
962  int i;
963 
964  assert(blkmem != NULL);
965  assert(factor != NULL);
966  assert(polynomialdata != NULL);
967 
968  if( factor->nfactors == 0 )
969  {
970  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factor->coef);
971  return SCIP_OKAY;
972  }
973 
974  /* multiply each monomial by factor */
975  for( i = 0; i < polynomialdata->nmonomials; ++i )
976  {
977  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i], factor, childmap) );
978  }
979 
980  /* add new monomial for constant multiplied by factor */
981  if( polynomialdata->constant != 0.0 )
982  {
983  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
984  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
985  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[polynomialdata->nmonomials], factor, childmap) );
986  ++polynomialdata->nmonomials;
987  polynomialdata->sorted = FALSE;
988  polynomialdata->constant = 0.0;
989  }
990 
991  return SCIP_OKAY;
992 }
993 
994 /** multiplies a polynomial by a polynomial
995  *
996  * Factors need to be different.
997  */
998 static
1000  BMS_BLKMEM* blkmem, /**< block memory */
1001  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1002  SCIP_EXPRDATA_POLYNOMIAL* factordata, /**< polynomial factor data */
1003  int* childmap /**< map children in factor to children in polynomialdata, or NULL for 1:1 */
1004  )
1005 {
1006  int i1;
1007  int i2;
1008  int orignmonomials;
1009 
1010  assert(blkmem != NULL);
1011  assert(polynomialdata != NULL);
1012  assert(factordata != NULL);
1013  assert(polynomialdata != factordata);
1014 
1015  if( factordata->nmonomials == 0 )
1016  {
1017  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factordata->constant);
1018  return SCIP_OKAY;
1019  }
1020  assert(factordata->monomials != NULL);
1021 
1022  if( factordata->nmonomials == 1 && factordata->constant == 0.0 )
1023  {
1024  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, polynomialdata, factordata->monomials[0], childmap) );
1025  return SCIP_OKAY;
1026  }
1027 
1028  /* turn constant into a monomial, so we can assume below that constant is 0.0 */
1029  if( polynomialdata->constant != 0.0 )
1030  {
1031  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
1032  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
1033  ++polynomialdata->nmonomials;
1034  polynomialdata->sorted = FALSE;
1035  polynomialdata->constant = 0.0;
1036  }
1037 
1038  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials * (factordata->nmonomials + (factordata->constant == 0.0 ? 0 : 1))) );
1039 
1040  /* for each monomial in factordata (except the last, if factordata->constant is 0),
1041  * duplicate monomials from polynomialdata and multiply them by the monomial for factordata */
1042  orignmonomials = polynomialdata->nmonomials;
1043  for( i2 = 0; i2 < factordata->nmonomials; ++i2 )
1044  {
1045  /* add a copy of original monomials to end of polynomialdata's monomials array */
1046  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 */
1047  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, orignmonomials, polynomialdata->monomials, TRUE) );
1048  assert(polynomialdata->nmonomials == (i2+2) * orignmonomials);
1049 
1050  /* multiply each copied monomial by current monomial from factordata */
1051  for( i1 = (i2+1) * orignmonomials; i1 < (i2+2) * orignmonomials; ++i1 )
1052  {
1053  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1054  }
1055 
1056  if( factordata->constant == 0.0 && i2 == factordata->nmonomials - 2 )
1057  {
1058  ++i2;
1059  break;
1060  }
1061  }
1062 
1063  if( factordata->constant != 0.0 )
1064  {
1065  assert(i2 == factordata->nmonomials);
1066  /* multiply original monomials in polynomialdata by constant in factordata */
1067  for( i1 = 0; i1 < orignmonomials; ++i1 )
1068  SCIPexprChgMonomialCoef(polynomialdata->monomials[i1], polynomialdata->monomials[i1]->coef * factordata->constant);
1069  }
1070  else
1071  {
1072  assert(i2 == factordata->nmonomials - 1);
1073  /* multiply original monomials in polynomialdata by last monomial in factordata */
1074  for( i1 = 0; i1 < orignmonomials; ++i1 )
1075  {
1076  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1077  }
1078  }
1079 
1080  return SCIP_OKAY;
1081 }
1082 
1083 /** takes a power of a polynomial
1084  *
1085  * Exponent needs to be an integer,
1086  * polynomial needs to be a monomial, if exponent is negative.
1087  */
1088 static
1090  BMS_BLKMEM* blkmem, /**< block memory */
1091  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1092  int exponent /**< exponent of power operation */
1093  )
1094 {
1095  SCIP_EXPRDATA_POLYNOMIAL* factor;
1096  int i;
1097 
1098  assert(blkmem != NULL);
1099  assert(polynomialdata != NULL);
1100 
1101  if( exponent == 0 )
1102  {
1103  /* x^0 = 1, except if x = 0 */
1104  if( polynomialdata->nmonomials == 0 && polynomialdata->constant == 0.0 )
1105  {
1106  polynomialdata->constant = 0.0;
1107  }
1108  else
1109  {
1110  polynomialdata->constant = 1.0;
1111 
1112  for( i = 0; i < polynomialdata->nmonomials; ++i )
1113  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
1114  polynomialdata->nmonomials = 0;
1115  }
1116 
1117  return SCIP_OKAY;
1118  }
1119 
1120  if( exponent == 1 )
1121  return SCIP_OKAY;
1122 
1123  if( polynomialdata->nmonomials == 1 && polynomialdata->constant == 0.0 )
1124  {
1125  /* polynomial is a single monomial */
1126  SCIPexprMonomialPower(polynomialdata->monomials[0], exponent);
1127  return SCIP_OKAY;
1128  }
1129 
1130  if( polynomialdata->nmonomials == 0 )
1131  {
1132  /* polynomial is a constant */
1133  polynomialdata->constant = pow(polynomialdata->constant, (SCIP_Real)exponent);
1134  return SCIP_OKAY;
1135  }
1136 
1137  assert(exponent >= 2); /* negative exponents not allowed if more than one monom */
1138 
1139  /* todo improve, look how SCIPintervalPowerScalar in intervalarith.c does it */
1140 
1141  /* get copy of our polynomial */
1142  SCIP_CALL( polynomialdataCopy(blkmem, &factor, polynomialdata) );
1143 
1144  /* do repeated multiplication */
1145  for( i = 2; i <= exponent; ++i )
1146  {
1147  SCIP_CALL( polynomialdataMultiplyByPolynomial(blkmem, polynomialdata, factor, NULL) );
1148  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
1149  }
1150 
1151  /* free copy again */
1152  polynomialdataFree(blkmem, &factor);
1153 
1154  return SCIP_OKAY;
1155 }
1156 
1157 /** applies a mapping of child indices to the indices used in polynomial monomials */
1158 static
1160  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1161  int* childmap /**< mapping of child indices */
1162  )
1163 {
1164  SCIP_EXPRDATA_MONOMIAL* monomial;
1165  int i;
1166  int j;
1167 
1168  assert(polynomialdata != NULL);
1169 
1170  for( i = 0; i < polynomialdata->nmonomials; ++i )
1171  {
1172  monomial = polynomialdata->monomials[i];
1173  assert(monomial != NULL);
1174 
1175  for( j = 0; j < monomial->nfactors; ++j )
1176  {
1177  monomial->childidxs[j] = childmap[monomial->childidxs[j]];
1178  assert(monomial->childidxs[j] >= 0);
1179  }
1180  monomial->sorted = FALSE;
1181  }
1182 
1183  polynomialdata->sorted = FALSE;
1184 }
1185 
1186 /** replaces a factor in a monomial by a polynomial and expands the result */
1187 static
1189  BMS_BLKMEM* blkmem, /**< block memory data structure */
1190  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1191  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data where to expand a monomial */
1192  int monomialpos, /**< position of monomial which factor to expand */
1193  int factorpos, /**< position of factor in monomial to expand */
1194  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomial,/**< polynomial that should replace factor */
1195  int* childmap, /**< map of child indices in factorpolynomial to children of polynomial */
1196  int maxexpansionexponent,/**< maximal exponent for which polynomials (with > 1 summands) are expanded */
1197  SCIP_Bool* success /**< buffer to store whether expansion has been done */
1198  )
1199 {
1200  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomialcopy;
1201  SCIP_EXPRDATA_MONOMIAL* monomial;
1202  int i;
1203 
1204  assert(blkmem != NULL);
1205  assert(polynomialdata != NULL);
1206  assert(factorpolynomial != NULL);
1207  assert(childmap != NULL || factorpolynomial->nmonomials == 0);
1208  assert(success != NULL);
1209  assert(monomialpos >= 0);
1210  assert(monomialpos < polynomialdata->nmonomials);
1211  assert(factorpos >= 0);
1212 
1213  monomial = polynomialdata->monomials[monomialpos];
1214  assert(monomial != NULL);
1215  assert(factorpos < monomial->nfactors);
1216 
1217  *success = TRUE;
1218 
1219  if( factorpolynomial->nmonomials == 0 )
1220  {
1221  /* factorpolynomial is a constant */
1222 
1223  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && factorpolynomial->constant < 0.0 ) /*lint !e835*/
1224  {
1225  /* if polynomial is a negative constant and our exponent is not integer, then cannot do expansion */
1226  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", factorpolynomial->constant, monomial->exponents[factorpos]);
1227  *success = FALSE;
1228  return SCIP_OKAY;
1229  }
1230  monomial->coef *= pow(factorpolynomial->constant, monomial->exponents[factorpos]);
1231 
1232  /* move last factor to position factorpos */
1233  if( factorpos < monomial->nfactors-1 )
1234  {
1235  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1236  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1237  }
1238  --monomial->nfactors;
1239  monomial->sorted = FALSE;
1240  polynomialdata->sorted = FALSE;
1241 
1242  return SCIP_OKAY;
1243  }
1244 
1245  if( factorpolynomial->constant == 0.0 && factorpolynomial->nmonomials == 1 )
1246  {
1247  /* factorpolynomial is a single monomial */
1248  SCIP_EXPRDATA_MONOMIAL* factormonomial;
1249  int childidx;
1250  SCIP_Real exponent;
1251 
1252  factormonomial = factorpolynomial->monomials[0];
1253  assert(factormonomial != NULL);
1254 
1255  if( !EPSISINT(monomial->exponents[factorpos], 0.0) ) /*lint !e835*/
1256  {
1257  if( factormonomial->coef < 0.0 )
1258  {
1259  /* if coefficient of monomial is negative and our exponent is not integer, then do not do expansion
1260  * @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
1261  */
1262  *success = FALSE;
1263  return SCIP_OKAY;
1264  }
1265  if( factormonomial->nfactors > 1 )
1266  {
1267  /* @todo if there is an even number of factors in factormonomial that are negative, then they always multiply to something positive
1268  * however, we cannot expand them as below, since we cannot compute the single powers
1269  * since we do not have the bounds on the factors here, we skip expansion in this case
1270  * MINLPLib instances tls2,4,6 are examples where we are loosing here (do not recognize convexity)
1271  */
1272  *success = FALSE;
1273  return SCIP_OKAY;
1274  }
1275  }
1276 
1277  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + factormonomial->nfactors) );
1278 
1279  for( i = 0; i < factormonomial->nfactors; ++i )
1280  {
1281  childidx = childmap[factormonomial->childidxs[i]]; /*lint !e613*/
1282  /* can do this because monomial->exponents[factorpos] is assumed to be integer or factormonomial has positive coefficient and only one factor
1283  * thus, if factormonomial->exponents[i] is fractional, then we can assume that it's argument is positive
1284  */
1285  exponent = factormonomial->exponents[i] * monomial->exponents[factorpos];
1286  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
1287  }
1288 
1289  monomial->coef *= pow(factormonomial->coef, monomial->exponents[factorpos]);
1290 
1291  /* move last factor to position factorpos */
1292  if( factorpos < monomial->nfactors-1 )
1293  {
1294  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1295  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1296  }
1297  --monomial->nfactors;
1298  monomial->sorted = FALSE;
1299  polynomialdata->sorted = FALSE;
1300 
1301  return SCIP_OKAY;
1302  }
1303 
1304  /* if exponent is negative or fractional and the polynomial is not just a monomial, then we cannot do expansion */
1305  if( !EPSISINT(monomial->exponents[factorpos], 0.0) || monomial->exponents[factorpos] < 0.0 ) /*lint !e835*/
1306  {
1307  *success = FALSE;
1308  return SCIP_OKAY;
1309  }
1310 
1311  /* if exponent is too large, skip expansion */
1312  if( monomial->exponents[factorpos] > maxexpansionexponent )
1313  {
1314  *success = FALSE;
1315  return SCIP_OKAY;
1316  }
1317 
1318  /* check whether maximal degree of expansion would exceed maxexpansionexponent
1319  * that is, assume monomial is f1^a1 f2^a2 ... and we want to expand f1 = (g11^beta11 g12^beta12... + g21^beta21 g22^beta22 ... + ...)
1320  * then we do this only if all ai and all beta are > 0.0 and a1 max(beta11+beta12+..., beta21+beta22+..., ...) + a2 + ... < maxexpansionexponent
1321  * exception (there need to be one) is if monomial is just f1
1322  */
1323  if( maxexpansionexponent < INT_MAX && (monomial->nfactors > 1 || monomial->exponents[factorpos] != 1.0) )
1324  {
1325  SCIP_Real restdegree;
1326  SCIP_Real degree;
1327  int j;
1328 
1329  restdegree = -monomial->exponents[factorpos];
1330  for( i = 0; i < monomial->nfactors; ++i )
1331  {
1332  if( monomial->exponents[i] < 0.0 )
1333  {
1334  /* ai < 0.0 */
1335  SCIPdebugMessage("skip expansion because factor %d in monomial has negative exponent\n", i);
1336  *success = FALSE;
1337  return SCIP_OKAY;
1338  }
1339  restdegree += monomial->exponents[i];
1340  }
1341 
1342  for( i = 0; i < factorpolynomial->nmonomials; ++i )
1343  {
1344  degree = 0.0;
1345  for( j = 0; j < factorpolynomial->monomials[i]->nfactors; ++j )
1346  {
1347  if( factorpolynomial->monomials[i]->exponents[j] < 0.0 )
1348  {
1349  /* beta_ij < 0.0 */
1350  SCIPdebugMessage("skip expansion because %d'th factor in %d'th monomial of factorpolynomial is negative\n", i, j);
1351  *success = FALSE;
1352  return SCIP_OKAY;
1353  }
1354  degree += factorpolynomial->monomials[i]->exponents[j];
1355  }
1356  if( degree * monomial->exponents[factorpos] + restdegree > maxexpansionexponent )
1357  {
1358  /* (beta_i1+beta_i2+...)*monomial->exponents[factorpos] + rest > maxexpansion */
1359  SCIPdebugMessage("skip expansion because degree of %d'th monomial would yield degree %g > max = %d in expansion\n",
1360  i, degree * monomial->exponents[factorpos] + restdegree, maxexpansionexponent);
1361  *success = FALSE;
1362  return SCIP_OKAY;
1363  }
1364  }
1365  }
1366 
1367  /* create a copy of factor */
1368  SCIP_CALL( polynomialdataCopy(blkmem, &factorpolynomialcopy, factorpolynomial) );
1369  /* apply childmap to copy */
1370  polynomialdataApplyChildmap(factorpolynomialcopy, childmap);
1371  /* create power of factor */
1372  SCIP_CALL( polynomialdataPower(blkmem, factorpolynomialcopy, (int)EPSFLOOR(monomial->exponents[factorpos], 0.0)) ); /*lint !e835*/
1373 
1374  /* remove factor from monomial by moving last factor to position factorpos */
1375  if( factorpos < monomial->nfactors-1 )
1376  {
1377  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1378  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1379  }
1380  --monomial->nfactors;
1381  monomial->sorted = FALSE;
1382 
1383  /* multiply factor with this reduced monomial */
1384  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, factorpolynomialcopy, monomial, NULL) );
1385 
1386  /* remove monomial from polynomial and move last monomial to monomialpos */
1387  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[monomialpos]);
1388  if( monomialpos < polynomialdata->nmonomials-1 )
1389  polynomialdata->monomials[monomialpos] = polynomialdata->monomials[polynomialdata->nmonomials-1];
1390  --polynomialdata->nmonomials;
1391  polynomialdata->sorted = FALSE;
1392 
1393  /* add factorpolynomialcopy to polynomial */
1394  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, factorpolynomialcopy->nmonomials, factorpolynomialcopy->monomials, FALSE) );
1395  polynomialdata->constant += factorpolynomialcopy->constant;
1396 
1397  factorpolynomialcopy->nmonomials = 0;
1398  polynomialdataFree(blkmem, &factorpolynomialcopy);
1399 
1400  return SCIP_OKAY;
1401 }
1402 
1403 /**@} */
1404 
1405 /**@name Expression operand private methods */
1406 /**@{ */
1407 
1408 /** a default implementation of expression interval evaluation that always gives a correct result */
1409 static
1410 SCIP_DECL_EXPRINTEVAL( exprevalIntDefault )
1411 { /*lint --e{715}*/
1413 
1414  return SCIP_OKAY;
1415 }
1416 
1417 /** a default implementation of expression curvature check that always gives a correct result */
1418 static
1419 SCIP_DECL_EXPRCURV( exprcurvDefault )
1420 { /*lint --e{715}*/
1421  *result = SCIP_EXPRCURV_UNKNOWN;
1422 
1423  return SCIP_OKAY;
1424 }
1425 
1426 /** point evaluation for EXPR_VAR */
1427 static
1428 SCIP_DECL_EXPREVAL( exprevalVar )
1429 { /*lint --e{715}*/
1430  assert(result != NULL);
1431  assert(varvals != NULL);
1432 
1433  *result = varvals[opdata.intval];
1434 
1435  return SCIP_OKAY;
1436 }
1437 
1438 /** interval evaluation for EXPR_VAR */
1439 static
1440 SCIP_DECL_EXPRINTEVAL( exprevalIntVar )
1441 { /*lint --e{715}*/
1442  assert(result != NULL);
1443  assert(varvals != NULL);
1444 
1445  *result = varvals[opdata.intval];
1446 
1447  return SCIP_OKAY;
1448 }
1449 
1450 /** curvature for EXPR_VAR */
1451 static
1452 SCIP_DECL_EXPRCURV( exprcurvVar )
1453 { /*lint --e{715}*/
1454  assert(result != NULL);
1455 
1456  *result = SCIP_EXPRCURV_LINEAR;
1457 
1458  return SCIP_OKAY;
1459 }
1460 
1461 /** point evaluation for EXPR_CONST */
1462 static
1463 SCIP_DECL_EXPREVAL( exprevalConst )
1464 { /*lint --e{715}*/
1465  assert(result != NULL);
1466 
1467  *result = opdata.dbl;
1468 
1469  return SCIP_OKAY;
1470 }
1471 
1472 /** interval evaluation for EXPR_CONST */
1473 static
1474 SCIP_DECL_EXPRINTEVAL( exprevalIntConst )
1475 { /*lint --e{715}*/
1476  assert(result != NULL);
1477 
1478  SCIPintervalSet(result, opdata.dbl);
1479 
1480  return SCIP_OKAY;
1481 }
1482 
1483 /** curvature for EXPR_CONST */
1484 static
1485 SCIP_DECL_EXPRCURV( exprcurvConst )
1486 { /*lint --e{715}*/
1487  assert(result != NULL);
1488 
1489  *result = SCIP_EXPRCURV_LINEAR;
1490 
1491  return SCIP_OKAY;
1492 }
1493 
1494 /** point evaluation for EXPR_PARAM */
1495 static
1496 SCIP_DECL_EXPREVAL( exprevalParam )
1497 { /*lint --e{715}*/
1498  assert(result != NULL);
1499  assert(paramvals != NULL );
1500 
1501  *result = paramvals[opdata.intval];
1502 
1503  return SCIP_OKAY;
1504 }
1505 
1506 /** interval evaluation for EXPR_PARAM */
1507 static
1508 SCIP_DECL_EXPRINTEVAL( exprevalIntParam )
1509 { /*lint --e{715}*/
1510  assert(result != NULL);
1511  assert(paramvals != NULL );
1512 
1513  SCIPintervalSet(result, paramvals[opdata.intval]);
1514 
1515  return SCIP_OKAY;
1516 }
1517 
1518 /** curvature for EXPR_PARAM */
1519 static
1520 SCIP_DECL_EXPRCURV( exprcurvParam )
1521 { /*lint --e{715}*/
1522  assert(result != NULL);
1523 
1524  *result = SCIP_EXPRCURV_LINEAR;
1525 
1526  return SCIP_OKAY;
1527 }
1528 
1529 /** point evaluation for EXPR_PLUS */
1530 static
1531 SCIP_DECL_EXPREVAL( exprevalPlus )
1532 { /*lint --e{715}*/
1533  assert(result != NULL);
1534  assert(argvals != NULL);
1535 
1536  *result = argvals[0] + argvals[1];
1537 
1538  return SCIP_OKAY;
1539 }
1540 
1541 /** interval evaluation for EXPR_PLUS */
1542 static
1543 SCIP_DECL_EXPRINTEVAL( exprevalIntPlus )
1544 { /*lint --e{715}*/
1545  assert(result != NULL);
1546  assert(argvals != NULL);
1547 
1548  SCIPintervalAdd(infinity, result, argvals[0], argvals[1]);
1549 
1550  return SCIP_OKAY;
1551 }
1552 
1553 /** curvature for EXPR_PLUS */
1554 static
1555 SCIP_DECL_EXPRCURV( exprcurvPlus )
1556 { /*lint --e{715}*/
1557  assert(result != NULL);
1558  assert(argcurv != NULL);
1559 
1560  *result = SCIPexprcurvAdd(argcurv[0], argcurv[1]);
1561 
1562  return SCIP_OKAY;
1563 }
1564 
1565 /** point evaluation for EXPR_MINUS */
1566 static
1567 SCIP_DECL_EXPREVAL( exprevalMinus )
1568 { /*lint --e{715}*/
1569  assert(result != NULL);
1570  assert(argvals != NULL);
1571 
1572  *result = argvals[0] - argvals[1];
1573 
1574  return SCIP_OKAY;
1575 }
1576 
1577 /** interval evaluation for EXPR_MINUS */
1578 static
1579 SCIP_DECL_EXPRINTEVAL( exprevalIntMinus )
1580 { /*lint --e{715}*/
1581  assert(result != NULL);
1582  assert(argvals != NULL);
1583 
1584  SCIPintervalSub(infinity, result, argvals[0], argvals[1]);
1585 
1586  return SCIP_OKAY;
1587 }
1588 
1589 /** curvature for EXPR_MINUS */
1590 static
1591 SCIP_DECL_EXPRCURV( exprcurvMinus )
1592 { /*lint --e{715}*/
1593  assert(result != NULL);
1594  assert(argcurv != NULL);
1595 
1596  *result = SCIPexprcurvAdd(argcurv[0], SCIPexprcurvNegate(argcurv[1]));
1597 
1598  return SCIP_OKAY;
1599 }
1600 
1601 /** point evaluation for EXPR_MUL */
1602 static
1603 SCIP_DECL_EXPREVAL( exprevalMult )
1604 { /*lint --e{715}*/
1605  assert(result != NULL);
1606  assert(argvals != NULL);
1607 
1608  *result = argvals[0] * argvals[1];
1609 
1610  return SCIP_OKAY;
1611 }
1612 
1613 /** interval evaluation for EXPR_MUL */
1614 static
1615 SCIP_DECL_EXPRINTEVAL( exprevalIntMult )
1616 { /*lint --e{715}*/
1617  assert(result != NULL);
1618  assert(argvals != NULL);
1619 
1620  SCIPintervalMul(infinity, result, argvals[0], argvals[1]);
1621 
1622  return SCIP_OKAY;
1623 }
1624 
1625 /** curvature for EXPR_MUL */
1626 static
1627 SCIP_DECL_EXPRCURV( exprcurvMult )
1628 { /*lint --e{715}*/
1629  assert(result != NULL);
1630  assert(argcurv != NULL);
1631  assert(argbounds != NULL);
1632 
1633  /* if one factor is constant, then product is
1634  * - linear, if constant is 0.0
1635  * - same curvature as other factor, if constant is positive
1636  * - negated curvature of other factor, if constant is negative
1637  *
1638  * if both factors are not constant, then product may not be convex nor concave
1639  */
1640  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1641  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1642  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1643  *result = SCIPexprcurvMultiply(argbounds[0].inf, argcurv[1]);
1644  else
1645  *result = SCIP_EXPRCURV_UNKNOWN;
1646 
1647  return SCIP_OKAY;
1648 }
1649 
1650 /** point evaluation for EXPR_DIV */
1651 static
1652 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1653 __attribute__((no_sanitize_undefined))
1654 #endif
1655 SCIP_DECL_EXPREVAL( exprevalDiv )
1656 { /*lint --e{715}*/
1657  assert(result != NULL);
1658  assert(argvals != NULL);
1659 
1660  *result = argvals[0] / argvals[1];
1661 
1662  return SCIP_OKAY;
1663 }
1664 
1665 /** interval evaluation for EXPR_DIV */
1666 static
1667 SCIP_DECL_EXPRINTEVAL( exprevalIntDiv )
1668 { /*lint --e{715}*/
1669  assert(result != NULL);
1670  assert(argvals != NULL);
1671 
1672  SCIPintervalDiv(infinity, result, argvals[0], argvals[1]);
1673 
1674  return SCIP_OKAY;
1675 }
1676 
1677 /** curvature for EXPR_DIV */
1678 static
1679 SCIP_DECL_EXPRCURV( exprcurvDiv )
1680 { /*lint --e{715}*/
1681  assert(result != NULL);
1682  assert(argcurv != NULL);
1683  assert(argbounds != NULL);
1684 
1685  /* if denominator is constant, then quotient has curvature sign(denominator) * curv(nominator)
1686  *
1687  * if nominator is a constant, then quotient is
1688  * - sign(nominator) * convex, if denominator is concave and positive
1689  * - sign(nominator) * concave, if denominator is convex and negative
1690  *
1691  * if denominator is positive but convex, then we don't know, e.g.,
1692  * - 1/x^2 is convex for x>=0
1693  * - 1/(1+(x-1)^2) is neither convex nor concave for x >= 0
1694  *
1695  * if both nominator and denominator are not constant, then quotient may not be convex nor concave
1696  */
1697  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1698  {
1699  /* denominator is constant */
1700  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1701  }
1702  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1703  {
1704  /* nominator is constant */
1705  if( argbounds[1].inf >= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
1706  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONVEX);
1707  else if( argbounds[1].sup <= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
1708  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONCAVE);
1709  else
1710  *result = SCIP_EXPRCURV_UNKNOWN;
1711  }
1712  else
1713  {
1714  /* denominator and nominator not constant */
1715  *result = SCIP_EXPRCURV_UNKNOWN;
1716  }
1717 
1718  return SCIP_OKAY;
1719 }
1720 
1721 /** point evaluation for EXPR_SQUARE */
1722 static
1723 SCIP_DECL_EXPREVAL( exprevalSquare )
1724 { /*lint --e{715}*/
1725  assert(result != NULL);
1726  assert(argvals != NULL);
1727 
1728  *result = argvals[0] * argvals[0];
1729 
1730  return SCIP_OKAY;
1731 }
1732 
1733 /** interval evaluation for EXPR_SQUARE */
1734 static
1735 SCIP_DECL_EXPRINTEVAL( exprevalIntSquare )
1736 { /*lint --e{715}*/
1737  assert(result != NULL);
1738  assert(argvals != NULL);
1739 
1740  SCIPintervalSquare(infinity, result, argvals[0]);
1741 
1742  return SCIP_OKAY;
1743 }
1744 
1745 /** curvature for EXPR_SQUARE */
1746 static
1747 SCIP_DECL_EXPRCURV( exprcurvSquare )
1748 { /*lint --e{715}*/
1749  assert(result != NULL);
1750  assert(argcurv != NULL);
1751  assert(argbounds != NULL);
1752 
1753  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], 2.0);
1754 
1755  return SCIP_OKAY;
1756 }
1757 
1758 /** point evaluation for EXPR_SQRT */
1759 static
1760 SCIP_DECL_EXPREVAL( exprevalSquareRoot )
1761 { /*lint --e{715}*/
1762  assert(result != NULL);
1763  assert(argvals != NULL);
1764 
1765  *result = sqrt(argvals[0]);
1766 
1767  return SCIP_OKAY;
1768 }
1769 
1770 /** interval evaluation for EXPR_SQRT */
1771 static
1772 SCIP_DECL_EXPRINTEVAL( exprevalIntSquareRoot )
1773 { /*lint --e{715}*/
1774  assert(result != NULL);
1775  assert(argvals != NULL);
1776 
1777  SCIPintervalSquareRoot(infinity, result, argvals[0]);
1778 
1779  return SCIP_OKAY;
1780 }
1781 
1782 /** curvature for EXPR_SQRT */
1783 static
1784 SCIP_DECL_EXPRCURV( exprcurvSquareRoot )
1785 { /*lint --e{715}*/
1786  assert(result != NULL);
1787  assert(argcurv != NULL);
1788 
1789  /* square-root is concave, if child is concave
1790  * otherwise, we don't know
1791  */
1792 
1793  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
1794  *result = SCIP_EXPRCURV_CONCAVE;
1795  else
1796  *result = SCIP_EXPRCURV_UNKNOWN;
1797 
1798  return SCIP_OKAY;
1799 }
1800 
1801 /** point evaluation for EXPR_REALPOWER */
1802 static
1803 SCIP_DECL_EXPREVAL( exprevalRealPower )
1804 { /*lint --e{715}*/
1805  assert(result != NULL);
1806  assert(argvals != NULL);
1807 
1808  *result = pow(argvals[0], opdata.dbl);
1809 
1810  return SCIP_OKAY;
1811 }
1812 
1813 /** interval evaluation for EXPR_REALPOWER */
1814 static
1815 SCIP_DECL_EXPRINTEVAL( exprevalIntRealPower )
1816 { /*lint --e{715}*/
1817  assert(result != NULL);
1818  assert(argvals != NULL);
1819 
1820  SCIPintervalPowerScalar(infinity, result, argvals[0], opdata.dbl);
1821 
1822  return SCIP_OKAY;
1823 }
1824 
1825 /** curvature for EXPR_REALPOWER */
1826 static
1827 SCIP_DECL_EXPRCURV( exprcurvRealPower )
1828 { /*lint --e{715}*/
1829  assert(result != NULL);
1830  assert(argcurv != NULL);
1831  assert(argbounds != NULL);
1832 
1833  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], opdata.dbl);
1834 
1835  return SCIP_OKAY;
1836 }
1837 
1838 /** point evaluation for EXPR_INTPOWER */
1839 static
1840 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1841 __attribute__((no_sanitize_undefined))
1842 #endif
1843 SCIP_DECL_EXPREVAL( exprevalIntPower )
1844 { /*lint --e{715}*/
1845  assert(result != NULL);
1846  assert(argvals != NULL);
1847 
1848  switch( opdata.intval )
1849  {
1850  case -1:
1851  *result = 1.0 / argvals[0];
1852  return SCIP_OKAY;
1853 
1854  case 0:
1855  *result = 1.0;
1856  return SCIP_OKAY;
1857 
1858  case 1:
1859  *result = argvals[0];
1860  return SCIP_OKAY;
1861 
1862  case 2:
1863  *result = argvals[0] * argvals[0];
1864  return SCIP_OKAY;
1865 
1866  default:
1867  *result = pow(argvals[0], (SCIP_Real)opdata.intval);
1868  }
1869 
1870  return SCIP_OKAY;
1871 }
1872 
1873 /** interval evaluation for EXPR_INTPOWER */
1874 static
1875 SCIP_DECL_EXPRINTEVAL( exprevalIntIntPower )
1876 { /*lint --e{715}*/
1877  assert(result != NULL);
1878  assert(argvals != NULL);
1879 
1880  SCIPintervalPowerScalar(infinity, result, argvals[0], (SCIP_Real)opdata.intval);
1881 
1882  return SCIP_OKAY;
1883 }
1884 
1885 /** curvature for EXPR_INTPOWER */
1886 static
1887 SCIP_DECL_EXPRCURV( exprcurvIntPower )
1888 { /*lint --e{715}*/
1889  assert(result != NULL);
1890  assert(argcurv != NULL);
1891  assert(argbounds != NULL);
1892 
1893  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], (SCIP_Real)opdata.intval);
1894 
1895  return SCIP_OKAY;
1896 }
1897 
1898 /** point evaluation for EXPR_SIGNPOWER */
1899 static
1900 SCIP_DECL_EXPREVAL( exprevalSignPower )
1901 { /*lint --e{715}*/
1902  assert(result != NULL);
1903  assert(argvals != NULL);
1904 
1905  if( argvals[0] > 0 )
1906  *result = pow( argvals[0], opdata.dbl);
1907  else
1908  *result = -pow(-argvals[0], opdata.dbl);
1909 
1910  return SCIP_OKAY;
1911 }
1912 
1913 /** interval evaluation for EXPR_SIGNPOWER */
1914 static
1915 SCIP_DECL_EXPRINTEVAL( exprevalIntSignPower )
1916 { /*lint --e{715}*/
1917  assert(result != NULL);
1918  assert(argvals != NULL);
1919 
1920  SCIPintervalSignPowerScalar(infinity, result, argvals[0], opdata.dbl);
1921 
1922  return SCIP_OKAY;
1923 }
1924 
1925 /** curvature for EXPR_SIGNPOWER */
1926 static
1927 SCIP_DECL_EXPRCURV( exprcurvSignPower )
1928 { /*lint --e{715}*/
1929  SCIP_INTERVAL tmp;
1930  SCIP_EXPRCURV left;
1931  SCIP_EXPRCURV right;
1932 
1933  assert(result != NULL);
1934  assert(argcurv != NULL);
1935  assert(argbounds != NULL);
1936 
1937  /* for x <= 0, signpower(x,c) = -(-x)^c
1938  * for x >= 0, signpower(x,c) = ( x)^c
1939  *
1940  * thus, get curvatures for both parts and "intersect" them
1941  */
1942 
1943  if( argbounds[0].inf < 0 )
1944  {
1945  SCIPintervalSetBounds(&tmp, 0.0, -argbounds[0].inf);
1946  left = SCIPexprcurvNegate(SCIPexprcurvPower(tmp, SCIPexprcurvNegate(argcurv[0]), opdata.dbl));
1947  }
1948  else
1949  {
1950  left = SCIP_EXPRCURV_LINEAR;
1951  }
1952 
1953  if( argbounds[0].sup > 0 )
1954  {
1955  SCIPintervalSetBounds(&tmp, 0.0, argbounds[0].sup);
1956  right = SCIPexprcurvPower(tmp, argcurv[0], opdata.dbl);
1957  }
1958  else
1959  {
1960  right = SCIP_EXPRCURV_LINEAR;
1961  }
1962 
1963  *result = (SCIP_EXPRCURV) (left & right);
1964 
1965  return SCIP_OKAY;
1966 }
1967 
1968 /** point evaluation for EXPR_EXP */
1969 static
1970 SCIP_DECL_EXPREVAL( exprevalExp )
1971 { /*lint --e{715}*/
1972  assert(result != NULL);
1973  assert(argvals != NULL);
1974 
1975  *result = exp(argvals[0]);
1976 
1977  return SCIP_OKAY;
1978 }
1979 
1980 /** interval evaluation for EXPR_EXP */
1981 static
1982 SCIP_DECL_EXPRINTEVAL( exprevalIntExp )
1983 { /*lint --e{715}*/
1984  assert(result != NULL);
1985  assert(argvals != NULL);
1986 
1987  SCIPintervalExp(infinity, result, argvals[0]);
1988 
1989  return SCIP_OKAY;
1990 }
1991 
1992 /** curvature for EXPR_EXP */
1993 static
1994 SCIP_DECL_EXPRCURV( exprcurvExp )
1995 { /*lint --e{715}*/
1996  assert(result != NULL);
1997  assert(argcurv != NULL);
1998 
1999  /* expression is convex if child is convex
2000  * otherwise, we don't know
2001  */
2002  if( argcurv[0] & SCIP_EXPRCURV_CONVEX )
2003  *result = SCIP_EXPRCURV_CONVEX;
2004  else
2005  *result = SCIP_EXPRCURV_UNKNOWN;
2006 
2007  return SCIP_OKAY;
2008 }
2009 
2010 /** point evaluation for EXPR_LOG */
2011 static
2012 SCIP_DECL_EXPREVAL( exprevalLog )
2013 { /*lint --e{715}*/
2014  assert(result != NULL);
2015  assert(argvals != NULL);
2016 
2017  *result = log(argvals[0]);
2018 
2019  return SCIP_OKAY;
2020 }
2021 
2022 /** interval evaluation for EXPR_LOG */
2023 static
2024 SCIP_DECL_EXPRINTEVAL( exprevalIntLog )
2025 { /*lint --e{715}*/
2026  assert(result != NULL);
2027  assert(argvals != NULL);
2028 
2029  SCIPintervalLog(infinity, result, argvals[0]);
2030 
2031  return SCIP_OKAY;
2032 }
2033 
2034 /** curvature for EXPR_LOG */
2035 static
2036 SCIP_DECL_EXPRCURV( exprcurvLog )
2037 { /*lint --e{715}*/
2038  assert(result != NULL);
2039  assert(argcurv != NULL);
2040 
2041  /* expression is concave if child is concave
2042  * otherwise, we don't know
2043  */
2044  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
2045  *result = SCIP_EXPRCURV_CONCAVE;
2046  else
2047  *result = SCIP_EXPRCURV_UNKNOWN;
2048 
2049  return SCIP_OKAY;
2050 }
2051 
2052 /** point evaluation for EXPR_SIN */
2053 static
2054 SCIP_DECL_EXPREVAL( exprevalSin )
2055 { /*lint --e{715}*/
2056  assert(result != NULL);
2057  assert(argvals != NULL);
2058 
2059  *result = sin(argvals[0]);
2060 
2061  return SCIP_OKAY;
2062 }
2063 
2064 /** interval evaluation for EXPR_SIN */
2065 static
2066 SCIP_DECL_EXPRINTEVAL( exprevalIntSin )
2067 { /*lint --e{715}*/
2068  assert(result != NULL);
2069  assert(argvals != NULL);
2070  assert(nargs == 1);
2071 
2072  SCIPintervalSin(infinity, result, *argvals);
2073 
2074  return SCIP_OKAY;
2075 }
2076 
2077 /* @todo implement exprcurvSin */
2078 #define exprcurvSin exprcurvDefault
2079 
2080 /** point evaluation for EXPR_COS */
2081 static
2082 SCIP_DECL_EXPREVAL( exprevalCos )
2083 { /*lint --e{715}*/
2084  assert(result != NULL);
2085  assert(argvals != NULL);
2086 
2087  *result = cos(argvals[0]);
2088 
2089  return SCIP_OKAY;
2090 }
2091 
2092 /** interval evaluation for EXPR_COS */
2093 static
2094 SCIP_DECL_EXPRINTEVAL( exprevalIntCos )
2095 { /*lint --e{715}*/
2096  assert(result != NULL);
2097  assert(argvals != NULL);
2098  assert(nargs == 1);
2099 
2100  SCIPintervalCos(infinity, result, *argvals);
2101 
2102  return SCIP_OKAY;
2103 }
2104 
2105 /* @todo implement exprcurvCos */
2106 #define exprcurvCos exprcurvDefault
2107 
2108 /** point evaluation for EXPR_TAN */
2109 static
2110 SCIP_DECL_EXPREVAL( exprevalTan )
2111 { /*lint --e{715}*/
2112  assert(result != NULL);
2113  assert(argvals != NULL);
2114 
2115  *result = tan(argvals[0]);
2116 
2117  return SCIP_OKAY;
2118 }
2119 
2120 /* @todo implement SCIPintervalTan */
2121 #define exprevalIntTan exprevalIntDefault
2122 
2123 /* @todo implement exprcurvTan */
2124 #define exprcurvTan exprcurvDefault
2125 
2126 /* erf and erfi do not seem to exist on every system, and we cannot really handle them anyway, so they are currently disabled */
2127 #ifdef SCIP_DISABLED_CODE
2128 static
2129 SCIP_DECL_EXPREVAL( exprevalErf )
2130 { /*lint --e{715}*/
2131  assert(result != NULL);
2132  assert(argvals != NULL);
2133 
2134  *result = erf(argvals[0]);
2135 
2136  return SCIP_OKAY;
2137 }
2138 
2139 /* @todo implement SCIPintervalErf */
2140 #define exprevalIntErf exprevalIntDefault
2141 
2142 /* @todo implement SCIPintervalErf */
2143 #define exprcurvErf exprcurvDefault
2144 
2145 static
2146 SCIP_DECL_EXPREVAL( exprevalErfi )
2147 { /*lint --e{715}*/
2148  assert(result != NULL);
2149  assert(argvals != NULL);
2150 
2151  /* @TODO implement erfi evaluation */
2152  SCIPerrorMessage("erfi not implemented");
2153 
2154  return SCIP_ERROR;
2155 }
2156 
2157 /* @todo implement SCIPintervalErfi */
2158 #define exprevalIntErfi NULL
2159 
2160 #define exprcurvErfi exprcurvDefault
2161 #endif
2162 
2163 /** point evaluation for EXPR_MIN */
2164 static
2165 SCIP_DECL_EXPREVAL( exprevalMin )
2166 { /*lint --e{715}*/
2167  assert(result != NULL);
2168  assert(argvals != NULL);
2169 
2170  *result = MIN(argvals[0], argvals[1]);
2171 
2172  return SCIP_OKAY;
2173 }
2174 
2175 /** interval evaluation for EXPR_MIN */
2176 static
2177 SCIP_DECL_EXPRINTEVAL( exprevalIntMin )
2178 { /*lint --e{715}*/
2179  assert(result != NULL);
2180  assert(argvals != NULL);
2181 
2182  SCIPintervalMin(infinity, result, argvals[0], argvals[1]);
2183 
2184  return SCIP_OKAY;
2185 }
2186 
2187 /** curvature for EXPR_MIN */
2188 static
2189 SCIP_DECL_EXPRCURV( exprcurvMin )
2190 { /*lint --e{715}*/
2191  assert(result != NULL);
2192  assert(argcurv != NULL);
2193 
2194  /* the minimum of two concave functions is concave
2195  * otherwise, we don't know
2196  */
2197 
2198  if( (argcurv[0] & SCIP_EXPRCURV_CONCAVE) && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
2199  *result = SCIP_EXPRCURV_CONCAVE;
2200  else
2201  *result = SCIP_EXPRCURV_UNKNOWN;
2202 
2203  return SCIP_OKAY;
2204 }
2205 
2206 /** point evaluation for EXPR_MAX */
2207 static
2208 SCIP_DECL_EXPREVAL( exprevalMax )
2209 { /*lint --e{715}*/
2210  assert(result != NULL);
2211  assert(argvals != NULL);
2212 
2213  *result = MAX(argvals[0], argvals[1]);
2214 
2215  return SCIP_OKAY;
2216 }
2217 
2218 /** interval evaluation for EXPR_MAX */
2219 static
2220 SCIP_DECL_EXPRINTEVAL( exprevalIntMax )
2221 { /*lint --e{715}*/
2222  assert(result != NULL);
2223  assert(argvals != NULL);
2224 
2225  SCIPintervalMax(infinity, result, argvals[0], argvals[1]);
2226 
2227  return SCIP_OKAY;
2228 }
2229 
2230 /** curvature for EXPR_MAX */
2231 static
2232 SCIP_DECL_EXPRCURV( exprcurvMax )
2233 { /*lint --e{715}*/
2234  assert(result != NULL);
2235  assert(argcurv != NULL);
2236 
2237  /* the maximum of two convex functions is convex
2238  * otherwise, we don't know
2239  */
2240  if( (argcurv[0] & SCIP_EXPRCURV_CONVEX) && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
2241  *result = SCIP_EXPRCURV_CONVEX;
2242  else
2243  *result = SCIP_EXPRCURV_UNKNOWN;
2244 
2245  return SCIP_OKAY;
2246 }
2247 
2248 /** point evaluation for EXPR_ABS */
2249 static
2250 SCIP_DECL_EXPREVAL( exprevalAbs )
2251 { /*lint --e{715}*/
2252  assert(result != NULL);
2253  assert(argvals != NULL);
2254 
2255  *result = ABS(argvals[0]);
2256 
2257  return SCIP_OKAY;
2258 }
2259 
2260 /** interval evaluation for EXPR_ABS */
2261 static
2262 SCIP_DECL_EXPRINTEVAL( exprevalIntAbs )
2263 { /*lint --e{715}*/
2264  assert(result != NULL);
2265  assert(argvals != NULL);
2266 
2267  SCIPintervalAbs(infinity, result, argvals[0]);
2268 
2269  return SCIP_OKAY;
2270 }
2271 
2272 /** curvature for EXPR_ABS */
2273 static
2274 SCIP_DECL_EXPRCURV( exprcurvAbs )
2275 { /*lint --e{715}*/
2276  assert(result != NULL);
2277  assert(argcurv != NULL);
2278  assert(argbounds != NULL);
2279 
2280  /* if child is only negative, then abs(child) = -child
2281  * if child is only positive, then abs(child) = child
2282  * if child is both positive and negative, but also linear, then abs(child) is convex
2283  * otherwise, we don't know
2284  */
2285  if( argbounds[0].sup <= 0.0 )
2286  *result = SCIPexprcurvMultiply(-1.0, argcurv[0]);
2287  else if( argbounds[0].inf >= 0.0 )
2288  *result = argcurv[0];
2289  else if( argcurv[0] == SCIP_EXPRCURV_LINEAR )
2290  *result = SCIP_EXPRCURV_CONVEX;
2291  else
2292  *result = SCIP_EXPRCURV_UNKNOWN;
2293 
2294  return SCIP_OKAY;
2295 }
2296 
2297 /** point evaluation for EXPR_SIGN */
2298 static
2299 SCIP_DECL_EXPREVAL( exprevalSign )
2300 { /*lint --e{715}*/
2301  assert(result != NULL);
2302  assert(argvals != NULL);
2303 
2304  *result = SIGN(argvals[0]);
2305 
2306  return SCIP_OKAY;
2307 }
2308 
2309 /** interval evaluation for EXPR_SIGN */
2310 static
2311 SCIP_DECL_EXPRINTEVAL( exprevalIntSign )
2312 { /*lint --e{715}*/
2313  assert(result != NULL);
2314  assert(argvals != NULL);
2315 
2316  SCIPintervalSign(infinity, result, argvals[0]);
2317 
2318  return SCIP_OKAY;
2319 }
2320 
2321 /** curvature for EXPR_SIGN */
2322 static
2323 SCIP_DECL_EXPRCURV( exprcurvSign )
2324 { /*lint --e{715}*/
2325  assert(result != NULL);
2326  assert(argbounds != NULL);
2327 
2328  /* if sign of child is clear, then sign is linear otherwise, we don't know */
2329  if( argbounds[0].sup <= 0.0 || argbounds[0].inf >= 0.0 )
2330  *result = SCIP_EXPRCURV_LINEAR;
2331  else
2332  *result = SCIP_EXPRCURV_UNKNOWN;
2333 
2334  return SCIP_OKAY;
2335 }
2336 
2337 /** point evaluation for EXPR_SUM */
2338 static
2339 SCIP_DECL_EXPREVAL( exprevalSum )
2340 { /*lint --e{715}*/
2341  int i;
2342 
2343  assert(result != NULL);
2344  assert(argvals != NULL);
2345 
2346  *result = 0.0;
2347  for( i = 0; i < nargs; ++i )
2348  *result += argvals[i];
2349 
2350  return SCIP_OKAY;
2351 }
2352 
2353 /** interval evaluation for EXPR_SUM */
2354 static
2355 SCIP_DECL_EXPRINTEVAL( exprevalIntSum )
2356 { /*lint --e{715}*/
2357  int i;
2358 
2359  assert(result != NULL);
2360  assert(argvals != NULL);
2361 
2362  SCIPintervalSet(result, 0.0);
2363 
2364  for( i = 0; i < nargs; ++i )
2365  SCIPintervalAdd(infinity, result, *result, argvals[i]);
2366 
2367  return SCIP_OKAY;
2368 }
2369 
2370 /** curvature for EXPR_SUM */
2371 static
2372 SCIP_DECL_EXPRCURV( exprcurvSum )
2373 { /*lint --e{715}*/
2374  int i;
2375 
2376  assert(result != NULL);
2377  assert(argcurv != NULL);
2378 
2379  *result = SCIP_EXPRCURV_LINEAR;
2380 
2381  for( i = 0; i < nargs; ++i )
2382  *result = SCIPexprcurvAdd(*result, argcurv[i]);
2383 
2384  return SCIP_OKAY;
2385 }
2386 
2387 /** point evaluation for EXPR_PRODUCT */
2388 static
2389 SCIP_DECL_EXPREVAL( exprevalProduct )
2390 { /*lint --e{715}*/
2391  int i;
2392 
2393  assert(result != NULL);
2394  assert(argvals != NULL);
2395 
2396  *result = 1.0;
2397  for( i = 0; i < nargs; ++i )
2398  *result *= argvals[i];
2399 
2400  return SCIP_OKAY;
2401 }
2402 
2403 /** interval evaluation for EXPR_PRODUCT */
2404 static
2405 SCIP_DECL_EXPRINTEVAL( exprevalIntProduct )
2406 { /*lint --e{715}*/
2407  int i;
2408 
2409  assert(result != NULL);
2410  assert(argvals != NULL);
2411 
2412  SCIPintervalSet(result, 1.0);
2413 
2414  for( i = 0; i < nargs; ++i )
2415  SCIPintervalMul(infinity, result, *result, argvals[i]);
2416 
2417  return SCIP_OKAY;
2418 }
2419 
2420 /** curvature for EXPR_PRODUCT */
2421 static
2422 SCIP_DECL_EXPRCURV( exprcurvProduct )
2423 { /*lint --e{715}*/
2424  SCIP_Bool hadnonconst;
2425  SCIP_Real constants;
2426  int i;
2427 
2428  assert(result != NULL);
2429  assert(argcurv != NULL);
2430  assert(argbounds != NULL);
2431 
2432  /* if all factors are constant, then product is linear (even constant)
2433  * if only one factor is not constant, then product is curvature of this factor, multiplied by sign of product of remaining factors
2434  */
2435  *result = SCIP_EXPRCURV_LINEAR;
2436  hadnonconst = FALSE;
2437  constants = 1.0;
2438 
2439  for( i = 0; i < nargs; ++i )
2440  {
2441  if( argbounds[i].inf == argbounds[i].sup ) /*lint !e777*/
2442  {
2443  constants *= argbounds[i].inf;
2444  }
2445  else if( !hadnonconst )
2446  {
2447  /* first non-constant child */
2448  *result = argcurv[i];
2449  hadnonconst = TRUE;
2450  }
2451  else
2452  {
2453  /* more than one non-constant child, thus don't know curvature */
2454  *result = SCIP_EXPRCURV_UNKNOWN;
2455  break;
2456  }
2457  }
2458 
2459  *result = SCIPexprcurvMultiply(constants, *result);
2460 
2461  return SCIP_OKAY;
2462 }
2463 
2464 /** point evaluation for EXPR_LINEAR */
2465 static
2466 SCIP_DECL_EXPREVAL( exprevalLinear )
2467 { /*lint --e{715}*/
2468  SCIP_Real* coef;
2469  int i;
2470 
2471  assert(result != NULL);
2472  assert(argvals != NULL || nargs == 0);
2473  assert(opdata.data != NULL);
2474 
2475  coef = &((SCIP_Real*)opdata.data)[nargs];
2476 
2477  *result = *coef;
2478  for( i = nargs-1, --coef; i >= 0; --i, --coef )
2479  *result += *coef * argvals[i]; /*lint !e613*/
2480 
2481  assert(++coef == (SCIP_Real*)opdata.data);
2482 
2483  return SCIP_OKAY;
2484 }
2485 
2486 /** interval evaluation for EXPR_LINEAR */
2487 static
2488 SCIP_DECL_EXPRINTEVAL( exprevalIntLinear )
2489 { /*lint --e{715}*/
2490  assert(result != NULL);
2491  assert(argvals != NULL || nargs == 0);
2492  assert(opdata.data != NULL);
2493 
2494  SCIPintervalScalprodScalars(infinity, result, nargs, argvals, (SCIP_Real*)opdata.data);
2495  SCIPintervalAddScalar(infinity, result, *result, ((SCIP_Real*)opdata.data)[nargs]);
2496 
2497  return SCIP_OKAY;
2498 }
2499 
2500 /** curvature for EXPR_LINEAR */
2501 static
2502 SCIP_DECL_EXPRCURV( exprcurvLinear )
2503 { /*lint --e{715}*/
2504  SCIP_Real* data;
2505  int i;
2506 
2507  assert(result != NULL);
2508  assert(argcurv != NULL);
2509 
2510  data = (SCIP_Real*)opdata.data;
2511  assert(data != NULL);
2512 
2513  *result = SCIP_EXPRCURV_LINEAR;
2514 
2515  for( i = 0; i < nargs; ++i )
2516  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(data[i], argcurv[i]));
2517 
2518  return SCIP_OKAY;
2519 }
2520 
2521 /** expression data copy for EXPR_LINEAR */
2522 static
2523 SCIP_DECL_EXPRCOPYDATA( exprCopyDataLinear )
2524 { /*lint --e{715}*/
2525  SCIP_Real* targetdata;
2526 
2527  assert(blkmem != NULL);
2528  assert(nchildren >= 0);
2529  assert(opdatatarget != NULL);
2530 
2531  /* for a linear expression, we need to copy the array that holds the coefficients and constant term */
2532  assert(opdatasource.data != NULL);
2533  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &targetdata, (SCIP_Real*)opdatasource.data, nchildren + 1) ); /*lint !e866*/
2534  opdatatarget->data = targetdata;
2535 
2536  return SCIP_OKAY;
2537 }
2538 
2539 /** expression data free for EXPR_LINEAR */
2540 static
2541 SCIP_DECL_EXPRFREEDATA( exprFreeDataLinear )
2542 { /*lint --e{715}*/
2543  SCIP_Real* freedata;
2544 
2545  assert(blkmem != NULL);
2546  assert(nchildren >= 0);
2547 
2548  freedata = (SCIP_Real*)opdata.data;
2549  assert(freedata != NULL);
2550 
2551  BMSfreeBlockMemoryArray(blkmem, &freedata, nchildren + 1); /*lint !e866*/
2552 }
2553 
2554 /** point evaluation for EXPR_QUADRATIC */
2555 static
2556 SCIP_DECL_EXPREVAL( exprevalQuadratic )
2557 { /*lint --e{715}*/
2558  SCIP_EXPRDATA_QUADRATIC* quaddata;
2559  SCIP_Real* lincoefs;
2560  SCIP_QUADELEM* quadelems;
2561  int nquadelems;
2562  int i;
2563 
2564  assert(result != NULL);
2565  assert(argvals != NULL || nargs == 0);
2566 
2567  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2568  assert(quaddata != NULL);
2569 
2570  lincoefs = quaddata->lincoefs;
2571  nquadelems = quaddata->nquadelems;
2572  quadelems = quaddata->quadelems;
2573 
2574  assert(quadelems != NULL || nquadelems == 0);
2575  assert(argvals != NULL || nquadelems == 0);
2576 
2577  *result = quaddata->constant;
2578 
2579  if( lincoefs != NULL )
2580  {
2581  for( i = nargs-1; i >= 0; --i )
2582  *result += lincoefs[i] * argvals[i]; /*lint !e613*/
2583  }
2584 
2585  for( i = 0; i < nquadelems; ++i, ++quadelems ) /*lint !e613*/
2586  *result += quadelems->coef * argvals[quadelems->idx1] * argvals[quadelems->idx2]; /*lint !e613*/
2587 
2588  return SCIP_OKAY;
2589 }
2590 
2591 /** interval evaluation for EXPR_QUADRATIC */
2592 static
2593 SCIP_DECL_EXPRINTEVAL( exprevalIntQuadratic )
2594 { /*lint --e{715}*/
2595  SCIP_EXPRDATA_QUADRATIC* quaddata;
2596  SCIP_Real* lincoefs;
2597  SCIP_QUADELEM* quadelems;
2598  int nquadelems;
2599  int i;
2600  int argidx;
2601  SCIP_Real sqrcoef;
2602  SCIP_INTERVAL lincoef;
2603  SCIP_INTERVAL tmp;
2604 
2605  assert(result != NULL);
2606  assert(argvals != NULL || nargs == 0);
2607 
2608  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2609  assert(quaddata != NULL);
2610 
2611  lincoefs = quaddata->lincoefs;
2612  nquadelems = quaddata->nquadelems;
2613  quadelems = quaddata->quadelems;
2614 
2615  assert(quadelems != NULL || nquadelems == 0);
2616  assert(argvals != NULL || nargs == 0);
2617 
2618  /* something fast for case of only one child */
2619  if( nargs == 1 )
2620  {
2621  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[0] : 0.0);
2622 
2623  sqrcoef = 0.0;
2624  for( i = 0; i < nquadelems; ++i )
2625  {
2626  assert(quadelems[i].idx1 == 0); /*lint !e613*/
2627  assert(quadelems[i].idx2 == 0); /*lint !e613*/
2628  sqrcoef += quadelems[i].coef; /*lint !e613*/
2629  }
2630 
2631  SCIPintervalQuad(infinity, result, sqrcoef, lincoef, argvals[0]); /*lint !e613*/
2632  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2633 
2634  return SCIP_OKAY;
2635  }
2636 
2637  if( nargs == 2 && nquadelems > 0 )
2638  {
2639  /* if it's a bivariate quadratic expression with bilinear term, do something special */
2640  SCIP_Real ax; /* square coefficient of first child */
2641  SCIP_Real ay; /* square coefficient of second child */
2642  SCIP_Real axy; /* bilinear coefficient */
2643 
2644  ax = 0.0;
2645  ay = 0.0;
2646  axy = 0.0;
2647  for( i = 0; i < nquadelems; ++i )
2648  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 ) /*lint !e613*/
2649  ax += quadelems[i].coef; /*lint !e613*/
2650  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 ) /*lint !e613*/
2651  ay += quadelems[i].coef; /*lint !e613*/
2652  else
2653  axy += quadelems[i].coef; /*lint !e613*/
2654 
2655  SCIPintervalQuadBivar(infinity, result, ax, ay, axy,
2656  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2657  argvals[0], argvals[1]); /*lint !e613*/
2658  SCIPdebugMessage("%g x^2 + %g y^2 + %g x y + %g x + %g y = [%g,%g] for x = [%g,%g], y = [%g,%g]\n",
2659  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2660  result->inf, result->sup, argvals[0].inf, argvals[0].sup, argvals[1].inf, argvals[1].sup); /*lint !e613*/
2661 
2662  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2663 
2664  return SCIP_OKAY;
2665  }
2666 
2667  /* make sure coefficients are sorted */
2668  quadraticdataSort(quaddata);
2669 
2670  SCIPintervalSet(result, quaddata->constant);
2671 
2672  /* for each argument, we collect it's linear index from lincoefs, it's square coefficients and all factors from bilinear terms
2673  * then we compute the interval sqrcoef*x^2 + lincoef*x and add it to result
2674  * @todo split quadratic expression into bivariate quadratic terms and apply the above method
2675  */
2676  i = 0;
2677  for( argidx = 0; argidx < nargs; ++argidx )
2678  {
2679  if( i == nquadelems || quadelems[i].idx1 > argidx ) /*lint !e613*/
2680  {
2681  /* there are no quadratic terms with argidx in its first argument, that should be easy to handle */
2682  if( lincoefs != NULL )
2683  {
2684  SCIPintervalMulScalar(infinity, &tmp, argvals[argidx], lincoefs[argidx]); /*lint !e613*/
2685  SCIPintervalAdd(infinity, result, *result, tmp);
2686  }
2687  continue;
2688  }
2689 
2690  sqrcoef = 0.0;
2691  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[argidx] : 0.0);
2692 
2693  assert(i < nquadelems && quadelems[i].idx1 == argidx); /*lint !e613*/
2694  do
2695  {
2696  if( quadelems[i].idx2 == argidx ) /*lint !e613*/
2697  {
2698  sqrcoef += quadelems[i].coef; /*lint !e613*/
2699  }
2700  else
2701  {
2702  SCIPintervalMulScalar(infinity, &tmp, argvals[quadelems[i].idx2], quadelems[i].coef); /*lint !e613*/
2703  SCIPintervalAdd(infinity, &lincoef, lincoef, tmp);
2704  }
2705  ++i;
2706  }
2707  while( i < nquadelems && quadelems[i].idx1 == argidx ); /*lint !e613*/
2708  assert(i == nquadelems || quadelems[i].idx1 > argidx); /*lint !e613*/
2709 
2710  SCIPintervalQuad(infinity, &tmp, sqrcoef, lincoef, argvals[argidx]); /*lint !e613*/
2711  SCIPintervalAdd(infinity, result, *result, tmp);
2712  }
2713  assert(i == nquadelems);
2714 
2715  return SCIP_OKAY;
2716 }
2717 
2718 /** curvature for EXPR_QUADRATIC */
2719 static
2720 SCIP_DECL_EXPRCURV( exprcurvQuadratic )
2721 { /*lint --e{715}*/
2723  SCIP_QUADELEM* quadelems;
2724  int nquadelems;
2725  SCIP_Real* lincoefs;
2726  int i;
2727 
2728  assert(result != NULL);
2729  assert(argcurv != NULL);
2730  assert(argbounds != NULL);
2731 
2732  data = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2733  assert(data != NULL);
2734 
2735  lincoefs = data->lincoefs;
2736  quadelems = data->quadelems;
2737  nquadelems = data->nquadelems;
2738 
2739  *result = SCIP_EXPRCURV_LINEAR;
2740 
2741  if( lincoefs != NULL )
2742  for( i = 0; i < nargs; ++i )
2743  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(lincoefs[i], argcurv[i]));
2744 
2745  /* @todo could try cholesky factorization if all children linear...
2746  * @todo should then cache the result
2747  */
2748  for( i = 0; i < nquadelems && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
2749  {
2750  if( quadelems[i].coef == 0.0 )
2751  continue;
2752 
2753  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup && /*lint !e777*/
2754  +argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup
2755  ) /*lint !e777*/
2756  {
2757  /* both factors are constants -> curvature does not change */
2758  continue;
2759  }
2760 
2761  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup ) /*lint !e777*/
2762  {
2763  /* first factor is constant, second is not -> add curvature of second */
2764  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx1].inf, argcurv[quadelems[i].idx2]));
2765  }
2766  else if( argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup ) /*lint !e777*/
2767  {
2768  /* first factor is not constant, second is -> add curvature of first */
2769  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx2].inf, argcurv[quadelems[i].idx1]));
2770  }
2771  else if( quadelems[i].idx1 == quadelems[i].idx2 )
2772  {
2773  /* both factors not constant, but the same (square term) */
2774  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef, SCIPexprcurvPower(argbounds[quadelems[i].idx1], argcurv[quadelems[i].idx1], 2.0)));
2775  }
2776  else
2777  {
2778  /* two different non-constant factors -> can't tell about curvature */
2779  *result = SCIP_EXPRCURV_UNKNOWN;
2780  }
2781  }
2782 
2783  return SCIP_OKAY;
2784 }
2785 
2786 /** expression data copy for EXPR_QUADRATIC */
2787 static
2788 SCIP_DECL_EXPRCOPYDATA( exprCopyDataQuadratic )
2789 { /*lint --e{715}*/
2790  SCIP_EXPRDATA_QUADRATIC* sourcedata;
2791 
2792  assert(blkmem != NULL);
2793  assert(opdatatarget != NULL);
2794 
2795  sourcedata = (SCIP_EXPRDATA_QUADRATIC*)opdatasource.data;
2796  assert(sourcedata != NULL);
2797 
2798  SCIP_CALL( quadraticdataCreate(blkmem, (SCIP_EXPRDATA_QUADRATIC**)&opdatatarget->data,
2799  sourcedata->constant, nchildren, sourcedata->lincoefs, sourcedata->nquadelems, sourcedata->quadelems) );
2800 
2801  return SCIP_OKAY;
2802 }
2803 
2804 /** expression data free for EXPR_QUADRATIC */
2805 static
2806 SCIP_DECL_EXPRFREEDATA( exprFreeDataQuadratic )
2807 { /*lint --e{715}*/
2808  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
2809 
2810  assert(blkmem != NULL);
2811  assert(nchildren >= 0);
2812 
2813  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2814  assert(quadraticdata != NULL);
2815 
2816  if( quadraticdata->lincoefs != NULL )
2817  {
2818  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->lincoefs, nchildren);
2819  }
2820 
2821  if( quadraticdata->nquadelems > 0 )
2822  {
2823  assert(quadraticdata->quadelems != NULL);
2824  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->quadelems, quadraticdata->nquadelems);
2825  }
2826 
2827  BMSfreeBlockMemory(blkmem, &quadraticdata);
2828 }
2829 
2830 /** point evaluation for EXPR_POLYNOMIAL */
2831 static
2832 SCIP_DECL_EXPREVAL( exprevalPolynomial )
2833 { /*lint --e{715}*/
2834  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2835  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2836  SCIP_Real childval;
2837  SCIP_Real exponent;
2838  SCIP_Real monomialval;
2839  int i;
2840  int j;
2841 
2842  assert(result != NULL);
2843  assert(argvals != NULL || nargs == 0);
2844  assert(opdata.data != NULL);
2845 
2846  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2847  assert(polynomialdata != NULL);
2848 
2849  *result = polynomialdata->constant;
2850 
2851  for( i = 0; i < polynomialdata->nmonomials; ++i )
2852  {
2853  monomialdata = polynomialdata->monomials[i];
2854  assert(monomialdata != NULL);
2855 
2856  monomialval = monomialdata->coef;
2857  for( j = 0; j < monomialdata->nfactors; ++j )
2858  {
2859  assert(monomialdata->childidxs[j] >= 0);
2860  assert(monomialdata->childidxs[j] < nargs);
2861 
2862  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2863  if( childval == 1.0 ) /* 1^anything == 1 */
2864  continue;
2865 
2866  exponent = monomialdata->exponents[j];
2867 
2868  if( childval == 0.0 )
2869  {
2870  if( exponent > 0.0 )
2871  {
2872  /* 0^positive == 0 */
2873  monomialval = 0.0;
2874  break;
2875  }
2876  else if( exponent < 0.0 )
2877  {
2878  /* 0^negative = nan (or should it be +inf?, doesn't really matter) */
2879 #ifdef NAN
2880  *result = NAN;
2881 #else
2882  /* cppcheck-suppress wrongmathcall */
2883  *result = pow(0.0, -1.0);
2884 #endif
2885  return SCIP_OKAY;
2886  }
2887  /* 0^0 == 1 */
2888  continue;
2889  }
2890 
2891  /* cover some special exponents separately to avoid calling expensive pow function */
2892  if( exponent == 0.0 )
2893  continue;
2894  if( exponent == 1.0 )
2895  {
2896  monomialval *= childval;
2897  continue;
2898  }
2899  if( exponent == 2.0 )
2900  {
2901  monomialval *= childval * childval;
2902  continue;
2903  }
2904  if( exponent == 0.5 )
2905  {
2906  monomialval *= sqrt(childval);
2907  continue;
2908  }
2909  if( exponent == -1.0 )
2910  {
2911  monomialval /= childval;
2912  continue;
2913  }
2914  if( exponent == -2.0 )
2915  {
2916  monomialval /= childval * childval;
2917  continue;
2918  }
2919  monomialval *= pow(childval, exponent);
2920  }
2921 
2922  *result += monomialval;
2923  }
2924 
2925  return SCIP_OKAY;
2926 }
2927 
2928 /** interval evaluation for EXPR_POLYNOMIAL */
2929 static
2930 SCIP_DECL_EXPRINTEVAL( exprevalIntPolynomial )
2931 { /*lint --e{715}*/
2932  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2933  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2934  SCIP_INTERVAL childval;
2935  SCIP_INTERVAL monomialval;
2936  SCIP_Real exponent;
2937  int i;
2938  int j;
2939 
2940  assert(result != NULL);
2941  assert(argvals != NULL || nargs == 0);
2942  assert(opdata.data != NULL);
2943 
2944  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2945  assert(polynomialdata != NULL);
2946 
2947  SCIPintervalSet(result, polynomialdata->constant);
2948 
2949  for( i = 0; i < polynomialdata->nmonomials; ++i )
2950  {
2951  monomialdata = polynomialdata->monomials[i];
2952  assert(monomialdata != NULL);
2953 
2954  SCIPintervalSet(&monomialval, monomialdata->coef);
2955  for( j = 0; j < monomialdata->nfactors && !SCIPintervalIsEntire(infinity, monomialval); ++j )
2956  {
2957  assert(monomialdata->childidxs[j] >= 0);
2958  assert(monomialdata->childidxs[j] < nargs);
2959 
2960  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2961 
2962  exponent = monomialdata->exponents[j];
2963 
2964  /* cover some special exponents separately to avoid calling expensive pow function */
2965  if( exponent == 0.0 )
2966  continue;
2967 
2968  if( exponent == 1.0 )
2969  {
2970  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2971  continue;
2972  }
2973 
2974  if( exponent == 2.0 )
2975  {
2976  SCIPintervalSquare(infinity, &childval, childval);
2977  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2978  continue;
2979  }
2980 
2981  if( exponent == 0.5 )
2982  {
2983  SCIPintervalSquareRoot(infinity, &childval, childval);
2984  if( SCIPintervalIsEmpty(infinity, childval) )
2985  {
2986  SCIPintervalSetEmpty(result);
2987  break;
2988  }
2989  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2990  continue;
2991  }
2992  else if( exponent == -1.0 )
2993  {
2994  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2995  }
2996  else if( exponent == -2.0 )
2997  {
2998  SCIPintervalSquare(infinity, &childval, childval);
2999  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
3000  }
3001  else
3002  {
3003  SCIPintervalPowerScalar(infinity, &childval, childval, exponent);
3004  if( SCIPintervalIsEmpty(infinity, childval) )
3005  {
3006  SCIPintervalSetEmpty(result);
3007  return SCIP_OKAY;
3008  }
3009  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
3010  }
3011 
3012  /* the cases in which monomialval gets empty should have been catched */
3013  assert(!SCIPintervalIsEmpty(infinity, monomialval));
3014  }
3015 
3016  SCIPintervalAdd(infinity, result, *result, monomialval);
3017  }
3018 
3019  return SCIP_OKAY;
3020 }
3021 
3022 /** curvature for EXPR_POLYNOMIAL */
3023 static
3024 SCIP_DECL_EXPRCURV( exprcurvPolynomial )
3025 { /*lint --e{715}*/
3027  SCIP_EXPRDATA_MONOMIAL** monomials;
3028  SCIP_EXPRDATA_MONOMIAL* monomial;
3029  int nmonomials;
3030  int i;
3031 
3032  assert(result != NULL);
3033  assert(argcurv != NULL);
3034  assert(argbounds != NULL);
3035 
3036  data = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3037  assert(data != NULL);
3038 
3039  monomials = data->monomials;
3040  nmonomials = data->nmonomials;
3041 
3042  *result = SCIP_EXPRCURV_LINEAR;
3043 
3044  for( i = 0; i < nmonomials && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
3045  {
3046  /* we assume that some simplifier was running, so that monomials do not have constants in their factors and such that all factors are different
3047  * (result would still be correct)
3048  */
3049  monomial = monomials[i];
3050  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(monomial->coef, SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, monomial->childidxs, argcurv, argbounds)));
3051  }
3052 
3053  return SCIP_OKAY;
3054 }
3055 
3056 /** expression data copy for EXPR_POLYNOMIAL */
3057 static
3058 SCIP_DECL_EXPRCOPYDATA( exprCopyDataPolynomial )
3059 { /*lint --e{715}*/
3060  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata;
3061  SCIP_EXPRDATA_POLYNOMIAL* targetpolynomialdata;
3062 
3063  assert(blkmem != NULL);
3064  assert(opdatatarget != NULL);
3065 
3066  sourcepolynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdatasource.data;
3067  assert(sourcepolynomialdata != NULL);
3068 
3069  SCIP_CALL( polynomialdataCopy(blkmem, &targetpolynomialdata, sourcepolynomialdata) );
3070 
3071  opdatatarget->data = (void*)targetpolynomialdata;
3072 
3073  return SCIP_OKAY;
3074 }
3075 
3076 /** expression data free for EXPR_POLYNOMIAL */
3077 static
3078 SCIP_DECL_EXPRFREEDATA( exprFreeDataPolynomial )
3079 { /*lint --e{715}*/
3080  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3081 
3082  assert(blkmem != NULL);
3083 
3084  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3085  assert(polynomialdata != NULL);
3086 
3087  polynomialdataFree(blkmem, &polynomialdata);
3088 }
3089 
3090 /** point evaluation for user expression */
3091 static
3092 SCIP_DECL_EXPREVAL( exprevalUser )
3093 { /*lint --e{715}*/
3094  SCIP_EXPRDATA_USER* exprdata;
3095 
3096  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3097 
3098  SCIP_CALL( exprdata->eval(exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3099 
3100  return SCIP_OKAY;
3101 }
3102 
3103 /** interval evaluation for user expression */
3104 static
3105 SCIP_DECL_EXPRINTEVAL( exprevalIntUser )
3106 { /*lint --e{715}*/
3107  SCIP_EXPRDATA_USER* exprdata;
3108 
3109  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3110 
3111  if( exprdata->inteval != NULL )
3112  {
3113  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3114  }
3115  else
3116  {
3117  /* if user does not provide interval evaluation, then return a result that is always correct */
3119  }
3120 
3121  return SCIP_OKAY;
3122 }
3123 
3124 /** curvature check for user expression */
3125 static
3126 SCIP_DECL_EXPRCURV( exprcurvUser )
3127 {
3128  SCIP_EXPRDATA_USER* exprdata;
3129 
3130  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3131 
3132  if( exprdata->curv != NULL )
3133  {
3134  SCIP_CALL( exprdata->curv(infinity, exprdata->userdata, nargs, argbounds, argcurv, result) );
3135  }
3136  else
3137  {
3138  /* if user does not provide curvature check, then return unknown (which is handled like indefinite) */
3139  *result = SCIP_EXPRCURV_UNKNOWN;
3140  }
3141 
3142  return SCIP_OKAY;
3143 }
3144 
3145 /** data copy for user expression */
3146 static
3147 SCIP_DECL_EXPRCOPYDATA( exprCopyDataUser )
3148 {
3149  SCIP_EXPRDATA_USER* exprdatasource;
3150  SCIP_EXPRDATA_USER* exprdatatarget;
3151 
3152  assert(blkmem != NULL);
3153  assert(opdatatarget != NULL);
3154 
3155  exprdatasource = (SCIP_EXPRDATA_USER*)opdatasource.data;
3156  assert(exprdatasource != NULL);
3157 
3158  /* duplicate expression data */
3159  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, &exprdatatarget, exprdatasource) );
3160 
3161  /* duplicate user expression data, if any */
3162  if( exprdatasource->copydata != NULL )
3163  {
3164  SCIP_CALL( exprdatasource->copydata(blkmem, nchildren, exprdatasource->userdata, &exprdatatarget->userdata) );
3165  }
3166  else
3167  {
3168  /* if no copy function for data, then there has to be no data */
3169  assert(exprdatatarget->userdata == NULL);
3170  }
3171 
3172  opdatatarget->data = (void*)exprdatatarget;
3173 
3174  return SCIP_OKAY;
3175 }
3176 
3177 /** data free for user expression */
3178 static
3179 SCIP_DECL_EXPRFREEDATA( exprFreeDataUser )
3180 {
3181  SCIP_EXPRDATA_USER* exprdata;
3182 
3183  assert(blkmem != NULL);
3184 
3185  exprdata = (SCIP_EXPRDATA_USER*)opdata.data;
3186 
3187  /* free user expression data, if any */
3188  if( exprdata->freedata != NULL )
3189  {
3190  exprdata->freedata(blkmem, nchildren, exprdata->userdata);
3191  }
3192  else
3193  {
3194  assert(exprdata->userdata == NULL);
3195  }
3196 
3197  /* free expression data */
3198  BMSfreeBlockMemory(blkmem, &exprdata);
3199 }
3200 
3201 /** element in table of expression operands */
3202 struct exprOpTableElement
3203 {
3204  const char* name; /**< name of operand (used for printing) */
3205  int nargs; /**< number of arguments (negative if not fixed) */
3206  SCIP_DECL_EXPREVAL ((*eval)); /**< evaluation function */
3207  SCIP_DECL_EXPRINTEVAL ((*inteval)); /**< interval evaluation function */
3208  SCIP_DECL_EXPRCURV ((*curv)); /**< curvature check function */
3209  SCIP_DECL_EXPRCOPYDATA ((*copydata)); /**< expression data copy function, or NULL to only opdata union */
3210  SCIP_DECL_EXPRFREEDATA ((*freedata)); /**< expression data free function, or NULL if nothing to free */
3211 };
3212 
3213 #define EXPROPEMPTY {NULL, -1, NULL, NULL, NULL, NULL, NULL}
3214 
3215 /** table containing for each operand the name, the number of children, and some evaluation functions */
3216 static
3217 struct exprOpTableElement exprOpTable[] =
3218  {
3219  EXPROPEMPTY,
3220  { "variable", 0, exprevalVar, exprevalIntVar, exprcurvVar, NULL, NULL },
3221  { "constant", 0, exprevalConst, exprevalIntConst, exprcurvConst, NULL, NULL },
3222  { "parameter", 0, exprevalParam, exprevalIntParam, exprcurvParam, NULL, NULL },
3224  { "plus", 2, exprevalPlus, exprevalIntPlus, exprcurvPlus, NULL, NULL },
3225  { "minus", 2, exprevalMinus, exprevalIntMinus, exprcurvMinus, NULL, NULL },
3226  { "mul", 2, exprevalMult, exprevalIntMult, exprcurvMult, NULL, NULL },
3227  { "div", 2, exprevalDiv, exprevalIntDiv, exprcurvDiv, NULL, NULL },
3228  { "sqr", 1, exprevalSquare, exprevalIntSquare, exprcurvSquare, NULL, NULL },
3229  { "sqrt", 1, exprevalSquareRoot, exprevalIntSquareRoot, exprcurvSquareRoot, NULL, NULL },
3230  { "realpower", 1, exprevalRealPower, exprevalIntRealPower, exprcurvRealPower, NULL, NULL },
3231  { "intpower", 1, exprevalIntPower, exprevalIntIntPower, exprcurvIntPower, NULL, NULL },
3232  { "signpower", 1, exprevalSignPower, exprevalIntSignPower, exprcurvSignPower, NULL, NULL },
3233  { "exp", 1, exprevalExp, exprevalIntExp, exprcurvExp, NULL, NULL },
3234  { "log", 1, exprevalLog, exprevalIntLog, exprcurvLog, NULL, NULL },
3235  { "sin", 1, exprevalSin, exprevalIntSin, exprcurvSin, NULL, NULL },
3236  { "cos", 1, exprevalCos, exprevalIntCos, exprcurvCos, NULL, NULL },
3237  { "tan", 1, exprevalTan, exprevalIntTan, exprcurvTan, NULL, NULL },
3238  /* { "erf", 1, exprevalErf, exprevalIntErf, exprcurvErf, NULL, NULL }, */
3239  /* { "erfi", 1, exprevalErfi, exprevalIntErfi exprcurvErfi, NULL, NULL }, */
3241  { "min", 2, exprevalMin, exprevalIntMin, exprcurvMin, NULL, NULL },
3242  { "max", 2, exprevalMax, exprevalIntMax, exprcurvMax, NULL, NULL },
3243  { "abs", 1, exprevalAbs, exprevalIntAbs, exprcurvAbs, NULL, NULL },
3244  { "sign", 1, exprevalSign, exprevalIntSign, exprcurvSign, NULL, NULL },
3250  { "sum", -2, exprevalSum, exprevalIntSum, exprcurvSum, NULL, NULL },
3251  { "prod", -2, exprevalProduct, exprevalIntProduct, exprcurvProduct, NULL, NULL },
3252  { "linear", -2, exprevalLinear, exprevalIntLinear, exprcurvLinear, exprCopyDataLinear, exprFreeDataLinear },
3253  { "quadratic", -2, exprevalQuadratic, exprevalIntQuadratic, exprcurvQuadratic, exprCopyDataQuadratic, exprFreeDataQuadratic },
3254  { "polynomial", -2, exprevalPolynomial, exprevalIntPolynomial, exprcurvPolynomial, exprCopyDataPolynomial, exprFreeDataPolynomial },
3255  { "user", -2, exprevalUser, exprevalIntUser, exprcurvUser, exprCopyDataUser, exprFreeDataUser }
3256  };
3257 
3258 /**@} */
3259 
3260 /**@name Expression operand methods */
3261 /**@{ */
3262 
3263 /** gives the name of an operand as string */
3264 const char* SCIPexpropGetName(
3265  SCIP_EXPROP op /**< expression operand */
3266  )
3267 {
3268  assert(op < SCIP_EXPR_LAST);
3269 
3270  return exprOpTable[op].name;
3271 }
3272 
3273 /** gives the number of children of a simple operand */
3275  SCIP_EXPROP op /**< expression operand */
3276  )
3277 {
3278  assert(op < SCIP_EXPR_LAST);
3279 
3280  return exprOpTable[op].nargs;
3281 }
3282 
3283 /**@} */
3284 
3285 /**@name Expressions private methods */
3286 /**@{ */
3287 
3288 /** creates an expression
3289  *
3290  * Note, that the expression is allocated but for the children only the pointer is copied.
3291  */
3292 static
3294  BMS_BLKMEM* blkmem, /**< block memory data structure */
3295  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
3296  SCIP_EXPROP op, /**< operand of expression */
3297  int nchildren, /**< number of children */
3298  SCIP_EXPR** children, /**< children */
3299  SCIP_EXPROPDATA opdata /**< operand data */
3300  )
3301 {
3302  assert(blkmem != NULL);
3303  assert(expr != NULL);
3304  assert(children != NULL || nchildren == 0);
3305  assert(children == NULL || nchildren > 0);
3306 
3307  SCIP_ALLOC( BMSallocBlockMemory(blkmem, expr) );
3308 
3309  (*expr)->op = op;
3310  (*expr)->nchildren = nchildren;
3311  (*expr)->children = children;
3312  (*expr)->data = opdata;
3313 
3314  return SCIP_OKAY;
3315 }
3316 
3317 /** tries to convert a given (operator,operatordata) pair into a polynomial operator with corresponding data
3318  *
3319  * Does not do this for constants.
3320  * If conversion is not possible or operator is already polynomial, *op and *data are
3321  * left untouched.
3322  */
3323 static
3325  BMS_BLKMEM* blkmem, /**< block memory */
3326  SCIP_EXPROP* op, /**< pointer to expression operator */
3327  SCIP_EXPROPDATA* data, /**< pointer to expression data */
3328  int nchildren /**< number of children of operator */
3329  )
3330 {
3331  assert(blkmem != NULL);
3332  assert(op != NULL);
3333  assert(data != NULL);
3334 
3335  switch( *op )
3336  {
3337  case SCIP_EXPR_VARIDX:
3338  case SCIP_EXPR_PARAM:
3339  case SCIP_EXPR_CONST:
3340  break;
3341 
3342  case SCIP_EXPR_PLUS:
3343  {
3344  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3345  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3346  int childidx;
3347  SCIP_Real exponent;
3348 
3349  assert(nchildren == 2);
3350 
3351  /* create monomial for first child */
3352  childidx = 0;
3353  exponent = 1.0;
3354  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3355 
3356  /* create monomial for second child */
3357  childidx = 1;
3358  exponent = 1.0;
3359  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], 1.0, 1, &childidx, &exponent) );
3360 
3361  /* create polynomial for sum of children */
3362  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3363 
3364  *op = SCIP_EXPR_POLYNOMIAL;
3365  data->data = (void*)polynomialdata;
3366 
3367  break;
3368  }
3369 
3370  case SCIP_EXPR_MINUS:
3371  {
3372  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3373  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3374  int childidx;
3375  SCIP_Real exponent;
3376 
3377  assert(nchildren == 2);
3378 
3379  /* create monomial for first child */
3380  childidx = 0;
3381  exponent = 1.0;
3382  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3383 
3384  /* create monomial for second child */
3385  childidx = 1;
3386  exponent = 1.0;
3387  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], -1.0, 1, &childidx, &exponent) );
3388 
3389  /* create polynomial for difference of children */
3390  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3391 
3392  *op = SCIP_EXPR_POLYNOMIAL;
3393  data->data = (void*)polynomialdata;
3394 
3395  break;
3396  }
3397 
3398  case SCIP_EXPR_MUL:
3399  {
3400  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3401  SCIP_EXPRDATA_MONOMIAL* monomial;
3402  int childidx[2];
3403  SCIP_Real exponent[2];
3404 
3405  assert(nchildren == 2);
3406 
3407  /* create monomial for product of children */
3408  childidx[0] = 0;
3409  childidx[1] = 1;
3410  exponent[0] = 1.0;
3411  exponent[1] = 1.0;
3412  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3413 
3414  /* create polynomial */
3415  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3416 
3417  *op = SCIP_EXPR_POLYNOMIAL;
3418  data->data = (void*)polynomialdata;
3419 
3420  break;
3421  }
3422 
3423  case SCIP_EXPR_DIV:
3424  {
3425  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3426  SCIP_EXPRDATA_MONOMIAL* monomial;
3427  int childidx[2];
3428  SCIP_Real exponent[2];
3429 
3430  assert(nchildren == 2);
3431 
3432  /* create monomial for division of children */
3433  childidx[0] = 0;
3434  childidx[1] = 1;
3435  exponent[0] = 1.0;
3436  exponent[1] = -1.0;
3437  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3438 
3439  /* create polynomial */
3440  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3441 
3442  *op = SCIP_EXPR_POLYNOMIAL;
3443  data->data = (void*)polynomialdata;
3444 
3445  break;
3446  }
3447 
3448  case SCIP_EXPR_SQUARE:
3449  {
3450  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3451  SCIP_EXPRDATA_MONOMIAL* monomial;
3452  int childidx;
3453  SCIP_Real exponent;
3454 
3455  assert(nchildren == 1);
3456 
3457  /* create monomial for square of child */
3458  childidx = 0;
3459  exponent = 2.0;
3460  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3461 
3462  /* create polynomial */
3463  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3464 
3465  *op = SCIP_EXPR_POLYNOMIAL;
3466  data->data = (void*)polynomialdata;
3467 
3468  break;
3469  }
3470 
3471  case SCIP_EXPR_SQRT:
3472  {
3473  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3474  SCIP_EXPRDATA_MONOMIAL* monomial;
3475  int childidx;
3476  SCIP_Real exponent;
3477 
3478  assert(nchildren == 1);
3479 
3480  /* create monomial for square root of child */
3481  childidx = 0;
3482  exponent = 0.5;
3483  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3484 
3485  /* create polynomial */
3486  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3487 
3488  *op = SCIP_EXPR_POLYNOMIAL;
3489  data->data = (void*)polynomialdata;
3490 
3491  break;
3492  }
3493 
3494  case SCIP_EXPR_REALPOWER:
3495  {
3496  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3497  SCIP_EXPRDATA_MONOMIAL* monomial;
3498  int childidx;
3499 
3500  assert(nchildren == 1);
3501 
3502  /* convert to child0 to the power of exponent */
3503 
3504  /* create monomial for power of first child */
3505  childidx = 0;
3506  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &data->dbl) );
3507 
3508  /* create polynomial */
3509  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3510 
3511  *op = SCIP_EXPR_POLYNOMIAL;
3512  data->data = (void*)polynomialdata;
3513 
3514  break;
3515  }
3516 
3517  case SCIP_EXPR_SIGNPOWER:
3518  {
3519  SCIP_Real exponent;
3520 
3521  assert(nchildren == 1);
3522 
3523  /* check if exponent is an odd integer */
3524  exponent = data->dbl;
3525  if( EPSISINT(exponent, 0.0) && (int)exponent % 2 != 0 ) /*lint !e835*/
3526  {
3527  /* convert to child0 to the power of exponent, since sign is kept by taking power */
3528  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3529  SCIP_EXPRDATA_MONOMIAL* monomial;
3530  int childidx;
3531 
3532  /* create monomial for power of first child */
3533  childidx = 0;
3534  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3535 
3536  /* create polynomial */
3537  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3538 
3539  *op = SCIP_EXPR_POLYNOMIAL;
3540  data->data = (void*)polynomialdata;
3541  }
3542  /* if exponent is not an odd integer constant, then keep it as signpower expression */
3543  break;
3544  }
3545 
3546  case SCIP_EXPR_INTPOWER:
3547  {
3548  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3549  SCIP_EXPRDATA_MONOMIAL* monomial;
3550  int childidx;
3551  SCIP_Real exponent;
3552 
3553  assert(nchildren == 1);
3554 
3555  /* create monomial for power of child */
3556  childidx = 0;
3557  exponent = data->intval;
3558  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3559 
3560  /* create polynomial */
3561  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3562 
3563  *op = SCIP_EXPR_POLYNOMIAL;
3564  data->data = (void*)polynomialdata;
3565 
3566  break;
3567  }
3568 
3569  case SCIP_EXPR_EXP:
3570  case SCIP_EXPR_LOG:
3571  case SCIP_EXPR_SIN:
3572  case SCIP_EXPR_COS:
3573  case SCIP_EXPR_TAN:
3574  /* case SCIP_EXPR_ERF: */
3575  /* case SCIP_EXPR_ERFI: */
3576  case SCIP_EXPR_MIN:
3577  case SCIP_EXPR_MAX:
3578  case SCIP_EXPR_ABS:
3579  case SCIP_EXPR_SIGN:
3580  case SCIP_EXPR_USER:
3581  break;
3582 
3583  case SCIP_EXPR_SUM:
3584  {
3585  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3586  SCIP_EXPRDATA_MONOMIAL* monomial;
3587  int childidx;
3588  int i;
3589  SCIP_Real exponent;
3590 
3591  /* create empty polynomial */
3592  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, 0.0, FALSE) );
3593  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3594  assert(polynomialdata->monomialssize >= nchildren);
3595 
3596  /* add summands as monomials */
3597  childidx = 0;
3598  exponent = 1.0;
3599  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3600  for( i = 0; i < nchildren; ++i )
3601  {
3602  monomial->childidxs[0] = i;
3603  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3604  }
3605  SCIPexprFreeMonomial(blkmem, &monomial);
3606 
3607  *op = SCIP_EXPR_POLYNOMIAL;
3608  data->data = (void*)polynomialdata;
3609 
3610  break;
3611  }
3612 
3613  case SCIP_EXPR_PRODUCT:
3614  {
3615  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3616  SCIP_EXPRDATA_MONOMIAL* monomial;
3617  int childidx;
3618  int i;
3619  SCIP_Real exponent;
3620 
3621  /* create monomial */
3622  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 0, NULL, NULL) );
3623  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, nchildren) );
3624  exponent = 1.0;
3625  for( i = 0; i < nchildren; ++i )
3626  {
3627  childidx = i;
3628  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
3629  }
3630 
3631  /* create polynomial */
3632  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3633 
3634  *op = SCIP_EXPR_POLYNOMIAL;
3635  data->data = (void*)polynomialdata;
3636 
3637  break;
3638  }
3639 
3640  case SCIP_EXPR_LINEAR:
3641  {
3642  SCIP_Real* lineardata;
3643  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3644  SCIP_EXPRDATA_MONOMIAL* monomial;
3645  int childidx;
3646  int i;
3647  SCIP_Real exponent;
3648 
3649  /* get coefficients of linear term */
3650  lineardata = (SCIP_Real*)data->data;
3651  assert(lineardata != NULL);
3652 
3653  /* create polynomial consisting of constant from linear term */
3654  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, lineardata[nchildren], FALSE) );
3655  /* ensure space for linear coefficients */
3656  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3657  assert(polynomialdata->monomialssize >= nchildren);
3658 
3659  /* add summands as monomials */
3660  childidx = 0;
3661  exponent = 1.0;
3662  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3663  for( i = 0; i < nchildren; ++i )
3664  {
3665  monomial->coef = lineardata[i];
3666  monomial->childidxs[0] = i;
3667  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3668  }
3669  SCIPexprFreeMonomial(blkmem, &monomial);
3670 
3671  /* free linear expression data */
3672  exprFreeDataLinear(blkmem, nchildren, *data);
3673 
3674  *op = SCIP_EXPR_POLYNOMIAL;
3675  data->data = (void*)polynomialdata;
3676 
3677  break;
3678  }
3679 
3680  case SCIP_EXPR_QUADRATIC:
3681  {
3682  SCIP_EXPRDATA_QUADRATIC* quaddata;
3683  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3684  SCIP_EXPRDATA_MONOMIAL* squaremonomial;
3685  SCIP_EXPRDATA_MONOMIAL* bilinmonomial;
3686  SCIP_EXPRDATA_MONOMIAL* linmonomial;
3687  int childidx[2];
3688  SCIP_Real exponent[2];
3689  int i;
3690 
3691  /* get data of quadratic expression */
3692  quaddata = (SCIP_EXPRDATA_QUADRATIC*)data->data;
3693  assert(quaddata != NULL);
3694 
3695  /* create empty polynomial */
3696  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, quaddata->constant, FALSE) );
3697  /* ensure space for linear and quadratic terms */
3698  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, (quaddata->lincoefs != NULL ? nchildren : 0) + quaddata->nquadelems) );
3699  assert(polynomialdata->monomialssize >= quaddata->nquadelems);
3700 
3701  childidx[0] = 0;
3702  childidx[1] = 0;
3703 
3704  /* create monomial templates */
3705  exponent[0] = 2.0;
3706  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &squaremonomial, 1.0, 1, childidx, exponent) );
3707  exponent[0] = 1.0;
3708  exponent[1] = 1.0;
3709  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &bilinmonomial, 1.0, 2, childidx, exponent) );
3710  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &linmonomial, 1.0, 1, childidx, exponent) );
3711 
3712  /* add linear terms as monomials */
3713  if( quaddata->lincoefs != NULL )
3714  for( i = 0; i < nchildren; ++i )
3715  if( quaddata->lincoefs[i] != 0.0 )
3716  {
3717  linmonomial->childidxs[0] = i;
3718  linmonomial->coef = quaddata->lincoefs[i];
3719  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &linmonomial, TRUE) );
3720  }
3721 
3722  /* add quadratic terms as monomials */
3723  for( i = 0; i < quaddata->nquadelems; ++i )
3724  {
3725  if( quaddata->quadelems[i].idx1 == quaddata->quadelems[i].idx2 )
3726  {
3727  squaremonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3728  squaremonomial->coef = quaddata->quadelems[i].coef;
3729  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &squaremonomial, TRUE) );
3730  }
3731  else
3732  {
3733  bilinmonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3734  bilinmonomial->childidxs[1] = quaddata->quadelems[i].idx2;
3735  bilinmonomial->coef = quaddata->quadelems[i].coef;
3736  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &bilinmonomial, TRUE) );
3737  }
3738  }
3739  SCIPexprFreeMonomial(blkmem, &squaremonomial);
3740  SCIPexprFreeMonomial(blkmem, &bilinmonomial);
3741  SCIPexprFreeMonomial(blkmem, &linmonomial);
3742 
3743  /* free quadratic expression data */
3744  exprFreeDataQuadratic(blkmem, nchildren, *data);
3745 
3746  *op = SCIP_EXPR_POLYNOMIAL;
3747  data->data = (void*)polynomialdata;
3748 
3749  break;
3750  }
3751 
3752  case SCIP_EXPR_POLYNOMIAL:
3753  case SCIP_EXPR_LAST:
3754  break;
3755  } /*lint !e788*/
3756 
3757  return SCIP_OKAY;
3758 }
3759 
3760 /** converts polynomial expression back into simpler expression, if possible */
3761 static
3763  BMS_BLKMEM* blkmem, /**< block memory data structure */
3764  SCIP_EXPROP* op, /**< pointer to expression operator */
3765  SCIP_EXPROPDATA* data, /**< pointer to expression data holding polynomial data */
3766  int nchildren, /**< number of children of operator */
3767  void** children /**< children array */
3768  )
3769 {
3770  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3771  SCIP_EXPRDATA_MONOMIAL* monomial;
3772  int maxdegree;
3773  int nlinmonomials;
3774  int i;
3775  int j;
3776 
3777  assert(blkmem != NULL);
3778  assert(op != NULL);
3779  assert(*op == SCIP_EXPR_POLYNOMIAL);
3780  assert(data != NULL);
3781  assert(children != NULL || nchildren == 0);
3782 
3783  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)data->data;
3784  assert(polynomialdata != NULL);
3785 
3786  /* make sure monomials are sorted and merged */
3787  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
3788 
3789  /* if no monomials, then leave as it is */
3790  if( polynomialdata->nmonomials == 0 )
3791  return SCIP_OKAY;
3792 
3793  /* check maximal degree of polynomial only - not considering children expressions
3794  * check number of linear monomials */
3795  maxdegree = 0;
3796  nlinmonomials = 0;
3797  for( i = 0; i < polynomialdata->nmonomials; ++i )
3798  {
3799  int monomialdegree;
3800 
3801  monomial = polynomialdata->monomials[i];
3802  assert(monomial != NULL);
3803 
3804  monomialdegree = 0;
3805  for(j = 0; j < monomial->nfactors; ++j )
3806  {
3807  if( !EPSISINT(monomial->exponents[j], 0.0) || monomial->exponents[j] < 0.0 ) /*lint !e835*/
3808  {
3809  monomialdegree = SCIP_EXPR_DEGREEINFINITY;
3810  break;
3811  }
3812 
3813  monomialdegree += (int)EPSROUND(monomial->exponents[j], 0.0); /*lint !e835*/
3814  }
3815 
3816  if( monomialdegree == SCIP_EXPR_DEGREEINFINITY )
3817  {
3818  maxdegree = SCIP_EXPR_DEGREEINFINITY;
3819  break;
3820  }
3821 
3822  if( monomialdegree == 1 )
3823  ++nlinmonomials;
3824 
3825  if( monomialdegree > maxdegree )
3826  maxdegree = monomialdegree;
3827  }
3828  assert(maxdegree > 0 );
3829 
3830  if( maxdegree == 1 )
3831  {
3832  /* polynomial is a linear expression in children */
3833 
3834  /* polynomial simplification and monomial merging should ensure that monomial i corresponds to child i and that there are not unused children */
3835  assert(polynomialdata->nmonomials == nchildren);
3836  assert(polynomialdata->nmonomials == nlinmonomials);
3837 
3838  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3839  {
3840  /* polynomial is addition of two expressions, so turn into SCIP_EXPR_PLUS */
3841  assert(polynomialdata->monomials[0]->nfactors == 1);
3842  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3843  assert(polynomialdata->monomials[1]->nfactors == 1);
3844  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3845 
3846  polynomialdataFree(blkmem, &polynomialdata);
3847  data->data = NULL;
3848 
3849  /* change operator type to PLUS */
3850  *op = SCIP_EXPR_PLUS;
3851 
3852  return SCIP_OKAY;
3853  }
3854 
3855  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == -1.0 )
3856  {
3857  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3858  assert(polynomialdata->monomials[0]->nfactors == 1);
3859  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3860  assert(polynomialdata->monomials[1]->nfactors == 1);
3861  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3862 
3863  polynomialdataFree(blkmem, &polynomialdata);
3864  data->data = NULL;
3865 
3866  /* change operator type to MINUS */
3867  *op = SCIP_EXPR_MINUS;
3868 
3869  return SCIP_OKAY;
3870  }
3871 
3872  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == -1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3873  {
3874  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3875  void* tmp;
3876 
3877  assert(polynomialdata->monomials[0]->nfactors == 1);
3878  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3879  assert(polynomialdata->monomials[1]->nfactors == 1);
3880  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3881 
3882  polynomialdataFree(blkmem, &polynomialdata);
3883  data->data = NULL;
3884 
3885  /* swap children */
3886  tmp = children[1]; /*lint !e613*/
3887  children[1] = children[0]; /*lint !e613*/
3888  children[0] = tmp; /*lint !e613*/
3889 
3890  /* change operator type to MINUS */
3891  *op = SCIP_EXPR_MINUS;
3892 
3893  return SCIP_OKAY;
3894  }
3895 
3896  if( polynomialdata->constant == 0.0 )
3897  {
3898  /* check if all monomials have coefficient 1.0 */
3899  for( i = 0; i < polynomialdata->nmonomials; ++i )
3900  if( polynomialdata->monomials[i]->coef != 1.0 )
3901  break;
3902 
3903  if( i == polynomialdata->nmonomials )
3904  {
3905  /* polynomial is sum of children, so turn into SCIP_EXPR_SUM */
3906 
3907  polynomialdataFree(blkmem, &polynomialdata);
3908  data->data = NULL;
3909 
3910  /* change operator type to MINUS */
3911  *op = SCIP_EXPR_SUM;
3912 
3913  return SCIP_OKAY;
3914  }
3915  }
3916 
3917  /* turn polynomial into linear expression */
3918  {
3919  SCIP_Real* lindata;
3920 
3921  /* monomial merging should ensure that each child appears in at most one monomial,
3922  * that monomials are ordered according to the child index, and that constant monomials have been removed
3923  */
3924 
3925  /* setup data of linear expression */
3926  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &lindata, polynomialdata->nmonomials + 1) );
3927 
3928  for( i = 0; i < polynomialdata->nmonomials; ++i )
3929  {
3930  assert(polynomialdata->monomials[i]->childidxs[0] == i);
3931  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3932  lindata[i] = polynomialdata->monomials[i]->coef; /*lint !e644*/
3933  }
3934  lindata[i] = polynomialdata->constant;
3935 
3936  polynomialdataFree(blkmem, &polynomialdata);
3937  *op = SCIP_EXPR_LINEAR;
3938  data->data = (void*)lindata;
3939 
3940  return SCIP_OKAY;
3941  }
3942  }
3943 
3944  if( maxdegree == 2 && (polynomialdata->nmonomials > 1 || polynomialdata->constant != 0.0 || polynomialdata->monomials[0]->coef != 1.0) )
3945  {
3946  /* 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 */
3947  SCIP_EXPRDATA_QUADRATIC* quaddata;
3948  int quadelemidx;
3949 
3950  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &quaddata) );
3951  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->quadelems, polynomialdata->nmonomials - nlinmonomials) );
3952  quaddata->nquadelems = polynomialdata->nmonomials - nlinmonomials;
3953  quaddata->constant = polynomialdata->constant;
3954  quaddata->sorted = FALSE; /* quadratic data is sorted different than polynomials */
3955 
3956  if( nlinmonomials > 0 )
3957  {
3958  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->lincoefs, nchildren) );
3959  BMSclearMemoryArray(quaddata->lincoefs, nchildren);
3960  }
3961  else
3962  quaddata->lincoefs = NULL;
3963 
3964  quadelemidx = 0;
3965  for( i = 0; i < polynomialdata->nmonomials; ++i )
3966  {
3967  assert(polynomialdata->monomials[i]->nfactors == 1 || polynomialdata->monomials[i]->nfactors == 2);
3968  if( polynomialdata->monomials[i]->nfactors == 1 )
3969  {
3970  if( polynomialdata->monomials[i]->exponents[0] == 1.0 )
3971  {
3972  /* monomial is a linear term */
3973  assert(quaddata->lincoefs != NULL);
3974  quaddata->lincoefs[polynomialdata->monomials[i]->childidxs[0]] += polynomialdata->monomials[i]->coef;
3975  }
3976  else
3977  {
3978  /* monomial should be a square term */
3979  assert(polynomialdata->monomials[i]->exponents[0] == 2.0);
3980  assert(quadelemidx < quaddata->nquadelems);
3981  quaddata->quadelems[quadelemidx].idx1 = polynomialdata->monomials[i]->childidxs[0];
3982  quaddata->quadelems[quadelemidx].idx2 = polynomialdata->monomials[i]->childidxs[0];
3983  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3984  ++quadelemidx;
3985  }
3986  }
3987  else
3988  {
3989  /* monomial should be a bilinear term */
3990  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3991  assert(polynomialdata->monomials[i]->exponents[1] == 1.0);
3992  assert(quadelemidx < quaddata->nquadelems);
3993  quaddata->quadelems[quadelemidx].idx1 = MIN(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3994  quaddata->quadelems[quadelemidx].idx2 = MAX(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3995  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3996  ++quadelemidx;
3997  }
3998  }
3999  assert(quadelemidx == quaddata->nquadelems);
4000 
4001  polynomialdataFree(blkmem, &polynomialdata);
4002 
4003  *op = SCIP_EXPR_QUADRATIC;
4004  data->data = (void*)quaddata;
4005 
4006  return SCIP_OKAY;
4007  }
4008 
4009  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 1 && polynomialdata->monomials[0]->coef == 1.0 )
4010  {
4011  /* polynomial is product of children */
4012  monomial = polynomialdata->monomials[0];
4013  assert(monomial->nfactors == nchildren);
4014 
4015  if( monomial->nfactors == 1 )
4016  {
4017  /* polynomial is x^k for some k */
4018  assert(monomial->exponents[0] != 1.0); /* should have been handled before */
4019  assert(monomial->childidxs[0] == 0);
4020 
4021  if( monomial->exponents[0] == 2.0 )
4022  {
4023  /* polynomial is x^2, so turn into SCIP_EXPR_SQUARE */
4024 
4025  polynomialdataFree(blkmem, &polynomialdata);
4026  data->data = NULL;
4027 
4028  *op = SCIP_EXPR_SQUARE;
4029 
4030  return SCIP_OKAY;
4031  }
4032 
4033  if( EPSISINT(monomial->exponents[0], 0.0) ) /*lint !e835*/
4034  {
4035  /* k is an integer, so turn into SCIP_EXPR_INTPOWER */
4036  int exponent;
4037 
4038  exponent = (int)EPSROUND(monomial->exponents[0], 0.0); /*lint !e835*/
4039 
4040  polynomialdataFree(blkmem, &polynomialdata);
4041 
4042  *op = SCIP_EXPR_INTPOWER;
4043  data->intval = exponent;
4044 
4045  return SCIP_OKAY;
4046  }
4047 
4048  if( monomial->exponents[0] == 0.5 )
4049  {
4050  /* polynomial is sqrt(x), so turn into SCIP_EXPR_SQRT */
4051 
4052  polynomialdataFree(blkmem, &polynomialdata);
4053  data->data = NULL;
4054 
4055  *op = SCIP_EXPR_SQRT;
4056 
4057  return SCIP_OKAY;
4058  }
4059 
4060  {
4061  /* polynomial is x^a with a some real number, so turn into SCIP_EXPR_REALPOWER */
4062  SCIP_Real exponent;
4063 
4064  exponent = monomial->exponents[0];
4065 
4066  polynomialdataFree(blkmem, &polynomialdata);
4067 
4068  *op = SCIP_EXPR_REALPOWER;
4069  data->dbl = exponent;
4070 
4071  return SCIP_OKAY;
4072  }
4073  }
4074 
4075  if( maxdegree == 2 && monomial->nfactors == 2 )
4076  {
4077  /* polynomial is product of two children, so turn into SCIP_EXPR_MUL */
4078  assert(monomial->exponents[0] == 1.0);
4079  assert(monomial->exponents[1] == 1.0);
4080 
4081  polynomialdataFree(blkmem, &polynomialdata);
4082  data->data = NULL;
4083 
4084  *op = SCIP_EXPR_MUL;
4085 
4086  return SCIP_OKAY;
4087  }
4088 
4089  if( maxdegree == monomial->nfactors )
4090  {
4091  /* polynomial is a product of n children, so turn into SCIP_EXPR_PRODUCT */
4092 
4093  polynomialdataFree(blkmem, &polynomialdata);
4094  data->data = NULL;
4095 
4096  *op = SCIP_EXPR_PRODUCT;
4097 
4098  return SCIP_OKAY;
4099  }
4100 
4101  if( monomial->nfactors == 2 && monomial->exponents[0] == 1.0 && monomial->exponents[1] == -1.0 )
4102  {
4103  /* polynomial is x/y, so turn into SCIP_EXPR_DIV */
4104  assert(monomial->childidxs[0] == 0);
4105  assert(monomial->childidxs[1] == 1);
4106 
4107  polynomialdataFree(blkmem, &polynomialdata);
4108  data->data = NULL;
4109 
4110  *op = SCIP_EXPR_DIV;
4111 
4112  return SCIP_OKAY;
4113  }
4114 
4115  if( monomial->nfactors == 2 && monomial->exponents[0] == -1.0 && monomial->exponents[1] == 1.0 )
4116  {
4117  /* polynomial is y/x, so turn into SCIP_EXPR_DIV */
4118  void* tmp;
4119 
4120  assert(monomial->childidxs[0] == 0);
4121  assert(monomial->childidxs[1] == 1);
4122 
4123  polynomialdataFree(blkmem, &polynomialdata);
4124  data->data = NULL;
4125 
4126  /* swap children */
4127  tmp = children[1]; /*lint !e613*/
4128  children[1] = children[0]; /*lint !e613*/
4129  children[0] = tmp; /*lint !e613*/
4130 
4131  *op = SCIP_EXPR_DIV;
4132 
4133  return SCIP_OKAY;
4134  }
4135  }
4136 
4137  return SCIP_OKAY;
4138 }
4139 
4140 /** adds copies of expressions to the array of children of a sum, product, linear, quadratic, or polynomial expression
4141  *
4142  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
4143  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
4144  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
4145  */
4146 static
4148  BMS_BLKMEM* blkmem, /**< block memory */
4149  SCIP_EXPR* expr, /**< quadratic or polynomial expression */
4150  int nexprs, /**< number of expressions to add */
4151  SCIP_EXPR** exprs, /**< expressions to add */
4152  SCIP_Bool comparechildren, /**< whether to compare expressions with already existing children (no effect for sum and product) */
4153  SCIP_Real eps, /**< which epsilon to use when comparing expressions */
4154  int* childmap /**< array where to store mapping of indices from exprs to children array in expr, or NULL if not of interest */
4155  )
4156 {
4157  int i;
4158 
4159  assert(blkmem != NULL);
4160  assert(expr != NULL);
4161  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);
4162  assert(exprs != NULL || nexprs == 0);
4163 
4164  if( nexprs == 0 )
4165  return SCIP_OKAY;
4166 
4167  switch( expr->op )
4168  {
4169  case SCIP_EXPR_SUM:
4170  case SCIP_EXPR_PRODUCT:
4171  {
4172  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4173  for( i = 0; i < nexprs; ++i )
4174  {
4175  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren + i], exprs[i]) ); /*lint !e613*/
4176  if( childmap != NULL )
4177  childmap[i] = expr->nchildren + i;
4178  }
4179  expr->nchildren += nexprs;
4180 
4181  break;
4182  }
4183 
4184  case SCIP_EXPR_LINEAR:
4185  case SCIP_EXPR_QUADRATIC:
4186  case SCIP_EXPR_POLYNOMIAL:
4187  {
4188  int j;
4189  int orignchildren;
4190  SCIP_Bool existsalready;
4191 
4192  orignchildren = expr->nchildren;
4193  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4194 
4195  for( i = 0; i < nexprs; ++i )
4196  {
4197  existsalready = FALSE;
4198  if( comparechildren )
4199  for( j = 0; j < orignchildren; ++j )
4200  /* during simplification of polynomials, their may be NULL's in children array */
4201  if( expr->children[j] != NULL && SCIPexprAreEqual(expr->children[j], exprs[i], eps) ) /*lint !e613*/
4202  {
4203  existsalready = TRUE;
4204  break;
4205  }
4206 
4207  if( !existsalready )
4208  {
4209  /* add copy of exprs[j] to children array */
4210  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren], exprs[i]) ); /*lint !e613*/
4211  if( childmap != NULL )
4212  childmap[i] = expr->nchildren;
4213  ++expr->nchildren;
4214  }
4215  else
4216  {
4217  if( childmap != NULL )
4218  childmap[i] = j; /*lint !e644*/
4219  if( expr->op == SCIP_EXPR_LINEAR )
4220  {
4221  /* if linear expression, increase coefficient by 1.0 */
4222  ((SCIP_Real*)expr->data.data)[j] += 1.0;
4223  }
4224  }
4225  }
4226 
4227  /* shrink children array to actually used size */
4228  assert(comparechildren || expr->nchildren == orignchildren + nexprs);
4229  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, orignchildren + nexprs, expr->nchildren) );
4230 
4231  if( expr->op == SCIP_EXPR_LINEAR && expr->nchildren > orignchildren )
4232  {
4233  /* if linear expression, then add 1.0 coefficients for new expressions */
4234  SCIP_Real* data;
4235 
4236  data = (SCIP_Real*)expr->data.data;
4237  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, expr->nchildren + 1) );
4238  data[expr->nchildren] = data[orignchildren]; /* move constant from old end to new end */
4239  for( i = orignchildren; i < expr->nchildren; ++i )
4240  data[i] = 1.0;
4241  expr->data.data = (void*)data;
4242  }
4243  else if( expr->op == SCIP_EXPR_QUADRATIC && expr->nchildren > orignchildren )
4244  {
4245  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
4247 
4248  data = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
4249  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, expr->nchildren) );
4250  BMSclearMemoryArray(&data->lincoefs[orignchildren], expr->nchildren - orignchildren); /*lint !e866*/
4251  }
4252 
4253  break;
4254  }
4255 
4256  default:
4257  SCIPerrorMessage("exprsimplifyAddChildren cannot be called for operand %d\n", expr->op);
4258  return SCIP_INVALIDDATA;
4259  } /*lint !e788*/
4260 
4261  return SCIP_OKAY;
4262 }
4263 
4264 /** converts expressions into polynomials, where possible and obvious */
4265 static
4267  BMS_BLKMEM* blkmem, /**< block memory data structure */
4268  SCIP_EXPR* expr /**< expression to convert */
4269  )
4270 {
4271  int i;
4272 
4273  assert(expr != NULL);
4274 
4275  for( i = 0; i < expr->nchildren; ++i )
4276  {
4278  }
4279 
4280  SCIP_CALL( exprConvertToPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren) );
4281 
4282  return SCIP_OKAY;
4283 }
4284 
4285 /** removes duplicate children in a polynomial expression
4286  *
4287  * Leaves NULL's in children array.
4288  */
4289 static
4291  BMS_BLKMEM* blkmem, /**< block memory data structure */
4292  SCIP_EXPR* expr, /**< expression */
4293  SCIP_Real eps /**< threshold for zero */
4294  )
4295 {
4296  SCIP_Bool foundduplicates;
4297  int* childmap;
4298  int i;
4299  int j;
4300 
4301  assert(blkmem != NULL);
4302  assert(expr != NULL);
4303  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4304 
4305  if( expr->nchildren == 0 )
4306  return SCIP_OKAY;
4307 
4308  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4309 
4310  foundduplicates = FALSE;
4311  for( i = 0; i < expr->nchildren; ++i )
4312  {
4313  if( expr->children[i] == NULL )
4314  continue;
4315  childmap[i] = i; /*lint !e644*/
4316 
4317  for( j = i+1; j < expr->nchildren; ++j )
4318  {
4319  if( expr->children[j] == NULL )
4320  continue;
4321 
4322  if( SCIPexprAreEqual(expr->children[i], expr->children[j], eps) )
4323  {
4324  /* forget about expr j and remember that is to be replaced by i */
4325  SCIPexprFreeDeep(blkmem, &expr->children[j]);
4326  childmap[j] = i;
4327  foundduplicates = TRUE;
4328  }
4329  }
4330  }
4331 
4332  /* apply childmap to monomials */
4333  if( foundduplicates )
4335 
4336  /* free childmap */
4337  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4338 
4339  return SCIP_OKAY;
4340 }
4341 
4342 /** eliminates NULL's in children array and shrinks it to actual size */
4343 static
4345  BMS_BLKMEM* blkmem, /**< block memory data structure */
4346  SCIP_EXPR* expr /**< expression */
4347  )
4348 {
4349  int* childmap;
4350  int lastnonnull;
4351  int i;
4352 
4353  assert(blkmem != NULL);
4354  assert(expr != NULL);
4355  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4356 
4357  if( expr->nchildren == 0 )
4358  return SCIP_OKAY;
4359 
4360  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4361 
4362  /* close gaps in children array */
4363  lastnonnull = expr->nchildren-1;
4364  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4365  --lastnonnull;
4366  for( i = 0; i <= lastnonnull; ++i )
4367  {
4368  if( expr->children[i] != NULL )
4369  {
4370  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
4371  continue;
4372  }
4373  assert(expr->children[lastnonnull] != NULL);
4374 
4375  /* move child at lastnonnull to position i */
4376  expr->children[i] = expr->children[lastnonnull];
4377  expr->children[lastnonnull] = NULL;
4378  childmap[lastnonnull] = i;
4379 
4380  /* update lastnonnull */
4381  --lastnonnull;
4382  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4383  --lastnonnull;
4384  }
4385  assert(i > lastnonnull);
4386 
4387  /* apply childmap to monomials */
4388  if( lastnonnull < expr->nchildren-1 )
4390 
4391  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4392 
4393  /* shrink children array */
4394  if( lastnonnull >= 0 )
4395  {
4396  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, lastnonnull+1) );
4397  expr->nchildren = lastnonnull+1;
4398  }
4399  else
4400  {
4401  BMSfreeBlockMemoryArray(blkmem, &expr->children, expr->nchildren);
4402  expr->nchildren = 0;
4403  }
4404 
4405  return SCIP_OKAY;
4406 }
4407 
4408 /** checks which children are still in use and frees those which are not */
4409 static
4411  BMS_BLKMEM* blkmem, /**< block memory data structure */
4412  SCIP_EXPR* expr /**< polynomial expression */
4413  )
4414 {
4415  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4416  SCIP_EXPRDATA_MONOMIAL* monomial;
4417  SCIP_Bool* childinuse;
4418  int i;
4419  int j;
4420 
4421  assert(blkmem != NULL);
4422  assert(expr != NULL);
4423 
4424  if( expr->nchildren == 0 )
4425  return SCIP_OKAY;
4426 
4427  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4428  assert(polynomialdata != NULL);
4429 
4430  /* check which children are still in use */
4431  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, expr->nchildren) );
4432  BMSclearMemoryArray(childinuse, expr->nchildren); /*lint !e644*/
4433  for( i = 0; i < polynomialdata->nmonomials; ++i )
4434  {
4435  monomial = polynomialdata->monomials[i];
4436  assert(monomial != NULL);
4437 
4438  for( j = 0; j < monomial->nfactors; ++j )
4439  {
4440  assert(monomial->childidxs[j] >= 0);
4441  assert(monomial->childidxs[j] < expr->nchildren);
4442  childinuse[monomial->childidxs[j]] = TRUE;
4443  }
4444  }
4445 
4446  /* free children that are not used in any monomial */
4447  for( i = 0; i < expr->nchildren; ++i )
4448  if( expr->children[i] != NULL && !childinuse[i] )
4449  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4450 
4451  BMSfreeBlockMemoryArray(blkmem, &childinuse, expr->nchildren);
4452 
4453  return SCIP_OKAY;
4454 }
4455 
4456 /** flattens polynomials in polynomials, check for constants in non-polynomials expressions
4457  *
4458  * exprsimplifyConvertToPolynomials should have been called before to eliminate simple polynomial operands.
4459  */
4460 static
4462  BMS_BLKMEM* blkmem, /**< block memory data structure */
4463  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4464  SCIP_EXPR* expr, /**< expression */
4465  SCIP_Real eps, /**< threshold, under which values are treat as 0 */
4466  int maxexpansionexponent/**< maximal exponent for which we still expand non-monomial polynomials */
4467  )
4468 {
4469  int i;
4470 
4471  assert(expr != NULL);
4472 
4473  for( i = 0; i < expr->nchildren; ++i )
4474  {
4475  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr->children[i], eps, maxexpansionexponent) );
4476  }
4477 
4478  switch( SCIPexprGetOperator(expr) )
4479  {
4480  case SCIP_EXPR_VARIDX:
4481  case SCIP_EXPR_CONST:
4482  case SCIP_EXPR_PARAM:
4483  case SCIP_EXPR_PLUS:
4484  case SCIP_EXPR_MINUS:
4485  case SCIP_EXPR_MUL:
4486  case SCIP_EXPR_DIV:
4487  case SCIP_EXPR_SQUARE:
4488  case SCIP_EXPR_SQRT:
4489  case SCIP_EXPR_INTPOWER:
4490  case SCIP_EXPR_REALPOWER:
4491  case SCIP_EXPR_SIGNPOWER:
4492  break;
4493 
4494  case SCIP_EXPR_EXP:
4495  case SCIP_EXPR_LOG:
4496  case SCIP_EXPR_SIN:
4497  case SCIP_EXPR_COS:
4498  case SCIP_EXPR_TAN:
4499  /* case SCIP_EXPR_ERF: */
4500  /* case SCIP_EXPR_ERFI: */
4501  case SCIP_EXPR_ABS:
4502  case SCIP_EXPR_SIGN:
4503  {
4504  /* check if argument is a constant */
4505  if( (expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) ||
4506  expr->children[0]->op == SCIP_EXPR_CONST )
4507  {
4508  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4509  SCIP_Real exprval;
4510 
4511  /* since child0 has no children and it's polynomial was flattened, it should have no monomials */
4512  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4513 
4514  /* evaluate expression in constant polynomial */
4515  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4516 
4517  /* create polynomial */
4518  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4519 
4520  expr->op = SCIP_EXPR_POLYNOMIAL;
4521  expr->data.data = (void*)polynomialdata;
4522 
4523  /* forget child */
4524  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4525  BMSfreeBlockMemoryArray(blkmem, &expr->children, 1);
4526  expr->nchildren = 0;
4527  }
4528 
4529  break;
4530  }
4531 
4532  case SCIP_EXPR_MIN:
4533  case SCIP_EXPR_MAX:
4534  {
4535  /* check if both arguments are constants */
4536  if( ((expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) || expr->children[0]->op == SCIP_EXPR_CONST) &&
4537  ((expr->children[1]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[1]) == 0) || expr->children[1]->op == SCIP_EXPR_CONST) )
4538  {
4539  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4540  SCIP_Real exprval;
4541 
4542  /* since children have no children and it's polynomial was flattened, it should have no monomials */
4543  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4544  assert(expr->children[1]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[1]) == 0);
4545 
4546  /* evaluate expression in constants */
4547  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4548 
4549  /* create polynomial */
4550  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4551 
4552  expr->op = SCIP_EXPR_POLYNOMIAL;
4553  expr->data.data = (void*)polynomialdata;
4554 
4555  /* forget children */
4556  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4557  SCIPexprFreeDeep(blkmem, &expr->children[1]);
4558  BMSfreeBlockMemoryArray(blkmem, &expr->children, 2);
4559  expr->nchildren = 0;
4560  }
4561 
4562  break;
4563  }
4564 
4565  case SCIP_EXPR_SUM:
4566  case SCIP_EXPR_PRODUCT:
4567  case SCIP_EXPR_LINEAR:
4568  case SCIP_EXPR_QUADRATIC:
4569  case SCIP_EXPR_USER:
4570  break;
4571 
4572  case SCIP_EXPR_POLYNOMIAL:
4573  {
4574  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4575  SCIP_EXPRDATA_MONOMIAL* monomial;
4576  SCIP_Bool removechild;
4577  int* childmap;
4578  int childmapsize;
4579  int j;
4580 
4581  /* simplify current polynomial */
4583  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4584 
4585  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4586  assert(polynomialdata != NULL);
4587 
4588  SCIPdebugMessage("expand factors in expression ");
4589  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4590  SCIPdebugPrintf("\n");
4591 
4592  childmap = NULL;
4593  childmapsize = 0;
4594 
4595  /* resolve children that are constants
4596  * we do this first, because it reduces the degree and number of factors in the monomials,
4597  * 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
4598  */
4599  for( i = 0; i < expr->nchildren; ++i )
4600  {
4601  if( expr->children[i] == NULL )
4602  continue;
4603 
4604  if( SCIPexprGetOperator(expr->children[i]) != SCIP_EXPR_CONST )
4605  continue;
4606 
4607  removechild = TRUE; /* we intend to delete children[i] */
4608 
4609  if( childmapsize < expr->children[i]->nchildren )
4610  {
4611  int newsize;
4612 
4613  newsize = calcGrowSize(expr->children[i]->nchildren);
4614  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4615  childmapsize = newsize;
4616  }
4617 
4618  /* put constant of child i into every monomial where child i is used */
4619  for( j = 0; j < polynomialdata->nmonomials; ++j )
4620  {
4621  int factorpos;
4622  SCIP_Bool success;
4623 
4624  monomial = polynomialdata->monomials[j];
4625  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4626  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4627 
4628  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4629  {
4630  assert(factorpos >= 0);
4631  assert(factorpos < monomial->nfactors);
4632  /* assert that factors have been merged */
4633  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4634  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4635 
4636  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4637  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4638  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4639 
4640  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && SCIPexprGetOpReal(expr->children[i]) < 0.0 ) /*lint !e835*/
4641  {
4642  /* if constant is negative and our exponent is not integer, then cannot do expansion */
4643  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n",
4644  SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4645  success = FALSE;
4646  }
4647  else
4648  {
4649  monomial->coef *= pow(SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4650 
4651  /* move last factor to position factorpos */
4652  if( factorpos < monomial->nfactors-1 )
4653  {
4654  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
4655  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
4656  }
4657  --monomial->nfactors;
4658  monomial->sorted = FALSE;
4659  polynomialdata->sorted = FALSE;
4660 
4661  success = TRUE;
4662  }
4663 
4664  if( !success )
4665  removechild = FALSE;
4666  }
4667  }
4668 
4669  /* forget about child i, if it is not used anymore */
4670  if( removechild )
4671  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4672 
4673  /* simplify current polynomial again */
4674  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4675  }
4676 
4677  /* try to resolve children that are polynomials itself */
4678  for( i = 0; i < expr->nchildren; ++i )
4679  {
4680  if( expr->children[i] == NULL )
4681  continue;
4682 
4684  continue;
4685 
4686  removechild = TRUE; /* we intend to delete children[i] */
4687 
4688  if( childmapsize < expr->children[i]->nchildren )
4689  {
4690  int newsize;
4691 
4692  newsize = calcGrowSize(expr->children[i]->nchildren);
4693  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4694  childmapsize = newsize;
4695  }
4696 
4697  /* add children of child i */
4698  SCIP_CALL( exprsimplifyAddChildren(blkmem, expr, expr->children[i]->nchildren, expr->children[i]->children, TRUE, eps, childmap) );
4699 
4700  /* put polynomial of child i into every monomial where child i is used */
4701  j = 0;
4702  while( j < polynomialdata->nmonomials )
4703  {
4704  int factorpos;
4705  SCIP_Bool success;
4706 
4707  monomial = polynomialdata->monomials[j];
4708  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4709  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4710 
4711  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4712  {
4713  assert(factorpos >= 0);
4714  assert(factorpos < monomial->nfactors);
4715  /* assert that factors have been merged */
4716  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4717  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4718 
4719  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4720  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4721  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4722 
4723  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
4724  (SCIP_EXPRDATA_POLYNOMIAL*)expr->children[i]->data.data, childmap, maxexpansionexponent, &success) );
4725 
4726  if( !success )
4727  {
4728  removechild = FALSE;
4729  ++j;
4730  }
4731  }
4732  else
4733  ++j;
4734 
4735  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
4736  * we thus repeat with index j, if a factor was successfully expanded
4737  */
4738  }
4739 
4740  /* forget about child i, if it is not used anymore */
4741  if( removechild )
4742  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4743 
4744  /* simplify current polynomial again */
4745  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4746  }
4747 
4748  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
4749 
4750  /* free children that are not in use anymore */
4752 
4753  /* remove NULLs from children array */
4755 
4756  /* if no children left, then it's a constant polynomial -> change into EXPR_CONST */
4757  if( expr->nchildren == 0 )
4758  {
4759  SCIP_Real val;
4760 
4761  /* if no children, then it should also have no monomials */
4762  assert(polynomialdata->nmonomials == 0);
4763 
4764  val = polynomialdata->constant;
4765  polynomialdataFree(blkmem, &polynomialdata);
4766 
4767  expr->op = SCIP_EXPR_CONST;
4768  expr->data.dbl = val;
4769  }
4770 
4771  SCIPdebugMessage("-> ");
4772  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4773  SCIPdebugPrintf("\n");
4774 
4775  break;
4776  }
4777 
4778  case SCIP_EXPR_LAST:
4779  break;
4780  } /*lint !e788*/
4781 
4782  return SCIP_OKAY;
4783 }
4784 
4785 /** separates linear monomials from an expression, if it is a polynomial expression
4786  *
4787  * Separates only those linear terms whose variable is not used otherwise in the expression.
4788  */
4789 static
4791  BMS_BLKMEM* blkmem, /**< block memory data structure */
4792  SCIP_EXPR* expr, /**< expression */
4793  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
4794  int nvars, /**< number of variables in expression */
4795  int* nlinvars, /**< buffer to store number of linear variables in linear part */
4796  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part */
4797  SCIP_Real* lincoefs /**< array to store coefficients of linear part */
4798  )
4799 {
4800  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4801  SCIP_EXPRDATA_MONOMIAL* monomial;
4802  int* varsusage;
4803  int* childusage;
4804  int childidx;
4805  int i;
4806  int j;
4807 
4808  assert(blkmem != NULL);
4809  assert(expr != NULL);
4810  assert(nlinvars != NULL);
4811  assert(linidxs != NULL);
4812  assert(lincoefs != NULL);
4813 
4814  *nlinvars = 0;
4815 
4817  return SCIP_OKAY;
4818 
4819  if( SCIPexprGetNChildren(expr) == 0 )
4820  return SCIP_OKAY;
4821 
4822  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4823  assert(polynomialdata != NULL);
4824 
4825  /* get variable usage */
4826  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &varsusage, nvars) );
4827  BMSclearMemoryArray(varsusage, nvars); /*lint !e644*/
4828  SCIPexprGetVarsUsage(expr, varsusage);
4829 
4830  /* get child usage: how often each child is used in the polynomial */
4831  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childusage, expr->nchildren) );
4832  BMSclearMemoryArray(childusage, expr->nchildren); /*lint !e644*/
4833  for( i = 0; i < polynomialdata->nmonomials; ++i )
4834  {
4835  monomial = polynomialdata->monomials[i];
4836  assert(monomial != NULL);
4837  for( j = 0; j < monomial->nfactors; ++j )
4838  {
4839  assert(monomial->childidxs[j] >= 0);
4840  assert(monomial->childidxs[j] < expr->nchildren);
4841  ++childusage[monomial->childidxs[j]];
4842  }
4843  }
4844 
4845  /* move linear monomials out of polynomial */
4846  for( i = 0; i < polynomialdata->nmonomials; ++i )
4847  {
4848  monomial = polynomialdata->monomials[i];
4849  assert(monomial != NULL);
4850  if( monomial->nfactors != 1 )
4851  continue;
4852  if( monomial->exponents[0] != 1.0 )
4853  continue;
4854  childidx = monomial->childidxs[0];
4855  if( SCIPexprGetOperator(expr->children[childidx]) != SCIP_EXPR_VARIDX )
4856  continue;
4857 
4858  /* we are at a linear monomial in a variable */
4859  assert(SCIPexprGetOpIndex(expr->children[childidx]) < nvars);
4860  if( childusage[childidx] == 1 && varsusage[SCIPexprGetOpIndex(expr->children[childidx])] == 1 )
4861  {
4862  /* if the child expression is not used in another monomial (which would due to merging be not linear)
4863  * and if the variable is not used somewhere else in the tree,
4864  * then move this monomial into linear part and free child
4865  */
4866  linidxs[*nlinvars] = SCIPexprGetOpIndex(expr->children[childidx]);
4867  lincoefs[*nlinvars] = monomial->coef;
4868  ++*nlinvars;
4869 
4870  SCIPexprFreeDeep(blkmem, &expr->children[childidx]);
4871  monomial->coef = 0.0;
4872  monomial->nfactors = 0;
4873  }
4874  }
4875 
4876  BMSfreeBlockMemoryArray(blkmem, &varsusage, nvars);
4877  BMSfreeBlockMemoryArray(blkmem, &childusage, expr->nchildren);
4878 
4879  if( *nlinvars > 0 )
4880  {
4881  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
4882  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, FALSE);
4884  }
4885 
4886  return SCIP_OKAY;
4887 }
4888 
4889 /** converts polynomial expressions back into simpler expressions, where possible */
4890 static
4892  BMS_BLKMEM* blkmem, /**< block memory data structure */
4893  SCIP_EXPR* expr /**< expression to convert back */
4894  )
4895 {
4896  int i;
4897 
4898  assert(blkmem != NULL);
4899  assert(expr != NULL);
4900 
4901  for( i = 0; i < expr->nchildren; ++i )
4902  {
4904  }
4905 
4906  if( expr->op != SCIP_EXPR_POLYNOMIAL )
4907  return SCIP_OKAY;
4908 
4909  SCIP_CALL( exprUnconvertPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren, (void**)expr->children) );
4910 
4911  return SCIP_OKAY;
4912 }
4913 
4914 static
4915 SCIP_DECL_HASHGETKEY( exprparseVarTableGetKey )
4916 { /*lint --e{715}*/
4917  return (void*)((char*)elem + sizeof(int));
4918 }
4919 
4920 /** parses a variable name from a string and creates corresponding expression
4921  *
4922  * Creates a new variable index if variable not seen before, updates varnames and vartable structures.
4923  */
4924 static
4926  BMS_BLKMEM* blkmem, /**< block memory data structure */
4927  const char** str, /**< pointer to the string to be parsed */
4928  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
4929  int* nvars, /**< running number of encountered variables so far */
4930  int** varnames, /**< pointer to buffer to store new variable names */
4931  int* varnameslength, /**< pointer to length of the varnames buffer array */
4932  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
4933  SCIP_Real coefficient, /**< coefficient to be used when creating the expression */
4934  const char* varnameendptr /**< if a <varname> should be parsed, set this to NULL. Then, str points to the '<'
4935  else, str should point to the first letter of the varname, and varnameendptr should
4936  point one char behind the last char of the variable name */
4937  )
4938 {
4939  int namelength;
4940  int varidx;
4941  char varname[SCIP_MAXSTRLEN];
4942  void* element;
4943 
4944  assert(blkmem != NULL);
4945  assert(str != NULL);
4946  assert(expr != NULL);
4947  assert(nvars != NULL);
4948  assert(varnames != NULL);
4949  assert(vartable != NULL);
4950 
4951  if( varnameendptr == NULL )
4952  {
4953  ++*str;
4954  varnameendptr = *str;
4955  while( varnameendptr[0] != '>' )
4956  ++varnameendptr;
4957  }
4958 
4959  namelength = varnameendptr - *str; /*lint !e712*/
4960  if( namelength >= SCIP_MAXSTRLEN )
4961  {
4962  SCIPerrorMessage("Variable name %.*s is too long for buffer in exprparseReadVariable.\n", namelength, str);
4963  return SCIP_READERROR;
4964  }
4965 
4966  memcpy(varname, *str, namelength * sizeof(char));
4967  varname[namelength] = '\0';
4968 
4969  element = SCIPhashtableRetrieve(vartable, varname);
4970  if( element != NULL )
4971  {
4972  /* variable is old friend */
4973  assert(strcmp((char*)element + sizeof(int), varname) == 0);
4974 
4975  varidx = *(int*)element;
4976  }
4977  else
4978  {
4979  /* variable is new */
4980  varidx = *nvars;
4981 
4982  (*varnameslength) -= (int)(1 + (strlen(varname) + 1) / sizeof(int) + 1);
4983  if( *varnameslength < 0 )
4984  {
4985  SCIPerrorMessage("Buffer in exprparseReadVariable is too short for varaible name %.*s.\n", namelength, str);
4986  return SCIP_READERROR;
4987  }
4988 
4989  /* store index of variable and variable name in varnames buffer */
4990  **varnames = varidx;
4991  (void) SCIPstrncpy((char*)(*varnames + 1), varname, (int)strlen(varname)+1);
4992 
4993  /* insert variable into hashtable */
4994  SCIP_CALL( SCIPhashtableInsert(vartable, (void*)*varnames) );
4995 
4996  ++*nvars;
4997  *varnames += 1 + (strlen(varname) + 1) / sizeof(int) + 1;
4998  }
4999 
5000  /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
5001  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_VARIDX, varidx) ); /*lint !e613*/
5002  if( coefficient != 1.0 )
5003  {
5004  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, expr, &coefficient, 0.0) );
5005  }
5006 
5007  /* Move pointer to char behind end of variable */
5008  *str = varnameendptr + 1;
5009 
5010  /* consprint sometimes prints a variable type identifier which we don't need */
5011  if( (*str)[0] == '[' && (*str)[2] == ']' &&
5012  ((*str)[1] == SCIP_VARTYPE_BINARY_CHAR ||
5013  (*str)[1] == SCIP_VARTYPE_INTEGER_CHAR ||
5014  (*str)[1] == SCIP_VARTYPE_IMPLINT_CHAR ||
5015  (*str)[1] == SCIP_VARTYPE_CONTINUOUS_CHAR ) )
5016  *str += 3;
5017 
5018  return SCIP_OKAY;
5019 }
5020 
5021 /** if str[0] points to an opening parenthesis, this function sets endptr to point to the matching closing bracket in str
5022  *
5023  * Searches for at most length characters.
5024  */
5025 static
5027  const char* str, /**< pointer to the string to be parsed */
5028  const char** endptr, /**< pointer to point to the closing parenthesis */
5029  int length /**< length of the string to be parsed */
5030  )
5031 {
5032  int nopenbrackets;
5033 
5034  assert(str[0] == '(');
5035 
5036  *endptr = str;
5037 
5038  /* find the end of this expression */
5039  nopenbrackets = 0;
5040  while( (*endptr - str ) < length && !(nopenbrackets == 1 && *endptr[0] == ')') )
5041  {
5042  if( *endptr[0] == '(')
5043  ++nopenbrackets;
5044  if( *endptr[0] == ')')
5045  --nopenbrackets;
5046  ++*endptr;
5047  }
5048 
5049  if( *endptr[0] != ')' )
5050  {
5051  SCIPerrorMessage("unable to find closing parenthesis in unbalanced expression %.*s\n", length, str);
5052  return SCIP_READERROR;
5053  }
5054 
5055  return SCIP_OKAY;
5056 }
5057 
5058 /** this function sets endptr to point to the next separating comma in str
5059  *
5060  * That is, for a given string like "x+f(x,y),z", endptr will point to the comma before "z"
5061  *
5062  * Searches for at most length characters.
5063  */
5064 static
5066  const char* str, /**< pointer to the string to be parsed */
5067  const char** endptr, /**< pointer to point to the comma */
5068  int length /**< length of the string to be parsed */
5069  )
5070 {
5071  int nopenbrackets;
5072 
5073  *endptr = str;
5074 
5075  /* find a comma without open brackets */
5076  nopenbrackets = 0;
5077  while( (*endptr - str ) < length && !(nopenbrackets == 0 && *endptr[0] == ',') )
5078  {
5079  if( *endptr[0] == '(')
5080  ++nopenbrackets;
5081  if( *endptr[0] == ')')
5082  --nopenbrackets;
5083  ++*endptr;
5084  }
5085 
5086  if( *endptr[0] != ',' )
5087  {
5088  SCIPerrorMessage("unable to find separating comma in unbalanced expression %.*s\n", length, str);
5089  return SCIP_READERROR;
5090  }
5091 
5092  return SCIP_OKAY;
5093 }
5094 
5095 /** parses an expression from a string */
5096 static
5098  BMS_BLKMEM* blkmem, /**< block memory data structure */
5099  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
5100  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
5101  const char* str, /**< pointer to the string to be parsed */
5102  int length, /**< length of the string to be parsed */
5103  const char* lastchar, /**< pointer to the last char of str that should be parsed */
5104  int* nvars, /**< running number of encountered variables so far */
5105  int** varnames, /**< pointer to buffer to store new variable names */
5106  int* varnameslength, /**< pointer to length of the varnames buffer array */
5107  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
5108  int recursiondepth /**< current recursion depth */
5109  )
5110 { /*lint --e{712,747}*/
5111  SCIP_EXPR* arg1;
5112  SCIP_EXPR* arg2;
5113  const char* subexpptr;
5114  const char* subexpendptr;
5115  const char* strstart;
5116  const char* endptr;
5117  char* nonconstendptr;
5118  SCIP_Real number;
5119  int subexplength;
5120  int nopenbrackets;
5121 
5122  assert(blkmem != NULL);
5123  assert(expr != NULL);
5124  assert(str != NULL);
5125  assert(lastchar >= str);
5126  assert(nvars != NULL);
5127  assert(varnames != NULL);
5128  assert(vartable != NULL);
5129 
5130  assert(recursiondepth < 100);
5131 
5132  strstart = str; /* might be needed for error message... */
5133 
5134  SCIPdebugMessage("exprParse (%i): parsing %.*s\n", recursiondepth, (int) (lastchar-str + 1), str);
5135 
5136  /* ignore whitespace */
5137  while( isspace((unsigned char)*str) )
5138  ++str;
5139 
5140  /* look for a sum or difference not contained in brackets */
5141  subexpptr = str;
5142  nopenbrackets = 0;
5143 
5144  /* find the end of this expression
5145  * a '+' right at the beginning indicates a coefficient, not treated here, or a summation
5146  */
5147  while( subexpptr != lastchar && !(nopenbrackets == 0 && (subexpptr[0] == '+' || subexpptr[0] == '-') && subexpptr != str) )
5148  {
5149  if( subexpptr[0] == '(')
5150  ++nopenbrackets;
5151  if( subexpptr[0] == ')')
5152  --nopenbrackets;
5153  ++subexpptr;
5154  }
5155 
5156  if( subexpptr != lastchar )
5157  {
5158  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str, (int) ((subexpptr - 1) - str + 1), subexpptr - 1, nvars,
5159  varnames, varnameslength, vartable, recursiondepth + 1) );
5160 
5161  if( subexpptr[0] == '+' )
5162  ++subexpptr;
5163  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, subexpptr , (int) (lastchar - (subexpptr ) + 1), lastchar, nvars,
5164  varnames, varnameslength, vartable, recursiondepth + 1) );
5165 
5166  /* make new expression from two arguments
5167  * we always use add, because we leave the operator between the found expressions in the second argument
5168  * this way, we do not have to worry about ''minus brackets'' in the case of more then two summands:
5169  * a - b - c = a + (-b -c)
5170  */
5171  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5172 
5173  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5174  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5175  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5176 
5177  return SCIP_OKAY;
5178  }
5179 
5180  /* check for a bracketed subexpression */
5181  if( str[0] == '(' )
5182  {
5183  nopenbrackets = 0;
5184 
5185  subexplength = -1; /* we do not want the closing bracket in the string */
5186  subexpptr = str + 1; /* leave out opening bracket */
5187 
5188  /* find the end of this expression */
5189  while( subexplength < length && !(nopenbrackets == 1 && str[0] == ')') )
5190  {
5191  if( str[0] == '(' )
5192  ++nopenbrackets;
5193  if( str[0] == ')' )
5194  --nopenbrackets;
5195  ++str;
5196  ++subexplength;
5197  }
5198  subexpendptr = str - 1; /* leave out closing bracket */
5199 
5200  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, subexpptr, subexplength, subexpendptr, nvars, varnames,
5201  varnameslength, vartable, recursiondepth + 1) );
5202  ++str;
5203  }
5204  else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+')
5205  && (isdigit((unsigned char)str[1]) || str[1] == ' ')) )
5206  {
5207  /* check if there is a lonely minus coming, indicating a -1.0 */
5208  if( str[0] == '-' && str[1] == ' ' )
5209  {
5210  number = -1.0;
5211  nonconstendptr = (char*) str + 1;
5212  }
5213  /* check if there is a number coming */
5214  else if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5215  {
5216  SCIPerrorMessage("error parsing number from <%s>\n", str);
5217  return SCIP_READERROR;
5218  }
5219  str = nonconstendptr;
5220 
5221  /* ignore whitespace */
5222  while( isspace((unsigned char)*str) && str != lastchar )
5223  ++str;
5224 
5225  if( str[0] != '*' && str[0] != '/' && str[0] != '+' && str[0] != '-' && str[0] != '^' )
5226  {
5227  if( str < lastchar )
5228  {
5229  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, str, (int)(lastchar - str) + 1, lastchar, nvars, varnames,
5230  varnameslength, vartable, recursiondepth + 1) );
5231  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, *expr, number) );
5232  }
5233  else
5234  {
5235  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5236  }
5237  str = lastchar + 1;
5238  }
5239  else
5240  {
5241  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5242  }
5243  }
5244  else if( str[0] == '<' )
5245  {
5246  /* check if expressions begins with a variable */
5247  SCIP_CALL( exprparseReadVariable(blkmem, &str, expr, nvars, varnames, varnameslength, vartable, 1.0, NULL) );
5248  }
5249  /* four character operators */
5250  else if( strncmp(str, "sqrt", 4) == 0 )
5251  {
5252  str += 4;
5253  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5254  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5255  varnameslength, vartable, recursiondepth + 1) );
5256  str = endptr + 1;
5257 
5258  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQRT, arg1) );
5259  }
5260  /* three character operators with 1 argument */
5261  else if(
5262  strncmp(str, "abs", 3) == 0 ||
5263  strncmp(str, "cos", 3) == 0 ||
5264  strncmp(str, "exp", 3) == 0 ||
5265  strncmp(str, "log", 3) == 0 ||
5266  strncmp(str, "sin", 3) == 0 ||
5267  strncmp(str, "sqr", 3) == 0 ||
5268  strncmp(str, "tan", 3) == 0 )
5269  {
5270  const char* opname = str;
5271 
5272  str += 3;
5273  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5274  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5275  varnameslength, vartable, recursiondepth + 1) );
5276  str = endptr + 1;
5277 
5278  if( strncmp(opname, "abs", 3) == 0 )
5279  {
5280  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_ABS, arg1) );
5281  }
5282  else if( strncmp(opname, "cos", 3) == 0 )
5283  {
5284  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_COS, arg1) );
5285  }
5286  else if( strncmp(opname, "exp", 3) == 0 )
5287  {
5288  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, arg1) );
5289  }
5290  else if( strncmp(opname, "log", 3) == 0 )
5291  {
5292  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5293  }
5294  else if( strncmp(opname, "sin", 3) == 0 )
5295  {
5296  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIN, arg1) );
5297  }
5298  else if( strncmp(opname, "sqr", 3) == 0 )
5299  {
5300  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQUARE, arg1) );
5301  }
5302  else
5303  {
5304  assert(strncmp(opname, "tan", 3) == 0);
5305  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_TAN, arg1) );
5306  }
5307  }
5308  /* three character operators with 2 arguments */
5309  else if(
5310  strncmp(str, "max", 3) == 0 ||
5311  strncmp(str, "min", 3) == 0 )
5312  {
5313  /* we have a string of the form "min(...,...)" or "max(...,...)"
5314  * first find the closing parenthesis, then the comma
5315  */
5316  const char* comma;
5317  SCIP_EXPROP op;
5318 
5319  op = (str[1] == 'a' ? SCIP_EXPR_MAX : SCIP_EXPR_MIN);
5320 
5321  str += 3;
5322  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5323 
5324  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5325 
5326  /* parse first argument [str+1..comma-1] */
5327  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5328  varnameslength, vartable, recursiondepth + 1) );
5329 
5330  /* parse second argument [comma+1..endptr] */
5331  ++comma;
5332  while( comma < endptr && *comma == ' ' )
5333  ++comma;
5334 
5335  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, comma, endptr - comma, endptr - 1, nvars, varnames,
5336  varnameslength, vartable, recursiondepth + 1) );
5337 
5338  SCIP_CALL( SCIPexprCreate(blkmem, expr, op, arg1, arg2) );
5339 
5340  str = endptr + 1;
5341  }
5342  else if( strncmp(str, "power", 5) == 0 )
5343  {
5344  /* we have a string of the form "power(...,integer)" (thus, intpower)
5345  * first find the closing parenthesis, then the comma
5346  */
5347  const char* comma;
5348  int exponent;
5349 
5350  str += 5;
5351  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5352 
5353  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5354 
5355  /* parse first argument [str+1..comma-1] */
5356  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5357  varnameslength, vartable, recursiondepth + 1) );
5358 
5359  ++comma;
5360  /* parse second argument [comma, endptr-1]: it needs to be an integer */
5361  while( comma < endptr && *comma == ' ' )
5362  ++comma;
5363  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5364  {
5365  SCIPerrorMessage("error parsing integer exponent from <%s>\n", comma);
5366  }
5367  if( !SCIPstrToIntValue(comma, &exponent, &nonconstendptr) )
5368  {
5369  SCIPerrorMessage("error parsing integer from <%s>\n", comma);
5370  return SCIP_READERROR;
5371  }
5372 
5373  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, exponent) );
5374 
5375  str = endptr + 1;
5376  }
5377  else if( strncmp(str, "realpower", 9) == 0 || strncmp(str, "signpower", 9) == 0 )
5378  {
5379  /* we have a string of the form "realpower(...,double)" or "signpower(...,double)"
5380  * first find the closing parenthesis, then the comma
5381  */
5382  const char* opname = str;
5383  const char* comma;
5384 
5385  str += 9;
5386  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5387 
5388  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5389 
5390  /* parse first argument [str+1..comma-1] */
5391  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5392  varnameslength, vartable, recursiondepth + 1) );
5393 
5394  ++comma;
5395  /* parse second argument [comma, endptr-1]: it needs to be an number */
5396  while( comma < endptr && *comma == ' ' )
5397  ++comma;
5398  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5399  {
5400  SCIPerrorMessage("error parsing number exponent from <%s>\n", comma);
5401  }
5402  if( !SCIPstrToRealValue(comma, &number, &nonconstendptr) )
5403  {
5404  SCIPerrorMessage("error parsing number from <%s>\n", comma);
5405  return SCIP_READERROR;
5406  }
5407 
5408  if( strncmp(opname, "realpower", 9) == 0 )
5409  {
5410  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, number) );
5411  }
5412  else
5413  {
5414  assert(strncmp(opname, "signpower", 9) == 0);
5415  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIGNPOWER, arg1, number) );
5416  }
5417 
5418  str = endptr + 1;
5419  }
5420  else if( isalpha(*str) || *str == '_' || *str == '#' )
5421  {
5422  /* check for a variable, that was not recognized earlier because somebody omitted the '<' and '>' we need for
5423  * SCIPparseVarName, making everyones life harder;
5424  * we allow only variable names starting with a character or underscore here
5425  */
5426  const char* varnamestartptr = str;
5427 
5428  /* allow only variable names containing characters, digits, hash marks, and underscores here */
5429  while( isalnum(str[0]) || str[0] == '_' || str[0] == '#' )
5430  ++str;
5431 
5432  SCIP_CALL( exprparseReadVariable(blkmem, &varnamestartptr, expr, nvars, varnames, varnameslength,
5433  vartable, 1.0, str) );
5434  }
5435  else
5436  {
5437  SCIPerrorMessage("parsing of invalid expression %.*s.\n", (int) (lastchar - str + 1), str);
5438  return SCIP_READERROR;
5439  }
5440 
5441  /* if we are one char behind lastchar, we are done */
5442  if( str == lastchar + 1)
5443  {
5444  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5445  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5446  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5447 
5448  return SCIP_OKAY;
5449  }
5450 
5451  /* check if we are still in bounds */
5452  if( str > lastchar + 1)
5453  {
5454  SCIPerrorMessage("error finding first expression in \"%.*s\" took us outside of given subexpression length\n", length, strstart);
5455  return SCIP_READERROR;
5456  }
5457 
5458  /* ignore whitespace */
5459  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5460  ++str;
5461 
5462  /* maybe now we're done? */
5463  if( str >= lastchar + 1)
5464  {
5465  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5466  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5467  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5468 
5469  return SCIP_OKAY;
5470  }
5471 
5472  if( str[0] == '^' )
5473  {
5474  /* a '^' behind the found expression indicates a power */
5475  SCIP_Real constant;
5476 
5477  arg1 = *expr;
5478  ++str;
5479  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5480  ++str;
5481 
5482  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5483  {
5484  /* there is a number coming */
5485  if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5486  {
5487  SCIPerrorMessage("error parsing number from <%s>\n", str);
5488  return SCIP_READERROR;
5489  }
5490 
5491  SCIP_CALL( SCIPexprCreate(blkmem, &arg2, SCIP_EXPR_CONST, number) );
5492  str = nonconstendptr;
5493 
5494  constant = SCIPexprGetOpReal(arg2);
5495  SCIPexprFreeDeep(blkmem, &arg2);
5496 
5497  /* expr^number is intpower or realpower */
5498  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5499  {
5500  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5501  }
5502  else
5503  {
5504  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5505  }
5506  }
5507  else if( str[0] == '(' )
5508  {
5509  /* we use exprParse to evaluate the exponent */
5510 
5511  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5512  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5513  varnameslength, vartable, recursiondepth + 1) );
5514 
5515  if( SCIPexprGetOperator(arg2) != SCIP_EXPR_CONST )
5516  {
5517  /* reformulate arg1^arg2 as exp(arg2 * log(arg1)) */
5518  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5519  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, *expr, arg2) );
5520  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, *expr) );
5521  }
5522  else
5523  {
5524  /* expr^number is intpower or realpower */
5525  constant = SCIPexprGetOpReal(arg2);
5526  SCIPexprFreeDeep(blkmem, &arg2);
5527  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5528  {
5529  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5530  }
5531  else
5532  {
5533  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5534  }
5535  }
5536  str = endptr + 1;
5537  }
5538  else
5539  {
5540  SCIPerrorMessage("unexpected string following ^ in %.*s\n", length, str);
5541  return SCIP_READERROR;
5542  }
5543 
5544  /* ignore whitespace */
5545  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5546  ++str;
5547  }
5548 
5549  /* check for a two argument operator that is not a multiplication */
5550  if( str <= lastchar && (str[0] == '+' || str[0] == '-' || str[0] == '/') )
5551  {
5552  char op;
5553 
5554  op = str[0];
5555  arg1 = *expr;
5556 
5557  /* step forward over the operator to go to the beginning of the second argument */
5558  ++str;
5559 
5560  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5561  varnameslength, vartable, recursiondepth + 1) );
5562  str = lastchar + 1;
5563 
5564  /* make new expression from two arguments */
5565  if( op == '+')
5566  {
5567  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5568  }
5569  else if( op == '-')
5570  {
5571  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, -1.0, arg2, 0.0) );
5572  }
5573  else if( op == '*' )
5574  {
5575  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5576  {
5577  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5578  }
5579  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5580  {
5581  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5582  }
5583  else
5584  {
5585  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5586  }
5587  }
5588  else
5589  {
5590  assert(op == '/');
5591 
5592  if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5593  {
5594  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, 1.0 / SCIPexprGetOpReal(arg2)) );
5595  SCIPexprFreeShallow(blkmem, &arg2);
5596  }
5597  else
5598  {
5599  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_DIV, arg1, arg2) );
5600  }
5601  }
5602  }
5603 
5604  /* ignore whitespace */
5605  while( isspace((unsigned char)*str) )
5606  ++str;
5607 
5608  /* we are either done or we have a multiplication? */
5609  if( str >= lastchar + 1 )
5610  {
5611  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5612  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5613  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5614 
5615  return SCIP_OKAY;
5616  }
5617 
5618  /* if there is a part of the string left to be parsed, we assume that this as a multiplication */
5619  arg1 = *expr;
5620 
5621  /* stepping over multiplication operator if needed */
5622  if( str[0] == '*' )
5623  {
5624  ++str;
5625  }
5626  else if( str[0] != '(' )
5627  {
5628  SCIPdebugMessage("No operator found, assuming a multiplication before %.*s\n", (int) (lastchar - str + 1), str);
5629  }
5630 
5631  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5632  varnameslength, vartable, recursiondepth + 1) );
5633 
5634  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5635  {
5636  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5637  SCIPexprFreeDeep(blkmem, &arg1);
5638  }
5639  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5640  {
5641  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5642  SCIPexprFreeDeep(blkmem, &arg2);
5643  }
5644  else
5645  {
5646  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5647  }
5648 
5649  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5650  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5651  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5652 
5653  return SCIP_OKAY;
5654 }
5655 
5656 /**@} */
5657 
5658 /**@name Expression methods */
5659 /**@{ */
5660 
5661 /* In debug mode, the following methods are implemented as function calls to ensure
5662  * type validity.
5663  * In optimized mode, the methods are implemented as defines to improve performance.
5664  * However, we want to have them in the library anyways, so we have to undef the defines.
5665  */
5666 
5667 #undef SCIPexprGetOperator
5668 #undef SCIPexprGetNChildren
5669 #undef SCIPexprGetChildren
5670 #undef SCIPexprGetOpIndex
5671 #undef SCIPexprGetOpReal
5672 #undef SCIPexprGetOpData
5673 #undef SCIPexprGetRealPowerExponent
5674 #undef SCIPexprGetIntPowerExponent
5675 #undef SCIPexprGetSignPowerExponent
5676 #undef SCIPexprGetLinearCoefs
5677 #undef SCIPexprGetLinearConstant
5678 #undef SCIPexprGetQuadElements
5679 #undef SCIPexprGetQuadConstant
5680 #undef SCIPexprGetQuadLinearCoefs
5681 #undef SCIPexprGetNQuadElements
5682 #undef SCIPexprGetMonomials
5683 #undef SCIPexprGetNMonomials
5684 #undef SCIPexprGetPolynomialConstant
5685 #undef SCIPexprGetMonomialCoef
5686 #undef SCIPexprGetMonomialNFactors
5687 #undef SCIPexprGetMonomialChildIndices
5688 #undef SCIPexprGetMonomialExponents
5689 #undef SCIPexprGetUserData
5690 #undef SCIPexprHasUserEstimator
5691 #undef SCIPexprGetUserEvalCapability
5692 
5693 /** gives operator of expression */
5695  SCIP_EXPR* expr /**< expression */
5696  )
5697 {
5698  assert(expr != NULL);
5699 
5700  return expr->op;
5701 }
5702 
5703 /** gives number of children of an expression */
5705  SCIP_EXPR* expr /**< expression */
5706  )
5707 {
5708  assert(expr != NULL);
5709 
5710  return expr->nchildren;
5711 }
5712 
5713 /** gives pointer to array with children of an expression */
5715  SCIP_EXPR* expr /**< expression */
5716  )
5717 {
5718  assert(expr != NULL);
5719 
5720  return expr->children;
5721 }
5722 
5723 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
5725  SCIP_EXPR* expr /**< expression */
5726  )
5727 {
5728  assert(expr != NULL);
5729  assert(expr->op == SCIP_EXPR_VARIDX || expr->op == SCIP_EXPR_PARAM);
5730 
5731  return expr->data.intval;
5732 }
5733 
5734 /** gives real belonging to a SCIP_EXPR_CONST operand */
5736  SCIP_EXPR* expr /**< expression */
5737  )
5738 {
5739  assert(expr != NULL);
5740  assert(expr->op == SCIP_EXPR_CONST);
5741 
5742  return expr->data.dbl;
5743 }
5744 
5745 /** gives void* belonging to a complex operand */
5747  SCIP_EXPR* expr /**< expression */
5748  )
5749 {
5750  assert(expr != NULL);
5751  assert(expr->op >= SCIP_EXPR_SUM); /* only complex operands store their data as void* */
5752 
5753  return expr->data.data;
5754 }
5755 
5756 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
5758  SCIP_EXPR* expr /**< expression */
5759  )
5760 {
5761  assert(expr != NULL);
5762  assert(expr->op == SCIP_EXPR_REALPOWER);
5763 
5764  return expr->data.dbl;
5765 }
5766 
5767 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
5769  SCIP_EXPR* expr /**< expression */
5770  )
5771 {
5772  assert(expr != NULL);
5773  assert(expr->op == SCIP_EXPR_INTPOWER);
5774 
5775  return expr->data.intval;
5776 }
5777 
5778 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
5780  SCIP_EXPR* expr /**< expression */
5781  )
5782 {
5783  assert(expr != NULL);
5784  assert(expr->op == SCIP_EXPR_SIGNPOWER);
5785 
5786  return expr->data.dbl;
5787 }
5788 
5789 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
5791  SCIP_EXPR* expr /**< expression */
5792  )
5793 {
5794  assert(expr != NULL);
5795  assert(expr->op == SCIP_EXPR_LINEAR);
5796  assert(expr->data.data != NULL);
5797 
5798  /* the coefficients are stored in the first nchildren elements of the array stored as expression data */
5799  return (SCIP_Real*)expr->data.data;
5800 }
5801 
5802 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
5804  SCIP_EXPR* expr /**< expression */
5805  )
5806 {
5807  assert(expr != NULL);
5808  assert(expr->op == SCIP_EXPR_LINEAR);
5809  assert(expr->data.data != NULL);
5810 
5811  /* the constant is stored in the nchildren's element of the array stored as expression data */
5812  return ((SCIP_Real*)expr->data.data)[expr->nchildren];
5813 }
5814 
5815 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5817  SCIP_EXPR* expr /**< quadratic expression */
5818  )
5819 {
5820  assert(expr != NULL);
5821  assert(expr->op == SCIP_EXPR_QUADRATIC);
5822  assert(expr->data.data != NULL);
5823 
5824  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->quadelems;
5825 }
5826 
5827 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
5829  SCIP_EXPR* expr /**< quadratic expression */
5830  )
5831 {
5832  assert(expr != NULL);
5833  assert(expr->op == SCIP_EXPR_QUADRATIC);
5834  assert(expr->data.data != NULL);
5835 
5836  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->constant;
5837 }
5838 
5839 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression
5840  * can be NULL if all coefficients are 0.0 */
5842  SCIP_EXPR* expr /**< quadratic expression */
5843  )
5844 {
5845  assert(expr != NULL);
5846  assert(expr->op == SCIP_EXPR_QUADRATIC);
5847  assert(expr->data.data != NULL);
5848 
5849  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->lincoefs;
5850 }
5851 
5852 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5854  SCIP_EXPR* expr /**< quadratic expression */
5855  )
5856 {
5857  assert(expr != NULL);
5858  assert(expr->op == SCIP_EXPR_QUADRATIC);
5859  assert(expr->data.data != NULL);
5860 
5861  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->nquadelems;
5862 }
5863 
5864 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5866  SCIP_EXPR* expr /**< expression */
5867  )
5868 {
5869  assert(expr != NULL);
5870  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5871  assert(expr->data.data != NULL);
5872 
5873  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->monomials;
5874 }
5875 
5876 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5878  SCIP_EXPR* expr /**< expression */
5879  )
5880 {
5881  assert(expr != NULL);
5882  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5883  assert(expr->data.data != NULL);
5884 
5885  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->nmonomials;
5886 }
5887 
5888 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
5890  SCIP_EXPR* expr /**< expression */
5891  )
5892 {
5893  assert(expr != NULL);
5894  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5895  assert(expr->data.data != NULL);
5896 
5897  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant;
5898 }
5899 
5900 /** gets coefficient of a monomial */
5902  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5903  )
5904 {
5905  assert(monomial != NULL);
5906 
5907  return monomial->coef;
5908 }
5909 
5910 /** gets number of factors of a monomial */
5912  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5913  )
5914 {
5915  assert(monomial != NULL);
5916 
5917  return monomial->nfactors;
5918 }
5919 
5920 /** gets indices of children corresponding to factors of a monomial */
5922  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5923  )
5924 {
5925  assert(monomial != NULL);
5926 
5927  return monomial->childidxs;
5928 }
5929 
5930 /** gets exponents in factors of a monomial */
5932  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5933  )
5934 {
5935  assert(monomial != NULL);
5936 
5937  return monomial->exponents;
5938 }
5939 
5940 /** gets user data of a user expression */
5942  SCIP_EXPR* expr
5943  )
5944 {
5945  assert(expr != NULL);
5946  assert(expr->data.data != NULL);
5947 
5948  return ((SCIP_EXPRDATA_USER*)expr->data.data)->userdata;
5949 }
5950 
5951 /** indicates whether a user expression has the estimator callback defined */
5953  SCIP_EXPR* expr
5954  )
5955 {
5956  assert(expr != NULL);
5957  assert(expr->data.data != NULL);
5958 
5959  return ((SCIP_EXPRDATA_USER*)expr->data.data)->estimate != NULL;
5960 }
5961 
5962 /** gives the evaluation capability of a user expression */
5964  SCIP_EXPR* expr
5965  )
5966 {
5967  assert(expr != NULL);
5968  assert(expr->data.data != NULL);
5969 
5970  return ((SCIP_EXPRDATA_USER*)expr->data.data)->evalcapability;
5971 }
5972 
5973 /** creates a simple expression */
5975  BMS_BLKMEM* blkmem, /**< block memory data structure */
5976  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
5977  SCIP_EXPROP op, /**< operand of expression */
5978  ... /**< arguments of operand */
5979  )
5980 {
5981  va_list ap;
5982  SCIP_EXPR** children;
5983  SCIP_EXPROPDATA opdata;
5984 
5985  assert(blkmem != NULL);
5986  assert(expr != NULL);
5987 
5988  switch( op )
5989  {
5990  case SCIP_EXPR_VARIDX:
5991  case SCIP_EXPR_PARAM:
5992  {
5993  va_start( ap, op ); /*lint !e838*/
5994  opdata.intval = va_arg( ap, int ); /*lint !e416 !e826*/
5995  va_end( ap ); /*lint !e826*/
5996 
5997  assert( opdata.intval >= 0 );
5998 
5999  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
6000  break;
6001  }
6002 
6003  case SCIP_EXPR_CONST:
6004  {
6005  va_start(ap, op ); /*lint !e838*/
6006  opdata.dbl = va_arg( ap, SCIP_Real ); /*lint !e416 !e826*/
6007  va_end( ap ); /*lint !e826*/
6008 
6009  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
6010  break;
6011  }
6012 
6013  /* operands with two children */
6014  case SCIP_EXPR_PLUS :
6015  case SCIP_EXPR_MINUS :
6016  case SCIP_EXPR_MUL :
6017  case SCIP_EXPR_DIV :
6018  case SCIP_EXPR_MIN :
6019  case SCIP_EXPR_MAX :
6020  {
6021  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 2) ); /*lint !e506*/
6022 
6023  va_start(ap, op ); /*lint !e838*/
6024  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6025  children[1] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6026  assert(children[0] != NULL);
6027  assert(children[1] != NULL);
6028  va_end( ap ); /*lint !e826*/
6029  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6030 
6031  SCIP_CALL( exprCreate( blkmem, expr, op, 2, children, opdata ) );
6032  break;
6033  }
6034 
6035  /* operands with one child */
6036  case SCIP_EXPR_SQUARE:
6037  case SCIP_EXPR_SQRT :
6038  case SCIP_EXPR_EXP :
6039  case SCIP_EXPR_LOG :
6040  case SCIP_EXPR_SIN :
6041  case SCIP_EXPR_COS :
6042  case SCIP_EXPR_TAN :
6043  /* case SCIP_EXPR_ERF : */
6044  /* case SCIP_EXPR_ERFI : */
6045  case SCIP_EXPR_ABS :
6046  case SCIP_EXPR_SIGN :
6047  {
6048  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6049 
6050  va_start(ap, op ); /*lint !e838*/
6051  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6052  assert(children[0] != NULL);
6053  va_end( ap ); /*lint !e826*/
6054  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6055 
6056  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6057  break;
6058  }
6059 
6060  case SCIP_EXPR_REALPOWER:
6061  case SCIP_EXPR_SIGNPOWER:
6062  {
6063  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6064 
6065  va_start(ap, op ); /*lint !e838*/
6066  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6067  assert(children[0] != NULL);
6068  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
6069  va_end( ap ); /*lint !e826*/
6070 
6071  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6072  break;
6073  }
6074 
6075  case SCIP_EXPR_INTPOWER:
6076  {
6077  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6078 
6079  va_start(ap, op ); /*lint !e838*/
6080  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6081  assert(children[0] != NULL);
6082  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
6083  va_end( ap ); /*lint !e826*/
6084 
6085  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6086  break;
6087  }
6088 
6089  /* complex operands */
6090  case SCIP_EXPR_SUM :
6091  case SCIP_EXPR_PRODUCT:
6092  {
6093  int nchildren;
6094  SCIP_EXPR** childrenarg;
6095 
6096  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6097 
6098  va_start(ap, op ); /*lint !e838*/
6099  /* first argument should be number of children */
6100  nchildren = va_arg( ap, int ); /*lint !e416 !e826*/
6101  assert(nchildren >= 0);
6102 
6103  /* for a sum or product of 0 terms we can finish here */
6104  if( nchildren == 0 )
6105  {
6106  SCIP_RETCODE retcode;
6107  retcode = exprCreate( blkmem, expr, op, 0, NULL, opdata);
6108  va_end( ap ); /*lint !e826*/
6109  SCIP_CALL( retcode );
6110  break;
6111  }
6112 
6113  /* next argument should be array of children expressions */
6114  childrenarg = va_arg( ap, SCIP_EXPR** ); /*lint !e416 !e826*/
6115  assert(childrenarg != NULL);
6116  va_end( ap ); /*lint !e826*/
6117 
6118  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &children, childrenarg, nchildren) );
6119 
6120  SCIP_CALL( exprCreate( blkmem, expr, op, nchildren, children, opdata) );
6121  break;
6122  }
6123 
6124  case SCIP_EXPR_LINEAR :
6125  case SCIP_EXPR_QUADRATIC:
6126  case SCIP_EXPR_POLYNOMIAL:
6127  case SCIP_EXPR_USER:
6128  {
6129  SCIPerrorMessage("cannot create complex expression linear, quadratic, polynomial, or user with SCIPexprCreate\n");
6130  return SCIP_INVALIDDATA;
6131  }
6132 
6133  case SCIP_EXPR_LAST:
6134  SCIPABORT();
6135  break;
6136  }
6137 
6138  return SCIP_OKAY;
6139 }
6140 
6141 /** copies an expression including its children */
6143  BMS_BLKMEM* blkmem, /**< block memory data structure */
6144  SCIP_EXPR** targetexpr, /**< buffer to store pointer to copied expression */
6145  SCIP_EXPR* sourceexpr /**< expression to copy */
6146  )
6147 {
6148  assert(blkmem != NULL);
6149  assert(targetexpr != NULL);
6150  assert(sourceexpr != NULL);
6151 
6152  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targetexpr, sourceexpr) );
6153 
6154  if( sourceexpr->nchildren )
6155  {
6156  int i;
6157 
6158  /* alloc memory for children expressions */
6159  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetexpr)->children, sourceexpr->nchildren) );
6160 
6161  /* copy children expressions */
6162  for( i = 0; i < sourceexpr->nchildren; ++i )
6163  {
6164  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targetexpr)->children[i], sourceexpr->children[i]) );
6165  }
6166  }
6167  else
6168  {
6169  assert((*targetexpr)->children == NULL); /* otherwise, sourceexpr->children was not NULL, which is wrong */
6170  }
6171 
6172  /* call operands data copy callback for complex operands
6173  * for simple operands BMSduplicate above should have done the job
6174  */
6175  if( exprOpTable[sourceexpr->op].copydata != NULL )
6176  {
6177  SCIP_CALL( exprOpTable[sourceexpr->op].copydata(blkmem, sourceexpr->nchildren, sourceexpr->data, &(*targetexpr)->data) );
6178  }
6179 
6180  return SCIP_OKAY;
6181 }
6182 
6183 /** frees an expression including its children */
6185  BMS_BLKMEM* blkmem, /**< block memory data structure */
6186  SCIP_EXPR** expr /**< pointer to expression to free */
6187  )
6188 {
6189  assert(blkmem != NULL);
6190  assert(expr != NULL);
6191  assert(*expr != NULL);
6192 
6193  /* call operands data free callback, if given */
6194  if( exprOpTable[(*expr)->op].freedata != NULL )
6195  {
6196  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6197  }
6198 
6199  if( (*expr)->nchildren )
6200  {
6201  int i;
6202 
6203  assert( (*expr)->children != NULL );
6204 
6205  for( i = 0; i < (*expr)->nchildren; ++i )
6206  {
6207  SCIPexprFreeDeep(blkmem, &(*expr)->children[i]);
6208  assert((*expr)->children[i] == NULL);
6209  }
6210 
6211  BMSfreeBlockMemoryArray(blkmem, &(*expr)->children, (*expr)->nchildren);
6212  }
6213  else
6214  {
6215  assert( (*expr)->children == NULL );
6216  }
6217 
6218  BMSfreeBlockMemory(blkmem, expr);
6219 }
6220 
6221 /** frees an expression but not its children */
6223  BMS_BLKMEM* blkmem, /**< block memory data structure */
6224  SCIP_EXPR** expr /**< pointer to expression to free */
6225  )
6226 {
6227  assert(blkmem != NULL);
6228  assert(expr != NULL);
6229  assert(*expr != NULL);
6230 
6231  /* call operands data free callback, if given */
6232  if( exprOpTable[(*expr)->op].freedata != NULL )
6233  {
6234  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6235  }
6236 
6237  BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->nchildren);
6238 
6239  BMSfreeBlockMemory(blkmem, expr);
6240 }
6241 
6242 /** creates an expression from the addition of two given expression, with coefficients, and a constant
6243  *
6244  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6245  * Favors creation and maintaining of SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6246  */
6248  BMS_BLKMEM* blkmem, /**< block memory data structure */
6249  SCIP_EXPR** expr, /**< pointer to store pointer to created expression */
6250  SCIP_Real coef1, /**< coefficient of first term */
6251  SCIP_EXPR* term1, /**< expression of first term, or NULL */
6252  SCIP_Real coef2, /**< coefficient of second term */
6253  SCIP_EXPR* term2, /**< expression of second term, or NULL */
6254  SCIP_Real constant /**< constant term to add */
6255  )
6256 {
6257  assert(blkmem != NULL);
6258  assert(expr != NULL);
6259 
6260  /* @todo could do something special with quadratic and polynomial expressions */
6261 
6262  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_CONST )
6263  {
6264  constant += coef1 * SCIPexprGetOpReal(term1);
6265  SCIPexprFreeDeep(blkmem, &term1);
6266  }
6267 
6268  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_CONST )
6269  {
6270  constant += coef2 * SCIPexprGetOpReal(term2);
6271  SCIPexprFreeDeep(blkmem, &term2);
6272  }
6273 
6274  if( term1 == NULL && term2 == NULL )
6275  {
6276  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, constant) );
6277  return SCIP_OKAY;
6278  }
6279 
6280  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && coef1 != 1.0 )
6281  {
6282  /* multiply coefficients and constant of linear expression term1 by coef1 */
6283  SCIP_Real* data;
6284  int i;
6285 
6286  data = (SCIP_Real*)term1->data.data;
6287  assert(data != NULL);
6288 
6289  /* loop one more index to multiply also constant of linear expression */
6290  for( i = 0; i <= term1->nchildren; ++i )
6291  data[i] *= coef1;
6292 
6293  coef1 = 1.0;
6294  }
6295 
6296  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR && coef2 != 1.0 )
6297  {
6298  /* multiply coefficients and constant of linear expression term2 by coef2 */
6299  SCIP_Real* data;
6300  int i;
6301 
6302  data = (SCIP_Real*)term2->data.data;
6303  assert(data != NULL);
6304 
6305  /* loop one more index to multiply also constant of linear expression */
6306  for( i = 0; i <= term2->nchildren; ++i )
6307  data[i] *= coef2;
6308 
6309  coef2 = 1.0;
6310  }
6311 
6312  if( term1 == NULL || term2 == NULL )
6313  {
6314  if( term1 == NULL )
6315  {
6316  term1 = term2;
6317  coef1 = coef2;
6318  }
6319  if( constant != 0.0 || coef1 != 1.0 )
6320  {
6321  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6322  {
6323  assert(coef1 == 1.0);
6324 
6325  /* add constant to existing linear expression */
6326  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 0, NULL, NULL, constant) );
6327  *expr = term1;
6328  }
6329  else
6330  {
6331  /* create new linear expression for coef1 * term1 + constant */
6332  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term1, &coef1, constant) );
6333  }
6334  }
6335  else
6336  {
6337  assert(constant == 0.0);
6338  assert(coef1 == 1.0);
6339  *expr = term1;
6340  }
6341 
6342  return SCIP_OKAY;
6343  }
6344 
6346  {
6347  /* add 2nd linear expression to first one */
6348  assert(coef1 == 1.0);
6349  assert(coef2 == 1.0);
6350 
6352  SCIPexprFreeShallow(blkmem, &term2);
6353 
6354  *expr = term1;
6355 
6356  return SCIP_OKAY;
6357  }
6358 
6359  if( SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
6360  {
6361  /* if only term2 is linear, then swap */
6362  SCIP_EXPR* tmp;
6363 
6364  tmp = term2;
6365  assert(coef2 == 1.0);
6366 
6367  term2 = term1;
6368  coef2 = coef1;
6369  term1 = tmp;
6370  coef1 = 1.0;
6371  }
6372 
6373  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6374  {
6375  /* add coef2*term2 as extra child to linear expression term1 */
6376  assert(coef1 == 1.0);
6377 
6378  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 1, &coef2, &term2, constant) );
6379  *expr = term1;
6380 
6381  return SCIP_OKAY;
6382  }
6383 
6384  /* both terms are not linear, then create new linear term for sum */
6385  {
6386  SCIP_Real coefs[2];
6387  SCIP_EXPR* children[2];
6388 
6389  coefs[0] = coef1;
6390  coefs[1] = coef2;
6391  children[0] = term1;
6392  children[1] = term2;
6393 
6394  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 2, children, coefs, constant) );
6395  }
6396 
6397  return SCIP_OKAY;
6398 }
6399 
6400 /** creates an expression from the multiplication of an expression with a constant
6401  *
6402  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6403  * Favors creation and maintaining SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6404  */
6406  BMS_BLKMEM* blkmem, /**< block memory data structure */
6407  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
6408  SCIP_EXPR* term, /**< term to multiply by factor */
6409  SCIP_Real factor /**< factor */
6410  )
6411 {
6412  assert(blkmem != NULL);
6413  assert(expr != NULL);
6414  assert(term != NULL);
6415 
6416  if( factor == 0.0 )
6417  {
6418  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, 0.0) );
6419 
6420  SCIPexprFreeDeep(blkmem, &term);
6421 
6422  return SCIP_OKAY;
6423  }
6424  if( factor == 1.0 )
6425  {
6426  *expr = term;
6427  return SCIP_OKAY;
6428  }
6429 
6430  switch( SCIPexprGetOperator(term) )
6431  {
6432  case SCIP_EXPR_CONST :
6433  {
6434  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, factor * SCIPexprGetOpReal(term)) );
6435  SCIPexprFreeDeep(blkmem, &term);
6436  break;
6437  }
6438 
6439  case SCIP_EXPR_LINEAR :
6440  {
6441  SCIP_Real* data;
6442  int i;
6443 
6444  data = (SCIP_Real*)term->data.data;
6445  assert(data != NULL);
6446 
6447  /* loop one more index to multiply also constant of linear expression */
6448  for( i = 0; i <= SCIPexprGetNChildren(term); ++i )
6449  data[i] *= factor;
6450 
6451  *expr = term;
6452  break;
6453  }
6454 
6455  case SCIP_EXPR_QUADRATIC :
6456  {
6458  int i;
6459 
6460  data = (SCIP_EXPRDATA_QUADRATIC*)term->data.data;
6461 
6462  data->constant *= factor;
6463 
6464  if( data->lincoefs != NULL )
6465  for( i = 0; i < term->nchildren; ++i )
6466  data->lincoefs[i] *= factor;
6467 
6468  for( i = 0; i < data->nquadelems; ++i )
6469  data->quadelems[i].coef *= factor;
6470 
6471  *expr = term;
6472  break;
6473  }
6474 
6475  case SCIP_EXPR_POLYNOMIAL :
6476  {
6478  int i;
6479 
6480  data = (SCIP_EXPRDATA_POLYNOMIAL*)term->data.data;
6481 
6482  data->constant *= factor;
6483 
6484  for( i = 0; i < data->nmonomials; ++i )
6485  data->monomials[i]->coef *= factor;
6486 
6487  *expr = term;
6488  break;
6489  }
6490 
6491  default:
6492  {
6493  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term, &factor, 0.0) );
6494  break;
6495  }
6496 
6497  } /*lint !e788 */
6498 
6499  return SCIP_OKAY;
6500 }
6501 
6502 /** creates a SCIP_EXPR_LINEAR expression that is (affine) linear in its children: constant + sum_i coef_i child_i */
6504  BMS_BLKMEM* blkmem, /**< block memory data structure */
6505  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6506  int nchildren, /**< number of children */
6507  SCIP_EXPR** children, /**< children of expression */
6508  SCIP_Real* coefs, /**< coefficients of children */
6509  SCIP_Real constant /**< constant part */
6510  )
6511 {
6512  SCIP_EXPROPDATA opdata;
6513  SCIP_EXPR** childrencopy;
6514  SCIP_Real* data;
6515 
6516  assert(nchildren >= 0);
6517  assert(children != NULL || nchildren == 0);
6518  assert(coefs != NULL || nchildren == 0);
6519 
6520  if( nchildren > 0 )
6521  {
6522  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6523  }
6524  else
6525  childrencopy = NULL;
6526 
6527  /* we store the coefficients and the constant in a single array and make this our operand data */
6528  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, nchildren + 1) );
6529  BMScopyMemoryArray(data, coefs, nchildren); /*lint !e644*/
6530  data[nchildren] = constant;
6531 
6532  opdata.data = (void*)data;
6533 
6534  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_LINEAR, nchildren, childrencopy, opdata) );
6535 
6536  return SCIP_OKAY;
6537 }
6538 
6539 /** adds new terms to a linear expression */
6541  BMS_BLKMEM* blkmem, /**< block memory */
6542  SCIP_EXPR* expr, /**< linear expression */
6543  int nchildren, /**< number of children to add */
6544  SCIP_Real* coefs, /**< coefficients of additional children */
6545  SCIP_EXPR** children, /**< additional children expressions */
6546  SCIP_Real constant /**< constant to add */
6547  )
6548 {
6549  SCIP_Real* data;
6550 
6551  assert(blkmem != NULL);
6552  assert(expr != NULL);
6553  assert(expr->op == SCIP_EXPR_LINEAR);
6554  assert(nchildren >= 0);
6555  assert(coefs != NULL || nchildren == 0);
6556  assert(children != NULL || nchildren == 0);
6557 
6558  data = (SCIP_Real*)expr->data.data;
6559  assert(data != NULL);
6560 
6561  /* handle simple case of adding a constant */
6562  if( nchildren == 0 )
6563  {
6564  data[expr->nchildren] += constant;
6565 
6566  return SCIP_OKAY;
6567  }
6568 
6569  /* add new children to expr's children array */
6570  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nchildren) );
6571  BMScopyMemoryArray(&expr->children[expr->nchildren], children, nchildren); /*lint !e866*/
6572 
6573  /* add constant and new coefs to expr's data array */
6574  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, expr->nchildren + 1, expr->nchildren + nchildren + 1) );
6575  data[expr->nchildren + nchildren] = data[expr->nchildren] + constant;
6576  BMScopyMemoryArray(&data[expr->nchildren], coefs, nchildren); /*lint !e866*/
6577  expr->data.data = (void*)data;
6578 
6579  expr->nchildren += nchildren;
6580 
6581  return SCIP_OKAY;
6582 }
6583 
6584 /** creates a SCIP_EXPR_QUADRATIC expression: constant + sum_i coef_i child_i + sum_i coef_i child1_i child2_i */
6586  BMS_BLKMEM* blkmem, /**< block memory data structure */
6587  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6588  int nchildren, /**< number of children */
6589  SCIP_EXPR** children, /**< children of expression */
6590  SCIP_Real constant, /**< constant */
6591  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
6592  int nquadelems, /**< number of quadratic elements */
6593  SCIP_QUADELEM* quadelems /**< quadratic elements specifying coefficients and child indices */
6594  )
6595 {
6596  SCIP_EXPROPDATA opdata;
6597  SCIP_EXPR** childrencopy;
6599 
6600  assert(nchildren >= 0);
6601  assert(children != NULL || nchildren == 0);
6602  assert(quadelems != NULL || nquadelems == 0);
6603 
6604  if( nchildren > 0 )
6605  {
6606  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6607  }
6608  else
6609  childrencopy = NULL;
6610 
6611  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
6612 
6613  opdata.data = (void*)data;
6614 
6615  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_QUADRATIC, nchildren, childrencopy, opdata) );
6616 
6617  return SCIP_OKAY;
6618 }
6619 
6620 /** ensures that quadratic elements of a quadratic expression are sorted */
6622  SCIP_EXPR* expr /**< quadratic expression */
6623  )
6624 {
6625  assert(expr != NULL);
6626  assert(expr->op == SCIP_EXPR_QUADRATIC);
6627  assert(expr->data.data != NULL);
6628 
6630 }
6631 
6632 /** creates a SCIP_EXPR_POLYNOMIAL expression from an array of monomials: constant + sum_i monomial_i */
6634  BMS_BLKMEM* blkmem, /**< block memory data structure */
6635  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6636  int nchildren, /**< number of children */
6637  SCIP_EXPR** children, /**< children of expression */
6638  int nmonomials, /**< number of monomials */
6639  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
6640  SCIP_Real constant, /**< constant part */
6641  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6642  )
6643 {
6644  SCIP_EXPROPDATA opdata;
6645  SCIP_EXPR** childrencopy;
6647 
6648  assert(nchildren >= 0);
6649  assert(children != NULL || nchildren == 0);
6650  assert(monomials != NULL || nmonomials == 0);
6651 
6652  if( nchildren > 0 )
6653  {
6654  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6655  }
6656  else
6657  childrencopy = NULL;
6658 
6659  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
6660  opdata.data = (void*)data;
6661 
6662  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_POLYNOMIAL, nchildren, childrencopy, opdata) );
6663 
6664  return SCIP_OKAY;
6665 }
6666 
6667 /** adds an array of monomials to a SCIP_EXPR_POLYNOMIAL expression */
6669  BMS_BLKMEM* blkmem, /**< block memory of expression */
6670  SCIP_EXPR* expr, /**< expression */
6671  int nmonomials, /**< number of monomials to add */
6672  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
6673  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6674  )
6675 {
6676  assert(blkmem != NULL);
6677  assert(expr != NULL);
6678  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6679  assert(monomials != NULL || nmonomials == 0);
6680 
6681  if( nmonomials == 0 )
6682  return SCIP_OKAY;
6683 
6684  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, nmonomials, monomials, copymonomials) );
6685 
6686  return SCIP_OKAY;
6687 }
6688 
6689 /** changes the constant in a SCIP_EXPR_POLYNOMIAL expression */
6691  SCIP_EXPR* expr, /**< expression */
6692  SCIP_Real constant /**< new value for constant */
6693  )
6694 {
6695  assert(expr != NULL);
6696  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6697  assert(expr->data.data != NULL);
6698 
6699  ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant = constant;
6700 }
6701 
6702 /** multiplies each summand of a polynomial by a given constant */
6704  BMS_BLKMEM* blkmem, /**< block memory */
6705  SCIP_EXPR* expr, /**< polynomial expression */
6706  SCIP_Real factor /**< constant factor */
6707  )
6708 {
6709  assert(expr != NULL);
6710  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6711  assert(expr->data.data != NULL);
6712 
6713  polynomialdataMultiplyByConstant(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor);
6714 }
6715 
6716 /** multiplies each summand of a polynomial by a given monomial */
6718  BMS_BLKMEM* blkmem, /**< block memory */
6719  SCIP_EXPR* expr, /**< polynomial expression */
6720  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
6721  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6722  )
6723 {
6724  assert(blkmem != NULL);
6725  assert(factor != NULL);
6726  assert(expr != NULL);
6727  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6728  assert(expr->data.data != NULL);
6729 
6730  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor, childmap) );
6731 
6732  return SCIP_OKAY;
6733 }
6734 
6735 /** multiplies this polynomial by a polynomial
6736  *
6737  * Factor needs to be different from expr.
6738  * Children of factor need to be children of expr already, w.r.t. an optional mapping of child indices.
6739  */
6741  BMS_BLKMEM* blkmem, /**< block memory */
6742  SCIP_EXPR* expr, /**< polynomial expression */
6743  SCIP_EXPR* factor, /**< polynomial factor */
6744  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6745  )
6746 {
6747  assert(blkmem != NULL);
6748  assert(expr != NULL);
6749  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6750  assert(expr->data.data != NULL);
6751  assert(factor != NULL);
6752  assert(factor->op == SCIP_EXPR_POLYNOMIAL);
6753  assert(factor->data.data != NULL);
6754  assert(expr != factor);
6755 
6756 #ifndef NDEBUG
6757  if( childmap == NULL )
6758  {
6759  int i;
6760  assert(factor->nchildren == expr->nchildren);
6761  for( i = 0; i < factor->nchildren; ++i )
6762  assert(SCIPexprAreEqual(expr->children[i], factor->children[i], 0.0));
6763  }
6764  else
6765  {
6766  int i;
6767  for( i = 0; i < factor->nchildren; ++i )
6768  {
6769  assert(childmap[i] >= 0);
6770  assert(childmap[i] < expr->nchildren);
6771  assert(SCIPexprAreEqual(expr->children[childmap[i]], factor->children[i], 0.0));
6772  }
6773  }
6774 #endif
6775 
6777 
6778  return SCIP_OKAY;
6779 }
6780 
6781 /** takes a power of the polynomial
6782  *
6783  * Exponent need to be an integer.
6784  * Polynomial needs to be a monomial, if exponent is negative.
6785  */
6787  BMS_BLKMEM* blkmem, /**< block memory */
6788  SCIP_EXPR* expr, /**< polynomial expression */
6789  int exponent /**< exponent of power operation */
6790  )
6791 {
6792  assert(blkmem != NULL);
6793  assert(expr != NULL);
6794  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6795  assert(expr->data.data != NULL);
6796 
6797  SCIP_CALL( polynomialdataPower(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, exponent) );
6798 
6799  return SCIP_OKAY;
6800 }
6801 
6802 /** merges monomials in a polynomial expression that differ only in coefficient into a single monomial
6803  *
6804  * Eliminates monomials with coefficient between -eps and eps.
6805  */
6807  BMS_BLKMEM* blkmem, /**< block memory */
6808  SCIP_EXPR* expr, /**< polynomial expression */
6809  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
6810  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
6811  )
6812 {
6813  assert(expr != NULL);
6814  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6815  assert(expr->data.data != NULL);
6816 
6817  polynomialdataMergeMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, eps, mergefactors);
6818 }
6819 
6820 /** checks if two monomials are equal */
6822  SCIP_EXPRDATA_MONOMIAL* monomial1, /**< first monomial */
6823  SCIP_EXPRDATA_MONOMIAL* monomial2, /**< second monomial */
6824  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6825  )
6826 {
6827  int i;
6828 
6829  assert(monomial1 != NULL);
6830  assert(monomial2 != NULL);
6831 
6832  if( monomial1->nfactors != monomial2->nfactors )
6833  return FALSE;
6834 
6835  if( !EPSEQ(monomial1->coef, monomial2->coef, eps) )
6836  return FALSE;
6837 
6838  SCIPexprSortMonomialFactors(monomial1);
6839  SCIPexprSortMonomialFactors(monomial2);
6840 
6841  for( i = 0; i < monomial1->nfactors; ++i )
6842  {
6843  if( monomial1->childidxs[i] != monomial2->childidxs[i] ||
6844  !EPSEQ(monomial1->exponents[i], monomial2->exponents[i], eps) )
6845  return FALSE;
6846  }
6847 
6848  return TRUE;
6849 }
6850 
6851 /** changes coefficient of monomial */
6853  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6854  SCIP_Real newcoef /**< new coefficient */
6855  )
6856 {
6857  assert(monomial != NULL);
6858 
6859  monomial->coef = newcoef;
6860 }
6861 
6862 /** adds factors to a monomial */
6864  BMS_BLKMEM* blkmem, /**< block memory */
6865  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6866  int nfactors, /**< number of factors to add */
6867  int* childidxs, /**< indices of children corresponding to factors */
6868  SCIP_Real* exponents /**< exponent in each factor */
6869  )
6870 {
6871  assert(monomial != NULL);
6872  assert(nfactors >= 0);
6873  assert(childidxs != NULL || nfactors == 0);
6874  assert(exponents != NULL || nfactors == 0);
6875 
6876  if( nfactors == 0 )
6877  return SCIP_OKAY;
6878 
6879  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + nfactors) );
6880  assert(monomial->nfactors + nfactors <= monomial->factorssize);
6881 
6882  BMScopyMemoryArray(&monomial->childidxs[monomial->nfactors], childidxs, nfactors); /*lint !e866*/
6883  BMScopyMemoryArray(&monomial->exponents[monomial->nfactors], exponents, nfactors); /*lint !e866*/
6884 
6885  monomial->nfactors += nfactors;
6886  monomial->sorted = (monomial->nfactors <= 1);
6887 
6888  return SCIP_OKAY;
6889 }
6890 
6891 /** multiplies a monomial with a monomial */
6893  BMS_BLKMEM* blkmem, /**< block memory */
6894  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6895  SCIP_EXPRDATA_MONOMIAL* factor, /**< factor monomial */
6896  int* childmap /**< map to apply to children in factor, or NULL for 1:1 */
6897  )
6898 {
6899  assert(monomial != NULL);
6900  assert(factor != NULL);
6901 
6902  if( factor->coef == 0.0 )
6903  {
6904  monomial->nfactors = 0;
6905  monomial->coef = 0.0;
6906  return SCIP_OKAY;
6907  }
6908 
6909  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, factor->nfactors, factor->childidxs, factor->exponents) );
6910 
6911  if( childmap != NULL )
6912  {
6913  int i;
6914  for( i = monomial->nfactors - factor->nfactors; i < monomial->nfactors; ++i )
6915  monomial->childidxs[i] = childmap[monomial->childidxs[i]];
6916  }
6917 
6918  monomial->coef *= factor->coef;
6919 
6920  return SCIP_OKAY;
6921 }
6922 
6923 /** replaces the monomial by a power of the monomial
6924  *
6925  * Allows only integers as exponent.
6926  */
6928  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6929  int exponent /**< integer exponent of power operation */
6930  )
6931 {
6932  int i;
6933 
6934  assert(monomial != NULL);
6935 
6936  if( exponent == 1 )
6937  return;
6938 
6939  if( exponent == 0 )
6940  {
6941  /* x^0 = 1, unless x = 0; 0^0 = 0 */
6942  if( monomial->coef != 0.0 )
6943  monomial->coef = 1.0;
6944  monomial->nfactors = 0;
6945  return;
6946  }
6947 
6948  monomial->coef = pow(monomial->coef, (SCIP_Real)exponent);
6949  for( i = 0; i < monomial->nfactors; ++i )
6950  monomial->exponents[i] *= exponent;
6951 }
6952 
6953 /** merges factors that correspond to the same child by adding exponents
6954  *
6955  * Eliminates factors with exponent between -eps and eps.
6956  */
6958  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6959  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6960  )
6961 {
6962  int i;
6963  int offset;
6964 
6965  assert(monomial != NULL);
6966  assert(eps >= 0.0);
6967 
6968  SCIPexprSortMonomialFactors(monomial);
6969 
6970  /* merge factors with same child index by adding up their exponents
6971  * delete factors with exponent 0.0 */
6972  offset = 0;
6973  i = 0;
6974  while( i + offset < monomial->nfactors )
6975  {
6976  if( offset > 0 )
6977  {
6978  assert(monomial->childidxs[i] == -1);
6979  assert(monomial->childidxs[i+offset] >= 0);
6980  monomial->childidxs[i] = monomial->childidxs[i+offset];
6981  monomial->exponents[i] = monomial->exponents[i+offset];
6982 #ifndef NDEBUG
6983  monomial->childidxs[i+offset] = -1;
6984 #endif
6985  }
6986 
6987  while( i+offset+1 < monomial->nfactors && monomial->childidxs[i] == monomial->childidxs[i+offset+1] )
6988  {
6989  monomial->exponents[i] += monomial->exponents[i+offset+1];
6990 #ifndef NDEBUG
6991  monomial->childidxs[i+offset+1] = -1;
6992 #endif
6993  ++offset;
6994  }
6995 
6996  if( EPSZ(monomial->exponents[i], eps) )
6997  {
6998 #ifndef NDEBUG
6999  monomial->childidxs[i] = -1;
7000 #endif
7001  ++offset;
7002  continue;
7003  }
7004  else if( EPSISINT(monomial->exponents[i], eps) )
7005  monomial->exponents[i] = EPSROUND(monomial->exponents[i], eps);
7006 
7007  ++i;
7008  }
7009 
7010 #ifndef NDEBUG
7011  for( ; i < monomial->nfactors; ++i )
7012  assert(monomial->childidxs[i] == -1);
7013 #endif
7014 
7015  monomial->nfactors -= offset;
7016 
7017  if( EPSEQ(monomial->coef, 1.0, eps) )
7018  monomial->coef = 1.0;
7019  else if( EPSEQ(monomial->coef, -1.0, eps) )
7020  monomial->coef = -1.0;
7021 }
7022 
7023 /** ensures that monomials of a polynomial are sorted */
7025  SCIP_EXPR* expr /**< polynomial expression */
7026  )
7027 {
7028  assert(expr != NULL);
7029  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
7030  assert(expr->data.data != NULL);
7031 
7033 }
7034 
7035 /** creates a monomial */
7037  BMS_BLKMEM* blkmem, /**< block memory */
7038  SCIP_EXPRDATA_MONOMIAL** monomial, /**< buffer where to store pointer to new monomial */
7039  SCIP_Real coef, /**< coefficient of monomial */
7040  int nfactors, /**< number of factors in monomial */
7041  int* childidxs, /**< indices of children corresponding to factors, or NULL if identity */
7042  SCIP_Real* exponents /**< exponent in each factor, or NULL if all 1.0 */
7043  )
7044 {
7045  assert(blkmem != NULL);
7046  assert(monomial != NULL);
7047 
7048  SCIP_ALLOC( BMSallocBlockMemory(blkmem, monomial) );
7049 
7050  (*monomial)->coef = coef;
7051  (*monomial)->nfactors = nfactors;
7052  (*monomial)->factorssize = nfactors;
7053  (*monomial)->sorted = (nfactors <= 1);
7054 
7055  if( nfactors > 0 )
7056  {
7057  if( childidxs != NULL )
7058  {
7059  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->childidxs, childidxs, nfactors) );
7060  }
7061  else
7062  {
7063  int i;
7064 
7065  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->childidxs, nfactors) );
7066  for( i = 0; i < nfactors; ++i )
7067  (*monomial)->childidxs[i] = i;
7068  }
7069 
7070  if( exponents != NULL )
7071  {
7072  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->exponents, exponents, nfactors) );
7073  }
7074  else
7075  {
7076  int i;
7077 
7078  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->exponents, nfactors) );
7079  for( i = 0; i < nfactors; ++i )
7080  (*monomial)->exponents[i] = 1.0;
7081  }
7082  }
7083  else
7084  {
7085  (*monomial)->childidxs = NULL;
7086  (*monomial)->exponents = NULL;
7087  }
7088 
7089  return SCIP_OKAY;
7090 }
7091 
7092 /** frees a monomial */
7094  BMS_BLKMEM* blkmem, /**< block memory */
7095  SCIP_EXPRDATA_MONOMIAL** monomial /**< pointer to monomial that should be freed */
7096  )
7097 {
7098  assert(blkmem != NULL);
7099  assert( monomial != NULL);
7100  assert(*monomial != NULL);
7101 
7102  if( (*monomial)->factorssize > 0 )
7103  {
7104  assert((*monomial)->childidxs != NULL);
7105  assert((*monomial)->exponents != NULL);
7106 
7107  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->childidxs, (*monomial)->factorssize);
7108  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->exponents, (*monomial)->factorssize);
7109  }
7110  assert((*monomial)->childidxs == NULL);
7111  assert((*monomial)->exponents == NULL);
7112 
7113  BMSfreeBlockMemory(blkmem, monomial);
7114 }
7115 
7116 /** ensures that factors in a monomial are sorted */
7118  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
7119  )
7120 {
7121  assert(monomial != NULL);
7122 
7123  if( monomial->sorted )
7124  return;
7125 
7126  if( monomial->nfactors > 0 )
7127  SCIPsortIntReal(monomial->childidxs, monomial->exponents, monomial->nfactors);
7128 
7129  monomial->sorted = TRUE;
7130 }
7131 
7132 /** finds a factor corresponding to a given child index in a monomial
7133  *
7134  * Note that if the factors have not been merged, the position of some factor corresponding to a given child is given.
7135  * Returns TRUE if a factor is found, FALSE if not.
7136  */
7138  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
7139  int childidx, /**< index of the child which factor to search for */
7140  int* pos /**< buffer to store position of factor */
7141  )
7142 {
7143  assert(monomial != NULL);
7144 
7145  if( monomial->nfactors == 0 )
7146  return FALSE;
7147 
7148  SCIPexprSortMonomialFactors(monomial);
7149 
7150  return SCIPsortedvecFindInt(monomial->childidxs, childidx, monomial->nfactors, pos);
7151 }
7152 
7153 /** creates a user expression */
7155  BMS_BLKMEM* blkmem, /**< block memory data structure */
7156  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
7157  int nchildren, /**< number of children */
7158  SCIP_EXPR** children, /**< children of expression */
7159  SCIP_USEREXPRDATA* data, /**< user data for expression, expression assumes ownership */
7160  SCIP_EXPRINTCAPABILITY evalcapability, /**< capability of evaluation functions (partially redundant, currently) */
7161  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
7162  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function, or NULL if not implemented */
7163  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
7164  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function, or NULL if not implemented */
7165  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
7166  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
7167  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
7168  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
7169  )
7170 {
7171  SCIP_EXPROPDATA opdata;
7172  SCIP_EXPRDATA_USER* userexprdata;
7173  SCIP_EXPR** childrencopy;
7174 
7175  assert(blkmem != NULL);
7176  assert(expr != NULL);
7177  assert(eval != NULL);
7178  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
7179  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
7180  assert(curv != NULL);
7181  assert(copydata != NULL || data == NULL);
7182  assert(freedata != NULL || data == NULL);
7183 
7184  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &userexprdata) );
7185 
7186  userexprdata->userdata = data;
7187  userexprdata->evalcapability = evalcapability;
7188  userexprdata->eval = eval;
7189  userexprdata->inteval = inteval;
7190  userexprdata->curv = curv;
7191  userexprdata->prop = prop;
7192  userexprdata->estimate = estimate;
7193  userexprdata->copydata = copydata;
7194  userexprdata->freedata = freedata;
7195  userexprdata->print = print;
7196 
7197  opdata.data = (void*) userexprdata;
7198 
7199  if( nchildren == 0 )
7200  {
7201  SCIP_CALL( exprCreate(blkmem, expr, SCIP_EXPR_USER, 0, NULL, opdata) );
7202  return SCIP_OKAY;
7203  }
7204  assert(children != NULL);
7205 
7206  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
7207 
7208  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_USER, nchildren, childrencopy, opdata) );
7209 
7210  return SCIP_OKAY;
7211 }
7212 
7213 /** indicates whether the expression contains a SCIP_EXPR_PARAM */
7215  SCIP_EXPR* expr /**< expression */
7216  )
7217 {
7218  int i;
7219 
7220  assert(expr != NULL);
7221 
7222  if( expr->op == SCIP_EXPR_PARAM )
7223  return TRUE;
7224 
7225  for( i = 0; i < expr->nchildren; ++i )
7226  if( SCIPexprHasParam(expr->children[i]) )
7227  return TRUE;
7228 
7229  return FALSE;
7230 }
7231 
7232 /** gets maximal degree of expression, or SCIP_EXPR_DEGREEINFINITY if not a polynomial */
7234  SCIP_EXPR* expr, /**< expression */
7235  int* maxdegree /**< buffer to store maximal degree */
7236  )
7237 {
7238  int child1;
7239  int child2;
7240 
7241  assert(expr != NULL);
7242  assert(maxdegree != NULL);
7243 
7244  switch( expr->op )
7245  {
7246  case SCIP_EXPR_VARIDX:
7247  *maxdegree = 1;
7248  break;
7249 
7250  case SCIP_EXPR_CONST:
7251  case SCIP_EXPR_PARAM:
7252  *maxdegree = 0;
7253  break;
7254 
7255  case SCIP_EXPR_PLUS:
7256  case SCIP_EXPR_MINUS:
7257  {
7258  assert(expr->children[0] != NULL);
7259  assert(expr->children[1] != NULL);
7260 
7261  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7262  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7263 
7264  *maxdegree = MAX(child1, child2);
7265  break;
7266  }
7267 
7268  case SCIP_EXPR_MUL:
7269  {
7270  assert(expr->children[0] != NULL);
7271  assert(expr->children[1] != NULL);
7272 
7273  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7274  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7275 
7276  *maxdegree = child1 + child2;
7277  break;
7278  }
7279 
7280  case SCIP_EXPR_DIV:
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 not division by constant, then it is not a polynomial */
7289  *maxdegree = (child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : child1;
7290  break;
7291  }
7292 
7293  case SCIP_EXPR_SQUARE:
7294  {
7295  assert(expr->children[0] != NULL);
7296 
7297  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7298 
7299  *maxdegree = 2 * child1;
7300  break;
7301  }
7302 
7303  case SCIP_EXPR_SQRT:
7304  {
7305  assert(expr->children[0] != NULL);
7306 
7307  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7308 
7309  /* if not squareroot of constant, then no polynomial */
7310  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7311  break;
7312  }
7313 
7314  case SCIP_EXPR_REALPOWER:
7315  {
7316  assert(expr->children[0] != NULL);
7317 
7318  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7319 
7320  /* constant ^ constant has degree 0 */
7321  if( child1 == 0 )
7322  {
7323  *maxdegree = 0;
7324  break;
7325  }
7326 
7327  /* non-polynomial ^ constant is not a polynomial */
7328  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7329  {
7330  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7331  break;
7332  }
7333 
7334  /* so it is polynomial ^ constant
7335  * let's see whether the constant is integral */
7336 
7337  if( expr->data.dbl == 0.0 ) /* polynomial ^ 0 == 0 */
7338  *maxdegree = 0;
7339  else if( expr->data.dbl > 0.0 && (int)expr->data.dbl == expr->data.dbl ) /* natural exponent gives polynomial again */ /*lint !e777*/
7340  *maxdegree = child1 * (int)expr->data.dbl;
7341  else /* negative or nonintegral exponent does not give polynomial */
7342  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7343 
7344  break;
7345  }
7346 
7347  case SCIP_EXPR_INTPOWER:
7348  {
7349  assert(expr->children[0] != NULL);
7350 
7351  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7352 
7353  /* constant ^ integer or something ^ 0 has degree 0 */
7354  if( child1 == 0 || expr->data.intval == 0 )
7355  {
7356  *maxdegree = 0;
7357  break;
7358  }
7359 
7360  /* non-polynomial ^ integer or something ^ negative is not a polynomial */
7361  if( child1 >= SCIP_EXPR_DEGREEINFINITY || expr->data.intval < 0 )
7362  {
7363  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7364  break;
7365  }
7366 
7367  /* so it is polynomial ^ natural, which gives a polynomial again */
7368  *maxdegree = child1 * expr->data.intval;
7369 
7370  break;
7371  }
7372 
7373  case SCIP_EXPR_SIGNPOWER:
7374  {
7375  assert(expr->children[0] != NULL);
7376 
7377  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7378 
7379  /* if child is not constant, then it is no polynomial */
7380  *maxdegree = child1 != 0 ? SCIP_EXPR_DEGREEINFINITY : 0;
7381  break;
7382  }
7383 
7384  case SCIP_EXPR_EXP:
7385  case SCIP_EXPR_LOG:
7386  case SCIP_EXPR_SIN:
7387  case SCIP_EXPR_COS:
7388  case SCIP_EXPR_TAN:
7389  /* case SCIP_EXPR_ERF: */
7390  /* case SCIP_EXPR_ERFI: */
7391  case SCIP_EXPR_ABS:
7392  case SCIP_EXPR_SIGN:
7393  case SCIP_EXPR_USER:
7394  {
7395  assert(expr->children[0] != NULL);
7396 
7397  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7398 
7399  /* if argument is not a constant, then no polynomial, otherwise it is a constant */
7400  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7401  break;
7402  }
7403 
7404  case SCIP_EXPR_MIN:
7405  case SCIP_EXPR_MAX:
7406  {
7407  assert(expr->children[0] != NULL);
7408  assert(expr->children[1] != NULL);
7409 
7410  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7411  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7412 
7413  /* if any of the operands is not constant, then it is no polynomial */
7414  *maxdegree = (child1 != 0 || child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7415  break;
7416  }
7417 
7418  case SCIP_EXPR_SUM:
7419  case SCIP_EXPR_LINEAR:
7420  {
7421  int i;
7422 
7423  *maxdegree = 0;
7424  for( i = 0; i < expr->nchildren && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7425  {
7426  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7427  if( child1 > *maxdegree )
7428  *maxdegree = child1;
7429  }
7430 
7431  break;
7432  }
7433 
7434  case SCIP_EXPR_PRODUCT:
7435  {
7436  int i;
7437 
7438  *maxdegree = 0;
7439  for( i = 0; i < expr->nchildren; ++i )
7440  {
7441  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7442  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7443  {
7444  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7445  break;
7446  }
7447  *maxdegree += child1;
7448  }
7449 
7450  break;
7451  }
7452 
7453  case SCIP_EXPR_QUADRATIC:
7454  {
7455  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7456  int childidx;
7457  int quadidx;
7458 
7459  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7460 
7461  /* make sure quadratic elements are sorted */
7462  quadraticdataSort(quadraticdata);
7463 
7464  *maxdegree = 0;
7465  quadidx = 0;
7466  for( childidx = 0; childidx < expr->nchildren; ++childidx )
7467  {
7468  /* if no linear or no quadratic coefficient with current child on first position, then nothing to do */
7469  if( (quadraticdata->lincoefs == NULL || quadraticdata->lincoefs[childidx] == 0.0) &&
7470  (quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 > childidx) )
7471  continue;
7472 
7473  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[childidx], &child1) );
7474  if( child1 == SCIP_EXPR_DEGREEINFINITY )
7475  {
7476  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7477  break;
7478  }
7479 
7480  while( quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 == childidx )
7481  {
7482  if( quadraticdata->quadelems[quadidx].idx2 == childidx )
7483  {
7484  /* square term */
7485  if( 2*child1 > *maxdegree )
7486  *maxdegree = 2*child1;
7487  }
7488  else
7489  {
7490  /* bilinear term */
7491  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[quadraticdata->quadelems[quadidx].idx2], &child2) );
7492  if( child2 == SCIP_EXPR_DEGREEINFINITY )
7493  {
7494  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7495  break;
7496  }
7497  if( child1 + child2 > *maxdegree )
7498  *maxdegree = child1 + child2;
7499  }
7500  ++quadidx;
7501  }
7502  if( *maxdegree == SCIP_EXPR_DEGREEINFINITY )
7503  break;
7504  }
7505 
7506  break;
7507  }
7508 
7509  case SCIP_EXPR_POLYNOMIAL:
7510  {
7511  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7512  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7513  int monomialdegree;
7514  int i;
7515  int j;
7516 
7517  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7518 
7519  *maxdegree = 0;
7520  for( i = 0; i < polynomialdata->nmonomials && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7521  {
7522  monomialdata = polynomialdata->monomials[i];
7523  assert(monomialdata != NULL);
7524 
7525  /* compute degree of monomial = sum of degree of factors */
7526  monomialdegree = 0;
7527  for( j = 0; j < monomialdata->nfactors; ++j )
7528  {
7529  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[monomialdata->childidxs[j]], &child1) );
7530 
7531  /* if the exponent of the factor is not a natural number and the child is not constant (degree 0),
7532  * then we report that we are not really a polynomial */
7533  if( child1 != 0 && (monomialdata->exponents[j] < 0.0 || (int)monomialdata->exponents[j] != monomialdata->exponents[j]) )
7534  {
7535  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7536  break;
7537  }
7538 
7539  monomialdegree += child1 * (int)monomialdata->exponents[j];
7540  }
7541 
7542  if( monomialdegree > *maxdegree )
7543  *maxdegree = monomialdegree;
7544  }
7545 
7546  break;
7547  }
7548 
7549  case SCIP_EXPR_LAST:
7550  SCIPABORT();
7551  break;
7552  }
7553 
7554  return SCIP_OKAY;
7555 }
7556 
7557 /** counts usage of variables in expression */
7559  SCIP_EXPR* expr, /**< expression to update */
7560  int* varsusage /**< array with counters of variable usage */
7561  )
7562 {
7563  int i;
7564 
7565  assert(expr != NULL);
7566  assert(varsusage != NULL);
7567 
7568  if( expr->op == SCIP_EXPR_VARIDX )
7569  {
7570  ++varsusage[expr->data.intval];
7571  }
7572 
7573  for( i = 0; i < expr->nchildren; ++i )
7574  SCIPexprGetVarsUsage(expr->children[i], varsusage);
7575 }
7576 
7577 /** compares whether two expressions are the same
7578  *
7579  * Inconclusive, i.e., may give FALSE even if expressions are equivalent (x*y != y*x).
7580  */
7582  SCIP_EXPR* expr1, /**< first expression */
7583  SCIP_EXPR* expr2, /**< second expression */
7584  SCIP_Real eps /**< threshold under which numbers are assumed to be zero */
7585  )
7586 {
7587  assert(expr1 != NULL);
7588  assert(expr2 != NULL);
7589 
7590  if( expr1 == expr2 )
7591  return TRUE;
7592 
7593  if( expr1->op != expr2->op )
7594  return FALSE;
7595 
7596  switch( expr1->op )
7597  {
7598  case SCIP_EXPR_VARIDX:
7599  case SCIP_EXPR_PARAM:
7600  return expr1->data.intval == expr2->data.intval;
7601 
7602  case SCIP_EXPR_CONST:
7603  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps);
7604 
7605  /* operands with two children */
7606  case SCIP_EXPR_PLUS :
7607  case SCIP_EXPR_MINUS :
7608  case SCIP_EXPR_MUL :
7609  case SCIP_EXPR_DIV :
7610  case SCIP_EXPR_MIN :
7611  case SCIP_EXPR_MAX :
7612  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps) && SCIPexprAreEqual(expr1->children[1], expr2->children[1], eps);
7613 
7614  /* operands with one child */
7615  case SCIP_EXPR_SQUARE:
7616  case SCIP_EXPR_SQRT :
7617  case SCIP_EXPR_EXP :
7618  case SCIP_EXPR_LOG :
7619  case SCIP_EXPR_SIN :
7620  case SCIP_EXPR_COS :
7621  case SCIP_EXPR_TAN :
7622  /* case SCIP_EXPR_ERF : */
7623  /* case SCIP_EXPR_ERFI : */
7624  case SCIP_EXPR_ABS :
7625  case SCIP_EXPR_SIGN :
7626  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7627 
7628  case SCIP_EXPR_REALPOWER:
7629  case SCIP_EXPR_SIGNPOWER:
7630  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps) && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7631 
7632  case SCIP_EXPR_INTPOWER:
7633  return expr1->data.intval == expr2->data.intval && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7634 
7635  /* complex operands */
7636  case SCIP_EXPR_SUM :
7637  case SCIP_EXPR_PRODUCT:
7638  {
7639  int i;
7640 
7641  /* @todo sort children and have sorted flag in data? */
7642 
7643  if( expr1->nchildren != expr2->nchildren )
7644  return FALSE;
7645 
7646  for( i = 0; i < expr1->nchildren; ++i )
7647  {
7648  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7649  return FALSE;
7650  }
7651 
7652  return TRUE;
7653  }
7654 
7655  case SCIP_EXPR_LINEAR :
7656  {
7657  SCIP_Real* data1;
7658  SCIP_Real* data2;
7659  int i;
7660 
7661  /* @todo sort children and have sorted flag in data? */
7662 
7663  if( expr1->nchildren != expr2->nchildren )
7664  return FALSE;
7665 
7666  data1 = (SCIP_Real*)expr1->data.data;
7667  data2 = (SCIP_Real*)expr2->data.data;
7668 
7669  /* check if constant and coefficients are equal */
7670  for( i = 0; i < expr1->nchildren + 1; ++i )
7671  if( !EPSEQ(data1[i], data2[i], eps) )
7672  return FALSE;
7673 
7674  /* check if children are equal */
7675  for( i = 0; i < expr1->nchildren; ++i )
7676  {
7677  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7678  return FALSE;
7679  }
7680 
7681  return TRUE;
7682  }
7683 
7684  case SCIP_EXPR_QUADRATIC:
7685  {
7686  SCIP_EXPRDATA_QUADRATIC* data1;
7687  SCIP_EXPRDATA_QUADRATIC* data2;
7688  int i;
7689 
7690  if( expr1->nchildren != expr2->nchildren )
7691  return FALSE;
7692 
7693  data1 = (SCIP_EXPRDATA_QUADRATIC*)expr1->data.data;
7694  data2 = (SCIP_EXPRDATA_QUADRATIC*)expr2->data.data;
7695 
7696  if( data1->nquadelems != data2->nquadelems )
7697  return FALSE;
7698 
7699  if( !EPSEQ(data1->constant, data2->constant, eps) )
7700  return FALSE;
7701 
7702  /* check if linear part is equal */
7703  if( data1->lincoefs != NULL || data2->lincoefs != NULL )
7704  for( i = 0; i < expr1->nchildren; ++i )
7705  {
7706  if( data1->lincoefs == NULL )
7707  {
7708  if( !EPSZ(data2->lincoefs[i], eps) )
7709  return FALSE;
7710  }
7711  else if( data2->lincoefs == NULL )
7712  {
7713  if( !EPSZ(data1->lincoefs[i], eps) )
7714  return FALSE;
7715  }
7716  else if( !EPSEQ(data1->lincoefs[i], data2->lincoefs[i], eps) )
7717  return FALSE;
7718  }
7719 
7720  SCIPexprSortQuadElems(expr1);
7721  SCIPexprSortQuadElems(expr2);
7722 
7723  /* check if quadratic elements are equal */
7724  for( i = 0; i < data1->nquadelems; ++i )
7725  if( data1->quadelems[i].idx1 != data2->quadelems[i].idx1 ||
7726  data1->quadelems[i].idx2 != data2->quadelems[i].idx2 ||
7727  !EPSEQ(data1->quadelems[i].coef, data2->quadelems[i].coef, eps) )
7728  return FALSE;
7729 
7730  /* check if children are equal */
7731  for( i = 0; i < expr1->nchildren; ++i )
7732  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7733  return FALSE;
7734 
7735  return TRUE;
7736  }
7737 
7738  case SCIP_EXPR_POLYNOMIAL:
7739  {
7740  SCIP_EXPRDATA_POLYNOMIAL* data1;
7741  SCIP_EXPRDATA_POLYNOMIAL* data2;
7742  int i;
7743 
7744  if( expr1->nchildren != expr2->nchildren )
7745  return FALSE;
7746 
7747  data1 = (SCIP_EXPRDATA_POLYNOMIAL*)expr1->data.data;
7748  data2 = (SCIP_EXPRDATA_POLYNOMIAL*)expr2->data.data;
7749 
7750  if( data1->nmonomials != data2->nmonomials )
7751  return FALSE;
7752 
7753  if( !EPSEQ(data1->constant, data2->constant, eps) )
7754  return FALSE;
7755 
7756  /* make sure polynomials are sorted */
7757  SCIPexprSortMonomials(expr1);
7758  SCIPexprSortMonomials(expr2);
7759 
7760  /* check if monomials are equal */
7761  for( i = 0; i < data1->nmonomials; ++i )
7762  {
7763  if( !SCIPexprAreMonomialsEqual(data1->monomials[i], data2->monomials[i], eps) )
7764  return FALSE;
7765  }
7766 
7767  /* check if children are equal */
7768  for( i = 0; i < expr1->nchildren; ++i )
7769  {
7770  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7771  return FALSE;
7772  }
7773 
7774  return TRUE;
7775  }
7776 
7777  case SCIP_EXPR_USER:
7778  {
7779  /* @todo could implement this via another user callback */
7780  return FALSE;
7781  }
7782 
7783  case SCIP_EXPR_LAST:
7784  break;
7785  }
7786 
7787  SCIPerrorMessage("this should never happen\n");
7788  SCIPABORT();
7789  return FALSE; /*lint !e527*/
7790 }
7791 
7792 /** aims at simplifying an expression and splitting of a linear expression
7793  *
7794  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
7795  */
7797  BMS_BLKMEM* blkmem, /**< block memory data structure */
7798  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7799  SCIP_EXPR* expr, /**< expression */
7800  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
7801  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
7802  int nvars, /**< number of variables in expression */
7803  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
7804  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
7805  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
7806  )
7807 {
7808  assert(blkmem != NULL);
7809  assert(expr != NULL);
7810  assert(eps >= 0.0);
7811 
7812  SCIPdebugMessage("simplify expression: ");
7813  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7814  SCIPdebugPrintf("\n");
7815 
7817 
7818  SCIPdebugMessage("converted to polynomials: ");
7819  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7820  SCIPdebugPrintf("\n");
7821 
7822  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr, eps, maxexpansionexponent) );
7823 
7824  SCIPdebugMessage("polynomials flattened: ");
7825  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7826  SCIPdebugPrintf("\n");
7827 
7828  if( nlinvars != NULL )
7829  {
7830  /* separate linear part from root polynomial */
7831  SCIP_CALL( exprsimplifySeparateLinearFromPolynomial(blkmem, expr, eps, nvars, nlinvars, linidxs, lincoefs) );
7832 
7833  SCIPdebugMessage("separated linear part: ");
7834  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7835  SCIPdebugPrintf("\n");
7836  }
7837 
7839 
7840  SCIPdebugMessage("converted back from polynomials: ");
7841  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7842  SCIPdebugPrintf("\n");
7843 
7844  return SCIP_OKAY;
7845 }
7846 
7847 /** evaluates an expression w.r.t. given values for children expressions */
7849  SCIP_EXPR* expr, /**< expression */
7850  SCIP_Real* argvals, /**< values for children, can be NULL if the expression has no children */
7851  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression operand is not a variable */
7852  SCIP_Real* param, /**< values for parameters, can be NULL if the expression operand is not a parameter */
7853  SCIP_Real* val /**< buffer to store value */
7854  )
7855 {
7856  assert(expr != NULL);
7857  assert(argvals != NULL || expr->nchildren == 0);
7858 
7859  /* evaluate this expression */
7860  assert( exprOpTable[expr->op].eval != NULL );
7861  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, argvals, varvals, param, val) );
7862 
7863  return SCIP_OKAY;
7864 }
7865 
7866 /** evaluates an expression w.r.t. a point */
7868  SCIP_EXPR* expr, /**< expression */
7869  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression is constant */
7870  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7871  SCIP_Real* val /**< buffer to store value */
7872  )
7873 {
7874  int i;
7876  SCIP_Real* buf;
7877 
7878  /* if many children, get large enough memory to store argument values */
7880  {
7881  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7882  }
7883  else
7884  {
7885  buf = staticbuf;
7886  }
7887 
7888  /* evaluate children */
7889  for( i = 0; i < expr->nchildren; ++i )
7890  {
7891  SCIP_CALL( SCIPexprEval(expr->children[i], varvals, param, &buf[i]) ); /*lint !e644*/
7892  }
7893 
7894  /* evaluate this expression */
7895  assert( exprOpTable[expr->op].eval != NULL );
7896  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, buf, varvals, param, val) );
7897 
7898  /* free memory, if allocated before */
7899  if( staticbuf != buf )
7900  {
7901  BMSfreeMemoryArray(&buf);
7902  }
7903 
7904  return SCIP_OKAY;
7905 }
7906 
7907 /** evaluates an expression w.r.t. given interval values for children expressions */
7909  SCIP_EXPR* expr, /**< expression */
7910  SCIP_Real infinity, /**< value to use for infinity */
7911  SCIP_INTERVAL* argvals, /**< interval values for children, can be NULL if the expression has no children */
7912  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7913  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7914  SCIP_INTERVAL* val /**< buffer to store value */
7915  )
7916 {
7917  assert(expr != NULL);
7918  assert(argvals != NULL || expr->nchildren == 0);
7919 
7920  /* evaluate this expression */
7921  assert( exprOpTable[expr->op].inteval != NULL );
7922  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, argvals, varvals, param, val) );
7923 
7924  return SCIP_OKAY;
7925 }
7926 
7927 /** evaluates an expression w.r.t. an interval */
7929  SCIP_EXPR* expr, /**< expression */
7930  SCIP_Real infinity, /**< value to use for infinity */
7931  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7932  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7933  SCIP_INTERVAL* val /**< buffer to store value */
7934  )
7935 {
7936  int i;
7938  SCIP_INTERVAL* buf;
7939 
7940  /* if many children, get large enough memory to store argument values */
7942  {
7943  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7944  }
7945  else
7946  {
7947  buf = staticbuf;
7948  }
7949 
7950  /* evaluate children */
7951  for( i = 0; i < expr->nchildren; ++i )
7952  {
7953  SCIP_CALL( SCIPexprEvalInt(expr->children[i], infinity, varvals, param, &buf[i]) ); /*lint !e644*/
7954  }
7955 
7956  /* evaluate this expression */
7957  assert( exprOpTable[expr->op].inteval != NULL );
7958  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, buf, varvals, param, val) );
7959 
7960  /* free memory, if allocated before */
7961  if( staticbuf != buf )
7962  {
7963  BMSfreeMemoryArray(&buf);
7964  }
7965 
7966  return SCIP_OKAY;
7967 }
7968 
7969 /** evaluates a user expression w.r.t. given values for children expressions */
7971  SCIP_EXPR* expr, /**< expression */
7972  SCIP_Real* argvals, /**< values for children */
7973  SCIP_Real* val, /**< buffer to store function value */
7974  SCIP_Real* gradient, /**< buffer to store gradient values, or NULL if not requested */
7975  SCIP_Real* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7976  )
7977 {
7978  SCIP_EXPRDATA_USER* exprdata;
7979 
7980  assert(expr != NULL);
7981  assert(expr->op == SCIP_EXPR_USER);
7982  assert(argvals != NULL || expr->nchildren == 0);
7983 
7984  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7985  assert(exprdata->eval != NULL);
7986 
7987  SCIP_CALL( exprdata->eval(exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7988 
7989  return SCIP_OKAY;
7990 }
7991 
7992 /** evaluates a user expression w.r.t. an interval */
7994  SCIP_EXPR* expr, /**< expression */
7995  SCIP_Real infinity, /**< value to use for infinity */
7996  SCIP_INTERVAL* argvals, /**< values for children */
7997  SCIP_INTERVAL* val, /**< buffer to store value */
7998  SCIP_INTERVAL* gradient, /**< buffer to store gradient values, or NULL if not requested */
7999  SCIP_INTERVAL* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
8000  )
8001 {
8002  SCIP_EXPRDATA_USER* exprdata;
8003 
8004  assert(expr != NULL);
8005  assert(expr->op == SCIP_EXPR_USER);
8006  assert(argvals != NULL || expr->nchildren == 0);
8007 
8008  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8009 
8010  if( exprdata->inteval == NULL )
8011  {
8012  int i;
8013 
8014  for( i = 0; i < expr->nchildren; ++i )
8015  SCIPintervalSetEntire(infinity, &argvals[i]); /*lint !e613*/
8016  }
8017  else
8018  {
8019  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
8020  }
8021 
8022  return SCIP_OKAY;
8023 }
8024 
8025 /** internal curvature check method */
8026 static
8028  SCIP_EXPR* expr, /**< expression to check */
8029  SCIP_Real infinity, /**< value to use for infinity */
8030  SCIP_INTERVAL* varbounds, /**< domains of variables */
8031  SCIP_INTERVAL* childbounds, /**< child bounds buffer array */
8032  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
8033  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8034  SCIP_EXPRCURV* childcurv, /**< buffer array for curvature of children */
8035  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
8036  )
8037 {
8038  int i;
8039 
8040  assert(childbounds != NULL);
8041  assert(childcurv != NULL);
8042 
8043  /* check curvature and compute bounds of children
8044  * constant children can be considered as always linear */
8045  for( i = 0; i < expr->nchildren; ++i )
8046  {
8047  SCIP_CALL( SCIPexprCheckCurvature(expr->children[i], infinity, varbounds, param, &childcurv[i], &childbounds[i]) ); /*lint !e644*/
8048  if( childbounds[i].inf == childbounds[i].sup ) /*lint !e777*/
8049  childcurv[i] = SCIP_EXPRCURV_LINEAR;
8050  }
8051 
8052  /* get curvature and bounds of expr */
8053  assert(exprOpTable[expr->op].curv != NULL);
8054  assert(exprOpTable[expr->op].inteval != NULL);
8055 
8056  SCIP_CALL( exprOpTable[expr->op].curv(infinity, expr->data, expr->nchildren, childbounds, childcurv, curv) );
8057  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, childbounds, varbounds, param, bounds) );
8058 
8059  return SCIP_OKAY;
8060 }
8061 
8062 /** tries to determine the curvature type of an expression w.r.t. given variable domains */
8064  SCIP_EXPR* expr, /**< expression to check */
8065  SCIP_Real infinity, /**< value to use for infinity */
8066  SCIP_INTERVAL* varbounds, /**< domains of variables */
8067  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
8068  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8069  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
8070  )
8071 {
8073  SCIP_INTERVAL* childbounds = NULL;
8075  SCIP_EXPRCURV* childcurv = NULL;
8076  SCIP_RETCODE retcode = SCIP_OKAY;
8077 
8078  assert(expr != NULL);
8079  assert(curv != NULL);
8080  assert(bounds != NULL);
8081 
8082  /* if many children, get large enough memory to store argument values */
8084  {
8085  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, expr->nchildren) );
8086  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, expr->nchildren), TERMINATE );
8087  }
8088  else
8089  {
8090  childbounds = childboundsbuf;
8091  childcurv = childcurvbuf;
8092  }
8093 
8094  retcode = doCheckCurvature(expr, infinity, varbounds, childbounds, param, curv, childcurv, bounds);
8095 
8096 TERMINATE:
8097  /* free memory, if allocated before */
8098  if( childboundsbuf != childbounds )
8099  {
8100  BMSfreeMemoryArrayNull(&childcurv);
8101  BMSfreeMemoryArrayNull(&childbounds);
8102  }
8103 
8104  return retcode;
8105 }
8106 
8107 /** under-/overestimates a user expression w.r.t. to given values and bounds for children expressions */
8109  SCIP_EXPR* expr, /**< expression */
8110  SCIP_Real infinity, /**< value to use for infinity */
8111  SCIP_Real* argvals, /**< values for children */
8112  SCIP_INTERVAL* argbounds, /**< bounds for children */
8113  SCIP_Bool overestimate, /**< whether to overestimate the expression */
8114  SCIP_Real* coeffs, /**< buffer to store the linear coefficients for each child expression that gives a valid under-/overestimator */
8115  SCIP_Real* constant, /**< buffer to store the constant value of the linear under-/overestimator */
8116  SCIP_Bool* success /**< buffer to store whether an estimator was successfully computed */
8117  )
8118 {
8119  SCIP_EXPRDATA_USER* exprdata;
8120 
8121  assert(expr != NULL);
8122  assert(expr->op == SCIP_EXPR_USER);
8123  assert(argvals != NULL || expr->nchildren == 0);
8124  assert(argbounds != NULL || expr->nchildren == 0);
8125 
8126  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8127 
8128  if( exprdata->estimate != NULL )
8129  {
8130  SCIP_CALL( exprdata->estimate(infinity, exprdata->userdata, expr->nchildren, argvals, argbounds, overestimate, coeffs, constant, success ) );
8131  }
8132  else
8133  {
8134  *success = FALSE;
8135  }
8136 
8137  return SCIP_OKAY;
8138 }
8139 
8140 /** substitutes variables (SCIP_EXPR_VARIDX) by expressions
8141  *
8142  * Note that only the children of the given expr are checked!
8143  * A variable with index i is replaced by a copy of substexprs[i], if the latter is not NULL.
8144  * If substexprs[i] == NULL, then the variable expression i is not touched.
8145  */
8147  BMS_BLKMEM* blkmem, /**< block memory data structure */
8148  SCIP_EXPR* expr, /**< expression, which of the children may be replaced */
8149  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8150  )
8151 {
8152  int i;
8153 
8154  assert(blkmem != NULL);
8155  assert(expr != NULL);
8156  assert(substexprs != NULL);
8157 
8158  for( i = 0; i < expr->nchildren; ++i )
8159  {
8160  if( expr->children[i]->op == SCIP_EXPR_VARIDX )
8161  {
8162  int varidx;
8163  varidx = expr->children[i]->data.intval;
8164 
8165  assert(varidx >= 0);
8166  if( substexprs[varidx] != NULL )
8167  {
8168  /* replace child i by copy of substexprs[expr->children[i]->opdata.intval] */
8169  SCIPexprFreeDeep(blkmem, &expr->children[i]);
8170  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[i], substexprs[varidx]) );
8171  }
8172  }
8173  else
8174  {
8175  /* call recursively */
8176  SCIP_CALL( SCIPexprSubstituteVars(blkmem, expr->children[i], substexprs) );
8177  }
8178  }
8179 
8180  return SCIP_OKAY;
8181 }
8182 
8183 /** updates variable indices in expression tree */
8185  SCIP_EXPR* expr, /**< expression to update */
8186  int* newindices /**< new indices of variables */
8187  )
8188 {
8189  int i;
8190 
8191  assert(expr != NULL);
8192  assert(newindices != NULL);
8193 
8194  if( expr->op == SCIP_EXPR_VARIDX )
8195  {
8196  expr->data.intval = newindices[expr->data.intval];
8197  assert(expr->data.intval >= 0);
8198  }
8199 
8200  for( i = 0; i < expr->nchildren; ++i )
8201  SCIPexprReindexVars(expr->children[i], newindices);
8202 }
8203 
8204 /** updates parameter indices in expression tree */
8206  SCIP_EXPR* expr, /**< expression to update */
8207  int* newindices /**< new indices of variables */
8208  )
8209 {
8210  int i;
8211 
8212  assert(expr != NULL);
8213  assert(newindices != NULL);
8214 
8215  if( expr->op == SCIP_EXPR_PARAM )
8216  {
8217  expr->data.intval = newindices[expr->data.intval];
8218  assert(expr->data.intval >= 0);
8219  }
8220 
8221  for( i = 0; i < expr->nchildren; ++i )
8222  SCIPexprReindexParams(expr->children[i], newindices);
8223 }
8224 
8225 /** prints an expression */
8227  SCIP_EXPR* expr, /**< expression */
8228  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8229  FILE* file, /**< file for printing, or NULL for stdout */
8230  const char** varnames, /**< names of variables, or NULL for default names */
8231  const char** paramnames, /**< names of parameters, or NULL for default names */
8232  SCIP_Real* paramvals /**< values of parameters, or NULL for not printing */
8233  )
8234 {
8235  assert( expr != NULL );
8236 
8237  switch( expr->op )
8238  {
8239  /* @Note: 'expr->data.intval' is either between 0 and number of variables-1, if it uses the varnames array, or
8240  * between 0 and number of params in the expression tree, if it uses the paramnames array
8241  * because, here, we cannot get the values above we cannot assert them
8242  */
8243  case SCIP_EXPR_VARIDX:
8244  if( varnames != NULL )
8245  {
8246  assert(varnames[expr->data.intval] != NULL);
8247  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", varnames[expr->data.intval]);
8248  }
8249  else
8250  {
8251  SCIPmessageFPrintInfo(messagehdlr, file, "var%d", expr->data.intval);
8252  }
8253  break;
8254 
8255  case SCIP_EXPR_PARAM:
8256  if( paramnames != NULL )
8257  {
8258  assert(paramnames[expr->data.intval] != NULL);
8259  SCIPmessageFPrintInfo(messagehdlr, file, "%s", paramnames[expr->data.intval]);
8260  }
8261  else
8262  {
8263  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", expr->data.intval );
8264  }
8265  if( paramvals != NULL )
8266  {
8267  SCIPmessageFPrintInfo(messagehdlr, file, "[%g]", paramvals[expr->data.intval] );
8268  }
8269  break;
8270 
8271  case SCIP_EXPR_CONST:
8272  if (expr->data.dbl < 0.0 )
8273  SCIPmessageFPrintInfo(messagehdlr, file, "(%g)", expr->data.dbl );
8274  else
8275  SCIPmessageFPrintInfo(messagehdlr, file, "%g", expr->data.dbl );
8276  break;
8277 
8278  case SCIP_EXPR_PLUS:
8279  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8280  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8281  SCIPmessageFPrintInfo(messagehdlr, file, " + ");
8282  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8283  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8284  break;
8285 
8286  case SCIP_EXPR_MINUS:
8287  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8288  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8289  SCIPmessageFPrintInfo(messagehdlr, file, " - ");
8290  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8291  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8292  break;
8293 
8294  case SCIP_EXPR_MUL:
8295  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8296  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8297  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8298  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8299  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8300  break;
8301 
8302  case SCIP_EXPR_DIV:
8303  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8304  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8305  SCIPmessageFPrintInfo(messagehdlr, file, " / ");
8306  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8307  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8308  break;
8309 
8310  case SCIP_EXPR_REALPOWER:
8311  case SCIP_EXPR_SIGNPOWER:
8312  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8313  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8314  SCIPmessageFPrintInfo(messagehdlr, file, ", %g)", expr->data.dbl);
8315  break;
8316 
8317  case SCIP_EXPR_INTPOWER:
8318  SCIPmessageFPrintInfo(messagehdlr, file, "power(");
8319  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8320  SCIPmessageFPrintInfo(messagehdlr, file, ", %d)", expr->data.intval);
8321  break;
8322 
8323  case SCIP_EXPR_SQUARE:
8324  case SCIP_EXPR_SQRT:
8325  case SCIP_EXPR_EXP:
8326  case SCIP_EXPR_LOG:
8327  case SCIP_EXPR_SIN:
8328  case SCIP_EXPR_COS:
8329  case SCIP_EXPR_TAN:
8330  /* case SCIP_EXPR_ERF: */
8331  /* case SCIP_EXPR_ERFI: */
8332  case SCIP_EXPR_MIN:
8333  case SCIP_EXPR_MAX:
8334  case SCIP_EXPR_ABS:
8335  case SCIP_EXPR_SIGN:
8336  {
8337  int i;
8338 
8339  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8340 
8341  for( i = 0; i < expr->nchildren; ++i )
8342  {
8343  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8344  if( i + 1 < expr->nchildren )
8345  {
8346  SCIPmessageFPrintInfo(messagehdlr, file, ", ");
8347  }
8348  }
8349 
8350  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8351  break;
8352  }
8353 
8354  case SCIP_EXPR_SUM:
8355  case SCIP_EXPR_PRODUCT:
8356  {
8357  switch( expr->nchildren )
8358  {
8359  case 0:
8360  SCIPmessageFPrintInfo(messagehdlr, file, expr->op == SCIP_EXPR_SUM ? "0" : "1");
8361  break;
8362  case 1:
8363  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8364  break;
8365  default:
8366  {
8367  int i;
8368  char opstr[SCIP_MAXSTRLEN];
8369 
8370  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8371  for( i = 0; i < expr->nchildren; ++i )
8372  {
8373  if( i > 0 )
8374  {
8375  (void) SCIPsnprintf(opstr, SCIP_MAXSTRLEN, "%s", expr->op == SCIP_EXPR_SUM ? " + " : " * ");
8376  SCIPmessageFPrintInfo(messagehdlr, file, opstr);
8377  }
8378  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8379  }
8380  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8381  }
8382  }
8383  break;
8384  }
8385 
8386  case SCIP_EXPR_LINEAR:
8387  {
8388  SCIP_Real constant;
8389  int i;
8390 
8391  constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
8392 
8393  if( expr->nchildren == 0 )
8394  {
8395  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", constant);
8396  break;
8397  }
8398 
8399  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8400 
8401  if( constant != 0.0 )
8402  {
8403  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", constant);
8404  }
8405 
8406  for( i = 0; i < expr->nchildren; ++i )
8407  {
8408  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", ((SCIP_Real*)expr->data.data)[i]);
8409  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8410  }
8411 
8412  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8413  break;
8414  }
8415 
8416  case SCIP_EXPR_QUADRATIC:
8417  {
8418  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
8419  int i;
8420 
8421  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
8422  assert(quadraticdata != NULL);
8423 
8424  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8425 
8426  if( quadraticdata->constant != 0.0 )
8427  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->constant);
8428 
8429  if( quadraticdata->lincoefs != NULL )
8430  for( i = 0; i < expr->nchildren; ++i )
8431  {
8432  if( quadraticdata->lincoefs[i] == 0.0 )
8433  continue;
8434  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->lincoefs[i]);
8435  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8436  }
8437 
8438  for( i = 0; i < quadraticdata->nquadelems; ++i )
8439  {
8440  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->quadelems[i].coef);
8441  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
8442  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
8443  {
8444  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
8445  }
8446  else
8447  {
8448  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8449  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
8450  }
8451  }
8452 
8453  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8454  break;
8455  }
8456 
8457  case SCIP_EXPR_POLYNOMIAL:
8458  {
8459  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
8460  SCIP_EXPRDATA_MONOMIAL* monomialdata;
8461  int i;
8462  int j;
8463 
8464  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8465 
8466  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
8467  assert(polynomialdata != NULL);
8468 
8469  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
8470  {
8471  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", polynomialdata->constant);
8472  }
8473 
8474  for( i = 0; i < polynomialdata->nmonomials; ++i )
8475  {
8476  monomialdata = polynomialdata->monomials[i];
8477  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g", monomialdata->coef);
8478 
8479  for( j = 0; j < monomialdata->nfactors; ++j )
8480  {
8481  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8482 
8483  SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
8484  if( monomialdata->exponents[j] < 0.0 )
8485  {
8486  SCIPmessageFPrintInfo(messagehdlr, file, "^(%.15g)", monomialdata->exponents[j]);
8487  }
8488  else if( monomialdata->exponents[j] != 1.0 )
8489  {
8490  SCIPmessageFPrintInfo(messagehdlr, file, "^%.15g", monomialdata->exponents[j]);
8491  }
8492  }
8493  }
8494 
8495  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8496  break;
8497  }
8498 
8499  case SCIP_EXPR_USER:
8500  {
8501  SCIP_EXPRDATA_USER* exprdata;
8502  int i;
8503 
8504  exprdata = (SCIP_EXPRDATA_USER*)expr->data.data;
8505  assert(exprdata != NULL);
8506 
8507  if( exprdata->print != NULL )
8508  {
8509  exprdata->print(exprdata->userdata, messagehdlr, file);
8510  }
8511  else
8512  {
8513  SCIPmessageFPrintInfo(messagehdlr, file, "user");
8514  }
8515 
8516  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8517  for( i = 0; i < expr->nchildren; ++i )
8518  {
8519  if( i > 0 )
8520  {
8521  SCIPmessageFPrintInfo(messagehdlr, file, ",");
8522  }
8523  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8524  }
8525  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8526 
8527  break;
8528  }
8529 
8530  case SCIP_EXPR_LAST:
8531  {
8532  SCIPerrorMessage("invalid expression\n");
8533  SCIPABORT();
8534  }
8535  }
8536 }
8537 
8538 /** parses an expression from a string */
8540  BMS_BLKMEM* blkmem, /**< block memory data structure */
8541  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8542  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
8543  const char* str, /**< pointer to the string to be parsed */
8544  const char* lastchar, /**< pointer to the last char of str that should be parsed */
8545  int* nvars, /**< buffer to store number of variables */
8546  int* varnames, /**< buffer to store variable names, prefixed by index (as int) */
8547  int varnameslength /**< length of the varnames buffer array */
8548  )
8549 {
8550  SCIP_HASHTABLE* vartable;
8551  SCIP_RETCODE retcode;
8552 
8553  assert(blkmem != NULL);
8554  assert(expr != NULL);
8555  assert(str != NULL);
8556  assert(lastchar != NULL);
8557  assert(nvars != NULL);
8558  assert(varnames != NULL);
8559 
8560  *nvars = 0;
8561 
8562  /* create a hash table for variable names and corresponding expression index
8563  * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
8564  */
8565  SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString,
8566  SCIPhashKeyValString, NULL) );
8567 
8568  retcode = exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames,
8569  &varnameslength, vartable, 0);
8570 
8571  SCIPhashtableFree(&vartable);
8572 
8573  return retcode;
8574 }
8575 
8576 
8577 /**@} */
8578 
8579 /**@name Expression tree methods */
8580 /**@{ */
8581 
8582 /* In debug mode, the following methods are implemented as function calls to ensure
8583  * type validity.
8584  * In optimized mode, the methods are implemented as defines to improve performance.
8585  * However, we want to have them in the library anyways, so we have to undef the defines.
8586  */
8587 
8588 #undef SCIPexprtreeGetRoot
8589 #undef SCIPexprtreeGetNVars
8590 #undef SCIPexprtreeGetNParams
8591 #undef SCIPexprtreeGetParamVals
8592 #undef SCIPexprtreeSetParamVal
8593 #undef SCIPexprtreeGetInterpreterData
8594 #undef SCIPexprtreeSetInterpreterData
8595 #undef SCIPexprtreeFreeInterpreterData
8596 #undef SCIPexprtreeHasParam
8597 #undef SCIPexprtreeGetMaxDegree
8598 #undef SCIPexprtreeEval
8599 #undef SCIPexprtreeEvalInt
8600 #undef SCIPexprtreePrint
8601 
8602 /** returns root expression of an expression tree */
8604  SCIP_EXPRTREE* tree /**< expression tree */
8605  )
8606 {
8607  assert(tree != NULL);
8608 
8609  return tree->root;
8610 }
8611 
8612 /** returns number of variables in expression tree */
8614  SCIP_EXPRTREE* tree /**< expression tree */
8615  )
8616 {
8617  assert(tree != NULL);
8618 
8619  return tree->nvars;
8620 }
8621 
8622 /** returns number of parameters in expression tree */
8624  SCIP_EXPRTREE* tree /**< expression tree */
8625  )
8626 {
8627  assert(tree != NULL);
8628 
8629  return tree->nparams;
8630 }
8631 
8632 /** returns values of parameters or NULL if none */
8634  SCIP_EXPRTREE* tree /**< expression tree */
8635  )
8636 {
8637  assert(tree != NULL);
8638 
8639  return tree->params;
8640 }
8641 
8642 /** sets value of a single parameter in expression tree */
8644  SCIP_EXPRTREE* tree, /**< expression tree */
8645  int paramidx, /**< index of parameter */
8646  SCIP_Real paramval /**< new value of parameter */
8647  )
8648 {
8649  assert(tree != NULL);
8650  assert(paramidx >= 0);
8651  assert(paramidx < tree->nparams);
8652  assert(tree->params != NULL);
8653 
8654  tree->params[paramidx] = paramval;
8655 }
8656 
8657 /** gets data of expression tree interpreter, or NULL if not set */
8659  SCIP_EXPRTREE* tree /**< expression tree */
8660  )
8661 {
8662  assert(tree != NULL);
8663 
8664  return tree->interpreterdata;
8665 }
8666 
8667 /** sets data of expression tree interpreter */
8669  SCIP_EXPRTREE* tree, /**< expression tree */
8670  SCIP_EXPRINTDATA* interpreterdata /**< expression interpreter data */
8671  )
8672 {
8673  assert(tree != NULL);
8674  assert(interpreterdata != NULL);
8675  assert(tree->interpreterdata == NULL);
8676 
8677  tree->interpreterdata = interpreterdata;
8678 }
8679 
8680 /** frees data of expression tree interpreter, if any */
8682  SCIP_EXPRTREE* tree /**< expression tree */
8683  )
8684 {
8685  if( tree->interpreterdata != NULL )
8686  {
8688  assert(tree->interpreterdata == NULL);
8689  }
8690 
8691  return SCIP_OKAY;
8692 }
8693 
8694 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
8696  SCIP_EXPRTREE* tree /**< expression tree */
8697  )
8698 {
8699  assert(tree != NULL);
8700 
8701  return SCIPexprHasParam(tree->root);
8702 }
8703 
8704 /** Gives maximal degree of expression in expression tree.
8705  *
8706  * If constant expression, gives 0,
8707  * if linear expression, gives 1,
8708  * if polynomial expression, gives its maximal degree,
8709  * otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8710  */
8712  SCIP_EXPRTREE* tree, /**< expression tree */
8713  int* maxdegree /**< buffer to store maximal degree */
8714  )
8715 {
8716  assert(tree != NULL);
8717 
8718  SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8719 
8720  return SCIP_OKAY;
8721 }
8722 
8723 /** evaluates an expression tree w.r.t. a point */
8725  SCIP_EXPRTREE* tree, /**< expression tree */
8726  SCIP_Real* varvals, /**< values for variables */
8727  SCIP_Real* val /**< buffer to store expression tree value */
8728  )
8729 {
8730  assert(tree != NULL);
8731  assert(varvals != NULL || tree->nvars == 0);
8732  assert(val != NULL);
8733 
8734  SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8735 
8736  return SCIP_OKAY;
8737 }
8738 
8739 /** evaluates an expression tree w.r.t. an interval */
8741  SCIP_EXPRTREE* tree, /**< expression tree */
8742  SCIP_Real infinity, /**< value for infinity */
8743  SCIP_INTERVAL* varvals, /**< intervals for variables */
8744  SCIP_INTERVAL* val /**< buffer to store expression tree value */
8745  )
8746 {
8747  assert(tree != NULL);
8748  assert(varvals != NULL || tree->nvars == 0);
8749  assert(val != NULL);
8750 
8751  SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8752 
8753  return SCIP_OKAY;
8754 }
8755 
8756 /** prints an expression tree */
8758  SCIP_EXPRTREE* tree, /**< expression tree */
8759  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8760  FILE* file, /**< file for printing, or NULL for stdout */
8761  const char** varnames, /**< names of variables, or NULL for default names */
8762  const char** paramnames /**< names of parameters, or NULL for default names */
8763  )
8764 {
8765  assert(tree != NULL);
8766 
8767  SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8768 }
8769 
8770 
8771 /** creates an expression tree */
8773  BMS_BLKMEM* blkmem, /**< block memory data structure */
8774  SCIP_EXPRTREE** tree, /**< buffer to store address of created expression tree */
8775  SCIP_EXPR* root, /**< pointer to root expression, not copied deep !, can be NULL */
8776  int nvars, /**< number of variables in variable mapping */
8777  int nparams, /**< number of parameters in expression */
8778  SCIP_Real* params /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8779  )
8780 {
8781  assert(blkmem != NULL);
8782  assert(tree != NULL);
8783 
8784  SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8785 
8786  (*tree)->blkmem = blkmem;
8787  (*tree)->root = root;
8788  (*tree)->nvars = nvars;
8789  (*tree)->vars = NULL;
8790  (*tree)->nparams = nparams;
8791  (*tree)->interpreterdata = NULL;
8792 
8793  if( params != NULL )
8794  {
8795  assert(nparams > 0);
8796  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8797  }
8798  else if( nparams > 0 )
8799  {
8800  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8801  BMSclearMemoryArray((*tree)->params, nparams);
8802  }
8803  else
8804  {
8805  assert(nparams == 0);
8806  (*tree)->params = NULL;
8807  }
8808 
8809  return SCIP_OKAY;
8810 }
8811 
8812 /** copies an expression tree */
8814  BMS_BLKMEM* blkmem, /**< block memory that should be used in new expression tree */
8815  SCIP_EXPRTREE** targettree, /**< buffer to store address of copied expression tree */
8816  SCIP_EXPRTREE* sourcetree /**< expression tree to copy */
8817  )
8818 {
8819  assert(blkmem != NULL);
8820  assert(targettree != NULL);
8821  assert(sourcetree != NULL);
8822 
8823  /* copy expression tree "header" */
8824  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8825 
8826  /* we may have a new block memory; and we do not want to keep the others interpreter data */
8827  (*targettree)->blkmem = blkmem;
8828  (*targettree)->interpreterdata = NULL;
8829 
8830  /* copy variables, if any */
8831  if( sourcetree->vars != NULL )
8832  {
8833  assert(sourcetree->nvars > 0);
8834 
8835  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8836  }
8837 
8838  /* copy parameters, if any */
8839  if( sourcetree->params != NULL )
8840  {
8841  assert(sourcetree->nparams > 0);
8842 
8843  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8844  }
8845 
8846  /* copy expression */
8847  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8848 
8849  return SCIP_OKAY;
8850 }
8851 
8852 /** frees an expression tree */
8854  SCIP_EXPRTREE** tree /**< pointer to expression tree that is freed */
8855  )
8856 {
8857  assert( tree != NULL);
8858  assert(*tree != NULL);
8859 
8861 
8862  if( (*tree)->root != NULL )
8863  {
8864  SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8865  assert((*tree)->root == NULL);
8866  }
8867 
8868  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars, (*tree)->nvars );
8869  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8870 
8871  BMSfreeBlockMemory((*tree)->blkmem, tree);
8872 
8873  return SCIP_OKAY;
8874 }
8875 
8876 /** sets number and values of all parameters in expression tree */
8878  SCIP_EXPRTREE* tree, /**< expression tree */
8879  int nparams, /**< number of parameters */
8880  SCIP_Real* paramvals /**< values of parameters, can be NULL if nparams == 0 */
8881  )
8882 {
8883  assert(tree != NULL);
8884  assert(paramvals != NULL || nparams == 0);
8885 
8886  if( nparams == 0 )
8887  {
8888  BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8889  }
8890  else if( tree->params != NULL )
8891  {
8892  SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8893  BMScopyMemoryArray(tree->params, paramvals, nparams);
8894  }
8895  else
8896  {
8897  SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8898  }
8899 
8900  tree->nparams = nparams;
8901  assert(tree->params != NULL || tree->nparams == 0);
8902 
8903  return SCIP_OKAY;
8904 }
8905 
8906 
8907 /** gives the number of usages for each variable in the expression tree */
8909  SCIP_EXPRTREE* tree, /**< expression tree */
8910  int* varsusage /**< array where to store for each variable how often it is used in the tree */
8911  )
8912 {
8913  assert(tree != NULL);
8914  assert(varsusage != NULL);
8915 
8916  if( tree->nvars == 0 )
8917  return;
8918 
8919  BMSclearMemoryArray(varsusage, tree->nvars);
8920  SCIPexprGetVarsUsage(tree->root, varsusage);
8921 }
8922 
8923 /** aims at simplifying an expression and splitting of a linear expression
8924  *
8925  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
8926  */
8928  SCIP_EXPRTREE* tree, /**< expression tree */
8929  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8930  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
8931  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8932  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8933  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8934  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
8935  )
8936 {
8937 #ifndef NDEBUG
8938  SCIP_RANDNUMGEN* randnumgen;
8939  SCIP_Real* testx;
8940  SCIP_Real testval_before;
8941  SCIP_Real testval_after;
8942  int i;
8943 #endif
8944 
8945  assert(tree != NULL);
8946 
8947 #ifndef NDEBUG
8948  SCIP_CALL( SCIPrandomCreate(&randnumgen, tree->blkmem, 42) );
8949 
8950  SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) ); /*lint !e666*/
8951  for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8952  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
8953  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8954 
8955  SCIPrandomFree(&randnumgen, tree->blkmem);
8956 #endif
8957 
8958  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8959  SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8960 
8961 #ifndef NDEBUG
8962  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8963  if( nlinvars != NULL && testval_before == testval_before ) /*lint !e777*/
8964  for( i = 0; i < *nlinvars; ++i )
8965  testval_after += lincoefs[i] * testx[linidxs[i]];
8966  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
8967  BMSfreeMemoryArray(&testx);
8968 #endif
8969 
8970  /* removing something from the the tree may invalidate the interpreter data */
8971  if( nlinvars != NULL && *nlinvars > 0 )
8973 
8974  return SCIP_OKAY;
8975 }
8976 
8977 /** adds an expression to the root expression of the tree
8978  *
8979  * 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.
8980  * If no root existed yet, then the root is set to the given expression (or a copy of it).
8981  */
8983  SCIP_EXPRTREE* tree, /**< expression tree */
8984  SCIP_EXPR* expr, /**< expression to add to tree */
8985  SCIP_Bool copyexpr /**< whether expression should be copied */
8986  )
8987 {
8988  assert(tree != NULL);
8989 
8990  /* adding something to the tree may invalidate the interpreter data */
8992 
8993  if( copyexpr )
8994  {
8995  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &expr, expr) );
8996  }
8997 
8998  if( tree->root == NULL )
8999  {
9000  tree->root = expr;
9001  }
9002  else
9003  {
9004  SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
9005  }
9006 
9007  return SCIP_OKAY;
9008 }
9009 
9010 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
9012  SCIP_EXPRTREE* tree, /**< expression tree */
9013  SCIP_Real infinity, /**< value for infinity */
9014  SCIP_INTERVAL* varbounds, /**< domains of variables */
9015  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
9016  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression, or NULL if not needed */
9017  )
9018 {
9019  SCIP_INTERVAL exprbounds;
9020 
9021  assert(tree != NULL);
9022 
9023  if( tree->root == NULL )
9024  {
9025  *curv = SCIP_EXPRCURV_LINEAR;
9026 
9027  if( bounds != NULL )
9028  SCIPintervalSet(bounds, 0.0);
9029 
9030  return SCIP_OKAY;
9031  }
9032 
9033  SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
9034 
9035  if( bounds != NULL )
9036  *bounds = exprbounds;
9037 
9038  return SCIP_OKAY;
9039 }
9040 
9041 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
9042  *
9043  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL.
9044  * If substexprs[i] == NULL, then the variable expression i is not touched.
9045  */
9047  SCIP_EXPRTREE* tree, /**< expression tree */
9048  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
9049  )
9050 {
9051  assert(tree != NULL);
9052 
9053  if( tree->root == NULL )
9054  return SCIP_OKAY;
9055 
9056  if( tree->root->op == SCIP_EXPR_VARIDX )
9057  {
9058  int varidx;
9059 
9060  varidx = tree->root->data.intval;
9061  assert(varidx >= 0);
9062  if( substexprs[varidx] != NULL )
9063  {
9064  /* substitute root expression */
9065  SCIPexprFreeDeep(tree->blkmem, &tree->root);
9066  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
9067  }
9068  }
9069  else
9070  {
9071  /* check children (and grandchildren and so on...) of root expression */
9072  SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
9073  }
9074 
9075  /* substitution of variables should invalidate interpreter data */
9077 
9078  return SCIP_OKAY;
9079 }
9080 
9081 /**@} */
9082 
9083 /**@name Quadratic element methods */
9084 /**@{ */
9085 
9086 /** comparing two quadratic elements
9087  *
9088  * 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
9089  */
9090 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
9091 
9092 /** swaps two quadratic elements */
9093 #define QUADELEMS_SWAP(x,y) \
9094  { \
9095  SCIP_QUADELEM temp = x; \
9096  x = y; \
9097  y = temp; \
9098  }
9099 
9100 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
9101 static
9103  SCIP_QUADELEM* elems, /**< array to be sorted */
9104  int start, /**< starting index */
9105  int end /**< ending index */
9106  )
9107 {
9108  assert(start <= end);
9109 
9110  /* use quick sort for long lists */
9111  while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
9112  {
9113  SCIP_QUADELEM pivotkey;
9114  int lo;
9115  int hi;
9116  int mid;
9117 
9118  /* select pivot element */
9119  mid = (start+end)/2;
9120  pivotkey = elems[mid];
9121 
9122  /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
9123  lo = start;
9124  hi = end;
9125  for( ;; )
9126  {
9127  while( lo < end && QUADELEMS_ISBETTER(elems[lo], pivotkey) )
9128  lo++;
9129  while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
9130  hi--;
9131 
9132  if( lo >= hi )
9133  break;
9134 
9135  QUADELEMS_SWAP(elems[lo], elems[hi]);
9136 
9137  lo++;
9138  hi--;
9139  }
9140  assert(hi == lo-1 || hi == start);
9141 
9142  /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
9143  while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
9144  lo++;
9145 
9146  /* make sure that we have at least one element in the smaller partition */
9147  if( lo == start )
9148  {
9149  /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
9150  assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
9151  assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
9152  QUADELEMS_SWAP(elems[lo], elems[mid]);
9153  lo++;
9154  }
9155 
9156  /* sort the smaller partition by a recursive call, sort the larger part without recursion */
9157  if( hi - start <= end - lo )
9158  {
9159  /* sort [start,hi] with a recursive call */
9160  if( start < hi )
9161  quadelemsQuickSort(elems, start, hi);
9162 
9163  /* now focus on the larger part [lo,end] */
9164  start = lo;
9165  }
9166  else
9167  {
9168  /* sort [lo,end] with a recursive call */
9169  if( lo < end )
9170  quadelemsQuickSort(elems, lo, end);
9171 
9172  /* now focus on the larger part [start,hi] */
9173  end = hi;
9174  }
9175  }
9176 
9177  /* use shell sort on the remaining small list */
9178  if( end - start >= 1 )
9179  {
9180  static const int incs[3] = {1, 5, 19}; /* sequence of increments */
9181  int k;
9182 
9183  for( k = 2; k >= 0; --k )
9184  {
9185  int h;
9186  int i;
9187 
9188  for( h = incs[k], i = h + start; i <= end; ++i )
9189  {
9190  int j;
9191  SCIP_QUADELEM tempkey = elems[i];
9192 
9193  j = i;
9194  while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
9195  {
9196  elems[j] = elems[j-h];
9197  j -= h;
9198  }
9199 
9200  elems[j] = tempkey;
9201  }
9202  }
9203  }
9204 }
9205 
9206 /** sorts an array of quadratic elements
9207  *
9208  * The elements are sorted such that the first index is increasing and
9209  * such that among elements with the same first index, the second index is increasing.
9210  * For elements with same first and second index, the order is not defined.
9211  */
9213  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9214  int nquadelems /**< number of quadratic elements */
9215  )
9216 {
9217  if( nquadelems == 0 )
9218  return;
9219 
9220 #ifndef NDEBUG
9221  {
9222  int i;
9223  for( i = 0; i < nquadelems; ++i )
9224  assert(quadelems[i].idx1 <= quadelems[i].idx2);
9225  }
9226 #endif
9227 
9228  quadelemsQuickSort(quadelems, 0, nquadelems-1);
9229 }
9230 
9231 /** Finds an index pair in a sorted array of quadratic elements.
9232  *
9233  * If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
9234  * 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.
9235  * Assumes that idx1 <= idx2.
9236  */
9238  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9239  int idx1, /**< index of first variable in element to search for */
9240  int idx2, /**< index of second variable in element to search for */
9241  int nquadelems, /**< number of quadratic elements in array */
9242  int* pos /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
9243  )
9244 {
9245  int left;
9246  int right;
9247 
9248  assert(quadelems != NULL || nquadelems == 0);
9249  assert(idx1 <= idx2);
9250 
9251  if( nquadelems == 0 )
9252  {
9253  if( pos != NULL )
9254  *pos = 0;
9255  return FALSE;
9256  }
9257 
9258  left = 0;
9259  right = nquadelems - 1;
9260  while( left <= right )
9261  {
9262  int middle;
9263 
9264  middle = (left+right)/2;
9265  assert(0 <= middle && middle < nquadelems);
9266 
9267  if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) ) /*lint !e613*/
9268  right = middle - 1;
9269  else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) ) /*lint !e613*/
9270  left = middle + 1;
9271  else
9272  {
9273  if( pos != NULL )
9274  *pos = middle;
9275  return TRUE;
9276  }
9277  }
9278  assert(left == right+1);
9279 
9280  if( pos != NULL )
9281  *pos = left;
9282  return FALSE;
9283 }
9284 
9285 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
9286  *
9287  * Assumes that elements have been sorted before.
9288  */
9290  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9291  int nquadelems, /**< number of quadratic elements */
9292  int* nquadelemsnew /**< pointer to store new (reduced) number of quadratic elements */
9293  )
9294 {
9295  int i;
9296  int next;
9297 
9298  assert(quadelems != NULL);
9299  assert(nquadelemsnew != NULL);
9300  assert(nquadelems >= 0);
9301 
9302  i = 0;
9303  next = 0;
9304  while( next < nquadelems )
9305  {
9306  /* assert that array is sorted */
9307  assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
9308  (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
9309 
9310  /* skip elements with coefficient 0.0 */
9311  if( quadelems[next].coef == 0.0 )
9312  {
9313  ++next;
9314  continue;
9315  }
9316 
9317  /* if next element has same index as previous one, add it to the previous one */
9318  if( i >= 1 &&
9319  quadelems[i-1].idx1 == quadelems[next].idx1 &&
9320  quadelems[i-1].idx2 == quadelems[next].idx2 )
9321  {
9322  quadelems[i-1].coef += quadelems[next].coef;
9323  ++next;
9324  continue;
9325  }
9326 
9327  /* otherwise, move next element to current position */
9328  quadelems[i] = quadelems[next];
9329  ++i;
9330  ++next;
9331  }
9332  assert(next == nquadelems);
9333 
9334  /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
9335  *nquadelemsnew = i;
9336 }
9337 
9338 /**@} */
9339 
9340 /**@name Expression graph node private methods */
9341 /**@{ */
9342 
9343 /** adds a parent to an expression graph node */
9344 static
9346  BMS_BLKMEM* blkmem, /**< block memory */
9347  SCIP_EXPRGRAPHNODE* node, /**< expression graph node where to add a parent */
9348  SCIP_EXPRGRAPHNODE* parent /**< parent node */
9349  )
9350 {
9351  assert(blkmem != NULL);
9352  assert(node != NULL);
9353  assert(node->depth >= 0);
9354  assert(node->pos >= 0);
9355  assert(parent != NULL);
9356  assert(parent->depth >= 0);
9357  assert(parent->pos >= 0);
9358  assert(parent->depth > node->depth); /* a parent node need to have larger depth */
9359 
9360  ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
9361  assert(node->nparents < node->parentssize);
9362 
9363  node->parents[node->nparents] = parent;
9364  ++node->nparents;
9365 
9366  /* update sorted flag */
9367  node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (exprgraphnodecomp((void*)node->parents[node->nparents-2], (void*)parent) <= 0));
9368 
9369  return SCIP_OKAY;
9370 }
9371 
9372 /** ensures that array of parents in a node is sorted */
9373 static
9375  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
9376  )
9377 {
9378  assert(node != NULL);
9379 
9380  if( node->parentssorted )
9381  {
9382 #ifndef NDEBUG
9383  int i;
9384  for( i = 1; i < node->nparents; ++i )
9385  assert(exprgraphnodecomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
9386 #endif
9387  return;
9388  }
9389 
9390  SCIPsortPtr((void**)node->parents, exprgraphnodecomp, node->nparents);
9391 
9392  node->parentssorted = TRUE;
9393 }
9394 
9395 /** removes a parent from an expression graph node
9396  *
9397  * If the node is not used and has no other parents, then it is freed.
9398  */
9399 static
9401  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9402  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to remove a parent, *node will be set to NULL */
9403  SCIP_EXPRGRAPHNODE* parent /**< parent node to remove */
9404  )
9405 {
9406  SCIP_EXPRGRAPHNODE* node_;
9407  int pos;
9408 
9409  assert(exprgraph != NULL);
9410  assert(node != NULL);
9411  assert(*node != NULL);
9412  assert((*node)->depth >= 0);
9413  assert((*node)->pos >= 0);
9414  assert((*node)->nparents > 0);
9415  assert(parent != NULL);
9416  assert(parent->depth >= 0);
9417  assert(parent->pos >= 0);
9418  assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
9419 
9420  /* find parent */
9421  exprgraphNodeSortParents(*node);
9422  (void) SCIPsortedvecFindPtr((void**)(*node)->parents, exprgraphnodecomp, (void*)parent, (*node)->nparents, &pos);
9423  assert(pos >= 0);
9424  assert(pos < (*node)->nparents);
9425  assert((*node)->parents[pos] == parent);
9426 
9427  /* move last parent to pos, if pos is before last
9428  * update sorted flag */
9429  if( pos < (*node)->nparents-1 )
9430  {
9431  (*node)->parents[pos] = (*node)->parents[(*node)->nparents-1];
9432  (*node)->parentssorted = ((*node)->nparents <= 2);
9433  }
9434  --(*node)->nparents;
9435 
9436  /* keep pointer to *node in case it is still used */
9437  node_ = (*node)->nuses > 0 ? *node : NULL;
9438 
9439  /* capture and release node so it is freed if possible */
9440  SCIPexprgraphCaptureNode(*node);
9441  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
9442 
9443  /* restore pointer, if node still exists */
9444  *node = node_;
9445 
9446  return SCIP_OKAY;
9447 }
9448 
9449 /** checks if a node is parent of a node */
9450 static
9452  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9453  SCIP_EXPRGRAPHNODE* parent /**< parent to look for */
9454  )
9455 {
9456  int pos;
9457 
9458  assert(node != NULL);
9459  assert(parent != NULL);
9460 
9461  /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
9462  if( node->depth >= parent->depth || node->nparents == 0 )
9463  return FALSE;
9464  assert(node->parents != NULL);
9465 
9466  /* ensure parents array is sorted */
9468 
9469  return SCIPsortedvecFindPtr((void**)node->parents, exprgraphnodecomp, (void*)parent, node->nparents, &pos);
9470 }
9471 
9472 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
9473  *
9474  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
9475  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
9476  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
9477  *
9478  * It is assumed that node and all exprs are in the expression graph already.
9479  * It is assumed that all expressions that are added have lower depth than node.
9480  */
9481 static
9483  BMS_BLKMEM* blkmem, /**< block memory */
9484  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9485  int nexprs, /**< number of children to add */
9486  SCIP_EXPRGRAPHNODE** exprs, /**< children nodes to add */
9487  int* childmap /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
9488  )
9489 {
9490  int i;
9491  int j;
9492  int orignchildren;
9493  SCIP_Bool existsalready;
9494 
9495  assert(blkmem != NULL);
9496  assert(node != NULL);
9497  assert(node->depth > 0);
9498  assert(node->pos >= 0);
9499  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);
9500  assert(exprs != NULL || nexprs == 0);
9501 
9502  if( nexprs == 0 )
9503  return SCIP_OKAY;
9504 
9505  orignchildren = node->nchildren;
9506  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
9507 
9508  for( i = 0; i < nexprs; ++i )
9509  {
9510  assert(exprs[i]->depth >= 0); /*lint !e613*/
9511  assert(exprs[i]->pos >= 0); /*lint !e613*/
9512  assert(exprs[i]->depth < node->depth); /*lint !e613*/
9513 
9514  /* check if exprs[i] is a child already, if not SUM or PRODUCT */
9515  existsalready = FALSE;
9516  if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
9517  for( j = 0; j < orignchildren; ++j )
9518  /* during simplification of polynomials, their may be NULL's in children array */
9519  if( node->children[j] != NULL && node->children[j] == exprs[i] ) /*lint !e613*/
9520  {
9521  existsalready = TRUE;
9522  break;
9523  }
9524 
9525  if( !existsalready )
9526  {
9527  /* add exprs[i] to children array */
9528  node->children[node->nchildren] = exprs[i]; /*lint !e613*/
9529  SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) ); /*lint !e613*/
9530  if( childmap != NULL )
9531  childmap[i] = node->nchildren;
9532  ++node->nchildren;
9533  }
9534  else
9535  {
9536  if( childmap != NULL )
9537  childmap[i] = j; /*lint !e644*/
9538  if( node->op == SCIP_EXPR_LINEAR )
9539  {
9540  /* if linear expression, increase coefficient by 1.0 */
9541  ((SCIP_Real*)node->data.data)[j] += 1.0;
9542  }
9543  }
9544  }
9545 
9546  /* shrink children array to actually used size */
9547  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
9548 
9549  if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
9550  {
9551  /* if linear expression, then add 1.0 coefficients for new expressions */
9552  SCIP_Real* data;
9553 
9554  data = (SCIP_Real*)node->data.data;
9555  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
9556  data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
9557  for( i = orignchildren; i < node->nchildren; ++i )
9558  data[i] = 1.0;
9559  node->data.data = (void*)data;
9560  }
9561  else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
9562  {
9563  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
9565 
9566  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9567  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
9568  BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren); /*lint !e866*/
9569  }
9570 
9571  node->simplified = FALSE;
9572 
9573  return SCIP_OKAY;
9574 }
9575 
9576 /** replaces a child node by another node
9577  *
9578  * Assumes that both nodes represent the same expression.
9579  * If this node was the last parent of oldchild and oldchild is not in use, then it is freed.
9580  * newchild must have deeper depth than node.
9581  */
9582 static
9584  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9585  SCIP_EXPRGRAPHNODE* node, /**< pointer to expression graph node */
9586  SCIP_EXPRGRAPHNODE** oldchild, /**< child node that should be replaced, it may be freed */
9587  SCIP_EXPRGRAPHNODE* newchild /**< node that should take position of oldchild */
9588  )
9589 {
9590  int i;
9591 
9592  assert(exprgraph != NULL);
9593  assert(node != NULL);
9594  assert(oldchild != NULL);
9595  assert(*oldchild != NULL);
9596  assert(newchild != NULL);
9597 
9598  if( *oldchild == newchild )
9599  return SCIP_OKAY;
9600 
9601  SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
9602 
9603  /* search for oldchild in children array */
9604  for( i = 0; i < node->nchildren; ++i )
9605  {
9606  if( node->children[i] == *oldchild )
9607  {
9608  /* add as parent to newchild */
9609  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
9610 
9611  /* remove as parent from oldchild */
9612  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
9613 
9614  /* set newchild as child i */
9615  node->children[i] = newchild;
9616 
9617  /* we're done */
9618  break;
9619  }
9620  }
9621  assert(i < node->nchildren); /* assert that oldchild has been found in children array */
9622 
9623  node->simplified = FALSE;
9624 
9625  return SCIP_OKAY;
9626 }
9627 
9628 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
9629  *
9630  * A node is larger than another node, if their corresponding constants are related that way.
9631  */
9632 static
9633 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
9634 {
9635  assert(elem1 != NULL);
9636  assert(elem2 != NULL);
9637  assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
9638  assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
9639  assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9640  assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9641 
9642  if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9643  return 1;
9644  else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9645  return -1;
9646  else
9647  return 0;
9648 }
9649 
9650 /** sort array of nodes that holds constants */
9651 static
9653  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
9654  )
9655 {
9656  assert(exprgraph != NULL);
9657 
9658  if( exprgraph->constssorted )
9659  return;
9660 
9661  SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
9662 
9663  exprgraph->constssorted = TRUE;
9664 }
9665 
9666 /** finds position of expression graph node corresponding to a constant in constnodes array */
9667 static
9669  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9670  SCIP_EXPRGRAPHNODE* node, /**< node to search for */
9671  int* pos /**< buffer to store position of node, if found */
9672  )
9673 {
9674  int left;
9675  int right;
9676  int middle;
9677 
9678  assert(exprgraph != NULL);
9679  assert(node != NULL);
9680  assert(node->op == SCIP_EXPR_CONST);
9681  assert(node->depth == 0);
9682  assert(node->pos >= 0);
9683  assert(pos != NULL);
9684 
9685  exprgraphSortConstNodes(exprgraph);
9686  assert(exprgraph->constssorted);
9687 
9688  /* find a node with constant node->data.dbl using binary search */
9689  left = 0;
9690  right = exprgraph->nconsts-1;
9691  *pos = -1;
9692  while( left <= right )
9693  {
9694  middle = (left+right)/2;
9695  assert(0 <= middle && middle < exprgraph->nconsts);
9696 
9697  if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9698  right = middle - 1;
9699  else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9700  left = middle + 1;
9701  else
9702  {
9703  *pos = middle;
9704  break;
9705  }
9706  }
9707  assert(left == right+1 || *pos >= 0);
9708  if( left == right+1 )
9709  return FALSE;
9710 
9711  /* search left of *pos to find node */
9712  while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl ) /*lint !e777*/
9713  --*pos;
9714  /* search right of *pos to find node */
9715  while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl ) /*lint !e777*/
9716  ++*pos;
9717 
9718  return exprgraph->constnodes[*pos] == node;
9719 }
9720 
9721 /** creates an expression graph node */
9722 static
9724  BMS_BLKMEM* blkmem, /**< block memory */
9725  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
9726  SCIP_EXPROP op, /**< operator type of expression */
9727  SCIP_EXPROPDATA opdata /**< operator data of expression */
9728  )
9729 {
9730  assert(blkmem != NULL);
9731  assert(node != NULL);
9732 
9733  SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9734  BMSclearMemory(*node);
9735 
9736  (*node)->op = op;
9737  (*node)->data = opdata;
9738 
9739  /* mark graph position as not in graph yet */
9740  (*node)->depth = -1;
9741  (*node)->pos = -1;
9742 
9743  /* arrays of length 0 are trivially sorted */
9744  (*node)->parentssorted = TRUE;
9745 
9746  /* set bounds interval to entire */
9747  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9748  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9749 
9750  /* set initial value to invalid */
9751  (*node)->value = SCIP_INVALID;
9752 
9753  /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9754  if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9755  (*node)->curv = SCIP_EXPRCURV_LINEAR;
9756  else
9757  (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9758 
9759  /* per default, a node is enabled */
9760  (*node)->enabled = TRUE;
9761 
9762  return SCIP_OKAY;
9763 }
9764 
9765 /** prints the expression corresponding to a node (not recursively) */
9766 static
9768  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9769  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9770  FILE* file, /**< file to print to, or NULL for stdout */
9771  const char** varnames, /**< variable names, or NULL for generic names */
9772  SCIP_Bool printchildrenbounds /**< whether to print bounds of children */
9773  )
9774 {
9775  int i;
9776 
9777  assert(node != NULL);
9778 
9779  switch( node->op )
9780  {
9781  case SCIP_EXPR_VARIDX:
9782  if( varnames != NULL )
9783  {
9784  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9785  }
9786  else
9787  SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9788  break;
9789 
9790  case SCIP_EXPR_CONST:
9791  SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9792  break;
9793 
9794  case SCIP_EXPR_PARAM:
9795  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9796  break;
9797 
9798  case SCIP_EXPR_PLUS:
9799  if( printchildrenbounds )
9800  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9801  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9802  if( printchildrenbounds )
9803  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9804  break;
9805 
9806  case SCIP_EXPR_MINUS:
9807  if( printchildrenbounds )
9808  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9809  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9810  if( printchildrenbounds )
9811  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9812  break;
9813 
9814  case SCIP_EXPR_MUL:
9815  if( printchildrenbounds )
9816  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9817  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9818  if( printchildrenbounds )
9819  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9820  break;
9821 
9822  case SCIP_EXPR_DIV:
9823  if( printchildrenbounds )
9824  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9825  SCIPmessageFPrintInfo(messagehdlr, file, "/");
9826  if( printchildrenbounds )
9827  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9828  break;
9829 
9830  case SCIP_EXPR_SQUARE:
9831  if( printchildrenbounds )
9832  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9833  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9834  break;
9835 
9836  case SCIP_EXPR_REALPOWER:
9837  if( printchildrenbounds )
9838  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9839  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9840  break;
9841 
9842  case SCIP_EXPR_SIGNPOWER:
9843  if( printchildrenbounds )
9844  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9845  node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9846  else
9847  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9848  break;
9849 
9850  case SCIP_EXPR_INTPOWER:
9851  SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9852  if( printchildrenbounds )
9853  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9854  SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9855  break;
9856 
9857  case SCIP_EXPR_SQRT:
9858  case SCIP_EXPR_EXP:
9859  case SCIP_EXPR_LOG:
9860  case SCIP_EXPR_SIN:
9861  case SCIP_EXPR_COS:
9862  case SCIP_EXPR_TAN:
9863  /* SCIP_EXPR_ERF = 20, */ /**< gaussian error function (1 operand) */
9864  /* SCIP_EXPR_ERFI = 21, */ /**< imaginary part of gaussian error function (1 operand) */
9865  case SCIP_EXPR_MIN:
9866  case SCIP_EXPR_MAX:
9867  case SCIP_EXPR_ABS:
9868  case SCIP_EXPR_SIGN:
9869  SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9870  if( printchildrenbounds )
9871  {
9872  SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9873  if( node->nchildren == 2 )
9874  SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9875  SCIPmessageFPrintInfo(messagehdlr, file, ")");
9876  }
9877  break;
9878 
9879  case SCIP_EXPR_SUM:
9880  if( printchildrenbounds )
9881  for( i = 0; i < node->nchildren; ++i )
9882  {
9883  if( i > 0 )
9884  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9885  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9886  }
9887  else
9888  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9889  break;
9890 
9891  case SCIP_EXPR_PRODUCT:
9892  if( printchildrenbounds )
9893  for( i = 0; i < node->nchildren; ++i )
9894  {
9895  if( i > 0 )
9896  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9897  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9898  }
9899  else
9900  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9901  break;
9902 
9903  case SCIP_EXPR_LINEAR:
9904  {
9905  SCIP_Real constant;
9906 
9907  constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9908 
9909  if( constant != 0.0 || node->nchildren == 0 )
9910  SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9911 
9912  for( i = 0; i < node->nchildren; ++i )
9913  {
9914  if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9915  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9916  else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9917  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9918  else
9919  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9920  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9921  if( printchildrenbounds )
9922  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9923  }
9924 
9925  break;
9926  }
9927 
9928  case SCIP_EXPR_QUADRATIC:
9929  {
9930  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9931 
9932  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9933  assert(quadraticdata != NULL);
9934 
9935  if( quadraticdata->constant != 0.0 )
9936  SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9937 
9938  if( quadraticdata->lincoefs != NULL )
9939  for( i = 0; i < node->nchildren; ++i )
9940  {
9941  if( quadraticdata->lincoefs[i] == 0.0 )
9942  continue;
9943  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9944  if( printchildrenbounds )
9945  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9946  }
9947 
9948  for( i = 0; i < quadraticdata->nquadelems; ++i )
9949  {
9950  if( quadraticdata->quadelems[i].coef == 1.0 )
9951  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9952  else if( quadraticdata->quadelems[i].coef == -1.0 )
9953  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9954  else
9955  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9956  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9957  if( printchildrenbounds )
9958  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9959  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9960  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9961  else
9962  {
9963  SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9964  if( printchildrenbounds )
9965  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9966  }
9967  }
9968 
9969  break;
9970  }
9971 
9972  case SCIP_EXPR_POLYNOMIAL:
9973  {
9974  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9975  SCIP_EXPRDATA_MONOMIAL* monomialdata;
9976  int j;
9977 
9978  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9979  assert(polynomialdata != NULL);
9980 
9981  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
9982  {
9983  SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
9984  }
9985 
9986  for( i = 0; i < polynomialdata->nmonomials; ++i )
9987  {
9988  monomialdata = polynomialdata->monomials[i];
9989  if( monomialdata->coef == 1.0 )
9990  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9991  else if( monomialdata->coef == -1.0 )
9992  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9993  else
9994  SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
9995 
9996  for( j = 0; j < monomialdata->nfactors; ++j )
9997  {
9998  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
9999  if( printchildrenbounds )
10000  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
10001  if( monomialdata->exponents[j] < 0.0 )
10002  SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
10003  else if( monomialdata->exponents[j] != 1.0 )
10004  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
10005  }
10006  }
10007 
10008  break;
10009  }
10010 
10011  case SCIP_EXPR_LAST:
10012  SCIPABORT();
10013  break;
10014 
10015  default:
10016  SCIPmessageFPrintInfo(messagehdlr, file, "%s", SCIPexpropGetName(node->op));
10017  break;
10018  } /*lint !e788*/
10019 }
10020 
10021 /** prints a node of an expression graph */
10022 static
10024  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10025  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10026  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
10027  FILE* file, /**< file to print to, or NULL for stdout */
10028  const char** varnames /**< variable names, or NULL for generic names */
10029  )
10030 {
10031  SCIP_Real color;
10032  int i;
10033 
10034  assert(exprgraph != NULL);
10035  assert(node != NULL);
10036  assert(file != NULL);
10037 
10038  color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
10039  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
10040 
10041  exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
10042 
10043  SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
10045  SCIPmessageFPrintInfo(messagehdlr, file, "!");
10047  SCIPmessageFPrintInfo(messagehdlr, file, "*");
10049  SCIPmessageFPrintInfo(messagehdlr, file, "+");
10050 
10051  SCIPmessageFPrintInfo(messagehdlr, file, "\"");
10052 
10053  if( !node->enabled )
10054  SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
10055 
10056  SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
10057 
10058  /* add edges from node to children */
10059  for( i = 0; i < node->nchildren; ++i )
10060  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);
10061 }
10062 
10063 /** evaluate node of expression graph w.r.t. values stored in children */
10064 static
10066  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10067  SCIP_Real* varvals /**< values for variables */
10068  )
10069 {
10070  int i;
10072  SCIP_Real* buf;
10073 
10074  assert(node != NULL);
10075 
10076  /* if many children, get large enough memory to store argument values */
10078  {
10079  SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
10080  }
10081  else
10082  {
10083  buf = staticbuf;
10084  }
10085 
10086  /* get values of children */
10087  for( i = 0; i < node->nchildren; ++i )
10088  {
10089  assert(node->children[i]->value != SCIP_INVALID); /*lint !e777*/
10090  buf[i] = node->children[i]->value; /*lint !e644*/
10091  }
10092 
10093  /* evaluate this expression */
10094  assert(exprOpTable[node->op].eval != NULL);
10095  SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
10096  assert(node->value != SCIP_INVALID); /*lint !e777*/
10097 
10098  /* free memory, if allocated before */
10099  if( staticbuf != buf )
10100  {
10101  BMSfreeMemoryArray(&buf);
10102  }
10103 
10104  return SCIP_OKAY;
10105 }
10106 
10107 /** evaluates node including subtree */
10108 static
10110  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10111  SCIP_Real* varvals /**< values for variables */
10112  )
10113 {
10114  int i;
10115 
10116  assert(node != NULL);
10117 
10118  for( i = 0; i < node->nchildren; ++i )
10119  {
10120  SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
10121  }
10122 
10123  SCIP_CALL( exprgraphNodeEval(node, varvals) );
10124 
10125  return SCIP_OKAY;
10126 }
10127 
10128 /** updates bounds of a node if a children has changed its bounds */
10129 static
10131  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10132  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10133  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
10134  SCIP_Bool parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
10135  )
10136 {
10137  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
10138  SCIP_INTERVAL* childbounds;
10139  SCIP_INTERVAL newbounds;
10140  int i;
10141 
10142  assert(node != NULL);
10143  assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
10144  assert(node->pos >= 0); /* node should be in graph */
10145  assert(node->op != SCIP_EXPR_VARIDX);
10146  assert(node->op != SCIP_EXPR_PARAM);
10147 
10148  /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
10149  * if node is disabled, then also do nothing */
10150  if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
10151  return SCIP_OKAY;
10152 
10153  /* if many children, get large enough memory to store children bounds */
10155  {
10156  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
10157  }
10158  else
10159  {
10160  childbounds = childboundsstatic;
10161  }
10162 
10163  /* assemble bounds of children */
10164  for( i = 0; i < node->nchildren; ++i )
10165  {
10166  /* child should have valid and non-empty bounds */
10168  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10169 
10170  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
10171  }
10172 
10173  /* call interval evaluation function for this operand */
10174  assert( exprOpTable[node->op].inteval != NULL );
10175  SCIPintervalSet(&newbounds, 0.0);
10176  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
10177 
10178  /* free memory, if allocated before */
10179  if( childbounds != childboundsstatic )
10180  {
10181  BMSfreeMemoryArray(&childbounds);
10182  }
10183 
10184  /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
10185 
10186  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
10187  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
10188  *
10189  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
10190  *
10191  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
10192  */
10193  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
10194  ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
10195  {
10196  for( i = 0; i < node->nparents; ++i )
10198 
10199  node->bounds = newbounds;
10200  }
10201  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
10202  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
10203  {
10204  for( i = 0; i < node->nparents; ++i )
10206 
10207  node->bounds = newbounds;
10208  }
10209  else
10210  {
10211  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
10212  }
10213 
10214  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);
10215 
10216  /* node now has valid bounds */
10217  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
10218 
10219  return SCIP_OKAY;
10220 }
10221 
10222 /** propagate bounds of a node into children by reverting the nodes expression */
10223 static
10225  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10226  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
10227  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10228  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
10229  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
10230  )
10231 {
10232  SCIP_INTERVAL childbounds;
10233  int i;
10234 
10235  assert(exprgraph != NULL);
10236  assert(node != NULL);
10237  assert(node->depth >= 0); /* node should be in graph */
10238  assert(node->pos >= 0); /* node should be in graph */
10239  assert(minstrength >= 0.0);
10240  assert(cutoff != NULL);
10241  assert(!SCIPintervalIsEmpty(infinity, node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
10242  assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
10243 
10244  /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
10246  return;
10247 
10248  /* if node is not enabled, then do nothing */
10249  if( !node->enabled )
10250  return;
10251 
10252  /* tell children that they should propagate their bounds even if not tightened */
10254  minstrength = -1.0;
10255 
10256  /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
10258 
10259  /* 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);
10260  * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10261  * SCIPdebugPrintf("\n");
10262  */
10263 
10264  /* @todo add callback to exprOpTable for this */
10265 
10266  switch( node->op )
10267  {
10268  case SCIP_EXPR_VARIDX:
10269  case SCIP_EXPR_CONST:
10270  case SCIP_EXPR_PARAM:
10271  /* cannot propagate bound changes further */
10272  break;
10273 
10274  case SCIP_EXPR_PLUS:
10275  {
10276  assert(node->nchildren == 2);
10277  /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
10278 
10279  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10280  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10281 
10282  if( *cutoff )
10283  break;
10284 
10285  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10286  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10287 
10288  break;
10289  }
10290 
10291  case SCIP_EXPR_MINUS:
10292  {
10293  assert(node->nchildren == 2);
10294  /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
10295 
10296  SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10297  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10298 
10299  if( *cutoff )
10300  break;
10301 
10302  SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10303  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10304 
10305  break;
10306  }
10307 
10308  case SCIP_EXPR_MUL:
10309  {
10310  assert(node->nchildren == 2);
10311  /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
10312 
10313  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10314  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10315 
10316  if( *cutoff )
10317  break;
10318 
10319  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10320  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10321 
10322  break;
10323  }
10324 
10325  case SCIP_EXPR_DIV:
10326  {
10327  assert(node->nchildren == 2);
10328  /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
10329 
10330  SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10331  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10332 
10333  if( *cutoff )
10334  break;
10335 
10336  SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10337  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10338 
10339  break;
10340  }
10341 
10342  case SCIP_EXPR_SQUARE:
10343  {
10344  assert(node->nchildren == 1);
10345  /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
10346 
10347  if( node->bounds.sup < 0.0 )
10348  {
10349  *cutoff = TRUE;
10350  break;
10351  }
10352 
10353  SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
10354  if( node->children[0]->bounds.inf <= -childbounds.inf )
10355  SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
10356  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10357 
10358  break;
10359  }
10360 
10361  case SCIP_EXPR_SQRT:
10362  {
10363  assert(node->nchildren == 1);
10364  /* f = sqrt(c0) -> c0 = f^2 */
10365 
10366  SCIPintervalSquare(infinity, &childbounds, node->bounds);
10367  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10368 
10369  break;
10370  }
10371 
10372  case SCIP_EXPR_REALPOWER:
10373  {
10374  assert(node->nchildren == 1);
10375 
10376  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
10377 
10378  if( SCIPintervalIsEmpty(infinity, childbounds) )
10379  {
10380  *cutoff = TRUE;
10381  break;
10382  }
10383  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10384 
10385  break;
10386  }
10387 
10388  case SCIP_EXPR_SIGNPOWER:
10389  {
10390  assert(node->nchildren == 1);
10391 
10392  if( node->data.dbl != 0.0 )
10393  {
10394  SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
10395  }
10396  else
10397  {
10398  /* behaves like SCIP_EXPR_SIGN */
10399  SCIPintervalSetBounds(&childbounds,
10400  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10401  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10402  }
10403 
10404  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10405 
10406  break;
10407  }
10408 
10409  case SCIP_EXPR_INTPOWER:
10410  {
10411  assert(node->nchildren == 1);
10412 
10413  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
10414 
10415  if( SCIPintervalIsEmpty(infinity, childbounds) )
10416  {
10417  *cutoff = TRUE;
10418  break;
10419  }
10420  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10421 
10422  break;
10423  }
10424 
10425  case SCIP_EXPR_EXP:
10426  {
10427  assert(node->nchildren == 1);
10428  /* f = exp(c0) -> c0 = log(f) */
10429 
10430  if( node->bounds.sup < 0.0 )
10431  {
10432  *cutoff = TRUE;
10433  break;
10434  }
10435 
10436  SCIPintervalLog(infinity, &childbounds, node->bounds);
10437  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10438 
10439  break;
10440  }
10441 
10442  case SCIP_EXPR_LOG:
10443  {
10444  assert(node->nchildren == 1);
10445  /* f = log(c0) -> c0 = exp(f) */
10446 
10447  SCIPintervalExp(infinity, &childbounds, node->bounds);
10448  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10449 
10450  break;
10451  }
10452 
10453  case SCIP_EXPR_SIN:
10454  case SCIP_EXPR_COS:
10455  case SCIP_EXPR_TAN:
10456  /* case SCIP_EXPR_ERF: */
10457  /* case SCIP_EXPR_ERFI: */
10458  {
10459  assert(node->nchildren == 1);
10460 
10461  /* @todo implement */
10462 
10463  break;
10464  }
10465 
10466  case SCIP_EXPR_ABS:
10467  {
10468  assert(node->nchildren == 1);
10469 
10470  /* use identity if child bounds are non-negative */
10471  if( node->children[0]->bounds.inf >= 0 )
10472  {
10473  SCIPintervalSetBounds(&childbounds, node->bounds.inf, node->bounds.sup);
10474  }
10475  /* use -identity if child bounds are non-positive */
10476  else if( node->children[0]->bounds.sup <= 0 )
10477  {
10478  assert(node->bounds.inf <= node->bounds.sup);
10479  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, -node->bounds.inf);
10480  }
10481  /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
10482  else
10483  {
10484  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
10485  }
10486 
10487  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10488 
10489  break;
10490  }
10491 
10492  case SCIP_EXPR_SIGN:
10493  {
10494  assert(node->nchildren == 1);
10495  /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
10496 
10497  SCIPintervalSetBounds(&childbounds,
10498  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10499  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10500  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10501 
10502  break;
10503  }
10504 
10505  case SCIP_EXPR_MIN:
10506  {
10507  assert(node->nchildren == 2);
10508  /* f = min(c0,c1) -> f <= c0, f <= c1
10509  * if c1 > f -> c0 = f
10510  * if c0 > f -> c1 = f
10511  */
10512 
10513  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10514  node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10515  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10516 
10517  if( *cutoff )
10518  break;
10519 
10520  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10521  node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10522  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10523 
10524  break;
10525  }
10526 
10527  case SCIP_EXPR_MAX:
10528  {
10529  assert(node->nchildren == 2);
10530  /* f = max(c0, c1) -> f >= c0, f >= c1
10531  * if c1 < f -> c0 = f
10532  * if c0 < f -> c1 = f
10533  */
10534 
10535  SCIPintervalSetBounds(&childbounds,
10536  node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10537  node->bounds.sup);
10538  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10539 
10540  SCIPintervalSetBounds(&childbounds,
10541  node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10542  node->bounds.sup);
10543  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10544 
10545  break;
10546  }
10547 
10548  case SCIP_EXPR_SUM:
10549  {
10550  SCIP_ROUNDMODE prevroundmode;
10551 
10552  /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
10553 
10554  SCIP_Real minlinactivity;
10555  SCIP_Real maxlinactivity;
10556  int minlinactivityinf;
10557  int maxlinactivityinf;
10558 
10559  if( node->nchildren == 0 )
10560  break;
10561 
10562  if( SCIPintervalIsEntire(infinity, node->bounds) )
10563  break;
10564 
10565  minlinactivity = 0.0;
10566  maxlinactivity = 0.0;
10567  minlinactivityinf = 0;
10568  maxlinactivityinf = 0;
10569 
10570  prevroundmode = SCIPintervalGetRoundingMode();
10572 
10573  for( i = 0; i < node->nchildren; ++i )
10574  {
10575  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10576 
10577  /* minimal activity is only useful if node has a finite upper bound */
10578  if( node->bounds.sup < infinity )
10579  {
10580  if( node->children[i]->bounds.inf <= -infinity )
10581  {
10582  ++minlinactivityinf;
10583  }
10584  else
10585  {
10586  assert(node->children[i]->bounds.inf < infinity);
10587  minlinactivity += node->children[i]->bounds.inf;
10588  }
10589  }
10590 
10591  /* maximal activity is only useful if node has a finite lower bound
10592  * we compute negated maximal activity here so we can keep downward rounding
10593  */
10594  if( node->bounds.inf > -infinity )
10595  {
10596  if( node->children[i]->bounds.sup >= infinity )
10597  {
10598  ++maxlinactivityinf;
10599  }
10600  else
10601  {
10602  assert(node->children[i]->bounds.sup > -infinity);
10603  maxlinactivity -= node->children[i]->bounds.sup;
10604  }
10605  }
10606  }
10607  maxlinactivity = -maxlinactivity; /* correct sign */
10608 
10609  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10610  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10611  ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10612  )
10613  {
10614  SCIPintervalSetRoundingMode(prevroundmode);
10615  break;
10616  }
10617 
10618  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10619  {
10620  /* upper bounds of c_i is
10621  * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
10622  * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
10623  */
10624  SCIPintervalSetEntire(infinity, &childbounds);
10625  if( node->bounds.sup < infinity )
10626  {
10627  /* we are still in downward rounding mode, so negate and negate to get upward rounding */
10628  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10629  {
10630  assert(minlinactivityinf == 1);
10631  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
10632  }
10633  else if( minlinactivityinf == 0 )
10634  {
10635  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
10636  }
10637  }
10638 
10639  /* lower bounds of c_i is
10640  * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
10641  * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
10642  */
10643  if( node->bounds.inf > -infinity )
10644  {
10645  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10646  {
10647  assert(maxlinactivityinf == 1);
10648  childbounds.inf = node->bounds.inf - maxlinactivity;
10649  }
10650  else if( maxlinactivityinf == 0 )
10651  {
10652  childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
10653  }
10654  }
10655 
10656  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10657  }
10658 
10659  SCIPintervalSetRoundingMode(prevroundmode);
10660 
10661  break;
10662  }
10663 
10664  case SCIP_EXPR_PRODUCT:
10665  {
10666  int j;
10667  /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
10668 
10669  /* too expensive (runtime here is quadratic in number of children) */
10670  if( node->nchildren > 10 )
10671  break;
10672 
10673  /* useless */
10674  if( SCIPintervalIsEntire(infinity, node->bounds) )
10675  break;
10676 
10677  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10678  {
10679  /* compute prod_{j:j!=i} c_j */
10680  SCIPintervalSet(&childbounds, 1.0);
10681  for( j = 0; j < node->nchildren; ++j )
10682  {
10683  if( i == j )
10684  continue;
10685  SCIPintervalMul(infinity, &childbounds, childbounds, node->children[j]->bounds);
10686 
10687  /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
10688  if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
10689  break;
10690  }
10691 
10692  if( j == node->nchildren )
10693  {
10694  SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
10695  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10696  }
10697  }
10698 
10699  break;
10700  }
10701 
10702  case SCIP_EXPR_LINEAR:
10703  {
10704  SCIP_ROUNDMODE prevroundmode;
10705  SCIP_Real* coefs;
10706 
10707  /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10708 
10709  SCIP_Real minlinactivity;
10710  SCIP_Real maxlinactivity;
10711  int minlinactivityinf;
10712  int maxlinactivityinf;
10713 
10714  if( node->nchildren == 0 )
10715  break;
10716 
10717  if( SCIPintervalIsEntire(infinity, node->bounds) )
10718  break;
10719 
10720  coefs = (SCIP_Real*)node->data.data;
10721 
10722  minlinactivity = coefs[node->nchildren];
10723  maxlinactivity = -coefs[node->nchildren];
10724  minlinactivityinf = 0;
10725  maxlinactivityinf = 0;
10726 
10727  prevroundmode = SCIPintervalGetRoundingMode();
10729 
10730  for( i = 0; i < node->nchildren; ++i )
10731  {
10732  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10733 
10734  /* minimal activity is only useful if node has a finite upper bound */
10735  if( node->bounds.sup < infinity )
10736  {
10737  if( coefs[i] >= 0.0 )
10738  {
10739  if( node->children[i]->bounds.inf <= -infinity )
10740  {
10741  ++minlinactivityinf;
10742  }
10743  else
10744  {
10745  assert(node->children[i]->bounds.inf < infinity);
10746  minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10747  }
10748  }
10749  else
10750  {
10751  if( node->children[i]->bounds.sup >= infinity )
10752  {
10753  ++minlinactivityinf;
10754  }
10755  else
10756  {
10757  assert(node->children[i]->bounds.sup > -infinity);
10758  minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10759  }
10760  }
10761  }
10762 
10763  /* maximal activity is only useful if node has a finite lower bound
10764  * we compute negated maximal activity here so we can keep downward rounding
10765  */
10766  if( node->bounds.inf > -infinity )
10767  {
10768  if( coefs[i] >= 0.0 )
10769  {
10770  if( node->children[i]->bounds.sup >= infinity )
10771  {
10772  ++maxlinactivityinf;
10773  }
10774  else
10775  {
10776  assert(node->children[i]->bounds.sup > -infinity);
10777  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.sup;
10778  }
10779  }
10780  else
10781  {
10782  if( node->children[i]->bounds.inf <= -infinity )
10783  {
10784  ++maxlinactivityinf;
10785  }
10786  else
10787  {
10788  assert(node->children[i]->bounds.inf < infinity);
10789  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.inf;
10790  }
10791  }
10792  }
10793  }
10794  maxlinactivity = SCIPintervalNegateReal(maxlinactivity); /* correct sign */
10795 
10796  /* SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]; bounds = [%10g,%10g]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf, node->bounds.inf, node->bounds.sup); */
10797 
10798  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10799  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10800  (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10801  )
10802  {
10803  SCIPintervalSetRoundingMode(prevroundmode);
10804  break;
10805  }
10806 
10807  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10808  {
10809  SCIP_INTERVAL ac;
10810 
10811  if( coefs[i] == 0.0 )
10812  continue;
10813 
10814  /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10815  SCIPintervalSet(&ac, 0.0);
10816  if( coefs[i] >= 0.0 )
10817  {
10818  if( node->children[i]->bounds.inf > -infinity )
10819  ac.inf = coefs[i] * node->children[i]->bounds.inf;
10820  if( node->children[i]->bounds.sup < infinity )
10822  }
10823  else
10824  {
10825  if( node->children[i]->bounds.sup < infinity )
10826  ac.inf = coefs[i] * node->children[i]->bounds.sup;
10827  if( node->children[i]->bounds.inf > -infinity )
10828  ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10829  }
10830 
10831  SCIPintervalSetEntire(infinity, &childbounds);
10832  if( coefs[i] > 0.0 )
10833  {
10834  /* upper bounds of c_i is
10835  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10836  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10837  */
10838  if( node->bounds.sup < infinity )
10839  {
10840  /* we are still in downward rounding mode, so negate to get upward rounding */
10841  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10842  {
10843  assert(minlinactivityinf == 1);
10844  childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10845  }
10846  else if( minlinactivityinf == 0 )
10847  {
10848  childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10849  }
10850  }
10851 
10852  /* lower bounds of c_i is
10853  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10854  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10855  */
10856  if( node->bounds.inf > -infinity )
10857  {
10858  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10859  {
10860  assert(maxlinactivityinf == 1);
10861  childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10862  }
10863  else if( maxlinactivityinf == 0 )
10864  {
10865  childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10866  }
10867  }
10868  }
10869  else
10870  {
10871  /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10872  * thus, we do (b-a)/(-c) in downward rounding
10873  */
10874  /* lower bounds of c_i is
10875  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10876  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10877  */
10878  if( node->bounds.sup < infinity )
10879  {
10880  if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10881  {
10882  assert(minlinactivityinf == 1);
10883  childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10884  }
10885  else if( minlinactivityinf == 0 )
10886  {
10887  childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10888  }
10889  }
10890 
10891  /* upper bounds of c_i is
10892  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10893  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10894  */
10895  if( node->bounds.inf > -infinity )
10896  {
10897  /* we are still in downward rounding mode, so negate to get upward rounding */
10898  if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10899  {
10900  assert(maxlinactivityinf == 1);
10901  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10902  }
10903  else if( maxlinactivityinf == 0 )
10904  {
10905  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10906  }
10907  }
10908  }
10909 
10910  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10911  }
10912 
10913  SCIPintervalSetRoundingMode(prevroundmode);
10914 
10915  break;
10916  }
10917 
10918  case SCIP_EXPR_QUADRATIC:
10919  {
10920  SCIP_EXPRDATA_QUADRATIC* quaddata;
10921  SCIP_INTERVAL tmp;
10922  SCIP_INTERVAL a;
10923  SCIP_INTERVAL b;
10924  SCIP_INTERVAL c;
10925  SCIP_QUADELEM* quadelems;
10926  int nquadelems;
10927  SCIP_Real* lincoefs;
10928  int k;
10929 
10930  /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10931  * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10932  */
10933 
10934  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10935  quadelems = quaddata->quadelems;
10936  nquadelems = quaddata->nquadelems;
10937  lincoefs = quaddata->lincoefs;
10938 
10939  /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10940  if( nquadelems > 10 )
10941  break;
10942 
10943  if( SCIPintervalIsEntire(infinity, node->bounds) )
10944  break;
10945 
10946  if( node->nchildren == 2 && nquadelems > 0 )
10947  {
10948  /* if it's a bivariate quadratic expression with bilinear term, do something special */
10949  SCIP_Real ax; /* square coefficient of first child */
10950  SCIP_Real ay; /* square coefficient of second child */
10951  SCIP_Real axy; /* bilinear coefficient */
10952 
10953  ax = 0.0;
10954  ay = 0.0;
10955  axy = 0.0;
10956  for( i = 0; i < nquadelems; ++i )
10957  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10958  ax += quadelems[i].coef;
10959  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10960  ay += quadelems[i].coef;
10961  else
10962  axy += quadelems[i].coef;
10963 
10964  c = node->bounds;
10965  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10966 
10967  /* compute bounds for x */
10969  infinity, &childbounds, ax, ay, axy,
10970  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10971  c, node->children[0]->bounds, node->children[1]->bounds
10972  );
10973  if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10974  {
10975  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",
10976  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10977  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10978  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10979  );
10980  }
10981 
10982  if( SCIPintervalIsEmpty(infinity, childbounds) )
10983  *cutoff = TRUE;
10984  else
10985  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10986  if( *cutoff )
10987  break;
10988 
10989  /* compute bounds for y */
10991  infinity, &childbounds, ay, ax, axy,
10992  lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
10993  c, node->children[1]->bounds, node->children[0]->bounds
10994  );
10995 
10996  if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
10997  {
10998  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",
10999  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
11000  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
11001  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
11002  );
11003  }
11004 
11005  if( SCIPintervalIsEmpty(infinity, childbounds) )
11006  *cutoff = TRUE;
11007  else
11008  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
11009  if( *cutoff )
11010  break;
11011 
11012  break;
11013  }
11014 
11015  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11016  {
11017  SCIPintervalSet(&a, 0.0);
11018  SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
11019  c = node->bounds;
11020  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
11021 
11022  /* move linear terms not corresponding to i into c
11023  * @todo do this faster, see EXPR_LINEAR
11024  */
11025  if( lincoefs != NULL )
11026  for( k = 0; k < node->nchildren; ++k )
11027  if( i != k && lincoefs[k] != 0.0 )
11028  {
11029  SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
11030  SCIPintervalSub(infinity, &c, c, tmp);
11031  }
11032 
11033  for( k = 0; k < nquadelems; ++k )
11034  {
11035  if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
11036  {
11037  SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
11038  }
11039  else if( quadelems[k].idx1 == i )
11040  {
11041  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
11042  SCIPintervalAdd(infinity, &b, b, tmp);
11043  }
11044  else if( quadelems[k].idx2 == i )
11045  {
11046  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
11047  SCIPintervalAdd(infinity, &b, b, tmp);
11048  }
11049  else if( quadelems[k].idx1 == quadelems[k].idx2 )
11050  {
11051  SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
11052  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11053  SCIPintervalSub(infinity, &c, c, tmp);
11054  }
11055  else
11056  {
11057  SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
11058  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11059  SCIPintervalSub(infinity, &c, c, tmp);
11060  }
11061  }
11062 
11063  SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
11064  a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
11065  SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c, node->children[i]->bounds);
11066  if( SCIPintervalIsEmpty(infinity, childbounds) )
11067  *cutoff = TRUE;
11068  else
11069  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11070  }
11071 
11072  break;
11073  }
11074 
11075  case SCIP_EXPR_POLYNOMIAL:
11076  {
11077  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11078  SCIP_EXPRDATA_MONOMIAL** monomials;
11079  SCIP_EXPRDATA_MONOMIAL* monomial;
11080  int nmonomials;
11081  int j;
11082  int k;
11083  SCIP_Real n;
11084  int nexpisdoublen;
11085  int nexpishalfn;
11086  char abc_flag;
11087 
11088  SCIP_INTERVAL monomialcoef;
11089  SCIP_INTERVAL tmp;
11090  SCIP_INTERVAL a;
11091  SCIP_INTERVAL b;
11092  SCIP_INTERVAL c;
11093  SCIP_INTERVAL childpowbounds;
11094 
11095  /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
11096  * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
11097  *
11098  * we determine n by setting n to the first exponent of x that we see
11099  * then we count how often we see x^(2n) and x^(n/2)
11100  * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
11101  */
11102 
11103  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11104  monomials = polynomialdata->monomials;
11105  nmonomials = polynomialdata->nmonomials;
11106 
11107  if( SCIPintervalIsEntire(infinity, node->bounds) )
11108  break;
11109 
11110  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11111  {
11112  n = 0.0;
11113  nexpisdoublen = 0;
11114  nexpishalfn = 0;
11115  for( j = 0; j < nmonomials; ++j )
11116  {
11117  monomial = monomials[j];
11118  for( k = 0; k < monomial->nfactors; ++k )
11119  {
11120  if( monomial->childidxs[k] == i )
11121  {
11122  if( n == 0.0 )
11123  n = monomial->exponents[k];
11124  else if( n == 2*monomial->exponents[k] ) /*lint !e777*/
11125  ++nexpishalfn;
11126  else if( 2*n == monomial->exponents[k] ) /*lint !e777*/
11127  ++nexpisdoublen;
11128  }
11129  }
11130  }
11131 
11132  if( n == 0.0 )
11133  {
11134  /* child does not appear in polynomial -> cannot deduce bound */
11135  continue;
11136  }
11137 
11138  /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
11139  if( nexpishalfn > nexpisdoublen )
11140  n /= 2.0;
11141 
11142  SCIPintervalSet(&a, 0.0);
11143  SCIPintervalSet(&b, 0.0);
11144  SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
11145 
11146  for( j = 0; j < nmonomials; ++j )
11147  {
11148  monomial = monomials[j];
11149  SCIPintervalSet(&monomialcoef, monomial->coef);
11150  abc_flag = 'c';
11151  for( k = 0; k < monomial->nfactors; ++k )
11152  {
11153  if( monomial->childidxs[k] == i )
11154  {
11155  assert(abc_flag == 'c'); /* child should appear only once per monom */
11156  if( n > 0.0 )
11157  {
11158  if( monomial->exponents[k] > 2.0*n )
11159  {
11160  abc_flag = 'a';
11161  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11162  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11163  }
11164  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11165  {
11166  abc_flag = 'a';
11167  }
11168  else if( monomial->exponents[k] > n )
11169  {
11170  abc_flag = 'b';
11171  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11172  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11173  }
11174  else if( monomial->exponents[k] == n ) /*lint !e777*/
11175  {
11176  abc_flag = 'b';
11177  }
11178  else
11179  {
11180  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11181  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11182  }
11183  }
11184  else
11185  {
11186  assert(n < 0.0);
11187  if( monomial->exponents[k] < 2.0*n )
11188  {
11189  abc_flag = 'a';
11190  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11191  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11192  }
11193  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11194  {
11195  abc_flag = 'a';
11196  }
11197  else if( monomial->exponents[k] < n )
11198  {
11199  abc_flag = 'b';
11200  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11201  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11202  }
11203  else if( monomial->exponents[k] == n ) /*lint !e777*/
11204  {
11205  abc_flag = 'b';
11206  }
11207  else
11208  {
11209  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11210  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11211  }
11212  }
11213  }
11214  else
11215  {
11216  SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
11217  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11218  }
11219  }
11220 
11221  if( abc_flag == 'a' )
11222  {
11223  SCIPintervalAdd(infinity, &a, a, monomialcoef);
11224  /* if monomialcoef is such that a exceeds value for infinity, then stop */
11225  if( a.inf >= infinity || a.sup <= -infinity )
11226  break;
11227  }
11228  else if( abc_flag == 'b' )
11229  {
11230  SCIPintervalAdd(infinity, &b, b, monomialcoef);
11231  /* if monomialcoef is such that b exceeds value for infinity, then stop */
11232  if( b.inf >= infinity || b.sup <= -infinity )
11233  break;
11234  }
11235  else
11236  {
11237  SCIPintervalSub(infinity, &c, c, monomialcoef);
11238  /* if monomialcoef is such that c exceeds value for infinity, then stop */
11239  if( c.inf >= infinity || c.sup <= -infinity )
11240  break;
11241  }
11242  }
11243 
11244  /* if we run out of numbers (within -infinity,infinity) above, then stop */
11245  if( j < nmonomials )
11246  continue;
11247 
11248  /* now have equation a*child^(2n) + b*child^n = c
11249  * solve a*y^2 + b*y = c (for y in childbounds^n), then child^n = y
11250  */
11251  SCIPintervalPowerScalar(infinity, &childpowbounds, node->children[i]->bounds, n);
11252  SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g] for c%d^%g in [%10g,%10g]",
11253  a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup, i, n, childpowbounds.inf, childpowbounds.sup);
11254  SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c, childpowbounds);
11255  SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
11256 
11257  if( SCIPintervalIsEmpty(infinity, tmp) )
11258  {
11259  *cutoff = TRUE;
11260  break;
11261  }
11262 
11263  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
11264  SCIPdebugPrintf(" -> c%d = [%10g, %10g]\n", i, childbounds.inf, childbounds.sup);
11265  if( SCIPintervalIsEmpty(infinity, childbounds) )
11266  {
11267  SCIPdebugMessage(" -> cutoff\n");
11268  *cutoff = TRUE;
11269  break;
11270  }
11271 
11272  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11273 
11274  /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
11275  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11276  SCIPdebugPrintf("\n"); */
11277  }
11278 
11279  break;
11280  }
11281 
11282  case SCIP_EXPR_USER:
11283  {
11284  SCIP_INTERVAL* childrenbounds;
11285  SCIP_EXPRDATA_USER* exprdata;
11286  int c;
11287 
11288  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11289 
11290  /* do nothing if callback not implemented */
11291  if( exprdata->prop == NULL )
11292  break;
11293 
11294  /* if only one child, do faster */
11295  if( node->nchildren == 1 )
11296  {
11297  childbounds = node->children[0]->bounds;
11298  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, 1, &childbounds, node->bounds, cutoff) );
11299 
11300  if( !*cutoff )
11301  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11302 
11303  break;
11304  }
11305 
11306  SCIP_ALLOC_ABORT( BMSallocBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren) );
11307  for( c = 0; c < node->nchildren; ++c )
11308  childrenbounds[c] = node->children[c]->bounds;
11309 
11310  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, node->nchildren, childrenbounds, node->bounds, cutoff) );
11311 
11312  for( c = 0; !*cutoff && c < node->nchildren; ++c )
11313  {
11314  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[c], childrenbounds[c], minstrength, infinity, cutoff);
11315  }
11316 
11317  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren);
11318 
11319  break;
11320  }
11321 
11322  case SCIP_EXPR_LAST:
11323  SCIPABORT();
11324  break;
11325  }
11326 }
11327 
11328 /** removes duplicate children in a polynomial expression node
11329  *
11330  * Leaves NULL's in children array.
11331  */
11332 static
11334  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11335  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11336  )
11337 {
11338  SCIP_Bool foundduplicates;
11339  int* childmap;
11340  int i;
11341  int j;
11342 
11343  assert(exprgraph != NULL);
11344  assert(node != NULL);
11345  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11346 
11347  if( node->nchildren == 0 )
11348  return SCIP_OKAY;
11349 
11350  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
11351 
11352  foundduplicates = FALSE;
11353  for( i = 0; i < node->nchildren; ++i )
11354  {
11355  if( node->children[i] == NULL )
11356  continue;
11357  childmap[i] = i; /*lint !e644*/
11358 
11359  for( j = i+1; j < node->nchildren; ++j )
11360  {
11361  if( node->children[j] == NULL )
11362  continue;
11363 
11364  if( node->children[i] == node->children[j] )
11365  {
11366  /* node should be parent of children[j] at least twice,
11367  * so we remove it once
11368  */
11369  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
11370  node->children[j] = NULL;
11371  assert(exprgraphNodeIsParent(node->children[i], node));
11372 
11373  childmap[j] = i;
11374  foundduplicates = TRUE;
11375  }
11376  }
11377  }
11378 
11379  /* apply childmap to monomials */
11380  if( foundduplicates )
11382 
11383  /* free childmap */
11384  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
11385 
11386  return SCIP_OKAY;
11387 }
11388 
11389 /** eliminates NULL's in children array and shrinks it to actual size */
11390 static
11392  BMS_BLKMEM* blkmem, /**< block memory */
11393  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11394  )
11395 {
11396  int* childmap;
11397  int lastnonnull;
11398  int i;
11399 
11400  assert(blkmem != NULL);
11401  assert(node != NULL);
11402  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11403 
11404  if( node->nchildren == 0 )
11405  return SCIP_OKAY;
11406 
11407  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
11408 
11409  /* close gaps in children array */
11410  lastnonnull = node->nchildren-1;
11411  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11412  --lastnonnull;
11413  for( i = 0; i <= lastnonnull; ++i )
11414  {
11415  if( node->children[i] != NULL )
11416  {
11417  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
11418  continue;
11419  }
11420  assert(node->children[lastnonnull] != NULL);
11421 
11422  /* move child at lastnonnull to position i */
11423  node->children[i] = node->children[lastnonnull];
11424  node->children[lastnonnull] = NULL;
11425  childmap[lastnonnull] = i;
11426 
11427  /* update lastnonnull */
11428  --lastnonnull;
11429  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11430  --lastnonnull;
11431  }
11432  assert(i > lastnonnull);
11433 
11434  /* apply childmap to monomials */
11435  if( lastnonnull < node->nchildren-1 )
11437 
11438  BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
11439 
11440  /* shrink children array */
11441  if( lastnonnull >= 0 )
11442  {
11443  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
11444  node->nchildren = lastnonnull+1;
11445  }
11446  else
11447  {
11448  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11449  node->nchildren = 0;
11450  }
11451 
11452  return SCIP_OKAY;
11453 }
11454 
11455 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
11456  *
11457  * Converts node into polynomial, if possible and not constant.
11458  */
11459 static
11461  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11462  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
11463  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
11464  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
11465  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
11466  SCIP_Bool* havechange /**< flag to set if the node has been changed */
11467  )
11468 {
11469  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11470  SCIP_EXPRDATA_MONOMIAL* monomial;
11471  BMS_BLKMEM* blkmem;
11472  SCIP_Bool removechild;
11473  SCIP_Bool* childinuse;
11474  int* childmap;
11475  int childmapsize;
11476  int i;
11477  int j;
11478  int orignchildren;
11479 
11480  assert(exprgraph != NULL);
11481  assert(node != NULL);
11482  assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
11483  assert(havechange != NULL);
11484 
11485  blkmem = exprgraph->blkmem;
11486  assert(blkmem != NULL);
11487 
11488  SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
11489 
11490  /* if all children are constants, then turn this node into constant */
11491  for( i = 0; i < node->nchildren; ++i )
11492  if( node->children[i]->op != SCIP_EXPR_CONST )
11493  break;
11494  if( node->nchildren > 0 && i == node->nchildren )
11495  {
11496  /* get value of node */
11498  assert(node->value != SCIP_INVALID); /*lint !e777*/
11499 
11500  SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
11501  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11502  SCIPdebugPrintf("\n");
11503 
11504  /* free expression data */
11505  if( exprOpTable[node->op].freedata != NULL )
11506  exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
11507 
11508  /* disconnect from children */
11509  for( i = 0; i < node->nchildren; ++i )
11510  {
11511  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11512  }
11513  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11514  node->nchildren = 0;
11515 
11516  /* turn into constant expression */
11517  node->op = SCIP_EXPR_CONST;
11518  node->data.dbl = node->value;
11519 
11520  *havechange = TRUE;
11521  node->simplified = TRUE;
11522 
11523  return SCIP_OKAY;
11524  }
11525 
11526  /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
11527  * @todo log(product) -> sum(log)
11528  * @todo product(exp) -> exp(sum)
11529  * @todo exp(x)^p -> exp(p*x)
11530  * @todo exp(const*log(x)) -> x^const
11531  */
11532 
11533  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
11534 
11535  if( node->op != SCIP_EXPR_POLYNOMIAL )
11536  {
11537  node->simplified = TRUE;
11538  return SCIP_OKAY;
11539  }
11540 
11541  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11542  assert(polynomialdata != NULL);
11543 
11544  orignchildren = node->nchildren;
11545 
11546  /* check if we have duplicate children and merge */
11548  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11549 
11550  SCIPdebugMessage("expand factors in expression node ");
11551  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11552  SCIPdebugPrintf("\n");
11553 
11554  childmap = NULL;
11555  childmapsize = 0;
11556 
11557  /* resolve children that are constants
11558  * we do this first, because it reduces the degree and number of factors in the monomials,
11559  * 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
11560  */
11561  for( i = 0; i < node->nchildren; ++i )
11562  {
11563  if( node->children[i] == NULL )
11564  continue;
11565 
11566  /* convert children to polynomial, if not constant or polynomial
11567  * if child was simplified in this round, it may have already been converted, and then nothing happens
11568  * but if child was already simplified, then it was not converted, and thus we try it here
11569  */
11570  if( node->children[i]->op != SCIP_EXPR_CONST )
11571  continue;
11572 
11573  SCIPdebugMessage("expand child %d in expression node ", i);
11574  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11575  SCIPdebugPrintf("\n\tchild = ");
11576  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11577  SCIPdebugPrintf("\n");
11578 
11579  removechild = TRUE; /* we intend to release children[i] */
11580 
11581  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11582 
11583  /* put constant of child i into every monomial where child i is used */
11584  for( j = 0; j < polynomialdata->nmonomials; ++j )
11585  {
11586  int factorpos;
11587 
11588  monomial = polynomialdata->monomials[j];
11589  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11590  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11591 
11592  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11593  {
11594  assert(factorpos >= 0);
11595  assert(factorpos < monomial->nfactors);
11596  /* assert that factors have been merged */
11597  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11598  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11599 
11600  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11601 
11602  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 ) /*lint !e835*/
11603  {
11604  /* if constant is negative and our exponent is not integer, then cannot do expansion */
11605  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
11606  removechild = FALSE;
11607  }
11608  else
11609  {
11610  monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
11611 
11612  /* move last factor to position factorpos */
11613  if( factorpos < monomial->nfactors-1 )
11614  {
11615  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
11616  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
11617  }
11618  --monomial->nfactors;
11619  monomial->sorted = FALSE;
11620  polynomialdata->sorted = FALSE;
11621 
11622  *havechange = TRUE;
11623  }
11624  }
11625  }
11626 
11627  /* forget about child i, if it is not used anymore */
11628  if( removechild )
11629  {
11630  /* remove node from list of parents of child i */
11631  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11632  node->children[i] = NULL;
11633  }
11634 
11635  /* simplify current polynomial again */
11636  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11637  }
11638 
11639  /* resolve children that are polynomials itself */
11640  for( i = 0; i < node->nchildren; ++i )
11641  {
11642  if( node->children[i] == NULL )
11643  continue;
11644 
11645  /* convert children to polynomial, if not constant or polynomial
11646  * if child was simplified in this round, it may have already been converted, and then nothing happens
11647  * but if child was already simplified, then it was not converted, and thus we try it here
11648  */
11649  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
11650 
11651  if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
11652  continue;
11653 
11654  SCIPdebugMessage("expand child %d in expression node %p = ", i, (void*)node);
11655  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11656  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n\tchild = ") );
11657  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11658  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
11659 
11660  removechild = TRUE; /* we intend to release children[i] */
11661 
11662  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11663 
11664  /* add children of child i to node */
11665  SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
11666 
11667  /* put polynomial of child i into every monomial where child i is used */
11668  j = 0;
11669  while( j < polynomialdata->nmonomials )
11670  {
11671  int factorpos;
11672  SCIP_Bool success;
11673 
11674  monomial = polynomialdata->monomials[j];
11675  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11676  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11677 
11678  /* make sure factors are merged, should only be potentially necessary if not sorted, see also #1848 */
11679  if( !monomial->sorted )
11680  SCIPexprMergeMonomialFactors(monomial, eps);
11681 
11682  if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11683  {
11684  ++j;
11685  continue;
11686  }
11687 
11688  assert(factorpos >= 0);
11689  assert(factorpos < monomial->nfactors);
11690  /* assert that factors have been merged */
11691  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11692  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11693 
11694  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11695 
11696  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
11697  (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
11698 
11699  if( !success )
11700  {
11701  removechild = FALSE;
11702  ++j;
11703  }
11704  else
11705  *havechange = TRUE;
11706 
11707  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
11708  * we thus repeat with index j, if a factor was successfully expanded
11709  */
11710  }
11711 
11712  /* forget about child i, if it is not used anymore */
11713  if( removechild )
11714  {
11715  /* remove node from list of parents of child i */
11716  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11717  node->children[i] = NULL;
11718  }
11719  }
11720 
11721  /* simplify current polynomial again */
11722  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11723 
11724  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
11725 
11726  /* check which children are still in use */
11727  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
11728  BMSclearMemoryArray(childinuse, node->nchildren); /*lint !e644*/
11729  for( i = 0; i < polynomialdata->nmonomials; ++i )
11730  {
11731  monomial = polynomialdata->monomials[i];
11732  assert(monomial != NULL);
11733 
11734  for( j = 0; j < monomial->nfactors; ++j )
11735  {
11736  assert(monomial->childidxs[j] >= 0);
11737  assert(monomial->childidxs[j] < node->nchildren);
11738  childinuse[monomial->childidxs[j]] = TRUE;
11739  }
11740  }
11741 
11742  /* free children that are not used in any monomial */
11743  for( i = 0; i < node->nchildren; ++i )
11744  if( node->children[i] != NULL && !childinuse[i] )
11745  {
11746  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11747  node->children[i] = NULL;
11748  }
11749 
11750  BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
11751 
11752  /* remove NULLs from children array */
11754 
11755  /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
11756  if( node->nchildren == 0 )
11757  {
11758  SCIP_Real val;
11759 
11760  /* if no children, then it should also have no monomials */
11761  assert(polynomialdata->nmonomials == 0);
11762 
11763  val = polynomialdata->constant;
11764  polynomialdataFree(blkmem, &polynomialdata);
11765 
11766  node->op = SCIP_EXPR_CONST;
11767  node->data.dbl = val;
11768  node->value = val;
11769  }
11770 
11771  /* if no factor in a monomial was replaced, the number of children should not have changed
11772  * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11773  */
11774  *havechange |= (node->nchildren < orignchildren); /*lint !e514*/
11775 
11776  node->simplified = TRUE;
11777 
11778  SCIPdebugMessage("-> %p = ", (void*)node);
11779  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11780  SCIPdebugPrintf("\n");
11781 
11782  return SCIP_OKAY;
11783 }
11784 
11785 /** creates an expression from a given node in an expression graph
11786  *
11787  * Assembles mapping of variables from graph to tree.
11788  */
11789 static
11791  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11792  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which expression should be created */
11793  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
11794  int* nexprvars, /**< current number of variables in expression */
11795  int* varidx /**< current mapping of variable indices from graph to expression */
11796  )
11797 {
11798  SCIP_EXPR** childexprs;
11799  int i;
11800 
11801  assert(exprgraph != NULL);
11802  assert(node != NULL);
11803  assert(expr != NULL);
11804  assert(nexprvars != NULL);
11805  assert(*nexprvars >= 0);
11806  assert(varidx != NULL);
11807 
11808  childexprs = NULL;
11809  if( node->nchildren > 0 )
11810  {
11811  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11812  for( i = 0; i < node->nchildren; ++i )
11813  {
11814  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) ); /*lint !e613*/
11815  }
11816  }
11817 
11818  switch( node->op )
11819  {
11820  case SCIP_EXPR_VARIDX:
11821  {
11822  /* check if the variable already has an index assigned in the expression tree
11823  * if not, create one and increase nexprvars
11824  */
11825  assert(node->data.intval >= 0);
11826  assert(node->data.intval < exprgraph->nvars);
11827  assert(varidx[node->data.intval] >= -1);
11828  assert(varidx[node->data.intval] < *nexprvars);
11829  if( varidx[node->data.intval] == -1 )
11830  {
11831  varidx[node->data.intval] = *nexprvars;
11832  ++*nexprvars;
11833  }
11834 
11835  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11836  break;
11837  }
11838 
11839  case SCIP_EXPR_CONST:
11840  {
11841  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11842  break;
11843  }
11844 
11845  case SCIP_EXPR_REALPOWER:
11846  case SCIP_EXPR_SIGNPOWER:
11847  {
11848  assert(node->nchildren == 1);
11849  assert(childexprs != NULL);
11850  /* coverity[var_deref_op] */
11851  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11852  break;
11853  }
11854 
11855  case SCIP_EXPR_INTPOWER:
11856  {
11857  assert(node->nchildren == 1);
11858  assert(childexprs != NULL);
11859  /* coverity[var_deref_op] */
11860  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11861  break;
11862  }
11863 
11864  case SCIP_EXPR_PLUS:
11865  case SCIP_EXPR_MINUS:
11866  case SCIP_EXPR_MUL:
11867  case SCIP_EXPR_DIV:
11868  case SCIP_EXPR_MIN:
11869  case SCIP_EXPR_MAX:
11870  {
11871  assert(node->nchildren == 2);
11872  assert(childexprs != NULL);
11873  /* coverity[var_deref_op] */
11874  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11875  break;
11876  }
11877 
11878  case SCIP_EXPR_SQUARE:
11879  case SCIP_EXPR_SQRT:
11880  case SCIP_EXPR_EXP:
11881  case SCIP_EXPR_LOG:
11882  case SCIP_EXPR_SIN:
11883  case SCIP_EXPR_COS:
11884  case SCIP_EXPR_TAN:
11885  /* case SCIP_EXPR_ERF: */
11886  /* case SCIP_EXPR_ERFI: */
11887  case SCIP_EXPR_ABS:
11888  case SCIP_EXPR_SIGN:
11889  {
11890  assert(node->nchildren == 1);
11891  assert(childexprs != NULL);
11892  /* coverity[var_deref_op] */
11893  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11894  break;
11895  }
11896 
11897  case SCIP_EXPR_SUM:
11898  case SCIP_EXPR_PRODUCT:
11899  {
11900  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11901  break;
11902  }
11903 
11904  case SCIP_EXPR_LINEAR:
11905  {
11906  assert(node->data.data != NULL);
11907 
11908  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11909  break;
11910  }
11911 
11912  case SCIP_EXPR_QUADRATIC:
11913  {
11914  SCIP_EXPRDATA_QUADRATIC* quaddata;
11915 
11916  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11917  assert(quaddata != NULL);
11918 
11919  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11920  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11921  break;
11922  }
11923 
11924  case SCIP_EXPR_POLYNOMIAL:
11925  {
11926  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11927 
11928  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11929  assert(polynomialdata != NULL);
11930 
11931  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11932  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11933 
11934  break;
11935  }
11936 
11937  case SCIP_EXPR_USER:
11938  {
11939  SCIP_EXPRDATA_USER* exprdata;
11940  SCIP_USEREXPRDATA* userdata;
11941 
11942  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11943  assert(exprdata != NULL);
11944 
11945  if( exprdata->copydata != NULL )
11946  {
11947  SCIP_CALL( exprdata->copydata(exprgraph->blkmem, node->nchildren, exprdata->userdata, &userdata) );
11948  }
11949  else
11950  userdata = exprdata->userdata;
11951 
11952  /* coverity[var_deref_op] */
11953  SCIP_CALL( SCIPexprCreateUser(exprgraph->blkmem, expr, node->nchildren, childexprs,
11954  userdata, exprdata->evalcapability, exprdata->eval, exprdata->inteval, exprdata->curv, exprdata->prop, exprdata->estimate, exprdata->copydata, exprdata->freedata, exprdata->print) );
11955 
11956  break;
11957  }
11958 
11959  case SCIP_EXPR_LAST:
11960  case SCIP_EXPR_PARAM:
11961  {
11962  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11963  return SCIP_ERROR;
11964  }
11965  }
11966 
11967  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11968 
11969  return SCIP_OKAY;
11970 }
11971 
11972 /** counts how often expression graph variables are used in a subtree of the expression graph
11973  *
11974  * @note The function does not clear the array first, but only increases already existing counts.
11975  */
11976 static
11978  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11979  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11980  )
11981 {
11982  int i;
11983 
11984  assert(node != NULL);
11985  assert(varsusage != NULL);
11986 
11987  if( node->op == SCIP_EXPR_VARIDX )
11988  {
11989  ++varsusage[node->data.intval];
11990  return;
11991  }
11992 
11993  for( i = 0; i < node->nchildren; ++i )
11994  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
11995 }
11996 
11997 /** checks whether a node can be put into a component when checking block separability of an expression
11998  *
11999  * If a variable used by node is already in another component, components are merged and component number is updated.
12000  */
12001 static
12003  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
12004  int* compnr, /**< component number to assign, may be reduced if variables overlap */
12005  int nchildcomps, /**< number of entries for which childcomps have been set already */
12006  int* childcomps, /**< component numbers of children */
12007  int nvars, /**< number of variables */
12008  int* varcomps /**< component numbers of variables */
12009  )
12010 {
12011  int varidx;
12012  int i;
12013 
12014  assert(node != NULL);
12015  assert(compnr != NULL);
12016  assert(*compnr >= 0);
12017  assert(childcomps != NULL);
12018  assert(varcomps != NULL);
12019 
12020  if( node->op != SCIP_EXPR_VARIDX )
12021  {
12022  for( i = 0; i < node->nchildren; ++i )
12023  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
12024  return;
12025  }
12026 
12027  varidx = node->data.intval;
12028  assert(varidx >= 0);
12029  assert(varidx < nvars);
12030 
12031  if( varcomps[varidx] == -1 )
12032  {
12033  /* first time we get to this variable, so set it's component to compnr and we are done */
12034  varcomps[varidx] = *compnr;
12035  return;
12036  }
12037 
12038  if( varcomps[varidx] == *compnr )
12039  {
12040  /* variable is already in current component, that's also good and we are done */
12041  return;
12042  }
12043 
12044  /* variable is already in another component, so have to merge component compnr into that component
12045  * do this by updating varcomps and childcomps */
12046  for( i = 0; i < nvars; ++i )
12047  if( varcomps[i] == *compnr )
12048  varcomps[i] = varcomps[varidx];
12049  for( i = 0; i < nchildcomps; ++i )
12050  if( childcomps[i] == *compnr )
12051  /* coverity[copy_paste_error] */
12052  childcomps[i] = varcomps[varidx];
12053  *compnr = varcomps[varidx];
12054 }
12055 
12056 /**@} */
12057 
12058 /**@name Expression graph private methods */
12059 /**@{ */
12060 
12061 /** assert that expression graph has at least a given depth */
12062 static
12064  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
12065  int mindepth /**< minimal depth that should be ensured */
12066  )
12067 {
12068  int olddepth;
12069 
12070  assert(exprgraph != NULL);
12071  assert(exprgraph->blkmem != NULL);
12072 
12073  if( mindepth <= exprgraph->depth )
12074  return SCIP_OKAY;
12075 
12076  olddepth = exprgraph->depth;
12077  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
12078  assert(exprgraph->depth >= mindepth);
12079 
12080  /* initialize new array entries to 0 and NULL, resp. */
12081  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12082  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12083  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12084 
12085  return SCIP_OKAY;
12086 }
12087 
12088 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
12089 static
12091  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12092  int varidx /**< variable index */
12093  )
12094 {
12095  SCIP_EXPRGRAPHNODE* varnode;
12096  void* var;
12097 
12098  assert(exprgraph != NULL);
12099  assert(varidx >= 0);
12100  assert(varidx < exprgraph->nvars);
12101 
12102  varnode = exprgraph->varnodes[varidx];
12103  assert(varnode->data.intval == varidx);
12104 
12105  var = exprgraph->vars[varidx];
12106 
12107  /* call varremove callback method, if set */
12108  if( exprgraph->exprgraphvarremove != NULL )
12109  {
12110  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
12111  }
12112 
12113  /* remove variable from hashmap */
12114  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
12115 
12116  /* move last variable to position varidx and give it the new index */
12117  if( varidx < exprgraph->nvars-1 )
12118  {
12119  /* call callback method, if set */
12120  if( exprgraph->exprgraphvarchgidx != NULL )
12121  {
12122  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
12123  }
12124 
12125  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
12126  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
12127  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
12128  exprgraph->varnodes[varidx]->data.intval = varidx;
12129  SCIP_CALL( SCIPhashmapSetImageInt(exprgraph->varidxs, exprgraph->vars[varidx], varidx) );
12130  }
12131  --exprgraph->nvars;
12132 
12133  return SCIP_OKAY;
12134 }
12135 
12136 /** moves a node in an expression graph to a different depth
12137  *
12138  * New depth must be larger than children depth.
12139  * Moves parent nodes to higher depth, if needed.
12140  * Variable nodes cannot be moved.
12141  */
12142 static
12144  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12145  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
12146  int newdepth /**< new depth to which to move node */
12147  )
12148 {
12149  int olddepth;
12150  int oldpos;
12151  int i;
12152 
12153  assert(exprgraph != NULL);
12154  assert(node != NULL);
12155  assert(node->depth >= 0); /* node should be in graph */
12156  assert(newdepth >= 0);
12157 
12158  /* if already on aimed depth, then don't need to move */
12159  if( node->depth == newdepth )
12160  return SCIP_OKAY;
12161 
12162  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
12163 
12164 #ifndef NDEBUG
12165  /* assert that children are at lower depth than new depth */
12166  for( i = 0; i < node->nchildren; ++i )
12167  assert(node->children[i]->depth < newdepth);
12168 #endif
12169 
12170  /* move parents to higher depth, if needed */
12171  for( i = 0; i < node->nparents; ++i )
12172  {
12173  if( node->parents[i]->depth <= newdepth )
12174  {
12175  /* move parent to depth+1 */
12176  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
12177  assert(node->parents[i]->depth > newdepth);
12178  }
12179  }
12180 
12181  /* ensure that graph is deep enough */
12182  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
12183  assert(exprgraph->depth > newdepth);
12184 
12185  olddepth = node->depth;
12186  oldpos = node->pos;
12187 
12188  /* add node to new depth */
12189  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
12190  node->depth = newdepth;
12191  node->pos = exprgraph->nnodes[newdepth];
12192  exprgraph->nodes[newdepth][node->pos] = node;
12193  ++exprgraph->nnodes[newdepth];
12194 
12195  /* by moving the node to a new depth, the parents array in all its childrens may not be sorted anymore (parents order depends on depth) */
12196  for( i = 0; i < node->nchildren; ++i )
12197  node->children[i]->parentssorted = FALSE;
12198 
12199  /* move last node at previous depth to previous position, if it wasn't last */
12200  if( oldpos < exprgraph->nnodes[olddepth]-1 )
12201  {
12202  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
12203  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
12204 
12205  /* by moving the node to a new position, the parents array in all its children may not be sorted anymore (parents order depends on depth) */
12206  for( i = 0; i < exprgraph->nodes[olddepth][oldpos]->nchildren; ++i )
12207  exprgraph->nodes[olddepth][oldpos]->children[i]->parentssorted = FALSE;
12208  }
12209  --exprgraph->nnodes[olddepth];
12210 
12211  if( node->depth == 0 )
12212  {
12213  /* if at depth 0, then it need to be a node for either a constant or a variable */
12214  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
12215  if( node->op == SCIP_EXPR_CONST )
12216  {
12217  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
12218  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
12219  exprgraph->constnodes[exprgraph->nconsts] = node;
12220  ++exprgraph->nconsts;
12221  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
12222  }
12223  else
12224  {
12225  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
12226  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
12227  return SCIP_ERROR;
12228  }
12229 
12230  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
12231  node->curv = SCIP_EXPRCURV_LINEAR;
12232  }
12233 
12234  return SCIP_OKAY;
12235 }
12236 
12237 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
12238 static
12240  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12241  int nchildren, /**< number of children */
12242  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
12243  SCIP_EXPROP op, /**< operator */
12244  SCIP_EXPROPDATA opdata, /**< operator data */
12245  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
12246  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
12247  )
12248 {
12249  SCIP_EXPRGRAPHNODE** parentcands;
12250  int nparentcands;
12251  int parentcandssize;
12252  int i;
12253  int p;
12254 
12255  assert(exprgraph != NULL);
12256  assert(nchildren > 0);
12257  assert(children != NULL);
12258  assert(parent != NULL);
12259 
12260  *parent = NULL;
12261 
12262  /* create initial set of parent candidates as
12263  * all parents of first child that have the same operator type and the same number of children
12264  * additionally, some easy conditions for complex expression types:
12265  * if expression type is int/real/signpower, then compare also exponent,
12266  * if expression type is linear, then compare also constant part,
12267  * if expression type is quadratic, then compare also number of quadratic elements,
12268  * if expression type is polynomial, then compare also number of monmials and constant part
12269  */
12270  parentcandssize = children[0]->nparents;
12271  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
12272  nparentcands = 0;
12273  for( p = 0; p < children[0]->nparents; ++p )
12274  if( children[0]->parents[p]->op == op &&
12275  children[0]->parents[p]->nchildren == nchildren &&
12276  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
12277  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12278  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12279  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
12280  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
12281  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
12282  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
12283  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
12284  )
12285  {
12286  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
12287  }
12288 
12289  /* for all remaining children, remove parent candidates, that are not in their list of parents */
12290  for( i = 1; i < nchildren && nparentcands > 0; ++i )
12291  {
12292  p = 0;
12293  while( p < nparentcands )
12294  {
12295  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
12296  * otherwise keep candidate and check next one
12297  */
12298  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
12299  {
12300  parentcands[p] = parentcands[nparentcands-1];
12301  --nparentcands;
12302  }
12303  else
12304  ++p;
12305  }
12306  }
12307 
12308  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
12309 
12310  if( nparentcands == 0 )
12311  {
12312  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
12313  return SCIP_OKAY;
12314  }
12315 
12316  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
12317  * check if there is also one which corresponds to same expression and store that one in *parent
12318  */
12319  switch( op )
12320  {
12321  /* commutative operands with no data */
12322  case SCIP_EXPR_PLUS :
12323  case SCIP_EXPR_MUL :
12324  case SCIP_EXPR_MIN :
12325  case SCIP_EXPR_MAX :
12326  case SCIP_EXPR_SUM :
12327  case SCIP_EXPR_PRODUCT:
12328  case SCIP_EXPR_SQUARE :
12329  case SCIP_EXPR_SQRT :
12330  case SCIP_EXPR_EXP :
12331  case SCIP_EXPR_LOG :
12332  case SCIP_EXPR_SIN :
12333  case SCIP_EXPR_COS :
12334  case SCIP_EXPR_TAN :
12335  /* case SCIP_EXPR_ERF : */
12336  /* case SCIP_EXPR_ERFI : */
12337  case SCIP_EXPR_ABS :
12338  case SCIP_EXPR_SIGN :
12339  {
12340  /* sort childnodes, if needed for later */
12341  if( nchildren > 2 )
12342  SCIPsortPtr((void**)children, exprgraphnodecomp, nchildren);
12343  for( p = 0; p < nparentcands; ++p )
12344  {
12345  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12346  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12347 
12348  if( nchildren == 1 )
12349  {
12350  assert(parentcands[p]->children[0] == children[0]);
12351  /* same operand, same child, so same expression */
12352  *parent = parentcands[p];
12353  break;
12354  }
12355  else if( nchildren == 2 )
12356  {
12357  /* We know that every node in children is also a child of parentcands[p].
12358  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
12359  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
12360  */
12361  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
12362  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
12363  {
12364  *parent = parentcands[p];
12365  break;
12366  }
12367  }
12368  else
12369  {
12370  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
12371 
12372  /* sort children of parent candidate */
12373  SCIPsortPtr((void**)parentcands[p]->children, exprgraphnodecomp, nchildren);
12374 
12375  /* check if childnodes and parentcands[p]->children are the same */
12376  for( i = 0; i < nchildren; ++i )
12377  if( children[i] != parentcands[p]->children[i] )
12378  break;
12379  if( i == nchildren )
12380  {
12381  /* yeah, found an exact match */
12382  *parent = parentcands[p];
12383  break;
12384  }
12385  }
12386  }
12387 
12388  break;
12389  }
12390 
12391  /* non-commutative operands with two children */
12392  case SCIP_EXPR_MINUS :
12393  case SCIP_EXPR_DIV :
12394  {
12395  for( p = 0; p < nparentcands; ++p )
12396  {
12397  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12398  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
12399  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
12400  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
12401  {
12402  /* yeah, found one */
12403  *parent = parentcands[p];
12404  break;
12405  }
12406  }
12407 
12408  break;
12409  }
12410 
12411  /* operands with one child and data */
12412  case SCIP_EXPR_INTPOWER:
12413  {
12414  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12415  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12416  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12417  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
12418 
12419  /* yeah, have one with same exponent */
12420  *parent = parentcands[0];
12421 
12422  break;
12423  }
12424 
12425  case SCIP_EXPR_REALPOWER:
12426  case SCIP_EXPR_SIGNPOWER:
12427  {
12428  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12429  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12430  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12431  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
12432 
12433  /* yeah, have one with same exponent */
12434  *parent = parentcands[0];
12435 
12436  break;
12437  }
12438 
12439  /* commutative operands with n children and data */
12440  case SCIP_EXPR_LINEAR:
12441  {
12442  SCIP_Real* exprcoef;
12443  SCIP_Real* candcoef;
12444 
12445  exprcoef = (SCIP_Real*)opdata.data;
12446  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
12447  if( exprchildren != NULL )
12448  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, exprgraphnodecomp, nchildren);
12449  else
12450  SCIPsortPtrReal((void**)children, exprcoef, exprgraphnodecomp, nchildren);
12451  for( p = 0; p < nparentcands; ++p )
12452  {
12453  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12454  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12455 
12456  candcoef = (SCIP_Real*)parentcands[p]->data.data;
12457  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12458 
12459  /* sort children of parent candidate */
12460  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, exprgraphnodecomp, nchildren);
12461 
12462  /* check if children and coefficients in parent candidate and expression are the same */
12463  for( i = 0; i < nchildren; ++i )
12464  {
12465  if( children[i] != parentcands[p]->children[i] )
12466  break;
12467  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
12468  break;
12469  }
12470  if( i < nchildren )
12471  continue;
12472 
12473  /* yeah, found an exact match */
12474  *parent = parentcands[p];
12475  break;
12476  }
12477 
12478  break;
12479  }
12480 
12481  case SCIP_EXPR_QUADRATIC:
12482  {
12483  SCIP_EXPRDATA_QUADRATIC* exprdata;
12484  SCIP_Real* exprlincoef;
12485  SCIP_Real* candlincoef;
12486  SCIP_EXPRDATA_QUADRATIC* canddata;
12487  int* perm;
12488  int* invperm;
12489 
12490  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
12491  exprlincoef = exprdata->lincoefs;
12492 
12493  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
12494 
12495  /* sort expr->children and childnodes and store inverse permutation in invperm */
12496  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12497  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12498  for( i = 0; i < nchildren; ++i )
12499  invperm[i] = i; /*lint !e644*/
12500 
12501  if( exprlincoef != NULL )
12502  if( exprchildren != NULL )
12503  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12504  else
12505  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12506  else
12507  if( exprchildren != NULL )
12508  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12509  else
12510  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12511 
12512  /* compute permutation from its inverse */
12513  for( i = 0; i < nchildren; ++i )
12514  perm[invperm[i]] = i; /*lint !e644*/
12515 
12516  /* apply permuation to exprdata->quadelems and sort again */
12517  for( i = 0; i < exprdata->nquadelems; ++i )
12518  {
12519  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
12520  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
12521  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
12522  {
12523  int tmp;
12524  tmp = exprdata->quadelems[i].idx1;
12525  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
12526  exprdata->quadelems[i].idx2 = tmp;
12527  }
12528  }
12529  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
12530  exprdata->sorted = TRUE;
12531 
12532  for( p = 0; p < nparentcands; ++p )
12533  {
12534  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12535  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12536 
12537  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
12538  candlincoef = canddata->lincoefs;
12539  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
12540  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12541 
12542  /* sort parentcands[p]->children and store inverse permutation in invperm */
12543  for( i = 0; i < nchildren; ++i )
12544  invperm[i] = i;
12545 
12546  if( candlincoef != NULL )
12547  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, exprgraphnodecomp, parentcands[p]->nchildren);
12548  else
12549  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12550 
12551  /* compute permutation from its inverse */
12552  for( i = 0; i < nchildren; ++i )
12553  perm[invperm[i]] = i;
12554 
12555  /* apply permutation to canddata->quadelems */
12556  for( i = 0; i < canddata->nquadelems; ++i )
12557  {
12558  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
12559  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
12560  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
12561  {
12562  int tmp;
12563  tmp = canddata->quadelems[i].idx1;
12564  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
12565  canddata->quadelems[i].idx2 = tmp;
12566  }
12567  }
12568  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
12569  canddata->sorted = TRUE;
12570 
12571  /* check if children and linear coefficients in parent candidate and expression are the same */
12572  for( i = 0; i < nchildren; ++i )
12573  {
12574  if( children[i] != parentcands[p]->children[i] )
12575  break;
12576  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
12577  break;
12578  }
12579  if( i < nchildren )
12580  continue;
12581 
12582  assert(exprdata->nquadelems == canddata->nquadelems);
12583  for( i = 0; i < exprdata->nquadelems; ++i )
12584  {
12585  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
12586  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
12587  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
12588  break;
12589  }
12590  if( i == exprdata->nquadelems )
12591  {
12592  /* yeah, parentcands[p] is same quadratic expression as expr */
12593  *parent = parentcands[p];
12594  break;
12595  }
12596  }
12597 
12598  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12599  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12600 
12601  break;
12602  }
12603 
12604  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
12605  case SCIP_EXPR_POLYNOMIAL:
12606  {
12607  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
12608  SCIP_EXPRDATA_POLYNOMIAL* canddata;
12609  int* perm;
12610  int* invperm;
12611 
12612  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
12613 
12614  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
12615 
12616  /* sort exprchildren and childnodes and store inverse permutation in invperm */
12617  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12618  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12619  for( i = 0; i < nchildren; ++i )
12620  invperm[i] = i; /*lint !e644*/
12621 
12622  if( exprchildren != NULL )
12623  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12624  else
12625  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12626 
12627  /* compute permutation from its inverse */
12628  for( i = 0; i < nchildren; ++i )
12629  perm[invperm[i]] = i; /*lint !e644*/
12630 
12631  /* apply permutation to exprdata and sort again */
12632  polynomialdataApplyChildmap(exprdata, perm);
12633  polynomialdataSortMonomials(exprdata);
12634 
12635  for( p = 0; p < nparentcands; ++p )
12636  {
12637  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12638  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12639 
12640  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
12641  assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
12642  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12643 
12644  /* sort parentcands[p]->children and store inverse permutation in invperm */
12645  for( i = 0; i < nchildren; ++i )
12646  invperm[i] = i;
12647 
12648  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12649 
12650  /* compute permutation from its inverse */
12651  for( i = 0; i < nchildren; ++i )
12652  perm[invperm[i]] = i;
12653 
12654  /* apply permutation to canddata and sort again */
12655  polynomialdataApplyChildmap(canddata, perm);
12656  polynomialdataSortMonomials(canddata);
12657 
12658  /* check if children are equal */
12659  for( i = 0; i < nchildren; ++i )
12660  if( children[i] != parentcands[p]->children[i] )
12661  break;
12662  if( i < nchildren )
12663  continue;
12664 
12665  /* check if monomials are equal */
12666  for( i = 0; i < exprdata->nmonomials; ++i )
12667  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
12668  break;
12669  if( i == exprdata->nmonomials )
12670  {
12671  /* yeah, parentcands[p] is same polynomial expression as expr */
12672  *parent = parentcands[p];
12673  break;
12674  }
12675  }
12676 
12677  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12678  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12679 
12680  break;
12681  }
12682 
12683  case SCIP_EXPR_USER:
12684  {
12685  /* @todo need comparison function on user data to decide whether a parent candidate fits */
12686  break;
12687  }
12688 
12689  case SCIP_EXPR_VARIDX:
12690  case SCIP_EXPR_PARAM:
12691  case SCIP_EXPR_CONST:
12692  case SCIP_EXPR_LAST:
12693  SCIPerrorMessage("expression operand %d unexpected here\n", op);
12694  return SCIP_ERROR;
12695  }
12696 
12697  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
12698 
12699  return SCIP_OKAY;
12700 }
12701 
12702 /** adds an expression into an expression graph
12703  *
12704  * Enables corresponding nodes.
12705  */
12706 static
12708  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12709  SCIP_EXPR* expr, /**< expression to add */
12710  void** vars, /**< variables corresponding to VARIDX expressions */
12711  SCIP_Real* params, /**< parameter values */
12712  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
12713  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12714  )
12715 {
12716  SCIP_EXPRGRAPHNODE** childnodes;
12717  SCIP_Bool childisnew;
12718  SCIP_Bool nochildisnew;
12719  SCIP_EXPROPDATA opdata;
12720  int i;
12721 
12722  assert(exprgraph != NULL);
12723  assert(expr != NULL);
12724  assert(exprnode != NULL);
12725  assert(exprnodeisnew != NULL);
12726 
12727  if( expr->op == SCIP_EXPR_VARIDX )
12728  {
12729  /* find node corresponding to variable and add if not existing yet */
12730  assert(expr->nchildren == 0);
12731 
12732  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12733  assert(*exprnode != NULL);
12734  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12735  assert((*exprnode)->data.intval >= 0);
12736  assert((*exprnode)->data.intval < exprgraph->nvars);
12737  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12738 
12739  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12740 
12741  return SCIP_OKAY;
12742  }
12743 
12744  if( expr->op == SCIP_EXPR_CONST )
12745  {
12746  /* find node corresponding to constant and add if not existing yet */
12747  assert(expr->nchildren == 0);
12748 
12749  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12750  assert(*exprnode != NULL);
12751  assert((*exprnode)->op == SCIP_EXPR_CONST);
12752  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
12753 
12754  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12755 
12756  return SCIP_OKAY;
12757  }
12758 
12759  if( expr->op == SCIP_EXPR_PARAM )
12760  {
12761  /* find node corresponding to constant corresponding to parameter and add if not existing yet */
12762  assert(expr->nchildren == 0);
12763  assert(params != NULL);
12764 
12765  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, params[expr->data.intval], exprnode) );
12766  assert(*exprnode != NULL);
12767  assert((*exprnode)->op == SCIP_EXPR_CONST);
12768  assert((*exprnode)->data.dbl == params[expr->data.intval]); /*lint !e777*/
12769 
12770  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12771 
12772  return SCIP_OKAY;
12773  }
12774 
12775  /* expression should be variable or constant or have children */
12776  assert(expr->nchildren > 0);
12777 
12778  /* add children expressions into expression graph
12779  * check if we can find a common parent
12780  */
12781  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12782  nochildisnew = TRUE;
12783  for( i = 0; i < expr->nchildren; ++i )
12784  {
12785  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, params, &childnodes[i], &childisnew) ); /*lint !e644*/
12786  assert(childnodes[i] != NULL);
12787  nochildisnew &= !childisnew; /*lint !e514*/
12788  }
12789 
12790  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12791  if( nochildisnew )
12792  {
12793  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12794 
12795  if( *exprnode != NULL )
12796  {
12797  /* node already existing, make sure it is enabled */
12798  (*exprnode)->enabled = TRUE;
12799  *exprnodeisnew = FALSE;
12800 
12801  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12802  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12803  * SCIPdebugPrintf("\n");
12804  */
12805 
12806  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12807  return SCIP_OKAY;
12808  }
12809  }
12810 
12811  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12812 
12813  /* copy expression data */
12814  if( exprOpTable[expr->op].copydata != NULL )
12815  {
12816  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12817  }
12818  else
12819  {
12820  opdata = expr->data;
12821  }
12822 
12823  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12824  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12825  *exprnodeisnew = TRUE;
12826 
12827  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12828 
12829  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12830  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12831  * SCIPdebugPrintf("\n");
12832  */
12833 
12834  return SCIP_OKAY;
12835 }
12836 
12837 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12838 static
12840  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12841  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12842  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12843  )
12844 {
12845  SCIP_EXPRGRAPHNODE* node;
12846  int i;
12847  int p;
12848 
12849  assert(exprgraph != NULL);
12850  assert(clearreverseprop != NULL);
12851  assert(boundchanged != NULL);
12852 
12853  *boundchanged = FALSE;
12854  for( i = 0; i < exprgraph->nvars; ++i )
12855  {
12856  node = exprgraph->varnodes[i];
12857 
12858  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12859  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12860  {
12862  continue;
12863  }
12864 
12865  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12866  {
12867  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12868  SCIP_Real tmp;
12869 
12870  tmp = exprgraph->varbounds[i].inf;
12871  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12872  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12873  }
12874 
12875  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12876  +exprgraph->varbounds[i].sup > node->bounds.sup )
12877  {
12878  for( p = 0; p < node->nparents; ++p )
12880 
12881  node->bounds = exprgraph->varbounds[i];
12882  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12883 
12884  *boundchanged = TRUE;
12885 
12886  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12887  *clearreverseprop = TRUE;
12888  }
12889  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12890  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12891  {
12892  for( p = 0; p < node->nparents; ++p )
12894 
12895  node->bounds = exprgraph->varbounds[i];
12896  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12897 
12898  *boundchanged = TRUE;
12899  }
12900  else
12901  {
12902  node->bounds = exprgraph->varbounds[i];
12903  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12904  }
12905 
12907  }
12908 }
12909 
12910 /**@} */
12911 
12912 /**@name Expression graph node methods */
12913 /**@{ */
12914 
12915 /* In debug mode, the following methods are implemented as function calls to ensure
12916  * type validity.
12917  * In optimized mode, the methods are implemented as defines to improve performance.
12918  * However, we want to have them in the library anyways, so we have to undef the defines.
12919  */
12920 
12921 #undef SCIPexprgraphCaptureNode
12922 #undef SCIPexprgraphIsNodeEnabled
12923 #undef SCIPexprgraphGetNodeNChildren
12924 #undef SCIPexprgraphGetNodeChildren
12925 #undef SCIPexprgraphGetNodeNParents
12926 #undef SCIPexprgraphGetNodeParents
12927 #undef SCIPexprgraphGetNodeDepth
12928 #undef SCIPexprgraphGetNodePosition
12929 #undef SCIPexprgraphGetNodeOperator
12930 #undef SCIPexprgraphGetNodeOperatorIndex
12931 #undef SCIPexprgraphGetNodeOperatorReal
12932 #undef SCIPexprgraphGetNodeVar
12933 #undef SCIPexprgraphGetNodeRealPowerExponent
12934 #undef SCIPexprgraphGetNodeIntPowerExponent
12935 #undef SCIPexprgraphGetNodeSignPowerExponent
12936 #undef SCIPexprgraphGetNodeLinearCoefs
12937 #undef SCIPexprgraphGetNodeLinearConstant
12938 #undef SCIPexprgraphGetNodeQuadraticConstant
12939 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12940 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12941 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12942 #undef SCIPexprgraphGetNodePolynomialMonomials
12943 #undef SCIPexprgraphGetNodePolynomialNMonomials
12944 #undef SCIPexprgraphGetNodePolynomialConstant
12945 #undef SCIPexprgraphGetNodeUserData
12946 #undef SCIPexprgraphHasNodeUserEstimator
12947 #undef SCIPexprgraphGetNodeBounds
12948 #undef SCIPexprgraphGetNodeVal
12949 #undef SCIPexprgraphGetNodeCurvature
12950 
12951 /** captures node, i.e., increases number of uses */
12953  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12954  )
12955 {
12956  assert(node->nuses >= 0);
12957 
12958  SCIPdebugMessage("capture node %p\n", (void*)node);
12959 
12960  ++node->nuses;
12961 }
12962 
12963 /** returns whether a node is currently enabled */
12965  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12966  )
12967 {
12968  assert(node != NULL);
12969 
12970  return node->enabled;
12971 }
12972 
12973 /** gets number of children of a node in an expression graph */
12975  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12976  )
12977 {
12978  assert(node != NULL);
12979 
12980  return node->nchildren;
12981 }
12982 
12983 /** gets children of a node in an expression graph */
12985  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12986  )
12987 {
12988  assert(node != NULL);
12989 
12990  return node->children;
12991 }
12992 
12993 /** gets number of parents of a node in an expression graph */
12995  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12996  )
12997 {
12998  assert(node != NULL);
12999 
13000  return node->nparents;
13001 }
13002 
13003 /** gets parents of a node in an expression graph */
13005  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13006  )
13007 {
13008  assert(node != NULL);
13009 
13010  return node->parents;
13011 }
13012 
13013 /** gets depth of node in expression graph */
13015  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13016  )
13017 {
13018  assert(node != NULL);
13019 
13020  return node->depth;
13021 }
13022 
13023 /** gets position of node in expression graph at its depth level */
13025  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13026  )
13027 {
13028  assert(node != NULL);
13029 
13030  return node->pos;
13031 }
13032 
13033 /** gets operator of a node in an expression graph */
13035  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13036  )
13037 {
13038  assert(node != NULL);
13039 
13040  return node->op;
13041 }
13042 
13043 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
13045  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13046  )
13047 {
13048  assert(node != NULL);
13049  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
13050 
13051  return node->data.intval;
13052 }
13053 
13054 /** gives real belonging to a SCIP_EXPR_CONST operand */
13056  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13057  )
13058 {
13059  assert(node != NULL);
13060  assert(node->op == SCIP_EXPR_CONST);
13061 
13062  return node->data.dbl;
13063 }
13064 
13065 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
13067  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13068  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13069  )
13070 {
13071  assert(exprgraph != NULL);
13072  assert(node != NULL);
13073  assert(node->op == SCIP_EXPR_VARIDX);
13074  assert(node->data.intval >= 0);
13075  assert(node->data.intval < exprgraph->nvars);
13076 
13077  return exprgraph->vars[node->data.intval];
13078 }
13079 
13080 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
13082  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13083  )
13084 {
13085  assert(node != NULL);
13086  assert(node->op == SCIP_EXPR_REALPOWER);
13087 
13088  return node->data.dbl;
13089 }
13090 
13091 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
13093  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13094  )
13095 {
13096  assert(node != NULL);
13097  assert(node->op == SCIP_EXPR_INTPOWER);
13098 
13099  return node->data.intval;
13100 }
13101 
13102 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
13104  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13105  )
13106 {
13107  assert(node != NULL);
13108  assert(node->op == SCIP_EXPR_SIGNPOWER);
13109 
13110  return node->data.dbl;
13111 }
13112 
13113 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
13115  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13116  )
13117 {
13118  assert(node != NULL);
13119  assert(node->op == SCIP_EXPR_LINEAR);
13120 
13121  return (SCIP_Real*)node->data.data;
13122 }
13123 
13124 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
13126  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13127  )
13128 {
13129  assert(node != NULL);
13130  assert(node->op == SCIP_EXPR_LINEAR);
13131  assert(node->data.data != NULL);
13132 
13133  return ((SCIP_Real*)node->data.data)[node->nchildren];
13134 }
13135 
13136 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
13138  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13139  )
13140 {
13141  assert(node != NULL);
13142  assert(node->op == SCIP_EXPR_QUADRATIC);
13143  assert(node->data.data != NULL);
13144 
13145  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
13146 }
13147 
13148 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
13150  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13151  )
13152 {
13153  assert(node != NULL);
13154  assert(node->op == SCIP_EXPR_QUADRATIC);
13155  assert(node->data.data != NULL);
13156 
13157  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
13158 }
13159 
13160 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13162  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13163  )
13164 {
13165  assert(node != NULL);
13166  assert(node->op == SCIP_EXPR_QUADRATIC);
13167  assert(node->data.data != NULL);
13168 
13169  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
13170 }
13171 
13172 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13174  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13175  )
13176 {
13177  assert(node != NULL);
13178  assert(node->op == SCIP_EXPR_QUADRATIC);
13179  assert(node->data.data != NULL);
13180 
13181  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
13182 }
13183 
13184 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13186  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13187  )
13188 {
13189  assert(node != NULL);
13190  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13191  assert(node->data.data != NULL);
13192 
13193  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
13194 }
13195 
13196 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13198  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13199  )
13200 {
13201  assert(node != NULL);
13202  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13203  assert(node->data.data != NULL);
13204 
13205  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
13206 }
13207 
13208 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
13210  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13211  )
13212 {
13213  assert(node != NULL);
13214  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13215  assert(node->data.data != NULL);
13216 
13217  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
13218 }
13219 
13220 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
13221  *
13222  * Assumes that curvature of children and bounds of children and node itself are valid.
13223  */
13225  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13226  int monomialidx, /**< index of monomial */
13227  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
13228  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
13229  )
13230 {
13231  SCIP_EXPRDATA_MONOMIAL* monomial;
13232  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13233  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13234  SCIP_INTERVAL* childbounds = NULL;
13235  SCIP_EXPRCURV* childcurv = NULL;
13236  SCIP_EXPRGRAPHNODE* child;
13237  SCIP_RETCODE retcode = SCIP_OKAY;
13238  int i;
13239 
13240  assert(node != NULL);
13241  assert(node->depth >= 0); /* node should be in graph */
13242  assert(node->pos >= 0); /* node should be in graph */
13243  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13244  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
13245  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13246  assert(node->data.data != NULL);
13247  assert(monomialidx >= 0);
13248  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
13249  assert(curv != NULL);
13250 
13251  if( SCIPintervalIsEmpty(infinity, node->bounds) )
13252  {
13253  *curv = SCIP_EXPRCURV_LINEAR;
13254  return SCIP_OKAY;
13255  }
13256 
13257  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
13258  assert(monomial != NULL);
13259 
13260  /* if many children, get large enough memory to store children bounds */
13261  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13262  {
13263  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13264  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, monomial->nfactors), TERMINATE );
13265  }
13266  else
13267  {
13268  childbounds = childboundsstatic;
13269  childcurv = childcurvstatic;
13270  }
13271 
13272  /* assemble bounds and curvature of children */
13273  for( i = 0; i < monomial->nfactors; ++i )
13274  {
13275  child = node->children[monomial->childidxs[i]];
13276  assert(child != NULL);
13277 
13278  /* child should have valid and non-empty bounds */
13279  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13280  assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13281  /* nodes at depth 0 are always linear */
13282  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13283 
13284  childbounds[i] = child->bounds; /*lint !e644*/
13285  childcurv[i] = child->curv; /*lint !e644*/
13286  }
13287 
13288  /* check curvature */
13289  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13290  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13291 
13292  /* free memory, if allocated before */
13293 TERMINATE:
13294  if( childbounds != childboundsstatic )
13295  {
13296  BMSfreeMemoryArrayNull(&childbounds);
13297  BMSfreeMemoryArrayNull(&childcurv);
13298  }
13299 
13300  return retcode;
13301 }
13302 
13303 /** gives the user data belonging to a SCIP_EXPR_USER expression */
13305  SCIP_EXPRGRAPHNODE* node
13306  )
13307 {
13308  assert(node != NULL);
13309  assert(node->op == SCIP_EXPR_USER);
13310  assert(node->data.data != NULL);
13311 
13312  return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13313 }
13314 
13315 /** indicates whether a user expression has the estimator callback defined */
13317  SCIP_EXPRGRAPHNODE* node
13318  )
13319 {
13320  assert(node != NULL);
13321  assert(node->op == SCIP_EXPR_USER);
13322  assert(node->data.data != NULL);
13323 
13324  return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13325 }
13326 
13327 /** gets bounds of a node in an expression graph */
13329  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13330  )
13331 {
13332  assert(node != NULL);
13333 
13334  return node->bounds;
13335 }
13336 
13337 /** gets value of expression associated to node from last evaluation call */
13339  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13340  )
13341 {
13342  assert(node != NULL);
13343 
13344  return node->value;
13345 }
13346 
13347 /** gets curvature of expression associated to node from last curvature check call */
13349  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13350  )
13351 {
13352  assert(node != NULL);
13353 
13354  return node->curv;
13355 }
13356 
13357 /** creates an expression graph node */
13359  BMS_BLKMEM* blkmem, /**< block memory */
13360  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13361  SCIP_EXPROP op, /**< operator type of expression */
13362  ...
13363  )
13364 {
13365  va_list ap;
13366  SCIP_EXPROPDATA opdata;
13367 
13368  assert(blkmem != NULL);
13369  assert(node != NULL);
13370 
13371  *node = NULL;
13372 
13373  switch( op )
13374  {
13375  case SCIP_EXPR_VARIDX :
13376  case SCIP_EXPR_PARAM :
13377  case SCIP_EXPR_CONST :
13378  case SCIP_EXPR_LINEAR :
13379  case SCIP_EXPR_QUADRATIC :
13380  case SCIP_EXPR_POLYNOMIAL:
13381  case SCIP_EXPR_USER :
13382  {
13383  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
13384  SCIPABORT();
13385  return SCIP_ERROR; /*lint !e527*/
13386  }
13387 
13388  /* operands without data */
13389  case SCIP_EXPR_PLUS :
13390  case SCIP_EXPR_MINUS :
13391  case SCIP_EXPR_MUL :
13392  case SCIP_EXPR_DIV :
13393  case SCIP_EXPR_MIN :
13394  case SCIP_EXPR_MAX :
13395  case SCIP_EXPR_SQUARE :
13396  case SCIP_EXPR_SQRT :
13397  case SCIP_EXPR_EXP :
13398  case SCIP_EXPR_LOG :
13399  case SCIP_EXPR_SIN :
13400  case SCIP_EXPR_COS :
13401  case SCIP_EXPR_TAN :
13402  /* case SCIP_EXPR_ERF : */
13403  /* case SCIP_EXPR_ERFI: */
13404  case SCIP_EXPR_ABS :
13405  case SCIP_EXPR_SIGN :
13406  case SCIP_EXPR_SUM :
13407  case SCIP_EXPR_PRODUCT:
13408  opdata.data = NULL;
13409  break;
13410 
13411  case SCIP_EXPR_REALPOWER:
13412  case SCIP_EXPR_SIGNPOWER:
13413  {
13414  va_start(ap, op ); /*lint !e838*/
13415  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
13416  va_end( ap ); /*lint !e826*/
13417 
13418  break;
13419  }
13420 
13421  case SCIP_EXPR_INTPOWER:
13422  {
13423  va_start(ap, op ); /*lint !e838*/
13424  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
13425  va_end( ap ); /*lint !e826*/
13426 
13427  break;
13428  }
13429 
13430  case SCIP_EXPR_LAST:
13431  SCIPABORT();
13432  return SCIP_INVALIDDATA; /*lint !e527*/
13433  }
13434 
13435  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13436 
13437  return SCIP_OKAY;
13438 }
13439 
13440 /** creates an expression graph node for a linear expression */
13442  BMS_BLKMEM* blkmem, /**< block memory */
13443  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13444  int ncoefs, /**< number of coefficients */
13445  SCIP_Real* coefs, /**< coefficients of linear expression */
13446  SCIP_Real constant /**< constant of linear expression */
13447  )
13448 {
13449  SCIP_EXPROPDATA opdata;
13450  SCIP_Real* data;
13451 
13452  assert(blkmem != NULL);
13453  assert(node != NULL);
13454 
13455  /* we store the coefficients and the constant in a single array and make this our operand data */
13456  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13457  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
13458  data[ncoefs] = constant;
13459 
13460  opdata.data = data;
13461  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13462 
13463  return SCIP_OKAY;
13464 }
13465 
13466 /** creates an expression graph node for a quadratic expression */
13468  BMS_BLKMEM* blkmem, /**< block memory */
13469  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13470  int nchildren, /**< number of children */
13471  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
13472  int nquadelems, /**< number of quadratic elements */
13473  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
13474  SCIP_Real constant /**< constant */
13475  )
13476 {
13477  SCIP_EXPROPDATA opdata;
13479 
13480  assert(blkmem != NULL);
13481  assert(node != NULL);
13482  assert(quadelems != NULL || nquadelems == 0);
13483 
13484  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13485 
13486  opdata.data = data;
13487  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13488 
13489  return SCIP_OKAY;
13490 }
13491 
13492 /** creates an expression graph node for a polynomial expression */
13494  BMS_BLKMEM* blkmem, /**< block memory */
13495  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13496  int nmonomials, /**< number of monomials */
13497  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13498  SCIP_Real constant, /**< constant of polynomial */
13499  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13500  )
13501 {
13502  SCIP_EXPROPDATA opdata;
13504 
13505  assert(blkmem != NULL);
13506  assert(node != NULL);
13507  assert(monomials != NULL || nmonomials == 0);
13508 
13509  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13510 
13511  opdata.data = data;
13512  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13513 
13514  return SCIP_OKAY;
13515 }
13516 
13517 /** adds monomials to an expression graph node that is a polynomial expression */
13519  BMS_BLKMEM* blkmem, /**< block memory */
13520  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
13521  int nmonomials, /**< number of monomials */
13522  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13523  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13524  )
13525 {
13526  assert(blkmem != NULL);
13527  assert(node != NULL);
13529  assert(monomials != NULL || nmonomials == 0);
13530 
13531  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13532 
13533  return SCIP_OKAY;
13534 }
13535 
13536 /** creates an expression graph node for a user expression */
13538  BMS_BLKMEM* blkmem, /**< block memory */
13539  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13540  SCIP_USEREXPRDATA* data, /**< user data for expression, node assumes ownership */
13541  SCIP_EXPRINTCAPABILITY evalcapability, /**< evaluation capability */
13542  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
13543  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function */
13544  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
13545  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function */
13546  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13547  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13548  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
13549  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
13550  )
13551 {
13552  SCIP_EXPROPDATA opdata;
13553  SCIP_EXPRDATA_USER* exprdata;
13554 
13555  assert(blkmem != NULL);
13556  assert(node != NULL);
13557  assert(eval != NULL);
13558  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
13559  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13560  assert(copydata != NULL || data == NULL);
13561  assert(freedata != NULL || data == NULL);
13562 
13563  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13564 
13565  exprdata->userdata = data;
13566  exprdata->evalcapability = evalcapability;
13567  exprdata->eval = eval;
13568  exprdata->estimate = estimate;
13569  exprdata->inteval = inteval;
13570  exprdata->curv = curv;
13571  exprdata->prop = prop;
13572  exprdata->copydata = copydata;
13573  exprdata->freedata = freedata;
13574  exprdata->print = print;
13575 
13576  opdata.data = (void*) exprdata;
13577 
13578  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13579 
13580  return SCIP_OKAY;
13581 }
13582 
13583 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13584  *
13585  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13586  * If the node is a linear expression, it may be freed.
13587  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13588  * It is assumed that the user had captured the node.
13589  * It is assumed that the expression graph has been simplified before.
13590  */
13592  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13593  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
13594  int linvarssize, /**< length of linvars and lincoefs arrays */
13595  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
13596  void** linvars, /**< buffer to store variables of linear part */
13597  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
13598  SCIP_Real* constant /**< buffer to store constant part */
13599  )
13600 {
13601  int orignvars;
13602  int* varsusage;
13603  SCIP_EXPRGRAPHNODE* orignode;
13604  SCIP_Bool havechange;
13605  int i;
13606 
13607  assert(exprgraph != NULL);
13608  assert(node != NULL);
13609  assert(*node != NULL);
13610  assert((*node)->nuses > 0);
13611  assert(nlinvars != NULL);
13612  assert(linvars != NULL || linvarssize == 0);
13613  assert(lincoefs != NULL || linvarssize == 0);
13614  assert(constant != NULL);
13615 
13616  *constant = 0.0;
13617  *nlinvars = 0;
13618 
13619  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13620 
13621  /* do some obvious and easy cases */
13622  switch( (*node)->op )
13623  {
13624  case SCIP_EXPR_VARIDX:
13625  {
13626  if( linvarssize >= 1 )
13627  {
13628  *nlinvars = 1;
13629  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
13630  lincoefs[0] = 1.0; /*lint !e613*/
13631 
13632  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13633  }
13634  return SCIP_OKAY;
13635  }
13636 
13637  case SCIP_EXPR_CONST:
13638  {
13639  *constant = (*node)->data.dbl;
13640  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13641 
13642  return SCIP_OKAY;
13643  }
13644 
13645  case SCIP_EXPR_REALPOWER:
13646  case SCIP_EXPR_SIGNPOWER:
13647  {
13648  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13649  {
13650  *nlinvars = 1;
13651  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13652  lincoefs[0] = 1.0; /*lint !e613*/
13653 
13654  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13655  }
13656  return SCIP_OKAY;
13657  }
13658 
13659  case SCIP_EXPR_INTPOWER:
13660  {
13661  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13662  {
13663  *nlinvars = 1;
13664  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13665  lincoefs[0] = 1.0; /*lint !e613*/
13666 
13667  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13668  }
13669  return SCIP_OKAY;
13670  }
13671 
13672  case SCIP_EXPR_PLUS:
13673  {
13674  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13675  {
13676  *constant = (*node)->children[0]->data.dbl;
13677  *nlinvars = 1;
13678  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13679  lincoefs[0] = 1.0; /*lint !e613*/
13680 
13681  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13682 
13683  return SCIP_OKAY;
13684  }
13685  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13686  {
13687  *constant = (*node)->children[1]->data.dbl;
13688  *nlinvars = 1;
13689  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13690  lincoefs[0] = 1.0; /*lint !e613*/
13691 
13692  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13693 
13694  return SCIP_OKAY;
13695  }
13696  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13697  {
13698  *nlinvars = 2;
13699  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13700  lincoefs[0] = 1.0; /*lint !e613*/
13701  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13702  lincoefs[1] = 1.0; /*lint !e613*/
13703 
13704  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13705 
13706  return SCIP_OKAY;
13707  }
13708  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13709  {
13710  /* handle this one later */
13711  break;
13712  }
13713  return SCIP_OKAY;
13714  }
13715 
13716  case SCIP_EXPR_MINUS:
13717  {
13718  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13719  {
13720  *constant = (*node)->children[0]->data.dbl;
13721  *nlinvars = 1;
13722  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13723  lincoefs[0] = -1.0; /*lint !e613*/
13724 
13725  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13726 
13727  return SCIP_OKAY;
13728  }
13729  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13730  {
13731  *constant = -(*node)->children[1]->data.dbl;
13732  *nlinvars = 1;
13733  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13734  lincoefs[0] = 1.0; /*lint !e613*/
13735 
13736  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13737 
13738  return SCIP_OKAY;
13739  }
13740  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13741  {
13742  *nlinvars = 2;
13743  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13744  lincoefs[0] = 1.0; /*lint !e613*/
13745  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13746  lincoefs[1] = -1.0; /*lint !e613*/
13747 
13748  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13749 
13750  return SCIP_OKAY;
13751  }
13752  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13753  {
13754  /* handle this one later */
13755  break;
13756  }
13757  return SCIP_OKAY;
13758  }
13759 
13760  case SCIP_EXPR_MUL:
13761  {
13762  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13763  {
13764  *nlinvars = 1;
13765  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13766  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
13767 
13768  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13769  }
13770  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13771  {
13772  *nlinvars = 1;
13773  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13774  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
13775 
13776  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13777  }
13778  return SCIP_OKAY;
13779  }
13780 
13781  case SCIP_EXPR_DIV:
13782  {
13783  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13784  return SCIP_OKAY;
13785 
13786  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13787  {
13788  *nlinvars = 1;
13789  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13790  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
13791 
13792  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13793  }
13794  return SCIP_OKAY;
13795  }
13796 
13797  case SCIP_EXPR_SQUARE:
13798  case SCIP_EXPR_SQRT:
13799  case SCIP_EXPR_EXP:
13800  case SCIP_EXPR_LOG:
13801  case SCIP_EXPR_SIN:
13802  case SCIP_EXPR_COS:
13803  case SCIP_EXPR_TAN:
13804  /* case SCIP_EXPR_ERF: */
13805  /* case SCIP_EXPR_ERFI: */
13806  case SCIP_EXPR_ABS:
13807  case SCIP_EXPR_SIGN:
13808  case SCIP_EXPR_MIN:
13809  case SCIP_EXPR_MAX:
13810  return SCIP_OKAY;
13811 
13812  case SCIP_EXPR_PRODUCT:
13813  case SCIP_EXPR_USER:
13814  return SCIP_OKAY;
13815 
13816  case SCIP_EXPR_SUM:
13817  case SCIP_EXPR_LINEAR:
13818  case SCIP_EXPR_QUADRATIC:
13819  case SCIP_EXPR_POLYNOMIAL:
13820  default:
13821  {
13822  /* check if there is a child that is a variable */
13823  for( i = 0; i < (*node)->nchildren; ++i )
13824  {
13825  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13826  break;
13827  }
13828 
13829  if( i == (*node)->nchildren )
13830  return SCIP_OKAY;
13831 
13832  break;
13833  }
13834  } /*lint !e788*/
13835 
13836  /* count how often variables are used in this expression */
13837  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13838  orignvars = exprgraph->nvars;
13839  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13840  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
13841 
13842  exprgraphNodeGetVarsUsage(*node, varsusage);
13843 
13844  /* duplicate node if it has parents or more than one user */
13845  orignode = NULL;
13846  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13847  {
13848  SCIP_EXPROPDATA data;
13849 
13850  orignode = *node;
13851 
13852  if( exprOpTable[orignode->op].copydata != NULL )
13853  {
13854  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13855  }
13856  else
13857  data = orignode->data;
13858 
13859  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13860  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13861  SCIPexprgraphCaptureNode(*node);
13862  }
13863 
13864  havechange = FALSE;
13865  /* split up constant and linear part */
13866  switch( (*node)->op )
13867  {
13868  case SCIP_EXPR_PLUS:
13869  case SCIP_EXPR_MINUS:
13870  {
13871  SCIP_EXPRGRAPHNODE* varchild;
13872  SCIP_EXPRGRAPHNODE* otherchild;
13873  int varidx;
13874 
13875  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13876  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13877  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13878  assert(linvarssize >= 1);
13879 
13880  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13881  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13882  varidx = varchild->data.intval;
13883  /* if variable is used in other child (which should be nonlinear), we don't take it */
13884  if( varsusage[varidx] > 1 )
13885  break;
13886 
13887  /* add to linear variables */
13888  *nlinvars = 1;
13889  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13890  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13891  lincoefs[0] = -1.0; /*lint !e613*/
13892  else
13893  lincoefs[0] = 1.0; /*lint !e613*/
13894 
13895  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13896  {
13897  /* replace *node by otherchild */
13898  SCIPexprgraphCaptureNode(otherchild);
13899  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13900  *node = otherchild;
13901  }
13902  else
13903  {
13904  SCIP_Real* lindata;
13905 
13906  /* turn *node into linear expression -1.0 * otherchild */
13907 
13908  /* reduce to one child */
13909  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13910  (*node)->children[0] = otherchild;
13911  (*node)->nchildren = 1;
13912  (*node)->op = SCIP_EXPR_LINEAR;
13913 
13914  /* setup linear data -1.0 * child0 + 0.0 */
13915  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13916  lindata[0] = -1.0;
13917  lindata[1] = 0.0;
13918  (*node)->data.data = (void*)lindata;
13919 
13920  /* remove *node as parent of varchild */
13921  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13922  }
13923 
13924  havechange = TRUE;
13925 
13926  break;
13927  }
13928 
13929  case SCIP_EXPR_SUM:
13930  {
13931  int nchildren;
13932 
13933  i = 0;
13934  nchildren = (*node)->nchildren;
13935  while( i < nchildren )
13936  {
13937  /* sort out constants */
13938  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13939  {
13940  *constant += (*node)->children[i]->data.dbl;
13941  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13942 
13943  if( i < nchildren-1 )
13944  {
13945  (*node)->children[i] = (*node)->children[nchildren-1];
13946  (*node)->children[nchildren-1] = NULL;
13947  }
13948  --nchildren;
13949 
13950  continue;
13951  }
13952 
13953  /* keep every child that is not a constant or variable */
13954  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13955  {
13956  ++i;
13957  continue;
13958  }
13959 
13960  /* skip variables that are used in other parts of the expression */
13961  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13962  {
13963  ++i;
13964  continue;
13965  }
13966 
13967  /* move variable into linear part, if still space */
13968  if( *nlinvars < linvarssize )
13969  {
13970  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13971  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13972  ++*nlinvars;
13973 
13974  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13975  if( i < nchildren-1 )
13976  {
13977  (*node)->children[i] = (*node)->children[nchildren-1];
13978  (*node)->children[nchildren-1] = NULL;
13979  }
13980  --nchildren;
13981 
13982  continue;
13983  }
13984  }
13985  assert(i == nchildren);
13986 
13987  if( nchildren == 0 )
13988  {
13989  /* all children were removed */
13990  havechange = TRUE;
13991  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13992  (*node)->nchildren = 0;
13993  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13994  break;
13995  }
13996 
13997  if( nchildren < (*node)->nchildren )
13998  {
13999  /* some children were removed */
14000  havechange = TRUE;
14001  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14002  (*node)->nchildren = nchildren;
14003  }
14004 
14005  if( havechange && (*node)->nchildren == 1 )
14006  {
14007  /* replace node by its child */
14008  SCIP_EXPRGRAPHNODE* child;
14009 
14010  child = (*node)->children[0];
14011  SCIPexprgraphCaptureNode(child);
14012  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14013  *node = child;
14014 
14015  break;
14016  }
14017 
14018  break;
14019  }
14020 
14021  case SCIP_EXPR_LINEAR:
14022  {
14023  int nchildren;
14024  SCIP_Real* coefs;
14025 
14026  coefs = (SCIP_Real*)(*node)->data.data;
14027  assert(coefs != NULL);
14028 
14029  /* remove constant, if nonzero */
14030  if( coefs[(*node)->nchildren] != 0.0 )
14031  {
14032  *constant = coefs[(*node)->nchildren];
14033  coefs[(*node)->nchildren] = 0.0;
14034  havechange = TRUE;
14035  }
14036 
14037  i = 0;
14038  nchildren = (*node)->nchildren;
14039  while( i < nchildren )
14040  {
14041  /* sort out constants */
14042  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
14043  {
14044  *constant += coefs[i] * (*node)->children[i]->data.dbl;
14045  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14046 
14047  if( i < nchildren-1 )
14048  {
14049  (*node)->children[i] = (*node)->children[nchildren-1];
14050  (*node)->children[nchildren-1] = NULL;
14051  coefs[i] = coefs[nchildren-1];
14052  coefs[nchildren-1] = 0.0;
14053  }
14054  --nchildren;
14055 
14056  continue;
14057  }
14058 
14059  /* keep everything that is not a constant or variable */
14060  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14061  {
14062  ++i;
14063  continue;
14064  }
14065 
14066  /* skip variables that are used in other parts of the expression */
14067  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14068  {
14069  ++i;
14070  continue;
14071  }
14072 
14073  /* move variable into linear part, if still space */
14074  if( *nlinvars < linvarssize )
14075  {
14076  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14077  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
14078  ++*nlinvars;
14079 
14080  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14081  if( i < nchildren-1 )
14082  {
14083  (*node)->children[i] = (*node)->children[nchildren-1];
14084  (*node)->children[nchildren-1] = NULL;
14085  coefs[i] = coefs[nchildren-1];
14086  coefs[nchildren-1] = 0.0;
14087  }
14088  --nchildren;
14089 
14090  continue;
14091  }
14092  }
14093  assert(i == nchildren);
14094 
14095  if( nchildren == 0 )
14096  {
14097  /* all children were removed */
14098  havechange = TRUE;
14099  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14100  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
14101  (*node)->data.data = NULL;
14102  (*node)->nchildren = 0;
14103  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
14104  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14105  break;
14106  }
14107 
14108  if( nchildren < (*node)->nchildren )
14109  {
14110  /* some children were removed */
14111  havechange = TRUE;
14112  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14113  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
14114  coefs[nchildren] = 0.0;
14115  (*node)->data.data = (void*)coefs;
14116  (*node)->nchildren = nchildren;
14117  }
14118 
14119  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
14120  {
14121  /* replace node by its child */
14122  SCIP_EXPRGRAPHNODE* child;
14123 
14124  child = (*node)->children[0];
14125  SCIPexprgraphCaptureNode(child);
14126  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14127  *node = child;
14128 
14129  break;
14130  }
14131 
14132  break;
14133  }
14134 
14135  case SCIP_EXPR_QUADRATIC:
14136  {
14137  SCIP_EXPRDATA_QUADRATIC* quaddata;
14138  SCIP_Bool* childused;
14139  int* childmap;
14140  int nchildren;
14141 
14142  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
14143  assert(quaddata != NULL);
14144 
14145  /* remove constant, if nonzero */
14146  if( quaddata->constant != 0.0 )
14147  {
14148  *constant = quaddata->constant;
14149  quaddata->constant = 0.0;
14150  havechange = TRUE;
14151  }
14152 
14153  /* if there is no linear part or no space left for linear variables, then stop */
14154  if( quaddata->lincoefs == NULL || linvarssize == 0 )
14155  break;
14156 
14157  /* check which childs are used in quadratic terms */
14158  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14159  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14160 
14161  for( i = 0; i < quaddata->nquadelems; ++i )
14162  {
14163  childused[quaddata->quadelems[i].idx1] = TRUE;
14164  childused[quaddata->quadelems[i].idx2] = TRUE;
14165  }
14166 
14167  /* alloc space for mapping of children indices */
14168  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
14169 
14170  nchildren = (*node)->nchildren;
14171  for( i = 0; i < nchildren; ++i )
14172  {
14173  childmap[i] = i; /*lint !e644*/
14174  if( *nlinvars >= linvarssize )
14175  continue;
14176  /* skip child if not variable or also used in quadratic part or other parts of expression */
14177  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14178  continue;
14179  if( childused[i] )
14180  continue;
14181  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14182  continue;
14183 
14184  /* put variable into linear part */
14185  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14186  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
14187  quaddata->lincoefs[i] = 0.0;
14188  ++*nlinvars;
14189 
14190  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14191 
14192  /* move last child to position i */
14193  if( i < nchildren-1 )
14194  {
14195  (*node)->children[i] = (*node)->children[nchildren-1];
14196  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
14197  childused[i] = childused[nchildren-1];
14198  childmap[nchildren-1] = i;
14199  }
14200  --nchildren;
14201  childmap[i] = -1;
14202 
14203  havechange = TRUE;
14204  --i; /* look at i again */
14205  }
14206 
14207  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
14208 
14209  if( nchildren < (*node)->nchildren )
14210  {
14211  /* apply childmap to quadratic term */
14212  for( i = 0; i < quaddata->nquadelems; ++i )
14213  {
14214  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
14215  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
14216  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
14217  {
14218  int tmp;
14219  tmp = quaddata->quadelems[i].idx1;
14220  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
14221  quaddata->quadelems[i].idx2 = tmp;
14222  }
14223  }
14224  quaddata->sorted = FALSE;
14225  }
14226  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
14227 
14228  if( nchildren == 0 )
14229  {
14230  /* all children were removed (so it was actually a linear expression) */
14231  havechange = TRUE;
14232  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14233  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
14234  (*node)->data.data = NULL;
14235  (*node)->nchildren = 0;
14236  (*node)->op = SCIP_EXPR_SUM;
14237  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14238  break;
14239  }
14240 
14241  if( nchildren < (*node)->nchildren )
14242  {
14243  /* reduce number of children */
14244  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14245  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
14246  (*node)->nchildren = nchildren;
14247  }
14248 
14249  break;
14250  }
14251 
14252  case SCIP_EXPR_POLYNOMIAL:
14253  {
14254  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
14255  SCIP_EXPRDATA_MONOMIAL* monomial;
14256  SCIP_Bool* childused;
14257  int childidx;
14258  int j;
14259 
14260  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
14261  assert(polynomialdata != NULL);
14262 
14263  /* make sure linear monomials are merged */
14264  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14265 
14266  /* remove constant, if nonzero */
14267  if( polynomialdata->constant != 0.0 )
14268  {
14269  *constant = polynomialdata->constant;
14270  polynomialdata->constant = 0.0;
14271  havechange = TRUE;
14272  }
14273 
14274  /* if there is no space for linear variables, then stop */
14275  if( linvarssize == 0 )
14276  break;
14277 
14278  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14279  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14280  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14281  for( i = 0; i < polynomialdata->nmonomials; ++i )
14282  {
14283  monomial = polynomialdata->monomials[i];
14284  assert(monomial != NULL);
14285  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14286  continue;
14287  for( j = 0; j < monomial->nfactors; ++j )
14288  {
14289  assert(monomial->childidxs[j] >= 0);
14290  assert(monomial->childidxs[j] < (*node)->nchildren);
14291  childused[monomial->childidxs[j]] = TRUE;
14292  }
14293  }
14294 
14295  /* move linear monomials out of polynomial */
14296  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14297  {
14298  monomial = polynomialdata->monomials[i];
14299  assert(monomial != NULL);
14300 
14301  /* sort out constants */
14302  if( monomial->nfactors == 0 )
14303  {
14304  if( monomial->coef != 0.0 )
14305  {
14306  *constant += monomial->coef;
14307  havechange = TRUE;
14308  }
14309  continue;
14310  }
14311 
14312  if( monomial->nfactors != 1 )
14313  continue;
14314  if( monomial->exponents[0] != 1.0 )
14315  continue;
14316  childidx = monomial->childidxs[0];
14317  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14318  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14319  continue;
14320  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14321  continue;
14322 
14323  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14324 
14325  /* put variable into linear part */
14326  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
14327  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
14328  ++*nlinvars;
14329 
14330  monomial->coef = 0.0;
14331  monomial->nfactors = 0;
14332  polynomialdata->sorted = FALSE;
14333 
14334  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14335  (*node)->children[childidx] = NULL;
14336 
14337  havechange = TRUE;
14338  }
14339 
14340  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14341 
14342  if( *nlinvars > 0 )
14343  {
14344  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14345  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14347  }
14348 
14349  if( (*node)->nchildren == 0 )
14350  {
14351  assert(polynomialdata->nmonomials == 0);
14352  assert(polynomialdata->constant == 0.0);
14353  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14354  havechange = TRUE;
14355  break;
14356  }
14357 
14358  break;
14359  }
14360 
14361  default: ;
14362  } /*lint !e788*/
14363 
14364  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14365 
14366  if( orignode != NULL )
14367  {
14368  /* if node was duplicated, we need to forget about original or duplicate */
14369  if( !havechange )
14370  {
14371  /* if nothing has changed, then forget about duplicate */
14372  assert(*constant == 0.0);
14373  assert(*nlinvars == 0);
14374  assert(*node != NULL);
14375  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14376  *node = orignode;
14377  }
14378  else
14379  {
14380  /* if something changed, then release original node */
14381  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14382  }
14383  }
14384  else if( havechange && *node != NULL )
14385  {
14386  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14387  (*node)->value = SCIP_INVALID;
14388  (*node)->simplified = FALSE;
14389  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14390  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14391  exprgraph->needvarboundprop = TRUE;
14392  }
14393 
14394  return SCIP_OKAY;
14395 }
14396 
14397 /** moves parents from a one node to another node
14398  *
14399  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14400  * srcnode may be freed, if not captured.
14401  * It is assumed that targetnode represents the same expression as srcnode.
14402  */
14404  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14405  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
14406  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
14407  )
14408 {
14409  assert(exprgraph != NULL);
14410  assert(srcnode != NULL);
14411  assert(*srcnode != NULL);
14412  assert(targetnode != NULL);
14413 
14414  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14415  {
14416  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14417  {
14418  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14419  }
14420  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14421  }
14422  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14423 
14424  return SCIP_OKAY;
14425 }
14426 
14427 /** releases node, i.e., decreases number of uses
14428  *
14429  * node is freed if no parents and no other uses.
14430  * Children are recursively released if they have no other parents.
14431  * Nodes that are removed are also freed.
14432  * If node correspond to a variable, then the variable is removed from the expression graph;
14433  * similarly for constants.
14434  */
14436  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14437  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
14438  )
14439 {
14440  int i;
14441 
14442  assert(exprgraph != NULL);
14443  assert(node != NULL);
14444  assert(*node != NULL);
14445  assert((*node)->depth >= 0); /* node should be in graph */
14446  assert((*node)->pos >= 0); /* node should be in graph */
14447  assert((*node)->depth < exprgraph->depth);
14448  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14449  assert((*node)->nuses >= 1);
14450  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14451 
14452  SCIPdebugMessage("release node %p\n", (void*)*node);
14453 
14454  --(*node)->nuses;
14455 
14456  /* do nothing if node still has parents or is still in use */
14457  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14458  {
14459  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);
14460  *node = NULL;
14461  return SCIP_OKAY;
14462  }
14463 
14464  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14465 
14466  /* notify children about removal of its parent
14467  * they are also freed, if possible */
14468  for( i = 0; i < (*node)->nchildren; ++i )
14469  {
14470  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14471  (*node)->children[i] = NULL;
14472  }
14473 
14474  if( (*node)->op == SCIP_EXPR_VARIDX )
14475  {
14476  assert((*node)->depth == 0);
14477  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14478  }
14479  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14480  {
14481  int constidx;
14482 
14483  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14484  assert(constidx >= 0);
14485  assert(constidx < exprgraph->nconsts);
14486  assert(exprgraph->constnodes[constidx] == *node);
14487 
14488  /* move last constant to position constidx */
14489  if( constidx < exprgraph->nconsts-1 )
14490  {
14491  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14492  exprgraph->constssorted = (exprgraph->nconsts <= 2);
14493  }
14494  --exprgraph->nconsts;
14495  }
14496  else
14497  {
14498  /* only variables and constants are allowed at depth 0 */
14499  assert((*node)->depth > 0);
14500  }
14501 
14502  /* remove node from nodes array in expression graph */
14503  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14504  {
14505  /* move last node at depth of *node to position of *node */
14506  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14507  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14508 
14509  /* moving the node may change the order in the parents array of each child */
14510  for( i = 0; i < exprgraph->nodes[(*node)->depth][(*node)->pos]->nchildren; ++i )
14511  exprgraph->nodes[(*node)->depth][(*node)->pos]->children[i]->parentssorted = FALSE;
14512  }
14513  --exprgraph->nnodes[(*node)->depth];
14514 
14515  /* node is now not in graph anymore */
14516  (*node)->depth = -1;
14517  (*node)->pos = -1;
14518 
14519  /* free node */
14520  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14521 
14522  *node = NULL;
14523 
14524  return SCIP_OKAY;
14525 }
14526 
14527 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14528 /** frees a node of an expression graph */
14530  BMS_BLKMEM* blkmem, /**< block memory */
14531  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
14532  )
14533 {
14534  assert(blkmem != NULL);
14535  assert( node != NULL);
14536  assert(*node != NULL);
14537  assert((*node)->depth == -1); /* node should not be in graph anymore */
14538  assert((*node)->pos == -1); /* node should not be in graph anymore */
14539  assert((*node)->nuses == 0); /* node should not be in use */
14540 
14541  /* free operator data, if needed */
14542  if( exprOpTable[(*node)->op].freedata != NULL )
14543  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14544 
14545  /* free arrays of children and parent nodes */
14546  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14547  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
14548 
14549  /* free node struct */
14550  BMSfreeBlockMemory(blkmem, node);
14551 }
14552 
14553 /** enables a node and recursively all its children in an expression graph */
14555  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14556  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14557  )
14558 {
14559  int i;
14560 
14561  assert(exprgraph != NULL);
14562  assert(node != NULL);
14563  assert(node->depth >= 0);
14564  assert(node->pos >= 0);
14565 
14566  if( node->enabled )
14567  return;
14568 
14569  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14570 
14571  node->enabled = TRUE;
14572  for( i = 0; i < node->nchildren; ++i )
14573  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14574 
14575  /* make sure bounds are updated in next bound propagation round */
14576  SCIPintervalSetEntire(SCIP_REAL_MAX, &node->bounds);
14577  exprgraph->needvarboundprop = TRUE;
14578 }
14579 
14580 /** disables a node and recursively all children which have no enabled parents in an expression graph */
14582  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14583  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14584  )
14585 {
14586  int i;
14587 
14588  assert(exprgraph != NULL);
14589  assert(node != NULL);
14590  assert(node->depth >= 0);
14591  assert(node->pos >= 0);
14592 
14593  if( !node->enabled )
14594  return;
14595 
14596  /* workaround: don't disable nodes if there could be more users than the one who is disabling the node
14597  * otherwise, if there are several nonlinear constraints using the same expression graph node as root node,
14598  * we might get enabled constraints with disabled node
14599  */
14600  if( node->nuses > 1 )
14601  return;
14602 
14603  /* if all parents of node are disabled, then also node can be disabled */
14604  node->enabled = FALSE;
14605  for( i = 0; i < node->nparents; ++i )
14606  if( node->parents[i]->enabled )
14607  {
14608  node->enabled = TRUE;
14609  return;
14610  }
14611 
14612  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14613 
14614  for( i = 0; i < node->nchildren; ++i )
14615  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14616 }
14617 
14618 /** returns whether the node has siblings in the expression graph */
14620  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14621  )
14622 {
14623  int p;
14624 
14625  assert(node != NULL);
14626 
14627  for( p = 0; p < node->nparents; ++p )
14628  if( node->parents[p]->nchildren > 1 )
14629  return TRUE;
14630 
14631  return FALSE;
14632 }
14633 
14634 /** returns whether all children of an expression graph node are variable nodes
14635  *
14636  * Returns TRUE for nodes without children.
14637  */
14639  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14640  )
14641 {
14642  int i;
14643 
14644  assert(node != NULL);
14645 
14646  for( i = 0; i < node->nchildren; ++i )
14647  if( node->children[i]->op != SCIP_EXPR_VARIDX )
14648  return FALSE;
14649 
14650  return TRUE;
14651 }
14652 
14653 /** returns whether the node has an ancestor which has a nonlinear expression operand */
14655  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14656  )
14657 {
14658  int p;
14659 
14660  for( p = 0; p < node->nparents; ++p )
14661  {
14662  assert(node->parents[p]->depth > node->depth);
14663  switch( node->parents[p]->op )
14664  {
14665  case SCIP_EXPR_PLUS:
14666  case SCIP_EXPR_MINUS:
14667  case SCIP_EXPR_SUM:
14668  case SCIP_EXPR_LINEAR:
14670  return TRUE;
14671  break;
14672 
14673 #ifndef NDEBUG
14674  case SCIP_EXPR_VARIDX:
14675  case SCIP_EXPR_CONST:
14676  case SCIP_EXPR_PARAM:
14677  assert(0); /* these expressions cannot have children */
14678  break;
14679 #endif
14680 
14681  default:
14682  /* parent has nonlinear expression operand */
14683  return TRUE;
14684  }/*lint !e788*/
14685  }
14686 
14687  return FALSE;
14688 }
14689 
14690 /** prints an expression graph node */
14692  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14693  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14694  FILE* file /**< file to print to, or NULL for stdout */
14695  )
14696 {
14697  assert(node != NULL);
14698 
14699  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14700 }
14701 
14702 /** tightens the bounds in a node of the graph
14703  *
14704  * Preparation for reverse propagation.
14705  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14706  */
14708  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14709  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
14710  SCIP_INTERVAL nodebounds, /**< new bounds for node */
14711  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) */
14712  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14713  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14714  )
14715 {
14716  assert(exprgraph != NULL);
14717  assert(node != NULL);
14718  assert(node->depth >= 0);
14719  assert(node->pos >= 0);
14720  assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14721  assert(cutoff != NULL);
14722 
14723  *cutoff = FALSE;
14724 
14725  /* if node is disabled, then ignore new bounds */
14726  if( !node->enabled )
14727  {
14728  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14729  return;
14730  }
14731 
14732  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14733  (void*)node, node->depth, node->pos,
14734  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14735 
14736  /* bounds in node should be valid */
14737  assert(!(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
14738 
14739  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14740  {
14741  *cutoff = TRUE;
14742  SCIPdebugPrintf(" -> cutoff\n");
14743  return;
14744  }
14745 
14746  /* if minstrength is negative, always mark that node has recently tightened bounds,
14747  * if bounds are considerably improved or tightening leads to an empty interval,
14748  * mark that node has recently tightened bounds
14749  * if bounds are only slightly improved, set the status to tightened by parent,
14750  * so next propagateVarBound round will reset the bounds
14751  */
14752  if( minstrength < 0.0 )
14753  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE;
14754  else if(
14755  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14756  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14757  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT;
14758  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14759  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT;
14760 
14761  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14762  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14763 }
14764 
14765 /** ensures that bounds and curvature information in a node is uptodate
14766  *
14767  * Assumes that bounds and curvature in children are uptodate.
14768  */
14770  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14771  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14772  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14773  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14774  )
14775 {
14776  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14777  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14778  SCIP_INTERVAL* childbounds = NULL;
14779  SCIP_EXPRCURV* childcurv = NULL;
14780  SCIP_RETCODE retcode = SCIP_OKAY;
14781  int i;
14782 
14783  assert(node != NULL);
14784  assert(node->depth >= 0); /* node should be in graph */
14785  assert(node->pos >= 0); /* node should be in graph */
14786  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14787 
14788  if( node->depth == 0 )
14789  {
14790  /* we cannot update bound tightenings in variable nodes here */
14791  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14792  return SCIP_OKAY;
14793  }
14794 
14795  assert(node->op != SCIP_EXPR_VARIDX);
14796  assert(node->op != SCIP_EXPR_PARAM);
14797 
14798  /* if many children, get large enough memory to store children bounds */
14800  {
14801  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14802  SCIP_ALLOC_TERMINATE(retcode, BMSallocMemoryArray(&childcurv, node->nchildren), TERMINATE);
14803  }
14804  else
14805  {
14806  childbounds = childboundsstatic;
14807  childcurv = childcurvstatic;
14808  }
14809 
14810  /* assemble bounds and curvature of children */
14811  for( i = 0; i < node->nchildren; ++i )
14812  {
14813  /* child should have valid and non-empty bounds */
14815  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14816  /* nodes at depth 0 are always linear */
14817  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14818 
14819  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
14820  childcurv[i] = node->children[i]->curv; /*lint !e644*/
14821  }
14822 
14823  /* if we do not have valid bounds, then update
14824  * code below is copied from exprgraphNodeUpdateBounds */
14826  {
14827  SCIP_INTERVAL newbounds;
14828 
14829  /* calling interval evaluation function for this operand */
14830  assert( exprOpTable[node->op].inteval != NULL );
14831  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds), TERMINATE );
14832 
14833  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14834  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14835  *
14836  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14837  *
14838  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14839  */
14840  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14842  {
14843  for( i = 0; i < node->nparents; ++i )
14845 
14846  node->bounds = newbounds;
14847  }
14848  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14849  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14850  {
14851  for( i = 0; i < node->nparents; ++i )
14853 
14854  node->bounds = newbounds;
14855  }
14856  else
14857  {
14858  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14859  }
14860 
14861  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);
14862 
14863  /* node now has valid bounds */
14864  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
14865  }
14866 
14867  /* update curvature */
14868  if( SCIPintervalIsEmpty(infinity, node->bounds) )
14869  {
14870  node->curv = SCIP_EXPRCURV_LINEAR;
14871 
14872  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14873  }
14874  else
14875  {
14876  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv), TERMINATE );
14877 
14878  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14879  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14880  * SCIPdebugPrintf("\n");
14881  */
14882  }
14883 TERMINATE:
14884  /* free memory, if allocated before */
14885  if( childbounds != childboundsstatic )
14886  {
14887  BMSfreeMemoryArrayNull(&childbounds);
14888  BMSfreeMemoryArrayNull(&childcurv);
14889  }
14890 
14891  return retcode;
14892 }
14893 
14894 /**@} */
14895 
14896 /**@name Expression graph methods */
14897 /**@{ */
14898 
14899 /* In debug mode, the following methods are implemented as function calls to ensure
14900  * type validity.
14901  * In optimized mode, the methods are implemented as defines to improve performance.
14902  * However, we want to have them in the library anyways, so we have to undef the defines.
14903  */
14904 
14905 #undef SCIPexprgraphGetDepth
14906 #undef SCIPexprgraphGetNNodes
14907 #undef SCIPexprgraphGetNodes
14908 #undef SCIPexprgraphGetNVars
14909 #undef SCIPexprgraphGetVars
14910 #undef SCIPexprgraphGetVarNodes
14911 #undef SCIPexprgraphSetVarNodeValue
14912 #undef SCIPexprgraphSetVarsBounds
14913 #undef SCIPexprgraphSetVarBounds
14914 #undef SCIPexprgraphSetVarNodeBounds
14915 #undef SCIPexprgraphSetVarNodeLb
14916 #undef SCIPexprgraphSetVarNodeUb
14917 #undef SCIPexprgraphGetVarsBounds
14918 
14919 /** get current maximal depth of expression graph */
14921  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14922  )
14923 {
14924  assert(exprgraph != NULL);
14925 
14926  return exprgraph->depth;
14927 }
14928 
14929 /** gets array with number of nodes at each depth of expression graph */
14931  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14932  )
14933 {
14934  assert(exprgraph != NULL);
14935 
14936  return exprgraph->nnodes;
14937 }
14938 
14939 /** gets nodes of expression graph, one array per depth */
14941  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14942  )
14943 {
14944  assert(exprgraph != NULL);
14945 
14946  return exprgraph->nodes;
14947 }
14948 
14949 /** gets number of variables in expression graph */
14951  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14952  )
14953 {
14954  assert(exprgraph != NULL);
14955 
14956  return exprgraph->nvars;
14957 }
14958 
14959 /** gets array of variables in expression graph */
14961  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14962  )
14963 {
14964  assert(exprgraph != NULL);
14965 
14966  return exprgraph->vars;
14967 }
14968 
14969 /** gets array of expression graph nodes corresponding to variables */
14971  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14972  )
14973 {
14974  assert(exprgraph != NULL);
14975 
14976  return exprgraph->varnodes;
14977 }
14978 
14979 /** sets value for a single variable given as expression graph node */
14981  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14982  SCIP_Real value /**< new value for variable */
14983  )
14984 {
14985  assert(varnode != NULL);
14986  assert(varnode->op == SCIP_EXPR_VARIDX);
14987 
14988  varnode->value = value;
14989 }
14990 
14991 /** sets bounds for variables */
14993  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14994  SCIP_INTERVAL* varbounds /**< new bounds for variables */
14995  )
14996 {
14997  assert(exprgraph != NULL);
14998  assert(varbounds != NULL || exprgraph->nvars == 0);
14999 
15000  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
15001 }
15002 
15003 /** sets bounds for a single variable */
15005  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15006  void* var, /**< variable */
15007  SCIP_INTERVAL varbounds /**< new bounds of variable */
15008  )
15009 {
15010  int pos;
15011 
15012  assert(exprgraph != NULL);
15013  assert(var != NULL);
15014  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15015 
15016  pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15017  assert(pos < exprgraph->nvars);
15018  assert(exprgraph->vars[pos] == var);
15019 
15020  exprgraph->varbounds[pos] = varbounds;
15021 }
15022 
15023 /** sets bounds for a single variable given as expression graph node */
15025  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15026  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15027  SCIP_INTERVAL varbounds /**< new bounds of variable */
15028  )
15029 {
15030  int pos;
15031 
15032  assert(exprgraph != NULL);
15033  assert(varnode != NULL);
15034 
15035  pos = varnode->data.intval;
15036  assert(pos >= 0);
15037  assert(pos < exprgraph->nvars);
15038  assert(exprgraph->varnodes[pos] == varnode);
15039 
15040  exprgraph->varbounds[pos] = varbounds;
15041 }
15042 
15043 /** sets lower bound for a single variable given as expression graph node */
15045  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15046  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15047  SCIP_Real lb /**< new lower bound for variable */
15048  )
15049 {
15050  int pos;
15051 
15052  assert(exprgraph != NULL);
15053  assert(varnode != NULL);
15054 
15055  pos = varnode->data.intval;
15056  assert(pos >= 0);
15057  assert(pos < exprgraph->nvars);
15058  assert(exprgraph->varnodes[pos] == varnode);
15059 
15060  exprgraph->varbounds[pos].inf = lb;
15061 }
15062 
15063 /** sets upper bound for a single variable given as expression graph node */
15065  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15066  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15067  SCIP_Real ub /**< new upper bound for variable */
15068  )
15069 {
15070  int pos;
15071 
15072  assert(exprgraph != NULL);
15073  assert(varnode != NULL);
15074 
15075  pos = varnode->data.intval;
15076  assert(pos >= 0);
15077  assert(pos < exprgraph->nvars);
15078  assert(exprgraph->varnodes[pos] == varnode);
15079 
15080  exprgraph->varbounds[pos].sup = ub;
15081 }
15082 
15083 /** gets bounds that are stored for all variables */
15085  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
15086  )
15087 {
15088  return exprgraph->varbounds;
15089 }
15090 
15091 /** creates an empty expression graph */
15093  BMS_BLKMEM* blkmem, /**< block memory */
15094  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
15095  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
15096  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
15097  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /**< callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
15098  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /**< callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
15099  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /**< callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
15100  void* userdata /**< user data to pass to callback functions */
15101  )
15102 {
15103  assert(blkmem != NULL);
15104  assert(exprgraph != NULL);
15105 
15106  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
15107  BMSclearMemory(*exprgraph);
15108  (*exprgraph)->blkmem = blkmem;
15109 
15110  /* create nodes's arrays */
15111  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
15112  assert((*exprgraph)->depth >= 1);
15113 
15114  /* create var's arrays and hashmap */
15115  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
15116  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, (*exprgraph)->varssize) );
15117 
15118  /* empty array of constants is sorted */
15119  (*exprgraph)->constssorted = TRUE;
15120 
15121  /* store callback functions and user data */
15122  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
15123  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
15124  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
15125  (*exprgraph)->userdata = userdata;
15126 
15127  return SCIP_OKAY;
15128 }
15129 
15130 /** frees an expression graph */
15132  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
15133  )
15134 {
15135  BMS_BLKMEM* blkmem;
15136  int d;
15137 
15138  assert( exprgraph != NULL);
15139  assert(*exprgraph != NULL);
15140  assert((*exprgraph)->nvars == 0);
15141  assert((*exprgraph)->nconsts == 0);
15142 
15143  blkmem = (*exprgraph)->blkmem;
15144  assert(blkmem != NULL);
15145 
15146  /* free nodes arrays */
15147  for( d = 0; d < (*exprgraph)->depth; ++d )
15148  {
15149  assert((*exprgraph)->nnodes[d] == 0);
15150  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
15151  }
15152  assert((*exprgraph)->nodes != NULL);
15153  assert((*exprgraph)->nnodes != NULL);
15154  assert((*exprgraph)->nodessize != NULL);
15155  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
15156  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
15157  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
15158 
15159  /* free variables arrays and hashmap */
15160  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
15161  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
15162  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
15163  SCIPhashmapFree(&(*exprgraph)->varidxs);
15164 
15165  /* free constants array */
15166  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
15167 
15168  /* free graph struct */
15169  BMSfreeBlockMemory(blkmem, exprgraph);
15170 
15171  return SCIP_OKAY;
15172 }
15173 
15174 /** adds an expression graph node to an expression graph
15175  *
15176  * Expression graph assumes ownership of node.
15177  * Children are notified about new parent.
15178  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
15179  */
15181  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15182  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
15183  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
15184  int nchildren, /**< number of children */
15185  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
15186  )
15187 {
15188  SCIP_Bool childvalsvalid;
15189  int depth;
15190  int i;
15191 
15192  assert(exprgraph != NULL);
15193  assert(node != NULL);
15194  assert(node->pos < 0); /* node should have no position in graph yet */
15195  assert(node->depth < 0); /* node should have no position in graph yet */
15196  assert(node->nchildren == 0); /* node should not have stored children yet */
15197  assert(node->children == NULL); /* node should not have stored children yet */
15198  assert(node->nparents == 0); /* node should not have parents stored yet */
15199  assert(children != NULL || nchildren == 0);
15200 
15201  /* choose depth as maximal depth of children + 1, and at least mindepth */
15202  depth = MAX(0, mindepth);
15203  for( i = 0; i < nchildren; ++i )
15204  {
15205  if( children[i]->depth >= depth ) /*lint !e613*/
15206  depth = children[i]->depth + 1; /*lint !e613*/
15207  }
15208 
15209  /* ensure that expression graph is deep enough */
15210  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
15211  assert(exprgraph->depth > depth);
15212 
15213  /* ensure enough space for nodes at depth depth */
15214  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
15215 
15216  /* add node to graph */
15217  node->depth = depth;
15218  node->pos = exprgraph->nnodes[depth];
15219  exprgraph->nodes[depth][node->pos] = node;
15220  ++exprgraph->nnodes[depth];
15221 
15222  /* add as parent to children
15223  * and check if children has valid values */
15224  childvalsvalid = TRUE;
15225  for( i = 0; i < nchildren; ++i )
15226  {
15227  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
15228  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
15229  }
15230  /* store children */
15231  if( nchildren > 0 )
15232  {
15233  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
15234  node->nchildren = nchildren;
15235  }
15236 
15237  if( node->op == SCIP_EXPR_CONST )
15238  {
15239  /* set bounds to constant value of node */
15241  SCIPintervalSet(&node->bounds, node->data.dbl);
15242  }
15243  else
15244  {
15245  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
15248  exprgraph->needvarboundprop = TRUE;
15249  }
15250 
15251  /* if not a variable, set value of node according to values of children (if all have valid values) */
15252  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
15253  {
15254  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15255  }
15256 
15257  return SCIP_OKAY;
15258 }
15259 
15260 /** adds variables to an expression graph, if not existing yet
15261  *
15262  * Also already existing nodes are enabled.
15263  */
15265  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15266  int nvars, /**< number of variables to add */
15267  void** vars, /**< variables to add */
15268  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
15269  )
15270 {
15271  SCIP_EXPRGRAPHNODE* node;
15272  SCIP_EXPROPDATA opdata;
15273  int i;
15274 
15275  assert(exprgraph != NULL);
15276  assert(exprgraph->depth >= 1);
15277  assert(vars != NULL || nvars == 0);
15278 
15279  /* 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 */
15280  if( exprgraph->nvars == 0 )
15281  {
15282  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15283  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15284  }
15285 
15286  for( i = 0; i < nvars; ++i )
15287  {
15288  /* skip variables that exist already */
15289  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15290  {
15291  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
15292  assert(node != NULL);
15293 
15294  /* enable node */
15295  node->enabled = TRUE;
15296 
15297  if( varnodes != NULL )
15298  varnodes[i] = node;
15299 
15300  continue;
15301  }
15302 
15303  /* create new variable expression */
15304  opdata.intval = exprgraph->nvars;
15305  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15306 
15307  /* add expression node to expression graph at depth 0 */
15308  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15309 
15310  /* add variable node to vars arrays and hashmap */
15311  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15312  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
15313  exprgraph->varnodes[exprgraph->nvars] = node;
15314  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15315  SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[i], exprgraph->nvars) ); /*lint !e613*/
15316  ++exprgraph->nvars;
15317 
15318  if( varnodes != NULL )
15319  varnodes[i] = node;
15320 
15321  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15322 
15323  /* call callback method, if set */
15324  if( exprgraph->exprgraphvaradded != NULL )
15325  {
15326  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
15327  }
15328  }
15329 
15330  return SCIP_OKAY;
15331 }
15332 
15333 /** adds a constant to an expression graph, if not existing yet
15334  *
15335  * Also already existing nodes are enabled.
15336  */
15338  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15339  SCIP_Real constant, /**< constant to add */
15340  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
15341  )
15342 {
15343  SCIP_EXPROPDATA opdata;
15344 
15345  assert(exprgraph != NULL);
15346  assert(constnode != NULL);
15347 
15348  /* check if there is already an expression for this constant */
15349  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15350  {
15351  assert(*constnode != NULL);
15352  assert((*constnode)->op == SCIP_EXPR_CONST);
15353  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15354  (*constnode)->enabled = TRUE;
15355  return SCIP_OKAY;
15356  }
15357 
15358  /* create new node for constant */
15359  opdata.dbl = constant;
15360  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15361 
15362  /* add node to expression graph at depth 0 */
15363  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15364  assert((*constnode)->depth == 0);
15365  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
15366 
15367  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15368  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15369  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15370  ++exprgraph->nconsts;
15371  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15372 
15373  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15374 
15375  return SCIP_OKAY;
15376 }
15377 
15378 /** adds sum of expression trees into expression graph
15379  *
15380  * node will also be captured.
15381  *
15382  * @note Parameters will be converted into constants
15383  */
15385  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15386  int nexprtrees, /**< number of expression trees to add */
15387  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
15388  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
15389  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
15390  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) */
15391  )
15392 {
15393  SCIP_Bool allone;
15394 
15395  assert(exprgraph != NULL);
15396  assert(nexprtrees > 0);
15397  assert(exprtrees != NULL);
15398  assert(rootnode != NULL);
15399  assert(rootnodeisnew != NULL);
15400 
15401  *rootnode = NULL;
15402 
15403  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15404  {
15405  assert(exprtrees[0] != NULL);
15406  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15407 
15408  /* coverity[var_deref_model] */
15409  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, exprtrees[0]->params, rootnode, rootnodeisnew) );
15410  }
15411  else
15412  {
15413  SCIP_EXPROP op;
15414  SCIP_EXPRGRAPHNODE** rootnodes;
15415  SCIP_Bool rootnodeisnew_;
15416  int i;
15417 
15418  *rootnodeisnew = TRUE;
15419  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15420 
15421  allone = TRUE;
15422  for( i = 0; i < nexprtrees; ++i )
15423  {
15424  assert(exprtrees[i] != NULL);
15425  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15426 
15427  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, exprtrees[i]->params, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
15428  assert(rootnodes[i] != NULL);
15429  *rootnodeisnew &= rootnodeisnew_;
15430 
15431  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
15432  }
15433 
15434  /* decide which operand we want to use for the root node */
15435  if( coefs == NULL || allone )
15436  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15437  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15438  op = SCIP_EXPR_MINUS;
15439  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15440  {
15441  SCIP_EXPRGRAPHNODE* tmp;
15442 
15443  tmp = rootnodes[0];
15444  rootnodes[0] = rootnodes[1];
15445  rootnodes[1] = tmp;
15446  op = SCIP_EXPR_MINUS;
15447  }
15448  else
15449  op = SCIP_EXPR_LINEAR;
15450 
15451  if( op != SCIP_EXPR_LINEAR )
15452  {
15453  SCIP_EXPROPDATA data;
15454  data.data = NULL;
15455 
15456  if( !*rootnodeisnew )
15457  {
15458  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15459  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15460  }
15461 
15462  if( *rootnode == NULL )
15463  {
15464  /* create new node for sum of rootnodes and add to exprgraph */
15465  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15466  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15467  *rootnodeisnew = TRUE;
15468  }
15469  else
15470  {
15471  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15472  *rootnodeisnew = FALSE;
15473  }
15474  }
15475  else
15476  {
15477  SCIP_EXPROPDATA data;
15478  SCIP_Real* lindata;
15479 
15480  assert(op == SCIP_EXPR_LINEAR);
15481 
15482  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15483  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15484  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
15485  lindata[nexprtrees] = 0.0;
15486  data.data = lindata;
15487 
15488  if( !*rootnodeisnew )
15489  {
15490  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15491  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15492  }
15493 
15494  if( *rootnode == NULL )
15495  {
15496  /* create new node for linear combination of rootnodes and add to exprgraph */
15497  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15498  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15499  *rootnodeisnew = TRUE;
15500  }
15501  else
15502  {
15503  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15504  *rootnodeisnew = FALSE;
15505  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15506  }
15507  }
15508 
15509  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15510  }
15511  assert(*rootnode != NULL);
15512 
15513  SCIPexprgraphCaptureNode(*rootnode);
15514 
15515  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15516  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15517 
15518  return SCIP_OKAY;
15519 }
15520 
15521 /** replaces variable in expression graph by a linear sum of variables
15522  *
15523  * Variables will be added if not in the graph yet.
15524  */
15526  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15527  void* var, /**< variable to replace */
15528  int ncoefs, /**< number of coefficients in linear term */
15529  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
15530  void** vars, /**< variables in linear term */
15531  SCIP_Real constant /**< constant offset */
15532  )
15533 {
15534  SCIP_EXPRGRAPHNODE* varnode;
15535  SCIP_Real* lindata;
15536  int varidx;
15537  int i;
15538 
15539  assert(exprgraph != NULL);
15540  assert(var != NULL);
15541  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15542  assert(coefs != NULL || ncoefs == 0);
15543  assert(vars != NULL || ncoefs == 0);
15544 
15545  varidx = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15546  assert(varidx < exprgraph->nvars);
15547  assert(exprgraph->vars[varidx] == var);
15548  varnode = exprgraph->varnodes[varidx];
15549  assert(varnode != NULL);
15550  assert(varnode->data.intval == varidx);
15551 
15552  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
15553  {
15554  /* variable is replaced by constant or variable */
15555  SCIP_EXPRGRAPHNODE* node;
15556 
15557  /* check if there is already a node for this constant or variable */
15558  node = NULL;
15559  if( ncoefs == 0 )
15560  {
15561  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15562  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
15563  }
15564  else
15565  {
15566  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
15567  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
15568  }
15569 
15570  if( node != NULL )
15571  {
15572  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15573 
15574  /* tell parents of varnode to replace child varnode by node, this may free varnode */
15575  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15576 
15577  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15578  if( varnode != NULL )
15579  {
15580  assert(varnode->nuses > 0);
15581  assert(varnode->nparents == 0);
15582 
15583  /* remove variable (but don't free it's node) from graph */
15584  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15585 
15586  /* move varnode up to depth 1 */
15587  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15588 
15589  /* turn into EXPR_SUM expression */
15590  varnode->op = SCIP_EXPR_SUM;
15591  varnode->data.data = NULL;
15592  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
15593  varnode->children[0] = node;
15594  varnode->nchildren = 1;
15595  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15596 
15597  varnode->value = node->value;
15598  varnode->bounds = node->bounds;
15599  varnode->boundstatus = (node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID) ? SCIP_EXPRBOUNDSTATUS_VALID : SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
15600  }
15601  }
15602  else if( ncoefs == 0 )
15603  {
15604  /* turn node into EXPR_CONST node */
15605 
15606  /* remove variable (but don't free it's node) from graph */
15607  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15608 
15609  /* convert into EXPR_CONST node */
15610  varnode->op = SCIP_EXPR_CONST;
15611  varnode->data.dbl = constant;
15612 
15613  varnode->value = constant;
15614  SCIPintervalSet(&varnode->bounds, constant);
15616 
15617  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15618  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15619  exprgraph->constnodes[exprgraph->nconsts] = varnode;
15620  ++exprgraph->nconsts;
15621  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15622  }
15623  else
15624  {
15625  /* turn node into EXPR_VARIDX node for new variable */
15626 
15627  /* remove variable (but don't free it's node) from graph */
15628  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15629 
15630  varnode->data.intval = exprgraph->nvars;
15631 
15632  /* add variable node to vars arrays and hashmap */
15633  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15634  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
15635  exprgraph->varnodes[exprgraph->nvars] = varnode;
15636  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15637  SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[0], exprgraph->nvars) ); /*lint !e613*/
15638  ++exprgraph->nvars;
15639 
15640  /* call callback method, if set */
15641  if( exprgraph->exprgraphvaradded != NULL )
15642  {
15643  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
15644  }
15645  }
15646 
15647  /* mark varnode and its parents as not simplified */
15648  if( varnode != NULL )
15649  {
15650  varnode->simplified = FALSE;
15651  for( i = 0; i < varnode->nparents; ++i )
15652  varnode->parents[i]->simplified = FALSE;
15653  }
15654 
15655  return SCIP_OKAY;
15656  }
15657 
15658  /* turn varnode into EXPR_LINEAR */
15659 
15660  /* remove variable (but don't free it's node) from graph */
15661  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15662 
15663  /* move varnode up to depth 1 */
15664  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15665 
15666  /* convert into EXPR_LINEAR node */
15667  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15668  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
15669  lindata[ncoefs] = constant;
15670  varnode->data.data = (void*)lindata;
15671  varnode->op = SCIP_EXPR_LINEAR;
15672 
15673  /* add nodes corresponding to vars to expression graph, if not existing yet */
15674  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15675  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15676  varnode->nchildren = ncoefs;
15677 
15678  /* notify vars about new parent varnode */
15679  for( i = 0; i < ncoefs; ++i )
15680  {
15681  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15682  }
15683 
15684  /* set value and bounds to invalid, curvature can remain (still linear) */
15685  varnode->value = SCIP_INVALID;
15687 
15688  /* mark varnode and its parents as not simplified */
15689  varnode->simplified = FALSE;
15690  for( i = 0; i < varnode->nparents; ++i )
15691  varnode->parents[i]->simplified = FALSE;
15692 
15693  return SCIP_OKAY;
15694 }
15695 
15696 /** finds expression graph node corresponding to a variable */
15698  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15699  void* var, /**< variable to search for */
15700  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15701  )
15702 {
15703  int pos;
15704 
15705  assert(exprgraph != NULL);
15706  assert(var != NULL);
15707  assert(varnode != NULL);
15708 
15709  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15710  {
15711  *varnode = NULL;
15712  return FALSE;
15713  }
15714 
15715  pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15716  assert(pos < exprgraph->nvars);
15717 
15718  *varnode = exprgraph->varnodes[pos];
15719  assert(*varnode != NULL);
15720  assert((*varnode)->op == SCIP_EXPR_VARIDX);
15721 
15722  return TRUE;
15723 }
15724 
15725 /** finds expression graph node corresponding to a constant */
15727  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15728  SCIP_Real constant, /**< constant to search for */
15729  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15730  )
15731 {
15732  int left;
15733  int right;
15734  int middle;
15735 
15736  assert(exprgraph != NULL);
15737  assert(constnode != NULL);
15738  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
15739 
15740  exprgraphSortConstNodes(exprgraph);
15741  assert(exprgraph->constssorted);
15742 
15743  /* find node using binary search */
15744  left = 0;
15745  right = exprgraph->nconsts-1;
15746  *constnode = NULL;
15747 
15748  while( left <= right )
15749  {
15750  middle = (left+right)/2;
15751  assert(0 <= middle && middle < exprgraph->nconsts);
15752 
15753  if( constant < exprgraph->constnodes[middle]->data.dbl )
15754  right = middle - 1;
15755  else if( constant > exprgraph->constnodes[middle]->data.dbl )
15756  left = middle + 1;
15757  else
15758  {
15759  *constnode = exprgraph->constnodes[middle];
15760  break;
15761  }
15762  }
15763  if( left == right+1 )
15764  return FALSE;
15765 
15766  assert(*constnode != NULL);
15767  assert((*constnode)->op == SCIP_EXPR_CONST);
15768  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15769 
15770  return TRUE;
15771 }
15772 
15773 /** prints an expression graph in dot format */
15775  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15776  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15777  FILE* file, /**< file to print to, or NULL for stdout */
15778  const char** varnames /**< variable names, or NULL for generic names */
15779  )
15780 {
15781  int d;
15782  int i;
15783 
15784  assert(exprgraph != NULL);
15785 
15786  if( file == NULL )
15787  file = stdout;
15788 
15789  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15790  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15791 
15792  for( d = 0; d < exprgraph->depth; ++d )
15793  {
15794  if( exprgraph->nnodes[d] == 0 )
15795  continue;
15796 
15797  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15798  {
15799  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15800  }
15801  }
15802 
15803  /* tell dot that all nodes of depth 0 have the same rank */
15804  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15805  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15806  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15807  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15808 
15809  /* tell dot that all nodes without parent have the same rank */
15810  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15811  for( d = 0; d < exprgraph->depth; ++d )
15812  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15813  if( exprgraph->nodes[d][i]->nparents == 0 )
15814  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15815  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15816 
15817  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15818 
15819  return SCIP_OKAY;
15820 }
15821 
15822 /** evaluates nodes of expression graph for given values of variables */
15824  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15825  SCIP_Real* varvals /**< values for variables */
15826  )
15827 {
15828  int d;
15829  int i;
15830 
15831  assert(exprgraph != NULL);
15832  assert(varvals != NULL || exprgraph->nvars == 0);
15833 
15834  for( d = 0; d < exprgraph->depth; ++d )
15835  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15836  {
15837  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15838  }
15839 
15840  return SCIP_OKAY;
15841 }
15842 
15843 /** propagates bound changes in variables forward through the expression graph */
15845  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15846  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15847  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
15848  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15849  )
15850 {
15851  SCIP_EXPRGRAPHNODE* node;
15852  SCIP_Bool boundchanged;
15853  int d;
15854  int i;
15855 
15856  assert(exprgraph != NULL);
15857  assert(domainerror != NULL);
15858 
15859  *domainerror = FALSE;
15860 
15861  /* update bounds in varnodes of expression graph */
15862  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15863 
15864  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15865  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15866  {
15867  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15868  return SCIP_OKAY;
15869  }
15870 
15871  /* propagate bound changes, interrupt if we get to a node with empty bounds */
15872  for( d = 1; d < exprgraph->depth; ++d )
15873  {
15874  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15875  {
15876  node = exprgraph->nodes[d][i];
15877  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15878  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15879  {
15880  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15881  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15882  *domainerror = TRUE;
15883  return SCIP_OKAY;
15884  }
15885  }
15886  }
15887 
15888  exprgraph->needvarboundprop = FALSE;
15889 
15890  return SCIP_OKAY;
15891 }
15892 
15893 /** propagates bound changes in nodes backward through the graph
15894  *
15895  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15896  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15897  */
15899  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15900  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15901  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15902  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15903  )
15904 {
15905  SCIP_EXPRGRAPHNODE* node;
15906  int d;
15907  int i;
15908 
15909  assert(exprgraph != NULL);
15910  assert(cutoff != NULL);
15911 
15912  *cutoff = FALSE;
15913 
15914  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15915  {
15916  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15917  {
15918  node = exprgraph->nodes[d][i];
15919  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15920  }
15921  }
15922  if( *cutoff )
15923  return;
15924 }
15925 
15926 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15927  *
15928  * Implies update of bounds in expression graph.
15929  */
15931  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15932  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15933  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15934  )
15935 {
15936  SCIP_EXPRGRAPHNODE* node;
15937  SCIP_Bool boundchanged;
15938  int d;
15939  int i;
15940 
15941  assert(exprgraph != NULL);
15942 
15943  /* update bounds in varnodes of expression graph */
15944  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15945 
15946 #ifndef NDEBUG
15947  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15948  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15949 #endif
15950 
15951  for( d = 1; d < exprgraph->depth; ++d )
15952  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15953  {
15954  node = exprgraph->nodes[d][i];
15955  assert(node != NULL);
15956 
15957  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15958 
15959  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15960  {
15961  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15962  return SCIP_OKAY;
15963  }
15964  }
15965 
15966  return SCIP_OKAY;
15967 }
15968 
15969 /** aims at simplifying an expression graph
15970  *
15971  * 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)).
15972  */
15974  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15975  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15976  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15977  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15978  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15979  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15980  )
15981 {
15982  SCIP_EXPRGRAPHNODE* node;
15983  SCIP_Bool havechangenode;
15984  SCIP_Bool allsimplified;
15985  int d;
15986  int i;
15987  int j;
15988 
15989 #ifndef NDEBUG
15990  SCIP_Real* testx;
15991  SCIP_HASHMAP* testvalidx;
15992  SCIP_Real* testvals;
15993  SCIP_RANDNUMGEN* randnumgen;
15994  int testvalssize;
15995  int ntestvals;
15996 #endif
15997 
15998  assert(exprgraph != NULL);
15999  assert(eps >= 0.0);
16000  assert(havechange != NULL);
16001  assert(domainerror != NULL);
16002 
16003 #ifndef NDEBUG
16004  SCIP_CALL( SCIPrandomCreate(&randnumgen, exprgraph->blkmem, 862) ); /* see also #1848 */
16005  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
16006  testvals = NULL;
16007  ntestvals = 0;
16008  testvalssize = 0;
16009 
16010  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
16011  for( i = 0; i < exprgraph->nvars; ++i )
16012  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
16013  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
16014  for( d = 1; d < exprgraph->depth; ++d )
16015  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16016  {
16017  node = exprgraph->nodes[d][i];
16018  assert(node != NULL);
16019 
16020  /* 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 */
16021  if( node->nuses > 0 )
16022  {
16023  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
16024  SCIP_CALL( SCIPhashmapInsertInt(testvalidx, (void*)node, ntestvals) );
16025  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
16026  ++ntestvals;
16027  }
16028  }
16029 
16030  SCIPrandomFree(&randnumgen, exprgraph->blkmem);
16031 #endif
16032 
16033 #ifdef SCIP_OUTPUT
16034  {
16035  FILE* file;
16036  file = fopen("exprgraph_beforesimplify.dot", "w");
16037  if( file != NULL )
16038  {
16039  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16040  fclose(file);
16041  }
16042  }
16043 #endif
16044 
16045  *havechange = FALSE; /* we have not changed any node yet */
16046  *domainerror = FALSE; /* no domain errors encountered so far */
16047  allsimplified = TRUE; /* all nodes we looked at are simplified */
16048 
16049  /* call node simplifier from bottom up
16050  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
16051  */
16052  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
16053  {
16054  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16055  {
16056  node = exprgraph->nodes[d][i];
16057  assert(node != NULL);
16058 
16059  havechangenode = FALSE; /* node did not change yet */
16060 
16061  if( node->op != SCIP_EXPR_CONST )
16062  {
16063  /* skip nodes that are already simplified */
16064  if( node->simplified )
16065  continue;
16066 
16067  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
16068 
16069  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
16070  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
16071  assert(node->simplified == TRUE);
16072  *havechange |= havechangenode;
16073  }
16074 
16075  /* if node was or has been converted into constant, may move to depth 0 */
16076  if( node->op == SCIP_EXPR_CONST )
16077  {
16078  SCIP_EXPRGRAPHNODE* constnode;
16079 
16080  if( !SCIPisFinite(node->value) ) /*lint !e777*/
16081  {
16082  SCIPdebugMessage("Expression graph simplify turned node into NaN or inf.\n");
16083  *domainerror = TRUE;
16084  break;
16085  }
16086 
16087  /* check if there is already a node for this constant */
16088  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
16089  {
16090  assert(constnode->op == SCIP_EXPR_CONST);
16091  assert(constnode->data.dbl == node->value); /*lint !e777*/
16092 
16093  if( node->nparents > 0 )
16094  {
16095  /* move parents of this node to constnode, node may be freed if not in use */
16096  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
16097  /* node should have no parents anymore, so it should have been freed if not in use */
16098  assert(node == NULL || node->nuses > 0);
16099  havechangenode = TRUE;
16100 
16101  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
16102  if( node == NULL )
16103  {
16104  --i;
16105  continue;
16106  }
16107  }
16108  assert(node != NULL);
16109  assert(node->nuses > 0);
16110 
16111  if( constnode->nuses == 0 )
16112  {
16113  /* move node to depth 0, adding it to constnodes */
16114  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16115 
16116  /* move parents of constnode to node, so constnode is freed */
16117  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
16118  assert(constnode == NULL);
16119  havechangenode = TRUE;
16120 
16121  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16122  --i;
16123  continue;
16124  }
16125  }
16126  else
16127  {
16128  /* move to depth 0, adding it to constnodes */
16129  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16130 
16131  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16132  --i;
16133  }
16134  }
16135 
16136  /* if there was a change, mark parents as not simplified */
16137  if( havechangenode )
16138  for( j = 0; j < node->nparents; ++j )
16139  node->parents[j]->simplified = FALSE;
16140  }
16141  } /*lint !e850*/
16142 
16143  /* if we did nothing, clean up and escape from here */
16144  if( allsimplified || *domainerror )
16145  goto EXPRGRAPHSIMPLIFY_CLEANUP;
16146 
16147  /* @todo find duplicate subexpressions in expression graph */
16148 
16149  /* unconvert polynomials into simpler expressions, where possible */
16150  for( d = 1; d < exprgraph->depth; ++d )
16151  {
16152  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16153  {
16154  node = exprgraph->nodes[d][i];
16155  assert(node != NULL);
16156 
16157  if( node->op != SCIP_EXPR_POLYNOMIAL )
16158  continue;
16159 
16160  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
16161 
16162  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
16163  {
16164  /* node is identity w.r.t only child
16165  * replace node as child of parents by child of node
16166  */
16167 
16168  for( j = 0; node != NULL && j < node->nparents; ++j )
16169  {
16170  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
16171  }
16172  /* node should have no parents anymore, so it should have been freed if not in use */
16173  assert(node == NULL || node->nuses > 0);
16174 
16175  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
16176  if( node == NULL )
16177  --i;
16178  }
16179  }
16180  } /*lint !e850*/
16181 
16182 #ifdef SCIP_OUTPUT
16183  {
16184  FILE* file;
16185  file = fopen("exprgraph_aftersimplify.dot", "w");
16186  if( file != NULL )
16187  {
16188  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16189  fclose(file);
16190  }
16191  }
16192 #endif
16193 
16194 #ifndef NDEBUG
16195  for( d = 1; d < exprgraph->depth; ++d )
16196  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16197  {
16198  int idx;
16199  SCIP_Real testval_before;
16200  SCIP_Real testval_after;
16201 
16202  node = exprgraph->nodes[d][i];
16203  assert(node != NULL);
16204 
16205  SCIP_CALL( exprgraphNodeEval(node, NULL) );
16206 
16207  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
16208  if( node->nuses > 0 )
16209  {
16210  assert(SCIPhashmapExists(testvalidx, (void*)node));
16211 
16212  idx = SCIPhashmapGetImageInt(testvalidx, (void*)node);
16213  assert(idx < ntestvals);
16214  assert(testvals != NULL);
16215 
16216  testval_before = testvals[idx]; /*lint !e613*/
16217  testval_after = SCIPexprgraphGetNodeVal(node);
16218 
16219  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
16220  }
16221  }
16222 #endif
16223 
16224  EXPRGRAPHSIMPLIFY_CLEANUP:
16225 #ifndef NDEBUG
16226  BMSfreeMemoryArray(&testx);
16227  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
16228  SCIPhashmapFree(&testvalidx);
16229 #endif
16230 
16231  return SCIP_OKAY;
16232 }
16233 
16234 /** creates an expression tree from a given node in an expression graph */
16236  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16237  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
16238  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
16239  )
16240 {
16241  SCIP_EXPR* root;
16242  int nexprvars;
16243  int* varidx;
16244  int i;
16245 
16246  assert(exprgraph != NULL);
16247  assert(rootnode != NULL);
16248  assert(rootnode->depth >= 0);
16249  assert(rootnode->pos >= 0);
16250  assert(exprtree != NULL);
16251 
16252  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16253  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16254 
16255  /* initially, no variable appears in the expression tree */
16256  for( i = 0; i < exprgraph->nvars; ++i )
16257  varidx[i] = -1; /*lint !e644*/
16258  nexprvars = 0;
16259 
16260  /* create expression from the subgraph that has rootnode as root */
16261  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
16262 
16263  /* create expression tree for this expression */
16264  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
16265 
16266  /* copy variables into expression tree */
16267  if( nexprvars > 0 )
16268  {
16269  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
16270  for( i = 0; i < exprgraph->nvars; ++i )
16271  {
16272  assert(varidx[i] >= -1);
16273  assert(varidx[i] < nexprvars);
16274  if( varidx[i] >= 0 )
16275  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
16276  }
16277  }
16278 
16279  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16280 
16281  return SCIP_OKAY;
16282 }
16283 
16284 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16285  *
16286  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16287  */
16289  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16290  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16291  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16292  int* nexprtrees, /**< buffer to store number of expression trees */
16293  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16294  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16295  )
16296 {
16297  int ncomponents;
16298  int* childcomp;
16299  int* varcomp;
16300  int compnr;
16301  SCIP_Bool haveoverlap;
16302  int i;
16303  int j;
16304  int k;
16305 
16306  SCIP_EXPR** exprs;
16307  int nexprs;
16308  int* childmap;
16309  int* childmapinv;
16310  int* varidx;
16311  int nexprvars;
16312 
16313  assert(exprgraph != NULL);
16314  assert(node != NULL);
16315  assert(node->depth >= 0);
16316  assert(node->pos >= 0);
16317  assert(exprtreessize > 0);
16318  assert(nexprtrees != NULL);
16319  assert(exprtrees != NULL);
16320  assert(exprtreecoefs != NULL);
16321 
16322  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16323  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16324  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16325  ( node->op != SCIP_EXPR_PLUS &&
16326  node->op != SCIP_EXPR_MINUS &&
16327  node->op != SCIP_EXPR_SUM &&
16328  node->op != SCIP_EXPR_LINEAR &&
16329  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16330  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16331  {
16332  *nexprtrees = 1;
16333  exprtreecoefs[0] = 1.0;
16334  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16335 
16336  return SCIP_OKAY;
16337  }
16338 
16339  /* find components in node->children <-> variables graph */
16340  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16341  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16342  for( i = 0; i < exprgraph->nvars; ++i )
16343  varcomp[i] = -1; /*lint !e644*/
16344 
16345  haveoverlap = FALSE;
16346  for( i = 0; i < node->nchildren; ++i )
16347  {
16348  compnr = i;
16349  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
16350  assert(compnr >= 0);
16351  assert(compnr < node->nchildren);
16352  childcomp[i] = compnr;
16353 
16354  /* remember if component number was changed by CheckComponent */
16355  if( compnr != i )
16356  haveoverlap = TRUE;
16357  }
16358 
16359  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16360 
16361  if( node->op == SCIP_EXPR_QUADRATIC )
16362  {
16363  /* merge components for products of children from different components */
16365 
16366  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16367  assert(data != NULL);
16368 
16369  for( i = 0; i < data->nquadelems; ++i )
16370  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16371  {
16372  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16373  compnr = childcomp[data->quadelems[i].idx2];
16374  for( j = 0; j < node->nchildren; ++j )
16375  if( childcomp[j] == compnr )
16376  childcomp[j] = childcomp[data->quadelems[i].idx1];
16377  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16378  haveoverlap = TRUE;
16379  }
16380  }
16381  else if( node->op == SCIP_EXPR_POLYNOMIAL )
16382  {
16383  /* merge components for monomials of children from different components */
16385 
16386  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16387  assert(data != NULL);
16388 
16389  for( i = 0; i < data->nmonomials; ++i )
16390  for( j = 1; j < data->monomials[i]->nfactors; ++j )
16391  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16392  {
16393  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16394  compnr = childcomp[data->monomials[i]->childidxs[j]];
16395  for( k = 0; k < node->nchildren; ++k )
16396  if( childcomp[k] == compnr )
16397  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16398  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16399  haveoverlap = TRUE;
16400  }
16401  }
16402 
16403  if( haveoverlap )
16404  {
16405  /* some component numbers are unused, thus relabel and count final number of components */
16406  int* compmap;
16407 
16408  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16409  for( i = 0; i < node->nchildren; ++i )
16410  compmap[i] = -1; /*lint !e644*/
16411 
16412  ncomponents = 0;
16413  for( i = 0; i < node->nchildren; ++i )
16414  {
16415  if( compmap[childcomp[i]] == -1 )
16416  compmap[childcomp[i]] = ncomponents++;
16417  childcomp[i] = compmap[childcomp[i]];
16418  }
16419 
16420  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16421  }
16422  else
16423  {
16424  ncomponents = node->nchildren;
16425  }
16426 
16427  if( ncomponents == 1 )
16428  {
16429  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16430  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16431 
16432  *nexprtrees = 1;
16433  exprtreecoefs[0] = 1.0;
16434  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16435 
16436  return SCIP_OKAY;
16437  }
16438 
16439  if( ncomponents > exprtreessize )
16440  {
16441  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16442  for( i = 0; i < node->nchildren; ++i )
16443  if( childcomp[i] >= exprtreessize )
16444  childcomp[i] = exprtreessize-1;
16445  ncomponents = exprtreessize;
16446  }
16447 
16448  assert(ncomponents >= 2);
16449 
16450  /* setup expression trees for each component */
16451  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16452  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16453  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16454  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16455  for( i = 0; i < ncomponents; ++i )
16456  {
16457  /* initially, no variable appears in the expression tree */
16458  for( j = 0; j < exprgraph->nvars; ++j )
16459  varidx[j] = -1; /*lint !e644*/
16460  nexprvars = 0;
16461 
16462  /* collect expressions from children belonging to component i */
16463  nexprs = 0;
16464  for( j = 0; j < node->nchildren; ++j )
16465  {
16466  assert(childcomp[j] >= 0);
16467  assert(childcomp[j] < ncomponents);
16468  if( childcomp[j] != i )
16469  continue;
16470 
16471  /* create expression from the subgraph that has child j as root */
16472  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
16473  childmap[j] = nexprs; /*lint !e644*/
16474  childmapinv[nexprs] = j; /*lint !e644*/
16475  ++nexprs;
16476  }
16477 
16478  /* setup expression tree for component i */
16479  switch( node->op )
16480  {
16481  case SCIP_EXPR_PLUS:
16482  {
16483  assert(ncomponents == 2);
16484  assert(nexprs == 1);
16485 
16486  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16487  exprtreecoefs[i] = 1.0;
16488 
16489  break;
16490  }
16491 
16492  case SCIP_EXPR_MINUS:
16493  {
16494  assert(ncomponents == 2);
16495  assert(nexprs == 1);
16496 
16497  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16498  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16499  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16500  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16501 
16502  break;
16503  }
16504 
16505  case SCIP_EXPR_SUM:
16506  {
16507  if( nexprs == 1 )
16508  {
16509  /* component corresponds to exactly one child of node */
16510  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16511  }
16512  else
16513  {
16514  /* component corresponds to a sum of children of node */
16515  SCIP_EXPR* sumexpr;
16516 
16517  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16518  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16519  }
16520  exprtreecoefs[i] = 1.0;
16521 
16522  break;
16523  }
16524 
16525  case SCIP_EXPR_LINEAR:
16526  {
16527  SCIP_Real* nodecoefs;
16528  SCIP_EXPR* sumexpr;
16529 
16530  nodecoefs = (SCIP_Real*)node->data.data;
16531 
16532  /* if there is a constant, then we put it into the expression of the first component */
16533  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16534  {
16535  /* component corresponds to exactly one child of node */
16536  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16537  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16538  }
16539  else if( nexprs == 1 )
16540  {
16541  /* component corresponds to a sum of one child and a constant */
16542  assert(i == 0);
16543  assert(nodecoefs[node->nchildren] != 0.0);
16544  assert(nodecoefs[childmapinv[0]] != 0.0);
16545  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16546  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16547  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16548  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16549  }
16550  else
16551  {
16552  /* component corresponds to a linear combination of children of node */
16553 
16554  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16555  {
16556  /* if two expressions with equal sign, then create PLUS expression */
16557  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16558  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16559  }
16560  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16561  {
16562  /* if two expressions with opposite sign, then create MINUS expression */
16563  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16564  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16565  }
16566  else
16567  {
16568  /* assemble coefficents and create SUM or LINEAR expression */
16569  SCIP_Real* coefs;
16570  SCIP_Bool allcoefsequal;
16571 
16572  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16573  allcoefsequal = TRUE;
16574  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
16575  for( j = 0; j < nexprs; ++j )
16576  {
16577  coefs[j] = nodecoefs[childmapinv[j]];
16578  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
16579  }
16580 
16581  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16582  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16583  {
16584  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16585  exprtreecoefs[i] = coefs[0];
16586  }
16587  else
16588  {
16589  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16590  exprtreecoefs[i] = 1.0;
16591  }
16592 
16593  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16594  }
16595 
16596  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16597  }
16598 
16599  break;
16600  }
16601 
16602  case SCIP_EXPR_QUADRATIC:
16603  {
16604  SCIP_EXPR* quadexpr;
16606  SCIP_Real* lincoefs;
16607  SCIP_QUADELEM* quadelems;
16608  int nquadelems;
16609 
16610  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16611 
16612  exprtreecoefs[i] = 1.0;
16613 
16614  /* assemble coefficients corresponding to component i */
16615  if( nodedata->lincoefs != NULL )
16616  {
16617  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16618  for( j = 0; j < nexprs; ++j )
16619  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
16620  }
16621  else
16622  lincoefs = NULL;
16623 
16624  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16625  nquadelems = 0;
16626  for( j = 0; j < nodedata->nquadelems; ++j )
16627  {
16628  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16629  if( childcomp[nodedata->quadelems[j].idx1] != i )
16630  continue;
16631  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
16632  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16633  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16634  ++nquadelems;
16635  }
16636 
16637  /* put constant into first component */
16638  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16639  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16640 
16641  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16642  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16643 
16644  break;
16645  }
16646 
16647  case SCIP_EXPR_POLYNOMIAL:
16648  {
16649  SCIP_EXPR* polyexpr;
16651  SCIP_EXPRDATA_MONOMIAL** monomials;
16652  SCIP_Real constant;
16653  int nmonomials;
16654 
16655  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16656 
16657  constant = nodedata->constant;
16658  exprtreecoefs[i] = 1.0;
16659 
16660  /* collect monomials belonging to component i */
16661  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16662  nmonomials = 0;
16663  for( j = 0; j < nodedata->nmonomials; ++j )
16664  {
16665  if( nodedata->monomials[j]->nfactors == 0 )
16666  {
16667  constant += nodedata->monomials[j]->coef;
16668  continue;
16669  }
16670  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16671  continue;
16672 
16673  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16674  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
16675  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16676  {
16677  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16678  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16679  }
16680  ++nmonomials;
16681  }
16682 
16683  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16684  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16685 
16686  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16687 
16688  break;
16689  }
16690 
16691  default:
16692  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16693  return SCIP_ERROR;
16694  } /*lint !e788*/
16695 
16696  /* copy variables into expression tree */
16697  if( nexprvars > 0 )
16698  {
16699  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16700  for( j = 0; j < exprgraph->nvars; ++j )
16701  {
16702  assert(varidx[j] >= -1);
16703  assert(varidx[j] < nexprvars);
16704  if( varidx[j] >= 0 )
16705  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16706  }
16707  }
16708  }
16709 
16710  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16711  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16712  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16713  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16714  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16715 
16716  *nexprtrees = ncomponents;
16717 
16718  return SCIP_OKAY;
16719 }
16720 
16721 /** returns how often expression graph variables are used in a subtree of the expression graph */
16723  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16724  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
16725  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16726  )
16727 {
16728  assert(exprgraph != NULL);
16729  assert(node != NULL);
16730  assert(varsusage != NULL);
16731 
16732  BMSclearMemoryArray(varsusage, exprgraph->nvars);
16733 
16734  exprgraphNodeGetVarsUsage(node, varsusage);
16735 }
16736 
16737 /** gives the number of summands which the expression of an expression graph node consists of */
16739  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
16740  )
16741 {
16742  switch( node->op )
16743  {
16744  case SCIP_EXPR_PLUS:
16745  case SCIP_EXPR_MINUS:
16746  return 2;
16747 
16748  case SCIP_EXPR_SUM:
16749  case SCIP_EXPR_LINEAR:
16750  return node->nchildren;
16751 
16752  case SCIP_EXPR_QUADRATIC:
16753  {
16755 
16756  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16757  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16758  }
16759 
16760  case SCIP_EXPR_POLYNOMIAL:
16761  {
16763 
16764  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16765  return nodedata->nmonomials;
16766  }
16767 
16768  default:
16769  return 1;
16770  } /*lint !e788*/
16771 }
16772 
16773 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
16775  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16776  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16777  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16778  int* nexprtrees, /**< buffer to store number of expression trees */
16779  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16780  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16781  )
16782 {
16783  int* varidx;
16784  int nexprvars;
16785  int i;
16786 
16787  assert(exprgraph != NULL);
16788  assert(node != NULL);
16789  assert(node->depth >= 0);
16790  assert(node->pos >= 0);
16791  assert(exprtreessize > 0);
16792  assert(nexprtrees != NULL);
16793  assert(exprtrees != NULL);
16794  assert(exprtreecoefs != NULL);
16795 
16796  /* if node is not separable, fallback to SCIPexprgraphGetTree */
16797  if( node->op != SCIP_EXPR_PLUS &&
16798  node->op != SCIP_EXPR_MINUS &&
16799  node->op != SCIP_EXPR_SUM &&
16800  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16801  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16802  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16803  {
16804  *nexprtrees = 1;
16805  exprtreecoefs[0] = 1.0;
16806  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16807 
16808  return SCIP_OKAY;
16809  }
16810 
16811  switch( node->op )
16812  {
16813  case SCIP_EXPR_PLUS:
16814  {
16815  assert(exprtreessize >= 2);
16816 
16817  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16818  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16819 
16820  exprtreecoefs[0] = 1.0;
16821  exprtreecoefs[1] = 1.0;
16822 
16823  *nexprtrees = 2;
16824  break;
16825  }
16826 
16827  case SCIP_EXPR_MINUS:
16828  {
16829  assert(exprtreessize >= 2);
16830 
16831  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16832  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16833 
16834  exprtreecoefs[0] = 1.0;
16835  exprtreecoefs[1] = -1.0;
16836 
16837  *nexprtrees = 2;
16838  break;
16839  }
16840 
16841  case SCIP_EXPR_SUM:
16842  {
16843  assert(exprtreessize >= node->nchildren);
16844 
16845  for( i = 0; i < node->nchildren; ++i )
16846  {
16847  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16848  exprtreecoefs[i] = 1.0;
16849  }
16850 
16851  *nexprtrees = node->nchildren;
16852  break;
16853  }
16854 
16855  case SCIP_EXPR_LINEAR:
16856  {
16857  SCIP_Real* nodecoefs;
16858 
16859  assert(exprtreessize >= node->nchildren);
16860  assert(node->nchildren > 0);
16861 
16862  nodecoefs = (SCIP_Real*)node->data.data;
16863  assert(nodecoefs != NULL);
16864 
16865  for( i = 0; i < node->nchildren; ++i )
16866  {
16867  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16868  exprtreecoefs[i] = nodecoefs[i];
16869  }
16870 
16871  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16872  if( nodecoefs[node->nchildren] != 0.0 )
16873  {
16874  SCIP_EXPR* constexpr_;
16875 
16876  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16877  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16878  }
16879 
16880  *nexprtrees = node->nchildren;
16881  break;
16882  }
16883 
16884  case SCIP_EXPR_QUADRATIC:
16885  {
16887  SCIP_Real* lincoefs;
16888  SCIP_QUADELEM* quadelems;
16889  int nquadelems;
16890  SCIP_EXPR* expr;
16891  int j;
16892 
16893  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16894  lincoefs = nodedata->lincoefs;
16895  quadelems = nodedata->quadelems;
16896  nquadelems = nodedata->nquadelems;
16897 
16898  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16899  assert(node->nchildren > 0);
16900 
16901  *nexprtrees = 0;
16902  if( lincoefs != NULL )
16903  {
16904  for( i = 0; i < node->nchildren; ++i )
16905  {
16906  if( lincoefs[i] == 0.0 )
16907  continue;
16908  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16909  exprtreecoefs[*nexprtrees] = lincoefs[i];
16910  ++*nexprtrees;
16911  }
16912  }
16913 
16914  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16915  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16916 
16917  for( i = 0; i < nquadelems; ++i )
16918  {
16919  /* initially, no variable appears in the expression tree */
16920  for( j = 0; j < exprgraph->nvars; ++j )
16921  varidx[j] = -1; /*lint !e644*/
16922  nexprvars = 0;
16923 
16924  /* create expression from the subgraph at quadelems[i].idx1 */
16925  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16926 
16927  if( quadelems[i].idx1 == quadelems[i].idx2 )
16928  {
16929  /* create expression for square of expr */
16930  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16931  }
16932  else
16933  {
16934  SCIP_EXPR* expr2;
16935 
16936  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16937  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16938  /* create expression for product */
16939  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16940  }
16941 
16942  /* create expression tree for expr */
16943  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16944 
16945  /* copy variables into expression tree */
16946  if( nexprvars > 0 )
16947  {
16948  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16949  for( j = 0; j < exprgraph->nvars; ++j )
16950  {
16951  assert(varidx[j] >= -1);
16952  assert(varidx[j] < nexprvars);
16953  if( varidx[j] >= 0 )
16954  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16955  }
16956  }
16957 
16958  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16959 
16960  ++*nexprtrees;
16961  }
16962 
16963  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16964  if( nodedata->constant != 0.0 )
16965  {
16966  SCIP_EXPR* constexpr_;
16967 
16968  assert(*nexprtrees > 0);
16969  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16970  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16971  }
16972 
16973  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16974 
16975  break;
16976  }
16977 
16978  case SCIP_EXPR_POLYNOMIAL:
16979  {
16981  SCIP_EXPRDATA_MONOMIAL** monomials;
16982  SCIP_Real constant;
16983  int nmonomials;
16984  SCIP_EXPR* expr;
16985  int* childidxs;
16986  int j;
16987 
16988  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16989  monomials = nodedata->monomials;
16990  nmonomials = nodedata->nmonomials;
16991  constant = nodedata->constant;
16992 
16993  assert(exprtreessize >= nmonomials);
16994  assert(node->nchildren > 0);
16995 
16996  *nexprtrees = 0;
16997 
16998  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16999  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
17000 
17001  for( i = 0; i < nmonomials; ++i )
17002  {
17003  /* initially, no variable appears in the expression tree */
17004  for( j = 0; j < exprgraph->nvars; ++j )
17005  varidx[j] = -1;
17006  nexprvars = 0;
17007 
17008  if( monomials[i]->nfactors == 1 )
17009  {
17010  /* create expression from the subgraph at only factor */
17011  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17012 
17013  /* put exponent in, if not 1.0 */
17014  if( monomials[i]->exponents[0] == 1.0 )
17015  ;
17016  else if( monomials[i]->exponents[0] == 2.0 )
17017  {
17018  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
17019  }
17020  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
17021  {
17022  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
17023  }
17024  else
17025  {
17026  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
17027  }
17028  }
17029  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
17030  {
17031  SCIP_EXPR* expr2;
17032 
17033  /* create expressions for both factors */
17034  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17035  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
17036 
17037  /* create expression for product of factors */
17038  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
17039  }
17040  else
17041  {
17042  SCIP_EXPRDATA_MONOMIAL* monomial;
17043  SCIP_EXPR** exprs;
17044  int f;
17045 
17046  /* create expression for each factor, assemble varidx and nexprvars
17047  * create child indices (= identity) */
17048  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
17049  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
17050  for( f = 0; f < monomials[i]->nfactors; ++f )
17051  {
17052  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
17053  childidxs[f] = f; /*lint !e644*/
17054  }
17055 
17056  /* create monomial and polynomial expression for this monomial
17057  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
17058  */
17059  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
17060  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
17061  constant = 0.0;
17062 
17063  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
17064  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
17065  }
17066 
17067  /* create expression tree for expr */
17068  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
17069 
17070  /* copy variables into expression tree */
17071  if( nexprvars > 0 )
17072  {
17073  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
17074  for( j = 0; j < exprgraph->nvars; ++j )
17075  {
17076  assert(varidx[j] >= -1);
17077  assert(varidx[j] < nexprvars);
17078  if( varidx[j] >= 0 )
17079  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
17080  }
17081  }
17082 
17083  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
17084 
17085  ++*nexprtrees;
17086  }
17087 
17088  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
17089  if( constant != 0.0 )
17090  {
17091  SCIP_EXPR* constexpr_;
17092 
17093  assert(*nexprtrees > 0);
17094  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
17095  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
17096  }
17097 
17098  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
17099 
17100  break;
17101  }
17102 
17103  default:
17104  SCIPerrorMessage("unexpected operator type %d\n", node->op);
17105  return SCIP_ERROR;
17106  } /*lint !e788*/
17107 
17108  return SCIP_OKAY;
17109 }
17110 
17111 /**@} */
void SCIPintervalSignPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_EXPRBOUNDSTATUS_CHILDRELAXED
Definition: type_expr.h:213
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13338
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15844
void SCIPexprFreeDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6184
void SCIPexprtreeGetVarsUsage(SCIP_EXPRTREE *tree, int *varsusage)
Definition: expr.c:8908
void SCIPquadelemSort(SCIP_QUADELEM *quadelems, int nquadelems)
Definition: expr.c:9212
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15525
void SCIPexprSortMonomials(SCIP_EXPR *expr)
Definition: expr.c:7024
void SCIPintervalSubScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define exprcurvSin
Definition: expr.c:2078
#define QUADELEMS_SWAP(x, y)
Definition: expr.c:9093
void SCIPintervalMax(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:457
#define NULL
Definition: def.h:253
SCIP_EXPROPDATA data
Definition: struct_expr.h:51
static void exprgraphSortConstNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:9652
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14980
static SCIP_RETCODE exprgraphNodeAddParent(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9345
SCIP_RETCODE SCIPexprSubstituteVars(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR **substexprs)
Definition: expr.c:8146
static SCIP_RETCODE exprsimplifyConvertToPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4266
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:15180
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2364
void SCIPintervalSign(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define QUADELEMS_ISBETTER(a, b)
Definition: expr.c:9090
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:4290
SCIP_RETCODE SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16774
SCIP_RETCODE SCIPexprtreeEvalInt(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_INTERVAL *val)
Definition: expr.c:8740
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:15264
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:138
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:8757
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5921
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:14769
static SCIP_RETCODE polynomialdataMultiplyByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:955
static SCIP_RETCODE exprUnconvertPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren, void **children)
Definition: expr.c:3762
SCIP_Bool constssorted
Definition: struct_expr.h:174
static SCIP_RETCODE doCheckCurvature(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_INTERVAL *childbounds, SCIP_Real *param, SCIP_EXPRCURV *curv, SCIP_EXPRCURV *childcurv, SCIP_INTERVAL *bounds)
Definition: expr.c:8027
static SCIP_RETCODE exprgraphNodeAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nexprs, SCIP_EXPRGRAPHNODE **exprs, int *childmap)
Definition: expr.c:9482
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12974
static SCIP_RETCODE exprgraphNodeCreateExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPR **expr, int *nexprvars, int *varidx)
Definition: expr.c:11790
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5694
SCIP_EXPORT SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
#define infinity
Definition: gastrans.c:71
struct SCIP_UserExprData SCIP_USEREXPRDATA
Definition: type_expr.h:221
void SCIPexprPrint(SCIP_EXPR *expr, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, const char **paramnames, SCIP_Real *paramvals)
Definition: expr.c:8226
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14950
static SCIP_RETCODE exprgraphEnsureDepth(SCIP_EXPRGRAPH *exprgraph, int mindepth)
Definition: expr.c:12063
#define SCIP_MAXSTRLEN
Definition: def.h:274
static void polynomialdataSortMonomials(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata)
Definition: expr.c:800
static SCIP_RETCODE exprgraphNodeSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange)
Definition: expr.c:11460
#define SCIP_VARTYPE_INTEGER_CHAR
Definition: def.h:136
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
SCIP_Real * exponents
Definition: struct_expr.h:95
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2425
#define SCIP_DECL_USEREXPREVAL(x)
Definition: type_expr.h:248
#define SCIP_DECL_USEREXPRPRINT(x)
Definition: type_expr.h:310
int SCIPexprgraphGetDepth(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14920
static SCIP_RETCODE polynomialdataMultiplyByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *factordata, int *childmap)
Definition: expr.c:999
static SCIP_RETCODE exprparseFindSeparatingComma(const char *str, const char **endptr, int length)
Definition: expr.c:5065
static SCIP_RETCODE exprgraphNodeRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11391
const char * SCIPexpropGetName(SCIP_EXPROP op)
Definition: expr.c:3264
void SCIPexprChgPolynomialConstant(SCIP_EXPR *expr, SCIP_Real constant)
Definition: expr.c:6690
SCIP_RETCODE SCIPexprgraphAddConst(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15337
SCIP_RETCODE SCIPexprtreeGetMaxDegree(SCIP_EXPRTREE *tree, int *maxdegree)
Definition: expr.c:8711
SCIP_Real * SCIPexprtreeGetParamVals(SCIP_EXPRTREE *tree)
Definition: expr.c:8633
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:15024
SCIP_RETCODE SCIPexprCreateMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial, SCIP_Real coef, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:7036
static SCIP_DECL_SORTPTRCOMP(exprgraphnodecomp)
Definition: expr.c:126
void SCIPexprgraphCaptureNode(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12952
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:13467
static SCIP_DECL_EXPRFREEDATA(exprFreeDataLinear)
Definition: expr.c:2541
SCIP_Real SCIPexprGetRealPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5757
SCIP_EXPROP op
Definition: struct_expr.h:48
int SCIPexprGetOpIndex(SCIP_EXPR *expr)
Definition: expr.c:5724
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3009
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:7796
SCIP_RETCODE SCIPexprPolynomialPower(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int exponent)
Definition: expr.c:6786
void SCIPexprChgMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real newcoef)
Definition: expr.c:6852
SCIP_Bool SCIPexprHasParam(SCIP_EXPR *expr)
Definition: expr.c:7214
SCIPInterval cos(const SCIPInterval &x)
SCIP_Real SCIPexprGetPolynomialConstant(SCIP_EXPR *expr)
Definition: expr.c:5889
SCIP_EXPRBOUNDSTATUS boundstatus
Definition: struct_expr.h:138
void SCIPintervalSetRoundingMode(SCIP_ROUNDMODE roundmode)
void SCIPexprgraphPropagateNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:15898
#define FALSE
Definition: def.h:73
void SCIPintervalMul(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define EPSEQ(x, y, eps)
Definition: def.h:189
#define EPSISINT(x, eps)
Definition: def.h:201
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT
Definition: type_expr.h:214
SCIP_Bool SCIPexprAreEqual(SCIP_EXPR *expr1, SCIP_EXPR *expr2, SCIP_Real eps)
Definition: expr.c:7581
void SCIPexprMonomialPower(SCIP_EXPRDATA_MONOMIAL *monomial, int exponent)
Definition: expr.c:6927
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14970
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:9640
static void exprgraphNodeCheckSeparabilityComponent(SCIP_EXPRGRAPHNODE *node, int *compnr, int nchildcomps, int *childcomps, int nvars, int *varcomps)
Definition: expr.c:12002
static SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11333
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13103
#define TRUE
Definition: def.h:72
#define SCIPdebug(x)
Definition: pub_message.h:74
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static int calcGrowSize(int num)
Definition: expr.c:106
static SCIP_RETCODE exprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op, int nchildren, SCIP_EXPR **children, SCIP_EXPROPDATA opdata)
Definition: expr.c:3293
SCIP_RETCODE SCIPexprtreeCopy(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **targettree, SCIP_EXPRTREE *sourcetree)
Definition: expr.c:8813
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12994
void SCIPexprGetVarsUsage(SCIP_EXPR *expr, int *varsusage)
Definition: expr.c:7558
void SCIPintervalMin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_INTERVAL SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13328
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15823
void SCIPexprReindexVars(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8184
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
#define SCIP_DECL_USEREXPRINTEVAL(x)
Definition: type_expr.h:261
void SCIPintervalPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int * SCIPexprgraphGetNNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14930
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:113
SCIP_RETCODE SCIPexprEvalInt(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7928
#define EPSGE(x, y, eps)
Definition: def.h:193
SCIP_EXPORT void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPexprSortMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:7117
static void polynomialdataApplyChildmap(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int *childmap)
Definition: expr.c:1159
#define SCIPdebugMessage
Definition: pub_message.h:77
static SCIP_DECL_EXPRCURV(exprcurvDefault)
Definition: expr.c:1419
SCIP_EXPRDATA_MONOMIAL ** monomials
Definition: struct_expr.h:80
static struct exprOpTableElement exprOpTable[]
Definition: expr.c:3217
#define SIGN(x)
Definition: expr.c:46
#define BMSduplicateBlockMemory(mem, ptr, source)
Definition: memory.h:449
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15384
SCIP_RETCODE SCIPexprMultiplyMonomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6892
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8772
SCIP_Bool SCIPquadelemSortedFind(SCIP_QUADELEM *quadelems, int idx1, int idx2, int nquadelems, int *pos)
Definition: expr.c:9237
unsigned int SCIP_EXPRINTCAPABILITY
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8643
BMS_BLKMEM * blkmem
Definition: struct_expr.h:157
SCIP_EXPRCURV curv
Definition: struct_expr.h:144
SCIP_EXPR * root
Definition: struct_expr.h:58
#define exprevalIntTan
Definition: expr.c:2121
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:15131
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13197
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:10023
real eps
#define SCIP_EXPRESSION_MAXCHILDEST
Definition: expr.c:40
static void exprgraphUpdateVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Bool *clearreverseprop, SCIP_Bool *boundchanged)
Definition: expr.c:12839
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:14403
SCIP_EXPRCURV SCIPexprcurvMonomial(int nfactors, SCIP_Real *exponents, int *factoridxs, SCIP_EXPRCURV *factorcurv, SCIP_INTERVAL *factorbounds)
Definition: expr.c:361
SCIP_EXPRDATA_MONOMIAL ** SCIPexprGetMonomials(SCIP_EXPR *expr)
Definition: expr.c:5865
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:2113
static SCIP_DECL_EXPREVAL(exprevalVar)
Definition: expr.c:1428
SCIP_EXPORT void SCIPsortPtrPtrRealInt(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
public methods for expressions, expression trees, expression graphs, and related stuff ...
SCIP_EXPRCURV SCIPexprcurvMultiply(SCIP_Real factor, SCIP_EXPRCURV curvature)
Definition: expr.c:240
int SCIPexprGetMonomialNFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5911
int SCIPexprGetIntPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5768
void SCIPintervalSin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3098
#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:9011
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13034
static SCIP_RETCODE exprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op, SCIP_EXPROPDATA opdata)
Definition: expr.c:9723
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13185
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:15092
#define SCIP_ALLOC_ABORT(x)
Definition: def.h:355
#define SCIP_DECL_EXPRGRAPHVARADDED(x)
Definition: type_expr.h:183
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3240
SCIP_HASHMAP * varidxs
Definition: struct_expr.h:169
int SCIPexprgraphGetNodeOperatorIndex(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13044
static SCIP_RETCODE exprparseReadVariable(BMS_BLKMEM *blkmem, const char **str, SCIP_EXPR **expr, int *nvars, int **varnames, int *varnameslength, SCIP_HASHTABLE *vartable, SCIP_Real coefficient, const char *varnameendptr)
Definition: expr.c:4925
SCIP_Real coef
Definition: type_expr.h:104
SCIP_Real inf
Definition: intervalarith.h:39
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10571
const char * SCIPexprcurvGetName(SCIP_EXPRCURV curv)
Definition: expr.c:474
static const NodeData nodedata[]
Definition: gastrans.c:74
SCIP_Real SCIPexprgraphGetNodeLinearConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13125
#define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize)
Definition: expr.c:87
SCIP_Real * params
Definition: struct_expr.h:62
#define BMSduplicateBlockMemoryArray(mem, ptr, source, num)
Definition: memory.h:451
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13209
SCIP_RETCODE SCIPexprAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:6668
SCIP_Bool SCIPexprgraphHasNodeNonlinearAncestor(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14654
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13348
SCIP_Bool simplified
Definition: struct_expr.h:148
SCIP_RETCODE SCIPexprCreateQuadratic(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real constant, SCIP_Real *lincoefs, int nquadelems, SCIP_QUADELEM *quadelems)
Definition: expr.c:6585
SCIP_Bool SCIPexprgraphFindConstNode(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15726
int SCIPstrncpy(char *t, const char *s, int size)
Definition: misc.c:10306
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:7867
void SCIPexprgraphSetVarsBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_INTERVAL *varbounds)
Definition: expr.c:14992
union SCIP_ExprOpData SCIP_EXPROPDATA
Definition: type_expr.h:92
static SCIP_Bool isUbBetter(SCIP_Real minstrength, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:169
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:137
SCIP_RETCODE SCIPexprgraphCheckCurvature(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop)
Definition: expr.c:15930
SCIP_RETCODE SCIPexprGetMaxDegree(SCIP_EXPR *expr, int *maxdegree)
Definition: expr.c:7233
static void polynomialdataMultiplyByConstant(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_Real factor)
Definition: expr.c:925
#define SCIPerrorMessage
Definition: pub_message.h:45
enum SCIP_ExprOp SCIP_EXPROP
Definition: type_expr.h:91
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10364
interval arithmetics for provable bounds
#define SCIPdebugPrintf
Definition: pub_message.h:80
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_RETCODE SCIPexprgraphCreateNodeUser(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_USEREXPRDATA *data, SCIP_EXPRINTCAPABILITY evalcapability, SCIP_DECL_USEREXPREVAL((*eval)), SCIP_DECL_USEREXPRINTEVAL((*inteval)), SCIP_DECL_USEREXPRCURV((*curv)), SCIP_DECL_USEREXPRPROP((*prop)), SCIP_DECL_USEREXPRESTIMATE((*estimate)), SCIP_DECL_USEREXPRCOPYDATA((*copydata)), SCIP_DECL_USEREXPRFREEDATA((*freedata)), SCIP_DECL_USEREXPRPRINT((*print)))
Definition: expr.c:13537
SCIP_Real * SCIPexprGetQuadLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5841
SCIP_EXPRGRAPHNODE *** SCIPexprgraphGetNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14940
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16738
SCIP_INTERVAL bounds
Definition: struct_expr.h:137
static SCIP_RETCODE exprsimplifyRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4344
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:6142
static const char * curvnames[4]
Definition: expr.c:194
SCIPInterval sqrt(const SCIPInterval &x)
SCIP_Bool SCIPexprgraphHasNodeUserEstimator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13316
static SCIP_DECL_EXPRCOPYDATA(exprCopyDataLinear)
Definition: expr.c:2523
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, int *varnameslength, SCIP_HASHTABLE *vartable, int recursiondepth)
Definition: expr.c:5097
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:490
SCIPInterval sign(const SCIPInterval &x)
SCIP_EXPRCURV SCIPexprcurvPower(SCIP_INTERVAL basebounds, SCIP_EXPRCURV basecurv, SCIP_Real exponent)
Definition: expr.c:253
void print(const Container &container, const std::string &prefix="", const std::string &suffix="", std::ostream &os=std::cout, bool negate=false, int prec=6)
SCIP_Real SCIPexprGetQuadConstant(SCIP_EXPR *expr)
Definition: expr.c:5828
static SCIP_RETCODE exprgraphNodeReplaceChild(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE **oldchild, SCIP_EXPRGRAPHNODE *newchild)
Definition: expr.c:9583
void SCIPmessagePrintWarning(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:417
SCIP_EXPRGRAPHNODE *** nodes
Definition: struct_expr.h:162
SCIP_EXPORT SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
#define EXPROPEMPTY
Definition: expr.c:3213
internal miscellaneous methods
void SCIPrandomFree(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem)
Definition: misc.c:9602
static SCIP_Bool exprgraphNodeIsParent(SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9451
static void polynomialdataFree(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata)
Definition: expr.c:712
#define REALABS(x)
Definition: def.h:188
void SCIPexprMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:6806
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:8613
SCIP_Bool SCIPexprAreMonomialsEqual(SCIP_EXPRDATA_MONOMIAL *monomial1, SCIP_EXPRDATA_MONOMIAL *monomial2, SCIP_Real eps)
Definition: expr.c:6821
SCIP_EXPORT void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_EXPRGRAPHNODE ** varnodes
Definition: struct_expr.h:167
SCIP_RETCODE SCIPexprgraphCreateNodeLinear(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int ncoefs, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:13441
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16288
#define SCIP_CALL(x)
Definition: def.h:365
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12964
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:15084
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:6633
SCIP_RETCODE SCIPexprCheckCurvature(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_Real *param, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:8063
SCIP_VAR * h
Definition: circlepacking.c:59
SCIP_RETCODE SCIPexprEvalUser(SCIP_EXPR *expr, SCIP_Real *argvals, SCIP_Real *val, SCIP_Real *gradient, SCIP_Real *hessian)
Definition: expr.c:7970
SCIP_Real sup
Definition: intervalarith.h:40
void SCIPmessagePrintInfo(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:584
SCIP_RETCODE SCIPexprEvalShallow(SCIP_EXPR *expr, SCIP_Real *argvals, SCIP_Real *varvals, SCIP_Real *param, SCIP_Real *val)
Definition: expr.c:7848
void SCIPexprMultiplyPolynomialByConstant(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real factor)
Definition: expr.c:6703
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:14707
static SCIP_RETCODE exprsimplifyUnconvertPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4891
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:8108
static SCIP_RETCODE exprgraphNodeUpdateBounds(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool parenttightenisinvalid)
Definition: expr.c:10130
#define SCIP_DECL_USEREXPRCURV(x)
Definition: type_expr.h:272
void SCIPexprFreeMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial)
Definition: expr.c:7093
SCIP_EXPORT void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPexprMulConstant(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPR *term, SCIP_Real factor)
Definition: expr.c:6405
SCIP_EXPR * SCIPexprtreeGetRoot(SCIP_EXPRTREE *tree)
Definition: expr.c:8603
SCIP_RETCODE SCIPexprCreateUser(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_USEREXPRDATA *data, SCIP_EXPRINTCAPABILITY evalcapability, SCIP_DECL_USEREXPREVAL((*eval)), SCIP_DECL_USEREXPRINTEVAL((*inteval)), SCIP_DECL_USEREXPRCURV((*curv)), SCIP_DECL_USEREXPRPROP((*prop)), SCIP_DECL_USEREXPRESTIMATE((*estimate)), SCIP_DECL_USEREXPRCOPYDATA((*copydata)), SCIP_DECL_USEREXPRFREEDATA((*freedata)), SCIP_DECL_USEREXPRPRINT((*print)))
Definition: expr.c:7154
SCIP_Bool SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14619
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:13224
#define SCIP_DECL_USEREXPRESTIMATE(x)
Definition: type_expr.h:236
#define SCIP_DECL_USEREXPRPROP(x)
Definition: type_expr.h:284
SCIP_Real SCIPexprgraphGetNodeOperatorReal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13055
#define SCIP_EXPRBOUNDSTATUS_VALID
Definition: type_expr.h:211
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:6247
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13137
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:454
SCIP_RETCODE SCIPexprMultiplyPolynomialByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR *factor, int *childmap)
Definition: expr.c:6740
void SCIPexprMergeMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real eps)
Definition: expr.c:6957
void SCIPintervalCos(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_EXPRINTCAPABILITY SCIPexprGetUserEvalCapability(SCIP_EXPR *expr)
Definition: expr.c:5963
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:833
SCIP_EXPORT void SCIPsortPtrRealInt(void **ptrarray, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:5714
SCIP_Real SCIPexprGetSignPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5779
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2163
SCIP_EXPRGRAPHNODE ** children
Definition: struct_expr.h:128
#define SCIP_Bool
Definition: def.h:70
void ** vars
Definition: struct_expr.h:60
SCIP_Bool needvarboundprop
Definition: struct_expr.h:181
static SCIP_RETCODE exprgraphNodeEval(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:10065
SCIP_USEREXPRDATA * userdata
Definition: struct_expr.h:103
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14638
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds)
SCIPInterval sin(const SCIPInterval &x)
#define BMSallocBlockMemoryArray(mem, ptr, num)
Definition: memory.h:443
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2891
void SCIPexprSortQuadElems(SCIP_EXPR *expr)
Definition: expr.c:6621
static SCIP_RETCODE monomialdataEnsureFactorsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomialdata, int minsize)
Definition: expr.c:603
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:15044
SCIP_EXPORT SCIP_RETCODE SCIPexprintFreeData(SCIP_EXPRINTDATA **interpreterdata)
static SCIP_RETCODE exprsimplifyFlattenPolynomials(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR *expr, SCIP_Real eps, int maxexpansionexponent)
Definition: expr.c:4461
static SCIP_RETCODE exprgraphNodeRemoveParent(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9400
BMS_BLKMEM * blkmem
Definition: struct_expr.h:57
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8658
SCIP_RETCODE SCIPexprtreeFreeInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8681
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:456
void SCIPquadelemSqueeze(SCIP_QUADELEM *quadelems, int nquadelems, int *nquadelemsnew)
Definition: expr.c:9289
SCIP_Bool SCIPexprHasUserEstimator(SCIP_EXPR *expr)
Definition: expr.c:5952
void SCIPintervalSquareRoot(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
void SCIPintervalQuadBivar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
SCIP_EXPR ** children
Definition: struct_expr.h:50
SCIP_INTERVAL * varbounds
Definition: struct_expr.h:168
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:5704
#define MIN(x, y)
Definition: def.h:223
SCIP_EXPORT void SCIPsortIntReal(int *intarray, SCIP_Real *realarray, int len)
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:16722
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:15064
static SCIP_Bool exprgraphFindConstNodePos(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *pos)
Definition: expr.c:9668
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:13591
SCIP_RETCODE SCIPexprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op,...)
Definition: expr.c:5974
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:8853
SCIP_Bool SCIPexprFindMonomialFactor(SCIP_EXPRDATA_MONOMIAL *monomial, int childidx, int *pos)
Definition: expr.c:7137
static SCIP_DECL_EXPRINTEVAL(exprevalIntDefault)
Definition: expr.c:1410
#define EPSLE(x, y, eps)
Definition: def.h:191
void SCIPexprgraphFreeNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14529
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:10224
#define SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED
Definition: type_expr.h:212
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14581
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:124
SCIPInterval log(const SCIPInterval &x)
SCIP_USEREXPRDATA * SCIPexprGetUserData(SCIP_EXPR *expr)
Definition: expr.c:5941
SCIP_RETCODE SCIPexprtreeAddExpr(SCIP_EXPRTREE *tree, SCIP_EXPR *expr, SCIP_Bool copyexpr)
Definition: expr.c:8982
#define SCIP_EXPR_DEGREEINFINITY
Definition: type_expr.h:116
SCIP_EXPROPDATA data
Definition: struct_expr.h:120
SCIP_EXPRGRAPHNODE ** parents
Definition: struct_expr.h:133
static long * number
void SCIPintervalAbs(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define BMSclearMemory(ptr)
Definition: memory.h:119
SCIP_Real SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5901
static SCIP_RETCODE polynomialdataCopy(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *sourcepolynomialdata)
Definition: expr.c:675
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:1188
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13066
void * SCIPexprGetOpData(SCIP_EXPR *expr)
Definition: expr.c:5746
SCIP_EXPROP op
Definition: struct_expr.h:119
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13149
#define SCIP_REAL_MAX
Definition: def.h:165
static SCIP_RETCODE exprConvertToPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren)
Definition: expr.c:3324
SCIP_RETCODE SCIPexprEvalIntUser(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *val, SCIP_INTERVAL *gradient, SCIP_INTERVAL *hessian)
Definition: expr.c:7993
int SCIPexprgraphGetNodeIntPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13092
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13004
SCIP_QUADELEM * quadelems
Definition: struct_expr.h:71
static void exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:9374
#define EPSLT(x, y, eps)
Definition: def.h:190
#define SCIP_DECL_EXPRGRAPHVARREMOVE(x)
Definition: type_expr.h:193
static SCIP_RETCODE exprgraphAddExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPR *expr, void **vars, SCIP_Real *params, SCIP_EXPRGRAPHNODE **exprnode, SCIP_Bool *exprnodeisnew)
Definition: expr.c:12707
static SCIP_RETCODE polynomialdataAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:758
#define EPSGT(x, y, eps)
Definition: def.h:192
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:95
SCIP_VAR ** b
Definition: circlepacking.c:56
int SCIPexpropGetNChildren(SCIP_EXPROP op)
Definition: expr.c:3274
static void quadraticdataSort(SCIP_EXPRDATA_QUADRATIC *quadraticdata)
Definition: expr.c:528
#define SCIP_VARTYPE_IMPLINT_CHAR
Definition: def.h:137
SCIP_EXPRINTDATA * interpreterdata
Definition: struct_expr.h:63
#define exprcurvCos
Definition: expr.c:2106
#define MAX(x, y)
Definition: def.h:222
SCIP_Bool SCIPexprgraphFindVarNode(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_EXPRGRAPHNODE **varnode)
Definition: expr.c:15697
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8205
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13114
#define SCIP_EXPRINTCAPABILITY_FUNCVALUE
SCIP_Real * SCIPexprGetLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5790
SCIP_Bool SCIPexprtreeHasParam(SCIP_EXPRTREE *tree)
Definition: expr.c:8695
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Real SCIPexprGetOpReal(SCIP_EXPR *expr)
Definition: expr.c:5735
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13024
static SCIP_Bool isLbBetter(SCIP_Real minstrength, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:149
SCIP_RETCODE SCIPexprgraphNodePolynomialAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:13518
SCIP_Bool parentssorted
Definition: struct_expr.h:134
#define SCIP_VARTYPE_CONTINUOUS_CHAR
Definition: def.h:138
SCIP_EXPRGRAPHNODE ** constnodes
Definition: struct_expr.h:173
void SCIPexprFreeShallow(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6222
SCIP_QUADELEM * SCIPexprGetQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5816
SCIP_RETCODE SCIPexprgraphCreateNodePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:13493
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:13304
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:4790
SCIP_RETCODE SCIPexprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op,...)
Definition: expr.c:13358
SCIP_RETCODE SCIPexprEvalIntShallow(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7908
SCIP_RETCODE SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14435
int SCIPexprGetNMonomials(SCIP_EXPR *expr)
Definition: expr.c:5877
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE
Definition: type_expr.h:216
SCIP_VAR * a
Definition: circlepacking.c:57
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10263
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:608
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2925
SCIP_RETCODE SCIPexprtreeSimplify(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:8927
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:16235
#define SCIP_DECL_USEREXPRCOPYDATA(x)
Definition: type_expr.h:293
#define SCIP_Real
Definition: def.h:164
#define EPSROUND(x, eps)
Definition: def.h:199
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:628
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_CALL_TERMINATE(retcode, x, TERM)
Definition: def.h:386
SCIP_RETCODE SCIPrandomCreate(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem, unsigned int initialseed)
Definition: misc.c:9586
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12984
#define SCIP_INVALID
Definition: def.h:184
SCIP_RETCODE SCIPexprAddMonomialFactors(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:6863
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5931
void SCIPexprgraphPrintNode(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: expr.c:14691
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:9046
SCIP_RETCODE SCIPexprParse(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR **expr, const char *str, const char *lastchar, int *nvars, int *varnames, int varnameslength)
Definition: expr.c:8539
#define SCIPisFinite(x)
Definition: pub_misc.h:1826
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:10109
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:135
int SCIPexprtreeGetNParams(SCIP_EXPRTREE *tree)
Definition: expr.c:8623
SCIP_RETCODE SCIPexprgraphSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange, SCIP_Bool *domainerror)
Definition: expr.c:15973
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
static SCIP_RETCODE exprsimplifyRemovePolynomialUnusedChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4410
#define exprcurvTan
Definition: expr.c:2124
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:12143
static SCIP_RETCODE exprparseFindClosingParenthesis(const char *str, const char **endptr, int length)
Definition: expr.c:5026
SCIP_RETCODE SCIPexprAddToLinear(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nchildren, SCIP_Real *coefs, SCIP_EXPR **children, SCIP_Real constant)
Definition: expr.c:6540
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:4147
#define nnodes
Definition: gastrans.c:65
SCIP_EXPORT void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:441
SCIP_RETCODE SCIPexprMultiplyPolynomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6717
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13081
#define EPSFLOOR(x, eps)
Definition: def.h:197
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:120
static SCIP_DECL_HASHGETKEY(exprparseVarTableGetKey)
Definition: expr.c:4915
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:427
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13173
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:10333
#define SCIP_ALLOC_TERMINATE(retcode, x, TERM)
Definition: def.h:396
static SCIP_RETCODE polynomialdataPower(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int exponent)
Definition: expr.c:1089
#define SCIP_CALL_ABORT(x)
Definition: def.h:344
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14960
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT
Definition: type_expr.h:215
SCIP_RETCODE SCIPexprCreateLinear(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:6503
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_ALLOC(x)
Definition: def.h:376
#define SCIPABORT()
Definition: def.h:337
SCIP_Real SCIPexprGetLinearConstant(SCIP_EXPR *expr)
Definition: expr.c:5803
void SCIPexprtreeSetInterpreterData(SCIP_EXPRTREE *tree, SCIP_EXPRINTDATA *interpreterdata)
Definition: expr.c:8668
SCIP_EXPRCURV SCIPexprcurvAdd(SCIP_EXPRCURV curv1, SCIP_EXPRCURV curv2)
Definition: expr.c:205
struct SCIP_ExprIntData SCIP_EXPRINTDATA
static void quadelemsQuickSort(SCIP_QUADELEM *elems, int start, int end)
Definition: expr.c:9102
static SCIP_RETCODE polynomialdataEnsureMonomialsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int minsize)
Definition: expr.c:741
SCIP_RETCODE SCIPexprtreeSetParams(SCIP_EXPRTREE *tree, int nparams, SCIP_Real *paramvals)
Definition: expr.c:8877
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
int SCIPexprGetNQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5853
static void exprgraphPrintNodeExpression(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, SCIP_Bool printchildrenbounds)
Definition: expr.c:9767
#define SCIP_DECL_USEREXPRFREEDATA(x)
Definition: type_expr.h:301
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:12239
static void exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:11977
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15774
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3256
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:447
void SCIPintervalSetRoundingModeDownwards(void)
#define EPSZ(x, eps)
Definition: def.h:194
#define ABS(x)
Definition: def.h:218
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:13014
#define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize)
Definition: expr.c:52
SCIP_EXPRCURV SCIPexprcurvNegate(SCIP_EXPRCURV curvature)
Definition: expr.c:214
SCIP_RETCODE SCIPexprtreeEval(SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
Definition: expr.c:8724
SCIP_EXPRINTCAPABILITY evalcapability
Definition: struct_expr.h:104
void SCIPexprgraphSetVarBounds(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_INTERVAL varbounds)
Definition: expr.c:15004
static SCIP_RETCODE exprgraphRemoveVar(SCIP_EXPRGRAPH *exprgraph, int varidx)
Definition: expr.c:12090
SCIP_EXPORT void SCIPsortPtrPtrInt(void **ptrarray1, void **ptrarray2, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_DECL_EXPRGRAPHVARCHGIDX(x)
Definition: type_expr.h:205
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:14554
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3174
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13161