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-2018 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 
1021  if( factordata->nmonomials == 1 && factordata->constant == 0.0 )
1022  {
1023  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, polynomialdata, factordata->monomials[0], childmap) );
1024  return SCIP_OKAY;
1025  }
1026 
1027  /* turn constant into a monomial, so we can assume below that constant is 0.0 */
1028  if( polynomialdata->constant != 0.0 )
1029  {
1030  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
1031  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
1032  ++polynomialdata->nmonomials;
1033  polynomialdata->sorted = FALSE;
1034  polynomialdata->constant = 0.0;
1035  }
1036 
1037  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials * (factordata->nmonomials + (factordata->constant == 0.0 ? 0 : 1))) );
1038 
1039  /* for each monomial in factordata (except the last, if factordata->constant is 0),
1040  * duplicate monomials from polynomialdata and multiply them by the monomial for factordata */
1041  orignmonomials = polynomialdata->nmonomials;
1042  for( i2 = 0; i2 < factordata->nmonomials; ++i2 )
1043  {
1044  /* add a copy of original monomials to end of polynomialdata's monomials array */
1045  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 */
1046  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, orignmonomials, polynomialdata->monomials, TRUE) );
1047  assert(polynomialdata->nmonomials == (i2+2) * orignmonomials);
1048 
1049  /* multiply each copied monomial by current monomial from factordata */
1050  for( i1 = (i2+1) * orignmonomials; i1 < (i2+2) * orignmonomials; ++i1 )
1051  {
1052  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1053  }
1054 
1055  if( factordata->constant == 0.0 && i2 == factordata->nmonomials - 2 )
1056  {
1057  ++i2;
1058  break;
1059  }
1060  }
1061 
1062  if( factordata->constant != 0.0 )
1063  {
1064  assert(i2 == factordata->nmonomials);
1065  /* multiply original monomials in polynomialdata by constant in factordata */
1066  for( i1 = 0; i1 < orignmonomials; ++i1 )
1067  SCIPexprChgMonomialCoef(polynomialdata->monomials[i1], polynomialdata->monomials[i1]->coef * factordata->constant);
1068  }
1069  else
1070  {
1071  assert(i2 == factordata->nmonomials - 1);
1072  /* multiply original monomials in polynomialdata by last monomial in factordata */
1073  for( i1 = 0; i1 < orignmonomials; ++i1 )
1074  {
1075  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1076  }
1077  }
1078 
1079  return SCIP_OKAY;
1080 }
1081 
1082 /** takes a power of a polynomial
1083  *
1084  * Exponent needs to be an integer,
1085  * polynomial needs to be a monomial, if exponent is negative.
1086  */
1087 static
1089  BMS_BLKMEM* blkmem, /**< block memory */
1090  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1091  int exponent /**< exponent of power operation */
1092  )
1093 {
1094  SCIP_EXPRDATA_POLYNOMIAL* factor;
1095  int i;
1096 
1097  assert(blkmem != NULL);
1098  assert(polynomialdata != NULL);
1099 
1100  if( exponent == 0 )
1101  {
1102  /* x^0 = 1, except if x = 0 */
1103  if( polynomialdata->nmonomials == 0 && polynomialdata->constant == 0.0 )
1104  {
1105  polynomialdata->constant = 0.0;
1106  }
1107  else
1108  {
1109  polynomialdata->constant = 1.0;
1110 
1111  for( i = 0; i < polynomialdata->nmonomials; ++i )
1112  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
1113  polynomialdata->nmonomials = 0;
1114  }
1115 
1116  return SCIP_OKAY;
1117  }
1118 
1119  if( exponent == 1 )
1120  return SCIP_OKAY;
1121 
1122  if( polynomialdata->nmonomials == 1 && polynomialdata->constant == 0.0 )
1123  {
1124  /* polynomial is a single monomial */
1125  SCIPexprMonomialPower(polynomialdata->monomials[0], exponent);
1126  return SCIP_OKAY;
1127  }
1128 
1129  if( polynomialdata->nmonomials == 0 )
1130  {
1131  /* polynomial is a constant */
1132  polynomialdata->constant = pow(polynomialdata->constant, (SCIP_Real)exponent);
1133  return SCIP_OKAY;
1134  }
1135 
1136  assert(exponent >= 2); /* negative exponents not allowed if more than one monom */
1137 
1138  /* todo improve, look how SCIPintervalPowerScalar in intervalarith.c does it */
1139 
1140  /* get copy of our polynomial */
1141  SCIP_CALL( polynomialdataCopy(blkmem, &factor, polynomialdata) );
1142 
1143  /* do repeated multiplication */
1144  for( i = 2; i <= exponent; ++i )
1145  {
1146  SCIP_CALL( polynomialdataMultiplyByPolynomial(blkmem, polynomialdata, factor, NULL) );
1147  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
1148  }
1149 
1150  /* free copy again */
1151  polynomialdataFree(blkmem, &factor);
1152 
1153  return SCIP_OKAY;
1154 }
1155 
1156 /** applies a mapping of child indices to the indices used in polynomial monomials */
1157 static
1159  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1160  int* childmap /**< mapping of child indices */
1161  )
1162 {
1163  SCIP_EXPRDATA_MONOMIAL* monomial;
1164  int i;
1165  int j;
1166 
1167  assert(polynomialdata != NULL);
1168 
1169  for( i = 0; i < polynomialdata->nmonomials; ++i )
1170  {
1171  monomial = polynomialdata->monomials[i];
1172  assert(monomial != NULL);
1173 
1174  for( j = 0; j < monomial->nfactors; ++j )
1175  {
1176  monomial->childidxs[j] = childmap[monomial->childidxs[j]];
1177  assert(monomial->childidxs[j] >= 0);
1178  }
1179  monomial->sorted = FALSE;
1180  }
1181 
1182  polynomialdata->sorted = FALSE;
1183 }
1184 
1185 /** replaces a factor in a monomial by a polynomial and expands the result */
1186 static
1188  BMS_BLKMEM* blkmem, /**< block memory data structure */
1189  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1190  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data where to expand a monomial */
1191  int monomialpos, /**< position of monomial which factor to expand */
1192  int factorpos, /**< position of factor in monomial to expand */
1193  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomial,/**< polynomial that should replace factor */
1194  int* childmap, /**< map of child indices in factorpolynomial to children of polynomial */
1195  int maxexpansionexponent,/**< maximal exponent for which polynomials (with > 1 summands) are expanded */
1196  SCIP_Bool* success /**< buffer to store whether expansion has been done */
1197  )
1198 {
1199  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomialcopy;
1200  SCIP_EXPRDATA_MONOMIAL* monomial;
1201  int i;
1202 
1203  assert(blkmem != NULL);
1204  assert(polynomialdata != NULL);
1205  assert(factorpolynomial != NULL);
1206  assert(childmap != NULL || factorpolynomial->nmonomials == 0);
1207  assert(success != NULL);
1208  assert(monomialpos >= 0);
1209  assert(monomialpos < polynomialdata->nmonomials);
1210  assert(factorpos >= 0);
1211 
1212  monomial = polynomialdata->monomials[monomialpos];
1213  assert(monomial != NULL);
1214  assert(factorpos < monomial->nfactors);
1215 
1216  *success = TRUE;
1217 
1218  if( factorpolynomial->nmonomials == 0 )
1219  {
1220  /* factorpolynomial is a constant */
1221 
1222  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && factorpolynomial->constant < 0.0 ) /*lint !e835*/
1223  {
1224  /* if polynomial is a negative constant and our exponent is not integer, then cannot do expansion */
1225  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", factorpolynomial->constant, monomial->exponents[factorpos]);
1226  *success = FALSE;
1227  return SCIP_OKAY;
1228  }
1229  monomial->coef *= pow(factorpolynomial->constant, monomial->exponents[factorpos]);
1230 
1231  /* move last factor to position factorpos */
1232  if( factorpos < monomial->nfactors-1 )
1233  {
1234  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1235  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1236  }
1237  --monomial->nfactors;
1238  monomial->sorted = FALSE;
1239  polynomialdata->sorted = FALSE;
1240 
1241  return SCIP_OKAY;
1242  }
1243 
1244  if( factorpolynomial->constant == 0.0 && factorpolynomial->nmonomials == 1 )
1245  {
1246  /* factorpolynomial is a single monomial */
1247  SCIP_EXPRDATA_MONOMIAL* factormonomial;
1248  int childidx;
1249  SCIP_Real exponent;
1250 
1251  factormonomial = factorpolynomial->monomials[0];
1252  assert(factormonomial != NULL);
1253 
1254  if( !EPSISINT(monomial->exponents[factorpos], 0.0) ) /*lint !e835*/
1255  {
1256  if( factormonomial->coef < 0.0 )
1257  {
1258  /* if coefficient of monomial is negative and our exponent is not integer, then do not do expansion
1259  * @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
1260  */
1261  *success = FALSE;
1262  return SCIP_OKAY;
1263  }
1264  if( factormonomial->nfactors > 1 )
1265  {
1266  /* @todo if there is an even number of factors in factormonomial that are negative, then they always multiply to something positive
1267  * however, we cannot expand them as below, since we cannot compute the single powers
1268  * since we do not have the bounds on the factors here, we skip expansion in this case
1269  * MINLPLib instances tls2,4,6 are examples where we are loosing here (do not recognize convexity)
1270  */
1271  *success = FALSE;
1272  return SCIP_OKAY;
1273  }
1274  }
1275 
1276  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + factormonomial->nfactors) );
1277 
1278  for( i = 0; i < factormonomial->nfactors; ++i )
1279  {
1280  childidx = childmap[factormonomial->childidxs[i]]; /*lint !e613*/
1281  /* can do this because monomial->exponents[factorpos] is assumed to be integer or factormonomial has positive coefficient and only one factor
1282  * thus, if factormonomial->exponents[i] is fractional, then we can assume that it's argument is positive
1283  */
1284  exponent = factormonomial->exponents[i] * monomial->exponents[factorpos];
1285  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
1286  }
1287 
1288  monomial->coef *= pow(factormonomial->coef, monomial->exponents[factorpos]);
1289 
1290  /* move last factor to position factorpos */
1291  if( factorpos < monomial->nfactors-1 )
1292  {
1293  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1294  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1295  }
1296  --monomial->nfactors;
1297  monomial->sorted = FALSE;
1298  polynomialdata->sorted = FALSE;
1299 
1300  return SCIP_OKAY;
1301  }
1302 
1303  /* if exponent is negative or fractional and the polynomial is not just a monomial, then we cannot do expansion */
1304  if( !EPSISINT(monomial->exponents[factorpos], 0.0) || monomial->exponents[factorpos] < 0.0 ) /*lint !e835*/
1305  {
1306  *success = FALSE;
1307  return SCIP_OKAY;
1308  }
1309 
1310  /* if exponent is too large, skip expansion */
1311  if( monomial->exponents[factorpos] > maxexpansionexponent )
1312  {
1313  *success = FALSE;
1314  return SCIP_OKAY;
1315  }
1316 
1317  /* check whether maximal degree of expansion would exceed maxexpansionexponent
1318  * that is, assume monomial is f1^a1 f2^a2 ... and we want to expand f1 = (g11^beta11 g12^beta12... + g21^beta21 g22^beta22 ... + ...)
1319  * then we do this only if all ai and all beta are > 0.0 and a1 max(beta11+beta12+..., beta21+beta22+..., ...) + a2 + ... < maxexpansionexponent
1320  * exception (there need to be one) is if monomial is just f1
1321  */
1322  if( maxexpansionexponent < INT_MAX && (monomial->nfactors > 1 || monomial->exponents[factorpos] != 1.0) )
1323  {
1324  SCIP_Real restdegree;
1325  SCIP_Real degree;
1326  int j;
1327 
1328  restdegree = -monomial->exponents[factorpos];
1329  for( i = 0; i < monomial->nfactors; ++i )
1330  {
1331  if( monomial->exponents[i] < 0.0 )
1332  {
1333  /* ai < 0.0 */
1334  SCIPdebugMessage("skip expansion because factor %d in monomial has negative exponent\n", i);
1335  *success = FALSE;
1336  return SCIP_OKAY;
1337  }
1338  restdegree += monomial->exponents[i];
1339  }
1340 
1341  for( i = 0; i < factorpolynomial->nmonomials; ++i )
1342  {
1343  degree = 0.0;
1344  for( j = 0; j < factorpolynomial->monomials[i]->nfactors; ++j )
1345  {
1346  if( factorpolynomial->monomials[i]->exponents[j] < 0.0 )
1347  {
1348  /* beta_ij < 0.0 */
1349  SCIPdebugMessage("skip expansion because %d'th factor in %d'th monomial of factorpolynomial is negative\n", i, j);
1350  *success = FALSE;
1351  return SCIP_OKAY;
1352  }
1353  degree += factorpolynomial->monomials[i]->exponents[j];
1354  }
1355  if( degree * monomial->exponents[factorpos] + restdegree > maxexpansionexponent )
1356  {
1357  /* (beta_i1+beta_i2+...)*monomial->exponents[factorpos] + rest > maxexpansion */
1358  SCIPdebugMessage("skip expansion because degree of %d'th monomial would yield degree %g > max = %d in expansion\n",
1359  i, degree * monomial->exponents[factorpos] + restdegree, maxexpansionexponent);
1360  *success = FALSE;
1361  return SCIP_OKAY;
1362  }
1363  }
1364  }
1365 
1366  /* create a copy of factor */
1367  SCIP_CALL( polynomialdataCopy(blkmem, &factorpolynomialcopy, factorpolynomial) );
1368  /* apply childmap to copy */
1369  polynomialdataApplyChildmap(factorpolynomialcopy, childmap);
1370  /* create power of factor */
1371  SCIP_CALL( polynomialdataPower(blkmem, factorpolynomialcopy, (int)EPSFLOOR(monomial->exponents[factorpos], 0.0)) ); /*lint !e835*/
1372 
1373  /* remove factor from monomial by moving last factor to position factorpos */
1374  if( factorpos < monomial->nfactors-1 )
1375  {
1376  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1377  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1378  }
1379  --monomial->nfactors;
1380  monomial->sorted = FALSE;
1381 
1382  /* multiply factor with this reduced monomial */
1383  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, factorpolynomialcopy, monomial, NULL) );
1384 
1385  /* remove monomial from polynomial and move last monomial to monomialpos */
1386  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[monomialpos]);
1387  if( monomialpos < polynomialdata->nmonomials-1 )
1388  polynomialdata->monomials[monomialpos] = polynomialdata->monomials[polynomialdata->nmonomials-1];
1389  --polynomialdata->nmonomials;
1390  polynomialdata->sorted = FALSE;
1391 
1392  /* add factorpolynomialcopy to polynomial */
1393  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, factorpolynomialcopy->nmonomials, factorpolynomialcopy->monomials, FALSE) );
1394  polynomialdata->constant += factorpolynomialcopy->constant;
1395 
1396  factorpolynomialcopy->nmonomials = 0;
1397  polynomialdataFree(blkmem, &factorpolynomialcopy);
1398 
1399  return SCIP_OKAY;
1400 }
1401 
1402 /**@} */
1403 
1404 /**@name Expression operand private methods */
1405 /**@{ */
1406 
1407 /** a default implementation of expression interval evaluation that always gives a correct result */
1408 static
1409 SCIP_DECL_EXPRINTEVAL( exprevalIntDefault )
1410 { /*lint --e{715}*/
1412 
1413  return SCIP_OKAY;
1414 }
1415 
1416 /** a default implementation of expression curvature check that always gives a correct result */
1417 static
1418 SCIP_DECL_EXPRCURV( exprcurvDefault )
1419 { /*lint --e{715}*/
1420  *result = SCIP_EXPRCURV_UNKNOWN;
1421 
1422  return SCIP_OKAY;
1423 }
1424 
1425 /** point evaluation for EXPR_VAR */
1426 static
1427 SCIP_DECL_EXPREVAL( exprevalVar )
1428 { /*lint --e{715}*/
1429  assert(result != NULL);
1430  assert(varvals != NULL);
1431 
1432  *result = varvals[opdata.intval];
1433 
1434  return SCIP_OKAY;
1435 }
1436 
1437 /** interval evaluation for EXPR_VAR */
1438 static
1439 SCIP_DECL_EXPRINTEVAL( exprevalIntVar )
1440 { /*lint --e{715}*/
1441  assert(result != NULL);
1442  assert(varvals != NULL);
1443 
1444  *result = varvals[opdata.intval];
1445 
1446  return SCIP_OKAY;
1447 }
1448 
1449 /** curvature for EXPR_VAR */
1450 static
1451 SCIP_DECL_EXPRCURV( exprcurvVar )
1452 { /*lint --e{715}*/
1453  assert(result != NULL);
1454 
1455  *result = SCIP_EXPRCURV_LINEAR;
1456 
1457  return SCIP_OKAY;
1458 }
1459 
1460 /** point evaluation for EXPR_CONST */
1461 static
1462 SCIP_DECL_EXPREVAL( exprevalConst )
1463 { /*lint --e{715}*/
1464  assert(result != NULL);
1465 
1466  *result = opdata.dbl;
1467 
1468  return SCIP_OKAY;
1469 }
1470 
1471 /** interval evaluation for EXPR_CONST */
1472 static
1473 SCIP_DECL_EXPRINTEVAL( exprevalIntConst )
1474 { /*lint --e{715}*/
1475  assert(result != NULL);
1476 
1477  SCIPintervalSet(result, opdata.dbl);
1478 
1479  return SCIP_OKAY;
1480 }
1481 
1482 /** curvature for EXPR_CONST */
1483 static
1484 SCIP_DECL_EXPRCURV( exprcurvConst )
1485 { /*lint --e{715}*/
1486  assert(result != NULL);
1487 
1488  *result = SCIP_EXPRCURV_LINEAR;
1489 
1490  return SCIP_OKAY;
1491 }
1492 
1493 /** point evaluation for EXPR_PARAM */
1494 static
1495 SCIP_DECL_EXPREVAL( exprevalParam )
1496 { /*lint --e{715}*/
1497  assert(result != NULL);
1498  assert(paramvals != NULL );
1499 
1500  *result = paramvals[opdata.intval];
1501 
1502  return SCIP_OKAY;
1503 }
1504 
1505 /** interval evaluation for EXPR_PARAM */
1506 static
1507 SCIP_DECL_EXPRINTEVAL( exprevalIntParam )
1508 { /*lint --e{715}*/
1509  assert(result != NULL);
1510  assert(paramvals != NULL );
1511 
1512  SCIPintervalSet(result, paramvals[opdata.intval]);
1513 
1514  return SCIP_OKAY;
1515 }
1516 
1517 /** curvature for EXPR_PARAM */
1518 static
1519 SCIP_DECL_EXPRCURV( exprcurvParam )
1520 { /*lint --e{715}*/
1521  assert(result != NULL);
1522 
1523  *result = SCIP_EXPRCURV_LINEAR;
1524 
1525  return SCIP_OKAY;
1526 }
1527 
1528 /** point evaluation for EXPR_PLUS */
1529 static
1530 SCIP_DECL_EXPREVAL( exprevalPlus )
1531 { /*lint --e{715}*/
1532  assert(result != NULL);
1533  assert(argvals != NULL);
1534 
1535  *result = argvals[0] + argvals[1];
1536 
1537  return SCIP_OKAY;
1538 }
1539 
1540 /** interval evaluation for EXPR_PLUS */
1541 static
1542 SCIP_DECL_EXPRINTEVAL( exprevalIntPlus )
1543 { /*lint --e{715}*/
1544  assert(result != NULL);
1545  assert(argvals != NULL);
1546 
1547  SCIPintervalAdd(infinity, result, argvals[0], argvals[1]);
1548 
1549  return SCIP_OKAY;
1550 }
1551 
1552 /** curvature for EXPR_PLUS */
1553 static
1554 SCIP_DECL_EXPRCURV( exprcurvPlus )
1555 { /*lint --e{715}*/
1556  assert(result != NULL);
1557  assert(argcurv != NULL);
1558 
1559  *result = SCIPexprcurvAdd(argcurv[0], argcurv[1]);
1560 
1561  return SCIP_OKAY;
1562 }
1563 
1564 /** point evaluation for EXPR_MINUS */
1565 static
1566 SCIP_DECL_EXPREVAL( exprevalMinus )
1567 { /*lint --e{715}*/
1568  assert(result != NULL);
1569  assert(argvals != NULL);
1570 
1571  *result = argvals[0] - argvals[1];
1572 
1573  return SCIP_OKAY;
1574 }
1575 
1576 /** interval evaluation for EXPR_MINUS */
1577 static
1578 SCIP_DECL_EXPRINTEVAL( exprevalIntMinus )
1579 { /*lint --e{715}*/
1580  assert(result != NULL);
1581  assert(argvals != NULL);
1582 
1583  SCIPintervalSub(infinity, result, argvals[0], argvals[1]);
1584 
1585  return SCIP_OKAY;
1586 }
1587 
1588 /** curvature for EXPR_MINUS */
1589 static
1590 SCIP_DECL_EXPRCURV( exprcurvMinus )
1591 { /*lint --e{715}*/
1592  assert(result != NULL);
1593  assert(argcurv != NULL);
1594 
1595  *result = SCIPexprcurvAdd(argcurv[0], SCIPexprcurvNegate(argcurv[1]));
1596 
1597  return SCIP_OKAY;
1598 }
1599 
1600 /** point evaluation for EXPR_MUL */
1601 static
1602 SCIP_DECL_EXPREVAL( exprevalMult )
1603 { /*lint --e{715}*/
1604  assert(result != NULL);
1605  assert(argvals != NULL);
1606 
1607  *result = argvals[0] * argvals[1];
1608 
1609  return SCIP_OKAY;
1610 }
1611 
1612 /** interval evaluation for EXPR_MUL */
1613 static
1614 SCIP_DECL_EXPRINTEVAL( exprevalIntMult )
1615 { /*lint --e{715}*/
1616  assert(result != NULL);
1617  assert(argvals != NULL);
1618 
1619  SCIPintervalMul(infinity, result, argvals[0], argvals[1]);
1620 
1621  return SCIP_OKAY;
1622 }
1623 
1624 /** curvature for EXPR_MUL */
1625 static
1626 SCIP_DECL_EXPRCURV( exprcurvMult )
1627 { /*lint --e{715}*/
1628  assert(result != NULL);
1629  assert(argcurv != NULL);
1630  assert(argbounds != NULL);
1631 
1632  /* if one factor is constant, then product is
1633  * - linear, if constant is 0.0
1634  * - same curvature as other factor, if constant is positive
1635  * - negated curvature of other factor, if constant is negative
1636  *
1637  * if both factors are not constant, then product may not be convex nor concave
1638  */
1639  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1640  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1641  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1642  *result = SCIPexprcurvMultiply(argbounds[0].inf, argcurv[1]);
1643  else
1644  *result = SCIP_EXPRCURV_UNKNOWN;
1645 
1646  return SCIP_OKAY;
1647 }
1648 
1649 /** point evaluation for EXPR_DIV */
1650 static
1651 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1652 __attribute__((no_sanitize_undefined))
1653 #endif
1654 SCIP_DECL_EXPREVAL( exprevalDiv )
1655 { /*lint --e{715}*/
1656  assert(result != NULL);
1657  assert(argvals != NULL);
1658 
1659  *result = argvals[0] / argvals[1];
1660 
1661  return SCIP_OKAY;
1662 }
1663 
1664 /** interval evaluation for EXPR_DIV */
1665 static
1666 SCIP_DECL_EXPRINTEVAL( exprevalIntDiv )
1667 { /*lint --e{715}*/
1668  assert(result != NULL);
1669  assert(argvals != NULL);
1670 
1671  SCIPintervalDiv(infinity, result, argvals[0], argvals[1]);
1672 
1673  return SCIP_OKAY;
1674 }
1675 
1676 /** curvature for EXPR_DIV */
1677 static
1678 SCIP_DECL_EXPRCURV( exprcurvDiv )
1679 { /*lint --e{715}*/
1680  assert(result != NULL);
1681  assert(argcurv != NULL);
1682  assert(argbounds != NULL);
1683 
1684  /* if denominator is constant, then quotient has curvature sign(denominator) * curv(nominator)
1685  *
1686  * if nominator is a constant, then quotient is
1687  * - sign(nominator) * convex, if denominator is concave and positive
1688  * - sign(nominator) * concave, if denominator is convex and negative
1689  *
1690  * if denominator is positive but convex, then we don't know, e.g.,
1691  * - 1/x^2 is convex for x>=0
1692  * - 1/(1+(x-1)^2) is neither convex nor concave for x >= 0
1693  *
1694  * if both nominator and denominator are not constant, then quotient may not be convex nor concave
1695  */
1696  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1697  {
1698  /* denominator is constant */
1699  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1700  }
1701  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1702  {
1703  /* nominator is constant */
1704  if( argbounds[1].inf >= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
1705  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONVEX);
1706  else if( argbounds[1].sup <= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
1707  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONCAVE);
1708  else
1709  *result = SCIP_EXPRCURV_UNKNOWN;
1710  }
1711  else
1712  {
1713  /* denominator and nominator not constant */
1714  *result = SCIP_EXPRCURV_UNKNOWN;
1715  }
1716 
1717  return SCIP_OKAY;
1718 }
1719 
1720 /** point evaluation for EXPR_SQUARE */
1721 static
1722 SCIP_DECL_EXPREVAL( exprevalSquare )
1723 { /*lint --e{715}*/
1724  assert(result != NULL);
1725  assert(argvals != NULL);
1726 
1727  *result = argvals[0] * argvals[0];
1728 
1729  return SCIP_OKAY;
1730 }
1731 
1732 /** interval evaluation for EXPR_SQUARE */
1733 static
1734 SCIP_DECL_EXPRINTEVAL( exprevalIntSquare )
1735 { /*lint --e{715}*/
1736  assert(result != NULL);
1737  assert(argvals != NULL);
1738 
1739  SCIPintervalSquare(infinity, result, argvals[0]);
1740 
1741  return SCIP_OKAY;
1742 }
1743 
1744 /** curvature for EXPR_SQUARE */
1745 static
1746 SCIP_DECL_EXPRCURV( exprcurvSquare )
1747 { /*lint --e{715}*/
1748  assert(result != NULL);
1749  assert(argcurv != NULL);
1750  assert(argbounds != NULL);
1751 
1752  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], 2.0);
1753 
1754  return SCIP_OKAY;
1755 }
1756 
1757 /** point evaluation for EXPR_SQRT */
1758 static
1759 SCIP_DECL_EXPREVAL( exprevalSquareRoot )
1760 { /*lint --e{715}*/
1761  assert(result != NULL);
1762  assert(argvals != NULL);
1763 
1764  *result = sqrt(argvals[0]);
1765 
1766  return SCIP_OKAY;
1767 }
1768 
1769 /** interval evaluation for EXPR_SQRT */
1770 static
1771 SCIP_DECL_EXPRINTEVAL( exprevalIntSquareRoot )
1772 { /*lint --e{715}*/
1773  assert(result != NULL);
1774  assert(argvals != NULL);
1775 
1776  SCIPintervalSquareRoot(infinity, result, argvals[0]);
1777 
1778  return SCIP_OKAY;
1779 }
1780 
1781 /** curvature for EXPR_SQRT */
1782 static
1783 SCIP_DECL_EXPRCURV( exprcurvSquareRoot )
1784 { /*lint --e{715}*/
1785  assert(result != NULL);
1786  assert(argcurv != NULL);
1787 
1788  /* square-root is concave, if child is concave
1789  * otherwise, we don't know
1790  */
1791 
1792  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
1793  *result = SCIP_EXPRCURV_CONCAVE;
1794  else
1795  *result = SCIP_EXPRCURV_UNKNOWN;
1796 
1797  return SCIP_OKAY;
1798 }
1799 
1800 /** point evaluation for EXPR_REALPOWER */
1801 static
1802 SCIP_DECL_EXPREVAL( exprevalRealPower )
1803 { /*lint --e{715}*/
1804  assert(result != NULL);
1805  assert(argvals != NULL);
1806 
1807  *result = pow(argvals[0], opdata.dbl);
1808 
1809  return SCIP_OKAY;
1810 }
1811 
1812 /** interval evaluation for EXPR_REALPOWER */
1813 static
1814 SCIP_DECL_EXPRINTEVAL( exprevalIntRealPower )
1815 { /*lint --e{715}*/
1816  assert(result != NULL);
1817  assert(argvals != NULL);
1818 
1819  SCIPintervalPowerScalar(infinity, result, argvals[0], opdata.dbl);
1820 
1821  return SCIP_OKAY;
1822 }
1823 
1824 /** curvature for EXPR_REALPOWER */
1825 static
1826 SCIP_DECL_EXPRCURV( exprcurvRealPower )
1827 { /*lint --e{715}*/
1828  assert(result != NULL);
1829  assert(argcurv != NULL);
1830  assert(argbounds != NULL);
1831 
1832  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], opdata.dbl);
1833 
1834  return SCIP_OKAY;
1835 }
1836 
1837 /** point evaluation for EXPR_INTPOWER */
1838 static
1839 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1840 __attribute__((no_sanitize_undefined))
1841 #endif
1842 SCIP_DECL_EXPREVAL( exprevalIntPower )
1843 { /*lint --e{715}*/
1844  assert(result != NULL);
1845  assert(argvals != NULL);
1846 
1847  switch( opdata.intval )
1848  {
1849  case -1:
1850  *result = 1.0 / argvals[0];
1851  return SCIP_OKAY;
1852 
1853  case 0:
1854  *result = 1.0;
1855  return SCIP_OKAY;
1856 
1857  case 1:
1858  *result = argvals[0];
1859  return SCIP_OKAY;
1860 
1861  case 2:
1862  *result = argvals[0] * argvals[0];
1863  return SCIP_OKAY;
1864 
1865  default:
1866  *result = pow(argvals[0], (SCIP_Real)opdata.intval);
1867  }
1868 
1869  return SCIP_OKAY;
1870 }
1871 
1872 /** interval evaluation for EXPR_INTPOWER */
1873 static
1874 SCIP_DECL_EXPRINTEVAL( exprevalIntIntPower )
1875 { /*lint --e{715}*/
1876  assert(result != NULL);
1877  assert(argvals != NULL);
1878 
1879  SCIPintervalPowerScalar(infinity, result, argvals[0], (SCIP_Real)opdata.intval);
1880 
1881  return SCIP_OKAY;
1882 }
1883 
1884 /** curvature for EXPR_INTPOWER */
1885 static
1886 SCIP_DECL_EXPRCURV( exprcurvIntPower )
1887 { /*lint --e{715}*/
1888  assert(result != NULL);
1889  assert(argcurv != NULL);
1890  assert(argbounds != NULL);
1891 
1892  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], (SCIP_Real)opdata.intval);
1893 
1894  return SCIP_OKAY;
1895 }
1896 
1897 /** point evaluation for EXPR_SIGNPOWER */
1898 static
1899 SCIP_DECL_EXPREVAL( exprevalSignPower )
1900 { /*lint --e{715}*/
1901  assert(result != NULL);
1902  assert(argvals != NULL);
1903 
1904  if( argvals[0] > 0 )
1905  *result = pow( argvals[0], opdata.dbl);
1906  else
1907  *result = -pow(-argvals[0], opdata.dbl);
1908 
1909  return SCIP_OKAY;
1910 }
1911 
1912 /** interval evaluation for EXPR_SIGNPOWER */
1913 static
1914 SCIP_DECL_EXPRINTEVAL( exprevalIntSignPower )
1915 { /*lint --e{715}*/
1916  assert(result != NULL);
1917  assert(argvals != NULL);
1918 
1919  SCIPintervalSignPowerScalar(infinity, result, argvals[0], opdata.dbl);
1920 
1921  return SCIP_OKAY;
1922 }
1923 
1924 /** curvature for EXPR_SIGNPOWER */
1925 static
1926 SCIP_DECL_EXPRCURV( exprcurvSignPower )
1927 { /*lint --e{715}*/
1928  SCIP_INTERVAL tmp;
1929  SCIP_EXPRCURV left;
1930  SCIP_EXPRCURV right;
1931 
1932  assert(result != NULL);
1933  assert(argcurv != NULL);
1934  assert(argbounds != NULL);
1935 
1936  /* for x <= 0, signpower(x,c) = -(-x)^c
1937  * for x >= 0, signpower(x,c) = ( x)^c
1938  *
1939  * thus, get curvatures for both parts and "intersect" them
1940  */
1941 
1942  if( argbounds[0].inf < 0 )
1943  {
1944  SCIPintervalSetBounds(&tmp, 0.0, -argbounds[0].inf);
1945  left = SCIPexprcurvNegate(SCIPexprcurvPower(tmp, SCIPexprcurvNegate(argcurv[0]), opdata.dbl));
1946  }
1947  else
1948  {
1949  left = SCIP_EXPRCURV_LINEAR;
1950  }
1951 
1952  if( argbounds[0].sup > 0 )
1953  {
1954  SCIPintervalSetBounds(&tmp, 0.0, argbounds[0].sup);
1955  right = SCIPexprcurvPower(tmp, argcurv[0], opdata.dbl);
1956  }
1957  else
1958  {
1959  right = SCIP_EXPRCURV_LINEAR;
1960  }
1961 
1962  *result = (SCIP_EXPRCURV) (left & right);
1963 
1964  return SCIP_OKAY;
1965 }
1966 
1967 /** point evaluation for EXPR_EXP */
1968 static
1969 SCIP_DECL_EXPREVAL( exprevalExp )
1970 { /*lint --e{715}*/
1971  assert(result != NULL);
1972  assert(argvals != NULL);
1973 
1974  *result = exp(argvals[0]);
1975 
1976  return SCIP_OKAY;
1977 }
1978 
1979 /** interval evaluation for EXPR_EXP */
1980 static
1981 SCIP_DECL_EXPRINTEVAL( exprevalIntExp )
1982 { /*lint --e{715}*/
1983  assert(result != NULL);
1984  assert(argvals != NULL);
1985 
1986  SCIPintervalExp(infinity, result, argvals[0]);
1987 
1988  return SCIP_OKAY;
1989 }
1990 
1991 /** curvature for EXPR_EXP */
1992 static
1993 SCIP_DECL_EXPRCURV( exprcurvExp )
1994 { /*lint --e{715}*/
1995  assert(result != NULL);
1996  assert(argcurv != NULL);
1997 
1998  /* expression is convex if child is convex
1999  * otherwise, we don't know
2000  */
2001  if( argcurv[0] & SCIP_EXPRCURV_CONVEX )
2002  *result = SCIP_EXPRCURV_CONVEX;
2003  else
2004  *result = SCIP_EXPRCURV_UNKNOWN;
2005 
2006  return SCIP_OKAY;
2007 }
2008 
2009 /** point evaluation for EXPR_LOG */
2010 static
2011 SCIP_DECL_EXPREVAL( exprevalLog )
2012 { /*lint --e{715}*/
2013  assert(result != NULL);
2014  assert(argvals != NULL);
2015 
2016  *result = log(argvals[0]);
2017 
2018  return SCIP_OKAY;
2019 }
2020 
2021 /** interval evaluation for EXPR_LOG */
2022 static
2023 SCIP_DECL_EXPRINTEVAL( exprevalIntLog )
2024 { /*lint --e{715}*/
2025  assert(result != NULL);
2026  assert(argvals != NULL);
2027 
2028  SCIPintervalLog(infinity, result, argvals[0]);
2029 
2030  return SCIP_OKAY;
2031 }
2032 
2033 /** curvature for EXPR_LOG */
2034 static
2035 SCIP_DECL_EXPRCURV( exprcurvLog )
2036 { /*lint --e{715}*/
2037  assert(result != NULL);
2038  assert(argcurv != NULL);
2039 
2040  /* expression is concave if child is concave
2041  * otherwise, we don't know
2042  */
2043  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
2044  *result = SCIP_EXPRCURV_CONCAVE;
2045  else
2046  *result = SCIP_EXPRCURV_UNKNOWN;
2047 
2048  return SCIP_OKAY;
2049 }
2050 
2051 /** point evaluation for EXPR_SIN */
2052 static
2053 SCIP_DECL_EXPREVAL( exprevalSin )
2054 { /*lint --e{715}*/
2055  assert(result != NULL);
2056  assert(argvals != NULL);
2057 
2058  *result = sin(argvals[0]);
2059 
2060  return SCIP_OKAY;
2061 }
2062 
2063 /** interval evaluation for EXPR_SIN */
2064 static
2065 SCIP_DECL_EXPRINTEVAL( exprevalIntSin )
2066 { /*lint --e{715}*/
2067  assert(result != NULL);
2068  assert(argvals != NULL);
2069  assert(nargs == 1);
2070 
2071  SCIPintervalSin(infinity, result, *argvals);
2072 
2073  return SCIP_OKAY;
2074 }
2075 
2076 /* @todo implement exprcurvSin */
2077 #define exprcurvSin exprcurvDefault
2078 
2079 /** point evaluation for EXPR_COS */
2080 static
2081 SCIP_DECL_EXPREVAL( exprevalCos )
2082 { /*lint --e{715}*/
2083  assert(result != NULL);
2084  assert(argvals != NULL);
2085 
2086  *result = cos(argvals[0]);
2087 
2088  return SCIP_OKAY;
2089 }
2090 
2091 /** interval evaluation for EXPR_COS */
2092 static
2093 SCIP_DECL_EXPRINTEVAL( exprevalIntCos )
2094 { /*lint --e{715}*/
2095  assert(result != NULL);
2096  assert(argvals != NULL);
2097  assert(nargs == 1);
2098 
2099  SCIPintervalCos(infinity, result, *argvals);
2100 
2101  return SCIP_OKAY;
2102 }
2103 
2104 /* @todo implement exprcurvCos */
2105 #define exprcurvCos exprcurvDefault
2106 
2107 /** point evaluation for EXPR_TAN */
2108 static
2109 SCIP_DECL_EXPREVAL( exprevalTan )
2110 { /*lint --e{715}*/
2111  assert(result != NULL);
2112  assert(argvals != NULL);
2113 
2114  *result = tan(argvals[0]);
2115 
2116  return SCIP_OKAY;
2117 }
2118 
2119 /* @todo implement SCIPintervalTan */
2120 #define exprevalIntTan exprevalIntDefault
2121 
2122 /* @todo implement exprcurvTan */
2123 #define exprcurvTan exprcurvDefault
2124 
2125 /* erf and erfi do not seem to exist on every system, and we cannot really handle them anyway, so they are currently disabled */
2126 #ifdef SCIP_DISABLED_CODE
2127 static
2128 SCIP_DECL_EXPREVAL( exprevalErf )
2129 { /*lint --e{715}*/
2130  assert(result != NULL);
2131  assert(argvals != NULL);
2132 
2133  *result = erf(argvals[0]);
2134 
2135  return SCIP_OKAY;
2136 }
2137 
2138 /* @todo implement SCIPintervalErf */
2139 #define exprevalIntErf exprevalIntDefault
2140 
2141 /* @todo implement SCIPintervalErf */
2142 #define exprcurvErf exprcurvDefault
2143 
2144 static
2145 SCIP_DECL_EXPREVAL( exprevalErfi )
2146 { /*lint --e{715}*/
2147  assert(result != NULL);
2148  assert(argvals != NULL);
2149 
2150  /* @TODO implement erfi evaluation */
2151  SCIPerrorMessage("erfi not implemented");
2152 
2153  return SCIP_ERROR;
2154 }
2155 
2156 /* @todo implement SCIPintervalErfi */
2157 #define exprevalIntErfi NULL
2158 
2159 #define exprcurvErfi exprcurvDefault
2160 #endif
2161 
2162 /** point evaluation for EXPR_MIN */
2163 static
2164 SCIP_DECL_EXPREVAL( exprevalMin )
2165 { /*lint --e{715}*/
2166  assert(result != NULL);
2167  assert(argvals != NULL);
2168 
2169  *result = MIN(argvals[0], argvals[1]);
2170 
2171  return SCIP_OKAY;
2172 }
2173 
2174 /** interval evaluation for EXPR_MIN */
2175 static
2176 SCIP_DECL_EXPRINTEVAL( exprevalIntMin )
2177 { /*lint --e{715}*/
2178  assert(result != NULL);
2179  assert(argvals != NULL);
2180 
2181  SCIPintervalMin(infinity, result, argvals[0], argvals[1]);
2182 
2183  return SCIP_OKAY;
2184 }
2185 
2186 /** curvature for EXPR_MIN */
2187 static
2188 SCIP_DECL_EXPRCURV( exprcurvMin )
2189 { /*lint --e{715}*/
2190  assert(result != NULL);
2191  assert(argcurv != NULL);
2192 
2193  /* the minimum of two concave functions is concave
2194  * otherwise, we don't know
2195  */
2196 
2197  if( (argcurv[0] & SCIP_EXPRCURV_CONCAVE) && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
2198  *result = SCIP_EXPRCURV_CONCAVE;
2199  else
2200  *result = SCIP_EXPRCURV_UNKNOWN;
2201 
2202  return SCIP_OKAY;
2203 }
2204 
2205 /** point evaluation for EXPR_MAX */
2206 static
2207 SCIP_DECL_EXPREVAL( exprevalMax )
2208 { /*lint --e{715}*/
2209  assert(result != NULL);
2210  assert(argvals != NULL);
2211 
2212  *result = MAX(argvals[0], argvals[1]);
2213 
2214  return SCIP_OKAY;
2215 }
2216 
2217 /** interval evaluation for EXPR_MAX */
2218 static
2219 SCIP_DECL_EXPRINTEVAL( exprevalIntMax )
2220 { /*lint --e{715}*/
2221  assert(result != NULL);
2222  assert(argvals != NULL);
2223 
2224  SCIPintervalMax(infinity, result, argvals[0], argvals[1]);
2225 
2226  return SCIP_OKAY;
2227 }
2228 
2229 /** curvature for EXPR_MAX */
2230 static
2231 SCIP_DECL_EXPRCURV( exprcurvMax )
2232 { /*lint --e{715}*/
2233  assert(result != NULL);
2234  assert(argcurv != NULL);
2235 
2236  /* the maximum of two convex functions is convex
2237  * otherwise, we don't know
2238  */
2239  if( (argcurv[0] & SCIP_EXPRCURV_CONVEX) && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
2240  *result = SCIP_EXPRCURV_CONVEX;
2241  else
2242  *result = SCIP_EXPRCURV_UNKNOWN;
2243 
2244  return SCIP_OKAY;
2245 }
2246 
2247 /** point evaluation for EXPR_ABS */
2248 static
2249 SCIP_DECL_EXPREVAL( exprevalAbs )
2250 { /*lint --e{715}*/
2251  assert(result != NULL);
2252  assert(argvals != NULL);
2253 
2254  *result = ABS(argvals[0]);
2255 
2256  return SCIP_OKAY;
2257 }
2258 
2259 /** interval evaluation for EXPR_ABS */
2260 static
2261 SCIP_DECL_EXPRINTEVAL( exprevalIntAbs )
2262 { /*lint --e{715}*/
2263  assert(result != NULL);
2264  assert(argvals != NULL);
2265 
2266  SCIPintervalAbs(infinity, result, argvals[0]);
2267 
2268  return SCIP_OKAY;
2269 }
2270 
2271 /** curvature for EXPR_ABS */
2272 static
2273 SCIP_DECL_EXPRCURV( exprcurvAbs )
2274 { /*lint --e{715}*/
2275  assert(result != NULL);
2276  assert(argcurv != NULL);
2277  assert(argbounds != NULL);
2278 
2279  /* if child is only negative, then abs(child) = -child
2280  * if child is only positive, then abs(child) = child
2281  * if child is both positive and negative, but also linear, then abs(child) is convex
2282  * otherwise, we don't know
2283  */
2284  if( argbounds[0].sup <= 0.0 )
2285  *result = SCIPexprcurvMultiply(-1.0, argcurv[0]);
2286  else if( argbounds[0].inf >= 0.0 )
2287  *result = argcurv[0];
2288  else if( argcurv[0] == SCIP_EXPRCURV_LINEAR )
2289  *result = SCIP_EXPRCURV_CONVEX;
2290  else
2291  *result = SCIP_EXPRCURV_UNKNOWN;
2292 
2293  return SCIP_OKAY;
2294 }
2295 
2296 /** point evaluation for EXPR_SIGN */
2297 static
2298 SCIP_DECL_EXPREVAL( exprevalSign )
2299 { /*lint --e{715}*/
2300  assert(result != NULL);
2301  assert(argvals != NULL);
2302 
2303  *result = SIGN(argvals[0]);
2304 
2305  return SCIP_OKAY;
2306 }
2307 
2308 /** interval evaluation for EXPR_SIGN */
2309 static
2310 SCIP_DECL_EXPRINTEVAL( exprevalIntSign )
2311 { /*lint --e{715}*/
2312  assert(result != NULL);
2313  assert(argvals != NULL);
2314 
2315  SCIPintervalSign(infinity, result, argvals[0]);
2316 
2317  return SCIP_OKAY;
2318 }
2319 
2320 /** curvature for EXPR_SIGN */
2321 static
2322 SCIP_DECL_EXPRCURV( exprcurvSign )
2323 { /*lint --e{715}*/
2324  assert(result != NULL);
2325  assert(argbounds != NULL);
2326 
2327  /* if sign of child is clear, then sign is linear otherwise, we don't know */
2328  if( argbounds[0].sup <= 0.0 || argbounds[0].inf >= 0.0 )
2329  *result = SCIP_EXPRCURV_LINEAR;
2330  else
2331  *result = SCIP_EXPRCURV_UNKNOWN;
2332 
2333  return SCIP_OKAY;
2334 }
2335 
2336 /** point evaluation for EXPR_SUM */
2337 static
2338 SCIP_DECL_EXPREVAL( exprevalSum )
2339 { /*lint --e{715}*/
2340  int i;
2341 
2342  assert(result != NULL);
2343  assert(argvals != NULL);
2344 
2345  *result = 0.0;
2346  for( i = 0; i < nargs; ++i )
2347  *result += argvals[i];
2348 
2349  return SCIP_OKAY;
2350 }
2351 
2352 /** interval evaluation for EXPR_SUM */
2353 static
2354 SCIP_DECL_EXPRINTEVAL( exprevalIntSum )
2355 { /*lint --e{715}*/
2356  int i;
2357 
2358  assert(result != NULL);
2359  assert(argvals != NULL);
2360 
2361  SCIPintervalSet(result, 0.0);
2362 
2363  for( i = 0; i < nargs; ++i )
2364  SCIPintervalAdd(infinity, result, *result, argvals[i]);
2365 
2366  return SCIP_OKAY;
2367 }
2368 
2369 /** curvature for EXPR_SUM */
2370 static
2371 SCIP_DECL_EXPRCURV( exprcurvSum )
2372 { /*lint --e{715}*/
2373  int i;
2374 
2375  assert(result != NULL);
2376  assert(argcurv != NULL);
2377 
2378  *result = SCIP_EXPRCURV_LINEAR;
2379 
2380  for( i = 0; i < nargs; ++i )
2381  *result = SCIPexprcurvAdd(*result, argcurv[i]);
2382 
2383  return SCIP_OKAY;
2384 }
2385 
2386 /** point evaluation for EXPR_PRODUCT */
2387 static
2388 SCIP_DECL_EXPREVAL( exprevalProduct )
2389 { /*lint --e{715}*/
2390  int i;
2391 
2392  assert(result != NULL);
2393  assert(argvals != NULL);
2394 
2395  *result = 1.0;
2396  for( i = 0; i < nargs; ++i )
2397  *result *= argvals[i];
2398 
2399  return SCIP_OKAY;
2400 }
2401 
2402 /** interval evaluation for EXPR_PRODUCT */
2403 static
2404 SCIP_DECL_EXPRINTEVAL( exprevalIntProduct )
2405 { /*lint --e{715}*/
2406  int i;
2407 
2408  assert(result != NULL);
2409  assert(argvals != NULL);
2410 
2411  SCIPintervalSet(result, 1.0);
2412 
2413  for( i = 0; i < nargs; ++i )
2414  SCIPintervalMul(infinity, result, *result, argvals[i]);
2415 
2416  return SCIP_OKAY;
2417 }
2418 
2419 /** curvature for EXPR_PRODUCT */
2420 static
2421 SCIP_DECL_EXPRCURV( exprcurvProduct )
2422 { /*lint --e{715}*/
2423  SCIP_Bool hadnonconst;
2424  SCIP_Real constants;
2425  int i;
2426 
2427  assert(result != NULL);
2428  assert(argcurv != NULL);
2429  assert(argbounds != NULL);
2430 
2431  /* if all factors are constant, then product is linear (even constant)
2432  * if only one factor is not constant, then product is curvature of this factor, multiplied by sign of product of remaining factors
2433  */
2434  *result = SCIP_EXPRCURV_LINEAR;
2435  hadnonconst = FALSE;
2436  constants = 1.0;
2437 
2438  for( i = 0; i < nargs; ++i )
2439  {
2440  if( argbounds[i].inf == argbounds[i].sup ) /*lint !e777*/
2441  {
2442  constants *= argbounds[i].inf;
2443  }
2444  else if( !hadnonconst )
2445  {
2446  /* first non-constant child */
2447  *result = argcurv[i];
2448  hadnonconst = TRUE;
2449  }
2450  else
2451  {
2452  /* more than one non-constant child, thus don't know curvature */
2453  *result = SCIP_EXPRCURV_UNKNOWN;
2454  break;
2455  }
2456  }
2457 
2458  *result = SCIPexprcurvMultiply(constants, *result);
2459 
2460  return SCIP_OKAY;
2461 }
2462 
2463 /** point evaluation for EXPR_LINEAR */
2464 static
2465 SCIP_DECL_EXPREVAL( exprevalLinear )
2466 { /*lint --e{715}*/
2467  SCIP_Real* coef;
2468  int i;
2469 
2470  assert(result != NULL);
2471  assert(argvals != NULL || nargs == 0);
2472  assert(opdata.data != NULL);
2473 
2474  coef = &((SCIP_Real*)opdata.data)[nargs];
2475 
2476  *result = *coef;
2477  for( i = nargs-1, --coef; i >= 0; --i, --coef )
2478  *result += *coef * argvals[i]; /*lint !e613*/
2479 
2480  assert(++coef == (SCIP_Real*)opdata.data);
2481 
2482  return SCIP_OKAY;
2483 }
2484 
2485 /** interval evaluation for EXPR_LINEAR */
2486 static
2487 SCIP_DECL_EXPRINTEVAL( exprevalIntLinear )
2488 { /*lint --e{715}*/
2489  assert(result != NULL);
2490  assert(argvals != NULL || nargs == 0);
2491  assert(opdata.data != NULL);
2492 
2493  SCIPintervalScalprodScalars(infinity, result, nargs, argvals, (SCIP_Real*)opdata.data);
2494  SCIPintervalAddScalar(infinity, result, *result, ((SCIP_Real*)opdata.data)[nargs]);
2495 
2496  return SCIP_OKAY;
2497 }
2498 
2499 /** curvature for EXPR_LINEAR */
2500 static
2501 SCIP_DECL_EXPRCURV( exprcurvLinear )
2502 { /*lint --e{715}*/
2503  SCIP_Real* data;
2504  int i;
2505 
2506  assert(result != NULL);
2507  assert(argcurv != NULL);
2508 
2509  data = (SCIP_Real*)opdata.data;
2510  assert(data != NULL);
2511 
2512  *result = SCIP_EXPRCURV_LINEAR;
2513 
2514  for( i = 0; i < nargs; ++i )
2515  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(data[i], argcurv[i]));
2516 
2517  return SCIP_OKAY;
2518 }
2519 
2520 /** expression data copy for EXPR_LINEAR */
2521 static
2522 SCIP_DECL_EXPRCOPYDATA( exprCopyDataLinear )
2523 { /*lint --e{715}*/
2524  SCIP_Real* targetdata;
2525 
2526  assert(blkmem != NULL);
2527  assert(nchildren >= 0);
2528  assert(opdatatarget != NULL);
2529 
2530  /* for a linear expression, we need to copy the array that holds the coefficients and constant term */
2531  assert(opdatasource.data != NULL);
2532  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &targetdata, (SCIP_Real*)opdatasource.data, nchildren + 1) ); /*lint !e866*/
2533  opdatatarget->data = targetdata;
2534 
2535  return SCIP_OKAY;
2536 }
2537 
2538 /** expression data free for EXPR_LINEAR */
2539 static
2540 SCIP_DECL_EXPRFREEDATA( exprFreeDataLinear )
2541 { /*lint --e{715}*/
2542  SCIP_Real* freedata;
2543 
2544  assert(blkmem != NULL);
2545  assert(nchildren >= 0);
2546 
2547  freedata = (SCIP_Real*)opdata.data;
2548  assert(freedata != NULL);
2549 
2550  BMSfreeBlockMemoryArray(blkmem, &freedata, nchildren + 1); /*lint !e866*/
2551 }
2552 
2553 /** point evaluation for EXPR_QUADRATIC */
2554 static
2555 SCIP_DECL_EXPREVAL( exprevalQuadratic )
2556 { /*lint --e{715}*/
2557  SCIP_EXPRDATA_QUADRATIC* quaddata;
2558  SCIP_Real* lincoefs;
2559  SCIP_QUADELEM* quadelems;
2560  int nquadelems;
2561  int i;
2562 
2563  assert(result != NULL);
2564  assert(argvals != NULL || nargs == 0);
2565 
2566  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2567  assert(quaddata != NULL);
2568 
2569  lincoefs = quaddata->lincoefs;
2570  nquadelems = quaddata->nquadelems;
2571  quadelems = quaddata->quadelems;
2572 
2573  assert(quadelems != NULL || nquadelems == 0);
2574  assert(argvals != NULL || nquadelems == 0);
2575 
2576  *result = quaddata->constant;
2577 
2578  if( lincoefs != NULL )
2579  {
2580  for( i = nargs-1; i >= 0; --i )
2581  *result += lincoefs[i] * argvals[i]; /*lint !e613*/
2582  }
2583 
2584  for( i = 0; i < nquadelems; ++i, ++quadelems ) /*lint !e613*/
2585  *result += quadelems->coef * argvals[quadelems->idx1] * argvals[quadelems->idx2]; /*lint !e613*/
2586 
2587  return SCIP_OKAY;
2588 }
2589 
2590 /** interval evaluation for EXPR_QUADRATIC */
2591 static
2592 SCIP_DECL_EXPRINTEVAL( exprevalIntQuadratic )
2593 { /*lint --e{715}*/
2594  SCIP_EXPRDATA_QUADRATIC* quaddata;
2595  SCIP_Real* lincoefs;
2596  SCIP_QUADELEM* quadelems;
2597  int nquadelems;
2598  int i;
2599  int argidx;
2600  SCIP_Real sqrcoef;
2601  SCIP_INTERVAL lincoef;
2602  SCIP_INTERVAL tmp;
2603 
2604  assert(result != NULL);
2605  assert(argvals != NULL || nargs == 0);
2606 
2607  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2608  assert(quaddata != NULL);
2609 
2610  lincoefs = quaddata->lincoefs;
2611  nquadelems = quaddata->nquadelems;
2612  quadelems = quaddata->quadelems;
2613 
2614  assert(quadelems != NULL || nquadelems == 0);
2615  assert(argvals != NULL || nargs == 0);
2616 
2617  /* something fast for case of only one child */
2618  if( nargs == 1 )
2619  {
2620  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[0] : 0.0);
2621 
2622  sqrcoef = 0.0;
2623  for( i = 0; i < nquadelems; ++i )
2624  {
2625  assert(quadelems[i].idx1 == 0); /*lint !e613*/
2626  assert(quadelems[i].idx2 == 0); /*lint !e613*/
2627  sqrcoef += quadelems[i].coef; /*lint !e613*/
2628  }
2629 
2630  SCIPintervalQuad(infinity, result, sqrcoef, lincoef, argvals[0]); /*lint !e613*/
2631  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2632 
2633  return SCIP_OKAY;
2634  }
2635 
2636  if( nargs == 2 && nquadelems > 0 )
2637  {
2638  /* if it's a bivariate quadratic expression with bilinear term, do something special */
2639  SCIP_Real ax; /* square coefficient of first child */
2640  SCIP_Real ay; /* square coefficient of second child */
2641  SCIP_Real axy; /* bilinear coefficient */
2642 
2643  ax = 0.0;
2644  ay = 0.0;
2645  axy = 0.0;
2646  for( i = 0; i < nquadelems; ++i )
2647  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 ) /*lint !e613*/
2648  ax += quadelems[i].coef; /*lint !e613*/
2649  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 ) /*lint !e613*/
2650  ay += quadelems[i].coef; /*lint !e613*/
2651  else
2652  axy += quadelems[i].coef; /*lint !e613*/
2653 
2654  SCIPintervalQuadBivar(infinity, result, ax, ay, axy,
2655  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2656  argvals[0], argvals[1]); /*lint !e613*/
2657  SCIPdebugMessage("%g x^2 + %g y^2 + %g x y + %g x + %g y = [%g,%g] for x = [%g,%g], y = [%g,%g]\n",
2658  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2659  result->inf, result->sup, argvals[0].inf, argvals[0].sup, argvals[1].inf, argvals[1].sup); /*lint !e613*/
2660 
2661  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2662 
2663  return SCIP_OKAY;
2664  }
2665 
2666  /* make sure coefficients are sorted */
2667  quadraticdataSort(quaddata);
2668 
2669  SCIPintervalSet(result, quaddata->constant);
2670 
2671  /* for each argument, we collect it's linear index from lincoefs, it's square coefficients and all factors from bilinear terms
2672  * then we compute the interval sqrcoef*x^2 + lincoef*x and add it to result
2673  * @todo split quadratic expression into bivariate quadratic terms and apply the above method
2674  */
2675  i = 0;
2676  for( argidx = 0; argidx < nargs; ++argidx )
2677  {
2678  if( i == nquadelems || quadelems[i].idx1 > argidx ) /*lint !e613*/
2679  {
2680  /* there are no quadratic terms with argidx in its first argument, that should be easy to handle */
2681  if( lincoefs != NULL )
2682  {
2683  SCIPintervalMulScalar(infinity, &tmp, argvals[argidx], lincoefs[argidx]); /*lint !e613*/
2684  SCIPintervalAdd(infinity, result, *result, tmp);
2685  }
2686  continue;
2687  }
2688 
2689  sqrcoef = 0.0;
2690  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[argidx] : 0.0);
2691 
2692  assert(i < nquadelems && quadelems[i].idx1 == argidx); /*lint !e613*/
2693  do
2694  {
2695  if( quadelems[i].idx2 == argidx ) /*lint !e613*/
2696  {
2697  sqrcoef += quadelems[i].coef; /*lint !e613*/
2698  }
2699  else
2700  {
2701  SCIPintervalMulScalar(infinity, &tmp, argvals[quadelems[i].idx2], quadelems[i].coef); /*lint !e613*/
2702  SCIPintervalAdd(infinity, &lincoef, lincoef, tmp);
2703  }
2704  ++i;
2705  }
2706  while( i < nquadelems && quadelems[i].idx1 == argidx ); /*lint !e613*/
2707  assert(i == nquadelems || quadelems[i].idx1 > argidx); /*lint !e613*/
2708 
2709  SCIPintervalQuad(infinity, &tmp, sqrcoef, lincoef, argvals[argidx]); /*lint !e613*/
2710  SCIPintervalAdd(infinity, result, *result, tmp);
2711  }
2712  assert(i == nquadelems);
2713 
2714  return SCIP_OKAY;
2715 }
2716 
2717 /** curvature for EXPR_QUADRATIC */
2718 static
2719 SCIP_DECL_EXPRCURV( exprcurvQuadratic )
2720 { /*lint --e{715}*/
2722  SCIP_QUADELEM* quadelems;
2723  int nquadelems;
2724  SCIP_Real* lincoefs;
2725  int i;
2726 
2727  assert(result != NULL);
2728  assert(argcurv != NULL);
2729  assert(argbounds != NULL);
2730 
2731  data = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2732  assert(data != NULL);
2733 
2734  lincoefs = data->lincoefs;
2735  quadelems = data->quadelems;
2736  nquadelems = data->nquadelems;
2737 
2738  *result = SCIP_EXPRCURV_LINEAR;
2739 
2740  if( lincoefs != NULL )
2741  for( i = 0; i < nargs; ++i )
2742  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(lincoefs[i], argcurv[i]));
2743 
2744  /* @todo could try cholesky factorization if all children linear...
2745  * @todo should then cache the result
2746  */
2747  for( i = 0; i < nquadelems && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
2748  {
2749  if( quadelems[i].coef == 0.0 )
2750  continue;
2751 
2752  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup && /*lint !e777*/
2753  +argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup
2754  ) /*lint !e777*/
2755  {
2756  /* both factors are constants -> curvature does not change */
2757  continue;
2758  }
2759 
2760  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup ) /*lint !e777*/
2761  {
2762  /* first factor is constant, second is not -> add curvature of second */
2763  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx1].inf, argcurv[quadelems[i].idx2]));
2764  }
2765  else if( argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup ) /*lint !e777*/
2766  {
2767  /* first factor is not constant, second is -> add curvature of first */
2768  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx2].inf, argcurv[quadelems[i].idx1]));
2769  }
2770  else if( quadelems[i].idx1 == quadelems[i].idx2 )
2771  {
2772  /* both factors not constant, but the same (square term) */
2773  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef, SCIPexprcurvPower(argbounds[quadelems[i].idx1], argcurv[quadelems[i].idx1], 2.0)));
2774  }
2775  else
2776  {
2777  /* two different non-constant factors -> can't tell about curvature */
2778  *result = SCIP_EXPRCURV_UNKNOWN;
2779  }
2780  }
2781 
2782  return SCIP_OKAY;
2783 }
2784 
2785 /** expression data copy for EXPR_QUADRATIC */
2786 static
2787 SCIP_DECL_EXPRCOPYDATA( exprCopyDataQuadratic )
2788 { /*lint --e{715}*/
2789  SCIP_EXPRDATA_QUADRATIC* sourcedata;
2790 
2791  assert(blkmem != NULL);
2792  assert(opdatatarget != NULL);
2793 
2794  sourcedata = (SCIP_EXPRDATA_QUADRATIC*)opdatasource.data;
2795  assert(sourcedata != NULL);
2796 
2797  SCIP_CALL( quadraticdataCreate(blkmem, (SCIP_EXPRDATA_QUADRATIC**)&opdatatarget->data,
2798  sourcedata->constant, nchildren, sourcedata->lincoefs, sourcedata->nquadelems, sourcedata->quadelems) );
2799 
2800  return SCIP_OKAY;
2801 }
2802 
2803 /** expression data free for EXPR_QUADRATIC */
2804 static
2805 SCIP_DECL_EXPRFREEDATA( exprFreeDataQuadratic )
2806 { /*lint --e{715}*/
2807  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
2808 
2809  assert(blkmem != NULL);
2810  assert(nchildren >= 0);
2811 
2812  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2813  assert(quadraticdata != NULL);
2814 
2815  if( quadraticdata->lincoefs != NULL )
2816  {
2817  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->lincoefs, nchildren);
2818  }
2819 
2820  if( quadraticdata->nquadelems > 0 )
2821  {
2822  assert(quadraticdata->quadelems != NULL);
2823  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->quadelems, quadraticdata->nquadelems);
2824  }
2825 
2826  BMSfreeBlockMemory(blkmem, &quadraticdata);
2827 }
2828 
2829 /** point evaluation for EXPR_POLYNOMIAL */
2830 static
2831 SCIP_DECL_EXPREVAL( exprevalPolynomial )
2832 { /*lint --e{715}*/
2833  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2834  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2835  SCIP_Real childval;
2836  SCIP_Real exponent;
2837  SCIP_Real monomialval;
2838  int i;
2839  int j;
2840 
2841  assert(result != NULL);
2842  assert(argvals != NULL || nargs == 0);
2843  assert(opdata.data != NULL);
2844 
2845  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2846  assert(polynomialdata != NULL);
2847 
2848  *result = polynomialdata->constant;
2849 
2850  for( i = 0; i < polynomialdata->nmonomials; ++i )
2851  {
2852  monomialdata = polynomialdata->monomials[i];
2853  assert(monomialdata != NULL);
2854 
2855  monomialval = monomialdata->coef;
2856  for( j = 0; j < monomialdata->nfactors; ++j )
2857  {
2858  assert(monomialdata->childidxs[j] >= 0);
2859  assert(monomialdata->childidxs[j] < nargs);
2860 
2861  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2862  if( childval == 1.0 ) /* 1^anything == 1 */
2863  continue;
2864 
2865  exponent = monomialdata->exponents[j];
2866 
2867  if( childval == 0.0 )
2868  {
2869  if( exponent > 0.0 )
2870  {
2871  /* 0^positive == 0 */
2872  monomialval = 0.0;
2873  break;
2874  }
2875  else if( exponent < 0.0 )
2876  {
2877  /* 0^negative = nan (or should it be +inf?, doesn't really matter) */
2878 #ifdef NAN
2879  *result = NAN;
2880 #else
2881  /* cppcheck-suppress wrongmathcall */
2882  *result = pow(0.0, -1.0);
2883 #endif
2884  return SCIP_OKAY;
2885  }
2886  /* 0^0 == 1 */
2887  continue;
2888  }
2889 
2890  /* cover some special exponents separately to avoid calling expensive pow function */
2891  if( exponent == 0.0 )
2892  continue;
2893  if( exponent == 1.0 )
2894  {
2895  monomialval *= childval;
2896  continue;
2897  }
2898  if( exponent == 2.0 )
2899  {
2900  monomialval *= childval * childval;
2901  continue;
2902  }
2903  if( exponent == 0.5 )
2904  {
2905  monomialval *= sqrt(childval);
2906  continue;
2907  }
2908  if( exponent == -1.0 )
2909  {
2910  monomialval /= childval;
2911  continue;
2912  }
2913  if( exponent == -2.0 )
2914  {
2915  monomialval /= childval * childval;
2916  continue;
2917  }
2918  monomialval *= pow(childval, exponent);
2919  }
2920 
2921  *result += monomialval;
2922  }
2923 
2924  return SCIP_OKAY;
2925 }
2926 
2927 /** interval evaluation for EXPR_POLYNOMIAL */
2928 static
2929 SCIP_DECL_EXPRINTEVAL( exprevalIntPolynomial )
2930 { /*lint --e{715}*/
2931  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2932  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2933  SCIP_INTERVAL childval;
2934  SCIP_INTERVAL monomialval;
2935  SCIP_Real exponent;
2936  int i;
2937  int j;
2938 
2939  assert(result != NULL);
2940  assert(argvals != NULL || nargs == 0);
2941  assert(opdata.data != NULL);
2942 
2943  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2944  assert(polynomialdata != NULL);
2945 
2946  SCIPintervalSet(result, polynomialdata->constant);
2947 
2948  for( i = 0; i < polynomialdata->nmonomials; ++i )
2949  {
2950  monomialdata = polynomialdata->monomials[i];
2951  assert(monomialdata != NULL);
2952 
2953  SCIPintervalSet(&monomialval, monomialdata->coef);
2954  for( j = 0; j < monomialdata->nfactors && !SCIPintervalIsEntire(infinity, monomialval); ++j )
2955  {
2956  assert(monomialdata->childidxs[j] >= 0);
2957  assert(monomialdata->childidxs[j] < nargs);
2958 
2959  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2960 
2961  exponent = monomialdata->exponents[j];
2962 
2963  /* cover some special exponents separately to avoid calling expensive pow function */
2964  if( exponent == 0.0 )
2965  continue;
2966 
2967  if( exponent == 1.0 )
2968  {
2969  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2970  continue;
2971  }
2972 
2973  if( exponent == 2.0 )
2974  {
2975  SCIPintervalSquare(infinity, &childval, childval);
2976  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2977  continue;
2978  }
2979 
2980  if( exponent == 0.5 )
2981  {
2982  SCIPintervalSquareRoot(infinity, &childval, childval);
2983  if( SCIPintervalIsEmpty(infinity, childval) )
2984  {
2985  SCIPintervalSetEmpty(result);
2986  break;
2987  }
2988  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2989  continue;
2990  }
2991  else if( exponent == -1.0 )
2992  {
2993  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2994  }
2995  else if( exponent == -2.0 )
2996  {
2997  SCIPintervalSquare(infinity, &childval, childval);
2998  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2999  }
3000  else
3001  {
3002  SCIPintervalPowerScalar(infinity, &childval, childval, exponent);
3003  if( SCIPintervalIsEmpty(infinity, childval) )
3004  {
3005  SCIPintervalSetEmpty(result);
3006  return SCIP_OKAY;
3007  }
3008  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
3009  }
3010 
3011  /* the cases in which monomialval gets empty should have been catched */
3012  assert(!SCIPintervalIsEmpty(infinity, monomialval));
3013  }
3014 
3015  SCIPintervalAdd(infinity, result, *result, monomialval);
3016  }
3017 
3018  return SCIP_OKAY;
3019 }
3020 
3021 /** curvature for EXPR_POLYNOMIAL */
3022 static
3023 SCIP_DECL_EXPRCURV( exprcurvPolynomial )
3024 { /*lint --e{715}*/
3026  SCIP_EXPRDATA_MONOMIAL** monomials;
3027  SCIP_EXPRDATA_MONOMIAL* monomial;
3028  int nmonomials;
3029  int i;
3030 
3031  assert(result != NULL);
3032  assert(argcurv != NULL);
3033  assert(argbounds != NULL);
3034 
3035  data = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3036  assert(data != NULL);
3037 
3038  monomials = data->monomials;
3039  nmonomials = data->nmonomials;
3040 
3041  *result = SCIP_EXPRCURV_LINEAR;
3042 
3043  for( i = 0; i < nmonomials && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
3044  {
3045  /* we assume that some simplifier was running, so that monomials do not have constants in their factors and such that all factors are different
3046  * (result would still be correct)
3047  */
3048  monomial = monomials[i];
3049  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(monomial->coef, SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, monomial->childidxs, argcurv, argbounds)));
3050  }
3051 
3052  return SCIP_OKAY;
3053 }
3054 
3055 /** expression data copy for EXPR_POLYNOMIAL */
3056 static
3057 SCIP_DECL_EXPRCOPYDATA( exprCopyDataPolynomial )
3058 { /*lint --e{715}*/
3059  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata;
3060  SCIP_EXPRDATA_POLYNOMIAL* targetpolynomialdata;
3061 
3062  assert(blkmem != NULL);
3063  assert(opdatatarget != NULL);
3064 
3065  sourcepolynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdatasource.data;
3066  assert(sourcepolynomialdata != NULL);
3067 
3068  SCIP_CALL( polynomialdataCopy(blkmem, &targetpolynomialdata, sourcepolynomialdata) );
3069 
3070  opdatatarget->data = (void*)targetpolynomialdata;
3071 
3072  return SCIP_OKAY;
3073 }
3074 
3075 /** expression data free for EXPR_POLYNOMIAL */
3076 static
3077 SCIP_DECL_EXPRFREEDATA( exprFreeDataPolynomial )
3078 { /*lint --e{715}*/
3079  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3080 
3081  assert(blkmem != NULL);
3082 
3083  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3084  assert(polynomialdata != NULL);
3085 
3086  polynomialdataFree(blkmem, &polynomialdata);
3087 }
3088 
3089 /** point evaluation for user expression */
3090 static
3091 SCIP_DECL_EXPREVAL( exprevalUser )
3092 { /*lint --e{715}*/
3093  SCIP_EXPRDATA_USER* exprdata;
3094 
3095  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3096 
3097  SCIP_CALL( exprdata->eval(exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3098 
3099  return SCIP_OKAY;
3100 }
3101 
3102 /** interval evaluation for user expression */
3103 static
3104 SCIP_DECL_EXPRINTEVAL( exprevalIntUser )
3105 { /*lint --e{715}*/
3106  SCIP_EXPRDATA_USER* exprdata;
3107 
3108  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3109 
3110  if( exprdata->inteval != NULL )
3111  {
3112  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3113  }
3114  else
3115  {
3116  /* if user does not provide interval evaluation, then return a result that is always correct */
3118  }
3119 
3120  return SCIP_OKAY;
3121 }
3122 
3123 /** curvature check for user expression */
3124 static
3125 SCIP_DECL_EXPRCURV( exprcurvUser )
3126 {
3127  SCIP_EXPRDATA_USER* exprdata;
3128 
3129  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3130 
3131  if( exprdata->curv != NULL )
3132  {
3133  SCIP_CALL( exprdata->curv(infinity, exprdata->userdata, nargs, argbounds, argcurv, result) );
3134  }
3135  else
3136  {
3137  /* if user does not provide curvature check, then return unknown (which is handled like indefinite) */
3138  *result = SCIP_EXPRCURV_UNKNOWN;
3139  }
3140 
3141  return SCIP_OKAY;
3142 }
3143 
3144 /** data copy for user expression */
3145 static
3146 SCIP_DECL_EXPRCOPYDATA( exprCopyDataUser )
3147 {
3148  SCIP_EXPRDATA_USER* exprdatasource;
3149  SCIP_EXPRDATA_USER* exprdatatarget;
3150 
3151  assert(blkmem != NULL);
3152  assert(opdatatarget != NULL);
3153 
3154  exprdatasource = (SCIP_EXPRDATA_USER*)opdatasource.data;
3155  assert(exprdatasource != NULL);
3156 
3157  /* duplicate expression data */
3158  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, &exprdatatarget, exprdatasource) );
3159 
3160  /* duplicate user expression data, if any */
3161  if( exprdatasource->copydata != NULL )
3162  {
3163  SCIP_CALL( exprdatasource->copydata(blkmem, nchildren, exprdatasource->userdata, &exprdatatarget->userdata) );
3164  }
3165  else
3166  {
3167  /* if no copy function for data, then there has to be no data */
3168  assert(exprdatatarget->userdata == NULL);
3169  }
3170 
3171  opdatatarget->data = (void*)exprdatatarget;
3172 
3173  return SCIP_OKAY;
3174 }
3175 
3176 /** data free for user expression */
3177 static
3178 SCIP_DECL_EXPRFREEDATA( exprFreeDataUser )
3179 {
3180  SCIP_EXPRDATA_USER* exprdata;
3181 
3182  assert(blkmem != NULL);
3183 
3184  exprdata = (SCIP_EXPRDATA_USER*)opdata.data;
3185 
3186  /* free user expression data, if any */
3187  if( exprdata->freedata != NULL )
3188  {
3189  exprdata->freedata(blkmem, nchildren, exprdata->userdata);
3190  }
3191  else
3192  {
3193  assert(exprdata->userdata == NULL);
3194  }
3195 
3196  /* free expression data */
3197  BMSfreeBlockMemory(blkmem, &exprdata);
3198 }
3199 
3200 /** element in table of expression operands */
3201 struct exprOpTableElement
3202 {
3203  const char* name; /**< name of operand (used for printing) */
3204  int nargs; /**< number of arguments (negative if not fixed) */
3205  SCIP_DECL_EXPREVAL ((*eval)); /**< evaluation function */
3206  SCIP_DECL_EXPRINTEVAL ((*inteval)); /**< interval evaluation function */
3207  SCIP_DECL_EXPRCURV ((*curv)); /**< curvature check function */
3208  SCIP_DECL_EXPRCOPYDATA ((*copydata)); /**< expression data copy function, or NULL to only opdata union */
3209  SCIP_DECL_EXPRFREEDATA ((*freedata)); /**< expression data free function, or NULL if nothing to free */
3210 };
3211 
3212 #define EXPROPEMPTY {NULL, -1, NULL, NULL, NULL, NULL, NULL}
3213 
3214 /** table containing for each operand the name, the number of children, and some evaluation functions */
3215 static
3216 struct exprOpTableElement exprOpTable[] =
3217  {
3218  EXPROPEMPTY,
3219  { "variable", 0, exprevalVar, exprevalIntVar, exprcurvVar, NULL, NULL },
3220  { "constant", 0, exprevalConst, exprevalIntConst, exprcurvConst, NULL, NULL },
3221  { "parameter", 0, exprevalParam, exprevalIntParam, exprcurvParam, NULL, NULL },
3223  { "plus", 2, exprevalPlus, exprevalIntPlus, exprcurvPlus, NULL, NULL },
3224  { "minus", 2, exprevalMinus, exprevalIntMinus, exprcurvMinus, NULL, NULL },
3225  { "mul", 2, exprevalMult, exprevalIntMult, exprcurvMult, NULL, NULL },
3226  { "div", 2, exprevalDiv, exprevalIntDiv, exprcurvDiv, NULL, NULL },
3227  { "sqr", 1, exprevalSquare, exprevalIntSquare, exprcurvSquare, NULL, NULL },
3228  { "sqrt", 1, exprevalSquareRoot, exprevalIntSquareRoot, exprcurvSquareRoot, NULL, NULL },
3229  { "realpower", 1, exprevalRealPower, exprevalIntRealPower, exprcurvRealPower, NULL, NULL },
3230  { "intpower", 1, exprevalIntPower, exprevalIntIntPower, exprcurvIntPower, NULL, NULL },
3231  { "signpower", 1, exprevalSignPower, exprevalIntSignPower, exprcurvSignPower, NULL, NULL },
3232  { "exp", 1, exprevalExp, exprevalIntExp, exprcurvExp, NULL, NULL },
3233  { "log", 1, exprevalLog, exprevalIntLog, exprcurvLog, NULL, NULL },
3234  { "sin", 1, exprevalSin, exprevalIntSin, exprcurvSin, NULL, NULL },
3235  { "cos", 1, exprevalCos, exprevalIntCos, exprcurvCos, NULL, NULL },
3236  { "tan", 1, exprevalTan, exprevalIntTan, exprcurvTan, NULL, NULL },
3237  /* { "erf", 1, exprevalErf, exprevalIntErf, exprcurvErf, NULL, NULL }, */
3238  /* { "erfi", 1, exprevalErfi, exprevalIntErfi exprcurvErfi, NULL, NULL }, */
3240  { "min", 2, exprevalMin, exprevalIntMin, exprcurvMin, NULL, NULL },
3241  { "max", 2, exprevalMax, exprevalIntMax, exprcurvMax, NULL, NULL },
3242  { "abs", 1, exprevalAbs, exprevalIntAbs, exprcurvAbs, NULL, NULL },
3243  { "sign", 1, exprevalSign, exprevalIntSign, exprcurvSign, NULL, NULL },
3249  { "sum", -2, exprevalSum, exprevalIntSum, exprcurvSum, NULL, NULL },
3250  { "prod", -2, exprevalProduct, exprevalIntProduct, exprcurvProduct, NULL, NULL },
3251  { "linear", -2, exprevalLinear, exprevalIntLinear, exprcurvLinear, exprCopyDataLinear, exprFreeDataLinear },
3252  { "quadratic", -2, exprevalQuadratic, exprevalIntQuadratic, exprcurvQuadratic, exprCopyDataQuadratic, exprFreeDataQuadratic },
3253  { "polynomial", -2, exprevalPolynomial, exprevalIntPolynomial, exprcurvPolynomial, exprCopyDataPolynomial, exprFreeDataPolynomial },
3254  { "user", -2, exprevalUser, exprevalIntUser, exprcurvUser, exprCopyDataUser, exprFreeDataUser }
3255  };
3256 
3257 /**@} */
3258 
3259 /**@name Expression operand methods */
3260 /**@{ */
3261 
3262 /** gives the name of an operand as string */
3263 const char* SCIPexpropGetName(
3264  SCIP_EXPROP op /**< expression operand */
3265  )
3266 {
3267  assert(op < SCIP_EXPR_LAST);
3268 
3269  return exprOpTable[op].name;
3270 }
3271 
3272 /** gives the number of children of a simple operand */
3274  SCIP_EXPROP op /**< expression operand */
3275  )
3276 {
3277  assert(op < SCIP_EXPR_LAST);
3278 
3279  return exprOpTable[op].nargs;
3280 }
3281 
3282 /**@} */
3283 
3284 /**@name Expressions private methods */
3285 /**@{ */
3286 
3287 /** creates an expression
3288  *
3289  * Note, that the expression is allocated but for the children only the pointer is copied.
3290  */
3291 static
3293  BMS_BLKMEM* blkmem, /**< block memory data structure */
3294  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
3295  SCIP_EXPROP op, /**< operand of expression */
3296  int nchildren, /**< number of children */
3297  SCIP_EXPR** children, /**< children */
3298  SCIP_EXPROPDATA opdata /**< operand data */
3299  )
3300 {
3301  assert(blkmem != NULL);
3302  assert(expr != NULL);
3303  assert(children != NULL || nchildren == 0);
3304  assert(children == NULL || nchildren > 0);
3305 
3306  SCIP_ALLOC( BMSallocBlockMemory(blkmem, expr) );
3307 
3308  (*expr)->op = op;
3309  (*expr)->nchildren = nchildren;
3310  (*expr)->children = children;
3311  (*expr)->data = opdata;
3312 
3313  return SCIP_OKAY;
3314 }
3315 
3316 /** tries to convert a given (operator,operatordata) pair into a polynomial operator with corresponding data
3317  *
3318  * Does not do this for constants.
3319  * If conversion is not possible or operator is already polynomial, *op and *data are
3320  * left untouched.
3321  */
3322 static
3324  BMS_BLKMEM* blkmem, /**< block memory */
3325  SCIP_EXPROP* op, /**< pointer to expression operator */
3326  SCIP_EXPROPDATA* data, /**< pointer to expression data */
3327  int nchildren /**< number of children of operator */
3328  )
3329 {
3330  assert(blkmem != NULL);
3331  assert(op != NULL);
3332  assert(data != NULL);
3333 
3334  switch( *op )
3335  {
3336  case SCIP_EXPR_VARIDX:
3337  case SCIP_EXPR_PARAM:
3338  case SCIP_EXPR_CONST:
3339  break;
3340 
3341  case SCIP_EXPR_PLUS:
3342  {
3343  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3344  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3345  int childidx;
3346  SCIP_Real exponent;
3347 
3348  assert(nchildren == 2);
3349 
3350  /* create monomial for first child */
3351  childidx = 0;
3352  exponent = 1.0;
3353  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3354 
3355  /* create monomial for second child */
3356  childidx = 1;
3357  exponent = 1.0;
3358  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], 1.0, 1, &childidx, &exponent) );
3359 
3360  /* create polynomial for sum of children */
3361  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3362 
3363  *op = SCIP_EXPR_POLYNOMIAL;
3364  data->data = (void*)polynomialdata;
3365 
3366  break;
3367  }
3368 
3369  case SCIP_EXPR_MINUS:
3370  {
3371  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3372  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3373  int childidx;
3374  SCIP_Real exponent;
3375 
3376  assert(nchildren == 2);
3377 
3378  /* create monomial for first child */
3379  childidx = 0;
3380  exponent = 1.0;
3381  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3382 
3383  /* create monomial for second child */
3384  childidx = 1;
3385  exponent = 1.0;
3386  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], -1.0, 1, &childidx, &exponent) );
3387 
3388  /* create polynomial for difference of children */
3389  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3390 
3391  *op = SCIP_EXPR_POLYNOMIAL;
3392  data->data = (void*)polynomialdata;
3393 
3394  break;
3395  }
3396 
3397  case SCIP_EXPR_MUL:
3398  {
3399  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3400  SCIP_EXPRDATA_MONOMIAL* monomial;
3401  int childidx[2];
3402  SCIP_Real exponent[2];
3403 
3404  assert(nchildren == 2);
3405 
3406  /* create monomial for product of children */
3407  childidx[0] = 0;
3408  childidx[1] = 1;
3409  exponent[0] = 1.0;
3410  exponent[1] = 1.0;
3411  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3412 
3413  /* create polynomial */
3414  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3415 
3416  *op = SCIP_EXPR_POLYNOMIAL;
3417  data->data = (void*)polynomialdata;
3418 
3419  break;
3420  }
3421 
3422  case SCIP_EXPR_DIV:
3423  {
3424  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3425  SCIP_EXPRDATA_MONOMIAL* monomial;
3426  int childidx[2];
3427  SCIP_Real exponent[2];
3428 
3429  assert(nchildren == 2);
3430 
3431  /* create monomial for division of children */
3432  childidx[0] = 0;
3433  childidx[1] = 1;
3434  exponent[0] = 1.0;
3435  exponent[1] = -1.0;
3436  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3437 
3438  /* create polynomial */
3439  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3440 
3441  *op = SCIP_EXPR_POLYNOMIAL;
3442  data->data = (void*)polynomialdata;
3443 
3444  break;
3445  }
3446 
3447  case SCIP_EXPR_SQUARE:
3448  {
3449  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3450  SCIP_EXPRDATA_MONOMIAL* monomial;
3451  int childidx;
3452  SCIP_Real exponent;
3453 
3454  assert(nchildren == 1);
3455 
3456  /* create monomial for square of child */
3457  childidx = 0;
3458  exponent = 2.0;
3459  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3460 
3461  /* create polynomial */
3462  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3463 
3464  *op = SCIP_EXPR_POLYNOMIAL;
3465  data->data = (void*)polynomialdata;
3466 
3467  break;
3468  }
3469 
3470  case SCIP_EXPR_SQRT:
3471  {
3472  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3473  SCIP_EXPRDATA_MONOMIAL* monomial;
3474  int childidx;
3475  SCIP_Real exponent;
3476 
3477  assert(nchildren == 1);
3478 
3479  /* create monomial for square root of child */
3480  childidx = 0;
3481  exponent = 0.5;
3482  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3483 
3484  /* create polynomial */
3485  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3486 
3487  *op = SCIP_EXPR_POLYNOMIAL;
3488  data->data = (void*)polynomialdata;
3489 
3490  break;
3491  }
3492 
3493  case SCIP_EXPR_REALPOWER:
3494  {
3495  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3496  SCIP_EXPRDATA_MONOMIAL* monomial;
3497  int childidx;
3498 
3499  assert(nchildren == 1);
3500 
3501  /* convert to child0 to the power of exponent */
3502 
3503  /* create monomial for power of first child */
3504  childidx = 0;
3505  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &data->dbl) );
3506 
3507  /* create polynomial */
3508  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3509 
3510  *op = SCIP_EXPR_POLYNOMIAL;
3511  data->data = (void*)polynomialdata;
3512 
3513  break;
3514  }
3515 
3516  case SCIP_EXPR_SIGNPOWER:
3517  {
3518  SCIP_Real exponent;
3519 
3520  assert(nchildren == 1);
3521 
3522  /* check if exponent is an odd integer */
3523  exponent = data->dbl;
3524  if( EPSISINT(exponent, 0.0) && (int)exponent % 2 != 0 ) /*lint !e835*/
3525  {
3526  /* convert to child0 to the power of exponent, since sign is kept by taking power */
3527  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3528  SCIP_EXPRDATA_MONOMIAL* monomial;
3529  int childidx;
3530 
3531  /* create monomial for power of first child */
3532  childidx = 0;
3533  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3534 
3535  /* create polynomial */
3536  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3537 
3538  *op = SCIP_EXPR_POLYNOMIAL;
3539  data->data = (void*)polynomialdata;
3540  }
3541  /* if exponent is not an odd integer constant, then keep it as signpower expression */
3542  break;
3543  }
3544 
3545  case SCIP_EXPR_INTPOWER:
3546  {
3547  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3548  SCIP_EXPRDATA_MONOMIAL* monomial;
3549  int childidx;
3550  SCIP_Real exponent;
3551 
3552  assert(nchildren == 1);
3553 
3554  /* create monomial for power of child */
3555  childidx = 0;
3556  exponent = data->intval;
3557  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3558 
3559  /* create polynomial */
3560  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3561 
3562  *op = SCIP_EXPR_POLYNOMIAL;
3563  data->data = (void*)polynomialdata;
3564 
3565  break;
3566  }
3567 
3568  case SCIP_EXPR_EXP:
3569  case SCIP_EXPR_LOG:
3570  case SCIP_EXPR_SIN:
3571  case SCIP_EXPR_COS:
3572  case SCIP_EXPR_TAN:
3573  /* case SCIP_EXPR_ERF: */
3574  /* case SCIP_EXPR_ERFI: */
3575  case SCIP_EXPR_MIN:
3576  case SCIP_EXPR_MAX:
3577  case SCIP_EXPR_ABS:
3578  case SCIP_EXPR_SIGN:
3579  case SCIP_EXPR_USER:
3580  break;
3581 
3582  case SCIP_EXPR_SUM:
3583  {
3584  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3585  SCIP_EXPRDATA_MONOMIAL* monomial;
3586  int childidx;
3587  int i;
3588  SCIP_Real exponent;
3589 
3590  /* create empty polynomial */
3591  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, 0.0, FALSE) );
3592  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3593  assert(polynomialdata->monomialssize >= nchildren);
3594 
3595  /* add summands as monomials */
3596  childidx = 0;
3597  exponent = 1.0;
3598  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3599  for( i = 0; i < nchildren; ++i )
3600  {
3601  monomial->childidxs[0] = i;
3602  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3603  }
3604  SCIPexprFreeMonomial(blkmem, &monomial);
3605 
3606  *op = SCIP_EXPR_POLYNOMIAL;
3607  data->data = (void*)polynomialdata;
3608 
3609  break;
3610  }
3611 
3612  case SCIP_EXPR_PRODUCT:
3613  {
3614  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3615  SCIP_EXPRDATA_MONOMIAL* monomial;
3616  int childidx;
3617  int i;
3618  SCIP_Real exponent;
3619 
3620  /* create monomial */
3621  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 0, NULL, NULL) );
3622  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, nchildren) );
3623  exponent = 1.0;
3624  for( i = 0; i < nchildren; ++i )
3625  {
3626  childidx = i;
3627  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
3628  }
3629 
3630  /* create polynomial */
3631  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3632 
3633  *op = SCIP_EXPR_POLYNOMIAL;
3634  data->data = (void*)polynomialdata;
3635 
3636  break;
3637  }
3638 
3639  case SCIP_EXPR_LINEAR:
3640  {
3641  SCIP_Real* lineardata;
3642  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3643  SCIP_EXPRDATA_MONOMIAL* monomial;
3644  int childidx;
3645  int i;
3646  SCIP_Real exponent;
3647 
3648  /* get coefficients of linear term */
3649  lineardata = (SCIP_Real*)data->data;
3650  assert(lineardata != NULL);
3651 
3652  /* create polynomial consisting of constant from linear term */
3653  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, lineardata[nchildren], FALSE) );
3654  /* ensure space for linear coefficients */
3655  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3656  assert(polynomialdata->monomialssize >= nchildren);
3657 
3658  /* add summands as monomials */
3659  childidx = 0;
3660  exponent = 1.0;
3661  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3662  for( i = 0; i < nchildren; ++i )
3663  {
3664  monomial->coef = lineardata[i];
3665  monomial->childidxs[0] = i;
3666  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3667  }
3668  SCIPexprFreeMonomial(blkmem, &monomial);
3669 
3670  /* free linear expression data */
3671  exprFreeDataLinear(blkmem, nchildren, *data);
3672 
3673  *op = SCIP_EXPR_POLYNOMIAL;
3674  data->data = (void*)polynomialdata;
3675 
3676  break;
3677  }
3678 
3679  case SCIP_EXPR_QUADRATIC:
3680  {
3681  SCIP_EXPRDATA_QUADRATIC* quaddata;
3682  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3683  SCIP_EXPRDATA_MONOMIAL* squaremonomial;
3684  SCIP_EXPRDATA_MONOMIAL* bilinmonomial;
3685  SCIP_EXPRDATA_MONOMIAL* linmonomial;
3686  int childidx[2];
3687  SCIP_Real exponent[2];
3688  int i;
3689 
3690  /* get data of quadratic expression */
3691  quaddata = (SCIP_EXPRDATA_QUADRATIC*)data->data;
3692  assert(quaddata != NULL);
3693 
3694  /* create empty polynomial */
3695  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, quaddata->constant, FALSE) );
3696  /* ensure space for linear and quadratic terms */
3697  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, (quaddata->lincoefs != NULL ? nchildren : 0) + quaddata->nquadelems) );
3698  assert(polynomialdata->monomialssize >= quaddata->nquadelems);
3699 
3700  childidx[0] = 0;
3701  childidx[1] = 0;
3702 
3703  /* create monomial templates */
3704  exponent[0] = 2.0;
3705  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &squaremonomial, 1.0, 1, childidx, exponent) );
3706  exponent[0] = 1.0;
3707  exponent[1] = 1.0;
3708  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &bilinmonomial, 1.0, 2, childidx, exponent) );
3709  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &linmonomial, 1.0, 1, childidx, exponent) );
3710 
3711  /* add linear terms as monomials */
3712  if( quaddata->lincoefs != NULL )
3713  for( i = 0; i < nchildren; ++i )
3714  if( quaddata->lincoefs[i] != 0.0 )
3715  {
3716  linmonomial->childidxs[0] = i;
3717  linmonomial->coef = quaddata->lincoefs[i];
3718  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &linmonomial, TRUE) );
3719  }
3720 
3721  /* add quadratic terms as monomials */
3722  for( i = 0; i < quaddata->nquadelems; ++i )
3723  {
3724  if( quaddata->quadelems[i].idx1 == quaddata->quadelems[i].idx2 )
3725  {
3726  squaremonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3727  squaremonomial->coef = quaddata->quadelems[i].coef;
3728  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &squaremonomial, TRUE) );
3729  }
3730  else
3731  {
3732  bilinmonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3733  bilinmonomial->childidxs[1] = quaddata->quadelems[i].idx2;
3734  bilinmonomial->coef = quaddata->quadelems[i].coef;
3735  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &bilinmonomial, TRUE) );
3736  }
3737  }
3738  SCIPexprFreeMonomial(blkmem, &squaremonomial);
3739  SCIPexprFreeMonomial(blkmem, &bilinmonomial);
3740  SCIPexprFreeMonomial(blkmem, &linmonomial);
3741 
3742  /* free quadratic expression data */
3743  exprFreeDataQuadratic(blkmem, nchildren, *data);
3744 
3745  *op = SCIP_EXPR_POLYNOMIAL;
3746  data->data = (void*)polynomialdata;
3747 
3748  break;
3749  }
3750 
3751  case SCIP_EXPR_POLYNOMIAL:
3752  case SCIP_EXPR_LAST:
3753  break;
3754  } /*lint !e788*/
3755 
3756  return SCIP_OKAY;
3757 }
3758 
3759 /** converts polynomial expression back into simpler expression, if possible */
3760 static
3762  BMS_BLKMEM* blkmem, /**< block memory data structure */
3763  SCIP_EXPROP* op, /**< pointer to expression operator */
3764  SCIP_EXPROPDATA* data, /**< pointer to expression data holding polynomial data */
3765  int nchildren, /**< number of children of operator */
3766  void** children /**< children array */
3767  )
3768 {
3769  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3770  SCIP_EXPRDATA_MONOMIAL* monomial;
3771  int maxdegree;
3772  int nlinmonomials;
3773  int i;
3774  int j;
3775 
3776  assert(blkmem != NULL);
3777  assert(op != NULL);
3778  assert(*op == SCIP_EXPR_POLYNOMIAL);
3779  assert(data != NULL);
3780  assert(children != NULL || nchildren == 0);
3781 
3782  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)data->data;
3783  assert(polynomialdata != NULL);
3784 
3785  /* make sure monomials are sorted and merged */
3786  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
3787 
3788  /* if no monomials, then leave as it is */
3789  if( polynomialdata->nmonomials == 0 )
3790  return SCIP_OKAY;
3791 
3792  /* check maximal degree of polynomial only - not considering children expressions
3793  * check number of linear monomials */
3794  maxdegree = 0;
3795  nlinmonomials = 0;
3796  for( i = 0; i < polynomialdata->nmonomials; ++i )
3797  {
3798  int monomialdegree;
3799 
3800  monomial = polynomialdata->monomials[i];
3801  assert(monomial != NULL);
3802 
3803  monomialdegree = 0;
3804  for(j = 0; j < monomial->nfactors; ++j )
3805  {
3806  if( !EPSISINT(monomial->exponents[j], 0.0) || monomial->exponents[j] < 0.0 ) /*lint !e835*/
3807  {
3808  monomialdegree = SCIP_EXPR_DEGREEINFINITY;
3809  break;
3810  }
3811 
3812  monomialdegree += (int)EPSROUND(monomial->exponents[j], 0.0); /*lint !e835*/
3813  }
3814 
3815  if( monomialdegree == SCIP_EXPR_DEGREEINFINITY )
3816  {
3817  maxdegree = SCIP_EXPR_DEGREEINFINITY;
3818  break;
3819  }
3820 
3821  if( monomialdegree == 1 )
3822  ++nlinmonomials;
3823 
3824  if( monomialdegree > maxdegree )
3825  maxdegree = monomialdegree;
3826  }
3827  assert(maxdegree > 0 );
3828 
3829  if( maxdegree == 1 )
3830  {
3831  /* polynomial is a linear expression in children */
3832 
3833  /* polynomial simplification and monomial merging should ensure that monomial i corresponds to child i and that there are not unused children */
3834  assert(polynomialdata->nmonomials == nchildren);
3835  assert(polynomialdata->nmonomials == nlinmonomials);
3836 
3837  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3838  {
3839  /* polynomial is addition of two expressions, so turn into SCIP_EXPR_PLUS */
3840  assert(polynomialdata->monomials[0]->nfactors == 1);
3841  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3842  assert(polynomialdata->monomials[1]->nfactors == 1);
3843  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3844 
3845  polynomialdataFree(blkmem, &polynomialdata);
3846  data->data = NULL;
3847 
3848  /* change operator type to PLUS */
3849  *op = SCIP_EXPR_PLUS;
3850 
3851  return SCIP_OKAY;
3852  }
3853 
3854  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == -1.0 )
3855  {
3856  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3857  assert(polynomialdata->monomials[0]->nfactors == 1);
3858  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3859  assert(polynomialdata->monomials[1]->nfactors == 1);
3860  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3861 
3862  polynomialdataFree(blkmem, &polynomialdata);
3863  data->data = NULL;
3864 
3865  /* change operator type to MINUS */
3866  *op = SCIP_EXPR_MINUS;
3867 
3868  return SCIP_OKAY;
3869  }
3870 
3871  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == -1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3872  {
3873  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3874  void* tmp;
3875 
3876  assert(polynomialdata->monomials[0]->nfactors == 1);
3877  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3878  assert(polynomialdata->monomials[1]->nfactors == 1);
3879  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3880 
3881  polynomialdataFree(blkmem, &polynomialdata);
3882  data->data = NULL;
3883 
3884  /* swap children */
3885  tmp = children[1]; /*lint !e613*/
3886  children[1] = children[0]; /*lint !e613*/
3887  children[0] = tmp; /*lint !e613*/
3888 
3889  /* change operator type to MINUS */
3890  *op = SCIP_EXPR_MINUS;
3891 
3892  return SCIP_OKAY;
3893  }
3894 
3895  if( polynomialdata->constant == 0.0 )
3896  {
3897  /* check if all monomials have coefficient 1.0 */
3898  for( i = 0; i < polynomialdata->nmonomials; ++i )
3899  if( polynomialdata->monomials[i]->coef != 1.0 )
3900  break;
3901 
3902  if( i == polynomialdata->nmonomials )
3903  {
3904  /* polynomial is sum of children, so turn into SCIP_EXPR_SUM */
3905 
3906  polynomialdataFree(blkmem, &polynomialdata);
3907  data->data = NULL;
3908 
3909  /* change operator type to MINUS */
3910  *op = SCIP_EXPR_SUM;
3911 
3912  return SCIP_OKAY;
3913  }
3914  }
3915 
3916  /* turn polynomial into linear expression */
3917  {
3918  SCIP_Real* lindata;
3919 
3920  /* monomial merging should ensure that each child appears in at most one monomial,
3921  * that monomials are ordered according to the child index, and that constant monomials have been removed
3922  */
3923 
3924  /* setup data of linear expression */
3925  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &lindata, polynomialdata->nmonomials + 1) );
3926 
3927  for( i = 0; i < polynomialdata->nmonomials; ++i )
3928  {
3929  assert(polynomialdata->monomials[i]->childidxs[0] == i);
3930  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3931  lindata[i] = polynomialdata->monomials[i]->coef; /*lint !e644*/
3932  }
3933  lindata[i] = polynomialdata->constant;
3934 
3935  polynomialdataFree(blkmem, &polynomialdata);
3936  *op = SCIP_EXPR_LINEAR;
3937  data->data = (void*)lindata;
3938 
3939  return SCIP_OKAY;
3940  }
3941  }
3942 
3943  if( maxdegree == 2 && (polynomialdata->nmonomials > 1 || polynomialdata->constant != 0.0 || polynomialdata->monomials[0]->coef != 1.0) )
3944  {
3945  /* 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 */
3946  SCIP_EXPRDATA_QUADRATIC* quaddata;
3947  int quadelemidx;
3948 
3949  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &quaddata) );
3950  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->quadelems, polynomialdata->nmonomials - nlinmonomials) );
3951  quaddata->nquadelems = polynomialdata->nmonomials - nlinmonomials;
3952  quaddata->constant = polynomialdata->constant;
3953  quaddata->sorted = FALSE; /* quadratic data is sorted different than polynomials */
3954 
3955  if( nlinmonomials > 0 )
3956  {
3957  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->lincoefs, nchildren) );
3958  BMSclearMemoryArray(quaddata->lincoefs, nchildren);
3959  }
3960  else
3961  quaddata->lincoefs = NULL;
3962 
3963  quadelemidx = 0;
3964  for( i = 0; i < polynomialdata->nmonomials; ++i )
3965  {
3966  assert(polynomialdata->monomials[i]->nfactors == 1 || polynomialdata->monomials[i]->nfactors == 2);
3967  if( polynomialdata->monomials[i]->nfactors == 1 )
3968  {
3969  if( polynomialdata->monomials[i]->exponents[0] == 1.0 )
3970  {
3971  /* monomial is a linear term */
3972  assert(quaddata->lincoefs != NULL);
3973  quaddata->lincoefs[polynomialdata->monomials[i]->childidxs[0]] += polynomialdata->monomials[i]->coef;
3974  }
3975  else
3976  {
3977  /* monomial should be a square term */
3978  assert(polynomialdata->monomials[i]->exponents[0] == 2.0);
3979  assert(quadelemidx < quaddata->nquadelems);
3980  quaddata->quadelems[quadelemidx].idx1 = polynomialdata->monomials[i]->childidxs[0];
3981  quaddata->quadelems[quadelemidx].idx2 = polynomialdata->monomials[i]->childidxs[0];
3982  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3983  ++quadelemidx;
3984  }
3985  }
3986  else
3987  {
3988  /* monomial should be a bilinear term */
3989  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3990  assert(polynomialdata->monomials[i]->exponents[1] == 1.0);
3991  assert(quadelemidx < quaddata->nquadelems);
3992  quaddata->quadelems[quadelemidx].idx1 = MIN(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3993  quaddata->quadelems[quadelemidx].idx2 = MAX(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3994  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3995  ++quadelemidx;
3996  }
3997  }
3998  assert(quadelemidx == quaddata->nquadelems);
3999 
4000  polynomialdataFree(blkmem, &polynomialdata);
4001 
4002  *op = SCIP_EXPR_QUADRATIC;
4003  data->data = (void*)quaddata;
4004 
4005  return SCIP_OKAY;
4006  }
4007 
4008  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 1 && polynomialdata->monomials[0]->coef == 1.0 )
4009  {
4010  /* polynomial is product of children */
4011  monomial = polynomialdata->monomials[0];
4012  assert(monomial->nfactors == nchildren);
4013 
4014  if( monomial->nfactors == 1 )
4015  {
4016  /* polynomial is x^k for some k */
4017  assert(monomial->exponents[0] != 1.0); /* should have been handled before */
4018  assert(monomial->childidxs[0] == 0);
4019 
4020  if( monomial->exponents[0] == 2.0 )
4021  {
4022  /* polynomial is x^2, so turn into SCIP_EXPR_SQUARE */
4023 
4024  polynomialdataFree(blkmem, &polynomialdata);
4025  data->data = NULL;
4026 
4027  *op = SCIP_EXPR_SQUARE;
4028 
4029  return SCIP_OKAY;
4030  }
4031 
4032  if( EPSISINT(monomial->exponents[0], 0.0) ) /*lint !e835*/
4033  {
4034  /* k is an integer, so turn into SCIP_EXPR_INTPOWER */
4035  int exponent;
4036 
4037  exponent = (int)EPSROUND(monomial->exponents[0], 0.0); /*lint !e835*/
4038 
4039  polynomialdataFree(blkmem, &polynomialdata);
4040 
4041  *op = SCIP_EXPR_INTPOWER;
4042  data->intval = exponent;
4043 
4044  return SCIP_OKAY;
4045  }
4046 
4047  if( monomial->exponents[0] == 0.5 )
4048  {
4049  /* polynomial is sqrt(x), so turn into SCIP_EXPR_SQRT */
4050 
4051  polynomialdataFree(blkmem, &polynomialdata);
4052  data->data = NULL;
4053 
4054  *op = SCIP_EXPR_SQRT;
4055 
4056  return SCIP_OKAY;
4057  }
4058 
4059  {
4060  /* polynomial is x^a with a some real number, so turn into SCIP_EXPR_REALPOWER */
4061  SCIP_Real exponent;
4062 
4063  exponent = monomial->exponents[0];
4064 
4065  polynomialdataFree(blkmem, &polynomialdata);
4066 
4067  *op = SCIP_EXPR_REALPOWER;
4068  data->dbl = exponent;
4069 
4070  return SCIP_OKAY;
4071  }
4072  }
4073 
4074  if( maxdegree == 2 && monomial->nfactors == 2 )
4075  {
4076  /* polynomial is product of two children, so turn into SCIP_EXPR_MUL */
4077  assert(monomial->exponents[0] == 1.0);
4078  assert(monomial->exponents[1] == 1.0);
4079 
4080  polynomialdataFree(blkmem, &polynomialdata);
4081  data->data = NULL;
4082 
4083  *op = SCIP_EXPR_MUL;
4084 
4085  return SCIP_OKAY;
4086  }
4087 
4088  if( maxdegree == monomial->nfactors )
4089  {
4090  /* polynomial is a product of n children, so turn into SCIP_EXPR_PRODUCT */
4091 
4092  polynomialdataFree(blkmem, &polynomialdata);
4093  data->data = NULL;
4094 
4095  *op = SCIP_EXPR_PRODUCT;
4096 
4097  return SCIP_OKAY;
4098  }
4099 
4100  if( monomial->nfactors == 2 && monomial->exponents[0] == 1.0 && monomial->exponents[1] == -1.0 )
4101  {
4102  /* polynomial is x/y, so turn into SCIP_EXPR_DIV */
4103  assert(monomial->childidxs[0] == 0);
4104  assert(monomial->childidxs[1] == 1);
4105 
4106  polynomialdataFree(blkmem, &polynomialdata);
4107  data->data = NULL;
4108 
4109  *op = SCIP_EXPR_DIV;
4110 
4111  return SCIP_OKAY;
4112  }
4113 
4114  if( monomial->nfactors == 2 && monomial->exponents[0] == -1.0 && monomial->exponents[1] == 1.0 )
4115  {
4116  /* polynomial is y/x, so turn into SCIP_EXPR_DIV */
4117  void* tmp;
4118 
4119  assert(monomial->childidxs[0] == 0);
4120  assert(monomial->childidxs[1] == 1);
4121 
4122  polynomialdataFree(blkmem, &polynomialdata);
4123  data->data = NULL;
4124 
4125  /* swap children */
4126  tmp = children[1]; /*lint !e613*/
4127  children[1] = children[0]; /*lint !e613*/
4128  children[0] = tmp; /*lint !e613*/
4129 
4130  *op = SCIP_EXPR_DIV;
4131 
4132  return SCIP_OKAY;
4133  }
4134  }
4135 
4136  return SCIP_OKAY;
4137 }
4138 
4139 /** adds copies of expressions to the array of children of a sum, product, linear, quadratic, or polynomial expression
4140  *
4141  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
4142  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
4143  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
4144  */
4145 static
4147  BMS_BLKMEM* blkmem, /**< block memory */
4148  SCIP_EXPR* expr, /**< quadratic or polynomial expression */
4149  int nexprs, /**< number of expressions to add */
4150  SCIP_EXPR** exprs, /**< expressions to add */
4151  SCIP_Bool comparechildren, /**< whether to compare expressions with already existing children (no effect for sum and product) */
4152  SCIP_Real eps, /**< which epsilon to use when comparing expressions */
4153  int* childmap /**< array where to store mapping of indices from exprs to children array in expr, or NULL if not of interest */
4154  )
4155 {
4156  int i;
4157 
4158  assert(blkmem != NULL);
4159  assert(expr != NULL);
4160  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);
4161  assert(exprs != NULL || nexprs == 0);
4162 
4163  if( nexprs == 0 )
4164  return SCIP_OKAY;
4165 
4166  switch( expr->op )
4167  {
4168  case SCIP_EXPR_SUM:
4169  case SCIP_EXPR_PRODUCT:
4170  {
4171  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4172  for( i = 0; i < nexprs; ++i )
4173  {
4174  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren + i], exprs[i]) ); /*lint !e613*/
4175  if( childmap != NULL )
4176  childmap[i] = expr->nchildren + i;
4177  }
4178  expr->nchildren += nexprs;
4179 
4180  break;
4181  }
4182 
4183  case SCIP_EXPR_LINEAR:
4184  case SCIP_EXPR_QUADRATIC:
4185  case SCIP_EXPR_POLYNOMIAL:
4186  {
4187  int j;
4188  int orignchildren;
4189  SCIP_Bool existsalready;
4190 
4191  orignchildren = expr->nchildren;
4192  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4193 
4194  for( i = 0; i < nexprs; ++i )
4195  {
4196  existsalready = FALSE;
4197  if( comparechildren )
4198  for( j = 0; j < orignchildren; ++j )
4199  /* during simplification of polynomials, their may be NULL's in children array */
4200  if( expr->children[j] != NULL && SCIPexprAreEqual(expr->children[j], exprs[i], eps) ) /*lint !e613*/
4201  {
4202  existsalready = TRUE;
4203  break;
4204  }
4205 
4206  if( !existsalready )
4207  {
4208  /* add copy of exprs[j] to children array */
4209  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren], exprs[i]) ); /*lint !e613*/
4210  if( childmap != NULL )
4211  childmap[i] = expr->nchildren;
4212  ++expr->nchildren;
4213  }
4214  else
4215  {
4216  if( childmap != NULL )
4217  childmap[i] = j; /*lint !e644*/
4218  if( expr->op == SCIP_EXPR_LINEAR )
4219  {
4220  /* if linear expression, increase coefficient by 1.0 */
4221  ((SCIP_Real*)expr->data.data)[j] += 1.0;
4222  }
4223  }
4224  }
4225 
4226  /* shrink children array to actually used size */
4227  assert(comparechildren || expr->nchildren == orignchildren + nexprs);
4228  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, orignchildren + nexprs, expr->nchildren) );
4229 
4230  if( expr->op == SCIP_EXPR_LINEAR && expr->nchildren > orignchildren )
4231  {
4232  /* if linear expression, then add 1.0 coefficients for new expressions */
4233  SCIP_Real* data;
4234 
4235  data = (SCIP_Real*)expr->data.data;
4236  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, expr->nchildren + 1) );
4237  data[expr->nchildren] = data[orignchildren]; /* move constant from old end to new end */
4238  for( i = orignchildren; i < expr->nchildren; ++i )
4239  data[i] = 1.0;
4240  expr->data.data = (void*)data;
4241  }
4242  else if( expr->op == SCIP_EXPR_QUADRATIC && expr->nchildren > orignchildren )
4243  {
4244  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
4246 
4247  data = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
4248  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, expr->nchildren) );
4249  BMSclearMemoryArray(&data->lincoefs[orignchildren], expr->nchildren - orignchildren); /*lint !e866*/
4250  }
4251 
4252  break;
4253  }
4254 
4255  default:
4256  SCIPerrorMessage("exprsimplifyAddChildren cannot be called for operand %d\n", expr->op);
4257  return SCIP_INVALIDDATA;
4258  } /*lint !e788*/
4259 
4260  return SCIP_OKAY;
4261 }
4262 
4263 /** converts expressions into polynomials, where possible and obvious */
4264 static
4266  BMS_BLKMEM* blkmem, /**< block memory data structure */
4267  SCIP_EXPR* expr /**< expression to convert */
4268  )
4269 {
4270  int i;
4271 
4272  assert(expr != NULL);
4273 
4274  for( i = 0; i < expr->nchildren; ++i )
4275  {
4277  }
4278 
4279  SCIP_CALL( exprConvertToPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren) );
4280 
4281  return SCIP_OKAY;
4282 }
4283 
4284 /** removes duplicate children in a polynomial expression
4285  *
4286  * Leaves NULL's in children array.
4287  */
4288 static
4290  BMS_BLKMEM* blkmem, /**< block memory data structure */
4291  SCIP_EXPR* expr, /**< expression */
4292  SCIP_Real eps /**< threshold for zero */
4293  )
4294 {
4295  SCIP_Bool foundduplicates;
4296  int* childmap;
4297  int i;
4298  int j;
4299 
4300  assert(blkmem != NULL);
4301  assert(expr != NULL);
4302  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4303 
4304  if( expr->nchildren == 0 )
4305  return SCIP_OKAY;
4306 
4307  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4308 
4309  foundduplicates = FALSE;
4310  for( i = 0; i < expr->nchildren; ++i )
4311  {
4312  if( expr->children[i] == NULL )
4313  continue;
4314  childmap[i] = i; /*lint !e644*/
4315 
4316  for( j = i+1; j < expr->nchildren; ++j )
4317  {
4318  if( expr->children[j] == NULL )
4319  continue;
4320 
4321  if( SCIPexprAreEqual(expr->children[i], expr->children[j], eps) )
4322  {
4323  /* forget about expr j and remember that is to be replaced by i */
4324  SCIPexprFreeDeep(blkmem, &expr->children[j]);
4325  childmap[j] = i;
4326  foundduplicates = TRUE;
4327  }
4328  }
4329  }
4330 
4331  /* apply childmap to monomials */
4332  if( foundduplicates )
4334 
4335  /* free childmap */
4336  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4337 
4338  return SCIP_OKAY;
4339 }
4340 
4341 /** eliminates NULL's in children array and shrinks it to actual size */
4342 static
4344  BMS_BLKMEM* blkmem, /**< block memory data structure */
4345  SCIP_EXPR* expr /**< expression */
4346  )
4347 {
4348  int* childmap;
4349  int lastnonnull;
4350  int i;
4351 
4352  assert(blkmem != NULL);
4353  assert(expr != NULL);
4354  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4355 
4356  if( expr->nchildren == 0 )
4357  return SCIP_OKAY;
4358 
4359  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4360 
4361  /* close gaps in children array */
4362  lastnonnull = expr->nchildren-1;
4363  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4364  --lastnonnull;
4365  for( i = 0; i <= lastnonnull; ++i )
4366  {
4367  if( expr->children[i] != NULL )
4368  {
4369  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
4370  continue;
4371  }
4372  assert(expr->children[lastnonnull] != NULL);
4373 
4374  /* move child at lastnonnull to position i */
4375  expr->children[i] = expr->children[lastnonnull];
4376  expr->children[lastnonnull] = NULL;
4377  childmap[lastnonnull] = i;
4378 
4379  /* update lastnonnull */
4380  --lastnonnull;
4381  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4382  --lastnonnull;
4383  }
4384  assert(i > lastnonnull);
4385 
4386  /* apply childmap to monomials */
4387  if( lastnonnull < expr->nchildren-1 )
4389 
4390  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4391 
4392  /* shrink children array */
4393  if( lastnonnull >= 0 )
4394  {
4395  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, lastnonnull+1) );
4396  expr->nchildren = lastnonnull+1;
4397  }
4398  else
4399  {
4400  BMSfreeBlockMemoryArray(blkmem, &expr->children, expr->nchildren);
4401  expr->nchildren = 0;
4402  }
4403 
4404  return SCIP_OKAY;
4405 }
4406 
4407 /** checks which children are still in use and frees those which are not */
4408 static
4410  BMS_BLKMEM* blkmem, /**< block memory data structure */
4411  SCIP_EXPR* expr /**< polynomial expression */
4412  )
4413 {
4414  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4415  SCIP_EXPRDATA_MONOMIAL* monomial;
4416  SCIP_Bool* childinuse;
4417  int i;
4418  int j;
4419 
4420  assert(blkmem != NULL);
4421  assert(expr != NULL);
4422 
4423  if( expr->nchildren == 0 )
4424  return SCIP_OKAY;
4425 
4426  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4427  assert(polynomialdata != NULL);
4428 
4429  /* check which children are still in use */
4430  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, expr->nchildren) );
4431  BMSclearMemoryArray(childinuse, expr->nchildren); /*lint !e644*/
4432  for( i = 0; i < polynomialdata->nmonomials; ++i )
4433  {
4434  monomial = polynomialdata->monomials[i];
4435  assert(monomial != NULL);
4436 
4437  for( j = 0; j < monomial->nfactors; ++j )
4438  {
4439  assert(monomial->childidxs[j] >= 0);
4440  assert(monomial->childidxs[j] < expr->nchildren);
4441  childinuse[monomial->childidxs[j]] = TRUE;
4442  }
4443  }
4444 
4445  /* free children that are not used in any monomial */
4446  for( i = 0; i < expr->nchildren; ++i )
4447  if( expr->children[i] != NULL && !childinuse[i] )
4448  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4449 
4450  BMSfreeBlockMemoryArray(blkmem, &childinuse, expr->nchildren);
4451 
4452  return SCIP_OKAY;
4453 }
4454 
4455 /** flattens polynomials in polynomials, check for constants in non-polynomials expressions
4456  *
4457  * exprsimplifyConvertToPolynomials should have been called before to eliminate simple polynomial operands.
4458  */
4459 static
4461  BMS_BLKMEM* blkmem, /**< block memory data structure */
4462  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4463  SCIP_EXPR* expr, /**< expression */
4464  SCIP_Real eps, /**< threshold, under which values are treat as 0 */
4465  int maxexpansionexponent/**< maximal exponent for which we still expand non-monomial polynomials */
4466  )
4467 {
4468  int i;
4469 
4470  assert(expr != NULL);
4471 
4472  for( i = 0; i < expr->nchildren; ++i )
4473  {
4474  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr->children[i], eps, maxexpansionexponent) );
4475  }
4476 
4477  switch( SCIPexprGetOperator(expr) )
4478  {
4479  case SCIP_EXPR_VARIDX:
4480  case SCIP_EXPR_CONST:
4481  case SCIP_EXPR_PARAM:
4482  case SCIP_EXPR_PLUS:
4483  case SCIP_EXPR_MINUS:
4484  case SCIP_EXPR_MUL:
4485  case SCIP_EXPR_DIV:
4486  case SCIP_EXPR_SQUARE:
4487  case SCIP_EXPR_SQRT:
4488  case SCIP_EXPR_INTPOWER:
4489  case SCIP_EXPR_REALPOWER:
4490  case SCIP_EXPR_SIGNPOWER:
4491  break;
4492 
4493  case SCIP_EXPR_EXP:
4494  case SCIP_EXPR_LOG:
4495  case SCIP_EXPR_SIN:
4496  case SCIP_EXPR_COS:
4497  case SCIP_EXPR_TAN:
4498  /* case SCIP_EXPR_ERF: */
4499  /* case SCIP_EXPR_ERFI: */
4500  case SCIP_EXPR_ABS:
4501  case SCIP_EXPR_SIGN:
4502  {
4503  /* check if argument is a constant */
4504  if( (expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) ||
4505  expr->children[0]->op == SCIP_EXPR_CONST )
4506  {
4507  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4508  SCIP_Real exprval;
4509 
4510  /* since child0 has no children and it's polynomial was flattened, it should have no monomials */
4511  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4512 
4513  /* evaluate expression in constant polynomial */
4514  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4515 
4516  /* create polynomial */
4517  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4518 
4519  expr->op = SCIP_EXPR_POLYNOMIAL;
4520  expr->data.data = (void*)polynomialdata;
4521 
4522  /* forget child */
4523  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4524  BMSfreeBlockMemoryArray(blkmem, &expr->children, 1);
4525  expr->nchildren = 0;
4526  }
4527 
4528  break;
4529  }
4530 
4531  case SCIP_EXPR_MIN:
4532  case SCIP_EXPR_MAX:
4533  {
4534  /* check if both arguments are constants */
4535  if( ((expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) || expr->children[0]->op == SCIP_EXPR_CONST) &&
4536  ((expr->children[1]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[1]) == 0) || expr->children[1]->op == SCIP_EXPR_CONST) )
4537  {
4538  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4539  SCIP_Real exprval;
4540 
4541  /* since children have no children and it's polynomial was flattened, it should have no monomials */
4542  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4543  assert(expr->children[1]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[1]) == 0);
4544 
4545  /* evaluate expression in constants */
4546  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4547 
4548  /* create polynomial */
4549  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4550 
4551  expr->op = SCIP_EXPR_POLYNOMIAL;
4552  expr->data.data = (void*)polynomialdata;
4553 
4554  /* forget children */
4555  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4556  SCIPexprFreeDeep(blkmem, &expr->children[1]);
4557  BMSfreeBlockMemoryArray(blkmem, &expr->children, 2);
4558  expr->nchildren = 0;
4559  }
4560 
4561  break;
4562  }
4563 
4564  case SCIP_EXPR_SUM:
4565  case SCIP_EXPR_PRODUCT:
4566  case SCIP_EXPR_LINEAR:
4567  case SCIP_EXPR_QUADRATIC:
4568  case SCIP_EXPR_USER:
4569  break;
4570 
4571  case SCIP_EXPR_POLYNOMIAL:
4572  {
4573  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4574  SCIP_EXPRDATA_MONOMIAL* monomial;
4575  SCIP_Bool removechild;
4576  int* childmap;
4577  int childmapsize;
4578  int j;
4579 
4580  /* simplify current polynomial */
4582  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4583 
4584  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4585  assert(polynomialdata != NULL);
4586 
4587  SCIPdebugMessage("expand factors in expression ");
4588  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4589  SCIPdebugPrintf("\n");
4590 
4591  childmap = NULL;
4592  childmapsize = 0;
4593 
4594  /* resolve children that are constants
4595  * we do this first, because it reduces the degree and number of factors in the monomials,
4596  * 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
4597  */
4598  for( i = 0; i < expr->nchildren; ++i )
4599  {
4600  if( expr->children[i] == NULL )
4601  continue;
4602 
4603  if( SCIPexprGetOperator(expr->children[i]) != SCIP_EXPR_CONST )
4604  continue;
4605 
4606  removechild = TRUE; /* we intend to delete children[i] */
4607 
4608  if( childmapsize < expr->children[i]->nchildren )
4609  {
4610  int newsize;
4611 
4612  newsize = calcGrowSize(expr->children[i]->nchildren);
4613  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4614  childmapsize = newsize;
4615  }
4616 
4617  /* put constant of child i into every monomial where child i is used */
4618  for( j = 0; j < polynomialdata->nmonomials; ++j )
4619  {
4620  int factorpos;
4621  SCIP_Bool success;
4622 
4623  monomial = polynomialdata->monomials[j];
4624  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4625  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4626 
4627  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4628  {
4629  assert(factorpos >= 0);
4630  assert(factorpos < monomial->nfactors);
4631  /* assert that factors have been merged */
4632  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4633  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4634 
4635  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4636  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4637  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4638 
4639  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && SCIPexprGetOpReal(expr->children[i]) < 0.0 ) /*lint !e835*/
4640  {
4641  /* if constant is negative and our exponent is not integer, then cannot do expansion */
4642  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n",
4643  SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4644  success = FALSE;
4645  }
4646  else
4647  {
4648  monomial->coef *= pow(SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4649 
4650  /* move last factor to position factorpos */
4651  if( factorpos < monomial->nfactors-1 )
4652  {
4653  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
4654  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
4655  }
4656  --monomial->nfactors;
4657  monomial->sorted = FALSE;
4658  polynomialdata->sorted = FALSE;
4659 
4660  success = TRUE;
4661  }
4662 
4663  if( !success )
4664  removechild = FALSE;
4665  }
4666  }
4667 
4668  /* forget about child i, if it is not used anymore */
4669  if( removechild )
4670  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4671 
4672  /* simplify current polynomial again */
4673  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4674  }
4675 
4676  /* try to resolve children that are polynomials itself */
4677  for( i = 0; i < expr->nchildren; ++i )
4678  {
4679  if( expr->children[i] == NULL )
4680  continue;
4681 
4683  continue;
4684 
4685  removechild = TRUE; /* we intend to delete children[i] */
4686 
4687  if( childmapsize < expr->children[i]->nchildren )
4688  {
4689  int newsize;
4690 
4691  newsize = calcGrowSize(expr->children[i]->nchildren);
4692  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4693  childmapsize = newsize;
4694  }
4695 
4696  /* add children of child i */
4697  SCIP_CALL( exprsimplifyAddChildren(blkmem, expr, expr->children[i]->nchildren, expr->children[i]->children, TRUE, eps, childmap) );
4698 
4699  /* put polynomial of child i into every monomial where child i is used */
4700  j = 0;
4701  while( j < polynomialdata->nmonomials )
4702  {
4703  int factorpos;
4704  SCIP_Bool success;
4705 
4706  monomial = polynomialdata->monomials[j];
4707  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4708  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4709 
4710  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4711  {
4712  assert(factorpos >= 0);
4713  assert(factorpos < monomial->nfactors);
4714  /* assert that factors have been merged */
4715  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4716  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4717 
4718  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4719  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4720  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4721 
4722  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
4723  (SCIP_EXPRDATA_POLYNOMIAL*)expr->children[i]->data.data, childmap, maxexpansionexponent, &success) );
4724 
4725  if( !success )
4726  {
4727  removechild = FALSE;
4728  ++j;
4729  }
4730  }
4731  else
4732  ++j;
4733 
4734  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
4735  * we thus repeat with index j, if a factor was successfully expanded
4736  */
4737  }
4738 
4739  /* forget about child i, if it is not used anymore */
4740  if( removechild )
4741  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4742 
4743  /* simplify current polynomial again */
4744  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4745  }
4746 
4747  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
4748 
4749  /* free children that are not in use anymore */
4751 
4752  /* remove NULLs from children array */
4754 
4755  /* if no children left, then it's a constant polynomial -> change into EXPR_CONST */
4756  if( expr->nchildren == 0 )
4757  {
4758  SCIP_Real val;
4759 
4760  /* if no children, then it should also have no monomials */
4761  assert(polynomialdata->nmonomials == 0);
4762 
4763  val = polynomialdata->constant;
4764  polynomialdataFree(blkmem, &polynomialdata);
4765 
4766  expr->op = SCIP_EXPR_CONST;
4767  expr->data.dbl = val;
4768  }
4769 
4770  SCIPdebugMessage("-> ");
4771  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4772  SCIPdebugPrintf("\n");
4773 
4774  break;
4775  }
4776 
4777  case SCIP_EXPR_LAST:
4778  break;
4779  } /*lint !e788*/
4780 
4781  return SCIP_OKAY;
4782 }
4783 
4784 /** separates linear monomials from an expression, if it is a polynomial expression
4785  *
4786  * Separates only those linear terms whose variable is not used otherwise in the expression.
4787  */
4788 static
4790  BMS_BLKMEM* blkmem, /**< block memory data structure */
4791  SCIP_EXPR* expr, /**< expression */
4792  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
4793  int nvars, /**< number of variables in expression */
4794  int* nlinvars, /**< buffer to store number of linear variables in linear part */
4795  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part */
4796  SCIP_Real* lincoefs /**< array to store coefficients of linear part */
4797  )
4798 {
4799  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4800  SCIP_EXPRDATA_MONOMIAL* monomial;
4801  int* varsusage;
4802  int* childusage;
4803  int childidx;
4804  int i;
4805  int j;
4806 
4807  assert(blkmem != NULL);
4808  assert(expr != NULL);
4809  assert(nlinvars != NULL);
4810  assert(linidxs != NULL);
4811  assert(lincoefs != NULL);
4812 
4813  *nlinvars = 0;
4814 
4816  return SCIP_OKAY;
4817 
4818  if( SCIPexprGetNChildren(expr) == 0 )
4819  return SCIP_OKAY;
4820 
4821  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4822  assert(polynomialdata != NULL);
4823 
4824  /* get variable usage */
4825  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &varsusage, nvars) );
4826  BMSclearMemoryArray(varsusage, nvars); /*lint !e644*/
4827  SCIPexprGetVarsUsage(expr, varsusage);
4828 
4829  /* get child usage: how often each child is used in the polynomial */
4830  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childusage, expr->nchildren) );
4831  BMSclearMemoryArray(childusage, expr->nchildren); /*lint !e644*/
4832  for( i = 0; i < polynomialdata->nmonomials; ++i )
4833  {
4834  monomial = polynomialdata->monomials[i];
4835  assert(monomial != NULL);
4836  for( j = 0; j < monomial->nfactors; ++j )
4837  {
4838  assert(monomial->childidxs[j] >= 0);
4839  assert(monomial->childidxs[j] < expr->nchildren);
4840  ++childusage[monomial->childidxs[j]];
4841  }
4842  }
4843 
4844  /* move linear monomials out of polynomial */
4845  for( i = 0; i < polynomialdata->nmonomials; ++i )
4846  {
4847  monomial = polynomialdata->monomials[i];
4848  assert(monomial != NULL);
4849  if( monomial->nfactors != 1 )
4850  continue;
4851  if( monomial->exponents[0] != 1.0 )
4852  continue;
4853  childidx = monomial->childidxs[0];
4854  if( SCIPexprGetOperator(expr->children[childidx]) != SCIP_EXPR_VARIDX )
4855  continue;
4856 
4857  /* we are at a linear monomial in a variable */
4858  assert(SCIPexprGetOpIndex(expr->children[childidx]) < nvars);
4859  if( childusage[childidx] == 1 && varsusage[SCIPexprGetOpIndex(expr->children[childidx])] == 1 )
4860  {
4861  /* if the child expression is not used in another monomial (which would due to merging be not linear)
4862  * and if the variable is not used somewhere else in the tree,
4863  * then move this monomial into linear part and free child
4864  */
4865  linidxs[*nlinvars] = SCIPexprGetOpIndex(expr->children[childidx]);
4866  lincoefs[*nlinvars] = monomial->coef;
4867  ++*nlinvars;
4868 
4869  SCIPexprFreeDeep(blkmem, &expr->children[childidx]);
4870  monomial->coef = 0.0;
4871  monomial->nfactors = 0;
4872  }
4873  }
4874 
4875  BMSfreeBlockMemoryArray(blkmem, &varsusage, nvars);
4876  BMSfreeBlockMemoryArray(blkmem, &childusage, expr->nchildren);
4877 
4878  if( *nlinvars > 0 )
4879  {
4880  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
4881  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, FALSE);
4883  }
4884 
4885  return SCIP_OKAY;
4886 }
4887 
4888 /** converts polynomial expressions back into simpler expressions, where possible */
4889 static
4891  BMS_BLKMEM* blkmem, /**< block memory data structure */
4892  SCIP_EXPR* expr /**< expression to convert back */
4893  )
4894 {
4895  int i;
4896 
4897  assert(blkmem != NULL);
4898  assert(expr != NULL);
4899 
4900  for( i = 0; i < expr->nchildren; ++i )
4901  {
4903  }
4904 
4905  if( expr->op != SCIP_EXPR_POLYNOMIAL )
4906  return SCIP_OKAY;
4907 
4908  SCIP_CALL( exprUnconvertPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren, (void**)expr->children) );
4909 
4910  return SCIP_OKAY;
4911 }
4912 
4913 static
4914 SCIP_DECL_HASHGETKEY( exprparseVarTableGetKey )
4915 { /*lint --e{715}*/
4916  return (void*)((char*)elem + sizeof(int));
4917 }
4918 
4919 /** parses a variable name from a string and creates corresponding expression
4920  *
4921  * Creates a new variable index if variable not seen before, updates varnames and vartable structures.
4922  */
4923 static
4925  BMS_BLKMEM* blkmem, /**< block memory data structure */
4926  const char** str, /**< pointer to the string to be parsed */
4927  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
4928  int* nvars, /**< running number of encountered variables so far */
4929  int** varnames, /**< pointer to buffer to store new variable names */
4930  int* varnameslength, /**< pointer to length of the varnames buffer array */
4931  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
4932  SCIP_Real coefficient, /**< coefficient to be used when creating the expression */
4933  const char* varnameendptr /**< if a <varname> should be parsed, set this to NULL. Then, str points to the '<'
4934  else, str should point to the first letter of the varname, and varnameendptr should
4935  point one char behind the last char of the variable name */
4936  )
4937 {
4938  int namelength;
4939  int varidx;
4940  char varname[SCIP_MAXSTRLEN];
4941  void* element;
4942 
4943  assert(blkmem != NULL);
4944  assert(str != NULL);
4945  assert(expr != NULL);
4946  assert(nvars != NULL);
4947  assert(varnames != NULL);
4948  assert(vartable != NULL);
4949 
4950  if( varnameendptr == NULL )
4951  {
4952  ++*str;
4953  varnameendptr = *str;
4954  while( varnameendptr[0] != '>' )
4955  ++varnameendptr;
4956  }
4957 
4958  namelength = varnameendptr - *str; /*lint !e712*/
4959  if( namelength >= SCIP_MAXSTRLEN )
4960  {
4961  SCIPerrorMessage("Variable name %.*s is too long for buffer in exprparseReadVariable.\n", namelength, str);
4962  return SCIP_READERROR;
4963  }
4964 
4965  memcpy(varname, *str, namelength * sizeof(char));
4966  varname[namelength] = '\0';
4967 
4968  element = SCIPhashtableRetrieve(vartable, varname);
4969  if( element != NULL )
4970  {
4971  /* variable is old friend */
4972  assert(strcmp((char*)element + sizeof(int), varname) == 0);
4973 
4974  varidx = *(int*)element;
4975  }
4976  else
4977  {
4978  /* variable is new */
4979  varidx = *nvars;
4980 
4981  (*varnameslength) -= (int)(1 + (strlen(varname) + 1) / sizeof(int) + 1);
4982  if( *varnameslength < 0 )
4983  {
4984  SCIPerrorMessage("Buffer in exprparseReadVariable is too short for varaible name %.*s.\n", namelength, str);
4985  return SCIP_READERROR;
4986  }
4987 
4988  /* store index of variable and variable name in varnames buffer */
4989  **varnames = varidx;
4990  strcpy((char*)(*varnames + 1), varname);
4991 
4992  /* insert variable into hashtable */
4993  SCIP_CALL( SCIPhashtableInsert(vartable, (void*)*varnames) );
4994 
4995  ++*nvars;
4996  *varnames += 1 + (strlen(varname) + 1) / sizeof(int) + 1;
4997  }
4998 
4999  /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
5000  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_VARIDX, varidx) ); /*lint !e613*/
5001  if( coefficient != 1.0 )
5002  {
5003  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, expr, &coefficient, 0.0) );
5004  }
5005 
5006  /* Move pointer to char behind end of variable */
5007  *str = varnameendptr + 1;
5008 
5009  /* consprint sometimes prints a variable type identifier which we don't need */
5010  if( (*str)[0] == '[' && (*str)[2] == ']' &&
5011  ((*str)[1] == SCIP_VARTYPE_BINARY_CHAR ||
5012  (*str)[1] == SCIP_VARTYPE_INTEGER_CHAR ||
5013  (*str)[1] == SCIP_VARTYPE_IMPLINT_CHAR ||
5014  (*str)[1] == SCIP_VARTYPE_CONTINUOUS_CHAR ) )
5015  *str += 3;
5016 
5017  return SCIP_OKAY;
5018 }
5019 
5020 /** if str[0] points to an opening parenthesis, this function sets endptr to point to the matching closing bracket in str
5021  *
5022  * Searches for at most length characters.
5023  */
5024 static
5026  const char* str, /**< pointer to the string to be parsed */
5027  const char** endptr, /**< pointer to point to the closing parenthesis */
5028  int length /**< length of the string to be parsed */
5029  )
5030 {
5031  int nopenbrackets;
5032 
5033  assert(str[0] == '(');
5034 
5035  *endptr = str;
5036 
5037  /* find the end of this expression */
5038  nopenbrackets = 0;
5039  while( (*endptr - str ) < length && !(nopenbrackets == 1 && *endptr[0] == ')') )
5040  {
5041  if( *endptr[0] == '(')
5042  ++nopenbrackets;
5043  if( *endptr[0] == ')')
5044  --nopenbrackets;
5045  ++*endptr;
5046  }
5047 
5048  if( *endptr[0] != ')' )
5049  {
5050  SCIPerrorMessage("unable to find closing parenthesis in unbalanced expression %.*s\n", length, str);
5051  return SCIP_READERROR;
5052  }
5053 
5054  return SCIP_OKAY;
5055 }
5056 
5057 /** this function sets endptr to point to the next separating comma in str
5058  *
5059  * That is, for a given string like "x+f(x,y),z", endptr will point to the comma before "z"
5060  *
5061  * Searches for at most length characters.
5062  */
5063 static
5065  const char* str, /**< pointer to the string to be parsed */
5066  const char** endptr, /**< pointer to point to the comma */
5067  int length /**< length of the string to be parsed */
5068  )
5069 {
5070  int nopenbrackets;
5071 
5072  *endptr = str;
5073 
5074  /* find a comma without open brackets */
5075  nopenbrackets = 0;
5076  while( (*endptr - str ) < length && !(nopenbrackets == 0 && *endptr[0] == ',') )
5077  {
5078  if( *endptr[0] == '(')
5079  ++nopenbrackets;
5080  if( *endptr[0] == ')')
5081  --nopenbrackets;
5082  ++*endptr;
5083  }
5084 
5085  if( *endptr[0] != ',' )
5086  {
5087  SCIPerrorMessage("unable to find separating comma in unbalanced expression %.*s\n", length, str);
5088  return SCIP_READERROR;
5089  }
5090 
5091  return SCIP_OKAY;
5092 }
5093 
5094 /** parses an expression from a string */
5095 static
5097  BMS_BLKMEM* blkmem, /**< block memory data structure */
5098  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
5099  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
5100  const char* str, /**< pointer to the string to be parsed */
5101  int length, /**< length of the string to be parsed */
5102  const char* lastchar, /**< pointer to the last char of str that should be parsed */
5103  int* nvars, /**< running number of encountered variables so far */
5104  int** varnames, /**< pointer to buffer to store new variable names */
5105  int* varnameslength, /**< pointer to length of the varnames buffer array */
5106  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
5107  int recursiondepth /**< current recursion depth */
5108  )
5109 { /*lint --e{712,747}*/
5110  SCIP_EXPR* arg1;
5111  SCIP_EXPR* arg2;
5112  const char* subexpptr;
5113  const char* subexpendptr;
5114  const char* strstart;
5115  const char* endptr;
5116  char* nonconstendptr;
5117  SCIP_Real number;
5118  int subexplength;
5119  int nopenbrackets;
5120 
5121  assert(blkmem != NULL);
5122  assert(expr != NULL);
5123  assert(str != NULL);
5124  assert(lastchar >= str);
5125  assert(nvars != NULL);
5126  assert(varnames != NULL);
5127  assert(vartable != NULL);
5128 
5129  assert(recursiondepth < 100);
5130 
5131  strstart = str; /* might be needed for error message... */
5132 
5133  SCIPdebugMessage("exprParse (%i): parsing %.*s\n", recursiondepth, (int) (lastchar-str + 1), str);
5134 
5135  /* ignore whitespace */
5136  while( isspace((unsigned char)*str) )
5137  ++str;
5138 
5139  /* look for a sum or difference not contained in brackets */
5140  subexpptr = str;
5141  nopenbrackets = 0;
5142 
5143  /* find the end of this expression
5144  * a '+' right at the beginning indicates a coefficient, not treated here, or a summation
5145  */
5146  while( subexpptr != lastchar && !(nopenbrackets == 0 && (subexpptr[0] == '+' || subexpptr[0] == '-') && subexpptr != str) )
5147  {
5148  if( subexpptr[0] == '(')
5149  ++nopenbrackets;
5150  if( subexpptr[0] == ')')
5151  --nopenbrackets;
5152  ++subexpptr;
5153  }
5154 
5155  if( subexpptr != lastchar )
5156  {
5157  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str, (int) ((subexpptr - 1) - str + 1), subexpptr - 1, nvars,
5158  varnames, varnameslength, vartable, recursiondepth + 1) );
5159 
5160  if( subexpptr[0] == '+' )
5161  ++subexpptr;
5162  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, subexpptr , (int) (lastchar - (subexpptr ) + 1), lastchar, nvars,
5163  varnames, varnameslength, vartable, recursiondepth + 1) );
5164 
5165  /* make new expression from two arguments
5166  * we always use add, because we leave the operator between the found expressions in the second argument
5167  * this way, we do not have to worry about ''minus brackets'' in the case of more then two summands:
5168  * a - b - c = a + (-b -c)
5169  */
5170  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5171 
5172  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5173  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5174  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5175 
5176  return SCIP_OKAY;
5177  }
5178 
5179  /* check for a bracketed subexpression */
5180  if( str[0] == '(' )
5181  {
5182  nopenbrackets = 0;
5183 
5184  subexplength = -1; /* we do not want the closing bracket in the string */
5185  subexpptr = str + 1; /* leave out opening bracket */
5186 
5187  /* find the end of this expression */
5188  while( subexplength < length && !(nopenbrackets == 1 && str[0] == ')') )
5189  {
5190  if( str[0] == '(' )
5191  ++nopenbrackets;
5192  if( str[0] == ')' )
5193  --nopenbrackets;
5194  ++str;
5195  ++subexplength;
5196  }
5197  subexpendptr = str - 1; /* leave out closing bracket */
5198 
5199  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, subexpptr, subexplength, subexpendptr, nvars, varnames,
5200  varnameslength, vartable, recursiondepth + 1) );
5201  ++str;
5202  }
5203  else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+')
5204  && (isdigit((unsigned char)str[1]) || str[1] == ' ')) )
5205  {
5206  /* check if there is a lonely minus coming, indicating a -1.0 */
5207  if( str[0] == '-' && str[1] == ' ' )
5208  {
5209  number = -1.0;
5210  nonconstendptr = (char*) str + 1;
5211  }
5212  /* check if there is a number coming */
5213  else if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5214  {
5215  SCIPerrorMessage("error parsing number from <%s>\n", str);
5216  return SCIP_READERROR;
5217  }
5218  str = nonconstendptr;
5219 
5220  /* ignore whitespace */
5221  while( isspace((unsigned char)*str) && str != lastchar )
5222  ++str;
5223 
5224  if( str[0] != '*' && str[0] != '/' && str[0] != '+' && str[0] != '-' && str[0] != '^' )
5225  {
5226  if( str < lastchar )
5227  {
5228  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, str, (int)(lastchar - str) + 1, lastchar, nvars, varnames,
5229  varnameslength, vartable, recursiondepth + 1) );
5230  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, *expr, number) );
5231  }
5232  else
5233  {
5234  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5235  }
5236  str = lastchar + 1;
5237  }
5238  else
5239  {
5240  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5241  }
5242  }
5243  else if( str[0] == '<' )
5244  {
5245  /* check if expressions begins with a variable */
5246  SCIP_CALL( exprparseReadVariable(blkmem, &str, expr, nvars, varnames, varnameslength, vartable, 1.0, NULL) );
5247  }
5248  /* four character operators */
5249  else if( strncmp(str, "sqrt", 4) == 0 )
5250  {
5251  str += 4;
5252  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5253  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5254  varnameslength, vartable, recursiondepth + 1) );
5255  str = endptr + 1;
5256 
5257  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQRT, arg1) );
5258  }
5259  /* three character operators with 1 argument */
5260  else if(
5261  strncmp(str, "abs", 3) == 0 ||
5262  strncmp(str, "cos", 3) == 0 ||
5263  strncmp(str, "exp", 3) == 0 ||
5264  strncmp(str, "log", 3) == 0 ||
5265  strncmp(str, "sin", 3) == 0 ||
5266  strncmp(str, "sqr", 3) == 0 ||
5267  strncmp(str, "tan", 3) == 0 )
5268  {
5269  const char* opname = str;
5270 
5271  str += 3;
5272  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5273  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5274  varnameslength, vartable, recursiondepth + 1) );
5275  str = endptr + 1;
5276 
5277  if( strncmp(opname, "abs", 3) == 0 )
5278  {
5279  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_ABS, arg1) );
5280  }
5281  else if( strncmp(opname, "cos", 3) == 0 )
5282  {
5283  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_COS, arg1) );
5284  }
5285  else if( strncmp(opname, "exp", 3) == 0 )
5286  {
5287  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, arg1) );
5288  }
5289  else if( strncmp(opname, "log", 3) == 0 )
5290  {
5291  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5292  }
5293  else if( strncmp(opname, "sin", 3) == 0 )
5294  {
5295  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIN, arg1) );
5296  }
5297  else if( strncmp(opname, "sqr", 3) == 0 )
5298  {
5299  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQUARE, arg1) );
5300  }
5301  else
5302  {
5303  assert(strncmp(opname, "tan", 3) == 0);
5304  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_TAN, arg1) );
5305  }
5306  }
5307  /* three character operators with 2 arguments */
5308  else if(
5309  strncmp(str, "max", 3) == 0 ||
5310  strncmp(str, "min", 3) == 0 )
5311  {
5312  /* we have a string of the form "min(...,...)" or "max(...,...)"
5313  * first find the closing parenthesis, then the comma
5314  */
5315  const char* comma;
5316  SCIP_EXPROP op;
5317 
5318  op = (str[1] == 'a' ? SCIP_EXPR_MAX : SCIP_EXPR_MIN);
5319 
5320  str += 3;
5321  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5322 
5323  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5324 
5325  /* parse first argument [str+1..comma-1] */
5326  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5327  varnameslength, vartable, recursiondepth + 1) );
5328 
5329  /* parse second argument [comma+1..endptr] */
5330  ++comma;
5331  while( comma < endptr && *comma == ' ' )
5332  ++comma;
5333 
5334  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, comma, endptr - comma, endptr - 1, nvars, varnames,
5335  varnameslength, vartable, recursiondepth + 1) );
5336 
5337  SCIP_CALL( SCIPexprCreate(blkmem, expr, op, arg1, arg2) );
5338 
5339  str = endptr + 1;
5340  }
5341  else if( strncmp(str, "power", 5) == 0 )
5342  {
5343  /* we have a string of the form "power(...,integer)" (thus, intpower)
5344  * first find the closing parenthesis, then the comma
5345  */
5346  const char* comma;
5347  int exponent;
5348 
5349  str += 5;
5350  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5351 
5352  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5353 
5354  /* parse first argument [str+1..comma-1] */
5355  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5356  varnameslength, vartable, recursiondepth + 1) );
5357 
5358  ++comma;
5359  /* parse second argument [comma, endptr-1]: it needs to be an integer */
5360  while( comma < endptr && *comma == ' ' )
5361  ++comma;
5362  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5363  {
5364  SCIPerrorMessage("error parsing integer exponent from <%s>\n", comma);
5365  }
5366  if( !SCIPstrToIntValue(comma, &exponent, &nonconstendptr) )
5367  {
5368  SCIPerrorMessage("error parsing integer from <%s>\n", comma);
5369  return SCIP_READERROR;
5370  }
5371 
5372  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, exponent) );
5373 
5374  str = endptr + 1;
5375  }
5376  else if( strncmp(str, "realpower", 9) == 0 || strncmp(str, "signpower", 9) == 0 )
5377  {
5378  /* we have a string of the form "realpower(...,double)" or "signpower(...,double)"
5379  * first find the closing parenthesis, then the comma
5380  */
5381  const char* opname = str;
5382  const char* comma;
5383 
5384  str += 9;
5385  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5386 
5387  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5388 
5389  /* parse first argument [str+1..comma-1] */
5390  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5391  varnameslength, vartable, recursiondepth + 1) );
5392 
5393  ++comma;
5394  /* parse second argument [comma, endptr-1]: it needs to be an number */
5395  while( comma < endptr && *comma == ' ' )
5396  ++comma;
5397  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5398  {
5399  SCIPerrorMessage("error parsing number exponent from <%s>\n", comma);
5400  }
5401  if( !SCIPstrToRealValue(comma, &number, &nonconstendptr) )
5402  {
5403  SCIPerrorMessage("error parsing number from <%s>\n", comma);
5404  return SCIP_READERROR;
5405  }
5406 
5407  if( strncmp(opname, "realpower", 9) == 0 )
5408  {
5409  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, number) );
5410  }
5411  else
5412  {
5413  assert(strncmp(opname, "signpower", 9) == 0);
5414  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIGNPOWER, arg1, number) );
5415  }
5416 
5417  str = endptr + 1;
5418  }
5419  else if( isalpha(*str) || *str == '_' || *str == '#' )
5420  {
5421  /* check for a variable, that was not recognized earlier because somebody omitted the '<' and '>' we need for
5422  * SCIPparseVarName, making everyones life harder;
5423  * we allow only variable names starting with a character or underscore here
5424  */
5425  const char* varnamestartptr = str;
5426 
5427  /* allow only variable names containing characters, digits, hash marks, and underscores here */
5428  while( isalnum(str[0]) || str[0] == '_' || str[0] == '#' )
5429  ++str;
5430 
5431  SCIP_CALL( exprparseReadVariable(blkmem, &varnamestartptr, expr, nvars, varnames, varnameslength,
5432  vartable, 1.0, str) );
5433  }
5434  else
5435  {
5436  SCIPerrorMessage("parsing of invalid expression %.*s.\n", (int) (lastchar - str + 1), str);
5437  return SCIP_READERROR;
5438  }
5439 
5440  /* if we are one char behind lastchar, we are done */
5441  if( str == lastchar + 1)
5442  {
5443  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5444  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5445  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5446 
5447  return SCIP_OKAY;
5448  }
5449 
5450  /* check if we are still in bounds */
5451  if( str > lastchar + 1)
5452  {
5453  SCIPerrorMessage("error finding first expression in \"%.*s\" took us outside of given subexpression length\n", length, strstart);
5454  return SCIP_READERROR;
5455  }
5456 
5457  /* ignore whitespace */
5458  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5459  ++str;
5460 
5461  /* maybe now we're done? */
5462  if( str >= lastchar + 1)
5463  {
5464  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5465  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5466  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5467 
5468  return SCIP_OKAY;
5469  }
5470 
5471  if( str[0] == '^' )
5472  {
5473  /* a '^' behind the found expression indicates a power */
5474  SCIP_Real constant;
5475 
5476  arg1 = *expr;
5477  ++str;
5478  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5479  ++str;
5480 
5481  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5482  {
5483  /* there is a number coming */
5484  if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5485  {
5486  SCIPerrorMessage("error parsing number from <%s>\n", str);
5487  return SCIP_READERROR;
5488  }
5489 
5490  SCIP_CALL( SCIPexprCreate(blkmem, &arg2, SCIP_EXPR_CONST, number) );
5491  str = nonconstendptr;
5492 
5493  constant = SCIPexprGetOpReal(arg2);
5494  SCIPexprFreeDeep(blkmem, &arg2);
5495 
5496  /* expr^number is intpower or realpower */
5497  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5498  {
5499  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5500  }
5501  else
5502  {
5503  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5504  }
5505  }
5506  else if( str[0] == '(' )
5507  {
5508  /* we use exprParse to evaluate the exponent */
5509 
5510  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5511  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5512  varnameslength, vartable, recursiondepth + 1) );
5513 
5514  if( SCIPexprGetOperator(arg2) != SCIP_EXPR_CONST )
5515  {
5516  /* reformulate arg1^arg2 as exp(arg2 * log(arg1)) */
5517  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5518  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, *expr, arg2) );
5519  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, *expr) );
5520  }
5521  else
5522  {
5523  /* expr^number is intpower or realpower */
5524  constant = SCIPexprGetOpReal(arg2);
5525  SCIPexprFreeDeep(blkmem, &arg2);
5526  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5527  {
5528  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5529  }
5530  else
5531  {
5532  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5533  }
5534  }
5535  str = endptr + 1;
5536  }
5537  else
5538  {
5539  SCIPerrorMessage("unexpected string following ^ in %.*s\n", length, str);
5540  return SCIP_READERROR;
5541  }
5542 
5543  /* ignore whitespace */
5544  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5545  ++str;
5546  }
5547 
5548  /* check for a two argument operator that is not a multiplication */
5549  if( str <= lastchar && (str[0] == '+' || str[0] == '-' || str[0] == '/') )
5550  {
5551  char op;
5552 
5553  op = str[0];
5554  arg1 = *expr;
5555 
5556  /* step forward over the operator to go to the beginning of the second argument */
5557  ++str;
5558 
5559  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5560  varnameslength, vartable, recursiondepth + 1) );
5561  str = lastchar + 1;
5562 
5563  /* make new expression from two arguments */
5564  if( op == '+')
5565  {
5566  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5567  }
5568  else if( op == '-')
5569  {
5570  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, -1.0, arg2, 0.0) );
5571  }
5572  else if( op == '*' )
5573  {
5574  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5575  {
5576  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5577  }
5578  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5579  {
5580  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5581  }
5582  else
5583  {
5584  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5585  }
5586  }
5587  else
5588  {
5589  assert(op == '/');
5590 
5591  if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5592  {
5593  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, 1.0 / SCIPexprGetOpReal(arg2)) );
5594  SCIPexprFreeShallow(blkmem, &arg2);
5595  }
5596  else
5597  {
5598  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_DIV, arg1, arg2) );
5599  }
5600  }
5601  }
5602 
5603  /* ignore whitespace */
5604  while( isspace((unsigned char)*str) )
5605  ++str;
5606 
5607  /* we are either done or we have a multiplication? */
5608  if( str >= lastchar + 1 )
5609  {
5610  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5611  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5612  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5613 
5614  return SCIP_OKAY;
5615  }
5616 
5617  /* if there is a part of the string left to be parsed, we assume that this as a multiplication */
5618  arg1 = *expr;
5619 
5620  /* stepping over multiplication operator if needed */
5621  if( str[0] == '*' )
5622  {
5623  ++str;
5624  }
5625  else if( str[0] != '(' )
5626  {
5627  SCIPdebugMessage("No operator found, assuming a multiplication before %.*s\n", (int) (lastchar - str + 1), str);
5628  }
5629 
5630  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5631  varnameslength, vartable, recursiondepth + 1) );
5632 
5633  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5634  {
5635  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5636  SCIPexprFreeDeep(blkmem, &arg1);
5637  }
5638  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5639  {
5640  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5641  SCIPexprFreeDeep(blkmem, &arg2);
5642  }
5643  else
5644  {
5645  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5646  }
5647 
5648  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5649  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5650  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5651 
5652  return SCIP_OKAY;
5653 }
5654 
5655 /**@} */
5656 
5657 /**@name Expression methods */
5658 /**@{ */
5659 
5660 /* In debug mode, the following methods are implemented as function calls to ensure
5661  * type validity.
5662  * In optimized mode, the methods are implemented as defines to improve performance.
5663  * However, we want to have them in the library anyways, so we have to undef the defines.
5664  */
5665 
5666 #undef SCIPexprGetOperator
5667 #undef SCIPexprGetNChildren
5668 #undef SCIPexprGetChildren
5669 #undef SCIPexprGetOpIndex
5670 #undef SCIPexprGetOpReal
5671 #undef SCIPexprGetOpData
5672 #undef SCIPexprGetRealPowerExponent
5673 #undef SCIPexprGetIntPowerExponent
5674 #undef SCIPexprGetSignPowerExponent
5675 #undef SCIPexprGetLinearCoefs
5676 #undef SCIPexprGetLinearConstant
5677 #undef SCIPexprGetQuadElements
5678 #undef SCIPexprGetQuadConstant
5679 #undef SCIPexprGetQuadLinearCoefs
5680 #undef SCIPexprGetNQuadElements
5681 #undef SCIPexprGetMonomials
5682 #undef SCIPexprGetNMonomials
5683 #undef SCIPexprGetPolynomialConstant
5684 #undef SCIPexprGetMonomialCoef
5685 #undef SCIPexprGetMonomialNFactors
5686 #undef SCIPexprGetMonomialChildIndices
5687 #undef SCIPexprGetMonomialExponents
5688 #undef SCIPexprGetUserData
5689 #undef SCIPexprHasUserEstimator
5690 #undef SCIPexprGetUserEvalCapability
5691 
5692 /** gives operator of expression */
5694  SCIP_EXPR* expr /**< expression */
5695  )
5696 {
5697  assert(expr != NULL);
5698 
5699  return expr->op;
5700 }
5701 
5702 /** gives number of children of an expression */
5704  SCIP_EXPR* expr /**< expression */
5705  )
5706 {
5707  assert(expr != NULL);
5708 
5709  return expr->nchildren;
5710 }
5711 
5712 /** gives pointer to array with children of an expression */
5714  SCIP_EXPR* expr /**< expression */
5715  )
5716 {
5717  assert(expr != NULL);
5718 
5719  return expr->children;
5720 }
5721 
5722 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
5724  SCIP_EXPR* expr /**< expression */
5725  )
5726 {
5727  assert(expr != NULL);
5728  assert(expr->op == SCIP_EXPR_VARIDX || expr->op == SCIP_EXPR_PARAM);
5729 
5730  return expr->data.intval;
5731 }
5732 
5733 /** gives real belonging to a SCIP_EXPR_CONST operand */
5735  SCIP_EXPR* expr /**< expression */
5736  )
5737 {
5738  assert(expr != NULL);
5739  assert(expr->op == SCIP_EXPR_CONST);
5740 
5741  return expr->data.dbl;
5742 }
5743 
5744 /** gives void* belonging to a complex operand */
5746  SCIP_EXPR* expr /**< expression */
5747  )
5748 {
5749  assert(expr != NULL);
5750  assert(expr->op >= SCIP_EXPR_SUM); /* only complex operands store their data as void* */
5751 
5752  return expr->data.data;
5753 }
5754 
5755 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
5757  SCIP_EXPR* expr /**< expression */
5758  )
5759 {
5760  assert(expr != NULL);
5761  assert(expr->op == SCIP_EXPR_REALPOWER);
5762 
5763  return expr->data.dbl;
5764 }
5765 
5766 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
5768  SCIP_EXPR* expr /**< expression */
5769  )
5770 {
5771  assert(expr != NULL);
5772  assert(expr->op == SCIP_EXPR_INTPOWER);
5773 
5774  return expr->data.intval;
5775 }
5776 
5777 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
5779  SCIP_EXPR* expr /**< expression */
5780  )
5781 {
5782  assert(expr != NULL);
5783  assert(expr->op == SCIP_EXPR_SIGNPOWER);
5784 
5785  return expr->data.dbl;
5786 }
5787 
5788 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
5790  SCIP_EXPR* expr /**< expression */
5791  )
5792 {
5793  assert(expr != NULL);
5794  assert(expr->op == SCIP_EXPR_LINEAR);
5795  assert(expr->data.data != NULL);
5796 
5797  /* the coefficients are stored in the first nchildren elements of the array stored as expression data */
5798  return (SCIP_Real*)expr->data.data;
5799 }
5800 
5801 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
5803  SCIP_EXPR* expr /**< expression */
5804  )
5805 {
5806  assert(expr != NULL);
5807  assert(expr->op == SCIP_EXPR_LINEAR);
5808  assert(expr->data.data != NULL);
5809 
5810  /* the constant is stored in the nchildren's element of the array stored as expression data */
5811  return ((SCIP_Real*)expr->data.data)[expr->nchildren];
5812 }
5813 
5814 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5816  SCIP_EXPR* expr /**< quadratic expression */
5817  )
5818 {
5819  assert(expr != NULL);
5820  assert(expr->op == SCIP_EXPR_QUADRATIC);
5821  assert(expr->data.data != NULL);
5822 
5823  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->quadelems;
5824 }
5825 
5826 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
5828  SCIP_EXPR* expr /**< quadratic expression */
5829  )
5830 {
5831  assert(expr != NULL);
5832  assert(expr->op == SCIP_EXPR_QUADRATIC);
5833  assert(expr->data.data != NULL);
5834 
5835  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->constant;
5836 }
5837 
5838 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression
5839  * can be NULL if all coefficients are 0.0 */
5841  SCIP_EXPR* expr /**< quadratic expression */
5842  )
5843 {
5844  assert(expr != NULL);
5845  assert(expr->op == SCIP_EXPR_QUADRATIC);
5846  assert(expr->data.data != NULL);
5847 
5848  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->lincoefs;
5849 }
5850 
5851 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5853  SCIP_EXPR* expr /**< quadratic expression */
5854  )
5855 {
5856  assert(expr != NULL);
5857  assert(expr->op == SCIP_EXPR_QUADRATIC);
5858  assert(expr->data.data != NULL);
5859 
5860  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->nquadelems;
5861 }
5862 
5863 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5865  SCIP_EXPR* expr /**< expression */
5866  )
5867 {
5868  assert(expr != NULL);
5869  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5870  assert(expr->data.data != NULL);
5871 
5872  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->monomials;
5873 }
5874 
5875 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5877  SCIP_EXPR* expr /**< expression */
5878  )
5879 {
5880  assert(expr != NULL);
5881  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5882  assert(expr->data.data != NULL);
5883 
5884  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->nmonomials;
5885 }
5886 
5887 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
5889  SCIP_EXPR* expr /**< expression */
5890  )
5891 {
5892  assert(expr != NULL);
5893  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5894  assert(expr->data.data != NULL);
5895 
5896  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant;
5897 }
5898 
5899 /** gets coefficient of a monomial */
5901  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5902  )
5903 {
5904  assert(monomial != NULL);
5905 
5906  return monomial->coef;
5907 }
5908 
5909 /** gets number of factors of a monomial */
5911  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5912  )
5913 {
5914  assert(monomial != NULL);
5915 
5916  return monomial->nfactors;
5917 }
5918 
5919 /** gets indices of children corresponding to factors of a monomial */
5921  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5922  )
5923 {
5924  assert(monomial != NULL);
5925 
5926  return monomial->childidxs;
5927 }
5928 
5929 /** gets exponents in factors of a monomial */
5931  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5932  )
5933 {
5934  assert(monomial != NULL);
5935 
5936  return monomial->exponents;
5937 }
5938 
5939 /** gets user data of a user expression */
5941  SCIP_EXPR* expr
5942  )
5943 {
5944  assert(expr != NULL);
5945  assert(expr->data.data != NULL);
5946 
5947  return ((SCIP_EXPRDATA_USER*)expr->data.data)->userdata;
5948 }
5949 
5950 /** indicates whether a user expression has the estimator callback defined */
5952  SCIP_EXPR* expr
5953  )
5954 {
5955  assert(expr != NULL);
5956  assert(expr->data.data != NULL);
5957 
5958  return ((SCIP_EXPRDATA_USER*)expr->data.data)->estimate != NULL;
5959 }
5960 
5961 /** gives the evaluation capability of a user expression */
5963  SCIP_EXPR* expr
5964  )
5965 {
5966  assert(expr != NULL);
5967  assert(expr->data.data != NULL);
5968 
5969  return ((SCIP_EXPRDATA_USER*)expr->data.data)->evalcapability;
5970 }
5971 
5972 /** creates a simple expression */
5974  BMS_BLKMEM* blkmem, /**< block memory data structure */
5975  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
5976  SCIP_EXPROP op, /**< operand of expression */
5977  ... /**< arguments of operand */
5978  )
5979 {
5980  va_list ap;
5981  SCIP_EXPR** children;
5982  SCIP_EXPROPDATA opdata;
5983 
5984  assert(blkmem != NULL);
5985  assert(expr != NULL);
5986 
5987  switch( op )
5988  {
5989  case SCIP_EXPR_VARIDX:
5990  case SCIP_EXPR_PARAM:
5991  {
5992  va_start( ap, op ); /*lint !e838*/
5993  opdata.intval = va_arg( ap, int ); /*lint !e416 !e826*/
5994  va_end( ap ); /*lint !e826*/
5995 
5996  assert( opdata.intval >= 0 );
5997 
5998  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5999  break;
6000  }
6001 
6002  case SCIP_EXPR_CONST:
6003  {
6004  va_start(ap, op ); /*lint !e838*/
6005  opdata.dbl = va_arg( ap, SCIP_Real ); /*lint !e416 !e826*/
6006  va_end( ap ); /*lint !e826*/
6007 
6008  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
6009  break;
6010  }
6011 
6012  /* operands with two children */
6013  case SCIP_EXPR_PLUS :
6014  case SCIP_EXPR_MINUS :
6015  case SCIP_EXPR_MUL :
6016  case SCIP_EXPR_DIV :
6017  case SCIP_EXPR_MIN :
6018  case SCIP_EXPR_MAX :
6019  {
6020  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 2) ); /*lint !e506*/
6021 
6022  va_start(ap, op ); /*lint !e838*/
6023  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6024  children[1] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6025  assert(children[0] != NULL);
6026  assert(children[1] != NULL);
6027  va_end( ap ); /*lint !e826*/
6028  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6029 
6030  SCIP_CALL( exprCreate( blkmem, expr, op, 2, children, opdata ) );
6031  break;
6032  }
6033 
6034  /* operands with one child */
6035  case SCIP_EXPR_SQUARE:
6036  case SCIP_EXPR_SQRT :
6037  case SCIP_EXPR_EXP :
6038  case SCIP_EXPR_LOG :
6039  case SCIP_EXPR_SIN :
6040  case SCIP_EXPR_COS :
6041  case SCIP_EXPR_TAN :
6042  /* case SCIP_EXPR_ERF : */
6043  /* case SCIP_EXPR_ERFI : */
6044  case SCIP_EXPR_ABS :
6045  case SCIP_EXPR_SIGN :
6046  {
6047  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6048 
6049  va_start(ap, op ); /*lint !e838*/
6050  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6051  assert(children[0] != NULL);
6052  va_end( ap ); /*lint !e826*/
6053  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6054 
6055  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6056  break;
6057  }
6058 
6059  case SCIP_EXPR_REALPOWER:
6060  case SCIP_EXPR_SIGNPOWER:
6061  {
6062  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6063 
6064  va_start(ap, op ); /*lint !e838*/
6065  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6066  assert(children[0] != NULL);
6067  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
6068  va_end( ap ); /*lint !e826*/
6069 
6070  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6071  break;
6072  }
6073 
6074  case SCIP_EXPR_INTPOWER:
6075  {
6076  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6077 
6078  va_start(ap, op ); /*lint !e838*/
6079  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6080  assert(children[0] != NULL);
6081  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
6082  va_end( ap ); /*lint !e826*/
6083 
6084  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6085  break;
6086  }
6087 
6088  /* complex operands */
6089  case SCIP_EXPR_SUM :
6090  case SCIP_EXPR_PRODUCT:
6091  {
6092  int nchildren;
6093  SCIP_EXPR** childrenarg;
6094 
6095  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6096 
6097  va_start(ap, op ); /*lint !e838*/
6098  /* first argument should be number of children */
6099  nchildren = va_arg( ap, int ); /*lint !e416 !e826*/
6100  assert(nchildren >= 0);
6101 
6102  /* for a sum or product of 0 terms we can finish here */
6103  if( nchildren == 0 )
6104  {
6105  SCIP_RETCODE retcode;
6106  retcode = exprCreate( blkmem, expr, op, 0, NULL, opdata);
6107  va_end( ap ); /*lint !e826*/
6108  SCIP_CALL( retcode );
6109  break;
6110  }
6111 
6112  /* next argument should be array of children expressions */
6113  childrenarg = va_arg( ap, SCIP_EXPR** ); /*lint !e416 !e826*/
6114  assert(childrenarg != NULL);
6115  va_end( ap ); /*lint !e826*/
6116 
6117  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &children, childrenarg, nchildren) );
6118 
6119  SCIP_CALL( exprCreate( blkmem, expr, op, nchildren, children, opdata) );
6120  break;
6121  }
6122 
6123  case SCIP_EXPR_LINEAR :
6124  case SCIP_EXPR_QUADRATIC:
6125  case SCIP_EXPR_POLYNOMIAL:
6126  case SCIP_EXPR_USER:
6127  {
6128  SCIPerrorMessage("cannot create complex expression linear, quadratic, polynomial, or user with SCIPexprCreate\n");
6129  return SCIP_INVALIDDATA;
6130  }
6131 
6132  case SCIP_EXPR_LAST:
6133  SCIPABORT();
6134  break;
6135  }
6136 
6137  return SCIP_OKAY;
6138 }
6139 
6140 /** copies an expression including its children */
6142  BMS_BLKMEM* blkmem, /**< block memory data structure */
6143  SCIP_EXPR** targetexpr, /**< buffer to store pointer to copied expression */
6144  SCIP_EXPR* sourceexpr /**< expression to copy */
6145  )
6146 {
6147  assert(blkmem != NULL);
6148  assert(targetexpr != NULL);
6149  assert(sourceexpr != NULL);
6150 
6151  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targetexpr, sourceexpr) );
6152 
6153  if( sourceexpr->nchildren )
6154  {
6155  int i;
6156 
6157  /* alloc memory for children expressions */
6158  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetexpr)->children, sourceexpr->nchildren) );
6159 
6160  /* copy children expressions */
6161  for( i = 0; i < sourceexpr->nchildren; ++i )
6162  {
6163  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targetexpr)->children[i], sourceexpr->children[i]) );
6164  }
6165  }
6166  else
6167  {
6168  assert((*targetexpr)->children == NULL); /* otherwise, sourceexpr->children was not NULL, which is wrong */
6169  }
6170 
6171  /* call operands data copy callback for complex operands
6172  * for simple operands BMSduplicate above should have done the job
6173  */
6174  if( exprOpTable[sourceexpr->op].copydata != NULL )
6175  {
6176  SCIP_CALL( exprOpTable[sourceexpr->op].copydata(blkmem, sourceexpr->nchildren, sourceexpr->data, &(*targetexpr)->data) );
6177  }
6178 
6179  return SCIP_OKAY;
6180 }
6181 
6182 /** frees an expression including its children */
6184  BMS_BLKMEM* blkmem, /**< block memory data structure */
6185  SCIP_EXPR** expr /**< pointer to expression to free */
6186  )
6187 {
6188  assert(blkmem != NULL);
6189  assert(expr != NULL);
6190  assert(*expr != NULL);
6191 
6192  /* call operands data free callback, if given */
6193  if( exprOpTable[(*expr)->op].freedata != NULL )
6194  {
6195  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6196  }
6197 
6198  if( (*expr)->nchildren )
6199  {
6200  int i;
6201 
6202  assert( (*expr)->children != NULL );
6203 
6204  for( i = 0; i < (*expr)->nchildren; ++i )
6205  {
6206  SCIPexprFreeDeep(blkmem, &(*expr)->children[i]);
6207  assert((*expr)->children[i] == NULL);
6208  }
6209 
6210  BMSfreeBlockMemoryArray(blkmem, &(*expr)->children, (*expr)->nchildren);
6211  }
6212  else
6213  {
6214  assert( (*expr)->children == NULL );
6215  }
6216 
6217  BMSfreeBlockMemory(blkmem, expr);
6218 }
6219 
6220 /** frees an expression but not its children */
6222  BMS_BLKMEM* blkmem, /**< block memory data structure */
6223  SCIP_EXPR** expr /**< pointer to expression to free */
6224  )
6225 {
6226  assert(blkmem != NULL);
6227  assert(expr != NULL);
6228  assert(*expr != NULL);
6229 
6230  /* call operands data free callback, if given */
6231  if( exprOpTable[(*expr)->op].freedata != NULL )
6232  {
6233  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6234  }
6235 
6236  BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->nchildren);
6237 
6238  BMSfreeBlockMemory(blkmem, expr);
6239 }
6240 
6241 /** creates an expression from the addition of two given expression, with coefficients, and a constant
6242  *
6243  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6244  * Favors creation and maintaining of SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6245  */
6247  BMS_BLKMEM* blkmem, /**< block memory data structure */
6248  SCIP_EXPR** expr, /**< pointer to store pointer to created expression */
6249  SCIP_Real coef1, /**< coefficient of first term */
6250  SCIP_EXPR* term1, /**< expression of first term, or NULL */
6251  SCIP_Real coef2, /**< coefficient of second term */
6252  SCIP_EXPR* term2, /**< expression of second term, or NULL */
6253  SCIP_Real constant /**< constant term to add */
6254  )
6255 {
6256  assert(blkmem != NULL);
6257  assert(expr != NULL);
6258 
6259  /* @todo could do something special with quadratic and polynomial expressions */
6260 
6261  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_CONST )
6262  {
6263  constant += coef1 * SCIPexprGetOpReal(term1);
6264  SCIPexprFreeDeep(blkmem, &term1);
6265  }
6266 
6267  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_CONST )
6268  {
6269  constant += coef2 * SCIPexprGetOpReal(term2);
6270  SCIPexprFreeDeep(blkmem, &term2);
6271  }
6272 
6273  if( term1 == NULL && term2 == NULL )
6274  {
6275  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, constant) );
6276  return SCIP_OKAY;
6277  }
6278 
6279  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && coef1 != 1.0 )
6280  {
6281  /* multiply coefficients and constant of linear expression term1 by coef1 */
6282  SCIP_Real* data;
6283  int i;
6284 
6285  data = (SCIP_Real*)term1->data.data;
6286  assert(data != NULL);
6287 
6288  /* loop one more index to multiply also constant of linear expression */
6289  for( i = 0; i <= term1->nchildren; ++i )
6290  data[i] *= coef1;
6291 
6292  coef1 = 1.0;
6293  }
6294 
6295  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR && coef2 != 1.0 )
6296  {
6297  /* multiply coefficients and constant of linear expression term2 by coef2 */
6298  SCIP_Real* data;
6299  int i;
6300 
6301  data = (SCIP_Real*)term2->data.data;
6302  assert(data != NULL);
6303 
6304  /* loop one more index to multiply also constant of linear expression */
6305  for( i = 0; i <= term2->nchildren; ++i )
6306  data[i] *= coef2;
6307 
6308  coef2 = 1.0;
6309  }
6310 
6311  if( term1 == NULL || term2 == NULL )
6312  {
6313  if( term1 == NULL )
6314  {
6315  term1 = term2;
6316  coef1 = coef2;
6317  }
6318  if( constant != 0.0 || coef1 != 1.0 )
6319  {
6320  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6321  {
6322  assert(coef1 == 1.0);
6323 
6324  /* add constant to existing linear expression */
6325  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 0, NULL, NULL, constant) );
6326  *expr = term1;
6327  }
6328  else
6329  {
6330  /* create new linear expression for coef1 * term1 + constant */
6331  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term1, &coef1, constant) );
6332  }
6333  }
6334  else
6335  {
6336  assert(constant == 0.0);
6337  assert(coef1 == 1.0);
6338  *expr = term1;
6339  }
6340 
6341  return SCIP_OKAY;
6342  }
6343 
6345  {
6346  /* add 2nd linear expression to first one */
6347  assert(coef1 == 1.0);
6348  assert(coef2 == 1.0);
6349 
6351  SCIPexprFreeShallow(blkmem, &term2);
6352 
6353  *expr = term1;
6354 
6355  return SCIP_OKAY;
6356  }
6357 
6358  if( SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
6359  {
6360  /* if only term2 is linear, then swap */
6361  SCIP_EXPR* tmp;
6362 
6363  tmp = term2;
6364  assert(coef2 == 1.0);
6365 
6366  term2 = term1;
6367  coef2 = coef1;
6368  term1 = tmp;
6369  coef1 = 1.0;
6370  }
6371 
6372  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6373  {
6374  /* add coef2*term2 as extra child to linear expression term1 */
6375  assert(coef1 == 1.0);
6376 
6377  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 1, &coef2, &term2, constant) );
6378  *expr = term1;
6379 
6380  return SCIP_OKAY;
6381  }
6382 
6383  /* both terms are not linear, then create new linear term for sum */
6384  {
6385  SCIP_Real coefs[2];
6386  SCIP_EXPR* children[2];
6387 
6388  coefs[0] = coef1;
6389  coefs[1] = coef2;
6390  children[0] = term1;
6391  children[1] = term2;
6392 
6393  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 2, children, coefs, constant) );
6394  }
6395 
6396  return SCIP_OKAY;
6397 }
6398 
6399 /** creates an expression from the multiplication of an expression with a constant
6400  *
6401  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6402  * Favors creation and maintaining SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6403  */
6405  BMS_BLKMEM* blkmem, /**< block memory data structure */
6406  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
6407  SCIP_EXPR* term, /**< term to multiply by factor */
6408  SCIP_Real factor /**< factor */
6409  )
6410 {
6411  assert(blkmem != NULL);
6412  assert(expr != NULL);
6413  assert(term != NULL);
6414 
6415  if( factor == 0.0 )
6416  {
6417  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, 0.0) );
6418 
6419  SCIPexprFreeDeep(blkmem, &term);
6420 
6421  return SCIP_OKAY;
6422  }
6423  if( factor == 1.0 )
6424  {
6425  *expr = term;
6426  return SCIP_OKAY;
6427  }
6428 
6429  switch( SCIPexprGetOperator(term) )
6430  {
6431  case SCIP_EXPR_CONST :
6432  {
6433  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, factor * SCIPexprGetOpReal(term)) );
6434  SCIPexprFreeDeep(blkmem, &term);
6435  break;
6436  }
6437 
6438  case SCIP_EXPR_LINEAR :
6439  {
6440  SCIP_Real* data;
6441  int i;
6442 
6443  data = (SCIP_Real*)term->data.data;
6444  assert(data != NULL);
6445 
6446  /* loop one more index to multiply also constant of linear expression */
6447  for( i = 0; i <= SCIPexprGetNChildren(term); ++i )
6448  data[i] *= factor;
6449 
6450  *expr = term;
6451  break;
6452  }
6453 
6454  case SCIP_EXPR_QUADRATIC :
6455  {
6457  int i;
6458 
6459  data = (SCIP_EXPRDATA_QUADRATIC*)term->data.data;
6460 
6461  data->constant *= factor;
6462 
6463  if( data->lincoefs != NULL )
6464  for( i = 0; i < term->nchildren; ++i )
6465  data->lincoefs[i] *= factor;
6466 
6467  for( i = 0; i < data->nquadelems; ++i )
6468  data->quadelems[i].coef *= factor;
6469 
6470  *expr = term;
6471  break;
6472  }
6473 
6474  case SCIP_EXPR_POLYNOMIAL :
6475  {
6477  int i;
6478 
6479  data = (SCIP_EXPRDATA_POLYNOMIAL*)term->data.data;
6480 
6481  data->constant *= factor;
6482 
6483  for( i = 0; i < data->nmonomials; ++i )
6484  data->monomials[i]->coef *= factor;
6485 
6486  *expr = term;
6487  break;
6488  }
6489 
6490  default:
6491  {
6492  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term, &factor, 0.0) );
6493  break;
6494  }
6495 
6496  } /*lint !e788 */
6497 
6498  return SCIP_OKAY;
6499 }
6500 
6501 /** creates a SCIP_EXPR_LINEAR expression that is (affine) linear in its children: constant + sum_i coef_i child_i */
6503  BMS_BLKMEM* blkmem, /**< block memory data structure */
6504  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6505  int nchildren, /**< number of children */
6506  SCIP_EXPR** children, /**< children of expression */
6507  SCIP_Real* coefs, /**< coefficients of children */
6508  SCIP_Real constant /**< constant part */
6509  )
6510 {
6511  SCIP_EXPROPDATA opdata;
6512  SCIP_EXPR** childrencopy;
6513  SCIP_Real* data;
6514 
6515  assert(nchildren >= 0);
6516  assert(children != NULL || nchildren == 0);
6517  assert(coefs != NULL || nchildren == 0);
6518 
6519  if( nchildren > 0 )
6520  {
6521  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6522  }
6523  else
6524  childrencopy = NULL;
6525 
6526  /* we store the coefficients and the constant in a single array and make this our operand data */
6527  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, nchildren + 1) );
6528  BMScopyMemoryArray(data, coefs, nchildren); /*lint !e644*/
6529  data[nchildren] = constant;
6530 
6531  opdata.data = (void*)data;
6532 
6533  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_LINEAR, nchildren, childrencopy, opdata) );
6534 
6535  return SCIP_OKAY;
6536 }
6537 
6538 /** adds new terms to a linear expression */
6540  BMS_BLKMEM* blkmem, /**< block memory */
6541  SCIP_EXPR* expr, /**< linear expression */
6542  int nchildren, /**< number of children to add */
6543  SCIP_Real* coefs, /**< coefficients of additional children */
6544  SCIP_EXPR** children, /**< additional children expressions */
6545  SCIP_Real constant /**< constant to add */
6546  )
6547 {
6548  SCIP_Real* data;
6549 
6550  assert(blkmem != NULL);
6551  assert(expr != NULL);
6552  assert(expr->op == SCIP_EXPR_LINEAR);
6553  assert(nchildren >= 0);
6554  assert(coefs != NULL || nchildren == 0);
6555  assert(children != NULL || nchildren == 0);
6556 
6557  data = (SCIP_Real*)expr->data.data;
6558  assert(data != NULL);
6559 
6560  /* handle simple case of adding a constant */
6561  if( nchildren == 0 )
6562  {
6563  data[expr->nchildren] += constant;
6564 
6565  return SCIP_OKAY;
6566  }
6567 
6568  /* add new children to expr's children array */
6569  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nchildren) );
6570  BMScopyMemoryArray(&expr->children[expr->nchildren], children, nchildren); /*lint !e866*/
6571 
6572  /* add constant and new coefs to expr's data array */
6573  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, expr->nchildren + 1, expr->nchildren + nchildren + 1) );
6574  data[expr->nchildren + nchildren] = data[expr->nchildren] + constant;
6575  BMScopyMemoryArray(&data[expr->nchildren], coefs, nchildren); /*lint !e866*/
6576  expr->data.data = (void*)data;
6577 
6578  expr->nchildren += nchildren;
6579 
6580  return SCIP_OKAY;
6581 }
6582 
6583 /** creates a SCIP_EXPR_QUADRATIC expression: constant + sum_i coef_i child_i + sum_i coef_i child1_i child2_i */
6585  BMS_BLKMEM* blkmem, /**< block memory data structure */
6586  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6587  int nchildren, /**< number of children */
6588  SCIP_EXPR** children, /**< children of expression */
6589  SCIP_Real constant, /**< constant */
6590  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
6591  int nquadelems, /**< number of quadratic elements */
6592  SCIP_QUADELEM* quadelems /**< quadratic elements specifying coefficients and child indices */
6593  )
6594 {
6595  SCIP_EXPROPDATA opdata;
6596  SCIP_EXPR** childrencopy;
6598 
6599  assert(nchildren >= 0);
6600  assert(children != NULL || nchildren == 0);
6601  assert(quadelems != NULL || nquadelems == 0);
6602 
6603  if( nchildren > 0 )
6604  {
6605  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6606  }
6607  else
6608  childrencopy = NULL;
6609 
6610  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
6611 
6612  opdata.data = (void*)data;
6613 
6614  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_QUADRATIC, nchildren, childrencopy, opdata) );
6615 
6616  return SCIP_OKAY;
6617 }
6618 
6619 /** ensures that quadratic elements of a quadratic expression are sorted */
6621  SCIP_EXPR* expr /**< quadratic expression */
6622  )
6623 {
6624  assert(expr != NULL);
6625  assert(expr->op == SCIP_EXPR_QUADRATIC);
6626  assert(expr->data.data != NULL);
6627 
6629 }
6630 
6631 /** creates a SCIP_EXPR_POLYNOMIAL expression from an array of monomials: constant + sum_i monomial_i */
6633  BMS_BLKMEM* blkmem, /**< block memory data structure */
6634  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6635  int nchildren, /**< number of children */
6636  SCIP_EXPR** children, /**< children of expression */
6637  int nmonomials, /**< number of monomials */
6638  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
6639  SCIP_Real constant, /**< constant part */
6640  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6641  )
6642 {
6643  SCIP_EXPROPDATA opdata;
6644  SCIP_EXPR** childrencopy;
6646 
6647  assert(nchildren >= 0);
6648  assert(children != NULL || nchildren == 0);
6649  assert(monomials != NULL || nmonomials == 0);
6650 
6651  if( nchildren > 0 )
6652  {
6653  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6654  }
6655  else
6656  childrencopy = NULL;
6657 
6658  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
6659  opdata.data = (void*)data;
6660 
6661  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_POLYNOMIAL, nchildren, childrencopy, opdata) );
6662 
6663  return SCIP_OKAY;
6664 }
6665 
6666 /** adds an array of monomials to a SCIP_EXPR_POLYNOMIAL expression */
6668  BMS_BLKMEM* blkmem, /**< block memory of expression */
6669  SCIP_EXPR* expr, /**< expression */
6670  int nmonomials, /**< number of monomials to add */
6671  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
6672  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6673  )
6674 {
6675  assert(blkmem != NULL);
6676  assert(expr != NULL);
6677  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6678  assert(monomials != NULL || nmonomials == 0);
6679 
6680  if( nmonomials == 0 )
6681  return SCIP_OKAY;
6682 
6683  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, nmonomials, monomials, copymonomials) );
6684 
6685  return SCIP_OKAY;
6686 }
6687 
6688 /** changes the constant in a SCIP_EXPR_POLYNOMIAL expression */
6690  SCIP_EXPR* expr, /**< expression */
6691  SCIP_Real constant /**< new value for constant */
6692  )
6693 {
6694  assert(expr != NULL);
6695  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6696  assert(expr->data.data != NULL);
6697 
6698  ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant = constant;
6699 }
6700 
6701 /** multiplies each summand of a polynomial by a given constant */
6703  BMS_BLKMEM* blkmem, /**< block memory */
6704  SCIP_EXPR* expr, /**< polynomial expression */
6705  SCIP_Real factor /**< constant factor */
6706  )
6707 {
6708  assert(expr != NULL);
6709  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6710  assert(expr->data.data != NULL);
6711 
6712  polynomialdataMultiplyByConstant(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor);
6713 }
6714 
6715 /** multiplies each summand of a polynomial by a given monomial */
6717  BMS_BLKMEM* blkmem, /**< block memory */
6718  SCIP_EXPR* expr, /**< polynomial expression */
6719  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
6720  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6721  )
6722 {
6723  assert(blkmem != NULL);
6724  assert(factor != NULL);
6725  assert(expr != NULL);
6726  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6727  assert(expr->data.data != NULL);
6728 
6729  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor, childmap) );
6730 
6731  return SCIP_OKAY;
6732 }
6733 
6734 /** multiplies this polynomial by a polynomial
6735  *
6736  * Factor needs to be different from expr.
6737  * Children of factor need to be children of expr already, w.r.t. an optional mapping of child indices.
6738  */
6740  BMS_BLKMEM* blkmem, /**< block memory */
6741  SCIP_EXPR* expr, /**< polynomial expression */
6742  SCIP_EXPR* factor, /**< polynomial factor */
6743  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6744  )
6745 {
6746  assert(blkmem != NULL);
6747  assert(expr != NULL);
6748  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6749  assert(expr->data.data != NULL);
6750  assert(factor != NULL);
6751  assert(factor->op == SCIP_EXPR_POLYNOMIAL);
6752  assert(factor->data.data != NULL);
6753  assert(expr != factor);
6754 
6755 #ifndef NDEBUG
6756  if( childmap == NULL )
6757  {
6758  int i;
6759  assert(factor->nchildren == expr->nchildren);
6760  for( i = 0; i < factor->nchildren; ++i )
6761  assert(SCIPexprAreEqual(expr->children[i], factor->children[i], 0.0));
6762  }
6763  else
6764  {
6765  int i;
6766  for( i = 0; i < factor->nchildren; ++i )
6767  {
6768  assert(childmap[i] >= 0);
6769  assert(childmap[i] < expr->nchildren);
6770  assert(SCIPexprAreEqual(expr->children[childmap[i]], factor->children[i], 0.0));
6771  }
6772  }
6773 #endif
6774 
6776 
6777  return SCIP_OKAY;
6778 }
6779 
6780 /** takes a power of the polynomial
6781  *
6782  * Exponent need to be an integer.
6783  * Polynomial needs to be a monomial, if exponent is negative.
6784  */
6786  BMS_BLKMEM* blkmem, /**< block memory */
6787  SCIP_EXPR* expr, /**< polynomial expression */
6788  int exponent /**< exponent of power operation */
6789  )
6790 {
6791  assert(blkmem != NULL);
6792  assert(expr != NULL);
6793  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6794  assert(expr->data.data != NULL);
6795 
6796  SCIP_CALL( polynomialdataPower(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, exponent) );
6797 
6798  return SCIP_OKAY;
6799 }
6800 
6801 /** merges monomials in a polynomial expression that differ only in coefficient into a single monomial
6802  *
6803  * Eliminates monomials with coefficient between -eps and eps.
6804  */
6806  BMS_BLKMEM* blkmem, /**< block memory */
6807  SCIP_EXPR* expr, /**< polynomial expression */
6808  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
6809  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
6810  )
6811 {
6812  assert(expr != NULL);
6813  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6814  assert(expr->data.data != NULL);
6815 
6816  polynomialdataMergeMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, eps, mergefactors);
6817 }
6818 
6819 /** checks if two monomials are equal */
6821  SCIP_EXPRDATA_MONOMIAL* monomial1, /**< first monomial */
6822  SCIP_EXPRDATA_MONOMIAL* monomial2, /**< second monomial */
6823  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6824  )
6825 {
6826  int i;
6827 
6828  assert(monomial1 != NULL);
6829  assert(monomial2 != NULL);
6830 
6831  if( monomial1->nfactors != monomial2->nfactors )
6832  return FALSE;
6833 
6834  if( !EPSEQ(monomial1->coef, monomial2->coef, eps) )
6835  return FALSE;
6836 
6837  SCIPexprSortMonomialFactors(monomial1);
6838  SCIPexprSortMonomialFactors(monomial2);
6839 
6840  for( i = 0; i < monomial1->nfactors; ++i )
6841  {
6842  if( monomial1->childidxs[i] != monomial2->childidxs[i] ||
6843  !EPSEQ(monomial1->exponents[i], monomial2->exponents[i], eps) )
6844  return FALSE;
6845  }
6846 
6847  return TRUE;
6848 }
6849 
6850 /** changes coefficient of monomial */
6852  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6853  SCIP_Real newcoef /**< new coefficient */
6854  )
6855 {
6856  assert(monomial != NULL);
6857 
6858  monomial->coef = newcoef;
6859 }
6860 
6861 /** adds factors to a monomial */
6863  BMS_BLKMEM* blkmem, /**< block memory */
6864  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6865  int nfactors, /**< number of factors to add */
6866  int* childidxs, /**< indices of children corresponding to factors */
6867  SCIP_Real* exponents /**< exponent in each factor */
6868  )
6869 {
6870  assert(monomial != NULL);
6871  assert(nfactors >= 0);
6872  assert(childidxs != NULL || nfactors == 0);
6873  assert(exponents != NULL || nfactors == 0);
6874 
6875  if( nfactors == 0 )
6876  return SCIP_OKAY;
6877 
6878  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + nfactors) );
6879  assert(monomial->nfactors + nfactors <= monomial->factorssize);
6880 
6881  BMScopyMemoryArray(&monomial->childidxs[monomial->nfactors], childidxs, nfactors); /*lint !e866*/
6882  BMScopyMemoryArray(&monomial->exponents[monomial->nfactors], exponents, nfactors); /*lint !e866*/
6883 
6884  monomial->nfactors += nfactors;
6885  monomial->sorted = (monomial->nfactors <= 1);
6886 
6887  return SCIP_OKAY;
6888 }
6889 
6890 /** multiplies a monomial with a monomial */
6892  BMS_BLKMEM* blkmem, /**< block memory */
6893  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6894  SCIP_EXPRDATA_MONOMIAL* factor, /**< factor monomial */
6895  int* childmap /**< map to apply to children in factor, or NULL for 1:1 */
6896  )
6897 {
6898  assert(monomial != NULL);
6899  assert(factor != NULL);
6900 
6901  if( factor->coef == 0.0 )
6902  {
6903  monomial->nfactors = 0;
6904  monomial->coef = 0.0;
6905  return SCIP_OKAY;
6906  }
6907 
6908  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, factor->nfactors, factor->childidxs, factor->exponents) );
6909 
6910  if( childmap != NULL )
6911  {
6912  int i;
6913  for( i = monomial->nfactors - factor->nfactors; i < monomial->nfactors; ++i )
6914  monomial->childidxs[i] = childmap[monomial->childidxs[i]];
6915  }
6916 
6917  monomial->coef *= factor->coef;
6918 
6919  return SCIP_OKAY;
6920 }
6921 
6922 /** replaces the monomial by a power of the monomial
6923  *
6924  * Allows only integers as exponent.
6925  */
6927  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6928  int exponent /**< integer exponent of power operation */
6929  )
6930 {
6931  int i;
6932 
6933  assert(monomial != NULL);
6934 
6935  if( exponent == 1 )
6936  return;
6937 
6938  if( exponent == 0 )
6939  {
6940  /* x^0 = 1, unless x = 0; 0^0 = 0 */
6941  if( monomial->coef != 0.0 )
6942  monomial->coef = 1.0;
6943  monomial->nfactors = 0;
6944  return;
6945  }
6946 
6947  monomial->coef = pow(monomial->coef, (SCIP_Real)exponent);
6948  for( i = 0; i < monomial->nfactors; ++i )
6949  monomial->exponents[i] *= exponent;
6950 }
6951 
6952 /** merges factors that correspond to the same child by adding exponents
6953  *
6954  * Eliminates factors with exponent between -eps and eps.
6955  */
6957  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6958  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6959  )
6960 {
6961  int i;
6962  int offset;
6963 
6964  assert(monomial != NULL);
6965  assert(eps >= 0.0);
6966 
6967  SCIPexprSortMonomialFactors(monomial);
6968 
6969  /* merge factors with same child index by adding up their exponents
6970  * delete factors with exponent 0.0 */
6971  offset = 0;
6972  i = 0;
6973  while( i + offset < monomial->nfactors )
6974  {
6975  if( offset > 0 )
6976  {
6977  assert(monomial->childidxs[i] == -1);
6978  assert(monomial->childidxs[i+offset] >= 0);
6979  monomial->childidxs[i] = monomial->childidxs[i+offset];
6980  monomial->exponents[i] = monomial->exponents[i+offset];
6981 #ifndef NDEBUG
6982  monomial->childidxs[i+offset] = -1;
6983 #endif
6984  }
6985 
6986  while( i+offset+1 < monomial->nfactors && monomial->childidxs[i] == monomial->childidxs[i+offset+1] )
6987  {
6988  monomial->exponents[i] += monomial->exponents[i+offset+1];
6989 #ifndef NDEBUG
6990  monomial->childidxs[i+offset+1] = -1;
6991 #endif
6992  ++offset;
6993  }
6994 
6995  if( EPSZ(monomial->exponents[i], eps) )
6996  {
6997 #ifndef NDEBUG
6998  monomial->childidxs[i] = -1;
6999 #endif
7000  ++offset;
7001  continue;
7002  }
7003  else if( EPSISINT(monomial->exponents[i], eps) )
7004  monomial->exponents[i] = EPSROUND(monomial->exponents[i], eps);
7005 
7006  ++i;
7007  }
7008 
7009 #ifndef NDEBUG
7010  for( ; i < monomial->nfactors; ++i )
7011  assert(monomial->childidxs[i] == -1);
7012 #endif
7013 
7014  monomial->nfactors -= offset;
7015 
7016  if( EPSEQ(monomial->coef, 1.0, eps) )
7017  monomial->coef = 1.0;
7018  else if( EPSEQ(monomial->coef, -1.0, eps) )
7019  monomial->coef = -1.0;
7020 }
7021 
7022 /** ensures that monomials of a polynomial are sorted */
7024  SCIP_EXPR* expr /**< polynomial expression */
7025  )
7026 {
7027  assert(expr != NULL);
7028  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
7029  assert(expr->data.data != NULL);
7030 
7032 }
7033 
7034 /** creates a monomial */
7036  BMS_BLKMEM* blkmem, /**< block memory */
7037  SCIP_EXPRDATA_MONOMIAL** monomial, /**< buffer where to store pointer to new monomial */
7038  SCIP_Real coef, /**< coefficient of monomial */
7039  int nfactors, /**< number of factors in monomial */
7040  int* childidxs, /**< indices of children corresponding to factors, or NULL if identity */
7041  SCIP_Real* exponents /**< exponent in each factor, or NULL if all 1.0 */
7042  )
7043 {
7044  assert(blkmem != NULL);
7045  assert(monomial != NULL);
7046 
7047  SCIP_ALLOC( BMSallocBlockMemory(blkmem, monomial) );
7048 
7049  (*monomial)->coef = coef;
7050  (*monomial)->nfactors = nfactors;
7051  (*monomial)->factorssize = nfactors;
7052  (*monomial)->sorted = (nfactors <= 1);
7053 
7054  if( nfactors > 0 )
7055  {
7056  if( childidxs != NULL )
7057  {
7058  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->childidxs, childidxs, nfactors) );
7059  }
7060  else
7061  {
7062  int i;
7063 
7064  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->childidxs, nfactors) );
7065  for( i = 0; i < nfactors; ++i )
7066  (*monomial)->childidxs[i] = i;
7067  }
7068 
7069  if( exponents != NULL )
7070  {
7071  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->exponents, exponents, nfactors) );
7072  }
7073  else
7074  {
7075  int i;
7076 
7077  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->exponents, nfactors) );
7078  for( i = 0; i < nfactors; ++i )
7079  (*monomial)->exponents[i] = 1.0;
7080  }
7081  }
7082  else
7083  {
7084  (*monomial)->childidxs = NULL;
7085  (*monomial)->exponents = NULL;
7086  }
7087 
7088  return SCIP_OKAY;
7089 }
7090 
7091 /** frees a monomial */
7093  BMS_BLKMEM* blkmem, /**< block memory */
7094  SCIP_EXPRDATA_MONOMIAL** monomial /**< pointer to monomial that should be freed */
7095  )
7096 {
7097  assert(blkmem != NULL);
7098  assert( monomial != NULL);
7099  assert(*monomial != NULL);
7100 
7101  if( (*monomial)->factorssize > 0 )
7102  {
7103  assert((*monomial)->childidxs != NULL);
7104  assert((*monomial)->exponents != NULL);
7105 
7106  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->childidxs, (*monomial)->factorssize);
7107  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->exponents, (*monomial)->factorssize);
7108  }
7109  assert((*monomial)->childidxs == NULL);
7110  assert((*monomial)->exponents == NULL);
7111 
7112  BMSfreeBlockMemory(blkmem, monomial);
7113 }
7114 
7115 /** ensures that factors in a monomial are sorted */
7117  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
7118  )
7119 {
7120  assert(monomial != NULL);
7121 
7122  if( monomial->sorted )
7123  return;
7124 
7125  if( monomial->nfactors > 0 )
7126  SCIPsortIntReal(monomial->childidxs, monomial->exponents, monomial->nfactors);
7127 
7128  monomial->sorted = TRUE;
7129 }
7130 
7131 /** finds a factor corresponding to a given child index in a monomial
7132  *
7133  * Note that if the factors have not been merged, the position of some factor corresponding to a given child is given.
7134  * Returns TRUE if a factor is found, FALSE if not.
7135  */
7137  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
7138  int childidx, /**< index of the child which factor to search for */
7139  int* pos /**< buffer to store position of factor */
7140  )
7141 {
7142  assert(monomial != NULL);
7143 
7144  if( monomial->nfactors == 0 )
7145  return FALSE;
7146 
7147  SCIPexprSortMonomialFactors(monomial);
7148 
7149  return SCIPsortedvecFindInt(monomial->childidxs, childidx, monomial->nfactors, pos);
7150 }
7151 
7152 /** creates a user expression */
7154  BMS_BLKMEM* blkmem, /**< block memory data structure */
7155  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
7156  int nchildren, /**< number of children */
7157  SCIP_EXPR** children, /**< children of expression */
7158  SCIP_USEREXPRDATA* data, /**< user data for expression, expression assumes ownership */
7159  SCIP_EXPRINTCAPABILITY evalcapability, /**< capability of evaluation functions (partially redundant, currently) */
7160  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
7161  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function, or NULL if not implemented */
7162  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
7163  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function, or NULL if not implemented */
7164  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
7165  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
7166  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
7167  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
7168  )
7169 {
7170  SCIP_EXPROPDATA opdata;
7171  SCIP_EXPRDATA_USER* userexprdata;
7172  SCIP_EXPR** childrencopy;
7173 
7174  assert(blkmem != NULL);
7175  assert(expr != NULL);
7176  assert(eval != NULL);
7177  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
7178  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
7179  assert(curv != NULL);
7180  assert(copydata != NULL || data == NULL);
7181  assert(freedata != NULL || data == NULL);
7182 
7183  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &userexprdata) );
7184 
7185  userexprdata->userdata = data;
7186  userexprdata->evalcapability = evalcapability;
7187  userexprdata->eval = eval;
7188  userexprdata->inteval = inteval;
7189  userexprdata->curv = curv;
7190  userexprdata->prop = prop;
7191  userexprdata->estimate = estimate;
7192  userexprdata->copydata = copydata;
7193  userexprdata->freedata = freedata;
7194  userexprdata->print = print;
7195 
7196  opdata.data = (void*) userexprdata;
7197 
7198  if( nchildren == 0 )
7199  {
7200  SCIP_CALL( exprCreate(blkmem, expr, SCIP_EXPR_USER, 0, NULL, opdata) );
7201  return SCIP_OKAY;
7202  }
7203  assert(children != NULL);
7204 
7205  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
7206 
7207  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_USER, nchildren, childrencopy, opdata) );
7208 
7209  return SCIP_OKAY;
7210 }
7211 
7212 /** indicates whether the expression contains a SCIP_EXPR_PARAM */
7214  SCIP_EXPR* expr /**< expression */
7215  )
7216 {
7217  int i;
7218 
7219  assert(expr != NULL);
7220 
7221  if( expr->op == SCIP_EXPR_PARAM )
7222  return TRUE;
7223 
7224  for( i = 0; i < expr->nchildren; ++i )
7225  if( SCIPexprHasParam(expr->children[i]) )
7226  return TRUE;
7227 
7228  return FALSE;
7229 }
7230 
7231 /** gets maximal degree of expression, or SCIP_EXPR_DEGREEINFINITY if not a polynomial */
7233  SCIP_EXPR* expr, /**< expression */
7234  int* maxdegree /**< buffer to store maximal degree */
7235  )
7236 {
7237  int child1;
7238  int child2;
7239 
7240  assert(expr != NULL);
7241  assert(maxdegree != NULL);
7242 
7243  switch( expr->op )
7244  {
7245  case SCIP_EXPR_VARIDX:
7246  *maxdegree = 1;
7247  break;
7248 
7249  case SCIP_EXPR_CONST:
7250  case SCIP_EXPR_PARAM:
7251  *maxdegree = 0;
7252  break;
7253 
7254  case SCIP_EXPR_PLUS:
7255  case SCIP_EXPR_MINUS:
7256  {
7257  assert(expr->children[0] != NULL);
7258  assert(expr->children[1] != NULL);
7259 
7260  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7261  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7262 
7263  *maxdegree = MAX(child1, child2);
7264  break;
7265  }
7266 
7267  case SCIP_EXPR_MUL:
7268  {
7269  assert(expr->children[0] != NULL);
7270  assert(expr->children[1] != NULL);
7271 
7272  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7273  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7274 
7275  *maxdegree = child1 + child2;
7276  break;
7277  }
7278 
7279  case SCIP_EXPR_DIV:
7280  {
7281  assert(expr->children[0] != NULL);
7282  assert(expr->children[1] != NULL);
7283 
7284  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7285  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7286 
7287  /* if not division by constant, then it is not a polynomial */
7288  *maxdegree = (child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : child1;
7289  break;
7290  }
7291 
7292  case SCIP_EXPR_SQUARE:
7293  {
7294  assert(expr->children[0] != NULL);
7295 
7296  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7297 
7298  *maxdegree = 2 * child1;
7299  break;
7300  }
7301 
7302  case SCIP_EXPR_SQRT:
7303  {
7304  assert(expr->children[0] != NULL);
7305 
7306  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7307 
7308  /* if not squareroot of constant, then no polynomial */
7309  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7310  break;
7311  }
7312 
7313  case SCIP_EXPR_REALPOWER:
7314  {
7315  assert(expr->children[0] != NULL);
7316 
7317  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7318 
7319  /* constant ^ constant has degree 0 */
7320  if( child1 == 0 )
7321  {
7322  *maxdegree = 0;
7323  break;
7324  }
7325 
7326  /* non-polynomial ^ constant is not a polynomial */
7327  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7328  {
7329  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7330  break;
7331  }
7332 
7333  /* so it is polynomial ^ constant
7334  * let's see whether the constant is integral */
7335 
7336  if( expr->data.dbl == 0.0 ) /* polynomial ^ 0 == 0 */
7337  *maxdegree = 0;
7338  else if( expr->data.dbl > 0.0 && (int)expr->data.dbl == expr->data.dbl ) /* natural exponent gives polynomial again */ /*lint !e777*/
7339  *maxdegree = child1 * (int)expr->data.dbl;
7340  else /* negative or nonintegral exponent does not give polynomial */
7341  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7342 
7343  break;
7344  }
7345 
7346  case SCIP_EXPR_INTPOWER:
7347  {
7348  assert(expr->children[0] != NULL);
7349 
7350  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7351 
7352  /* constant ^ integer or something ^ 0 has degree 0 */
7353  if( child1 == 0 || expr->data.intval == 0 )
7354  {
7355  *maxdegree = 0;
7356  break;
7357  }
7358 
7359  /* non-polynomial ^ integer or something ^ negative is not a polynomial */
7360  if( child1 >= SCIP_EXPR_DEGREEINFINITY || expr->data.intval < 0 )
7361  {
7362  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7363  break;
7364  }
7365 
7366  /* so it is polynomial ^ natural, which gives a polynomial again */
7367  *maxdegree = child1 * expr->data.intval;
7368 
7369  break;
7370  }
7371 
7372  case SCIP_EXPR_SIGNPOWER:
7373  {
7374  assert(expr->children[0] != NULL);
7375 
7376  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7377 
7378  /* if child is not constant, then it is no polynomial */
7379  *maxdegree = child1 != 0 ? SCIP_EXPR_DEGREEINFINITY : 0;
7380  break;
7381  }
7382 
7383  case SCIP_EXPR_EXP:
7384  case SCIP_EXPR_LOG:
7385  case SCIP_EXPR_SIN:
7386  case SCIP_EXPR_COS:
7387  case SCIP_EXPR_TAN:
7388  /* case SCIP_EXPR_ERF: */
7389  /* case SCIP_EXPR_ERFI: */
7390  case SCIP_EXPR_ABS:
7391  case SCIP_EXPR_SIGN:
7392  case SCIP_EXPR_USER:
7393  {
7394  assert(expr->children[0] != NULL);
7395 
7396  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7397 
7398  /* if argument is not a constant, then no polynomial, otherwise it is a constant */
7399  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7400  break;
7401  }
7402 
7403  case SCIP_EXPR_MIN:
7404  case SCIP_EXPR_MAX:
7405  {
7406  assert(expr->children[0] != NULL);
7407  assert(expr->children[1] != NULL);
7408 
7409  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7410  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7411 
7412  /* if any of the operands is not constant, then it is no polynomial */
7413  *maxdegree = (child1 != 0 || child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7414  break;
7415  }
7416 
7417  case SCIP_EXPR_SUM:
7418  case SCIP_EXPR_LINEAR:
7419  {
7420  int i;
7421 
7422  *maxdegree = 0;
7423  for( i = 0; i < expr->nchildren && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7424  {
7425  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7426  if( child1 > *maxdegree )
7427  *maxdegree = child1;
7428  }
7429 
7430  break;
7431  }
7432 
7433  case SCIP_EXPR_PRODUCT:
7434  {
7435  int i;
7436 
7437  *maxdegree = 0;
7438  for( i = 0; i < expr->nchildren; ++i )
7439  {
7440  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7441  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7442  {
7443  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7444  break;
7445  }
7446  *maxdegree += child1;
7447  }
7448 
7449  break;
7450  }
7451 
7452  case SCIP_EXPR_QUADRATIC:
7453  {
7454  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7455  int childidx;
7456  int quadidx;
7457 
7458  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7459 
7460  /* make sure quadratic elements are sorted */
7461  quadraticdataSort(quadraticdata);
7462 
7463  *maxdegree = 0;
7464  quadidx = 0;
7465  for( childidx = 0; childidx < expr->nchildren; ++childidx )
7466  {
7467  /* if no linear or no quadratic coefficient with current child on first position, then nothing to do */
7468  if( (quadraticdata->lincoefs == NULL || quadraticdata->lincoefs[childidx] == 0.0) &&
7469  (quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 > childidx) )
7470  continue;
7471 
7472  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[childidx], &child1) );
7473  if( child1 == SCIP_EXPR_DEGREEINFINITY )
7474  {
7475  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7476  break;
7477  }
7478 
7479  while( quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 == childidx )
7480  {
7481  if( quadraticdata->quadelems[quadidx].idx2 == childidx )
7482  {
7483  /* square term */
7484  if( 2*child1 > *maxdegree )
7485  *maxdegree = 2*child1;
7486  }
7487  else
7488  {
7489  /* bilinear term */
7490  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[quadraticdata->quadelems[quadidx].idx2], &child2) );
7491  if( child2 == SCIP_EXPR_DEGREEINFINITY )
7492  {
7493  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7494  break;
7495  }
7496  if( child1 + child2 > *maxdegree )
7497  *maxdegree = child1 + child2;
7498  }
7499  ++quadidx;
7500  }
7501  if( *maxdegree == SCIP_EXPR_DEGREEINFINITY )
7502  break;
7503  }
7504 
7505  break;
7506  }
7507 
7508  case SCIP_EXPR_POLYNOMIAL:
7509  {
7510  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7511  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7512  int monomialdegree;
7513  int i;
7514  int j;
7515 
7516  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7517 
7518  *maxdegree = 0;
7519  for( i = 0; i < polynomialdata->nmonomials && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7520  {
7521  monomialdata = polynomialdata->monomials[i];
7522  assert(monomialdata != NULL);
7523 
7524  /* compute degree of monomial = sum of degree of factors */
7525  monomialdegree = 0;
7526  for( j = 0; j < monomialdata->nfactors; ++j )
7527  {
7528  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[monomialdata->childidxs[j]], &child1) );
7529 
7530  /* if the exponent of the factor is not a natural number and the child is not constant (degree 0),
7531  * then we report that we are not really a polynomial */
7532  if( child1 != 0 && (monomialdata->exponents[j] < 0.0 || (int)monomialdata->exponents[j] != monomialdata->exponents[j]) )
7533  {
7534  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7535  break;
7536  }
7537 
7538  monomialdegree += child1 * (int)monomialdata->exponents[j];
7539  }
7540 
7541  if( monomialdegree > *maxdegree )
7542  *maxdegree = monomialdegree;
7543  }
7544 
7545  break;
7546  }
7547 
7548  case SCIP_EXPR_LAST:
7549  SCIPABORT();
7550  break;
7551  }
7552 
7553  return SCIP_OKAY;
7554 }
7555 
7556 /** counts usage of variables in expression */
7558  SCIP_EXPR* expr, /**< expression to update */
7559  int* varsusage /**< array with counters of variable usage */
7560  )
7561 {
7562  int i;
7563 
7564  assert(expr != NULL);
7565  assert(varsusage != NULL);
7566 
7567  if( expr->op == SCIP_EXPR_VARIDX )
7568  {
7569  ++varsusage[expr->data.intval];
7570  }
7571 
7572  for( i = 0; i < expr->nchildren; ++i )
7573  SCIPexprGetVarsUsage(expr->children[i], varsusage);
7574 }
7575 
7576 /** compares whether two expressions are the same
7577  *
7578  * Inconclusive, i.e., may give FALSE even if expressions are equivalent (x*y != y*x).
7579  */
7581  SCIP_EXPR* expr1, /**< first expression */
7582  SCIP_EXPR* expr2, /**< second expression */
7583  SCIP_Real eps /**< threshold under which numbers are assumed to be zero */
7584  )
7585 {
7586  assert(expr1 != NULL);
7587  assert(expr2 != NULL);
7588 
7589  if( expr1 == expr2 )
7590  return TRUE;
7591 
7592  if( expr1->op != expr2->op )
7593  return FALSE;
7594 
7595  switch( expr1->op )
7596  {
7597  case SCIP_EXPR_VARIDX:
7598  case SCIP_EXPR_PARAM:
7599  return expr1->data.intval == expr2->data.intval;
7600 
7601  case SCIP_EXPR_CONST:
7602  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps);
7603 
7604  /* operands with two children */
7605  case SCIP_EXPR_PLUS :
7606  case SCIP_EXPR_MINUS :
7607  case SCIP_EXPR_MUL :
7608  case SCIP_EXPR_DIV :
7609  case SCIP_EXPR_MIN :
7610  case SCIP_EXPR_MAX :
7611  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps) && SCIPexprAreEqual(expr1->children[1], expr2->children[1], eps);
7612 
7613  /* operands with one child */
7614  case SCIP_EXPR_SQUARE:
7615  case SCIP_EXPR_SQRT :
7616  case SCIP_EXPR_EXP :
7617  case SCIP_EXPR_LOG :
7618  case SCIP_EXPR_SIN :
7619  case SCIP_EXPR_COS :
7620  case SCIP_EXPR_TAN :
7621  /* case SCIP_EXPR_ERF : */
7622  /* case SCIP_EXPR_ERFI : */
7623  case SCIP_EXPR_ABS :
7624  case SCIP_EXPR_SIGN :
7625  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7626 
7627  case SCIP_EXPR_REALPOWER:
7628  case SCIP_EXPR_SIGNPOWER:
7629  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps) && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7630 
7631  case SCIP_EXPR_INTPOWER:
7632  return expr1->data.intval == expr2->data.intval && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7633 
7634  /* complex operands */
7635  case SCIP_EXPR_SUM :
7636  case SCIP_EXPR_PRODUCT:
7637  {
7638  int i;
7639 
7640  /* @todo sort children and have sorted flag in data? */
7641 
7642  if( expr1->nchildren != expr2->nchildren )
7643  return FALSE;
7644 
7645  for( i = 0; i < expr1->nchildren; ++i )
7646  {
7647  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7648  return FALSE;
7649  }
7650 
7651  return TRUE;
7652  }
7653 
7654  case SCIP_EXPR_LINEAR :
7655  {
7656  SCIP_Real* data1;
7657  SCIP_Real* data2;
7658  int i;
7659 
7660  /* @todo sort children and have sorted flag in data? */
7661 
7662  if( expr1->nchildren != expr2->nchildren )
7663  return FALSE;
7664 
7665  data1 = (SCIP_Real*)expr1->data.data;
7666  data2 = (SCIP_Real*)expr2->data.data;
7667 
7668  /* check if constant and coefficients are equal */
7669  for( i = 0; i < expr1->nchildren + 1; ++i )
7670  if( !EPSEQ(data1[i], data2[i], eps) )
7671  return FALSE;
7672 
7673  /* check if children are equal */
7674  for( i = 0; i < expr1->nchildren; ++i )
7675  {
7676  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7677  return FALSE;
7678  }
7679 
7680  return TRUE;
7681  }
7682 
7683  case SCIP_EXPR_QUADRATIC:
7684  {
7685  SCIP_EXPRDATA_QUADRATIC* data1;
7686  SCIP_EXPRDATA_QUADRATIC* data2;
7687  int i;
7688 
7689  if( expr1->nchildren != expr2->nchildren )
7690  return FALSE;
7691 
7692  data1 = (SCIP_EXPRDATA_QUADRATIC*)expr1->data.data;
7693  data2 = (SCIP_EXPRDATA_QUADRATIC*)expr2->data.data;
7694 
7695  if( data1->nquadelems != data2->nquadelems )
7696  return FALSE;
7697 
7698  if( !EPSEQ(data1->constant, data2->constant, eps) )
7699  return FALSE;
7700 
7701  /* check if linear part is equal */
7702  if( data1->lincoefs != NULL || data2->lincoefs != NULL )
7703  for( i = 0; i < expr1->nchildren; ++i )
7704  {
7705  if( data1->lincoefs == NULL )
7706  {
7707  if( !EPSZ(data2->lincoefs[i], eps) )
7708  return FALSE;
7709  }
7710  else if( data2->lincoefs == NULL )
7711  {
7712  if( !EPSZ(data1->lincoefs[i], eps) )
7713  return FALSE;
7714  }
7715  else if( !EPSEQ(data1->lincoefs[i], data2->lincoefs[i], eps) )
7716  return FALSE;
7717  }
7718 
7719  SCIPexprSortQuadElems(expr1);
7720  SCIPexprSortQuadElems(expr2);
7721 
7722  /* check if quadratic elements are equal */
7723  for( i = 0; i < data1->nquadelems; ++i )
7724  if( data1->quadelems[i].idx1 != data2->quadelems[i].idx1 ||
7725  data1->quadelems[i].idx2 != data2->quadelems[i].idx2 ||
7726  !EPSEQ(data1->quadelems[i].coef, data2->quadelems[i].coef, eps) )
7727  return FALSE;
7728 
7729  /* check if children are equal */
7730  for( i = 0; i < expr1->nchildren; ++i )
7731  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7732  return FALSE;
7733 
7734  return TRUE;
7735  }
7736 
7737  case SCIP_EXPR_POLYNOMIAL:
7738  {
7739  SCIP_EXPRDATA_POLYNOMIAL* data1;
7740  SCIP_EXPRDATA_POLYNOMIAL* data2;
7741  int i;
7742 
7743  if( expr1->nchildren != expr2->nchildren )
7744  return FALSE;
7745 
7746  data1 = (SCIP_EXPRDATA_POLYNOMIAL*)expr1->data.data;
7747  data2 = (SCIP_EXPRDATA_POLYNOMIAL*)expr2->data.data;
7748 
7749  if( data1->nmonomials != data2->nmonomials )
7750  return FALSE;
7751 
7752  if( !EPSEQ(data1->constant, data2->constant, eps) )
7753  return FALSE;
7754 
7755  /* make sure polynomials are sorted */
7756  SCIPexprSortMonomials(expr1);
7757  SCIPexprSortMonomials(expr2);
7758 
7759  /* check if monomials are equal */
7760  for( i = 0; i < data1->nmonomials; ++i )
7761  {
7762  if( !SCIPexprAreMonomialsEqual(data1->monomials[i], data2->monomials[i], eps) )
7763  return FALSE;
7764  }
7765 
7766  /* check if children are equal */
7767  for( i = 0; i < expr1->nchildren; ++i )
7768  {
7769  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7770  return FALSE;
7771  }
7772 
7773  return TRUE;
7774  }
7775 
7776  case SCIP_EXPR_USER:
7777  {
7778  /* @todo could implement this via another user callback */
7779  return FALSE;
7780  }
7781 
7782  case SCIP_EXPR_LAST:
7783  break;
7784  }
7785 
7786  SCIPerrorMessage("this should never happen\n");
7787  SCIPABORT();
7788  return FALSE; /*lint !e527*/
7789 }
7790 
7791 /** aims at simplifying an expression and splitting of a linear expression
7792  *
7793  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
7794  */
7796  BMS_BLKMEM* blkmem, /**< block memory data structure */
7797  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7798  SCIP_EXPR* expr, /**< expression */
7799  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
7800  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
7801  int nvars, /**< number of variables in expression */
7802  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
7803  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
7804  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
7805  )
7806 {
7807  assert(blkmem != NULL);
7808  assert(expr != NULL);
7809  assert(eps >= 0.0);
7810 
7811  SCIPdebugMessage("simplify expression: ");
7812  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7813  SCIPdebugPrintf("\n");
7814 
7816 
7817  SCIPdebugMessage("converted to polynomials: ");
7818  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7819  SCIPdebugPrintf("\n");
7820 
7821  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr, eps, maxexpansionexponent) );
7822 
7823  SCIPdebugMessage("polynomials flattened: ");
7824  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7825  SCIPdebugPrintf("\n");
7826 
7827  if( nlinvars != NULL )
7828  {
7829  /* separate linear part from root polynomial */
7830  SCIP_CALL( exprsimplifySeparateLinearFromPolynomial(blkmem, expr, eps, nvars, nlinvars, linidxs, lincoefs) );
7831 
7832  SCIPdebugMessage("separated linear part: ");
7833  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7834  SCIPdebugPrintf("\n");
7835  }
7836 
7838 
7839  SCIPdebugMessage("converted back from polynomials: ");
7840  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7841  SCIPdebugPrintf("\n");
7842 
7843  return SCIP_OKAY;
7844 }
7845 
7846 /** evaluates an expression w.r.t. given values for children expressions */
7848  SCIP_EXPR* expr, /**< expression */
7849  SCIP_Real* argvals, /**< values for children, can be NULL if the expression has no children */
7850  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression operand is not a variable */
7851  SCIP_Real* param, /**< values for parameters, can be NULL if the expression operand is not a parameter */
7852  SCIP_Real* val /**< buffer to store value */
7853  )
7854 {
7855  assert(expr != NULL);
7856  assert(argvals != NULL || expr->nchildren == 0);
7857 
7858  /* evaluate this expression */
7859  assert( exprOpTable[expr->op].eval != NULL );
7860  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, argvals, varvals, param, val) );
7861 
7862  return SCIP_OKAY;
7863 }
7864 
7865 /** evaluates an expression w.r.t. a point */
7867  SCIP_EXPR* expr, /**< expression */
7868  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression is constant */
7869  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7870  SCIP_Real* val /**< buffer to store value */
7871  )
7872 {
7873  int i;
7875  SCIP_Real* buf;
7876 
7877  /* if many children, get large enough memory to store argument values */
7879  {
7880  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7881  }
7882  else
7883  {
7884  buf = staticbuf;
7885  }
7886 
7887  /* evaluate children */
7888  for( i = 0; i < expr->nchildren; ++i )
7889  {
7890  SCIP_CALL( SCIPexprEval(expr->children[i], varvals, param, &buf[i]) ); /*lint !e644*/
7891  }
7892 
7893  /* evaluate this expression */
7894  assert( exprOpTable[expr->op].eval != NULL );
7895  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, buf, varvals, param, val) );
7896 
7897  /* free memory, if allocated before */
7898  if( staticbuf != buf )
7899  {
7900  BMSfreeMemoryArray(&buf);
7901  }
7902 
7903  return SCIP_OKAY;
7904 }
7905 
7906 /** evaluates an expression w.r.t. given interval values for children expressions */
7908  SCIP_EXPR* expr, /**< expression */
7909  SCIP_Real infinity, /**< value to use for infinity */
7910  SCIP_INTERVAL* argvals, /**< interval values for children, can be NULL if the expression has no children */
7911  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7912  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7913  SCIP_INTERVAL* val /**< buffer to store value */
7914  )
7915 {
7916  assert(expr != NULL);
7917  assert(argvals != NULL || expr->nchildren == 0);
7918 
7919  /* evaluate this expression */
7920  assert( exprOpTable[expr->op].inteval != NULL );
7921  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, argvals, varvals, param, val) );
7922 
7923  return SCIP_OKAY;
7924 }
7925 
7926 /** evaluates an expression w.r.t. an interval */
7928  SCIP_EXPR* expr, /**< expression */
7929  SCIP_Real infinity, /**< value to use for infinity */
7930  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7931  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7932  SCIP_INTERVAL* val /**< buffer to store value */
7933  )
7934 {
7935  int i;
7937  SCIP_INTERVAL* buf;
7938 
7939  /* if many children, get large enough memory to store argument values */
7941  {
7942  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7943  }
7944  else
7945  {
7946  buf = staticbuf;
7947  }
7948 
7949  /* evaluate children */
7950  for( i = 0; i < expr->nchildren; ++i )
7951  {
7952  SCIP_CALL( SCIPexprEvalInt(expr->children[i], infinity, varvals, param, &buf[i]) ); /*lint !e644*/
7953  }
7954 
7955  /* evaluate this expression */
7956  assert( exprOpTable[expr->op].inteval != NULL );
7957  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, buf, varvals, param, val) );
7958 
7959  /* free memory, if allocated before */
7960  if( staticbuf != buf )
7961  {
7962  BMSfreeMemoryArray(&buf);
7963  }
7964 
7965  return SCIP_OKAY;
7966 }
7967 
7968 /** evaluates a user expression w.r.t. given values for children expressions */
7970  SCIP_EXPR* expr, /**< expression */
7971  SCIP_Real* argvals, /**< values for children */
7972  SCIP_Real* val, /**< buffer to store function value */
7973  SCIP_Real* gradient, /**< buffer to store gradient values, or NULL if not requested */
7974  SCIP_Real* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7975  )
7976 {
7977  SCIP_EXPRDATA_USER* exprdata;
7978 
7979  assert(expr != NULL);
7980  assert(expr->op == SCIP_EXPR_USER);
7981  assert(argvals != NULL || expr->nchildren == 0);
7982 
7983  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7984  assert(exprdata->eval != NULL);
7985 
7986  SCIP_CALL( exprdata->eval(exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7987 
7988  return SCIP_OKAY;
7989 }
7990 
7991 /** evaluates a user expression w.r.t. an interval */
7993  SCIP_EXPR* expr, /**< expression */
7994  SCIP_Real infinity, /**< value to use for infinity */
7995  SCIP_INTERVAL* argvals, /**< values for children */
7996  SCIP_INTERVAL* val, /**< buffer to store value */
7997  SCIP_INTERVAL* gradient, /**< buffer to store gradient values, or NULL if not requested */
7998  SCIP_INTERVAL* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7999  )
8000 {
8001  SCIP_EXPRDATA_USER* exprdata;
8002 
8003  assert(expr != NULL);
8004  assert(expr->op == SCIP_EXPR_USER);
8005  assert(argvals != NULL || expr->nchildren == 0);
8006 
8007  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8008 
8009  if( exprdata->inteval == NULL )
8010  {
8011  int i;
8012 
8013  for( i = 0; i < expr->nchildren; ++i )
8014  SCIPintervalSetEntire(infinity, &argvals[i]); /*lint !e613*/
8015  }
8016  else
8017  {
8018  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
8019  }
8020 
8021  return SCIP_OKAY;
8022 }
8023 
8024 /** internal curvature check method */
8025 static
8027  SCIP_EXPR* expr, /**< expression to check */
8028  SCIP_Real infinity, /**< value to use for infinity */
8029  SCIP_INTERVAL* varbounds, /**< domains of variables */
8030  SCIP_INTERVAL* childbounds, /**< child bounds buffer array */
8031  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
8032  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8033  SCIP_EXPRCURV* childcurv, /**< buffer array for curvature of children */
8034  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
8035  )
8036 {
8037  int i;
8038 
8039  assert(childbounds != NULL);
8040  assert(childcurv != NULL);
8041 
8042  /* check curvature and compute bounds of children
8043  * constant children can be considered as always linear */
8044  for( i = 0; i < expr->nchildren; ++i )
8045  {
8046  SCIP_CALL( SCIPexprCheckCurvature(expr->children[i], infinity, varbounds, param, &childcurv[i], &childbounds[i]) ); /*lint !e644*/
8047  if( childbounds[i].inf == childbounds[i].sup ) /*lint !e777*/
8048  childcurv[i] = SCIP_EXPRCURV_LINEAR;
8049  }
8050 
8051  /* get curvature and bounds of expr */
8052  assert(exprOpTable[expr->op].curv != NULL);
8053  assert(exprOpTable[expr->op].inteval != NULL);
8054 
8055  SCIP_CALL( exprOpTable[expr->op].curv(infinity, expr->data, expr->nchildren, childbounds, childcurv, curv) );
8056  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, childbounds, varbounds, param, bounds) );
8057 
8058  return SCIP_OKAY;
8059 }
8060 
8061 /** tries to determine the curvature type of an expression w.r.t. given variable domains */
8063  SCIP_EXPR* expr, /**< expression to check */
8064  SCIP_Real infinity, /**< value to use for infinity */
8065  SCIP_INTERVAL* varbounds, /**< domains of variables */
8066  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
8067  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8068  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
8069  )
8070 {
8072  SCIP_INTERVAL* childbounds = NULL;
8074  SCIP_EXPRCURV* childcurv = NULL;
8075  SCIP_RETCODE retcode = SCIP_OKAY;
8076 
8077  assert(expr != NULL);
8078  assert(curv != NULL);
8079  assert(bounds != NULL);
8080 
8081  /* if many children, get large enough memory to store argument values */
8083  {
8084  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, expr->nchildren) );
8085  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, expr->nchildren), TERMINATE );
8086  }
8087  else
8088  {
8089  childbounds = childboundsbuf;
8090  childcurv = childcurvbuf;
8091  }
8092 
8093  retcode = doCheckCurvature(expr, infinity, varbounds, childbounds, param, curv, childcurv, bounds);
8094 
8095 TERMINATE:
8096  /* free memory, if allocated before */
8097  if( childboundsbuf != childbounds )
8098  {
8099  BMSfreeMemoryArrayNull(&childcurv);
8100  BMSfreeMemoryArrayNull(&childbounds);
8101  }
8102 
8103  return retcode;
8104 }
8105 
8106 /** under-/overestimates a user expression w.r.t. to given values and bounds for children expressions */
8108  SCIP_EXPR* expr, /**< expression */
8109  SCIP_Real infinity, /**< value to use for infinity */
8110  SCIP_Real* argvals, /**< values for children */
8111  SCIP_INTERVAL* argbounds, /**< bounds for children */
8112  SCIP_Bool overestimate, /**< whether to overestimate the expression */
8113  SCIP_Real* coeffs, /**< buffer to store the linear coefficients for each child expression that gives a valid under-/overestimator */
8114  SCIP_Real* constant, /**< buffer to store the constant value of the linear under-/overestimator */
8115  SCIP_Bool* success /**< buffer to store whether an estimator was successfully computed */
8116  )
8117 {
8118  SCIP_EXPRDATA_USER* exprdata;
8119 
8120  assert(expr != NULL);
8121  assert(expr->op == SCIP_EXPR_USER);
8122  assert(argvals != NULL || expr->nchildren == 0);
8123  assert(argbounds != NULL || expr->nchildren == 0);
8124 
8125  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8126 
8127  if( exprdata->estimate != NULL )
8128  {
8129  SCIP_CALL( exprdata->estimate(infinity, exprdata->userdata, expr->nchildren, argvals, argbounds, overestimate, coeffs, constant, success ) );
8130  }
8131  else
8132  {
8133  *success = FALSE;
8134  }
8135 
8136  return SCIP_OKAY;
8137 }
8138 
8139 /** substitutes variables (SCIP_EXPR_VARIDX) by expressions
8140  *
8141  * Note that only the children of the given expr are checked!
8142  * A variable with index i is replaced by a copy of substexprs[i], if the latter is not NULL.
8143  * If substexprs[i] == NULL, then the variable expression i is not touched.
8144  */
8146  BMS_BLKMEM* blkmem, /**< block memory data structure */
8147  SCIP_EXPR* expr, /**< expression, which of the children may be replaced */
8148  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8149  )
8150 {
8151  int i;
8152 
8153  assert(blkmem != NULL);
8154  assert(expr != NULL);
8155  assert(substexprs != NULL);
8156 
8157  for( i = 0; i < expr->nchildren; ++i )
8158  {
8159  if( expr->children[i]->op == SCIP_EXPR_VARIDX )
8160  {
8161  int varidx;
8162  varidx = expr->children[i]->data.intval;
8163 
8164  assert(varidx >= 0);
8165  if( substexprs[varidx] != NULL )
8166  {
8167  /* replace child i by copy of substexprs[expr->children[i]->opdata.intval] */
8168  SCIPexprFreeDeep(blkmem, &expr->children[i]);
8169  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[i], substexprs[varidx]) );
8170  }
8171  }
8172  else
8173  {
8174  /* call recursively */
8175  SCIP_CALL( SCIPexprSubstituteVars(blkmem, expr->children[i], substexprs) );
8176  }
8177  }
8178 
8179  return SCIP_OKAY;
8180 }
8181 
8182 /** updates variable indices in expression tree */
8184  SCIP_EXPR* expr, /**< expression to update */
8185  int* newindices /**< new indices of variables */
8186  )
8187 {
8188  int i;
8189 
8190  assert(expr != NULL);
8191  assert(newindices != NULL);
8192 
8193  if( expr->op == SCIP_EXPR_VARIDX )
8194  {
8195  expr->data.intval = newindices[expr->data.intval];
8196  assert(expr->data.intval >= 0);
8197  }
8198 
8199  for( i = 0; i < expr->nchildren; ++i )
8200  SCIPexprReindexVars(expr->children[i], newindices);
8201 }
8202 
8203 /** updates parameter indices in expression tree */
8205  SCIP_EXPR* expr, /**< expression to update */
8206  int* newindices /**< new indices of variables */
8207  )
8208 {
8209  int i;
8210 
8211  assert(expr != NULL);
8212  assert(newindices != NULL);
8213 
8214  if( expr->op == SCIP_EXPR_PARAM )
8215  {
8216  expr->data.intval = newindices[expr->data.intval];
8217  assert(expr->data.intval >= 0);
8218  }
8219 
8220  for( i = 0; i < expr->nchildren; ++i )
8221  SCIPexprReindexParams(expr->children[i], newindices);
8222 }
8223 
8224 /** prints an expression */
8226  SCIP_EXPR* expr, /**< expression */
8227  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8228  FILE* file, /**< file for printing, or NULL for stdout */
8229  const char** varnames, /**< names of variables, or NULL for default names */
8230  const char** paramnames, /**< names of parameters, or NULL for default names */
8231  SCIP_Real* paramvals /**< values of parameters, or NULL for not printing */
8232  )
8233 {
8234  assert( expr != NULL );
8235 
8236  switch( expr->op )
8237  {
8238  /* @Note: 'expr->data.intval' is either between 0 and number of variables-1, if it uses the varnames array, or
8239  * between 0 and number of params in the expression tree, if it uses the paramnames array
8240  * because, here, we cannot get the values above we cannot assert them
8241  */
8242  case SCIP_EXPR_VARIDX:
8243  if( varnames != NULL )
8244  {
8245  assert(varnames[expr->data.intval] != NULL);
8246  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", varnames[expr->data.intval]);
8247  }
8248  else
8249  {
8250  SCIPmessageFPrintInfo(messagehdlr, file, "var%d", expr->data.intval);
8251  }
8252  break;
8253 
8254  case SCIP_EXPR_PARAM:
8255  if( paramnames != NULL )
8256  {
8257  assert(paramnames[expr->data.intval] != NULL);
8258  SCIPmessageFPrintInfo(messagehdlr, file, "%s", paramnames[expr->data.intval]);
8259  }
8260  else
8261  {
8262  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", expr->data.intval );
8263  }
8264  if( paramvals != NULL )
8265  {
8266  SCIPmessageFPrintInfo(messagehdlr, file, "[%g]", paramvals[expr->data.intval] );
8267  }
8268  break;
8269 
8270  case SCIP_EXPR_CONST:
8271  if (expr->data.dbl < 0.0 )
8272  SCIPmessageFPrintInfo(messagehdlr, file, "(%g)", expr->data.dbl );
8273  else
8274  SCIPmessageFPrintInfo(messagehdlr, file, "%g", expr->data.dbl );
8275  break;
8276 
8277  case SCIP_EXPR_PLUS:
8278  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8279  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8280  SCIPmessageFPrintInfo(messagehdlr, file, " + ");
8281  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8282  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8283  break;
8284 
8285  case SCIP_EXPR_MINUS:
8286  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8287  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8288  SCIPmessageFPrintInfo(messagehdlr, file, " - ");
8289  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8290  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8291  break;
8292 
8293  case SCIP_EXPR_MUL:
8294  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8295  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8296  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8297  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8298  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8299  break;
8300 
8301  case SCIP_EXPR_DIV:
8302  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8303  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8304  SCIPmessageFPrintInfo(messagehdlr, file, " / ");
8305  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8306  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8307  break;
8308 
8309  case SCIP_EXPR_REALPOWER:
8310  case SCIP_EXPR_SIGNPOWER:
8311  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8312  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8313  SCIPmessageFPrintInfo(messagehdlr, file, ", %g)", expr->data.dbl);
8314  break;
8315 
8316  case SCIP_EXPR_INTPOWER:
8317  SCIPmessageFPrintInfo(messagehdlr, file, "power(");
8318  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8319  SCIPmessageFPrintInfo(messagehdlr, file, ", %d)", expr->data.intval);
8320  break;
8321 
8322  case SCIP_EXPR_SQUARE:
8323  case SCIP_EXPR_SQRT:
8324  case SCIP_EXPR_EXP:
8325  case SCIP_EXPR_LOG:
8326  case SCIP_EXPR_SIN:
8327  case SCIP_EXPR_COS:
8328  case SCIP_EXPR_TAN:
8329  /* case SCIP_EXPR_ERF: */
8330  /* case SCIP_EXPR_ERFI: */
8331  case SCIP_EXPR_MIN:
8332  case SCIP_EXPR_MAX:
8333  case SCIP_EXPR_ABS:
8334  case SCIP_EXPR_SIGN:
8335  {
8336  int i;
8337 
8338  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8339 
8340  for( i = 0; i < expr->nchildren; ++i )
8341  {
8342  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8343  if( i + 1 < expr->nchildren )
8344  {
8345  SCIPmessageFPrintInfo(messagehdlr, file, ", ");
8346  }
8347  }
8348 
8349  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8350  break;
8351  }
8352 
8353  case SCIP_EXPR_SUM:
8354  case SCIP_EXPR_PRODUCT:
8355  {
8356  switch( expr->nchildren )
8357  {
8358  case 0:
8359  SCIPmessageFPrintInfo(messagehdlr, file, expr->op == SCIP_EXPR_SUM ? "0" : "1");
8360  break;
8361  case 1:
8362  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8363  break;
8364  default:
8365  {
8366  int i;
8367  char opstr[SCIP_MAXSTRLEN];
8368 
8369  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8370  for( i = 0; i < expr->nchildren; ++i )
8371  {
8372  if( i > 0 )
8373  {
8374  (void) SCIPsnprintf(opstr, SCIP_MAXSTRLEN, "%s", expr->op == SCIP_EXPR_SUM ? " + " : " * ");
8375  SCIPmessageFPrintInfo(messagehdlr, file, opstr);
8376  }
8377  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8378  }
8379  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8380  }
8381  }
8382  break;
8383  }
8384 
8385  case SCIP_EXPR_LINEAR:
8386  {
8387  SCIP_Real constant;
8388  int i;
8389 
8390  constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
8391 
8392  if( expr->nchildren == 0 )
8393  {
8394  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
8395  break;
8396  }
8397 
8398  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8399 
8400  if( constant != 0.0 )
8401  {
8402  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
8403  }
8404 
8405  for( i = 0; i < expr->nchildren; ++i )
8406  {
8407  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", ((SCIP_Real*)expr->data.data)[i]);
8408  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8409  }
8410 
8411  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8412  break;
8413  }
8414 
8415  case SCIP_EXPR_QUADRATIC:
8416  {
8417  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
8418  int i;
8419 
8420  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
8421  assert(quadraticdata != NULL);
8422 
8423  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8424 
8425  if( quadraticdata->constant != 0.0 )
8426  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->constant);
8427 
8428  if( quadraticdata->lincoefs != NULL )
8429  for( i = 0; i < expr->nchildren; ++i )
8430  {
8431  if( quadraticdata->lincoefs[i] == 0.0 )
8432  continue;
8433  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->lincoefs[i]);
8434  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8435  }
8436 
8437  for( i = 0; i < quadraticdata->nquadelems; ++i )
8438  {
8439  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->quadelems[i].coef);
8440  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
8441  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
8442  {
8443  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
8444  }
8445  else
8446  {
8447  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8448  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
8449  }
8450  }
8451 
8452  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8453  break;
8454  }
8455 
8456  case SCIP_EXPR_POLYNOMIAL:
8457  {
8458  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
8459  SCIP_EXPRDATA_MONOMIAL* monomialdata;
8460  int i;
8461  int j;
8462 
8463  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8464 
8465  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
8466  assert(polynomialdata != NULL);
8467 
8468  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
8469  {
8470  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", polynomialdata->constant);
8471  }
8472 
8473  for( i = 0; i < polynomialdata->nmonomials; ++i )
8474  {
8475  monomialdata = polynomialdata->monomials[i];
8476  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g", monomialdata->coef);
8477 
8478  for( j = 0; j < monomialdata->nfactors; ++j )
8479  {
8480  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8481 
8482  SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
8483  if( monomialdata->exponents[j] < 0.0 )
8484  {
8485  SCIPmessageFPrintInfo(messagehdlr, file, "^(%.20g)", monomialdata->exponents[j]);
8486  }
8487  else if( monomialdata->exponents[j] != 1.0 )
8488  {
8489  SCIPmessageFPrintInfo(messagehdlr, file, "^%.20g", monomialdata->exponents[j]);
8490  }
8491  }
8492  }
8493 
8494  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8495  break;
8496  }
8497 
8498  case SCIP_EXPR_USER:
8499  {
8500  SCIP_EXPRDATA_USER* exprdata;
8501  int i;
8502 
8503  exprdata = (SCIP_EXPRDATA_USER*)expr->data.data;
8504  assert(exprdata != NULL);
8505 
8506  if( exprdata->print != NULL )
8507  {
8508  exprdata->print(exprdata->userdata, messagehdlr, file);
8509  }
8510  else
8511  {
8512  SCIPmessageFPrintInfo(messagehdlr, file, "user");
8513  }
8514 
8515  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8516  for( i = 0; i < expr->nchildren; ++i )
8517  {
8518  if( i > 0 )
8519  {
8520  SCIPmessageFPrintInfo(messagehdlr, file, ",");
8521  }
8522  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8523  }
8524  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8525 
8526  break;
8527  }
8528 
8529  case SCIP_EXPR_LAST:
8530  {
8531  SCIPerrorMessage("invalid expression\n");
8532  SCIPABORT();
8533  }
8534  }
8535 }
8536 
8537 /** parses an expression from a string */
8539  BMS_BLKMEM* blkmem, /**< block memory data structure */
8540  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8541  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
8542  const char* str, /**< pointer to the string to be parsed */
8543  const char* lastchar, /**< pointer to the last char of str that should be parsed */
8544  int* nvars, /**< buffer to store number of variables */
8545  int* varnames, /**< buffer to store variable names, prefixed by index (as int) */
8546  int varnameslength /**< length of the varnames buffer array */
8547  )
8548 {
8549  SCIP_HASHTABLE* vartable;
8550  SCIP_RETCODE retcode;
8551 
8552  assert(blkmem != NULL);
8553  assert(expr != NULL);
8554  assert(str != NULL);
8555  assert(lastchar != NULL);
8556  assert(nvars != NULL);
8557  assert(varnames != NULL);
8558 
8559  *nvars = 0;
8560 
8561  /* create a hash table for variable names and corresponding expression index
8562  * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
8563  */
8564  SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString,
8565  SCIPhashKeyValString, NULL) );
8566 
8567  retcode = exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames,
8568  &varnameslength, vartable, 0);
8569 
8570  SCIPhashtableFree(&vartable);
8571 
8572  return retcode;
8573 }
8574 
8575 
8576 /**@} */
8577 
8578 /**@name Expression tree methods */
8579 /**@{ */
8580 
8581 /* In debug mode, the following methods are implemented as function calls to ensure
8582  * type validity.
8583  * In optimized mode, the methods are implemented as defines to improve performance.
8584  * However, we want to have them in the library anyways, so we have to undef the defines.
8585  */
8586 
8587 #undef SCIPexprtreeGetRoot
8588 #undef SCIPexprtreeGetNVars
8589 #undef SCIPexprtreeGetNParams
8590 #undef SCIPexprtreeGetParamVals
8591 #undef SCIPexprtreeSetParamVal
8592 #undef SCIPexprtreeGetInterpreterData
8593 #undef SCIPexprtreeSetInterpreterData
8594 #undef SCIPexprtreeFreeInterpreterData
8595 #undef SCIPexprtreeHasParam
8596 #undef SCIPexprtreeGetMaxDegree
8597 #undef SCIPexprtreeEval
8598 #undef SCIPexprtreeEvalInt
8599 #undef SCIPexprtreePrint
8600 
8601 /** returns root expression of an expression tree */
8603  SCIP_EXPRTREE* tree /**< expression tree */
8604  )
8605 {
8606  assert(tree != NULL);
8607 
8608  return tree->root;
8609 }
8610 
8611 /** returns number of variables in expression tree */
8613  SCIP_EXPRTREE* tree /**< expression tree */
8614  )
8615 {
8616  assert(tree != NULL);
8617 
8618  return tree->nvars;
8619 }
8620 
8621 /** returns number of parameters in expression tree */
8623  SCIP_EXPRTREE* tree /**< expression tree */
8624  )
8625 {
8626  assert(tree != NULL);
8627 
8628  return tree->nparams;
8629 }
8630 
8631 /** returns values of parameters or NULL if none */
8633  SCIP_EXPRTREE* tree /**< expression tree */
8634  )
8635 {
8636  assert(tree != NULL);
8637 
8638  return tree->params;
8639 }
8640 
8641 /** sets value of a single parameter in expression tree */
8643  SCIP_EXPRTREE* tree, /**< expression tree */
8644  int paramidx, /**< index of parameter */
8645  SCIP_Real paramval /**< new value of parameter */
8646  )
8647 {
8648  assert(tree != NULL);
8649  assert(paramidx >= 0);
8650  assert(paramidx < tree->nparams);
8651  assert(tree->params != NULL);
8652 
8653  tree->params[paramidx] = paramval;
8654 }
8655 
8656 /** gets data of expression tree interpreter, or NULL if not set */
8658  SCIP_EXPRTREE* tree /**< expression tree */
8659  )
8660 {
8661  assert(tree != NULL);
8662 
8663  return tree->interpreterdata;
8664 }
8665 
8666 /** sets data of expression tree interpreter */
8668  SCIP_EXPRTREE* tree, /**< expression tree */
8669  SCIP_EXPRINTDATA* interpreterdata /**< expression interpreter data */
8670  )
8671 {
8672  assert(tree != NULL);
8673  assert(interpreterdata != NULL);
8674  assert(tree->interpreterdata == NULL);
8675 
8676  tree->interpreterdata = interpreterdata;
8677 }
8678 
8679 /** frees data of expression tree interpreter, if any */
8681  SCIP_EXPRTREE* tree /**< expression tree */
8682  )
8683 {
8684  if( tree->interpreterdata != NULL )
8685  {
8687  assert(tree->interpreterdata == NULL);
8688  }
8689 
8690  return SCIP_OKAY;
8691 }
8692 
8693 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
8695  SCIP_EXPRTREE* tree /**< expression tree */
8696  )
8697 {
8698  assert(tree != NULL);
8699 
8700  return SCIPexprHasParam(tree->root);
8701 }
8702 
8703 /** Gives maximal degree of expression in expression tree.
8704  *
8705  * If constant expression, gives 0,
8706  * if linear expression, gives 1,
8707  * if polynomial expression, gives its maximal degree,
8708  * otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8709  */
8711  SCIP_EXPRTREE* tree, /**< expression tree */
8712  int* maxdegree /**< buffer to store maximal degree */
8713  )
8714 {
8715  assert(tree != NULL);
8716 
8717  SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8718 
8719  return SCIP_OKAY;
8720 }
8721 
8722 /** evaluates an expression tree w.r.t. a point */
8724  SCIP_EXPRTREE* tree, /**< expression tree */
8725  SCIP_Real* varvals, /**< values for variables */
8726  SCIP_Real* val /**< buffer to store expression tree value */
8727  )
8728 {
8729  assert(tree != NULL);
8730  assert(varvals != NULL || tree->nvars == 0);
8731  assert(val != NULL);
8732 
8733  SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8734 
8735  return SCIP_OKAY;
8736 }
8737 
8738 /** evaluates an expression tree w.r.t. an interval */
8740  SCIP_EXPRTREE* tree, /**< expression tree */
8741  SCIP_Real infinity, /**< value for infinity */
8742  SCIP_INTERVAL* varvals, /**< intervals for variables */
8743  SCIP_INTERVAL* val /**< buffer to store expression tree value */
8744  )
8745 {
8746  assert(tree != NULL);
8747  assert(varvals != NULL || tree->nvars == 0);
8748  assert(val != NULL);
8749 
8750  SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8751 
8752  return SCIP_OKAY;
8753 }
8754 
8755 /** prints an expression tree */
8757  SCIP_EXPRTREE* tree, /**< expression tree */
8758  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8759  FILE* file, /**< file for printing, or NULL for stdout */
8760  const char** varnames, /**< names of variables, or NULL for default names */
8761  const char** paramnames /**< names of parameters, or NULL for default names */
8762  )
8763 {
8764  assert(tree != NULL);
8765 
8766  SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8767 }
8768 
8769 
8770 /** creates an expression tree */
8772  BMS_BLKMEM* blkmem, /**< block memory data structure */
8773  SCIP_EXPRTREE** tree, /**< buffer to store address of created expression tree */
8774  SCIP_EXPR* root, /**< pointer to root expression, not copied deep !, can be NULL */
8775  int nvars, /**< number of variables in variable mapping */
8776  int nparams, /**< number of parameters in expression */
8777  SCIP_Real* params /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8778  )
8779 {
8780  assert(blkmem != NULL);
8781  assert(tree != NULL);
8782 
8783  SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8784 
8785  (*tree)->blkmem = blkmem;
8786  (*tree)->root = root;
8787  (*tree)->nvars = nvars;
8788  (*tree)->vars = NULL;
8789  (*tree)->nparams = nparams;
8790  (*tree)->interpreterdata = NULL;
8791 
8792  if( params != NULL )
8793  {
8794  assert(nparams > 0);
8795  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8796  }
8797  else if( nparams > 0 )
8798  {
8799  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8800  BMSclearMemoryArray((*tree)->params, nparams);
8801  }
8802  else
8803  {
8804  assert(nparams == 0);
8805  (*tree)->params = NULL;
8806  }
8807 
8808  return SCIP_OKAY;
8809 }
8810 
8811 /** copies an expression tree */
8813  BMS_BLKMEM* blkmem, /**< block memory that should be used in new expression tree */
8814  SCIP_EXPRTREE** targettree, /**< buffer to store address of copied expression tree */
8815  SCIP_EXPRTREE* sourcetree /**< expression tree to copy */
8816  )
8817 {
8818  assert(blkmem != NULL);
8819  assert(targettree != NULL);
8820  assert(sourcetree != NULL);
8821 
8822  /* copy expression tree "header" */
8823  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8824 
8825  /* we may have a new block memory; and we do not want to keep the others interpreter data */
8826  (*targettree)->blkmem = blkmem;
8827  (*targettree)->interpreterdata = NULL;
8828 
8829  /* copy variables, if any */
8830  if( sourcetree->vars != NULL )
8831  {
8832  assert(sourcetree->nvars > 0);
8833 
8834  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8835  }
8836 
8837  /* copy parameters, if any */
8838  if( sourcetree->params != NULL )
8839  {
8840  assert(sourcetree->nparams > 0);
8841 
8842  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8843  }
8844 
8845  /* copy expression */
8846  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8847 
8848  return SCIP_OKAY;
8849 }
8850 
8851 /** frees an expression tree */
8853  SCIP_EXPRTREE** tree /**< pointer to expression tree that is freed */
8854  )
8855 {
8856  assert( tree != NULL);
8857  assert(*tree != NULL);
8858 
8860 
8861  if( (*tree)->root != NULL )
8862  {
8863  SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8864  assert((*tree)->root == NULL);
8865  }
8866 
8867  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars, (*tree)->nvars );
8868  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8869 
8870  BMSfreeBlockMemory((*tree)->blkmem, tree);
8871 
8872  return SCIP_OKAY;
8873 }
8874 
8875 /** sets number and values of all parameters in expression tree */
8877  SCIP_EXPRTREE* tree, /**< expression tree */
8878  int nparams, /**< number of parameters */
8879  SCIP_Real* paramvals /**< values of parameters, can be NULL if nparams == 0 */
8880  )
8881 {
8882  assert(tree != NULL);
8883  assert(paramvals != NULL || nparams == 0);
8884 
8885  if( nparams == 0 )
8886  {
8887  BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8888  }
8889  else if( tree->params != NULL )
8890  {
8891  SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8892  BMScopyMemoryArray(tree->params, paramvals, nparams);
8893  }
8894  else
8895  {
8896  SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8897  }
8898 
8899  tree->nparams = nparams;
8900  assert(tree->params != NULL || tree->nparams == 0);
8901 
8902  return SCIP_OKAY;
8903 }
8904 
8905 
8906 /** gives the number of usages for each variable in the expression tree */
8908  SCIP_EXPRTREE* tree, /**< expression tree */
8909  int* varsusage /**< array where to store for each variable how often it is used in the tree */
8910  )
8911 {
8912  assert(tree != NULL);
8913  assert(varsusage != NULL);
8914 
8915  if( tree->nvars == 0 )
8916  return;
8917 
8918  BMSclearMemoryArray(varsusage, tree->nvars);
8919  SCIPexprGetVarsUsage(tree->root, varsusage);
8920 }
8921 
8922 /** aims at simplifying an expression and splitting of a linear expression
8923  *
8924  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
8925  */
8927  SCIP_EXPRTREE* tree, /**< expression tree */
8928  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8929  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
8930  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8931  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8932  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8933  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
8934  )
8935 {
8936 #ifndef NDEBUG
8937  SCIP_RANDNUMGEN* randnumgen;
8938  SCIP_Real* testx;
8939  SCIP_Real testval_before;
8940  SCIP_Real testval_after;
8941  int i;
8942 #endif
8943 
8944  assert(tree != NULL);
8945 
8946 #ifndef NDEBUG
8947  SCIP_CALL( SCIPrandomCreate(&randnumgen, tree->blkmem, 42) );
8948 
8949  SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) ); /*lint !e666*/
8950  for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8951  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
8952  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8953 
8954  SCIPrandomFree(&randnumgen, tree->blkmem);
8955 #endif
8956 
8957  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8958  SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8959 
8960 #ifndef NDEBUG
8961  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8962  if( nlinvars != NULL && testval_before == testval_before ) /*lint !e777*/
8963  for( i = 0; i < *nlinvars; ++i )
8964  testval_after += lincoefs[i] * testx[linidxs[i]];
8965  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
8966  BMSfreeMemoryArray(&testx);
8967 #endif
8968 
8969  /* removing something from the the tree may invalidate the interpreter data */
8970  if( nlinvars != NULL && *nlinvars > 0 )
8972 
8973  return SCIP_OKAY;
8974 }
8975 
8976 /** adds an expression to the root expression of the tree
8977  *
8978  * 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.
8979  * If no root existed yet, then the root is set to the given expression (or a copy of it).
8980  */
8982  SCIP_EXPRTREE* tree, /**< expression tree */
8983  SCIP_EXPR* expr, /**< expression to add to tree */
8984  SCIP_Bool copyexpr /**< whether expression should be copied */
8985  )
8986 {
8987  assert(tree != NULL);
8988 
8989  /* adding something to the tree may invalidate the interpreter data */
8991 
8992  if( copyexpr )
8993  {
8994  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &expr, expr) );
8995  }
8996 
8997  if( tree->root == NULL )
8998  {
8999  tree->root = expr;
9000  }
9001  else
9002  {
9003  SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
9004  }
9005 
9006  return SCIP_OKAY;
9007 }
9008 
9009 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
9011  SCIP_EXPRTREE* tree, /**< expression tree */
9012  SCIP_Real infinity, /**< value for infinity */
9013  SCIP_INTERVAL* varbounds, /**< domains of variables */
9014  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
9015  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression, or NULL if not needed */
9016  )
9017 {
9018  SCIP_INTERVAL exprbounds;
9019 
9020  assert(tree != NULL);
9021 
9022  if( tree->root == NULL )
9023  {
9024  *curv = SCIP_EXPRCURV_LINEAR;
9025 
9026  if( bounds != NULL )
9027  SCIPintervalSet(bounds, 0.0);
9028 
9029  return SCIP_OKAY;
9030  }
9031 
9032  SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
9033 
9034  if( bounds != NULL )
9035  *bounds = exprbounds;
9036 
9037  return SCIP_OKAY;
9038 }
9039 
9040 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
9041  *
9042  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL.
9043  * If substexprs[i] == NULL, then the variable expression i is not touched.
9044  */
9046  SCIP_EXPRTREE* tree, /**< expression tree */
9047  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
9048  )
9049 {
9050  assert(tree != NULL);
9051 
9052  if( tree->root == NULL )
9053  return SCIP_OKAY;
9054 
9055  if( tree->root->op == SCIP_EXPR_VARIDX )
9056  {
9057  int varidx;
9058 
9059  varidx = tree->root->data.intval;
9060  assert(varidx >= 0);
9061  if( substexprs[varidx] != NULL )
9062  {
9063  /* substitute root expression */
9064  SCIPexprFreeDeep(tree->blkmem, &tree->root);
9065  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
9066  }
9067  }
9068  else
9069  {
9070  /* check children (and grandchildren and so on...) of root expression */
9071  SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
9072  }
9073 
9074  /* substitution of variables should invalidate interpreter data */
9076 
9077  return SCIP_OKAY;
9078 }
9079 
9080 /**@} */
9081 
9082 /**@name Quadratic element methods */
9083 /**@{ */
9084 
9085 /** comparing two quadratic elements
9086  *
9087  * 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
9088  */
9089 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
9090 
9091 /** swaps two quadratic elements */
9092 #define QUADELEMS_SWAP(x,y) \
9093  { \
9094  SCIP_QUADELEM temp = x; \
9095  x = y; \
9096  y = temp; \
9097  }
9098 
9099 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
9100 static
9102  SCIP_QUADELEM* elems, /**< array to be sorted */
9103  int start, /**< starting index */
9104  int end /**< ending index */
9105  )
9106 {
9107  assert(start <= end);
9108 
9109  /* use quick sort for long lists */
9110  while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
9111  {
9112  SCIP_QUADELEM pivotkey;
9113  int lo;
9114  int hi;
9115  int mid;
9116 
9117  /* select pivot element */
9118  mid = (start+end)/2;
9119  pivotkey = elems[mid];
9120 
9121  /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
9122  lo = start;
9123  hi = end;
9124  for( ;; )
9125  {
9126  while( lo < end && QUADELEMS_ISBETTER(elems[lo], pivotkey) )
9127  lo++;
9128  while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
9129  hi--;
9130 
9131  if( lo >= hi )
9132  break;
9133 
9134  QUADELEMS_SWAP(elems[lo], elems[hi]);
9135 
9136  lo++;
9137  hi--;
9138  }
9139  assert(hi == lo-1 || hi == start);
9140 
9141  /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
9142  while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
9143  lo++;
9144 
9145  /* make sure that we have at least one element in the smaller partition */
9146  if( lo == start )
9147  {
9148  /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
9149  assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
9150  assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
9151  QUADELEMS_SWAP(elems[lo], elems[mid]);
9152  lo++;
9153  }
9154 
9155  /* sort the smaller partition by a recursive call, sort the larger part without recursion */
9156  if( hi - start <= end - lo )
9157  {
9158  /* sort [start,hi] with a recursive call */
9159  if( start < hi )
9160  quadelemsQuickSort(elems, start, hi);
9161 
9162  /* now focus on the larger part [lo,end] */
9163  start = lo;
9164  }
9165  else
9166  {
9167  /* sort [lo,end] with a recursive call */
9168  if( lo < end )
9169  quadelemsQuickSort(elems, lo, end);
9170 
9171  /* now focus on the larger part [start,hi] */
9172  end = hi;
9173  }
9174  }
9175 
9176  /* use shell sort on the remaining small list */
9177  if( end - start >= 1 )
9178  {
9179  static const int incs[3] = {1, 5, 19}; /* sequence of increments */
9180  int k;
9181 
9182  for( k = 2; k >= 0; --k )
9183  {
9184  int h;
9185  int i;
9186 
9187  for( h = incs[k], i = h + start; i <= end; ++i )
9188  {
9189  int j;
9190  SCIP_QUADELEM tempkey = elems[i];
9191 
9192  j = i;
9193  while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
9194  {
9195  elems[j] = elems[j-h];
9196  j -= h;
9197  }
9198 
9199  elems[j] = tempkey;
9200  }
9201  }
9202  }
9203 }
9204 
9205 /** sorts an array of quadratic elements
9206  *
9207  * The elements are sorted such that the first index is increasing and
9208  * such that among elements with the same first index, the second index is increasing.
9209  * For elements with same first and second index, the order is not defined.
9210  */
9212  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9213  int nquadelems /**< number of quadratic elements */
9214  )
9215 {
9216  if( nquadelems == 0 )
9217  return;
9218 
9219 #ifndef NDEBUG
9220  {
9221  int i;
9222  for( i = 0; i < nquadelems; ++i )
9223  assert(quadelems[i].idx1 <= quadelems[i].idx2);
9224  }
9225 #endif
9226 
9227  quadelemsQuickSort(quadelems, 0, nquadelems-1);
9228 }
9229 
9230 /** Finds an index pair in a sorted array of quadratic elements.
9231  *
9232  * If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
9233  * 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.
9234  * Assumes that idx1 <= idx2.
9235  */
9237  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9238  int idx1, /**< index of first variable in element to search for */
9239  int idx2, /**< index of second variable in element to search for */
9240  int nquadelems, /**< number of quadratic elements in array */
9241  int* pos /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
9242  )
9243 {
9244  int left;
9245  int right;
9246 
9247  assert(quadelems != NULL || nquadelems == 0);
9248  assert(idx1 <= idx2);
9249 
9250  if( nquadelems == 0 )
9251  {
9252  if( pos != NULL )
9253  *pos = 0;
9254  return FALSE;
9255  }
9256 
9257  left = 0;
9258  right = nquadelems - 1;
9259  while( left <= right )
9260  {
9261  int middle;
9262 
9263  middle = (left+right)/2;
9264  assert(0 <= middle && middle < nquadelems);
9265 
9266  if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) ) /*lint !e613*/
9267  right = middle - 1;
9268  else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) ) /*lint !e613*/
9269  left = middle + 1;
9270  else
9271  {
9272  if( pos != NULL )
9273  *pos = middle;
9274  return TRUE;
9275  }
9276  }
9277  assert(left == right+1);
9278 
9279  if( pos != NULL )
9280  *pos = left;
9281  return FALSE;
9282 }
9283 
9284 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
9285  *
9286  * Assumes that elements have been sorted before.
9287  */
9289  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9290  int nquadelems, /**< number of quadratic elements */
9291  int* nquadelemsnew /**< pointer to store new (reduced) number of quadratic elements */
9292  )
9293 {
9294  int i;
9295  int next;
9296 
9297  assert(quadelems != NULL);
9298  assert(nquadelemsnew != NULL);
9299  assert(nquadelems >= 0);
9300 
9301  i = 0;
9302  next = 0;
9303  while( next < nquadelems )
9304  {
9305  /* assert that array is sorted */
9306  assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
9307  (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
9308 
9309  /* skip elements with coefficient 0.0 */
9310  if( quadelems[next].coef == 0.0 )
9311  {
9312  ++next;
9313  continue;
9314  }
9315 
9316  /* if next element has same index as previous one, add it to the previous one */
9317  if( i >= 1 &&
9318  quadelems[i-1].idx1 == quadelems[next].idx1 &&
9319  quadelems[i-1].idx2 == quadelems[next].idx2 )
9320  {
9321  quadelems[i-1].coef += quadelems[next].coef;
9322  ++next;
9323  continue;
9324  }
9325 
9326  /* otherwise, move next element to current position */
9327  quadelems[i] = quadelems[next];
9328  ++i;
9329  ++next;
9330  }
9331  assert(next == nquadelems);
9332 
9333  /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
9334  *nquadelemsnew = i;
9335 }
9336 
9337 /**@} */
9338 
9339 /**@name Expression graph node private methods */
9340 /**@{ */
9341 
9342 /** adds a parent to an expression graph node */
9343 static
9345  BMS_BLKMEM* blkmem, /**< block memory */
9346  SCIP_EXPRGRAPHNODE* node, /**< expression graph node where to add a parent */
9347  SCIP_EXPRGRAPHNODE* parent /**< parent node */
9348  )
9349 {
9350  assert(blkmem != NULL);
9351  assert(node != NULL);
9352  assert(node->depth >= 0);
9353  assert(node->pos >= 0);
9354  assert(parent != NULL);
9355  assert(parent->depth >= 0);
9356  assert(parent->pos >= 0);
9357  assert(parent->depth > node->depth); /* a parent node need to have larger depth */
9358 
9359  ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
9360  assert(node->nparents < node->parentssize);
9361 
9362  node->parents[node->nparents] = parent;
9363  ++node->nparents;
9364 
9365  /* update sorted flag */
9366  node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (exprgraphnodecomp((void*)node->parents[node->nparents-2], (void*)parent) <= 0));
9367 
9368  return SCIP_OKAY;
9369 }
9370 
9371 /** ensures that array of parents in a node is sorted */
9372 static
9374  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
9375  )
9376 {
9377  assert(node != NULL);
9378 
9379  if( node->parentssorted )
9380  {
9381 #ifndef NDEBUG
9382  int i;
9383  for( i = 1; i < node->nparents; ++i )
9384  assert(exprgraphnodecomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
9385 #endif
9386  return;
9387  }
9388 
9389  SCIPsortPtr((void**)node->parents, exprgraphnodecomp, node->nparents);
9390 
9391  node->parentssorted = TRUE;
9392 }
9393 
9394 /** removes a parent from an expression graph node
9395  *
9396  * If the node is not used and has no other parents, then it is freed.
9397  */
9398 static
9400  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9401  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to remove a parent, *node will be set to NULL */
9402  SCIP_EXPRGRAPHNODE* parent /**< parent node to remove */
9403  )
9404 {
9405  SCIP_EXPRGRAPHNODE* node_;
9406  int pos;
9407 
9408  assert(exprgraph != NULL);
9409  assert(node != NULL);
9410  assert(*node != NULL);
9411  assert((*node)->depth >= 0);
9412  assert((*node)->pos >= 0);
9413  assert((*node)->nparents > 0);
9414  assert(parent != NULL);
9415  assert(parent->depth >= 0);
9416  assert(parent->pos >= 0);
9417  assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
9418 
9419  /* find parent */
9420  exprgraphNodeSortParents(*node);
9421  (void) SCIPsortedvecFindPtr((void**)(*node)->parents, exprgraphnodecomp, (void*)parent, (*node)->nparents, &pos);
9422  assert(pos >= 0);
9423  assert(pos < (*node)->nparents);
9424  assert((*node)->parents[pos] == parent);
9425 
9426  /* move last parent to pos, if pos is before last
9427  * update sorted flag */
9428  if( pos < (*node)->nparents-1 )
9429  {
9430  (*node)->parents[pos] = (*node)->parents[(*node)->nparents-1];
9431  (*node)->parentssorted = ((*node)->nparents <= 2);
9432  }
9433  --(*node)->nparents;
9434 
9435  /* keep pointer to *node in case it is still used */
9436  node_ = (*node)->nuses > 0 ? *node : NULL;
9437 
9438  /* capture and release node so it is freed if possible */
9439  SCIPexprgraphCaptureNode(*node);
9440  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
9441 
9442  /* restore pointer, if node still exists */
9443  *node = node_;
9444 
9445  return SCIP_OKAY;
9446 }
9447 
9448 /** checks if a node is parent of a node */
9449 static
9451  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9452  SCIP_EXPRGRAPHNODE* parent /**< parent to look for */
9453  )
9454 {
9455  int pos;
9456 
9457  assert(node != NULL);
9458  assert(parent != NULL);
9459 
9460  /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
9461  if( node->depth >= parent->depth || node->nparents == 0 )
9462  return FALSE;
9463  assert(node->parents != NULL);
9464 
9465  /* ensure parents array is sorted */
9467 
9468  return SCIPsortedvecFindPtr((void**)node->parents, exprgraphnodecomp, (void*)parent, node->nparents, &pos);
9469 }
9470 
9471 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
9472  *
9473  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
9474  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
9475  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
9476  *
9477  * It is assumed that node and all exprs are in the expression graph already.
9478  * It is assumed that all expressions that are added have lower depth than node.
9479  */
9480 static
9482  BMS_BLKMEM* blkmem, /**< block memory */
9483  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9484  int nexprs, /**< number of children to add */
9485  SCIP_EXPRGRAPHNODE** exprs, /**< children nodes to add */
9486  int* childmap /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
9487  )
9488 {
9489  int i;
9490  int j;
9491  int orignchildren;
9492  SCIP_Bool existsalready;
9493 
9494  assert(blkmem != NULL);
9495  assert(node != NULL);
9496  assert(node->depth > 0);
9497  assert(node->pos >= 0);
9498  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);
9499  assert(exprs != NULL || nexprs == 0);
9500 
9501  if( nexprs == 0 )
9502  return SCIP_OKAY;
9503 
9504  orignchildren = node->nchildren;
9505  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
9506 
9507  for( i = 0; i < nexprs; ++i )
9508  {
9509  assert(exprs[i]->depth >= 0); /*lint !e613*/
9510  assert(exprs[i]->pos >= 0); /*lint !e613*/
9511  assert(exprs[i]->depth < node->depth); /*lint !e613*/
9512 
9513  /* check if exprs[i] is a child already, if not SUM or PRODUCT */
9514  existsalready = FALSE;
9515  if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
9516  for( j = 0; j < orignchildren; ++j )
9517  /* during simplification of polynomials, their may be NULL's in children array */
9518  if( node->children[j] != NULL && node->children[j] == exprs[i] ) /*lint !e613*/
9519  {
9520  existsalready = TRUE;
9521  break;
9522  }
9523 
9524  if( !existsalready )
9525  {
9526  /* add exprs[i] to children array */
9527  node->children[node->nchildren] = exprs[i]; /*lint !e613*/
9528  SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) ); /*lint !e613*/
9529  if( childmap != NULL )
9530  childmap[i] = node->nchildren;
9531  ++node->nchildren;
9532  }
9533  else
9534  {
9535  if( childmap != NULL )
9536  childmap[i] = j; /*lint !e644*/
9537  if( node->op == SCIP_EXPR_LINEAR )
9538  {
9539  /* if linear expression, increase coefficient by 1.0 */
9540  ((SCIP_Real*)node->data.data)[j] += 1.0;
9541  }
9542  }
9543  }
9544 
9545  /* shrink children array to actually used size */
9546  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
9547 
9548  if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
9549  {
9550  /* if linear expression, then add 1.0 coefficients for new expressions */
9551  SCIP_Real* data;
9552 
9553  data = (SCIP_Real*)node->data.data;
9554  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
9555  data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
9556  for( i = orignchildren; i < node->nchildren; ++i )
9557  data[i] = 1.0;
9558  node->data.data = (void*)data;
9559  }
9560  else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
9561  {
9562  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
9564 
9565  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9566  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
9567  BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren); /*lint !e866*/
9568  }
9569 
9570  node->simplified = FALSE;
9571 
9572  return SCIP_OKAY;
9573 }
9574 
9575 /** replaces a child node by another node
9576  *
9577  * Assumes that both nodes represent the same expression.
9578  * If this node was the last parent of oldchild and oldchild is not in use, then it is freed.
9579  * newchild must have deeper depth than node.
9580  */
9581 static
9583  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9584  SCIP_EXPRGRAPHNODE* node, /**< pointer to expression graph node */
9585  SCIP_EXPRGRAPHNODE** oldchild, /**< child node that should be replaced, it may be freed */
9586  SCIP_EXPRGRAPHNODE* newchild /**< node that should take position of oldchild */
9587  )
9588 {
9589  int i;
9590 
9591  assert(exprgraph != NULL);
9592  assert(node != NULL);
9593  assert(oldchild != NULL);
9594  assert(*oldchild != NULL);
9595  assert(newchild != NULL);
9596 
9597  if( *oldchild == newchild )
9598  return SCIP_OKAY;
9599 
9600  SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
9601 
9602  /* search for oldchild in children array */
9603  for( i = 0; i < node->nchildren; ++i )
9604  {
9605  if( node->children[i] == *oldchild )
9606  {
9607  /* add as parent to newchild */
9608  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
9609 
9610  /* remove as parent from oldchild */
9611  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
9612 
9613  /* set newchild as child i */
9614  node->children[i] = newchild;
9615 
9616  /* we're done */
9617  break;
9618  }
9619  }
9620  assert(i < node->nchildren); /* assert that oldchild has been found in children array */
9621 
9622  node->simplified = FALSE;
9623 
9624  return SCIP_OKAY;
9625 }
9626 
9627 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
9628  *
9629  * A node is larger than another node, if their corresponding constants are related that way.
9630  */
9631 static
9632 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
9633 {
9634  assert(elem1 != NULL);
9635  assert(elem2 != NULL);
9636  assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
9637  assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
9638  assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9639  assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9640 
9641  if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9642  return 1;
9643  else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9644  return -1;
9645  else
9646  return 0;
9647 }
9648 
9649 /** sort array of nodes that holds constants */
9650 static
9652  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
9653  )
9654 {
9655  assert(exprgraph != NULL);
9656 
9657  if( exprgraph->constssorted )
9658  return;
9659 
9660  SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
9661 
9662  exprgraph->constssorted = TRUE;
9663 }
9664 
9665 /** finds position of expression graph node corresponding to a constant in constnodes array */
9666 static
9668  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9669  SCIP_EXPRGRAPHNODE* node, /**< node to search for */
9670  int* pos /**< buffer to store position of node, if found */
9671  )
9672 {
9673  int left;
9674  int right;
9675  int middle;
9676 
9677  assert(exprgraph != NULL);
9678  assert(node != NULL);
9679  assert(node->op == SCIP_EXPR_CONST);
9680  assert(node->depth == 0);
9681  assert(node->pos >= 0);
9682  assert(pos != NULL);
9683 
9684  exprgraphSortConstNodes(exprgraph);
9685  assert(exprgraph->constssorted);
9686 
9687  /* find a node with constant node->data.dbl using binary search */
9688  left = 0;
9689  right = exprgraph->nconsts-1;
9690  *pos = -1;
9691  while( left <= right )
9692  {
9693  middle = (left+right)/2;
9694  assert(0 <= middle && middle < exprgraph->nconsts);
9695 
9696  if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9697  right = middle - 1;
9698  else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9699  left = middle + 1;
9700  else
9701  {
9702  *pos = middle;
9703  break;
9704  }
9705  }
9706  assert(left == right+1 || *pos >= 0);
9707  if( left == right+1 )
9708  return FALSE;
9709 
9710  /* search left of *pos to find node */
9711  while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl ) /*lint !e777*/
9712  --*pos;
9713  /* search right of *pos to find node */
9714  while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl ) /*lint !e777*/
9715  ++*pos;
9716 
9717  return exprgraph->constnodes[*pos] == node;
9718 }
9719 
9720 /** creates an expression graph node */
9721 static
9723  BMS_BLKMEM* blkmem, /**< block memory */
9724  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
9725  SCIP_EXPROP op, /**< operator type of expression */
9726  SCIP_EXPROPDATA opdata /**< operator data of expression */
9727  )
9728 {
9729  assert(blkmem != NULL);
9730  assert(node != NULL);
9731 
9732  SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9733  BMSclearMemory(*node);
9734 
9735  (*node)->op = op;
9736  (*node)->data = opdata;
9737 
9738  /* mark graph position as not in graph yet */
9739  (*node)->depth = -1;
9740  (*node)->pos = -1;
9741 
9742  /* arrays of length 0 are trivially sorted */
9743  (*node)->parentssorted = TRUE;
9744 
9745  /* set bounds interval to entire */
9746  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9747  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9748 
9749  /* set initial value to invalid */
9750  (*node)->value = SCIP_INVALID;
9751 
9752  /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9753  if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9754  (*node)->curv = SCIP_EXPRCURV_LINEAR;
9755  else
9756  (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9757 
9758  /* per default, a node is enabled */
9759  (*node)->enabled = TRUE;
9760 
9761  return SCIP_OKAY;
9762 }
9763 
9764 /** prints the expression corresponding to a node (not recursively) */
9765 static
9767  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9768  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9769  FILE* file, /**< file to print to, or NULL for stdout */
9770  const char** varnames, /**< variable names, or NULL for generic names */
9771  SCIP_Bool printchildrenbounds /**< whether to print bounds of children */
9772  )
9773 {
9774  int i;
9775 
9776  assert(node != NULL);
9777 
9778  switch( node->op )
9779  {
9780  case SCIP_EXPR_VARIDX:
9781  if( varnames != NULL )
9782  {
9783  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9784  }
9785  else
9786  SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9787  break;
9788 
9789  case SCIP_EXPR_CONST:
9790  SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9791  break;
9792 
9793  case SCIP_EXPR_PARAM:
9794  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9795  break;
9796 
9797  case SCIP_EXPR_PLUS:
9798  if( printchildrenbounds )
9799  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9800  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9801  if( printchildrenbounds )
9802  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9803  break;
9804 
9805  case SCIP_EXPR_MINUS:
9806  if( printchildrenbounds )
9807  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9808  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9809  if( printchildrenbounds )
9810  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9811  break;
9812 
9813  case SCIP_EXPR_MUL:
9814  if( printchildrenbounds )
9815  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9816  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9817  if( printchildrenbounds )
9818  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9819  break;
9820 
9821  case SCIP_EXPR_DIV:
9822  if( printchildrenbounds )
9823  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9824  SCIPmessageFPrintInfo(messagehdlr, file, "/");
9825  if( printchildrenbounds )
9826  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9827  break;
9828 
9829  case SCIP_EXPR_SQUARE:
9830  if( printchildrenbounds )
9831  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9832  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9833  break;
9834 
9835  case SCIP_EXPR_REALPOWER:
9836  if( printchildrenbounds )
9837  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9838  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9839  break;
9840 
9841  case SCIP_EXPR_SIGNPOWER:
9842  if( printchildrenbounds )
9843  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9844  node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9845  else
9846  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9847  break;
9848 
9849  case SCIP_EXPR_INTPOWER:
9850  SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9851  if( printchildrenbounds )
9852  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9853  SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9854  break;
9855 
9856  case SCIP_EXPR_SQRT:
9857  case SCIP_EXPR_EXP:
9858  case SCIP_EXPR_LOG:
9859  case SCIP_EXPR_SIN:
9860  case SCIP_EXPR_COS:
9861  case SCIP_EXPR_TAN:
9862  /* SCIP_EXPR_ERF = 20, */ /**< gaussian error function (1 operand) */
9863  /* SCIP_EXPR_ERFI = 21, */ /**< imaginary part of gaussian error function (1 operand) */
9864  case SCIP_EXPR_MIN:
9865  case SCIP_EXPR_MAX:
9866  case SCIP_EXPR_ABS:
9867  case SCIP_EXPR_SIGN:
9868  SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9869  if( printchildrenbounds )
9870  {
9871  SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9872  if( node->nchildren == 2 )
9873  SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9874  SCIPmessageFPrintInfo(messagehdlr, file, ")");
9875  }
9876  break;
9877 
9878  case SCIP_EXPR_SUM:
9879  if( printchildrenbounds )
9880  for( i = 0; i < node->nchildren; ++i )
9881  {
9882  if( i > 0 )
9883  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9884  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9885  }
9886  else
9887  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9888  break;
9889 
9890  case SCIP_EXPR_PRODUCT:
9891  if( printchildrenbounds )
9892  for( i = 0; i < node->nchildren; ++i )
9893  {
9894  if( i > 0 )
9895  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9896  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9897  }
9898  else
9899  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9900  break;
9901 
9902  case SCIP_EXPR_LINEAR:
9903  {
9904  SCIP_Real constant;
9905 
9906  constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9907 
9908  if( constant != 0.0 || node->nchildren == 0 )
9909  SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9910 
9911  for( i = 0; i < node->nchildren; ++i )
9912  {
9913  if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9914  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9915  else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9916  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9917  else
9918  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9919  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9920  if( printchildrenbounds )
9921  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9922  }
9923 
9924  break;
9925  }
9926 
9927  case SCIP_EXPR_QUADRATIC:
9928  {
9929  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9930 
9931  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9932  assert(quadraticdata != NULL);
9933 
9934  if( quadraticdata->constant != 0.0 )
9935  SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9936 
9937  if( quadraticdata->lincoefs != NULL )
9938  for( i = 0; i < node->nchildren; ++i )
9939  {
9940  if( quadraticdata->lincoefs[i] == 0.0 )
9941  continue;
9942  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9943  if( printchildrenbounds )
9944  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9945  }
9946 
9947  for( i = 0; i < quadraticdata->nquadelems; ++i )
9948  {
9949  if( quadraticdata->quadelems[i].coef == 1.0 )
9950  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9951  else if( quadraticdata->quadelems[i].coef == -1.0 )
9952  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9953  else
9954  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9955  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9956  if( printchildrenbounds )
9957  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9958  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9959  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9960  else
9961  {
9962  SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9963  if( printchildrenbounds )
9964  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9965  }
9966  }
9967 
9968  break;
9969  }
9970 
9971  case SCIP_EXPR_POLYNOMIAL:
9972  {
9973  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9974  SCIP_EXPRDATA_MONOMIAL* monomialdata;
9975  int j;
9976 
9977  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9978  assert(polynomialdata != NULL);
9979 
9980  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
9981  {
9982  SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
9983  }
9984 
9985  for( i = 0; i < polynomialdata->nmonomials; ++i )
9986  {
9987  monomialdata = polynomialdata->monomials[i];
9988  if( monomialdata->coef == 1.0 )
9989  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9990  else if( monomialdata->coef == -1.0 )
9991  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9992  else
9993  SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
9994 
9995  for( j = 0; j < monomialdata->nfactors; ++j )
9996  {
9997  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
9998  if( printchildrenbounds )
9999  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
10000  if( monomialdata->exponents[j] < 0.0 )
10001  SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
10002  else if( monomialdata->exponents[j] != 1.0 )
10003  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
10004  }
10005  }
10006 
10007  break;
10008  }
10009 
10010  case SCIP_EXPR_LAST:
10011  SCIPABORT();
10012  break;
10013 
10014  default:
10015  SCIPmessageFPrintInfo(messagehdlr, file, "%s", SCIPexpropGetName(node->op));
10016  break;
10017  } /*lint !e788*/
10018 }
10019 
10020 /** prints a node of an expression graph */
10021 static
10023  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10024  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10025  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
10026  FILE* file, /**< file to print to, or NULL for stdout */
10027  const char** varnames /**< variable names, or NULL for generic names */
10028  )
10029 {
10030  SCIP_Real color;
10031  int i;
10032 
10033  assert(exprgraph != NULL);
10034  assert(node != NULL);
10035  assert(file != NULL);
10036 
10037  color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
10038  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
10039 
10040  exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
10041 
10042  SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
10044  SCIPmessageFPrintInfo(messagehdlr, file, "!");
10046  SCIPmessageFPrintInfo(messagehdlr, file, "*");
10048  SCIPmessageFPrintInfo(messagehdlr, file, "+");
10049 
10050  SCIPmessageFPrintInfo(messagehdlr, file, "\"");
10051 
10052  if( !node->enabled )
10053  SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
10054 
10055  SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
10056 
10057  /* add edges from node to children */
10058  for( i = 0; i < node->nchildren; ++i )
10059  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);
10060 }
10061 
10062 /** evaluate node of expression graph w.r.t. values stored in children */
10063 static
10065  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10066  SCIP_Real* varvals /**< values for variables */
10067  )
10068 {
10069  int i;
10071  SCIP_Real* buf;
10072 
10073  assert(node != NULL);
10074 
10075  /* if many children, get large enough memory to store argument values */
10077  {
10078  SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
10079  }
10080  else
10081  {
10082  buf = staticbuf;
10083  }
10084 
10085  /* get values of children */
10086  for( i = 0; i < node->nchildren; ++i )
10087  {
10088  assert(node->children[i]->value != SCIP_INVALID); /*lint !e777*/
10089  buf[i] = node->children[i]->value; /*lint !e644*/
10090  }
10091 
10092  /* evaluate this expression */
10093  assert(exprOpTable[node->op].eval != NULL);
10094  SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
10095  assert(node->value != SCIP_INVALID); /*lint !e777*/
10096 
10097  /* free memory, if allocated before */
10098  if( staticbuf != buf )
10099  {
10100  BMSfreeMemoryArray(&buf);
10101  }
10102 
10103  return SCIP_OKAY;
10104 }
10105 
10106 /** evaluates node including subtree */
10107 static
10109  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10110  SCIP_Real* varvals /**< values for variables */
10111  )
10112 {
10113  int i;
10114 
10115  assert(node != NULL);
10116 
10117  for( i = 0; i < node->nchildren; ++i )
10118  {
10119  SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
10120  }
10121 
10122  SCIP_CALL( exprgraphNodeEval(node, varvals) );
10123 
10124  return SCIP_OKAY;
10125 }
10126 
10127 /** updates bounds of a node if a children has changed its bounds */
10128 static
10130  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10131  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10132  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
10133  SCIP_Bool parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
10134  )
10135 {
10136  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
10137  SCIP_INTERVAL* childbounds;
10138  SCIP_INTERVAL newbounds;
10139  int i;
10140 
10141  assert(node != NULL);
10142  assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
10143  assert(node->pos >= 0); /* node should be in graph */
10144  assert(node->op != SCIP_EXPR_VARIDX);
10145  assert(node->op != SCIP_EXPR_PARAM);
10146 
10147  /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
10148  * if node is disabled, then also do nothing */
10149  if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
10150  return SCIP_OKAY;
10151 
10152  /* if many children, get large enough memory to store children bounds */
10154  {
10155  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
10156  }
10157  else
10158  {
10159  childbounds = childboundsstatic;
10160  }
10161 
10162  /* assemble bounds of children */
10163  for( i = 0; i < node->nchildren; ++i )
10164  {
10165  /* child should have valid and non-empty bounds */
10167  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10168 
10169  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
10170  }
10171 
10172  /* call interval evaluation function for this operand */
10173  assert( exprOpTable[node->op].inteval != NULL );
10174  SCIPintervalSet(&newbounds, 0.0);
10175  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
10176 
10177  /* free memory, if allocated before */
10178  if( childbounds != childboundsstatic )
10179  {
10180  BMSfreeMemoryArray(&childbounds);
10181  }
10182 
10183  /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
10184 
10185  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
10186  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
10187  *
10188  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
10189  *
10190  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
10191  */
10192  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
10193  ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
10194  {
10195  for( i = 0; i < node->nparents; ++i )
10197 
10198  node->bounds = newbounds;
10199  }
10200  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
10201  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
10202  {
10203  for( i = 0; i < node->nparents; ++i )
10205 
10206  node->bounds = newbounds;
10207  }
10208  else
10209  {
10210  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
10211  }
10212 
10213  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);
10214 
10215  /* node now has valid bounds */
10216  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
10217 
10218  return SCIP_OKAY;
10219 }
10220 
10221 /** propagate bounds of a node into children by reverting the nodes expression */
10222 static
10224  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10225  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
10226  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10227  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
10228  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
10229  )
10230 {
10231  SCIP_INTERVAL childbounds;
10232  int i;
10233 
10234  assert(exprgraph != NULL);
10235  assert(node != NULL);
10236  assert(node->depth >= 0); /* node should be in graph */
10237  assert(node->pos >= 0); /* node should be in graph */
10238  assert(minstrength >= 0.0);
10239  assert(cutoff != NULL);
10240  assert(!SCIPintervalIsEmpty(infinity, node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
10241  assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
10242 
10243  /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
10245  return;
10246 
10247  /* if node is not enabled, then do nothing */
10248  if( !node->enabled )
10249  return;
10250 
10251  /* tell children that they should propagate their bounds even if not tightened */
10253  minstrength = -1.0;
10254 
10255  /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
10257 
10258  /* 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);
10259  * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10260  * SCIPdebugPrintf("\n");
10261  */
10262 
10263  /* @todo add callback to exprOpTable for this */
10264 
10265  switch( node->op )
10266  {
10267  case SCIP_EXPR_VARIDX:
10268  case SCIP_EXPR_CONST:
10269  case SCIP_EXPR_PARAM:
10270  /* cannot propagate bound changes further */
10271  break;
10272 
10273  case SCIP_EXPR_PLUS:
10274  {
10275  assert(node->nchildren == 2);
10276  /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
10277 
10278  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10279  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10280 
10281  if( *cutoff )
10282  break;
10283 
10284  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10285  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10286 
10287  break;
10288  }
10289 
10290  case SCIP_EXPR_MINUS:
10291  {
10292  assert(node->nchildren == 2);
10293  /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
10294 
10295  SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10296  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10297 
10298  if( *cutoff )
10299  break;
10300 
10301  SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10302  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10303 
10304  break;
10305  }
10306 
10307  case SCIP_EXPR_MUL:
10308  {
10309  assert(node->nchildren == 2);
10310  /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
10311 
10312  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10313  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10314 
10315  if( *cutoff )
10316  break;
10317 
10318  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10319  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10320 
10321  break;
10322  }
10323 
10324  case SCIP_EXPR_DIV:
10325  {
10326  assert(node->nchildren == 2);
10327  /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
10328 
10329  SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10330  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10331 
10332  if( *cutoff )
10333  break;
10334 
10335  SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10336  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10337 
10338  break;
10339  }
10340 
10341  case SCIP_EXPR_SQUARE:
10342  {
10343  assert(node->nchildren == 1);
10344  /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
10345 
10346  if( node->bounds.sup < 0.0 )
10347  {
10348  *cutoff = TRUE;
10349  break;
10350  }
10351 
10352  SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
10353  if( node->children[0]->bounds.inf <= -childbounds.inf )
10354  SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
10355  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10356 
10357  break;
10358  }
10359 
10360  case SCIP_EXPR_SQRT:
10361  {
10362  assert(node->nchildren == 1);
10363  /* f = sqrt(c0) -> c0 = f^2 */
10364 
10365  SCIPintervalSquare(infinity, &childbounds, node->bounds);
10366  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10367 
10368  break;
10369  }
10370 
10371  case SCIP_EXPR_REALPOWER:
10372  {
10373  assert(node->nchildren == 1);
10374 
10375  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
10376 
10377  if( SCIPintervalIsEmpty(infinity, childbounds) )
10378  {
10379  *cutoff = TRUE;
10380  break;
10381  }
10382  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10383 
10384  break;
10385  }
10386 
10387  case SCIP_EXPR_SIGNPOWER:
10388  {
10389  assert(node->nchildren == 1);
10390 
10391  if( node->data.dbl != 0.0 )
10392  {
10393  SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
10394  }
10395  else
10396  {
10397  /* behaves like SCIP_EXPR_SIGN */
10398  SCIPintervalSetBounds(&childbounds,
10399  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10400  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10401  }
10402 
10403  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10404 
10405  break;
10406  }
10407 
10408  case SCIP_EXPR_INTPOWER:
10409  {
10410  assert(node->nchildren == 1);
10411 
10412  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
10413 
10414  if( SCIPintervalIsEmpty(infinity, childbounds) )
10415  {
10416  *cutoff = TRUE;
10417  break;
10418  }
10419  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10420 
10421  break;
10422  }
10423 
10424  case SCIP_EXPR_EXP:
10425  {
10426  assert(node->nchildren == 1);
10427  /* f = exp(c0) -> c0 = log(f) */
10428 
10429  if( node->bounds.sup < 0.0 )
10430  {
10431  *cutoff = TRUE;
10432  break;
10433  }
10434 
10435  SCIPintervalLog(infinity, &childbounds, node->bounds);
10436  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10437 
10438  break;
10439  }
10440 
10441  case SCIP_EXPR_LOG:
10442  {
10443  assert(node->nchildren == 1);
10444  /* f = log(c0) -> c0 = exp(f) */
10445 
10446  SCIPintervalExp(infinity, &childbounds, node->bounds);
10447  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10448 
10449  break;
10450  }
10451 
10452  case SCIP_EXPR_SIN:
10453  case SCIP_EXPR_COS:
10454  case SCIP_EXPR_TAN:
10455  /* case SCIP_EXPR_ERF: */
10456  /* case SCIP_EXPR_ERFI: */
10457  {
10458  assert(node->nchildren == 1);
10459 
10460  /* @todo implement */
10461 
10462  break;
10463  }
10464 
10465  case SCIP_EXPR_ABS:
10466  {
10467  assert(node->nchildren == 1);
10468 
10469  /* use identity if child bounds are non-negative */
10470  if( node->children[0]->bounds.inf >= 0 )
10471  {
10472  SCIPintervalSetBounds(&childbounds, node->bounds.inf, node->bounds.sup);
10473  }
10474  /* use -identity if child bounds are non-positive */
10475  else if( node->children[0]->bounds.sup <= 0 )
10476  {
10477  assert(node->bounds.inf <= node->bounds.sup);
10478  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, -node->bounds.inf);
10479  }
10480  /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
10481  else
10482  {
10483  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
10484  }
10485 
10486  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10487 
10488  break;
10489  }
10490 
10491  case SCIP_EXPR_SIGN:
10492  {
10493  assert(node->nchildren == 1);
10494  /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
10495 
10496  SCIPintervalSetBounds(&childbounds,
10497  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10498  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10499  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10500 
10501  break;
10502  }
10503 
10504  case SCIP_EXPR_MIN:
10505  {
10506  assert(node->nchildren == 2);
10507  /* f = min(c0,c1) -> f <= c0, f <= c1
10508  * if c1 > f -> c0 = f
10509  * if c0 > f -> c1 = f
10510  */
10511 
10512  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10513  node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10514  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10515 
10516  if( *cutoff )
10517  break;
10518 
10519  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10520  node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10521  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10522 
10523  break;
10524  }
10525 
10526  case SCIP_EXPR_MAX:
10527  {
10528  assert(node->nchildren == 2);
10529  /* f = max(c0, c1) -> f >= c0, f >= c1
10530  * if c1 < f -> c0 = f
10531  * if c0 < f -> c1 = f
10532  */
10533 
10534  SCIPintervalSetBounds(&childbounds,
10535  node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10536  node->bounds.sup);
10537  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10538 
10539  SCIPintervalSetBounds(&childbounds,
10540  node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10541  node->bounds.sup);
10542  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10543 
10544  break;
10545  }
10546 
10547  case SCIP_EXPR_SUM:
10548  {
10549  SCIP_ROUNDMODE prevroundmode;
10550 
10551  /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
10552 
10553  SCIP_Real minlinactivity;
10554  SCIP_Real maxlinactivity;
10555  int minlinactivityinf;
10556  int maxlinactivityinf;
10557 
10558  if( node->nchildren == 0 )
10559  break;
10560 
10561  if( SCIPintervalIsEntire(infinity, node->bounds) )
10562  break;
10563 
10564  minlinactivity = 0.0;
10565  maxlinactivity = 0.0;
10566  minlinactivityinf = 0;
10567  maxlinactivityinf = 0;
10568 
10569  prevroundmode = SCIPintervalGetRoundingMode();
10571 
10572  for( i = 0; i < node->nchildren; ++i )
10573  {
10574  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10575 
10576  /* minimal activity is only useful if node has a finite upper bound */
10577  if( node->bounds.sup < infinity )
10578  {
10579  if( node->children[i]->bounds.inf <= -infinity )
10580  {
10581  ++minlinactivityinf;
10582  }
10583  else
10584  {
10585  assert(node->children[i]->bounds.inf < infinity);
10586  minlinactivity += node->children[i]->bounds.inf;
10587  }
10588  }
10589 
10590  /* maximal activity is only useful if node has a finite lower bound
10591  * we compute negated maximal activity here so we can keep downward rounding
10592  */
10593  if( node->bounds.inf > -infinity )
10594  {
10595  if( node->children[i]->bounds.sup >= infinity )
10596  {
10597  ++maxlinactivityinf;
10598  }
10599  else
10600  {
10601  assert(node->children[i]->bounds.sup > -infinity);
10602  maxlinactivity -= node->children[i]->bounds.sup;
10603  }
10604  }
10605  }
10606  maxlinactivity = -maxlinactivity; /* correct sign */
10607 
10608  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10609  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10610  ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10611  )
10612  {
10613  SCIPintervalSetRoundingMode(prevroundmode);
10614  break;
10615  }
10616 
10617  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10618  {
10619  /* upper bounds of c_i is
10620  * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
10621  * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
10622  */
10623  SCIPintervalSetEntire(infinity, &childbounds);
10624  if( node->bounds.sup < infinity )
10625  {
10626  /* we are still in downward rounding mode, so negate and negate to get upward rounding */
10627  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10628  {
10629  assert(minlinactivityinf == 1);
10630  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
10631  }
10632  else if( minlinactivityinf == 0 )
10633  {
10634  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
10635  }
10636  }
10637 
10638  /* lower bounds of c_i is
10639  * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
10640  * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
10641  */
10642  if( node->bounds.inf > -infinity )
10643  {
10644  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10645  {
10646  assert(maxlinactivityinf == 1);
10647  childbounds.inf = node->bounds.inf - maxlinactivity;
10648  }
10649  else if( maxlinactivityinf == 0 )
10650  {
10651  childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
10652  }
10653  }
10654 
10655  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10656  }
10657 
10658  SCIPintervalSetRoundingMode(prevroundmode);
10659 
10660  break;
10661  }
10662 
10663  case SCIP_EXPR_PRODUCT:
10664  {
10665  int j;
10666  /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
10667 
10668  /* too expensive (runtime here is quadratic in number of children) */
10669  if( node->nchildren > 10 )
10670  break;
10671 
10672  /* useless */
10673  if( SCIPintervalIsEntire(infinity, node->bounds) )
10674  break;
10675 
10676  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10677  {
10678  /* compute prod_{j:j!=i} c_j */
10679  SCIPintervalSet(&childbounds, 1.0);
10680  for( j = 0; j < node->nchildren; ++j )
10681  {
10682  if( i == j )
10683  continue;
10684  SCIPintervalMul(infinity, &childbounds, childbounds, node->children[j]->bounds);
10685 
10686  /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
10687  if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
10688  break;
10689  }
10690 
10691  if( j == node->nchildren )
10692  {
10693  SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
10694  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10695  }
10696  }
10697 
10698  break;
10699  }
10700 
10701  case SCIP_EXPR_LINEAR:
10702  {
10703  SCIP_ROUNDMODE prevroundmode;
10704  SCIP_Real* coefs;
10705 
10706  /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10707 
10708  SCIP_Real minlinactivity;
10709  SCIP_Real maxlinactivity;
10710  int minlinactivityinf;
10711  int maxlinactivityinf;
10712 
10713  if( node->nchildren == 0 )
10714  break;
10715 
10716  if( SCIPintervalIsEntire(infinity, node->bounds) )
10717  break;
10718 
10719  coefs = (SCIP_Real*)node->data.data;
10720 
10721  minlinactivity = coefs[node->nchildren];
10722  maxlinactivity = -coefs[node->nchildren];
10723  minlinactivityinf = 0;
10724  maxlinactivityinf = 0;
10725 
10726  prevroundmode = SCIPintervalGetRoundingMode();
10728 
10729  for( i = 0; i < node->nchildren; ++i )
10730  {
10731  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10732 
10733  /* minimal activity is only useful if node has a finite upper bound */
10734  if( node->bounds.sup < infinity )
10735  {
10736  if( coefs[i] >= 0.0 )
10737  {
10738  if( node->children[i]->bounds.inf <= -infinity )
10739  {
10740  ++minlinactivityinf;
10741  }
10742  else
10743  {
10744  assert(node->children[i]->bounds.inf < infinity);
10745  minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10746  }
10747  }
10748  else
10749  {
10750  if( node->children[i]->bounds.sup >= infinity )
10751  {
10752  ++minlinactivityinf;
10753  }
10754  else
10755  {
10756  assert(node->children[i]->bounds.sup > -infinity);
10757  minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10758  }
10759  }
10760  }
10761 
10762  /* maximal activity is only useful if node has a finite lower bound
10763  * we compute negated maximal activity here so we can keep downward rounding
10764  */
10765  if( node->bounds.inf > -infinity )
10766  {
10767  if( coefs[i] >= 0.0 )
10768  {
10769  if( node->children[i]->bounds.sup >= infinity )
10770  {
10771  ++maxlinactivityinf;
10772  }
10773  else
10774  {
10775  assert(node->children[i]->bounds.sup > -infinity);
10776  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.sup;
10777  }
10778  }
10779  else
10780  {
10781  if( node->children[i]->bounds.inf <= -infinity )
10782  {
10783  ++maxlinactivityinf;
10784  }
10785  else
10786  {
10787  assert(node->children[i]->bounds.inf < infinity);
10788  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.inf;
10789  }
10790  }
10791  }
10792  }
10793  maxlinactivity = SCIPintervalNegateReal(maxlinactivity); /* correct sign */
10794 
10795  /* SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]; bounds = [%10g,%10g]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf, node->bounds.inf, node->bounds.sup); */
10796 
10797  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10798  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10799  (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10800  )
10801  {
10802  SCIPintervalSetRoundingMode(prevroundmode);
10803  break;
10804  }
10805 
10806  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10807  {
10808  SCIP_INTERVAL ac;
10809 
10810  if( coefs[i] == 0.0 )
10811  continue;
10812 
10813  /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10814  SCIPintervalSet(&ac, 0.0);
10815  if( coefs[i] >= 0.0 )
10816  {
10817  if( node->children[i]->bounds.inf > -infinity )
10818  ac.inf = coefs[i] * node->children[i]->bounds.inf;
10819  if( node->children[i]->bounds.sup < infinity )
10821  }
10822  else
10823  {
10824  if( node->children[i]->bounds.sup < infinity )
10825  ac.inf = coefs[i] * node->children[i]->bounds.sup;
10826  if( node->children[i]->bounds.inf > -infinity )
10827  ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10828  }
10829 
10830  SCIPintervalSetEntire(infinity, &childbounds);
10831  if( coefs[i] > 0.0 )
10832  {
10833  /* upper bounds of c_i is
10834  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10835  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10836  */
10837  if( node->bounds.sup < infinity )
10838  {
10839  /* we are still in downward rounding mode, so negate to get upward rounding */
10840  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10841  {
10842  assert(minlinactivityinf == 1);
10843  childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10844  }
10845  else if( minlinactivityinf == 0 )
10846  {
10847  childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10848  }
10849  }
10850 
10851  /* lower bounds of c_i is
10852  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10853  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10854  */
10855  if( node->bounds.inf > -infinity )
10856  {
10857  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10858  {
10859  assert(maxlinactivityinf == 1);
10860  childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10861  }
10862  else if( maxlinactivityinf == 0 )
10863  {
10864  childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10865  }
10866  }
10867  }
10868  else
10869  {
10870  /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10871  * thus, we do (b-a)/(-c) in downward rounding
10872  */
10873  /* lower bounds of c_i is
10874  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10875  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10876  */
10877  if( node->bounds.sup < infinity )
10878  {
10879  if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10880  {
10881  assert(minlinactivityinf == 1);
10882  childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10883  }
10884  else if( minlinactivityinf == 0 )
10885  {
10886  childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10887  }
10888  }
10889 
10890  /* upper bounds of c_i is
10891  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10892  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10893  */
10894  if( node->bounds.inf > -infinity )
10895  {
10896  /* we are still in downward rounding mode, so negate to get upward rounding */
10897  if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10898  {
10899  assert(maxlinactivityinf == 1);
10900  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10901  }
10902  else if( maxlinactivityinf == 0 )
10903  {
10904  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10905  }
10906  }
10907  }
10908 
10909  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10910  }
10911 
10912  SCIPintervalSetRoundingMode(prevroundmode);
10913 
10914  break;
10915  }
10916 
10917  case SCIP_EXPR_QUADRATIC:
10918  {
10919  SCIP_EXPRDATA_QUADRATIC* quaddata;
10920  SCIP_INTERVAL tmp;
10921  SCIP_INTERVAL a;
10922  SCIP_INTERVAL b;
10923  SCIP_INTERVAL c;
10924  SCIP_QUADELEM* quadelems;
10925  int nquadelems;
10926  SCIP_Real* lincoefs;
10927  int k;
10928 
10929  /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10930  * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10931  */
10932 
10933  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10934  quadelems = quaddata->quadelems;
10935  nquadelems = quaddata->nquadelems;
10936  lincoefs = quaddata->lincoefs;
10937 
10938  /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10939  if( nquadelems > 10 )
10940  break;
10941 
10942  if( SCIPintervalIsEntire(infinity, node->bounds) )
10943  break;
10944 
10945  if( node->nchildren == 2 && nquadelems > 0 )
10946  {
10947  /* if it's a bivariate quadratic expression with bilinear term, do something special */
10948  SCIP_Real ax; /* square coefficient of first child */
10949  SCIP_Real ay; /* square coefficient of second child */
10950  SCIP_Real axy; /* bilinear coefficient */
10951 
10952  ax = 0.0;
10953  ay = 0.0;
10954  axy = 0.0;
10955  for( i = 0; i < nquadelems; ++i )
10956  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10957  ax += quadelems[i].coef;
10958  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10959  ay += quadelems[i].coef;
10960  else
10961  axy += quadelems[i].coef;
10962 
10963  c = node->bounds;
10964  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10965 
10966  /* compute bounds for x */
10968  infinity, &childbounds, ax, ay, axy,
10969  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10970  c, node->children[0]->bounds, node->children[1]->bounds
10971  );
10972  if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10973  {
10974  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",
10975  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10976  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10977  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10978  );
10979  }
10980 
10981  if( SCIPintervalIsEmpty(infinity, childbounds) )
10982  *cutoff = TRUE;
10983  else
10984  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10985  if( *cutoff )
10986  break;
10987 
10988  /* compute bounds for y */
10990  infinity, &childbounds, ay, ax, axy,
10991  lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
10992  c, node->children[1]->bounds, node->children[0]->bounds
10993  );
10994 
10995  if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
10996  {
10997  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",
10998  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10999  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
11000  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
11001  );
11002  }
11003 
11004  if( SCIPintervalIsEmpty(infinity, childbounds) )
11005  *cutoff = TRUE;
11006  else
11007  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
11008  if( *cutoff )
11009  break;
11010 
11011  break;
11012  }
11013 
11014  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11015  {
11016  SCIPintervalSet(&a, 0.0);
11017  SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
11018  c = node->bounds;
11019  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
11020 
11021  /* move linear terms not corresponding to i into c
11022  * @todo do this faster, see EXPR_LINEAR
11023  */
11024  if( lincoefs != NULL )
11025  for( k = 0; k < node->nchildren; ++k )
11026  if( i != k && lincoefs[k] != 0.0 )
11027  {
11028  SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
11029  SCIPintervalSub(infinity, &c, c, tmp);
11030  }
11031 
11032  for( k = 0; k < nquadelems; ++k )
11033  {
11034  if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
11035  {
11036  SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
11037  }
11038  else if( quadelems[k].idx1 == i )
11039  {
11040  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
11041  SCIPintervalAdd(infinity, &b, b, tmp);
11042  }
11043  else if( quadelems[k].idx2 == i )
11044  {
11045  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
11046  SCIPintervalAdd(infinity, &b, b, tmp);
11047  }
11048  else if( quadelems[k].idx1 == quadelems[k].idx2 )
11049  {
11050  SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
11051  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11052  SCIPintervalSub(infinity, &c, c, tmp);
11053  }
11054  else
11055  {
11056  SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
11057  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11058  SCIPintervalSub(infinity, &c, c, tmp);
11059  }
11060  }
11061 
11062  SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
11063  a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
11064  SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c, node->children[i]->bounds);
11065  if( SCIPintervalIsEmpty(infinity, childbounds) )
11066  *cutoff = TRUE;
11067  else
11068  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11069  }
11070 
11071  break;
11072  }
11073 
11074  case SCIP_EXPR_POLYNOMIAL:
11075  {
11076  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11077  SCIP_EXPRDATA_MONOMIAL** monomials;
11078  SCIP_EXPRDATA_MONOMIAL* monomial;
11079  int nmonomials;
11080  int j;
11081  int k;
11082  SCIP_Real n;
11083  int nexpisdoublen;
11084  int nexpishalfn;
11085  char abc_flag;
11086 
11087  SCIP_INTERVAL monomialcoef;
11088  SCIP_INTERVAL tmp;
11089  SCIP_INTERVAL a;
11090  SCIP_INTERVAL b;
11091  SCIP_INTERVAL c;
11092  SCIP_INTERVAL childpowbounds;
11093 
11094  /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
11095  * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
11096  *
11097  * we determine n by setting n to the first exponent of x that we see
11098  * then we count how often we see x^(2n) and x^(n/2)
11099  * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
11100  */
11101 
11102  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11103  monomials = polynomialdata->monomials;
11104  nmonomials = polynomialdata->nmonomials;
11105 
11106  if( SCIPintervalIsEntire(infinity, node->bounds) )
11107  break;
11108 
11109  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11110  {
11111  n = 0.0;
11112  nexpisdoublen = 0;
11113  nexpishalfn = 0;
11114  for( j = 0; j < nmonomials; ++j )
11115  {
11116  monomial = monomials[j];
11117  for( k = 0; k < monomial->nfactors; ++k )
11118  {
11119  if( monomial->childidxs[k] == i )
11120  {
11121  if( n == 0.0 )
11122  n = monomial->exponents[k];
11123  else if( n == 2*monomial->exponents[k] ) /*lint !e777*/
11124  ++nexpishalfn;
11125  else if( 2*n == monomial->exponents[k] ) /*lint !e777*/
11126  ++nexpisdoublen;
11127  }
11128  }
11129  }
11130 
11131  if( n == 0.0 )
11132  {
11133  /* child does not appear in polynomial -> cannot deduce bound */
11134  continue;
11135  }
11136 
11137  /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
11138  if( nexpishalfn > nexpisdoublen )
11139  n /= 2.0;
11140 
11141  SCIPintervalSet(&a, 0.0);
11142  SCIPintervalSet(&b, 0.0);
11143  SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
11144 
11145  for( j = 0; j < nmonomials; ++j )
11146  {
11147  monomial = monomials[j];
11148  SCIPintervalSet(&monomialcoef, monomial->coef);
11149  abc_flag = 'c';
11150  for( k = 0; k < monomial->nfactors; ++k )
11151  {
11152  if( monomial->childidxs[k] == i )
11153  {
11154  assert(abc_flag == 'c'); /* child should appear only once per monom */
11155  if( n > 0.0 )
11156  {
11157  if( monomial->exponents[k] > 2.0*n )
11158  {
11159  abc_flag = 'a';
11160  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11161  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11162  }
11163  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11164  {
11165  abc_flag = 'a';
11166  }
11167  else if( monomial->exponents[k] > n )
11168  {
11169  abc_flag = 'b';
11170  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11171  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11172  }
11173  else if( monomial->exponents[k] == n ) /*lint !e777*/
11174  {
11175  abc_flag = 'b';
11176  }
11177  else
11178  {
11179  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11180  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11181  }
11182  }
11183  else
11184  {
11185  assert(n < 0.0);
11186  if( monomial->exponents[k] < 2.0*n )
11187  {
11188  abc_flag = 'a';
11189  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11190  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11191  }
11192  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11193  {
11194  abc_flag = 'a';
11195  }
11196  else if( monomial->exponents[k] < n )
11197  {
11198  abc_flag = 'b';
11199  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11200  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11201  }
11202  else if( monomial->exponents[k] == n ) /*lint !e777*/
11203  {
11204  abc_flag = 'b';
11205  }
11206  else
11207  {
11208  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11209  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11210  }
11211  }
11212  }
11213  else
11214  {
11215  SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
11216  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11217  }
11218  }
11219 
11220  if( abc_flag == 'a' )
11221  {
11222  SCIPintervalAdd(infinity, &a, a, monomialcoef);
11223  /* if monomialcoef is such that a exceeds value for infinity, then stop */
11224  if( a.inf >= infinity || a.sup <= -infinity )
11225  break;
11226  }
11227  else if( abc_flag == 'b' )
11228  {
11229  SCIPintervalAdd(infinity, &b, b, monomialcoef);
11230  /* if monomialcoef is such that b exceeds value for infinity, then stop */
11231  if( b.inf >= infinity || b.sup <= -infinity )
11232  break;
11233  }
11234  else
11235  {
11236  SCIPintervalSub(infinity, &c, c, monomialcoef);
11237  /* if monomialcoef is such that c exceeds value for infinity, then stop */
11238  if( c.inf >= infinity || c.sup <= -infinity )
11239  break;
11240  }
11241  }
11242 
11243  /* if we run out of numbers (within -infinity,infinity) above, then stop */
11244  if( j < nmonomials )
11245  continue;
11246 
11247  /* now have equation a*child^(2n) + b*child^n = c
11248  * solve a*y^2 + b*y = c (for y in childbounds^n), then child^n = y
11249  */
11250  SCIPintervalPowerScalar(infinity, &childpowbounds, node->children[i]->bounds, n);
11251  SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g] for c%d^%g in [%10g,%10g]",
11252  a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup, i, n, childpowbounds.inf, childpowbounds.sup);
11253  SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c, childpowbounds);
11254  SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
11255 
11256  if( SCIPintervalIsEmpty(infinity, tmp) )
11257  {
11258  *cutoff = TRUE;
11259  break;
11260  }
11261 
11262  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
11263  SCIPdebugPrintf(" -> c%d = [%10g, %10g]\n", i, childbounds.inf, childbounds.sup);
11264  if( SCIPintervalIsEmpty(infinity, childbounds) )
11265  {
11266  SCIPdebugMessage(" -> cutoff\n");
11267  *cutoff = TRUE;
11268  break;
11269  }
11270 
11271  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11272 
11273  /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
11274  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11275  SCIPdebugPrintf("\n"); */
11276  }
11277 
11278  break;
11279  }
11280 
11281  case SCIP_EXPR_USER:
11282  {
11283  SCIP_INTERVAL* childrenbounds;
11284  SCIP_EXPRDATA_USER* exprdata;
11285  int c;
11286 
11287  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11288 
11289  /* do nothing if callback not implemented */
11290  if( exprdata->prop == NULL )
11291  break;
11292 
11293  /* if only one child, do faster */
11294  if( node->nchildren == 1 )
11295  {
11296  childbounds = node->children[0]->bounds;
11297  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, 1, &childbounds, node->bounds, cutoff) );
11298 
11299  if( !*cutoff )
11300  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11301 
11302  break;
11303  }
11304 
11305  SCIP_ALLOC_ABORT( BMSallocBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren) );
11306  for( c = 0; c < node->nchildren; ++c )
11307  childrenbounds[c] = node->children[c]->bounds;
11308 
11309  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, node->nchildren, childrenbounds, node->bounds, cutoff) );
11310 
11311  for( c = 0; !*cutoff && c < node->nchildren; ++c )
11312  {
11313  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[c], childrenbounds[c], minstrength, infinity, cutoff);
11314  }
11315 
11316  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren);
11317 
11318  break;
11319  }
11320 
11321  case SCIP_EXPR_LAST:
11322  SCIPABORT();
11323  break;
11324  }
11325 }
11326 
11327 /** removes duplicate children in a polynomial expression node
11328  *
11329  * Leaves NULL's in children array.
11330  */
11331 static
11333  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11334  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11335  )
11336 {
11337  SCIP_Bool foundduplicates;
11338  int* childmap;
11339  int i;
11340  int j;
11341 
11342  assert(exprgraph != NULL);
11343  assert(node != NULL);
11344  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11345 
11346  if( node->nchildren == 0 )
11347  return SCIP_OKAY;
11348 
11349  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
11350 
11351  foundduplicates = FALSE;
11352  for( i = 0; i < node->nchildren; ++i )
11353  {
11354  if( node->children[i] == NULL )
11355  continue;
11356  childmap[i] = i; /*lint !e644*/
11357 
11358  for( j = i+1; j < node->nchildren; ++j )
11359  {
11360  if( node->children[j] == NULL )
11361  continue;
11362 
11363  if( node->children[i] == node->children[j] )
11364  {
11365  /* node should be parent of children[j] at least twice,
11366  * so we remove it once
11367  */
11368  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
11369  node->children[j] = NULL;
11370  assert(exprgraphNodeIsParent(node->children[i], node));
11371 
11372  childmap[j] = i;
11373  foundduplicates = TRUE;
11374  }
11375  }
11376  }
11377 
11378  /* apply childmap to monomials */
11379  if( foundduplicates )
11381 
11382  /* free childmap */
11383  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
11384 
11385  return SCIP_OKAY;
11386 }
11387 
11388 /** eliminates NULL's in children array and shrinks it to actual size */
11389 static
11391  BMS_BLKMEM* blkmem, /**< block memory */
11392  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11393  )
11394 {
11395  int* childmap;
11396  int lastnonnull;
11397  int i;
11398 
11399  assert(blkmem != NULL);
11400  assert(node != NULL);
11401  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11402 
11403  if( node->nchildren == 0 )
11404  return SCIP_OKAY;
11405 
11406  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
11407 
11408  /* close gaps in children array */
11409  lastnonnull = node->nchildren-1;
11410  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11411  --lastnonnull;
11412  for( i = 0; i <= lastnonnull; ++i )
11413  {
11414  if( node->children[i] != NULL )
11415  {
11416  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
11417  continue;
11418  }
11419  assert(node->children[lastnonnull] != NULL);
11420 
11421  /* move child at lastnonnull to position i */
11422  node->children[i] = node->children[lastnonnull];
11423  node->children[lastnonnull] = NULL;
11424  childmap[lastnonnull] = i;
11425 
11426  /* update lastnonnull */
11427  --lastnonnull;
11428  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11429  --lastnonnull;
11430  }
11431  assert(i > lastnonnull);
11432 
11433  /* apply childmap to monomials */
11434  if( lastnonnull < node->nchildren-1 )
11436 
11437  BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
11438 
11439  /* shrink children array */
11440  if( lastnonnull >= 0 )
11441  {
11442  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
11443  node->nchildren = lastnonnull+1;
11444  }
11445  else
11446  {
11447  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11448  node->nchildren = 0;
11449  }
11450 
11451  return SCIP_OKAY;
11452 }
11453 
11454 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
11455  *
11456  * Converts node into polynomial, if possible and not constant.
11457  */
11458 static
11460  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11461  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
11462  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
11463  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
11464  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
11465  SCIP_Bool* havechange /**< flag to set if the node has been changed */
11466  )
11467 {
11468  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11469  SCIP_EXPRDATA_MONOMIAL* monomial;
11470  BMS_BLKMEM* blkmem;
11471  SCIP_Bool removechild;
11472  SCIP_Bool* childinuse;
11473  int* childmap;
11474  int childmapsize;
11475  int i;
11476  int j;
11477  int orignchildren;
11478 
11479  assert(exprgraph != NULL);
11480  assert(node != NULL);
11481  assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
11482  assert(havechange != NULL);
11483 
11484  blkmem = exprgraph->blkmem;
11485  assert(blkmem != NULL);
11486 
11487  SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
11488 
11489  /* if all children are constants, then turn this node into constant */
11490  for( i = 0; i < node->nchildren; ++i )
11491  if( node->children[i]->op != SCIP_EXPR_CONST )
11492  break;
11493  if( node->nchildren > 0 && i == node->nchildren )
11494  {
11495  /* get value of node */
11497  assert(node->value != SCIP_INVALID); /*lint !e777*/
11498 
11499  SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
11500  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11501  SCIPdebugPrintf("\n");
11502 
11503  /* free expression data */
11504  if( exprOpTable[node->op].freedata != NULL )
11505  exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
11506 
11507  /* disconnect from children */
11508  for( i = 0; i < node->nchildren; ++i )
11509  {
11510  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11511  }
11512  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11513  node->nchildren = 0;
11514 
11515  /* turn into constant expression */
11516  node->op = SCIP_EXPR_CONST;
11517  node->data.dbl = node->value;
11518 
11519  *havechange = TRUE;
11520  node->simplified = TRUE;
11521 
11522  return SCIP_OKAY;
11523  }
11524 
11525  /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
11526  * @todo log(product) -> sum(log)
11527  * @todo product(exp) -> exp(sum)
11528  * @todo exp(x)^p -> exp(p*x)
11529  * @todo exp(const*log(x)) -> x^const
11530  */
11531 
11532  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
11533 
11534  if( node->op != SCIP_EXPR_POLYNOMIAL )
11535  {
11536  node->simplified = TRUE;
11537  return SCIP_OKAY;
11538  }
11539 
11540  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11541  assert(polynomialdata != NULL);
11542 
11543  orignchildren = node->nchildren;
11544 
11545  /* check if we have duplicate children and merge */
11547  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11548 
11549  SCIPdebugMessage("expand factors in expression node ");
11550  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11551  SCIPdebugPrintf("\n");
11552 
11553  childmap = NULL;
11554  childmapsize = 0;
11555 
11556  /* resolve children that are constants
11557  * we do this first, because it reduces the degree and number of factors in the monomials,
11558  * 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
11559  */
11560  for( i = 0; i < node->nchildren; ++i )
11561  {
11562  if( node->children[i] == NULL )
11563  continue;
11564 
11565  /* convert children to polynomial, if not constant or polynomial
11566  * if child was simplified in this round, it may have already been converted, and then nothing happens
11567  * but if child was already simplified, then it was not converted, and thus we try it here
11568  */
11569  if( node->children[i]->op != SCIP_EXPR_CONST )
11570  continue;
11571 
11572  SCIPdebugMessage("expand child %d in expression node ", i);
11573  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11574  SCIPdebugPrintf("\n\tchild = ");
11575  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11576  SCIPdebugPrintf("\n");
11577 
11578  removechild = TRUE; /* we intend to release children[i] */
11579 
11580  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11581 
11582  /* put constant of child i into every monomial where child i is used */
11583  for( j = 0; j < polynomialdata->nmonomials; ++j )
11584  {
11585  int factorpos;
11586 
11587  monomial = polynomialdata->monomials[j];
11588  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11589  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11590 
11591  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11592  {
11593  assert(factorpos >= 0);
11594  assert(factorpos < monomial->nfactors);
11595  /* assert that factors have been merged */
11596  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11597  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11598 
11599  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11600 
11601  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 ) /*lint !e835*/
11602  {
11603  /* if constant is negative and our exponent is not integer, then cannot do expansion */
11604  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
11605  removechild = FALSE;
11606  }
11607  else
11608  {
11609  monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
11610 
11611  /* move last factor to position factorpos */
11612  if( factorpos < monomial->nfactors-1 )
11613  {
11614  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
11615  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
11616  }
11617  --monomial->nfactors;
11618  monomial->sorted = FALSE;
11619  polynomialdata->sorted = FALSE;
11620 
11621  *havechange = TRUE;
11622  }
11623  }
11624  }
11625 
11626  /* forget about child i, if it is not used anymore */
11627  if( removechild )
11628  {
11629  /* remove node from list of parents of child i */
11630  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11631  node->children[i] = NULL;
11632  }
11633 
11634  /* simplify current polynomial again */
11635  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11636  }
11637 
11638  /* resolve children that are polynomials itself */
11639  for( i = 0; i < node->nchildren; ++i )
11640  {
11641  if( node->children[i] == NULL )
11642  continue;
11643 
11644  /* convert children to polynomial, if not constant or polynomial
11645  * if child was simplified in this round, it may have already been converted, and then nothing happens
11646  * but if child was already simplified, then it was not converted, and thus we try it here
11647  */
11648  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
11649 
11650  if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
11651  continue;
11652 
11653  SCIPdebugMessage("expand child %d in expression node %p = ", i, (void*)node);
11654  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11655  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n\tchild = ") );
11656  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11657  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
11658 
11659  removechild = TRUE; /* we intend to release children[i] */
11660 
11661  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11662 
11663  /* add children of child i to node */
11664  SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
11665 
11666  /* put polynomial of child i into every monomial where child i is used */
11667  j = 0;
11668  while( j < polynomialdata->nmonomials )
11669  {
11670  int factorpos;
11671  SCIP_Bool success;
11672 
11673  monomial = polynomialdata->monomials[j];
11674  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11675  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11676 
11677  /* make sure factors are merged, should only be potentially necessary if not sorted, see also #1848 */
11678  if( !monomial->sorted )
11679  SCIPexprMergeMonomialFactors(monomial, eps);
11680 
11681  if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11682  {
11683  ++j;
11684  continue;
11685  }
11686 
11687  assert(factorpos >= 0);
11688  assert(factorpos < monomial->nfactors);
11689  /* assert that factors have been merged */
11690  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11691  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11692 
11693  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11694 
11695  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
11696  (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
11697 
11698  if( !success )
11699  {
11700  removechild = FALSE;
11701  ++j;
11702  }
11703  else
11704  *havechange = TRUE;
11705 
11706  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
11707  * we thus repeat with index j, if a factor was successfully expanded
11708  */
11709  }
11710 
11711  /* forget about child i, if it is not used anymore */
11712  if( removechild )
11713  {
11714  /* remove node from list of parents of child i */
11715  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11716  node->children[i] = NULL;
11717  }
11718  }
11719 
11720  /* simplify current polynomial again */
11721  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11722 
11723  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
11724 
11725  /* check which children are still in use */
11726  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
11727  BMSclearMemoryArray(childinuse, node->nchildren); /*lint !e644*/
11728  for( i = 0; i < polynomialdata->nmonomials; ++i )
11729  {
11730  monomial = polynomialdata->monomials[i];
11731  assert(monomial != NULL);
11732 
11733  for( j = 0; j < monomial->nfactors; ++j )
11734  {
11735  assert(monomial->childidxs[j] >= 0);
11736  assert(monomial->childidxs[j] < node->nchildren);
11737  childinuse[monomial->childidxs[j]] = TRUE;
11738  }
11739  }
11740 
11741  /* free children that are not used in any monomial */
11742  for( i = 0; i < node->nchildren; ++i )
11743  if( node->children[i] != NULL && !childinuse[i] )
11744  {
11745  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11746  node->children[i] = NULL;
11747  }
11748 
11749  BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
11750 
11751  /* remove NULLs from children array */
11753 
11754  /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
11755  if( node->nchildren == 0 )
11756  {
11757  SCIP_Real val;
11758 
11759  /* if no children, then it should also have no monomials */
11760  assert(polynomialdata->nmonomials == 0);
11761 
11762  val = polynomialdata->constant;
11763  polynomialdataFree(blkmem, &polynomialdata);
11764 
11765  node->op = SCIP_EXPR_CONST;
11766  node->data.dbl = val;
11767  node->value = val;
11768  }
11769 
11770  /* if no factor in a monomial was replaced, the number of children should not have changed
11771  * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11772  */
11773  *havechange |= (node->nchildren < orignchildren); /*lint !e514*/
11774 
11775  node->simplified = TRUE;
11776 
11777  SCIPdebugMessage("-> %p = ", (void*)node);
11778  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11779  SCIPdebugPrintf("\n");
11780 
11781  return SCIP_OKAY;
11782 }
11783 
11784 /** creates an expression from a given node in an expression graph
11785  *
11786  * Assembles mapping of variables from graph to tree.
11787  */
11788 static
11790  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11791  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which expression should be created */
11792  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
11793  int* nexprvars, /**< current number of variables in expression */
11794  int* varidx /**< current mapping of variable indices from graph to expression */
11795  )
11796 {
11797  SCIP_EXPR** childexprs;
11798  int i;
11799 
11800  assert(exprgraph != NULL);
11801  assert(node != NULL);
11802  assert(expr != NULL);
11803  assert(nexprvars != NULL);
11804  assert(*nexprvars >= 0);
11805  assert(varidx != NULL);
11806 
11807  childexprs = NULL;
11808  if( node->nchildren > 0 )
11809  {
11810  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11811  for( i = 0; i < node->nchildren; ++i )
11812  {
11813  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) ); /*lint !e613*/
11814  }
11815  }
11816 
11817  switch( node->op )
11818  {
11819  case SCIP_EXPR_VARIDX:
11820  {
11821  /* check if the variable already has an index assigned in the expression tree
11822  * if not, create one and increase nexprvars
11823  */
11824  assert(node->data.intval >= 0);
11825  assert(node->data.intval < exprgraph->nvars);
11826  assert(varidx[node->data.intval] >= -1);
11827  assert(varidx[node->data.intval] < *nexprvars);
11828  if( varidx[node->data.intval] == -1 )
11829  {
11830  varidx[node->data.intval] = *nexprvars;
11831  ++*nexprvars;
11832  }
11833 
11834  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11835  break;
11836  }
11837 
11838  case SCIP_EXPR_CONST:
11839  {
11840  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11841  break;
11842  }
11843 
11844  case SCIP_EXPR_REALPOWER:
11845  case SCIP_EXPR_SIGNPOWER:
11846  {
11847  assert(node->nchildren == 1);
11848  assert(childexprs != NULL);
11849  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11850  break;
11851  }
11852 
11853  case SCIP_EXPR_INTPOWER:
11854  {
11855  assert(node->nchildren == 1);
11856  assert(childexprs != NULL);
11857  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11858  break;
11859  }
11860 
11861  case SCIP_EXPR_PLUS:
11862  case SCIP_EXPR_MINUS:
11863  case SCIP_EXPR_MUL:
11864  case SCIP_EXPR_DIV:
11865  case SCIP_EXPR_MIN:
11866  case SCIP_EXPR_MAX:
11867  {
11868  assert(node->nchildren == 2);
11869  assert(childexprs != NULL);
11870  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11871  break;
11872  }
11873 
11874  case SCIP_EXPR_SQUARE:
11875  case SCIP_EXPR_SQRT:
11876  case SCIP_EXPR_EXP:
11877  case SCIP_EXPR_LOG:
11878  case SCIP_EXPR_SIN:
11879  case SCIP_EXPR_COS:
11880  case SCIP_EXPR_TAN:
11881  /* case SCIP_EXPR_ERF: */
11882  /* case SCIP_EXPR_ERFI: */
11883  case SCIP_EXPR_ABS:
11884  case SCIP_EXPR_SIGN:
11885  {
11886  assert(node->nchildren == 1);
11887  assert(childexprs != NULL);
11888  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11889  break;
11890  }
11891 
11892  case SCIP_EXPR_SUM:
11893  case SCIP_EXPR_PRODUCT:
11894  {
11895  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11896  break;
11897  }
11898 
11899  case SCIP_EXPR_LINEAR:
11900  {
11901  assert(node->data.data != NULL);
11902 
11903  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11904  break;
11905  }
11906 
11907  case SCIP_EXPR_QUADRATIC:
11908  {
11909  SCIP_EXPRDATA_QUADRATIC* quaddata;
11910 
11911  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11912  assert(quaddata != NULL);
11913 
11914  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11915  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11916  break;
11917  }
11918 
11919  case SCIP_EXPR_POLYNOMIAL:
11920  {
11921  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11922 
11923  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11924  assert(polynomialdata != NULL);
11925 
11926  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11927  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11928 
11929  break;
11930  }
11931 
11932  case SCIP_EXPR_USER:
11933  {
11934  SCIP_EXPRDATA_USER* exprdata;
11935  SCIP_USEREXPRDATA* userdata;
11936 
11937  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11938  assert(exprdata != NULL);
11939 
11940  if( exprdata->copydata != NULL )
11941  {
11942  SCIP_CALL( exprdata->copydata(exprgraph->blkmem, node->nchildren, exprdata->userdata, &userdata) );
11943  }
11944  else
11945  userdata = exprdata->userdata;
11946 
11947  SCIP_CALL( SCIPexprCreateUser(exprgraph->blkmem, expr, node->nchildren, childexprs,
11948  userdata, exprdata->evalcapability, exprdata->eval, exprdata->inteval, exprdata->curv, exprdata->prop, exprdata->estimate, exprdata->copydata, exprdata->freedata, exprdata->print) );
11949 
11950  break;
11951  }
11952 
11953  case SCIP_EXPR_LAST:
11954  case SCIP_EXPR_PARAM:
11955  {
11956  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11957  return SCIP_ERROR;
11958  }
11959  }
11960 
11961  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11962 
11963  return SCIP_OKAY;
11964 }
11965 
11966 /** counts how often expression graph variables are used in a subtree of the expression graph
11967  *
11968  * @note The function does not clear the array first, but only increases already existing counts.
11969  */
11970 static
11972  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11973  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11974  )
11975 {
11976  int i;
11977 
11978  assert(node != NULL);
11979  assert(varsusage != NULL);
11980 
11981  if( node->op == SCIP_EXPR_VARIDX )
11982  {
11983  ++varsusage[node->data.intval];
11984  return;
11985  }
11986 
11987  for( i = 0; i < node->nchildren; ++i )
11988  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
11989 }
11990 
11991 /** checks whether a node can be put into a component when checking block separability of an expression
11992  *
11993  * If a variable used by node is already in another component, components are merged and component number is updated.
11994  */
11995 static
11997  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
11998  int* compnr, /**< component number to assign, may be reduced if variables overlap */
11999  int nchildcomps, /**< number of entries for which childcomps have been set already */
12000  int* childcomps, /**< component numbers of children */
12001  int nvars, /**< number of variables */
12002  int* varcomps /**< component numbers of variables */
12003  )
12004 {
12005  int varidx;
12006  int i;
12007 
12008  assert(node != NULL);
12009  assert(compnr != NULL);
12010  assert(*compnr >= 0);
12011  assert(childcomps != NULL);
12012  assert(varcomps != NULL);
12013 
12014  if( node->op != SCIP_EXPR_VARIDX )
12015  {
12016  for( i = 0; i < node->nchildren; ++i )
12017  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
12018  return;
12019  }
12020 
12021  varidx = node->data.intval;
12022  assert(varidx >= 0);
12023  assert(varidx < nvars);
12024 
12025  if( varcomps[varidx] == -1 )
12026  {
12027  /* first time we get to this variable, so set it's component to compnr and we are done */
12028  varcomps[varidx] = *compnr;
12029  return;
12030  }
12031 
12032  if( varcomps[varidx] == *compnr )
12033  {
12034  /* variable is already in current component, that's also good and we are done */
12035  return;
12036  }
12037 
12038  /* variable is already in another component, so have to merge component compnr into that component
12039  * do this by updating varcomps and childcomps */
12040  for( i = 0; i < nvars; ++i )
12041  if( varcomps[i] == *compnr )
12042  varcomps[i] = varcomps[varidx];
12043  for( i = 0; i < nchildcomps; ++i )
12044  if( childcomps[i] == *compnr )
12045  childcomps[i] = varcomps[varidx];
12046  *compnr = varcomps[varidx];
12047 }
12048 
12049 /**@} */
12050 
12051 /**@name Expression graph private methods */
12052 /**@{ */
12053 
12054 /** assert that expression graph has at least a given depth */
12055 static
12057  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
12058  int mindepth /**< minimal depth that should be ensured */
12059  )
12060 {
12061  int olddepth;
12062 
12063  assert(exprgraph != NULL);
12064  assert(exprgraph->blkmem != NULL);
12065 
12066  if( mindepth <= exprgraph->depth )
12067  return SCIP_OKAY;
12068 
12069  olddepth = exprgraph->depth;
12070  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
12071  assert(exprgraph->depth >= mindepth);
12072 
12073  /* initialize new array entries to 0 and NULL, resp. */
12074  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12075  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12076  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12077 
12078  return SCIP_OKAY;
12079 }
12080 
12081 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
12082 static
12084  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12085  int varidx /**< variable index */
12086  )
12087 {
12088  SCIP_EXPRGRAPHNODE* varnode;
12089  void* var;
12090 
12091  assert(exprgraph != NULL);
12092  assert(varidx >= 0);
12093  assert(varidx < exprgraph->nvars);
12094 
12095  varnode = exprgraph->varnodes[varidx];
12096  assert(varnode->data.intval == varidx);
12097 
12098  var = exprgraph->vars[varidx];
12099 
12100  /* call varremove callback method, if set */
12101  if( exprgraph->exprgraphvarremove != NULL )
12102  {
12103  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
12104  }
12105 
12106  /* remove variable from hashmap */
12107  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
12108 
12109  /* move last variable to position varidx and give it the new index */
12110  if( varidx < exprgraph->nvars-1 )
12111  {
12112  /* call callback method, if set */
12113  if( exprgraph->exprgraphvarchgidx != NULL )
12114  {
12115  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
12116  }
12117 
12118  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
12119  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
12120  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
12121  exprgraph->varnodes[varidx]->data.intval = varidx;
12122  SCIP_CALL( SCIPhashmapSetImage(exprgraph->varidxs, exprgraph->vars[varidx], (void*)(size_t)(varidx)) );
12123  }
12124  --exprgraph->nvars;
12125 
12126  return SCIP_OKAY;
12127 }
12128 
12129 /** moves a node in an expression graph to a different depth
12130  *
12131  * New depth must be larger than children depth.
12132  * Moves parent nodes to higher depth, if needed.
12133  * Variable nodes cannot be moved.
12134  */
12135 static
12137  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12138  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
12139  int newdepth /**< new depth to which to move node */
12140  )
12141 {
12142  int olddepth;
12143  int oldpos;
12144  int i;
12145 
12146  assert(exprgraph != NULL);
12147  assert(node != NULL);
12148  assert(node->depth >= 0); /* node should be in graph */
12149  assert(newdepth >= 0);
12150 
12151  /* if already on aimed depth, then don't need to move */
12152  if( node->depth == newdepth )
12153  return SCIP_OKAY;
12154 
12155  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
12156 
12157 #ifndef NDEBUG
12158  /* assert that children are at lower depth than new depth */
12159  for( i = 0; i < node->nchildren; ++i )
12160  assert(node->children[i]->depth < newdepth);
12161 #endif
12162 
12163  /* move parents to higher depth, if needed */
12164  for( i = 0; i < node->nparents; ++i )
12165  {
12166  if( node->parents[i]->depth <= newdepth )
12167  {
12168  /* move parent to depth+1 */
12169  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
12170  assert(node->parents[i]->depth > newdepth);
12171  }
12172  }
12173 
12174  /* ensure that graph is deep enough */
12175  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
12176  assert(exprgraph->depth > newdepth);
12177 
12178  olddepth = node->depth;
12179  oldpos = node->pos;
12180 
12181  /* add node to new depth */
12182  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
12183  node->depth = newdepth;
12184  node->pos = exprgraph->nnodes[newdepth];
12185  exprgraph->nodes[newdepth][node->pos] = node;
12186  ++exprgraph->nnodes[newdepth];
12187 
12188  /* 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) */
12189  for( i = 0; i < node->nchildren; ++i )
12190  node->children[i]->parentssorted = FALSE;
12191 
12192  /* move last node at previous depth to previous position, if it wasn't last */
12193  if( oldpos < exprgraph->nnodes[olddepth]-1 )
12194  {
12195  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
12196  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
12197 
12198  /* 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) */
12199  for( i = 0; i < exprgraph->nodes[olddepth][oldpos]->nchildren; ++i )
12200  exprgraph->nodes[olddepth][oldpos]->children[i]->parentssorted = FALSE;
12201  }
12202  --exprgraph->nnodes[olddepth];
12203 
12204  if( node->depth == 0 )
12205  {
12206  /* if at depth 0, then it need to be a node for either a constant or a variable */
12207  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
12208  if( node->op == SCIP_EXPR_CONST )
12209  {
12210  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
12211  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
12212  exprgraph->constnodes[exprgraph->nconsts] = node;
12213  ++exprgraph->nconsts;
12214  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
12215  }
12216  else
12217  {
12218  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
12219  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
12220  return SCIP_ERROR;
12221  }
12222 
12223  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
12224  node->curv = SCIP_EXPRCURV_LINEAR;
12225  }
12226 
12227  return SCIP_OKAY;
12228 }
12229 
12230 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
12231 static
12233  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12234  int nchildren, /**< number of children */
12235  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
12236  SCIP_EXPROP op, /**< operator */
12237  SCIP_EXPROPDATA opdata, /**< operator data */
12238  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
12239  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
12240  )
12241 {
12242  SCIP_EXPRGRAPHNODE** parentcands;
12243  int nparentcands;
12244  int parentcandssize;
12245  int i;
12246  int p;
12247 
12248  assert(exprgraph != NULL);
12249  assert(nchildren > 0);
12250  assert(children != NULL);
12251  assert(parent != NULL);
12252 
12253  *parent = NULL;
12254 
12255  /* create initial set of parent candidates as
12256  * all parents of first child that have the same operator type and the same number of children
12257  * additionally, some easy conditions for complex expression types:
12258  * if expression type is int/real/signpower, then compare also exponent,
12259  * if expression type is linear, then compare also constant part,
12260  * if expression type is quadratic, then compare also number of quadratic elements,
12261  * if expression type is polynomial, then compare also number of monmials and constant part
12262  */
12263  parentcandssize = children[0]->nparents;
12264  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
12265  nparentcands = 0;
12266  for( p = 0; p < children[0]->nparents; ++p )
12267  if( children[0]->parents[p]->op == op &&
12268  children[0]->parents[p]->nchildren == nchildren &&
12269  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
12270  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12271  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12272  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
12273  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
12274  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
12275  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
12276  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
12277  )
12278  {
12279  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
12280  }
12281 
12282  /* for all remaining children, remove parent candidates, that are not in their list of parents */
12283  for( i = 1; i < nchildren && nparentcands > 0; ++i )
12284  {
12285  p = 0;
12286  while( p < nparentcands )
12287  {
12288  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
12289  * otherwise keep candidate and check next one
12290  */
12291  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
12292  {
12293  parentcands[p] = parentcands[nparentcands-1];
12294  --nparentcands;
12295  }
12296  else
12297  ++p;
12298  }
12299  }
12300 
12301  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
12302 
12303  if( nparentcands == 0 )
12304  {
12305  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
12306  return SCIP_OKAY;
12307  }
12308 
12309  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
12310  * check if there is also one which corresponds to same expression and store that one in *parent
12311  */
12312  switch( op )
12313  {
12314  /* commutative operands with no data */
12315  case SCIP_EXPR_PLUS :
12316  case SCIP_EXPR_MUL :
12317  case SCIP_EXPR_MIN :
12318  case SCIP_EXPR_MAX :
12319  case SCIP_EXPR_SUM :
12320  case SCIP_EXPR_PRODUCT:
12321  case SCIP_EXPR_SQUARE :
12322  case SCIP_EXPR_SQRT :
12323  case SCIP_EXPR_EXP :
12324  case SCIP_EXPR_LOG :
12325  case SCIP_EXPR_SIN :
12326  case SCIP_EXPR_COS :
12327  case SCIP_EXPR_TAN :
12328  /* case SCIP_EXPR_ERF : */
12329  /* case SCIP_EXPR_ERFI : */
12330  case SCIP_EXPR_ABS :
12331  case SCIP_EXPR_SIGN :
12332  {
12333  /* sort childnodes, if needed for later */
12334  if( nchildren > 2 )
12335  SCIPsortPtr((void**)children, exprgraphnodecomp, nchildren);
12336  for( p = 0; p < nparentcands; ++p )
12337  {
12338  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12339  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12340 
12341  if( nchildren == 1 )
12342  {
12343  assert(parentcands[p]->children[0] == children[0]);
12344  /* same operand, same child, so same expression */
12345  *parent = parentcands[p];
12346  break;
12347  }
12348  else if( nchildren == 2 )
12349  {
12350  /* We know that every node in children is also a child of parentcands[p].
12351  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
12352  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
12353  */
12354  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
12355  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
12356  {
12357  *parent = parentcands[p];
12358  break;
12359  }
12360  }
12361  else
12362  {
12363  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
12364 
12365  /* sort children of parent candidate */
12366  SCIPsortPtr((void**)parentcands[p]->children, exprgraphnodecomp, nchildren);
12367 
12368  /* check if childnodes and parentcands[p]->children are the same */
12369  for( i = 0; i < nchildren; ++i )
12370  if( children[i] != parentcands[p]->children[i] )
12371  break;
12372  if( i == nchildren )
12373  {
12374  /* yeah, found an exact match */
12375  *parent = parentcands[p];
12376  break;
12377  }
12378  }
12379  }
12380 
12381  break;
12382  }
12383 
12384  /* non-commutative operands with two children */
12385  case SCIP_EXPR_MINUS :
12386  case SCIP_EXPR_DIV :
12387  {
12388  for( p = 0; p < nparentcands; ++p )
12389  {
12390  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12391  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
12392  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
12393  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
12394  {
12395  /* yeah, found one */
12396  *parent = parentcands[p];
12397  break;
12398  }
12399  }
12400 
12401  break;
12402  }
12403 
12404  /* operands with one child and data */
12405  case SCIP_EXPR_INTPOWER:
12406  {
12407  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12408  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12409  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12410  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
12411 
12412  /* yeah, have one with same exponent */
12413  *parent = parentcands[0];
12414 
12415  break;
12416  }
12417 
12418  case SCIP_EXPR_REALPOWER:
12419  case SCIP_EXPR_SIGNPOWER:
12420  {
12421  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12422  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12423  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12424  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
12425 
12426  /* yeah, have one with same exponent */
12427  *parent = parentcands[0];
12428 
12429  break;
12430  }
12431 
12432  /* commutative operands with n children and data */
12433  case SCIP_EXPR_LINEAR:
12434  {
12435  SCIP_Real* exprcoef;
12436  SCIP_Real* candcoef;
12437 
12438  exprcoef = (SCIP_Real*)opdata.data;
12439  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
12440  if( exprchildren != NULL )
12441  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, exprgraphnodecomp, nchildren);
12442  else
12443  SCIPsortPtrReal((void**)children, exprcoef, exprgraphnodecomp, nchildren);
12444  for( p = 0; p < nparentcands; ++p )
12445  {
12446  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12447  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12448 
12449  candcoef = (SCIP_Real*)parentcands[p]->data.data;
12450  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12451 
12452  /* sort children of parent candidate */
12453  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, exprgraphnodecomp, nchildren);
12454 
12455  /* check if children and coefficients in parent candidate and expression are the same */
12456  for( i = 0; i < nchildren; ++i )
12457  {
12458  if( children[i] != parentcands[p]->children[i] )
12459  break;
12460  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
12461  break;
12462  }
12463  if( i < nchildren )
12464  continue;
12465 
12466  /* yeah, found an exact match */
12467  *parent = parentcands[p];
12468  break;
12469  }
12470 
12471  break;
12472  }
12473 
12474  case SCIP_EXPR_QUADRATIC:
12475  {
12476  SCIP_EXPRDATA_QUADRATIC* exprdata;
12477  SCIP_Real* exprlincoef;
12478  SCIP_Real* candlincoef;
12479  SCIP_EXPRDATA_QUADRATIC* canddata;
12480  int* perm;
12481  int* invperm;
12482 
12483  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
12484  exprlincoef = exprdata->lincoefs;
12485 
12486  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
12487 
12488  /* sort expr->children and childnodes and store inverse permutation in invperm */
12489  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12490  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12491  for( i = 0; i < nchildren; ++i )
12492  invperm[i] = i; /*lint !e644*/
12493 
12494  if( exprlincoef != NULL )
12495  if( exprchildren != NULL )
12496  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12497  else
12498  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12499  else
12500  if( exprchildren != NULL )
12501  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12502  else
12503  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12504 
12505  /* compute permutation from its inverse */
12506  for( i = 0; i < nchildren; ++i )
12507  perm[invperm[i]] = i; /*lint !e644*/
12508 
12509  /* apply permuation to exprdata->quadelems and sort again */
12510  for( i = 0; i < exprdata->nquadelems; ++i )
12511  {
12512  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
12513  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
12514  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
12515  {
12516  int tmp;
12517  tmp = exprdata->quadelems[i].idx1;
12518  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
12519  exprdata->quadelems[i].idx2 = tmp;
12520  }
12521  }
12522  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
12523  exprdata->sorted = TRUE;
12524 
12525  for( p = 0; p < nparentcands; ++p )
12526  {
12527  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12528  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12529 
12530  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
12531  candlincoef = canddata->lincoefs;
12532  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
12533  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12534 
12535  /* sort parentcands[p]->children and store inverse permutation in invperm */
12536  for( i = 0; i < nchildren; ++i )
12537  invperm[i] = i;
12538 
12539  if( candlincoef != NULL )
12540  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, exprgraphnodecomp, parentcands[p]->nchildren);
12541  else
12542  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12543 
12544  /* compute permutation from its inverse */
12545  for( i = 0; i < nchildren; ++i )
12546  perm[invperm[i]] = i;
12547 
12548  /* apply permutation to canddata->quadelems */
12549  for( i = 0; i < canddata->nquadelems; ++i )
12550  {
12551  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
12552  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
12553  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
12554  {
12555  int tmp;
12556  tmp = canddata->quadelems[i].idx1;
12557  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
12558  canddata->quadelems[i].idx2 = tmp;
12559  }
12560  }
12561  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
12562  canddata->sorted = TRUE;
12563 
12564  /* check if children and linear coefficients in parent candidate and expression are the same */
12565  for( i = 0; i < nchildren; ++i )
12566  {
12567  if( children[i] != parentcands[p]->children[i] )
12568  break;
12569  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
12570  break;
12571  }
12572  if( i < nchildren )
12573  continue;
12574 
12575  assert(exprdata->nquadelems == canddata->nquadelems);
12576  for( i = 0; i < exprdata->nquadelems; ++i )
12577  {
12578  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
12579  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
12580  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
12581  break;
12582  }
12583  if( i == exprdata->nquadelems )
12584  {
12585  /* yeah, parentcands[p] is same quadratic expression as expr */
12586  *parent = parentcands[p];
12587  break;
12588  }
12589  }
12590 
12591  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12592  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12593 
12594  break;
12595  }
12596 
12597  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
12598  case SCIP_EXPR_POLYNOMIAL:
12599  {
12600  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
12601  SCIP_EXPRDATA_POLYNOMIAL* canddata;
12602  int* perm;
12603  int* invperm;
12604 
12605  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
12606 
12607  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
12608 
12609  /* sort exprchildren and childnodes and store inverse permutation in invperm */
12610  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12611  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12612  for( i = 0; i < nchildren; ++i )
12613  invperm[i] = i; /*lint !e644*/
12614 
12615  if( exprchildren != NULL )
12616  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12617  else
12618  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12619 
12620  /* compute permutation from its inverse */
12621  for( i = 0; i < nchildren; ++i )
12622  perm[invperm[i]] = i; /*lint !e644*/
12623 
12624  /* apply permutation to exprdata and sort again */
12625  polynomialdataApplyChildmap(exprdata, perm);
12626  polynomialdataSortMonomials(exprdata);
12627 
12628  for( p = 0; p < nparentcands; ++p )
12629  {
12630  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12631  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12632 
12633  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
12634  assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
12635  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12636 
12637  /* sort parentcands[p]->children and store inverse permutation in invperm */
12638  for( i = 0; i < nchildren; ++i )
12639  invperm[i] = i;
12640 
12641  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12642 
12643  /* compute permutation from its inverse */
12644  for( i = 0; i < nchildren; ++i )
12645  perm[invperm[i]] = i;
12646 
12647  /* apply permutation to canddata and sort again */
12648  polynomialdataApplyChildmap(canddata, perm);
12649  polynomialdataSortMonomials(canddata);
12650 
12651  /* check if children are equal */
12652  for( i = 0; i < nchildren; ++i )
12653  if( children[i] != parentcands[p]->children[i] )
12654  break;
12655  if( i < nchildren )
12656  continue;
12657 
12658  /* check if monomials are equal */
12659  for( i = 0; i < exprdata->nmonomials; ++i )
12660  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
12661  break;
12662  if( i == exprdata->nmonomials )
12663  {
12664  /* yeah, parentcands[p] is same polynomial expression as expr */
12665  *parent = parentcands[p];
12666  break;
12667  }
12668  }
12669 
12670  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12671  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12672 
12673  break;
12674  }
12675 
12676  case SCIP_EXPR_USER:
12677  {
12678  /* @todo need comparison function on user data to decide whether a parent candidate fits */
12679  break;
12680  }
12681 
12682  case SCIP_EXPR_VARIDX:
12683  case SCIP_EXPR_PARAM:
12684  case SCIP_EXPR_CONST:
12685  case SCIP_EXPR_LAST:
12686  SCIPerrorMessage("expression operand %d unexpected here\n", op);
12687  return SCIP_ERROR;
12688  }
12689 
12690  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
12691 
12692  return SCIP_OKAY;
12693 }
12694 
12695 /** adds an expression into an expression graph
12696  *
12697  * Enables corresponding nodes.
12698  */
12699 static
12701  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12702  SCIP_EXPR* expr, /**< expression to add */
12703  void** vars, /**< variables corresponding to VARIDX expressions */
12704  SCIP_Real* params, /**< parameter values */
12705  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
12706  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12707  )
12708 {
12709  SCIP_EXPRGRAPHNODE** childnodes;
12710  SCIP_Bool childisnew;
12711  SCIP_Bool nochildisnew;
12712  SCIP_EXPROPDATA opdata;
12713  int i;
12714 
12715  assert(exprgraph != NULL);
12716  assert(expr != NULL);
12717  assert(exprnode != NULL);
12718  assert(exprnodeisnew != NULL);
12719 
12720  if( expr->op == SCIP_EXPR_VARIDX )
12721  {
12722  /* find node corresponding to variable and add if not existing yet */
12723  assert(expr->nchildren == 0);
12724 
12725  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12726  assert(*exprnode != NULL);
12727  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12728  assert((*exprnode)->data.intval >= 0);
12729  assert((*exprnode)->data.intval < exprgraph->nvars);
12730  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12731 
12732  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12733 
12734  return SCIP_OKAY;
12735  }
12736 
12737  if( expr->op == SCIP_EXPR_CONST )
12738  {
12739  /* find node corresponding to constant and add if not existing yet */
12740  assert(expr->nchildren == 0);
12741 
12742  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12743  assert(*exprnode != NULL);
12744  assert((*exprnode)->op == SCIP_EXPR_CONST);
12745  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
12746 
12747  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12748 
12749  return SCIP_OKAY;
12750  }
12751 
12752  if( expr->op == SCIP_EXPR_PARAM )
12753  {
12754  /* find node corresponding to constant corresponding to parameter and add if not existing yet */
12755  assert(expr->nchildren == 0);
12756  assert(params != NULL);
12757 
12758  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, params[expr->data.intval], exprnode) );
12759  assert(*exprnode != NULL);
12760  assert((*exprnode)->op == SCIP_EXPR_CONST);
12761  assert((*exprnode)->data.dbl == params[expr->data.intval]); /*lint !e777*/
12762 
12763  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12764 
12765  return SCIP_OKAY;
12766  }
12767 
12768  /* expression should be variable or constant or have children */
12769  assert(expr->nchildren > 0);
12770 
12771  /* add children expressions into expression graph
12772  * check if we can find a common parent
12773  */
12774  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12775  nochildisnew = TRUE;
12776  for( i = 0; i < expr->nchildren; ++i )
12777  {
12778  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, params, &childnodes[i], &childisnew) ); /*lint !e644*/
12779  assert(childnodes[i] != NULL);
12780  nochildisnew &= !childisnew; /*lint !e514*/
12781  }
12782 
12783  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12784  if( nochildisnew )
12785  {
12786  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12787 
12788  if( *exprnode != NULL )
12789  {
12790  /* node already existing, make sure it is enabled */
12791  (*exprnode)->enabled = TRUE;
12792  *exprnodeisnew = FALSE;
12793 
12794  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12795  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12796  * SCIPdebugPrintf("\n");
12797  */
12798 
12799  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12800  return SCIP_OKAY;
12801  }
12802  }
12803 
12804  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12805 
12806  /* copy expression data */
12807  if( exprOpTable[expr->op].copydata != NULL )
12808  {
12809  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12810  }
12811  else
12812  {
12813  opdata = expr->data;
12814  }
12815 
12816  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12817  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12818  *exprnodeisnew = TRUE;
12819 
12820  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12821 
12822  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12823  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12824  * SCIPdebugPrintf("\n");
12825  */
12826 
12827  return SCIP_OKAY;
12828 }
12829 
12830 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12831 static
12833  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12834  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12835  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12836  )
12837 {
12838  SCIP_EXPRGRAPHNODE* node;
12839  int i;
12840  int p;
12841 
12842  assert(exprgraph != NULL);
12843  assert(clearreverseprop != NULL);
12844  assert(boundchanged != NULL);
12845 
12846  *boundchanged = FALSE;
12847  for( i = 0; i < exprgraph->nvars; ++i )
12848  {
12849  node = exprgraph->varnodes[i];
12850 
12851  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12852  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12853  {
12855  continue;
12856  }
12857 
12858  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12859  {
12860  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12861  SCIP_Real tmp;
12862 
12863  tmp = exprgraph->varbounds[i].inf;
12864  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12865  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12866  }
12867 
12868  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12869  +exprgraph->varbounds[i].sup > node->bounds.sup )
12870  {
12871  for( p = 0; p < node->nparents; ++p )
12873 
12874  node->bounds = exprgraph->varbounds[i];
12875  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12876 
12877  *boundchanged = TRUE;
12878 
12879  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12880  *clearreverseprop = TRUE;
12881  }
12882  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12883  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12884  {
12885  for( p = 0; p < node->nparents; ++p )
12887 
12888  node->bounds = exprgraph->varbounds[i];
12889  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12890 
12891  *boundchanged = TRUE;
12892  }
12893  else
12894  {
12895  node->bounds = exprgraph->varbounds[i];
12896  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12897  }
12898 
12900  }
12901 }
12902 
12903 /**@} */
12904 
12905 /**@name Expression graph node methods */
12906 /**@{ */
12907 
12908 /* In debug mode, the following methods are implemented as function calls to ensure
12909  * type validity.
12910  * In optimized mode, the methods are implemented as defines to improve performance.
12911  * However, we want to have them in the library anyways, so we have to undef the defines.
12912  */
12913 
12914 #undef SCIPexprgraphCaptureNode
12915 #undef SCIPexprgraphIsNodeEnabled
12916 #undef SCIPexprgraphGetNodeNChildren
12917 #undef SCIPexprgraphGetNodeChildren
12918 #undef SCIPexprgraphGetNodeNParents
12919 #undef SCIPexprgraphGetNodeParents
12920 #undef SCIPexprgraphGetNodeDepth
12921 #undef SCIPexprgraphGetNodePosition
12922 #undef SCIPexprgraphGetNodeOperator
12923 #undef SCIPexprgraphGetNodeOperatorIndex
12924 #undef SCIPexprgraphGetNodeOperatorReal
12925 #undef SCIPexprgraphGetNodeVar
12926 #undef SCIPexprgraphGetNodeRealPowerExponent
12927 #undef SCIPexprgraphGetNodeIntPowerExponent
12928 #undef SCIPexprgraphGetNodeSignPowerExponent
12929 #undef SCIPexprgraphGetNodeLinearCoefs
12930 #undef SCIPexprgraphGetNodeLinearConstant
12931 #undef SCIPexprgraphGetNodeQuadraticConstant
12932 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12933 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12934 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12935 #undef SCIPexprgraphGetNodePolynomialMonomials
12936 #undef SCIPexprgraphGetNodePolynomialNMonomials
12937 #undef SCIPexprgraphGetNodePolynomialConstant
12938 #undef SCIPexprgraphGetNodeUserData
12939 #undef SCIPexprgraphHasNodeUserEstimator
12940 #undef SCIPexprgraphGetNodeBounds
12941 #undef SCIPexprgraphGetNodeVal
12942 #undef SCIPexprgraphGetNodeCurvature
12943 
12944 /** captures node, i.e., increases number of uses */
12946  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12947  )
12948 {
12949  assert(node->nuses >= 0);
12950 
12951  SCIPdebugMessage("capture node %p\n", (void*)node);
12952 
12953  ++node->nuses;
12954 }
12955 
12956 /** returns whether a node is currently enabled */
12958  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12959  )
12960 {
12961  assert(node != NULL);
12962 
12963  return node->enabled;
12964 }
12965 
12966 /** gets number of children of a node in an expression graph */
12968  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12969  )
12970 {
12971  assert(node != NULL);
12972 
12973  return node->nchildren;
12974 }
12975 
12976 /** gets children of a node in an expression graph */
12978  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12979  )
12980 {
12981  assert(node != NULL);
12982 
12983  return node->children;
12984 }
12985 
12986 /** gets number of parents of a node in an expression graph */
12988  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12989  )
12990 {
12991  assert(node != NULL);
12992 
12993  return node->nparents;
12994 }
12995 
12996 /** gets parents of a node in an expression graph */
12998  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12999  )
13000 {
13001  assert(node != NULL);
13002 
13003  return node->parents;
13004 }
13005 
13006 /** gets depth of node in expression graph */
13008  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13009  )
13010 {
13011  assert(node != NULL);
13012 
13013  return node->depth;
13014 }
13015 
13016 /** gets position of node in expression graph at its depth level */
13018  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13019  )
13020 {
13021  assert(node != NULL);
13022 
13023  return node->pos;
13024 }
13025 
13026 /** gets operator of a node in an expression graph */
13028  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13029  )
13030 {
13031  assert(node != NULL);
13032 
13033  return node->op;
13034 }
13035 
13036 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
13038  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13039  )
13040 {
13041  assert(node != NULL);
13042  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
13043 
13044  return node->data.intval;
13045 }
13046 
13047 /** gives real belonging to a SCIP_EXPR_CONST operand */
13049  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13050  )
13051 {
13052  assert(node != NULL);
13053  assert(node->op == SCIP_EXPR_CONST);
13054 
13055  return node->data.dbl;
13056 }
13057 
13058 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
13060  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13061  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13062  )
13063 {
13064  assert(exprgraph != NULL);
13065  assert(node != NULL);
13066  assert(node->op == SCIP_EXPR_VARIDX);
13067  assert(node->data.intval >= 0);
13068  assert(node->data.intval < exprgraph->nvars);
13069 
13070  return exprgraph->vars[node->data.intval];
13071 }
13072 
13073 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
13075  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13076  )
13077 {
13078  assert(node != NULL);
13079  assert(node->op == SCIP_EXPR_REALPOWER);
13080 
13081  return node->data.dbl;
13082 }
13083 
13084 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
13086  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13087  )
13088 {
13089  assert(node != NULL);
13090  assert(node->op == SCIP_EXPR_INTPOWER);
13091 
13092  return node->data.intval;
13093 }
13094 
13095 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
13097  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13098  )
13099 {
13100  assert(node != NULL);
13101  assert(node->op == SCIP_EXPR_SIGNPOWER);
13102 
13103  return node->data.dbl;
13104 }
13105 
13106 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
13108  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13109  )
13110 {
13111  assert(node != NULL);
13112  assert(node->op == SCIP_EXPR_LINEAR);
13113 
13114  return (SCIP_Real*)node->data.data;
13115 }
13116 
13117 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
13119  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13120  )
13121 {
13122  assert(node != NULL);
13123  assert(node->op == SCIP_EXPR_LINEAR);
13124  assert(node->data.data != NULL);
13125 
13126  return ((SCIP_Real*)node->data.data)[node->nchildren];
13127 }
13128 
13129 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
13131  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13132  )
13133 {
13134  assert(node != NULL);
13135  assert(node->op == SCIP_EXPR_QUADRATIC);
13136  assert(node->data.data != NULL);
13137 
13138  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
13139 }
13140 
13141 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
13143  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13144  )
13145 {
13146  assert(node != NULL);
13147  assert(node->op == SCIP_EXPR_QUADRATIC);
13148  assert(node->data.data != NULL);
13149 
13150  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
13151 }
13152 
13153 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13155  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13156  )
13157 {
13158  assert(node != NULL);
13159  assert(node->op == SCIP_EXPR_QUADRATIC);
13160  assert(node->data.data != NULL);
13161 
13162  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
13163 }
13164 
13165 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13167  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13168  )
13169 {
13170  assert(node != NULL);
13171  assert(node->op == SCIP_EXPR_QUADRATIC);
13172  assert(node->data.data != NULL);
13173 
13174  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
13175 }
13176 
13177 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13179  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13180  )
13181 {
13182  assert(node != NULL);
13183  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13184  assert(node->data.data != NULL);
13185 
13186  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
13187 }
13188 
13189 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13191  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13192  )
13193 {
13194  assert(node != NULL);
13195  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13196  assert(node->data.data != NULL);
13197 
13198  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
13199 }
13200 
13201 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
13203  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13204  )
13205 {
13206  assert(node != NULL);
13207  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13208  assert(node->data.data != NULL);
13209 
13210  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
13211 }
13212 
13213 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
13214  *
13215  * Assumes that curvature of children and bounds of children and node itself are valid.
13216  */
13218  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13219  int monomialidx, /**< index of monomial */
13220  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
13221  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
13222  )
13223 {
13224  SCIP_EXPRDATA_MONOMIAL* monomial;
13225  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13226  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13227  SCIP_INTERVAL* childbounds = NULL;
13228  SCIP_EXPRCURV* childcurv = NULL;
13229  SCIP_EXPRGRAPHNODE* child;
13230  SCIP_RETCODE retcode = SCIP_OKAY;
13231  int i;
13232 
13233  assert(node != NULL);
13234  assert(node->depth >= 0); /* node should be in graph */
13235  assert(node->pos >= 0); /* node should be in graph */
13236  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13237  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
13238  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13239  assert(node->data.data != NULL);
13240  assert(monomialidx >= 0);
13241  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
13242  assert(curv != NULL);
13243 
13244  if( SCIPintervalIsEmpty(infinity, node->bounds) )
13245  {
13246  *curv = SCIP_EXPRCURV_LINEAR;
13247  return SCIP_OKAY;
13248  }
13249 
13250  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
13251  assert(monomial != NULL);
13252 
13253  /* if many children, get large enough memory to store children bounds */
13254  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13255  {
13256  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13257  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, monomial->nfactors), TERMINATE );
13258  }
13259  else
13260  {
13261  childbounds = childboundsstatic;
13262  childcurv = childcurvstatic;
13263  }
13264 
13265  /* assemble bounds and curvature of children */
13266  for( i = 0; i < monomial->nfactors; ++i )
13267  {
13268  child = node->children[monomial->childidxs[i]];
13269  assert(child != NULL);
13270 
13271  /* child should have valid and non-empty bounds */
13272  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13273  assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13274  /* nodes at depth 0 are always linear */
13275  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13276 
13277  childbounds[i] = child->bounds; /*lint !e644*/
13278  childcurv[i] = child->curv; /*lint !e644*/
13279  }
13280 
13281  /* check curvature */
13282  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13283  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13284 
13285  /* free memory, if allocated before */
13286 TERMINATE:
13287  if( childbounds != childboundsstatic )
13288  {
13289  BMSfreeMemoryArrayNull(&childbounds);
13290  BMSfreeMemoryArrayNull(&childcurv);
13291  }
13292 
13293  return retcode;
13294 }
13295 
13296 /** gives the user data belonging to a SCIP_EXPR_USER expression */
13298  SCIP_EXPRGRAPHNODE* node
13299  )
13300 {
13301  assert(node != NULL);
13302  assert(node->op == SCIP_EXPR_USER);
13303  assert(node->data.data != NULL);
13304 
13305  return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13306 }
13307 
13308 /** indicates whether a user expression has the estimator callback defined */
13310  SCIP_EXPRGRAPHNODE* node
13311  )
13312 {
13313  assert(node != NULL);
13314  assert(node->op == SCIP_EXPR_USER);
13315  assert(node->data.data != NULL);
13316 
13317  return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13318 }
13319 
13320 /** gets bounds of a node in an expression graph */
13322  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13323  )
13324 {
13325  assert(node != NULL);
13326 
13327  return node->bounds;
13328 }
13329 
13330 /** gets value of expression associated to node from last evaluation call */
13332  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13333  )
13334 {
13335  assert(node != NULL);
13336 
13337  return node->value;
13338 }
13339 
13340 /** gets curvature of expression associated to node from last curvature check call */
13342  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13343  )
13344 {
13345  assert(node != NULL);
13346 
13347  return node->curv;
13348 }
13349 
13350 /** creates an expression graph node */
13352  BMS_BLKMEM* blkmem, /**< block memory */
13353  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13354  SCIP_EXPROP op, /**< operator type of expression */
13355  ...
13356  )
13357 {
13358  va_list ap;
13359  SCIP_EXPROPDATA opdata;
13360 
13361  assert(blkmem != NULL);
13362  assert(node != NULL);
13363 
13364  *node = NULL;
13365 
13366  switch( op )
13367  {
13368  case SCIP_EXPR_VARIDX :
13369  case SCIP_EXPR_PARAM :
13370  case SCIP_EXPR_CONST :
13371  case SCIP_EXPR_LINEAR :
13372  case SCIP_EXPR_QUADRATIC :
13373  case SCIP_EXPR_POLYNOMIAL:
13374  case SCIP_EXPR_USER :
13375  {
13376  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
13377  SCIPABORT();
13378  return SCIP_ERROR; /*lint !e527*/
13379  }
13380 
13381  /* operands without data */
13382  case SCIP_EXPR_PLUS :
13383  case SCIP_EXPR_MINUS :
13384  case SCIP_EXPR_MUL :
13385  case SCIP_EXPR_DIV :
13386  case SCIP_EXPR_MIN :
13387  case SCIP_EXPR_MAX :
13388  case SCIP_EXPR_SQUARE :
13389  case SCIP_EXPR_SQRT :
13390  case SCIP_EXPR_EXP :
13391  case SCIP_EXPR_LOG :
13392  case SCIP_EXPR_SIN :
13393  case SCIP_EXPR_COS :
13394  case SCIP_EXPR_TAN :
13395  /* case SCIP_EXPR_ERF : */
13396  /* case SCIP_EXPR_ERFI: */
13397  case SCIP_EXPR_ABS :
13398  case SCIP_EXPR_SIGN :
13399  case SCIP_EXPR_SUM :
13400  case SCIP_EXPR_PRODUCT:
13401  opdata.data = NULL;
13402  break;
13403 
13404  case SCIP_EXPR_REALPOWER:
13405  case SCIP_EXPR_SIGNPOWER:
13406  {
13407  va_start(ap, op ); /*lint !e838*/
13408  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
13409  va_end( ap ); /*lint !e826*/
13410 
13411  break;
13412  }
13413 
13414  case SCIP_EXPR_INTPOWER:
13415  {
13416  va_start(ap, op ); /*lint !e838*/
13417  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
13418  va_end( ap ); /*lint !e826*/
13419 
13420  break;
13421  }
13422 
13423  case SCIP_EXPR_LAST:
13424  SCIPABORT();
13425  return SCIP_INVALIDDATA; /*lint !e527*/
13426  }
13427 
13428  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13429 
13430  return SCIP_OKAY;
13431 }
13432 
13433 /** creates an expression graph node for a linear expression */
13435  BMS_BLKMEM* blkmem, /**< block memory */
13436  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13437  int ncoefs, /**< number of coefficients */
13438  SCIP_Real* coefs, /**< coefficients of linear expression */
13439  SCIP_Real constant /**< constant of linear expression */
13440  )
13441 {
13442  SCIP_EXPROPDATA opdata;
13443  SCIP_Real* data;
13444 
13445  assert(blkmem != NULL);
13446  assert(node != NULL);
13447 
13448  /* we store the coefficients and the constant in a single array and make this our operand data */
13449  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13450  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
13451  data[ncoefs] = constant;
13452 
13453  opdata.data = data;
13454  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13455 
13456  return SCIP_OKAY;
13457 }
13458 
13459 /** creates an expression graph node for a quadratic expression */
13461  BMS_BLKMEM* blkmem, /**< block memory */
13462  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13463  int nchildren, /**< number of children */
13464  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
13465  int nquadelems, /**< number of quadratic elements */
13466  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
13467  SCIP_Real constant /**< constant */
13468  )
13469 {
13470  SCIP_EXPROPDATA opdata;
13472 
13473  assert(blkmem != NULL);
13474  assert(node != NULL);
13475  assert(quadelems != NULL || nquadelems == 0);
13476 
13477  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13478 
13479  opdata.data = data;
13480  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13481 
13482  return SCIP_OKAY;
13483 }
13484 
13485 /** creates an expression graph node for a polynomial expression */
13487  BMS_BLKMEM* blkmem, /**< block memory */
13488  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13489  int nmonomials, /**< number of monomials */
13490  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13491  SCIP_Real constant, /**< constant of polynomial */
13492  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13493  )
13494 {
13495  SCIP_EXPROPDATA opdata;
13497 
13498  assert(blkmem != NULL);
13499  assert(node != NULL);
13500  assert(monomials != NULL || nmonomials == 0);
13501 
13502  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13503 
13504  opdata.data = data;
13505  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13506 
13507  return SCIP_OKAY;
13508 }
13509 
13510 /** adds monomials to an expression graph node that is a polynomial expression */
13512  BMS_BLKMEM* blkmem, /**< block memory */
13513  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
13514  int nmonomials, /**< number of monomials */
13515  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13516  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13517  )
13518 {
13519  assert(blkmem != NULL);
13520  assert(node != NULL);
13522  assert(monomials != NULL || nmonomials == 0);
13523 
13524  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13525 
13526  return SCIP_OKAY;
13527 }
13528 
13529 /** creates an expression graph node for a user expression */
13531  BMS_BLKMEM* blkmem, /**< block memory */
13532  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13533  SCIP_USEREXPRDATA* data, /**< user data for expression, node assumes ownership */
13534  SCIP_EXPRINTCAPABILITY evalcapability, /**< evaluation capability */
13535  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
13536  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function */
13537  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
13538  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function */
13539  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13540  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13541  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
13542  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
13543  )
13544 {
13545  SCIP_EXPROPDATA opdata;
13546  SCIP_EXPRDATA_USER* exprdata;
13547 
13548  assert(blkmem != NULL);
13549  assert(node != NULL);
13550  assert(eval != NULL);
13551  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
13552  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13553  assert(copydata != NULL || data == NULL);
13554  assert(freedata != NULL || data == NULL);
13555 
13556  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13557 
13558  exprdata->userdata = data;
13559  exprdata->evalcapability = evalcapability;
13560  exprdata->eval = eval;
13561  exprdata->estimate = estimate;
13562  exprdata->inteval = inteval;
13563  exprdata->curv = curv;
13564  exprdata->prop = prop;
13565  exprdata->copydata = copydata;
13566  exprdata->freedata = freedata;
13567  exprdata->print = print;
13568 
13569  opdata.data = (void*) exprdata;
13570 
13571  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13572 
13573  return SCIP_OKAY;
13574 }
13575 
13576 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13577  *
13578  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13579  * If the node is a linear expression, it may be freed.
13580  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13581  * It is assumed that the user had captured the node.
13582  * It is assumed that the expression graph has been simplified before.
13583  */
13585  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13586  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
13587  int linvarssize, /**< length of linvars and lincoefs arrays */
13588  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
13589  void** linvars, /**< buffer to store variables of linear part */
13590  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
13591  SCIP_Real* constant /**< buffer to store constant part */
13592  )
13593 {
13594  int orignvars;
13595  int* varsusage;
13596  SCIP_EXPRGRAPHNODE* orignode;
13597  SCIP_Bool havechange;
13598  int i;
13599 
13600  assert(exprgraph != NULL);
13601  assert(node != NULL);
13602  assert(*node != NULL);
13603  assert((*node)->nuses > 0);
13604  assert(nlinvars != NULL);
13605  assert(linvars != NULL || linvarssize == 0);
13606  assert(lincoefs != NULL || linvarssize == 0);
13607  assert(constant != NULL);
13608 
13609  *constant = 0.0;
13610  *nlinvars = 0;
13611 
13612  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13613 
13614  /* do some obvious and easy cases */
13615  switch( (*node)->op )
13616  {
13617  case SCIP_EXPR_VARIDX:
13618  {
13619  if( linvarssize >= 1 )
13620  {
13621  *nlinvars = 1;
13622  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
13623  lincoefs[0] = 1.0; /*lint !e613*/
13624 
13625  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13626  }
13627  return SCIP_OKAY;
13628  }
13629 
13630  case SCIP_EXPR_CONST:
13631  {
13632  *constant = (*node)->data.dbl;
13633  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13634 
13635  return SCIP_OKAY;
13636  }
13637 
13638  case SCIP_EXPR_REALPOWER:
13639  case SCIP_EXPR_SIGNPOWER:
13640  {
13641  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13642  {
13643  *nlinvars = 1;
13644  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13645  lincoefs[0] = 1.0; /*lint !e613*/
13646 
13647  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13648  }
13649  return SCIP_OKAY;
13650  }
13651 
13652  case SCIP_EXPR_INTPOWER:
13653  {
13654  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13655  {
13656  *nlinvars = 1;
13657  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13658  lincoefs[0] = 1.0; /*lint !e613*/
13659 
13660  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13661  }
13662  return SCIP_OKAY;
13663  }
13664 
13665  case SCIP_EXPR_PLUS:
13666  {
13667  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13668  {
13669  *constant = (*node)->children[0]->data.dbl;
13670  *nlinvars = 1;
13671  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13672  lincoefs[0] = 1.0; /*lint !e613*/
13673 
13674  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13675 
13676  return SCIP_OKAY;
13677  }
13678  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13679  {
13680  *constant = (*node)->children[1]->data.dbl;
13681  *nlinvars = 1;
13682  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13683  lincoefs[0] = 1.0; /*lint !e613*/
13684 
13685  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13686 
13687  return SCIP_OKAY;
13688  }
13689  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13690  {
13691  *nlinvars = 2;
13692  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13693  lincoefs[0] = 1.0; /*lint !e613*/
13694  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13695  lincoefs[1] = 1.0; /*lint !e613*/
13696 
13697  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13698 
13699  return SCIP_OKAY;
13700  }
13701  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13702  {
13703  /* handle this one later */
13704  break;
13705  }
13706  return SCIP_OKAY;
13707  }
13708 
13709  case SCIP_EXPR_MINUS:
13710  {
13711  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13712  {
13713  *constant = (*node)->children[0]->data.dbl;
13714  *nlinvars = 1;
13715  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13716  lincoefs[0] = -1.0; /*lint !e613*/
13717 
13718  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13719 
13720  return SCIP_OKAY;
13721  }
13722  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13723  {
13724  *constant = -(*node)->children[1]->data.dbl;
13725  *nlinvars = 1;
13726  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13727  lincoefs[0] = 1.0; /*lint !e613*/
13728 
13729  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13730 
13731  return SCIP_OKAY;
13732  }
13733  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13734  {
13735  *nlinvars = 2;
13736  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13737  lincoefs[0] = 1.0; /*lint !e613*/
13738  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13739  lincoefs[1] = -1.0; /*lint !e613*/
13740 
13741  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13742 
13743  return SCIP_OKAY;
13744  }
13745  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13746  {
13747  /* handle this one later */
13748  break;
13749  }
13750  return SCIP_OKAY;
13751  }
13752 
13753  case SCIP_EXPR_MUL:
13754  {
13755  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13756  {
13757  *nlinvars = 1;
13758  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13759  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
13760 
13761  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13762  }
13763  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13764  {
13765  *nlinvars = 1;
13766  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13767  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
13768 
13769  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13770  }
13771  return SCIP_OKAY;
13772  }
13773 
13774  case SCIP_EXPR_DIV:
13775  {
13776  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13777  return SCIP_OKAY;
13778 
13779  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13780  {
13781  *nlinvars = 1;
13782  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13783  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
13784 
13785  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13786  }
13787  return SCIP_OKAY;
13788  }
13789 
13790  case SCIP_EXPR_SQUARE:
13791  case SCIP_EXPR_SQRT:
13792  case SCIP_EXPR_EXP:
13793  case SCIP_EXPR_LOG:
13794  case SCIP_EXPR_SIN:
13795  case SCIP_EXPR_COS:
13796  case SCIP_EXPR_TAN:
13797  /* case SCIP_EXPR_ERF: */
13798  /* case SCIP_EXPR_ERFI: */
13799  case SCIP_EXPR_ABS:
13800  case SCIP_EXPR_SIGN:
13801  case SCIP_EXPR_MIN:
13802  case SCIP_EXPR_MAX:
13803  return SCIP_OKAY;
13804 
13805  case SCIP_EXPR_PRODUCT:
13806  case SCIP_EXPR_USER:
13807  return SCIP_OKAY;
13808 
13809  case SCIP_EXPR_SUM:
13810  case SCIP_EXPR_LINEAR:
13811  case SCIP_EXPR_QUADRATIC:
13812  case SCIP_EXPR_POLYNOMIAL:
13813  default:
13814  {
13815  /* check if there is a child that is a variable */
13816  for( i = 0; i < (*node)->nchildren; ++i )
13817  {
13818  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13819  break;
13820  }
13821 
13822  if( i == (*node)->nchildren )
13823  return SCIP_OKAY;
13824 
13825  break;
13826  }
13827  } /*lint !e788*/
13828 
13829  /* count how often variables are used in this expression */
13830  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13831  orignvars = exprgraph->nvars;
13832  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13833  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
13834 
13835  exprgraphNodeGetVarsUsage(*node, varsusage);
13836 
13837  /* duplicate node if it has parents or more than one user */
13838  orignode = NULL;
13839  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13840  {
13841  SCIP_EXPROPDATA data;
13842 
13843  orignode = *node;
13844 
13845  if( exprOpTable[orignode->op].copydata != NULL )
13846  {
13847  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13848  }
13849  else
13850  data = orignode->data;
13851 
13852  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13853  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13854  SCIPexprgraphCaptureNode(*node);
13855  }
13856 
13857  havechange = FALSE;
13858  /* split up constant and linear part */
13859  switch( (*node)->op )
13860  {
13861  case SCIP_EXPR_PLUS:
13862  case SCIP_EXPR_MINUS:
13863  {
13864  SCIP_EXPRGRAPHNODE* varchild;
13865  SCIP_EXPRGRAPHNODE* otherchild;
13866  int varidx;
13867 
13868  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13869  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13870  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13871  assert(linvarssize >= 1);
13872 
13873  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13874  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13875  varidx = varchild->data.intval;
13876  /* if variable is used in other child (which should be nonlinear), we don't take it */
13877  if( varsusage[varidx] > 1 )
13878  break;
13879 
13880  /* add to linear variables */
13881  *nlinvars = 1;
13882  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13883  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13884  lincoefs[0] = -1.0; /*lint !e613*/
13885  else
13886  lincoefs[0] = 1.0; /*lint !e613*/
13887 
13888  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13889  {
13890  /* replace *node by otherchild */
13891  SCIPexprgraphCaptureNode(otherchild);
13892  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13893  *node = otherchild;
13894  }
13895  else
13896  {
13897  SCIP_Real* lindata;
13898 
13899  /* turn *node into linear expression -1.0 * otherchild */
13900 
13901  /* reduce to one child */
13902  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13903  (*node)->children[0] = otherchild;
13904  (*node)->nchildren = 1;
13905  (*node)->op = SCIP_EXPR_LINEAR;
13906 
13907  /* setup linear data -1.0 * child0 + 0.0 */
13908  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13909  lindata[0] = -1.0;
13910  lindata[1] = 0.0;
13911  (*node)->data.data = (void*)lindata;
13912 
13913  /* remove *node as parent of varchild */
13914  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13915  }
13916 
13917  havechange = TRUE;
13918 
13919  break;
13920  }
13921 
13922  case SCIP_EXPR_SUM:
13923  {
13924  int nchildren;
13925 
13926  i = 0;
13927  nchildren = (*node)->nchildren;
13928  while( i < nchildren )
13929  {
13930  /* sort out constants */
13931  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13932  {
13933  *constant += (*node)->children[i]->data.dbl;
13934  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13935 
13936  if( i < nchildren-1 )
13937  {
13938  (*node)->children[i] = (*node)->children[nchildren-1];
13939  (*node)->children[nchildren-1] = NULL;
13940  }
13941  --nchildren;
13942 
13943  continue;
13944  }
13945 
13946  /* keep every child that is not a constant or variable */
13947  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13948  {
13949  ++i;
13950  continue;
13951  }
13952 
13953  /* skip variables that are used in other parts of the expression */
13954  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13955  {
13956  ++i;
13957  continue;
13958  }
13959 
13960  /* move variable into linear part, if still space */
13961  if( *nlinvars < linvarssize )
13962  {
13963  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13964  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13965  ++*nlinvars;
13966 
13967  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13968  if( i < nchildren-1 )
13969  {
13970  (*node)->children[i] = (*node)->children[nchildren-1];
13971  (*node)->children[nchildren-1] = NULL;
13972  }
13973  --nchildren;
13974 
13975  continue;
13976  }
13977  }
13978  assert(i == nchildren);
13979 
13980  if( nchildren == 0 )
13981  {
13982  /* all children were removed */
13983  havechange = TRUE;
13984  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13985  (*node)->nchildren = 0;
13986  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13987  break;
13988  }
13989 
13990  if( nchildren < (*node)->nchildren )
13991  {
13992  /* some children were removed */
13993  havechange = TRUE;
13994  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13995  (*node)->nchildren = nchildren;
13996  }
13997 
13998  if( havechange && (*node)->nchildren == 1 )
13999  {
14000  /* replace node by its child */
14001  SCIP_EXPRGRAPHNODE* child;
14002 
14003  child = (*node)->children[0];
14004  SCIPexprgraphCaptureNode(child);
14005  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14006  *node = child;
14007 
14008  break;
14009  }
14010 
14011  break;
14012  }
14013 
14014  case SCIP_EXPR_LINEAR:
14015  {
14016  int nchildren;
14017  SCIP_Real* coefs;
14018 
14019  coefs = (SCIP_Real*)(*node)->data.data;
14020  assert(coefs != NULL);
14021 
14022  /* remove constant, if nonzero */
14023  if( coefs[(*node)->nchildren] != 0.0 )
14024  {
14025  *constant = coefs[(*node)->nchildren];
14026  coefs[(*node)->nchildren] = 0.0;
14027  havechange = TRUE;
14028  }
14029 
14030  i = 0;
14031  nchildren = (*node)->nchildren;
14032  while( i < nchildren )
14033  {
14034  /* sort out constants */
14035  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
14036  {
14037  *constant += coefs[i] * (*node)->children[i]->data.dbl;
14038  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14039 
14040  if( i < nchildren-1 )
14041  {
14042  (*node)->children[i] = (*node)->children[nchildren-1];
14043  (*node)->children[nchildren-1] = NULL;
14044  coefs[i] = coefs[nchildren-1];
14045  coefs[nchildren-1] = 0.0;
14046  }
14047  --nchildren;
14048 
14049  continue;
14050  }
14051 
14052  /* keep everything that is not a constant or variable */
14053  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14054  {
14055  ++i;
14056  continue;
14057  }
14058 
14059  /* skip variables that are used in other parts of the expression */
14060  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14061  {
14062  ++i;
14063  continue;
14064  }
14065 
14066  /* move variable into linear part, if still space */
14067  if( *nlinvars < linvarssize )
14068  {
14069  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14070  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
14071  ++*nlinvars;
14072 
14073  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14074  if( i < nchildren-1 )
14075  {
14076  (*node)->children[i] = (*node)->children[nchildren-1];
14077  (*node)->children[nchildren-1] = NULL;
14078  coefs[i] = coefs[nchildren-1];
14079  coefs[nchildren-1] = 0.0;
14080  }
14081  --nchildren;
14082 
14083  continue;
14084  }
14085  }
14086  assert(i == nchildren);
14087 
14088  if( nchildren == 0 )
14089  {
14090  /* all children were removed */
14091  havechange = TRUE;
14092  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14093  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
14094  (*node)->data.data = NULL;
14095  (*node)->nchildren = 0;
14096  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
14097  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14098  break;
14099  }
14100 
14101  if( nchildren < (*node)->nchildren )
14102  {
14103  /* some children were removed */
14104  havechange = TRUE;
14105  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14106  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
14107  coefs[nchildren] = 0.0;
14108  (*node)->data.data = (void*)coefs;
14109  (*node)->nchildren = nchildren;
14110  }
14111 
14112  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
14113  {
14114  /* replace node by its child */
14115  SCIP_EXPRGRAPHNODE* child;
14116 
14117  child = (*node)->children[0];
14118  SCIPexprgraphCaptureNode(child);
14119  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14120  *node = child;
14121 
14122  break;
14123  }
14124 
14125  break;
14126  }
14127 
14128  case SCIP_EXPR_QUADRATIC:
14129  {
14130  SCIP_EXPRDATA_QUADRATIC* quaddata;
14131  SCIP_Bool* childused;
14132  int* childmap;
14133  int nchildren;
14134 
14135  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
14136  assert(quaddata != NULL);
14137 
14138  /* remove constant, if nonzero */
14139  if( quaddata->constant != 0.0 )
14140  {
14141  *constant = quaddata->constant;
14142  quaddata->constant = 0.0;
14143  havechange = TRUE;
14144  }
14145 
14146  /* if there is no linear part or no space left for linear variables, then stop */
14147  if( quaddata->lincoefs != NULL || linvarssize == 0 )
14148  break;
14149 
14150  /* check which childs are used in quadratic terms */
14151  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14152  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14153 
14154  for( i = 0; i < quaddata->nquadelems; ++i )
14155  {
14156  childused[quaddata->quadelems[i].idx1] = TRUE;
14157  childused[quaddata->quadelems[i].idx2] = TRUE;
14158  }
14159 
14160  /* alloc space for mapping of children indices */
14161  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
14162 
14163  nchildren = (*node)->nchildren;
14164  for( i = 0; i < nchildren; ++i )
14165  {
14166  childmap[i] = i; /*lint !e644*/
14167  if( *nlinvars >= linvarssize )
14168  continue;
14169  /* skip child if not variable or also used in quadratic part or other parts of expression */
14170  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14171  continue;
14172  if( childused[i] )
14173  continue;
14174  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14175  continue;
14176 
14177  /* put variable into linear part */
14178  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14179  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
14180  quaddata->lincoefs[i] = 0.0;
14181  ++*nlinvars;
14182 
14183  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14184 
14185  /* move last child to position i */
14186  if( i < nchildren-1 )
14187  {
14188  (*node)->children[i] = (*node)->children[nchildren-1];
14189  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
14190  childused[i] = childused[nchildren-1];
14191  childmap[nchildren-1] = i;
14192  }
14193  --nchildren;
14194  childmap[i] = -1;
14195 
14196  havechange = TRUE;
14197  --i; /* look at i again */
14198  }
14199 
14200  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
14201 
14202  if( nchildren < (*node)->nchildren )
14203  {
14204  /* apply childmap to quadratic term */
14205  for( i = 0; i < quaddata->nquadelems; ++i )
14206  {
14207  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
14208  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
14209  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
14210  {
14211  int tmp;
14212  tmp = quaddata->quadelems[i].idx1;
14213  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
14214  quaddata->quadelems[i].idx2 = tmp;
14215  }
14216  }
14217  quaddata->sorted = FALSE;
14218  }
14219  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
14220 
14221  if( nchildren == 0 )
14222  {
14223  /* all children were removed (so it was actually a linear expression) */
14224  havechange = TRUE;
14225  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14226  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
14227  (*node)->data.data = NULL;
14228  (*node)->nchildren = 0;
14229  (*node)->op = SCIP_EXPR_SUM;
14230  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14231  break;
14232  }
14233 
14234  if( nchildren < (*node)->nchildren )
14235  {
14236  /* reduce number of children */
14237  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14238  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
14239  (*node)->nchildren = nchildren;
14240  }
14241 
14242  break;
14243  }
14244 
14245  case SCIP_EXPR_POLYNOMIAL:
14246  {
14247  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
14248  SCIP_EXPRDATA_MONOMIAL* monomial;
14249  SCIP_Bool* childused;
14250  int childidx;
14251  int j;
14252 
14253  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
14254  assert(polynomialdata != NULL);
14255 
14256  /* make sure linear monomials are merged */
14257  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14258 
14259  /* remove constant, if nonzero */
14260  if( polynomialdata->constant != 0.0 )
14261  {
14262  *constant = polynomialdata->constant;
14263  polynomialdata->constant = 0.0;
14264  havechange = TRUE;
14265  }
14266 
14267  /* if there is no space for linear variables, then stop */
14268  if( linvarssize == 0 )
14269  break;
14270 
14271  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14272  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14273  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14274  for( i = 0; i < polynomialdata->nmonomials; ++i )
14275  {
14276  monomial = polynomialdata->monomials[i];
14277  assert(monomial != NULL);
14278  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14279  continue;
14280  for( j = 0; j < monomial->nfactors; ++j )
14281  {
14282  assert(monomial->childidxs[j] >= 0);
14283  assert(monomial->childidxs[j] < (*node)->nchildren);
14284  childused[monomial->childidxs[j]] = TRUE;
14285  }
14286  }
14287 
14288  /* move linear monomials out of polynomial */
14289  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14290  {
14291  monomial = polynomialdata->monomials[i];
14292  assert(monomial != NULL);
14293 
14294  /* sort out constants */
14295  if( monomial->nfactors == 0 )
14296  {
14297  if( monomial->coef != 0.0 )
14298  {
14299  *constant += monomial->coef;
14300  havechange = TRUE;
14301  }
14302  continue;
14303  }
14304 
14305  if( monomial->nfactors != 1 )
14306  continue;
14307  if( monomial->exponents[0] != 1.0 )
14308  continue;
14309  childidx = monomial->childidxs[0];
14310  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14311  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14312  continue;
14313  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14314  continue;
14315 
14316  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14317 
14318  /* put variable into linear part */
14319  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
14320  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
14321  ++*nlinvars;
14322 
14323  monomial->coef = 0.0;
14324  monomial->nfactors = 0;
14325  polynomialdata->sorted = FALSE;
14326 
14327  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14328  (*node)->children[childidx] = NULL;
14329 
14330  havechange = TRUE;
14331  }
14332 
14333  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14334 
14335  if( *nlinvars > 0 )
14336  {
14337  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14338  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14340  }
14341 
14342  if( (*node)->nchildren == 0 )
14343  {
14344  assert(polynomialdata->nmonomials == 0);
14345  assert(polynomialdata->constant == 0.0);
14346  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14347  havechange = TRUE;
14348  break;
14349  }
14350 
14351  break;
14352  }
14353 
14354  default: ;
14355  } /*lint !e788*/
14356 
14357  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14358 
14359  if( orignode != NULL )
14360  {
14361  /* if node was duplicated, we need to forget about original or duplicate */
14362  if( !havechange )
14363  {
14364  /* if nothing has changed, then forget about duplicate */
14365  assert(*constant == 0.0);
14366  assert(*nlinvars == 0);
14367  assert(*node != NULL);
14368  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14369  *node = orignode;
14370  }
14371  else
14372  {
14373  /* if something changed, then release original node */
14374  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14375  }
14376  }
14377  else if( havechange && *node != NULL )
14378  {
14379  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14380  (*node)->value = SCIP_INVALID;
14381  (*node)->simplified = FALSE;
14382  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14383  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14384  exprgraph->needvarboundprop = TRUE;
14385  }
14386 
14387  return SCIP_OKAY;
14388 }
14389 
14390 /** moves parents from a one node to another node
14391  *
14392  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14393  * srcnode may be freed, if not captured.
14394  * It is assumed that targetnode represents the same expression as srcnode.
14395  */
14397  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14398  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
14399  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
14400  )
14401 {
14402  assert(exprgraph != NULL);
14403  assert(srcnode != NULL);
14404  assert(*srcnode != NULL);
14405  assert(targetnode != NULL);
14406 
14407  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14408  {
14409  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14410  {
14411  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14412  }
14413  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14414  }
14415  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14416 
14417  return SCIP_OKAY;
14418 }
14419 
14420 /** releases node, i.e., decreases number of uses
14421  *
14422  * node is freed if no parents and no other uses.
14423  * Children are recursively released if they have no other parents.
14424  * Nodes that are removed are also freed.
14425  * If node correspond to a variable, then the variable is removed from the expression graph;
14426  * similarly for constants.
14427  */
14429  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14430  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
14431  )
14432 {
14433  int i;
14434 
14435  assert(exprgraph != NULL);
14436  assert(node != NULL);
14437  assert(*node != NULL);
14438  assert((*node)->depth >= 0); /* node should be in graph */
14439  assert((*node)->pos >= 0); /* node should be in graph */
14440  assert((*node)->depth < exprgraph->depth);
14441  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14442  assert((*node)->nuses >= 1);
14443  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14444 
14445  SCIPdebugMessage("release node %p\n", (void*)*node);
14446 
14447  --(*node)->nuses;
14448 
14449  /* do nothing if node still has parents or is still in use */
14450  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14451  {
14452  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);
14453  *node = NULL;
14454  return SCIP_OKAY;
14455  }
14456 
14457  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14458 
14459  /* notify children about removal of its parent
14460  * they are also freed, if possible */
14461  for( i = 0; i < (*node)->nchildren; ++i )
14462  {
14463  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14464  (*node)->children[i] = NULL;
14465  }
14466 
14467  if( (*node)->op == SCIP_EXPR_VARIDX )
14468  {
14469  assert((*node)->depth == 0);
14470  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14471  }
14472  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14473  {
14474  int constidx;
14475 
14476  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14477  assert(constidx >= 0);
14478  assert(constidx < exprgraph->nconsts);
14479  assert(exprgraph->constnodes[constidx] == *node);
14480 
14481  /* move last constant to position constidx */
14482  if( constidx < exprgraph->nconsts-1 )
14483  {
14484  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14485  exprgraph->constssorted = (exprgraph->nconsts <= 2);
14486  }
14487  --exprgraph->nconsts;
14488  }
14489  else
14490  {
14491  /* only variables and constants are allowed at depth 0 */
14492  assert((*node)->depth > 0);
14493  }
14494 
14495  /* remove node from nodes array in expression graph */
14496  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14497  {
14498  /* move last node at depth of *node to position of *node */
14499  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14500  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14501 
14502  /* moving the node may change the order in the parents array of each child */
14503  for( i = 0; i < exprgraph->nodes[(*node)->depth][(*node)->pos]->nchildren; ++i )
14504  exprgraph->nodes[(*node)->depth][(*node)->pos]->children[i]->parentssorted = FALSE;
14505  }
14506  --exprgraph->nnodes[(*node)->depth];
14507 
14508  /* node is now not in graph anymore */
14509  (*node)->depth = -1;
14510  (*node)->pos = -1;
14511 
14512  /* free node */
14513  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14514 
14515  *node = NULL;
14516 
14517  return SCIP_OKAY;
14518 }
14519 
14520 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14521 /** frees a node of an expression graph */
14523  BMS_BLKMEM* blkmem, /**< block memory */
14524  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
14525  )
14526 {
14527  assert(blkmem != NULL);
14528  assert( node != NULL);
14529  assert(*node != NULL);
14530  assert((*node)->depth == -1); /* node should not be in graph anymore */
14531  assert((*node)->pos == -1); /* node should not be in graph anymore */
14532  assert((*node)->nuses == 0); /* node should not be in use */
14533 
14534  /* free operator data, if needed */
14535  if( exprOpTable[(*node)->op].freedata != NULL )
14536  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14537 
14538  /* free arrays of children and parent nodes */
14539  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14540  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
14541 
14542  /* free node struct */
14543  BMSfreeBlockMemory(blkmem, node);
14544 }
14545 
14546 /** enables a node and recursively all its children in an expression graph */
14548  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14549  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14550  )
14551 {
14552  int i;
14553 
14554  assert(exprgraph != NULL);
14555  assert(node != NULL);
14556  assert(node->depth >= 0);
14557  assert(node->pos >= 0);
14558 
14559  if( node->enabled )
14560  return;
14561 
14562  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14563 
14564  node->enabled = TRUE;
14565  for( i = 0; i < node->nchildren; ++i )
14566  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14567 
14568  /* make sure bounds are updated in next bound propagation round */
14569  SCIPintervalSetEntire(SCIP_REAL_MAX, &node->bounds);
14570  exprgraph->needvarboundprop = TRUE;
14571 }
14572 
14573 /** disables a node and recursively all children which have no enabled parents in an expression graph */
14575  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14576  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14577  )
14578 {
14579  int i;
14580 
14581  assert(exprgraph != NULL);
14582  assert(node != NULL);
14583  assert(node->depth >= 0);
14584  assert(node->pos >= 0);
14585 
14586  if( !node->enabled )
14587  return;
14588 
14589  /* workaround: don't disable nodes if there could be more users than the one who is disabling the node
14590  * otherwise, if there are several nonlinear constraints using the same expression graph node as root node,
14591  * we might get enabled constraints with disabled node
14592  */
14593  if( node->nuses > 1 )
14594  return;
14595 
14596  /* if all parents of node are disabled, then also node can be disabled */
14597  node->enabled = FALSE;
14598  for( i = 0; i < node->nparents; ++i )
14599  if( node->parents[i]->enabled )
14600  {
14601  node->enabled = TRUE;
14602  return;
14603  }
14604 
14605  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14606 
14607  for( i = 0; i < node->nchildren; ++i )
14608  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14609 }
14610 
14611 /** returns whether the node has siblings in the expression graph */
14613  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14614  )
14615 {
14616  int p;
14617 
14618  assert(node != NULL);
14619 
14620  for( p = 0; p < node->nparents; ++p )
14621  if( node->parents[p]->nchildren > 1 )
14622  return TRUE;
14623 
14624  return FALSE;
14625 }
14626 
14627 /** returns whether all children of an expression graph node are variable nodes
14628  *
14629  * Returns TRUE for nodes without children.
14630  */
14632  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14633  )
14634 {
14635  int i;
14636 
14637  assert(node != NULL);
14638 
14639  for( i = 0; i < node->nchildren; ++i )
14640  if( node->children[i]->op != SCIP_EXPR_VARIDX )
14641  return FALSE;
14642 
14643  return TRUE;
14644 }
14645 
14646 /** returns whether the node has an ancestor which has a nonlinear expression operand */
14648  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14649  )
14650 {
14651  int p;
14652 
14653  for( p = 0; p < node->nparents; ++p )
14654  {
14655  assert(node->parents[p]->depth > node->depth);
14656  switch( node->parents[p]->op )
14657  {
14658  case SCIP_EXPR_PLUS:
14659  case SCIP_EXPR_MINUS:
14660  case SCIP_EXPR_SUM:
14661  case SCIP_EXPR_LINEAR:
14663  return TRUE;
14664  break;
14665 
14666 #ifndef NDEBUG
14667  case SCIP_EXPR_VARIDX:
14668  case SCIP_EXPR_CONST:
14669  case SCIP_EXPR_PARAM:
14670  assert(0); /* these expressions cannot have children */
14671  break;
14672 #endif
14673 
14674  default:
14675  /* parent has nonlinear expression operand */
14676  return TRUE;
14677  }/*lint !e788*/
14678  }
14679 
14680  return FALSE;
14681 }
14682 
14683 /** prints an expression graph node */
14685  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14686  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14687  FILE* file /**< file to print to, or NULL for stdout */
14688  )
14689 {
14690  assert(node != NULL);
14691 
14692  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14693 }
14694 
14695 /** tightens the bounds in a node of the graph
14696  *
14697  * Preparation for reverse propagation.
14698  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14699  */
14701  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14702  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
14703  SCIP_INTERVAL nodebounds, /**< new bounds for node */
14704  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) */
14705  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14706  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14707  )
14708 {
14709  assert(exprgraph != NULL);
14710  assert(node != NULL);
14711  assert(node->depth >= 0);
14712  assert(node->pos >= 0);
14713  assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14714  assert(cutoff != NULL);
14715 
14716  *cutoff = FALSE;
14717 
14718  /* if node is disabled, then ignore new bounds */
14719  if( !node->enabled )
14720  {
14721  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14722  return;
14723  }
14724 
14725  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14726  (void*)node, node->depth, node->pos,
14727  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14728 
14729  /* bounds in node should be valid */
14730  assert(!(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
14731 
14732  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14733  {
14734  *cutoff = TRUE;
14735  SCIPdebugPrintf(" -> cutoff\n");
14736  return;
14737  }
14738 
14739  /* if minstrength is negative, always mark that node has recently tightened bounds,
14740  * if bounds are considerably improved or tightening leads to an empty interval,
14741  * mark that node has recently tightened bounds
14742  * if bounds are only slightly improved, set the status to tightened by parent,
14743  * so next propagateVarBound round will reset the bounds
14744  */
14745  if( minstrength < 0.0 )
14746  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE;
14747  else if(
14748  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14749  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14750  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT;
14751  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14752  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT;
14753 
14754  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14755  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14756 }
14757 
14758 /** ensures that bounds and curvature information in a node is uptodate
14759  *
14760  * Assumes that bounds and curvature in children are uptodate.
14761  */
14763  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14764  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14765  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14766  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14767  )
14768 {
14769  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14770  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14771  SCIP_INTERVAL* childbounds = NULL;
14772  SCIP_EXPRCURV* childcurv = NULL;
14773  SCIP_RETCODE retcode = SCIP_OKAY;
14774  int i;
14775 
14776  assert(node != NULL);
14777  assert(node->depth >= 0); /* node should be in graph */
14778  assert(node->pos >= 0); /* node should be in graph */
14779  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14780 
14781  if( node->depth == 0 )
14782  {
14783  /* we cannot update bound tightenings in variable nodes here */
14784  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14785  return SCIP_OKAY;
14786  }
14787 
14788  assert(node->op != SCIP_EXPR_VARIDX);
14789  assert(node->op != SCIP_EXPR_PARAM);
14790 
14791  /* if many children, get large enough memory to store children bounds */
14793  {
14794  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14795  SCIP_ALLOC_TERMINATE(retcode, BMSallocMemoryArray(&childcurv, node->nchildren), TERMINATE);
14796  }
14797  else
14798  {
14799  childbounds = childboundsstatic;
14800  childcurv = childcurvstatic;
14801  }
14802 
14803  /* assemble bounds and curvature of children */
14804  for( i = 0; i < node->nchildren; ++i )
14805  {
14806  /* child should have valid and non-empty bounds */
14808  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14809  /* nodes at depth 0 are always linear */
14810  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14811 
14812  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
14813  childcurv[i] = node->children[i]->curv; /*lint !e644*/
14814  }
14815 
14816  /* if we do not have valid bounds, then update
14817  * code below is copied from exprgraphNodeUpdateBounds */
14819  {
14820  SCIP_INTERVAL newbounds;
14821 
14822  /* calling interval evaluation function for this operand */
14823  assert( exprOpTable[node->op].inteval != NULL );
14824  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds), TERMINATE );
14825 
14826  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14827  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14828  *
14829  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14830  *
14831  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14832  */
14833  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14835  {
14836  for( i = 0; i < node->nparents; ++i )
14838 
14839  node->bounds = newbounds;
14840  }
14841  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14842  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14843  {
14844  for( i = 0; i < node->nparents; ++i )
14846 
14847  node->bounds = newbounds;
14848  }
14849  else
14850  {
14851  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14852  }
14853 
14854  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);
14855 
14856  /* node now has valid bounds */
14857  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
14858  }
14859 
14860  /* update curvature */
14861  if( SCIPintervalIsEmpty(infinity, node->bounds) )
14862  {
14863  node->curv = SCIP_EXPRCURV_LINEAR;
14864 
14865  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14866  }
14867  else
14868  {
14869  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv), TERMINATE );
14870 
14871  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14872  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14873  * SCIPdebugPrintf("\n");
14874  */
14875  }
14876 TERMINATE:
14877  /* free memory, if allocated before */
14878  if( childbounds != childboundsstatic )
14879  {
14880  BMSfreeMemoryArrayNull(&childbounds);
14881  BMSfreeMemoryArrayNull(&childcurv);
14882  }
14883 
14884  return retcode;
14885 }
14886 
14887 /**@} */
14888 
14889 /**@name Expression graph methods */
14890 /**@{ */
14891 
14892 /* In debug mode, the following methods are implemented as function calls to ensure
14893  * type validity.
14894  * In optimized mode, the methods are implemented as defines to improve performance.
14895  * However, we want to have them in the library anyways, so we have to undef the defines.
14896  */
14897 
14898 #undef SCIPexprgraphGetDepth
14899 #undef SCIPexprgraphGetNNodes
14900 #undef SCIPexprgraphGetNodes
14901 #undef SCIPexprgraphGetNVars
14902 #undef SCIPexprgraphGetVars
14903 #undef SCIPexprgraphGetVarNodes
14904 #undef SCIPexprgraphSetVarNodeValue
14905 #undef SCIPexprgraphSetVarsBounds
14906 #undef SCIPexprgraphSetVarBounds
14907 #undef SCIPexprgraphSetVarNodeBounds
14908 #undef SCIPexprgraphSetVarNodeLb
14909 #undef SCIPexprgraphSetVarNodeUb
14910 #undef SCIPexprgraphGetVarsBounds
14911 
14912 /** get current maximal depth of expression graph */
14914  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14915  )
14916 {
14917  assert(exprgraph != NULL);
14918 
14919  return exprgraph->depth;
14920 }
14921 
14922 /** gets array with number of nodes at each depth of expression graph */
14924  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14925  )
14926 {
14927  assert(exprgraph != NULL);
14928 
14929  return exprgraph->nnodes;
14930 }
14931 
14932 /** gets nodes of expression graph, one array per depth */
14934  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14935  )
14936 {
14937  assert(exprgraph != NULL);
14938 
14939  return exprgraph->nodes;
14940 }
14941 
14942 /** gets number of variables in expression graph */
14944  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14945  )
14946 {
14947  assert(exprgraph != NULL);
14948 
14949  return exprgraph->nvars;
14950 }
14951 
14952 /** gets array of variables in expression graph */
14954  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14955  )
14956 {
14957  assert(exprgraph != NULL);
14958 
14959  return exprgraph->vars;
14960 }
14961 
14962 /** gets array of expression graph nodes corresponding to variables */
14964  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14965  )
14966 {
14967  assert(exprgraph != NULL);
14968 
14969  return exprgraph->varnodes;
14970 }
14971 
14972 /** sets value for a single variable given as expression graph node */
14974  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14975  SCIP_Real value /**< new value for variable */
14976  )
14977 {
14978  assert(varnode != NULL);
14979  assert(varnode->op == SCIP_EXPR_VARIDX);
14980 
14981  varnode->value = value;
14982 }
14983 
14984 /** sets bounds for variables */
14986  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14987  SCIP_INTERVAL* varbounds /**< new bounds for variables */
14988  )
14989 {
14990  assert(exprgraph != NULL);
14991  assert(varbounds != NULL || exprgraph->nvars == 0);
14992 
14993  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
14994 }
14995 
14996 /** sets bounds for a single variable */
14998  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14999  void* var, /**< variable */
15000  SCIP_INTERVAL varbounds /**< new bounds of variable */
15001  )
15002 {
15003  int pos;
15004 
15005  assert(exprgraph != NULL);
15006  assert(var != NULL);
15007  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15008 
15009  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15010  assert(pos < exprgraph->nvars);
15011  assert(exprgraph->vars[pos] == var);
15012 
15013  exprgraph->varbounds[pos] = varbounds;
15014 }
15015 
15016 /** sets bounds for a single variable given as expression graph node */
15018  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15019  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15020  SCIP_INTERVAL varbounds /**< new bounds of variable */
15021  )
15022 {
15023  int pos;
15024 
15025  assert(exprgraph != NULL);
15026  assert(varnode != NULL);
15027 
15028  pos = varnode->data.intval;
15029  assert(pos >= 0);
15030  assert(pos < exprgraph->nvars);
15031  assert(exprgraph->varnodes[pos] == varnode);
15032 
15033  exprgraph->varbounds[pos] = varbounds;
15034 }
15035 
15036 /** sets lower bound for a single variable given as expression graph node */
15038  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15039  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15040  SCIP_Real lb /**< new lower bound for variable */
15041  )
15042 {
15043  int pos;
15044 
15045  assert(exprgraph != NULL);
15046  assert(varnode != NULL);
15047 
15048  pos = varnode->data.intval;
15049  assert(pos >= 0);
15050  assert(pos < exprgraph->nvars);
15051  assert(exprgraph->varnodes[pos] == varnode);
15052 
15053  exprgraph->varbounds[pos].inf = lb;
15054 }
15055 
15056 /** sets upper bound for a single variable given as expression graph node */
15058  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15059  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15060  SCIP_Real ub /**< new upper bound for variable */
15061  )
15062 {
15063  int pos;
15064 
15065  assert(exprgraph != NULL);
15066  assert(varnode != NULL);
15067 
15068  pos = varnode->data.intval;
15069  assert(pos >= 0);
15070  assert(pos < exprgraph->nvars);
15071  assert(exprgraph->varnodes[pos] == varnode);
15072 
15073  exprgraph->varbounds[pos].sup = ub;
15074 }
15075 
15076 /** gets bounds that are stored for all variables */
15078  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
15079  )
15080 {
15081  return exprgraph->varbounds;
15082 }
15083 
15084 /** creates an empty expression graph */
15086  BMS_BLKMEM* blkmem, /**< block memory */
15087  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
15088  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
15089  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
15090  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /**< callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
15091  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /**< callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
15092  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /**< callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
15093  void* userdata /**< user data to pass to callback functions */
15094  )
15095 {
15096  assert(blkmem != NULL);
15097  assert(exprgraph != NULL);
15098 
15099  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
15100  BMSclearMemory(*exprgraph);
15101  (*exprgraph)->blkmem = blkmem;
15102 
15103  /* create nodes's arrays */
15104  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
15105  assert((*exprgraph)->depth >= 1);
15106 
15107  /* create var's arrays and hashmap */
15108  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
15109  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, (*exprgraph)->varssize) );
15110 
15111  /* empty array of constants is sorted */
15112  (*exprgraph)->constssorted = TRUE;
15113 
15114  /* store callback functions and user data */
15115  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
15116  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
15117  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
15118  (*exprgraph)->userdata = userdata;
15119 
15120  return SCIP_OKAY;
15121 }
15122 
15123 /** frees an expression graph */
15125  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
15126  )
15127 {
15128  BMS_BLKMEM* blkmem;
15129  int d;
15130 
15131  assert( exprgraph != NULL);
15132  assert(*exprgraph != NULL);
15133  assert((*exprgraph)->nvars == 0);
15134  assert((*exprgraph)->nconsts == 0);
15135 
15136  blkmem = (*exprgraph)->blkmem;
15137  assert(blkmem != NULL);
15138 
15139  /* free nodes arrays */
15140  for( d = 0; d < (*exprgraph)->depth; ++d )
15141  {
15142  assert((*exprgraph)->nnodes[d] == 0);
15143  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
15144  }
15145  assert((*exprgraph)->nodes != NULL);
15146  assert((*exprgraph)->nnodes != NULL);
15147  assert((*exprgraph)->nodessize != NULL);
15148  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
15149  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
15150  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
15151 
15152  /* free variables arrays and hashmap */
15153  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
15154  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
15155  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
15156  SCIPhashmapFree(&(*exprgraph)->varidxs);
15157 
15158  /* free constants array */
15159  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
15160 
15161  /* free graph struct */
15162  BMSfreeBlockMemory(blkmem, exprgraph);
15163 
15164  return SCIP_OKAY;
15165 }
15166 
15167 /** adds an expression graph node to an expression graph
15168  *
15169  * Expression graph assumes ownership of node.
15170  * Children are notified about new parent.
15171  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
15172  */
15174  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15175  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
15176  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
15177  int nchildren, /**< number of children */
15178  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
15179  )
15180 {
15181  SCIP_Bool childvalsvalid;
15182  int depth;
15183  int i;
15184 
15185  assert(exprgraph != NULL);
15186  assert(node != NULL);
15187  assert(node->pos < 0); /* node should have no position in graph yet */
15188  assert(node->depth < 0); /* node should have no position in graph yet */
15189  assert(node->nchildren == 0); /* node should not have stored children yet */
15190  assert(node->children == NULL); /* node should not have stored children yet */
15191  assert(node->nparents == 0); /* node should not have parents stored yet */
15192  assert(children != NULL || nchildren == 0);
15193 
15194  /* choose depth as maximal depth of children + 1, and at least mindepth */
15195  depth = MAX(0, mindepth);
15196  for( i = 0; i < nchildren; ++i )
15197  {
15198  if( children[i]->depth >= depth ) /*lint !e613*/
15199  depth = children[i]->depth + 1; /*lint !e613*/
15200  }
15201 
15202  /* ensure that expression graph is deep enough */
15203  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
15204  assert(exprgraph->depth > depth);
15205 
15206  /* ensure enough space for nodes at depth depth */
15207  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
15208 
15209  /* add node to graph */
15210  node->depth = depth;
15211  node->pos = exprgraph->nnodes[depth];
15212  exprgraph->nodes[depth][node->pos] = node;
15213  ++exprgraph->nnodes[depth];
15214 
15215  /* add as parent to children
15216  * and check if children has valid values */
15217  childvalsvalid = TRUE;
15218  for( i = 0; i < nchildren; ++i )
15219  {
15220  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
15221  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
15222  }
15223  /* store children */
15224  if( nchildren > 0 )
15225  {
15226  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
15227  node->nchildren = nchildren;
15228  }
15229 
15230  if( node->op == SCIP_EXPR_CONST )
15231  {
15232  /* set bounds to constant value of node */
15234  SCIPintervalSet(&node->bounds, node->data.dbl);
15235  }
15236  else
15237  {
15238  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
15241  exprgraph->needvarboundprop = TRUE;
15242  }
15243 
15244  /* if not a variable, set value of node according to values of children (if all have valid values) */
15245  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
15246  {
15247  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15248  }
15249 
15250  return SCIP_OKAY;
15251 }
15252 
15253 /** adds variables to an expression graph, if not existing yet
15254  *
15255  * Also already existing nodes are enabled.
15256  */
15258  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15259  int nvars, /**< number of variables to add */
15260  void** vars, /**< variables to add */
15261  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
15262  )
15263 {
15264  SCIP_EXPRGRAPHNODE* node;
15265  SCIP_EXPROPDATA opdata;
15266  int i;
15267 
15268  assert(exprgraph != NULL);
15269  assert(exprgraph->depth >= 1);
15270  assert(vars != NULL || nvars == 0);
15271 
15272  /* 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 */
15273  if( exprgraph->nvars == 0 )
15274  {
15275  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15276  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15277  }
15278 
15279  for( i = 0; i < nvars; ++i )
15280  {
15281  /* skip variables that exist already */
15282  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15283  {
15284  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
15285  assert(node != NULL);
15286 
15287  /* enable node */
15288  node->enabled = TRUE;
15289 
15290  if( varnodes != NULL )
15291  varnodes[i] = node;
15292 
15293  continue;
15294  }
15295 
15296  /* create new variable expression */
15297  opdata.intval = exprgraph->nvars;
15298  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15299 
15300  /* add expression node to expression graph at depth 0 */
15301  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15302 
15303  /* add variable node to vars arrays and hashmap */
15304  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15305  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
15306  exprgraph->varnodes[exprgraph->nvars] = node;
15307  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15308  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[i], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15309  ++exprgraph->nvars;
15310 
15311  if( varnodes != NULL )
15312  varnodes[i] = node;
15313 
15314  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15315 
15316  /* call callback method, if set */
15317  if( exprgraph->exprgraphvaradded != NULL )
15318  {
15319  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
15320  }
15321  }
15322 
15323  return SCIP_OKAY;
15324 }
15325 
15326 /** adds a constant to an expression graph, if not existing yet
15327  *
15328  * Also already existing nodes are enabled.
15329  */
15331  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15332  SCIP_Real constant, /**< constant to add */
15333  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
15334  )
15335 {
15336  SCIP_EXPROPDATA opdata;
15337 
15338  assert(exprgraph != NULL);
15339  assert(constnode != NULL);
15340 
15341  /* check if there is already an expression for this constant */
15342  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15343  {
15344  assert(*constnode != NULL);
15345  assert((*constnode)->op == SCIP_EXPR_CONST);
15346  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15347  (*constnode)->enabled = TRUE;
15348  return SCIP_OKAY;
15349  }
15350 
15351  /* create new node for constant */
15352  opdata.dbl = constant;
15353  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15354 
15355  /* add node to expression graph at depth 0 */
15356  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15357  assert((*constnode)->depth == 0);
15358  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
15359 
15360  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15361  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15362  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15363  ++exprgraph->nconsts;
15364  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15365 
15366  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15367 
15368  return SCIP_OKAY;
15369 }
15370 
15371 /** adds sum of expression trees into expression graph
15372  *
15373  * node will also be captured.
15374  *
15375  * @note Parameters will be converted into constants
15376  */
15378  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15379  int nexprtrees, /**< number of expression trees to add */
15380  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
15381  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
15382  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
15383  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) */
15384  )
15385 {
15386  SCIP_Bool allone;
15387 
15388  assert(exprgraph != NULL);
15389  assert(nexprtrees > 0);
15390  assert(exprtrees != NULL);
15391  assert(rootnode != NULL);
15392  assert(rootnodeisnew != NULL);
15393 
15394  *rootnode = NULL;
15395 
15396  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15397  {
15398  assert(exprtrees[0] != NULL);
15399  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15400 
15401  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, exprtrees[0]->params, rootnode, rootnodeisnew) );
15402  }
15403  else
15404  {
15405  SCIP_EXPROP op;
15406  SCIP_EXPRGRAPHNODE** rootnodes;
15407  SCIP_Bool rootnodeisnew_;
15408  int i;
15409 
15410  *rootnodeisnew = TRUE;
15411  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15412 
15413  allone = TRUE;
15414  for( i = 0; i < nexprtrees; ++i )
15415  {
15416  assert(exprtrees[i] != NULL);
15417  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15418 
15419  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, exprtrees[i]->params, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
15420  assert(rootnodes[i] != NULL);
15421  *rootnodeisnew &= rootnodeisnew_;
15422 
15423  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
15424  }
15425 
15426  /* decide which operand we want to use for the root node */
15427  if( coefs == NULL || allone )
15428  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15429  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15430  op = SCIP_EXPR_MINUS;
15431  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15432  {
15433  SCIP_EXPRGRAPHNODE* tmp;
15434 
15435  tmp = rootnodes[0];
15436  rootnodes[0] = rootnodes[1];
15437  rootnodes[1] = tmp;
15438  op = SCIP_EXPR_MINUS;
15439  }
15440  else
15441  op = SCIP_EXPR_LINEAR;
15442 
15443  if( op != SCIP_EXPR_LINEAR )
15444  {
15445  SCIP_EXPROPDATA data;
15446  data.data = NULL;
15447 
15448  if( !*rootnodeisnew )
15449  {
15450  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15451  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15452  }
15453 
15454  if( *rootnode == NULL )
15455  {
15456  /* create new node for sum of rootnodes and add to exprgraph */
15457  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15458  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15459  *rootnodeisnew = TRUE;
15460  }
15461  else
15462  {
15463  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15464  *rootnodeisnew = FALSE;
15465  }
15466  }
15467  else
15468  {
15469  SCIP_EXPROPDATA data;
15470  SCIP_Real* lindata;
15471 
15472  assert(op == SCIP_EXPR_LINEAR);
15473 
15474  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15475  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15476  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
15477  lindata[nexprtrees] = 0.0;
15478  data.data = lindata;
15479 
15480  if( !*rootnodeisnew )
15481  {
15482  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15483  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15484  }
15485 
15486  if( *rootnode == NULL )
15487  {
15488  /* create new node for linear combination of rootnodes and add to exprgraph */
15489  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15490  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15491  *rootnodeisnew = TRUE;
15492  }
15493  else
15494  {
15495  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15496  *rootnodeisnew = FALSE;
15497  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15498  }
15499  }
15500 
15501  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15502  }
15503  assert(*rootnode != NULL);
15504 
15505  SCIPexprgraphCaptureNode(*rootnode);
15506 
15507  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15508  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15509 
15510  return SCIP_OKAY;
15511 }
15512 
15513 /** replaces variable in expression graph by a linear sum of variables
15514  *
15515  * Variables will be added if not in the graph yet.
15516  */
15518  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15519  void* var, /**< variable to replace */
15520  int ncoefs, /**< number of coefficients in linear term */
15521  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
15522  void** vars, /**< variables in linear term */
15523  SCIP_Real constant /**< constant offset */
15524  )
15525 {
15526  SCIP_EXPRGRAPHNODE* varnode;
15527  SCIP_Real* lindata;
15528  int varidx;
15529  int i;
15530 
15531  assert(exprgraph != NULL);
15532  assert(var != NULL);
15533  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15534  assert(coefs != NULL || ncoefs == 0);
15535  assert(vars != NULL || ncoefs == 0);
15536 
15537  varidx = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15538  assert(varidx < exprgraph->nvars);
15539  assert(exprgraph->vars[varidx] == var);
15540  varnode = exprgraph->varnodes[varidx];
15541  assert(varnode != NULL);
15542  assert(varnode->data.intval == varidx);
15543 
15544  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
15545  {
15546  /* variable is replaced by constant or variable */
15547  SCIP_EXPRGRAPHNODE* node;
15548 
15549  /* check if there is already a node for this constant or variable */
15550  node = NULL;
15551  if( ncoefs == 0 )
15552  {
15553  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15554  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
15555  }
15556  else
15557  {
15558  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
15559  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
15560  }
15561 
15562  if( node != NULL )
15563  {
15564  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15565 
15566  /* tell parents of varnode to replace child varnode by node, this may free varnode */
15567  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15568 
15569  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15570  if( varnode != NULL )
15571  {
15572  assert(varnode->nuses > 0);
15573  assert(varnode->nparents == 0);
15574 
15575  /* remove variable (but don't free it's node) from graph */
15576  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15577 
15578  /* move varnode up to depth 1 */
15579  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15580 
15581  /* turn into EXPR_SUM expression */
15582  varnode->op = SCIP_EXPR_SUM;
15583  varnode->data.data = NULL;
15584  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
15585  varnode->children[0] = node;
15586  varnode->nchildren = 1;
15587  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15588 
15589  varnode->value = node->value;
15590  varnode->bounds = node->bounds;
15591  varnode->boundstatus = (node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID) ? SCIP_EXPRBOUNDSTATUS_VALID : SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
15592  }
15593  }
15594  else if( ncoefs == 0 )
15595  {
15596  /* turn node into EXPR_CONST node */
15597 
15598  /* remove variable (but don't free it's node) from graph */
15599  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15600 
15601  /* convert into EXPR_CONST node */
15602  varnode->op = SCIP_EXPR_CONST;
15603  varnode->data.dbl = constant;
15604 
15605  varnode->value = constant;
15606  SCIPintervalSet(&varnode->bounds, constant);
15608 
15609  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15610  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15611  exprgraph->constnodes[exprgraph->nconsts] = varnode;
15612  ++exprgraph->nconsts;
15613  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15614  }
15615  else
15616  {
15617  /* turn node into EXPR_VARIDX node for new variable */
15618 
15619  /* remove variable (but don't free it's node) from graph */
15620  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15621 
15622  varnode->data.intval = exprgraph->nvars;
15623 
15624  /* add variable node to vars arrays and hashmap */
15625  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15626  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
15627  exprgraph->varnodes[exprgraph->nvars] = varnode;
15628  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15629  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[0], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15630  ++exprgraph->nvars;
15631 
15632  /* call callback method, if set */
15633  if( exprgraph->exprgraphvaradded != NULL )
15634  {
15635  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
15636  }
15637  }
15638 
15639  /* mark varnode and its parents as not simplified */
15640  if( varnode != NULL )
15641  {
15642  varnode->simplified = FALSE;
15643  for( i = 0; i < varnode->nparents; ++i )
15644  varnode->parents[i]->simplified = FALSE;
15645  }
15646 
15647  return SCIP_OKAY;
15648  }
15649 
15650  /* turn varnode into EXPR_LINEAR */
15651 
15652  /* remove variable (but don't free it's node) from graph */
15653  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15654 
15655  /* move varnode up to depth 1 */
15656  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15657 
15658  /* convert into EXPR_LINEAR node */
15659  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15660  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
15661  lindata[ncoefs] = constant;
15662  varnode->data.data = (void*)lindata;
15663  varnode->op = SCIP_EXPR_LINEAR;
15664 
15665  /* add nodes corresponding to vars to expression graph, if not existing yet */
15666  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15667  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15668  varnode->nchildren = ncoefs;
15669 
15670  /* notify vars about new parent varnode */
15671  for( i = 0; i < ncoefs; ++i )
15672  {
15673  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15674  }
15675 
15676  /* set value and bounds to invalid, curvature can remain (still linear) */
15677  varnode->value = SCIP_INVALID;
15679 
15680  /* mark varnode and its parents as not simplified */
15681  varnode->simplified = FALSE;
15682  for( i = 0; i < varnode->nparents; ++i )
15683  varnode->parents[i]->simplified = FALSE;
15684 
15685  return SCIP_OKAY;
15686 }
15687 
15688 /** finds expression graph node corresponding to a variable */
15690  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15691  void* var, /**< variable to search for */
15692  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15693  )
15694 {
15695  int pos;
15696 
15697  assert(exprgraph != NULL);
15698  assert(var != NULL);
15699  assert(varnode != NULL);
15700 
15701  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15702  {
15703  *varnode = NULL;
15704  return FALSE;
15705  }
15706 
15707  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15708  assert(pos < exprgraph->nvars);
15709 
15710  *varnode = exprgraph->varnodes[pos];
15711  assert(*varnode != NULL);
15712  assert((*varnode)->op == SCIP_EXPR_VARIDX);
15713 
15714  return TRUE;
15715 }
15716 
15717 /** finds expression graph node corresponding to a constant */
15719  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15720  SCIP_Real constant, /**< constant to search for */
15721  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15722  )
15723 {
15724  int left;
15725  int right;
15726  int middle;
15727 
15728  assert(exprgraph != NULL);
15729  assert(constnode != NULL);
15730  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
15731 
15732  exprgraphSortConstNodes(exprgraph);
15733  assert(exprgraph->constssorted);
15734 
15735  /* find node using binary search */
15736  left = 0;
15737  right = exprgraph->nconsts-1;
15738  *constnode = NULL;
15739 
15740  while( left <= right )
15741  {
15742  middle = (left+right)/2;
15743  assert(0 <= middle && middle < exprgraph->nconsts);
15744 
15745  if( constant < exprgraph->constnodes[middle]->data.dbl )
15746  right = middle - 1;
15747  else if( constant > exprgraph->constnodes[middle]->data.dbl )
15748  left = middle + 1;
15749  else
15750  {
15751  *constnode = exprgraph->constnodes[middle];
15752  break;
15753  }
15754  }
15755  if( left == right+1 )
15756  return FALSE;
15757 
15758  assert(*constnode != NULL);
15759  assert((*constnode)->op == SCIP_EXPR_CONST);
15760  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15761 
15762  return TRUE;
15763 }
15764 
15765 /** prints an expression graph in dot format */
15767  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15768  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15769  FILE* file, /**< file to print to, or NULL for stdout */
15770  const char** varnames /**< variable names, or NULL for generic names */
15771  )
15772 {
15773  int d;
15774  int i;
15775 
15776  assert(exprgraph != NULL);
15777 
15778  if( file == NULL )
15779  file = stdout;
15780 
15781  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15782  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15783 
15784  for( d = 0; d < exprgraph->depth; ++d )
15785  {
15786  if( exprgraph->nnodes[d] == 0 )
15787  continue;
15788 
15789  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15790  {
15791  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15792  }
15793  }
15794 
15795  /* tell dot that all nodes of depth 0 have the same rank */
15796  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15797  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15798  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15799  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15800 
15801  /* tell dot that all nodes without parent have the same rank */
15802  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15803  for( d = 0; d < exprgraph->depth; ++d )
15804  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15805  if( exprgraph->nodes[d][i]->nparents == 0 )
15806  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15807  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15808 
15809  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15810 
15811  return SCIP_OKAY;
15812 }
15813 
15814 /** evaluates nodes of expression graph for given values of variables */
15816  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15817  SCIP_Real* varvals /**< values for variables */
15818  )
15819 {
15820  int d;
15821  int i;
15822 
15823  assert(exprgraph != NULL);
15824  assert(varvals != NULL || exprgraph->nvars == 0);
15825 
15826  for( d = 0; d < exprgraph->depth; ++d )
15827  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15828  {
15829  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15830  }
15831 
15832  return SCIP_OKAY;
15833 }
15834 
15835 /** propagates bound changes in variables forward through the expression graph */
15837  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15838  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15839  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
15840  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15841  )
15842 {
15843  SCIP_EXPRGRAPHNODE* node;
15844  SCIP_Bool boundchanged;
15845  int d;
15846  int i;
15847 
15848  assert(exprgraph != NULL);
15849  assert(domainerror != NULL);
15850 
15851  *domainerror = FALSE;
15852 
15853  /* update bounds in varnodes of expression graph */
15854  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15855 
15856  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15857  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15858  {
15859  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15860  return SCIP_OKAY;
15861  }
15862 
15863  /* propagate bound changes, interrupt if we get to a node with empty bounds */
15864  for( d = 1; d < exprgraph->depth; ++d )
15865  {
15866  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15867  {
15868  node = exprgraph->nodes[d][i];
15869  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15870  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15871  {
15872  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15873  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15874  *domainerror = TRUE;
15875  return SCIP_OKAY;
15876  }
15877  }
15878  }
15879 
15880  exprgraph->needvarboundprop = FALSE;
15881 
15882  return SCIP_OKAY;
15883 }
15884 
15885 /** propagates bound changes in nodes backward through the graph
15886  *
15887  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15888  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15889  */
15891  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15892  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15893  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15894  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15895  )
15896 {
15897  SCIP_EXPRGRAPHNODE* node;
15898  int d;
15899  int i;
15900 
15901  assert(exprgraph != NULL);
15902  assert(cutoff != NULL);
15903 
15904  *cutoff = FALSE;
15905 
15906  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15907  {
15908  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15909  {
15910  node = exprgraph->nodes[d][i];
15911  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15912  }
15913  }
15914  if( *cutoff )
15915  return;
15916 }
15917 
15918 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15919  *
15920  * Implies update of bounds in expression graph.
15921  */
15923  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15924  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15925  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15926  )
15927 {
15928  SCIP_EXPRGRAPHNODE* node;
15929  SCIP_Bool boundchanged;
15930  int d;
15931  int i;
15932 
15933  assert(exprgraph != NULL);
15934 
15935  /* update bounds in varnodes of expression graph */
15936  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15937 
15938 #ifndef NDEBUG
15939  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15940  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15941 #endif
15942 
15943  for( d = 1; d < exprgraph->depth; ++d )
15944  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15945  {
15946  node = exprgraph->nodes[d][i];
15947  assert(node != NULL);
15948 
15949  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15950 
15951  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15952  {
15953  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15954  return SCIP_OKAY;
15955  }
15956  }
15957 
15958  return SCIP_OKAY;
15959 }
15960 
15961 /** aims at simplifying an expression graph
15962  *
15963  * 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)).
15964  */
15966  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15967  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15968  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15969  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15970  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15971  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15972  )
15973 {
15974  SCIP_EXPRGRAPHNODE* node;
15975  SCIP_Bool havechangenode;
15976  SCIP_Bool allsimplified;
15977  int d;
15978  int i;
15979  int j;
15980 
15981 #ifndef NDEBUG
15982  SCIP_Real* testx;
15983  SCIP_HASHMAP* testvalidx;
15984  SCIP_Real* testvals;
15985  SCIP_RANDNUMGEN* randnumgen;
15986  int testvalssize;
15987  int ntestvals;
15988 #endif
15989 
15990  assert(exprgraph != NULL);
15991  assert(eps >= 0.0);
15992  assert(havechange != NULL);
15993  assert(domainerror != NULL);
15994 
15995 #ifndef NDEBUG
15996  SCIP_CALL( SCIPrandomCreate(&randnumgen, exprgraph->blkmem, 862) ); /* see also #1848 */
15997  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
15998  testvals = NULL;
15999  ntestvals = 0;
16000  testvalssize = 0;
16001 
16002  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
16003  for( i = 0; i < exprgraph->nvars; ++i )
16004  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
16005  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
16006  for( d = 1; d < exprgraph->depth; ++d )
16007  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16008  {
16009  node = exprgraph->nodes[d][i];
16010  assert(node != NULL);
16011 
16012  /* 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 */
16013  if( node->nuses > 0 )
16014  {
16015  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
16016  SCIP_CALL( SCIPhashmapInsert(testvalidx, (void*)node, (void*)(size_t)ntestvals) );
16017  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
16018  ++ntestvals;
16019  }
16020  }
16021 
16022  SCIPrandomFree(&randnumgen, exprgraph->blkmem);
16023 #endif
16024 
16025 #ifdef SCIP_OUTPUT
16026  {
16027  FILE* file;
16028  file = fopen("exprgraph_beforesimplify.dot", "w");
16029  if( file != NULL )
16030  {
16031  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16032  fclose(file);
16033  }
16034  }
16035 #endif
16036 
16037  *havechange = FALSE; /* we have not changed any node yet */
16038  *domainerror = FALSE; /* no domain errors encountered so far */
16039  allsimplified = TRUE; /* all nodes we looked at are simplified */
16040 
16041  /* call node simplifier from bottom up
16042  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
16043  */
16044  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
16045  {
16046  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16047  {
16048  node = exprgraph->nodes[d][i];
16049  assert(node != NULL);
16050 
16051  havechangenode = FALSE; /* node did not change yet */
16052 
16053  if( node->op != SCIP_EXPR_CONST )
16054  {
16055  /* skip nodes that are already simplified */
16056  if( node->simplified )
16057  continue;
16058 
16059  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
16060 
16061  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
16062  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
16063  assert(node->simplified == TRUE);
16064  *havechange |= havechangenode;
16065  }
16066 
16067  /* if node was or has been converted into constant, may move to depth 0 */
16068  if( node->op == SCIP_EXPR_CONST )
16069  {
16070  SCIP_EXPRGRAPHNODE* constnode;
16071 
16072  if( !SCIPisFinite(node->value) ) /*lint !e777*/
16073  {
16074  SCIPdebugMessage("Expression graph simplify turned node into NaN or inf.\n");
16075  *domainerror = TRUE;
16076  break;
16077  }
16078 
16079  /* check if there is already a node for this constant */
16080  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
16081  {
16082  assert(constnode->op == SCIP_EXPR_CONST);
16083  assert(constnode->data.dbl == node->value); /*lint !e777*/
16084 
16085  if( node->nparents > 0 )
16086  {
16087  /* move parents of this node to constnode, node may be freed if not in use */
16088  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
16089  /* node should have no parents anymore, so it should have been freed if not in use */
16090  assert(node == NULL || node->nuses > 0);
16091  havechangenode = TRUE;
16092 
16093  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
16094  if( node == NULL )
16095  {
16096  --i;
16097  continue;
16098  }
16099  }
16100  assert(node != NULL);
16101  assert(node->nuses > 0);
16102 
16103  if( constnode->nuses == 0 )
16104  {
16105  /* move node to depth 0, adding it to constnodes */
16106  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16107 
16108  /* move parents of constnode to node, so constnode is freed */
16109  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
16110  assert(constnode == NULL);
16111  havechangenode = TRUE;
16112 
16113  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16114  --i;
16115  continue;
16116  }
16117  }
16118  else
16119  {
16120  /* move to depth 0, adding it to constnodes */
16121  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16122 
16123  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16124  --i;
16125  }
16126  }
16127 
16128  /* if there was a change, mark parents as not simplified */
16129  if( havechangenode )
16130  for( j = 0; j < node->nparents; ++j )
16131  node->parents[j]->simplified = FALSE;
16132  }
16133  } /*lint !e850*/
16134 
16135  /* if we did nothing, clean up and escape from here */
16136  if( allsimplified || *domainerror )
16137  goto EXPRGRAPHSIMPLIFY_CLEANUP;
16138 
16139  /* @todo find duplicate subexpressions in expression graph */
16140 
16141  /* unconvert polynomials into simpler expressions, where possible */
16142  for( d = 1; d < exprgraph->depth; ++d )
16143  {
16144  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16145  {
16146  node = exprgraph->nodes[d][i];
16147  assert(node != NULL);
16148 
16149  if( node->op != SCIP_EXPR_POLYNOMIAL )
16150  continue;
16151 
16152  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
16153 
16154  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
16155  {
16156  /* node is identity w.r.t only child
16157  * replace node as child of parents by child of node
16158  */
16159 
16160  for( j = 0; node != NULL && j < node->nparents; ++j )
16161  {
16162  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
16163  }
16164  /* node should have no parents anymore, so it should have been freed if not in use */
16165  assert(node == NULL || node->nuses > 0);
16166 
16167  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
16168  if( node == NULL )
16169  --i;
16170  }
16171  }
16172  } /*lint !e850*/
16173 
16174 #ifdef SCIP_OUTPUT
16175  {
16176  FILE* file;
16177  file = fopen("exprgraph_aftersimplify.dot", "w");
16178  if( file != NULL )
16179  {
16180  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16181  fclose(file);
16182  }
16183  }
16184 #endif
16185 
16186 #ifndef NDEBUG
16187  for( d = 1; d < exprgraph->depth; ++d )
16188  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16189  {
16190  int idx;
16191  SCIP_Real testval_before;
16192  SCIP_Real testval_after;
16193 
16194  node = exprgraph->nodes[d][i];
16195  assert(node != NULL);
16196 
16197  SCIP_CALL( exprgraphNodeEval(node, NULL) );
16198 
16199  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
16200  if( node->nuses > 0 )
16201  {
16202  assert(SCIPhashmapExists(testvalidx, (void*)node));
16203 
16204  idx = (int)(size_t)(void*)SCIPhashmapGetImage(testvalidx, (void*)node);
16205  assert(idx < ntestvals);
16206 
16207  testval_before = testvals[idx]; /*lint !e613*/
16208  testval_after = SCIPexprgraphGetNodeVal(node);
16209 
16210  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
16211  }
16212  }
16213 #endif
16214 
16215  EXPRGRAPHSIMPLIFY_CLEANUP:
16216 #ifndef NDEBUG
16217  BMSfreeMemoryArray(&testx);
16218  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
16219  SCIPhashmapFree(&testvalidx);
16220 #endif
16221 
16222  return SCIP_OKAY;
16223 }
16224 
16225 /** creates an expression tree from a given node in an expression graph */
16227  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16228  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
16229  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
16230  )
16231 {
16232  SCIP_EXPR* root;
16233  int nexprvars;
16234  int* varidx;
16235  int i;
16236 
16237  assert(exprgraph != NULL);
16238  assert(rootnode != NULL);
16239  assert(rootnode->depth >= 0);
16240  assert(rootnode->pos >= 0);
16241  assert(exprtree != NULL);
16242 
16243  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16244  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16245 
16246  /* initially, no variable appears in the expression tree */
16247  for( i = 0; i < exprgraph->nvars; ++i )
16248  varidx[i] = -1; /*lint !e644*/
16249  nexprvars = 0;
16250 
16251  /* create expression from the subgraph that has rootnode as root */
16252  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
16253 
16254  /* create expression tree for this expression */
16255  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
16256 
16257  /* copy variables into expression tree */
16258  if( nexprvars > 0 )
16259  {
16260  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
16261  for( i = 0; i < exprgraph->nvars; ++i )
16262  {
16263  assert(varidx[i] >= -1);
16264  assert(varidx[i] < nexprvars);
16265  if( varidx[i] >= 0 )
16266  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
16267  }
16268  }
16269 
16270  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16271 
16272  return SCIP_OKAY;
16273 }
16274 
16275 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16276  *
16277  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16278  */
16280  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16281  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16282  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16283  int* nexprtrees, /**< buffer to store number of expression trees */
16284  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16285  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16286  )
16287 {
16288  int ncomponents;
16289  int* childcomp;
16290  int* varcomp;
16291  int compnr;
16292  SCIP_Bool haveoverlap;
16293  int i;
16294  int j;
16295  int k;
16296 
16297  SCIP_EXPR** exprs;
16298  int nexprs;
16299  int* childmap;
16300  int* childmapinv;
16301  int* varidx;
16302  int nexprvars;
16303 
16304  assert(exprgraph != NULL);
16305  assert(node != NULL);
16306  assert(node->depth >= 0);
16307  assert(node->pos >= 0);
16308  assert(exprtreessize > 0);
16309  assert(nexprtrees != NULL);
16310  assert(exprtrees != NULL);
16311  assert(exprtreecoefs != NULL);
16312 
16313  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16314  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16315  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16316  ( node->op != SCIP_EXPR_PLUS &&
16317  node->op != SCIP_EXPR_MINUS &&
16318  node->op != SCIP_EXPR_SUM &&
16319  node->op != SCIP_EXPR_LINEAR &&
16320  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16321  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16322  {
16323  *nexprtrees = 1;
16324  exprtreecoefs[0] = 1.0;
16325  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16326 
16327  return SCIP_OKAY;
16328  }
16329 
16330  /* find components in node->children <-> variables graph */
16331  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16332  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16333  for( i = 0; i < exprgraph->nvars; ++i )
16334  varcomp[i] = -1; /*lint !e644*/
16335 
16336  haveoverlap = FALSE;
16337  for( i = 0; i < node->nchildren; ++i )
16338  {
16339  compnr = i;
16340  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
16341  assert(compnr >= 0);
16342  assert(compnr < node->nchildren);
16343  childcomp[i] = compnr;
16344 
16345  /* remember if component number was changed by CheckComponent */
16346  if( compnr != i )
16347  haveoverlap = TRUE;
16348  }
16349 
16350  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16351 
16352  if( node->op == SCIP_EXPR_QUADRATIC )
16353  {
16354  /* merge components for products of children from different components */
16356 
16357  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16358  assert(data != NULL);
16359 
16360  for( i = 0; i < data->nquadelems; ++i )
16361  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16362  {
16363  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16364  compnr = childcomp[data->quadelems[i].idx2];
16365  for( j = 0; j < node->nchildren; ++j )
16366  if( childcomp[j] == compnr )
16367  childcomp[j] = childcomp[data->quadelems[i].idx1];
16368  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16369  haveoverlap = TRUE;
16370  }
16371  }
16372  else if( node->op == SCIP_EXPR_POLYNOMIAL )
16373  {
16374  /* merge components for monomials of children from different components */
16376 
16377  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16378  assert(data != NULL);
16379 
16380  for( i = 0; i < data->nmonomials; ++i )
16381  for( j = 1; j < data->monomials[i]->nfactors; ++j )
16382  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16383  {
16384  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16385  compnr = childcomp[data->monomials[i]->childidxs[j]];
16386  for( k = 0; k < node->nchildren; ++k )
16387  if( childcomp[k] == compnr )
16388  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16389  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16390  haveoverlap = TRUE;
16391  }
16392  }
16393 
16394  if( haveoverlap )
16395  {
16396  /* some component numbers are unused, thus relabel and count final number of components */
16397  int* compmap;
16398 
16399  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16400  for( i = 0; i < node->nchildren; ++i )
16401  compmap[i] = -1; /*lint !e644*/
16402 
16403  ncomponents = 0;
16404  for( i = 0; i < node->nchildren; ++i )
16405  {
16406  if( compmap[childcomp[i]] == -1 )
16407  compmap[childcomp[i]] = ncomponents++;
16408  childcomp[i] = compmap[childcomp[i]];
16409  }
16410 
16411  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16412  }
16413  else
16414  {
16415  ncomponents = node->nchildren;
16416  }
16417 
16418  if( ncomponents == 1 )
16419  {
16420  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16421  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16422 
16423  *nexprtrees = 1;
16424  exprtreecoefs[0] = 1.0;
16425  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16426 
16427  return SCIP_OKAY;
16428  }
16429 
16430  if( ncomponents > exprtreessize )
16431  {
16432  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16433  for( i = 0; i < node->nchildren; ++i )
16434  if( childcomp[i] >= exprtreessize )
16435  childcomp[i] = exprtreessize-1;
16436  ncomponents = exprtreessize;
16437  }
16438 
16439  assert(ncomponents >= 2);
16440 
16441  /* setup expression trees for each component */
16442  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16443  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16444  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16445  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16446  for( i = 0; i < ncomponents; ++i )
16447  {
16448  /* initially, no variable appears in the expression tree */
16449  for( j = 0; j < exprgraph->nvars; ++j )
16450  varidx[j] = -1; /*lint !e644*/
16451  nexprvars = 0;
16452 
16453  /* collect expressions from children belonging to component i */
16454  nexprs = 0;
16455  for( j = 0; j < node->nchildren; ++j )
16456  {
16457  assert(childcomp[j] >= 0);
16458  assert(childcomp[j] < ncomponents);
16459  if( childcomp[j] != i )
16460  continue;
16461 
16462  /* create expression from the subgraph that has child j as root */
16463  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
16464  childmap[j] = nexprs; /*lint !e644*/
16465  childmapinv[nexprs] = j; /*lint !e644*/
16466  ++nexprs;
16467  }
16468 
16469  /* setup expression tree for component i */
16470  switch( node->op )
16471  {
16472  case SCIP_EXPR_PLUS:
16473  {
16474  assert(ncomponents == 2);
16475  assert(nexprs == 1);
16476 
16477  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16478  exprtreecoefs[i] = 1.0;
16479 
16480  break;
16481  }
16482 
16483  case SCIP_EXPR_MINUS:
16484  {
16485  assert(ncomponents == 2);
16486  assert(nexprs == 1);
16487 
16488  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16489  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16490  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16491  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16492 
16493  break;
16494  }
16495 
16496  case SCIP_EXPR_SUM:
16497  {
16498  if( nexprs == 1 )
16499  {
16500  /* component corresponds to exactly one child of node */
16501  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16502  }
16503  else
16504  {
16505  /* component corresponds to a sum of children of node */
16506  SCIP_EXPR* sumexpr;
16507 
16508  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16509  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16510  }
16511  exprtreecoefs[i] = 1.0;
16512 
16513  break;
16514  }
16515 
16516  case SCIP_EXPR_LINEAR:
16517  {
16518  SCIP_Real* nodecoefs;
16519  SCIP_EXPR* sumexpr;
16520 
16521  nodecoefs = (SCIP_Real*)node->data.data;
16522 
16523  /* if there is a constant, then we put it into the expression of the first component */
16524  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16525  {
16526  /* component corresponds to exactly one child of node */
16527  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16528  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16529  }
16530  else if( nexprs == 1 )
16531  {
16532  /* component corresponds to a sum of one child and a constant */
16533  assert(i == 0);
16534  assert(nodecoefs[node->nchildren] != 0.0);
16535  assert(nodecoefs[childmapinv[0]] != 0.0);
16536  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16537  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16538  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16539  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16540  }
16541  else
16542  {
16543  /* component corresponds to a linear combination of children of node */
16544 
16545  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16546  {
16547  /* if two expressions with equal sign, then create PLUS expression */
16548  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16549  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16550  }
16551  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16552  {
16553  /* if two expressions with opposite sign, then create MINUS expression */
16554  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16555  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16556  }
16557  else
16558  {
16559  /* assemble coefficents and create SUM or LINEAR expression */
16560  SCIP_Real* coefs;
16561  SCIP_Bool allcoefsequal;
16562 
16563  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16564  allcoefsequal = TRUE;
16565  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
16566  for( j = 0; j < nexprs; ++j )
16567  {
16568  coefs[j] = nodecoefs[childmapinv[j]];
16569  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
16570  }
16571 
16572  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16573  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16574  {
16575  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16576  exprtreecoefs[i] = coefs[0];
16577  }
16578  else
16579  {
16580  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16581  exprtreecoefs[i] = 1.0;
16582  }
16583 
16584  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16585  }
16586 
16587  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16588  }
16589 
16590  break;
16591  }
16592 
16593  case SCIP_EXPR_QUADRATIC:
16594  {
16595  SCIP_EXPR* quadexpr;
16597  SCIP_Real* lincoefs;
16598  SCIP_QUADELEM* quadelems;
16599  int nquadelems;
16600 
16601  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16602 
16603  exprtreecoefs[i] = 1.0;
16604 
16605  /* assemble coefficients corresponding to component i */
16606  if( nodedata->lincoefs != NULL )
16607  {
16608  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16609  for( j = 0; j < nexprs; ++j )
16610  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
16611  }
16612  else
16613  lincoefs = NULL;
16614 
16615  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16616  nquadelems = 0;
16617  for( j = 0; j < nodedata->nquadelems; ++j )
16618  {
16619  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16620  if( childcomp[nodedata->quadelems[j].idx1] != i )
16621  continue;
16622  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
16623  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16624  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16625  ++nquadelems;
16626  }
16627 
16628  /* put constant into first component */
16629  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16630  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16631 
16632  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16633  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16634 
16635  break;
16636  }
16637 
16638  case SCIP_EXPR_POLYNOMIAL:
16639  {
16640  SCIP_EXPR* polyexpr;
16642  SCIP_EXPRDATA_MONOMIAL** monomials;
16643  SCIP_Real constant;
16644  int nmonomials;
16645 
16646  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16647 
16648  constant = nodedata->constant;
16649  exprtreecoefs[i] = 1.0;
16650 
16651  /* collect monomials belonging to component i */
16652  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16653  nmonomials = 0;
16654  for( j = 0; j < nodedata->nmonomials; ++j )
16655  {
16656  if( nodedata->monomials[j]->nfactors == 0 )
16657  {
16658  constant += nodedata->monomials[j]->coef;
16659  continue;
16660  }
16661  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16662  continue;
16663 
16664  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16665  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
16666  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16667  {
16668  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16669  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16670  }
16671  ++nmonomials;
16672  }
16673 
16674  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16675  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16676 
16677  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16678 
16679  break;
16680  }
16681 
16682  default:
16683  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16684  return SCIP_ERROR;
16685  } /*lint !e788*/
16686 
16687  /* copy variables into expression tree */
16688  if( nexprvars > 0 )
16689  {
16690  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16691  for( j = 0; j < exprgraph->nvars; ++j )
16692  {
16693  assert(varidx[j] >= -1);
16694  assert(varidx[j] < nexprvars);
16695  if( varidx[j] >= 0 )
16696  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16697  }
16698  }
16699  }
16700 
16701  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16702  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16703  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16704  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16705  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16706 
16707  *nexprtrees = ncomponents;
16708 
16709  return SCIP_OKAY;
16710 }
16711 
16712 /** returns how often expression graph variables are used in a subtree of the expression graph */
16714  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16715  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
16716  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16717  )
16718 {
16719  assert(exprgraph != NULL);
16720  assert(node != NULL);
16721  assert(varsusage != NULL);
16722 
16723  BMSclearMemoryArray(varsusage, exprgraph->nvars);
16724 
16725  exprgraphNodeGetVarsUsage(node, varsusage);
16726 }
16727 
16728 /** gives the number of summands which the expression of an expression graph node consists of */
16730  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
16731  )
16732 {
16733  switch( node->op )
16734  {
16735  case SCIP_EXPR_PLUS:
16736  case SCIP_EXPR_MINUS:
16737  return 2;
16738 
16739  case SCIP_EXPR_SUM:
16740  case SCIP_EXPR_LINEAR:
16741  return node->nchildren;
16742 
16743  case SCIP_EXPR_QUADRATIC:
16744  {
16746 
16747  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16748  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16749  }
16750 
16751  case SCIP_EXPR_POLYNOMIAL:
16752  {
16754 
16755  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16756  return nodedata->nmonomials;
16757  }
16758 
16759  default:
16760  return 1;
16761  } /*lint !e788*/
16762 }
16763 
16764 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
16766  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16767  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16768  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16769  int* nexprtrees, /**< buffer to store number of expression trees */
16770  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16771  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16772  )
16773 {
16774  int* varidx;
16775  int nexprvars;
16776  int i;
16777 
16778  assert(exprgraph != NULL);
16779  assert(node != NULL);
16780  assert(node->depth >= 0);
16781  assert(node->pos >= 0);
16782  assert(exprtreessize > 0);
16783  assert(nexprtrees != NULL);
16784  assert(exprtrees != NULL);
16785  assert(exprtreecoefs != NULL);
16786 
16787  /* if node is not separable, fallback to SCIPexprgraphGetTree */
16788  if( node->op != SCIP_EXPR_PLUS &&
16789  node->op != SCIP_EXPR_MINUS &&
16790  node->op != SCIP_EXPR_SUM &&
16791  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16792  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16793  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16794  {
16795  *nexprtrees = 1;
16796  exprtreecoefs[0] = 1.0;
16797  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16798 
16799  return SCIP_OKAY;
16800  }
16801 
16802  switch( node->op )
16803  {
16804  case SCIP_EXPR_PLUS:
16805  {
16806  assert(exprtreessize >= 2);
16807 
16808  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16809  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16810 
16811  exprtreecoefs[0] = 1.0;
16812  exprtreecoefs[1] = 1.0;
16813 
16814  *nexprtrees = 2;
16815  break;
16816  }
16817 
16818  case SCIP_EXPR_MINUS:
16819  {
16820  assert(exprtreessize >= 2);
16821 
16822  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16823  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16824 
16825  exprtreecoefs[0] = 1.0;
16826  exprtreecoefs[1] = -1.0;
16827 
16828  *nexprtrees = 2;
16829  break;
16830  }
16831 
16832  case SCIP_EXPR_SUM:
16833  {
16834  assert(exprtreessize >= node->nchildren);
16835 
16836  for( i = 0; i < node->nchildren; ++i )
16837  {
16838  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16839  exprtreecoefs[i] = 1.0;
16840  }
16841 
16842  *nexprtrees = node->nchildren;
16843  break;
16844  }
16845 
16846  case SCIP_EXPR_LINEAR:
16847  {
16848  SCIP_Real* nodecoefs;
16849 
16850  assert(exprtreessize >= node->nchildren);
16851  assert(node->nchildren > 0);
16852 
16853  nodecoefs = (SCIP_Real*)node->data.data;
16854  assert(nodecoefs != NULL);
16855 
16856  for( i = 0; i < node->nchildren; ++i )
16857  {
16858  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16859  exprtreecoefs[i] = nodecoefs[i];
16860  }
16861 
16862  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16863  if( nodecoefs[node->nchildren] != 0.0 )
16864  {
16865  SCIP_EXPR* constexpr_;
16866 
16867  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16868  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16869  }
16870 
16871  *nexprtrees = node->nchildren;
16872  break;
16873  }
16874 
16875  case SCIP_EXPR_QUADRATIC:
16876  {
16878  SCIP_Real* lincoefs;
16879  SCIP_QUADELEM* quadelems;
16880  int nquadelems;
16881  SCIP_EXPR* expr;
16882  int j;
16883 
16884  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16885  lincoefs = nodedata->lincoefs;
16886  quadelems = nodedata->quadelems;
16887  nquadelems = nodedata->nquadelems;
16888 
16889  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16890  assert(node->nchildren > 0);
16891 
16892  *nexprtrees = 0;
16893  if( lincoefs != NULL )
16894  {
16895  for( i = 0; i < node->nchildren; ++i )
16896  {
16897  if( lincoefs[i] == 0.0 )
16898  continue;
16899  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16900  exprtreecoefs[*nexprtrees] = lincoefs[i];
16901  ++*nexprtrees;
16902  }
16903  }
16904 
16905  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16906  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16907 
16908  for( i = 0; i < nquadelems; ++i )
16909  {
16910  /* initially, no variable appears in the expression tree */
16911  for( j = 0; j < exprgraph->nvars; ++j )
16912  varidx[j] = -1; /*lint !e644*/
16913  nexprvars = 0;
16914 
16915  /* create expression from the subgraph at quadelems[i].idx1 */
16916  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16917 
16918  if( quadelems[i].idx1 == quadelems[i].idx2 )
16919  {
16920  /* create expression for square of expr */
16921  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16922  }
16923  else
16924  {
16925  SCIP_EXPR* expr2;
16926 
16927  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16928  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16929  /* create expression for product */
16930  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16931  }
16932 
16933  /* create expression tree for expr */
16934  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16935 
16936  /* copy variables into expression tree */
16937  if( nexprvars > 0 )
16938  {
16939  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16940  for( j = 0; j < exprgraph->nvars; ++j )
16941  {
16942  assert(varidx[j] >= -1);
16943  assert(varidx[j] < nexprvars);
16944  if( varidx[j] >= 0 )
16945  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16946  }
16947  }
16948 
16949  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16950 
16951  ++*nexprtrees;
16952  }
16953 
16954  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16955  if( nodedata->constant != 0.0 )
16956  {
16957  SCIP_EXPR* constexpr_;
16958 
16959  assert(*nexprtrees > 0);
16960  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16961  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16962  }
16963 
16964  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16965 
16966  break;
16967  }
16968 
16969  case SCIP_EXPR_POLYNOMIAL:
16970  {
16972  SCIP_EXPRDATA_MONOMIAL** monomials;
16973  SCIP_Real constant;
16974  int nmonomials;
16975  SCIP_EXPR* expr;
16976  int* childidxs;
16977  int j;
16978 
16979  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16980  monomials = nodedata->monomials;
16981  nmonomials = nodedata->nmonomials;
16982  constant = nodedata->constant;
16983 
16984  assert(exprtreessize >= nmonomials);
16985  assert(node->nchildren > 0);
16986 
16987  *nexprtrees = 0;
16988 
16989  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16990  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16991 
16992  for( i = 0; i < nmonomials; ++i )
16993  {
16994  /* initially, no variable appears in the expression tree */
16995  for( j = 0; j < exprgraph->nvars; ++j )
16996  varidx[j] = -1;
16997  nexprvars = 0;
16998 
16999  if( monomials[i]->nfactors == 1 )
17000  {
17001  /* create expression from the subgraph at only factor */
17002  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17003 
17004  /* put exponent in, if not 1.0 */
17005  if( monomials[i]->exponents[0] == 1.0 )
17006  ;
17007  else if( monomials[i]->exponents[0] == 2.0 )
17008  {
17009  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
17010  }
17011  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
17012  {
17013  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
17014  }
17015  else
17016  {
17017  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
17018  }
17019  }
17020  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
17021  {
17022  SCIP_EXPR* expr2;
17023 
17024  /* create expressions for both factors */
17025  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17026  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
17027 
17028  /* create expression for product of factors */
17029  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
17030  }
17031  else
17032  {
17033  SCIP_EXPRDATA_MONOMIAL* monomial;
17034  SCIP_EXPR** exprs;
17035  int f;
17036 
17037  /* create expression for each factor, assemble varidx and nexprvars
17038  * create child indices (= identity) */
17039  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
17040  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
17041  for( f = 0; f < monomials[i]->nfactors; ++f )
17042  {
17043  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
17044  childidxs[f] = f; /*lint !e644*/
17045  }
17046 
17047  /* create monomial and polynomial expression for this monomial
17048  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
17049  */
17050  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
17051  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
17052  constant = 0.0;
17053 
17054  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
17055  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
17056  }
17057 
17058  /* create expression tree for expr */
17059  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
17060 
17061  /* copy variables into expression tree */
17062  if( nexprvars > 0 )
17063  {
17064  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
17065  for( j = 0; j < exprgraph->nvars; ++j )
17066  {
17067  assert(varidx[j] >= -1);
17068  assert(varidx[j] < nexprvars);
17069  if( varidx[j] >= 0 )
17070  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
17071  }
17072  }
17073 
17074  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
17075 
17076  ++*nexprtrees;
17077  }
17078 
17079  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
17080  if( constant != 0.0 )
17081  {
17082  SCIP_EXPR* constexpr_;
17083 
17084  assert(*nexprtrees > 0);
17085  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
17086  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
17087  }
17088 
17089  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
17090 
17091  break;
17092  }
17093 
17094  default:
17095  SCIPerrorMessage("unexpected operator type %d\n", node->op);
17096  return SCIP_ERROR;
17097  } /*lint !e788*/
17098 
17099  return SCIP_OKAY;
17100 }
17101 
17102 /**@} */
void SCIPintervalSignPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_EXPRBOUNDSTATUS_CHILDRELAXED
Definition: type_expr.h:213
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13331
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15836
void SCIPexprFreeDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6183
void SCIPexprtreeGetVarsUsage(SCIP_EXPRTREE *tree, int *varsusage)
Definition: expr.c:8907
void SCIPquadelemSort(SCIP_QUADELEM *quadelems, int nquadelems)
Definition: expr.c:9211
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15517
void SCIPexprSortMonomials(SCIP_EXPR *expr)
Definition: expr.c:7023
void SCIPintervalSubScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define exprcurvSin
Definition: expr.c:2077
#define QUADELEMS_SWAP(x, y)
Definition: expr.c:9092
void SCIPintervalMax(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:449
#define NULL
Definition: def.h:239
SCIP_EXPROPDATA data
Definition: struct_expr.h:51
static void exprgraphSortConstNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:9651
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14973
static SCIP_RETCODE exprgraphNodeAddParent(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9344
SCIP_RETCODE SCIPexprSubstituteVars(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR **substexprs)
Definition: expr.c:8145
static SCIP_RETCODE exprsimplifyConvertToPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4265
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:15173
void SCIPintervalSign(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define QUADELEMS_ISBETTER(a, b)
Definition: expr.c:9089
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:4289
SCIP_RETCODE SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16765
SCIP_RETCODE SCIPexprtreeEvalInt(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_INTERVAL *val)
Definition: expr.c:8739
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:15257
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:130
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:8756
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5920
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:14762
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:3761
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2265
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:8026
static SCIP_RETCODE exprgraphNodeAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nexprs, SCIP_EXPRGRAPHNODE **exprs, int *childmap)
Definition: expr.c:9481
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12967
static SCIP_RETCODE exprgraphNodeCreateExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPR **expr, int *nexprvars, int *varidx)
Definition: expr.c:11789
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5693
#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:8225
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14943
static SCIP_RETCODE exprgraphEnsureDepth(SCIP_EXPRGRAPH *exprgraph, int mindepth)
Definition: expr.c:12056
void SCIPsortPtrPtrRealInt(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_MAXSTRLEN
Definition: def.h:260
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:11459
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_VARTYPE_INTEGER_CHAR
Definition: def.h:122
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
SCIP_Real * exponents
Definition: struct_expr.h:95
#define SCIP_DECL_USEREXPREVAL(x)
Definition: type_expr.h:248
#define SCIP_DECL_USEREXPRPRINT(x)
Definition: type_expr.h:310
int SCIPexprgraphGetDepth(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14913
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:5064
static SCIP_RETCODE exprgraphNodeRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11390
const char * SCIPexpropGetName(SCIP_EXPROP op)
Definition: expr.c:3263
void SCIPexprChgPolynomialConstant(SCIP_EXPR *expr, SCIP_Real constant)
Definition: expr.c:6689
SCIP_RETCODE SCIPexprgraphAddConst(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15330
SCIP_RETCODE SCIPexprtreeGetMaxDegree(SCIP_EXPRTREE *tree, int *maxdegree)
Definition: expr.c:8710
SCIP_Real * SCIPexprtreeGetParamVals(SCIP_EXPRTREE *tree)
Definition: expr.c:8632
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:15017
SCIP_RETCODE SCIPexprCreateMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial, SCIP_Real coef, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:7035
static SCIP_DECL_SORTPTRCOMP(exprgraphnodecomp)
Definition: expr.c:126
void SCIPexprgraphCaptureNode(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12945
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:13460
static SCIP_DECL_EXPRFREEDATA(exprFreeDataLinear)
Definition: expr.c:2540
SCIP_Real SCIPexprGetRealPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5756
SCIP_EXPROP op
Definition: struct_expr.h:48
int SCIPexprGetOpIndex(SCIP_EXPR *expr)
Definition: expr.c:5723
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:7795
SCIP_RETCODE SCIPexprPolynomialPower(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int exponent)
Definition: expr.c:6785
void SCIPexprChgMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real newcoef)
Definition: expr.c:6851
SCIP_Bool SCIPexprHasParam(SCIP_EXPR *expr)
Definition: expr.c:7213
SCIPInterval cos(const SCIPInterval &x)
SCIP_Real SCIPexprGetPolynomialConstant(SCIP_EXPR *expr)
Definition: expr.c:5888
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:15890
#define FALSE
Definition: def.h:65
void SCIPintervalMul(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2793
#define EPSEQ(x, y, eps)
Definition: def.h:175
#define EPSISINT(x, eps)
Definition: def.h:187
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT
Definition: type_expr.h:214
SCIP_Bool SCIPexprAreEqual(SCIP_EXPR *expr1, SCIP_EXPR *expr2, SCIP_Real eps)
Definition: expr.c:7580
void SCIPexprMonomialPower(SCIP_EXPRDATA_MONOMIAL *monomial, int exponent)
Definition: expr.c:6926
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14963
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10325
static void exprgraphNodeCheckSeparabilityComponent(SCIP_EXPRGRAPHNODE *node, int *compnr, int nchildcomps, int *childcomps, int nvars, int *varcomps)
Definition: expr.c:11996
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10017
static SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11332
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13096
#define TRUE
Definition: def.h:64
#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:3292
void SCIPsortPtrPtrInt(void **ptrarray1, void **ptrarray2, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPexprtreeCopy(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **targettree, SCIP_EXPRTREE *sourcetree)
Definition: expr.c:8812
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12987
void SCIPexprGetVarsUsage(SCIP_EXPR *expr, int *varsusage)
Definition: expr.c:7557
void SCIPintervalMin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_INTERVAL SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13321
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15815
void SCIPexprReindexVars(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8183
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:14923
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:105
SCIP_RETCODE SCIPexprEvalInt(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7927
#define EPSGE(x, y, eps)
Definition: def.h:179
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:10087
void SCIPexprSortMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:7116
static void polynomialdataApplyChildmap(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int *childmap)
Definition: expr.c:1158
#define SCIPdebugMessage
Definition: pub_message.h:77
static SCIP_DECL_EXPRCURV(exprcurvDefault)
Definition: expr.c:1418
SCIP_EXPRDATA_MONOMIAL ** monomials
Definition: struct_expr.h:80
static struct exprOpTableElement exprOpTable[]
Definition: expr.c:3216
#define SIGN(x)
Definition: expr.c:46
#define BMSduplicateBlockMemory(mem, ptr, source)
Definition: memory.h:441
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15377
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2931
SCIP_RETCODE SCIPexprMultiplyMonomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6891
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8771
SCIP_Bool SCIPquadelemSortedFind(SCIP_QUADELEM *quadelems, int idx1, int idx2, int nquadelems, int *pos)
Definition: expr.c:9236
unsigned int SCIP_EXPRINTCAPABILITY
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8642
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:2120
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:15124
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13190
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:10022
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:12832
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:14396
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:5864
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:2014
static SCIP_DECL_EXPREVAL(exprevalVar)
Definition: expr.c:1427
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:5910
int SCIPexprGetIntPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5767
void SCIPintervalSin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3025
#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:9010
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13027
static SCIP_RETCODE exprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op, SCIP_EXPROPDATA opdata)
Definition: expr.c:9722
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13178
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:15085
#define SCIP_ALLOC_ABORT(x)
Definition: def.h:341
#define SCIP_DECL_EXPRGRAPHVARADDED(x)
Definition: type_expr.h:183
SCIP_HASHMAP * varidxs
Definition: struct_expr.h:169
int SCIPexprgraphGetNodeOperatorIndex(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13037
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:4924
SCIP_Real coef
Definition: type_expr.h:104
SCIP_Real inf
Definition: intervalarith.h:39
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:13118
#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:443
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13202
SCIP_RETCODE SCIPexprAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:6667
SCIP_Bool SCIPexprgraphHasNodeNonlinearAncestor(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14647
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13341
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:6584
SCIP_Bool SCIPexprgraphFindConstNode(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15718
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:7866
void SCIPexprgraphSetVarsBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_INTERVAL *varbounds)
Definition: expr.c:14985
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:129
SCIP_RETCODE SCIPexprgraphCheckCurvature(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop)
Definition: expr.c:15922
SCIP_RETCODE SCIPexprGetMaxDegree(SCIP_EXPR *expr, int *maxdegree)
Definition: expr.c:7232
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
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:13530
void SCIPsortPtrRealInt(void **ptrarray, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Real * SCIPexprGetQuadLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5840
SCIP_EXPRGRAPHNODE *** SCIPexprgraphGetNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14933
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16729
SCIP_INTERVAL bounds
Definition: struct_expr.h:137
static SCIP_RETCODE exprsimplifyRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4343
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:6141
static const char * curvnames[4]
Definition: expr.c:194
SCIPInterval sqrt(const SCIPInterval &x)
SCIP_Bool SCIPexprgraphHasNodeUserEstimator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13309
static SCIP_DECL_EXPRCOPYDATA(exprCopyDataLinear)
Definition: expr.c:2522
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
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:5096
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:5827
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2826
static SCIP_RETCODE exprgraphNodeReplaceChild(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE **oldchild, SCIP_EXPRGRAPHNODE *newchild)
Definition: expr.c:9582
void SCIPmessagePrintWarning(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:417
SCIP_EXPRGRAPHNODE *** nodes
Definition: struct_expr.h:162
#define EXPROPEMPTY
Definition: expr.c:3212
internal miscellaneous methods
void SCIPrandomFree(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem)
Definition: misc.c:9356
static SCIP_Bool exprgraphNodeIsParent(SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9450
static void polynomialdataFree(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata)
Definition: expr.c:712
#define REALABS(x)
Definition: def.h:174
void SCIPexprMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:6805
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:8612
SCIP_Bool SCIPexprAreMonomialsEqual(SCIP_EXPRDATA_MONOMIAL *monomial1, SCIP_EXPRDATA_MONOMIAL *monomial2, SCIP_Real eps)
Definition: expr.c:6820
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:13434
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16279
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_CALL(x)
Definition: def.h:351
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12957
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:15077
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:6632
SCIP_RETCODE SCIPexprCheckCurvature(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_Real *param, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:8062
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:7969
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:7847
void SCIPexprMultiplyPolynomialByConstant(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real factor)
Definition: expr.c:6702
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:14700
static SCIP_RETCODE exprsimplifyUnconvertPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4890
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:8107
static SCIP_RETCODE exprgraphNodeUpdateBounds(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool parenttightenisinvalid)
Definition: expr.c:10129
#define SCIP_DECL_USEREXPRCURV(x)
Definition: type_expr.h:272
void SCIPexprFreeMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial)
Definition: expr.c:7092
SCIP_RETCODE SCIPexprMulConstant(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPR *term, SCIP_Real factor)
Definition: expr.c:6404
SCIP_EXPR * SCIPexprtreeGetRoot(SCIP_EXPRTREE *tree)
Definition: expr.c:8602
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:7153
SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
SCIP_Bool SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14612
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:13217
#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:13048
#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:6246
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13130
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:446
SCIP_RETCODE SCIPexprMultiplyPolynomialByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR *factor, int *childmap)
Definition: expr.c:6739
void SCIPexprMergeMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real eps)
Definition: expr.c:6956
void SCIPintervalCos(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_EXPRINTCAPABILITY SCIPexprGetUserEvalCapability(SCIP_EXPR *expr)
Definition: expr.c:5962
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_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:5713
SCIP_Real SCIPexprGetSignPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5778
SCIP_EXPRGRAPHNODE ** children
Definition: struct_expr.h:128
#define SCIP_Bool
Definition: def.h:62
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:10064
SCIP_USEREXPRDATA * userdata
Definition: struct_expr.h:103
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14631
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:435
void SCIPexprSortQuadElems(SCIP_EXPR *expr)
Definition: expr.c:6620
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:15037
static SCIP_RETCODE exprsimplifyFlattenPolynomials(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR *expr, SCIP_Real eps, int maxexpansionexponent)
Definition: expr.c:4460
static SCIP_RETCODE exprgraphNodeRemoveParent(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9399
BMS_BLKMEM * blkmem
Definition: struct_expr.h:57
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8657
SCIP_RETCODE SCIPexprtreeFreeInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8680
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:448
void SCIPquadelemSqueeze(SCIP_QUADELEM *quadelems, int nquadelems, int *nquadelemsnew)
Definition: expr.c:9288
SCIP_Bool SCIPexprHasUserEstimator(SCIP_EXPR *expr)
Definition: expr.c:5951
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10118
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:5703
#define MIN(x, y)
Definition: def.h:209
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:16713
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:15057
static SCIP_Bool exprgraphFindConstNodePos(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *pos)
Definition: expr.c:9667
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:13584
SCIP_RETCODE SCIPexprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op,...)
Definition: expr.c:5973
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:8852
SCIP_Bool SCIPexprFindMonomialFactor(SCIP_EXPRDATA_MONOMIAL *monomial, int childidx, int *pos)
Definition: expr.c:7136
static SCIP_DECL_EXPRINTEVAL(exprevalIntDefault)
Definition: expr.c:1409
#define EPSLE(x, y, eps)
Definition: def.h:177
void SCIPexprgraphFreeNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14522
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:10223
#define SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED
Definition: type_expr.h:212
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14574
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:116
SCIPInterval log(const SCIPInterval &x)
SCIP_USEREXPRDATA * SCIPexprGetUserData(SCIP_EXPR *expr)
Definition: expr.c:5940
SCIP_RETCODE SCIPexprtreeAddExpr(SCIP_EXPRTREE *tree, SCIP_EXPR *expr, SCIP_Bool copyexpr)
Definition: expr.c:8981
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2326
#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:111
SCIP_Real SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5900
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:1187
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13059
void * SCIPexprGetOpData(SCIP_EXPR *expr)
Definition: expr.c:5745
SCIP_EXPROP op
Definition: struct_expr.h:119
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:9394
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13142
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2064
#define SCIP_REAL_MAX
Definition: def.h:151
static SCIP_RETCODE exprConvertToPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren)
Definition: expr.c:3323
SCIP_RETCODE SCIPexprEvalIntUser(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *val, SCIP_INTERVAL *gradient, SCIP_INTERVAL *hessian)
Definition: expr.c:7992
int SCIPexprgraphGetNodeIntPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13085
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12997
SCIP_QUADELEM * quadelems
Definition: struct_expr.h:71
static void exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:9373
#define EPSLT(x, y, eps)
Definition: def.h:176
#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:12700
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:178
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:3273
static void quadraticdataSort(SCIP_EXPRDATA_QUADRATIC *quadraticdata)
Definition: expr.c:528
#define SCIP_VARTYPE_IMPLINT_CHAR
Definition: def.h:123
SCIP_EXPRINTDATA * interpreterdata
Definition: struct_expr.h:63
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3041
#define exprcurvCos
Definition: expr.c:2105
#define MAX(x, y)
Definition: def.h:208
SCIP_Bool SCIPexprgraphFindVarNode(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_EXPRGRAPHNODE **varnode)
Definition: expr.c:15689
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8204
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13107
#define SCIP_EXPRINTCAPABILITY_FUNCVALUE
SCIP_Real * SCIPexprGetLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5789
SCIP_Bool SCIPexprtreeHasParam(SCIP_EXPRTREE *tree)
Definition: expr.c:8694
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Real SCIPexprGetOpReal(SCIP_EXPR *expr)
Definition: expr.c:5734
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13017
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:13511
SCIP_Bool parentssorted
Definition: struct_expr.h:134
#define SCIP_VARTYPE_CONTINUOUS_CHAR
Definition: def.h:124
SCIP_EXPRGRAPHNODE ** constnodes
Definition: struct_expr.h:173
void SCIPexprFreeShallow(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6221
SCIP_QUADELEM * SCIPexprGetQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5815
SCIP_RETCODE SCIPexprgraphCreateNodePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:13486
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:13297
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:4789
SCIP_RETCODE SCIPexprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op,...)
Definition: expr.c:13351
SCIP_RETCODE SCIPexprEvalIntShallow(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7907
SCIP_RETCODE SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14428
int SCIPexprGetNMonomials(SCIP_EXPR *expr)
Definition: expr.c:5876
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE
Definition: type_expr.h:216
SCIP_VAR * a
Definition: circlepacking.c:57
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:608
SCIP_RETCODE SCIPhashmapSetImage(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2971
SCIP_RETCODE SCIPexprtreeSimplify(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:8926
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:16226
#define SCIP_DECL_USEREXPRCOPYDATA(x)
Definition: type_expr.h:293
#define SCIP_Real
Definition: def.h:150
#define EPSROUND(x, eps)
Definition: def.h:185
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:372
SCIP_RETCODE SCIPrandomCreate(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem, unsigned int initialseed)
Definition: misc.c:9340
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12977
#define SCIP_INVALID
Definition: def.h:170
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPexprAddMonomialFactors(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:6862
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5930
void SCIPexprgraphPrintNode(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: expr.c:14684
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:9045
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:8538
#define SCIPisFinite(x)
Definition: pub_misc.h:1769
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:10108
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:121
int SCIPexprtreeGetNParams(SCIP_EXPRTREE *tree)
Definition: expr.c:8622
SCIP_RETCODE SCIPexprgraphSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange, SCIP_Bool *domainerror)
Definition: expr.c:15965
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
static SCIP_RETCODE exprsimplifyRemovePolynomialUnusedChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4409
#define exprcurvTan
Definition: expr.c:2123
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:12136
static SCIP_RETCODE exprparseFindClosingParenthesis(const char *str, const char **endptr, int length)
Definition: expr.c:5025
SCIP_RETCODE SCIPexprAddToLinear(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nchildren, SCIP_Real *coefs, SCIP_EXPR **children, SCIP_Real constant)
Definition: expr.c:6539
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:4146
#define nnodes
Definition: gastrans.c:65
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:433
SCIP_RETCODE SCIPexprMultiplyPolynomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6716
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13074
SCIP_RETCODE SCIPexprintFreeData(SCIP_EXPRINTDATA **interpreterdata)
#define EPSFLOOR(x, eps)
Definition: def.h:183
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2874
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:112
static SCIP_DECL_HASHGETKEY(exprparseVarTableGetKey)
Definition: expr.c:4914
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:419
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13166
#define SCIP_ALLOC_TERMINATE(retcode, x, TERM)
Definition: def.h:382
static SCIP_RETCODE polynomialdataPower(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int exponent)
Definition: expr.c:1088
#define SCIP_CALL_ABORT(x)
Definition: def.h:330
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14953
#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:6502
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_ALLOC(x)
Definition: def.h:362
#define SCIPABORT()
Definition: def.h:323
SCIP_Real SCIPexprGetLinearConstant(SCIP_EXPR *expr)
Definition: expr.c:5802
void SCIPexprtreeSetInterpreterData(SCIP_EXPRTREE *tree, SCIP_EXPRINTDATA *interpreterdata)
Definition: expr.c:8667
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:9101
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:8876
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
int SCIPexprGetNQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5852
static void exprgraphPrintNodeExpression(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, SCIP_Bool printchildrenbounds)
Definition: expr.c:9766
#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:12232
static void exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:11971
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15766
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:439
void SCIPintervalSetRoundingModeDownwards(void)
#define EPSZ(x, eps)
Definition: def.h:180
#define ABS(x)
Definition: def.h:204
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:13007
#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:8723
SCIP_EXPRINTCAPABILITY evalcapability
Definition: struct_expr.h:104
void SCIPexprgraphSetVarBounds(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_INTERVAL varbounds)
Definition: expr.c:14997
void SCIPsortIntReal(int *intarray, SCIP_Real *realarray, int len)
static SCIP_RETCODE exprgraphRemoveVar(SCIP_EXPRGRAPH *exprgraph, int varidx)
Definition: expr.c:12083
#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:14547
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13154