Scippy

SCIP

Solving Constraint Integer Programs

expr.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2019 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file nlpi/expr.c
17  * @brief methods for expressions, expression trees, expression graphs, and related
18  * @author Stefan Vigerske
19  * @author Thorsten Gellermann
20  * @author Ingmar Vierhaus (exprparse)
21  */
22 
23 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24 
25 #include <stdarg.h>
26 #include <string.h>
27 #include <math.h>
28 #include <ctype.h>
29 
30 #include "nlpi/pub_expr.h"
31 #include "nlpi/struct_expr.h"
32 #include "nlpi/exprinterpret.h"
33 
34 #include "scip/intervalarith.h"
35 #include "scip/pub_misc.h"
36 #include "scip/misc.h"
37 #include "scip/pub_message.h"
38 
39 
40 #define SCIP_EXPRESSION_MAXCHILDEST 16 /**< estimate on maximal number of children */
41 
42 /** sign of a value (-1 or +1)
43  *
44  * 0.0 has sign +1
45  */
46 #define SIGN(x) ((x) >= 0.0 ? 1.0 : -1.0)
47 
48 /** ensures that a block memory array has at least a given size
49  *
50  * if cursize is 0, then *array1 can be NULL
51  */
52 #define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize) \
53  do { \
54  int __newsize; \
55  assert((blkmem) != NULL); \
56  if( *(cursize) >= (minsize) ) \
57  break; \
58  __newsize = calcGrowSize(minsize); \
59  assert(__newsize >= (minsize)); \
60  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
61  *(cursize) = __newsize; \
62  } while( FALSE )
63 
64 #ifdef SCIP_DISABLED_CODE /* this macro is currently not used, which offends lint, so disable it */
65 /** ensures that two block memory arrays have at least a given size
66  *
67  * if cursize is 0, then arrays can be NULL
68  */
69 #define ensureBlockMemoryArraySize2(blkmem, array1, array2, cursize, minsize) \
70  do { \
71  int __newsize; \
72  assert((blkmem) != NULL); \
73  if( *(cursize) >= (minsize) ) \
74  break; \
75  __newsize = calcGrowSize(minsize); \
76  assert(__newsize >= (minsize)); \
77  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
78  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
79  *(cursize) = __newsize; \
80  } while( FALSE )
81 #endif
82 
83 /** ensures that three block memory arrays have at least a given size
84  *
85  * if cursize is 0, then arrays can be NULL
86  */
87 #define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize) \
88  do { \
89  int __newsize; \
90  assert((blkmem) != NULL); \
91  if( *(cursize) >= (minsize) ) \
92  break; \
93  __newsize = calcGrowSize(minsize); \
94  assert(__newsize >= (minsize)); \
95  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
96  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
97  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array3, *(cursize), __newsize) ); \
98  *(cursize) = __newsize; \
99  } while( FALSE )
100 
101 /**@name Miscellaneous private methods */
102 /**@{ */
103 
104 /** calculate memory size for dynamically allocated arrays (copied from scip/set.c) */
105 static
107  int num /**< minimum number of entries to store */
108  )
109 {
110  int size;
111 
112  /* calculate the size with this loop, such that the resulting numbers are always the same (-> block memory) */
113  size = 4;
114  while( size < num )
115  size = (int)(1.2 * size + 4);
116 
117  return size;
118 }
119 
120 /** expression graph nodes comparison to use in sorting methods
121  *
122  * The nodes need to have been added to the expression graph (depth,pos >= 0).
123  * The better node is the one with the lower depth and lower position, if depth is equal.
124  */
125 static
126 SCIP_DECL_SORTPTRCOMP(exprgraphnodecomp)
127 {
128  SCIP_EXPRGRAPHNODE* node1 = (SCIP_EXPRGRAPHNODE*)elem1;
129  SCIP_EXPRGRAPHNODE* node2 = (SCIP_EXPRGRAPHNODE*)elem2;
130 
131  assert(node1 != NULL);
132  assert(node2 != NULL);
133  assert(node1->depth >= 0);
134  assert(node1->pos >= 0);
135  assert(node2->depth >= 0);
136  assert(node2->pos >= 0);
137 
138  if( node1->depth != node2->depth )
139  return node1->depth - node2->depth;
140 
141  /* there should be no two nodes on the same position */
142  assert((node1->pos != node2->pos) || (node1 == node2));
143 
144  return node1->pos - node2->pos;
145 }
146 
147 /** checks if a given new lower bound is tighter (w.r.t. given bound strengthening epsilon) than the old one (copied from scip/set.c) */
148 static
150  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
151  SCIP_Real newlb, /**< new lower bound */
152  SCIP_Real oldlb, /**< old lower bound */
153  SCIP_Real oldub /**< old upper bound */
154  )
155 {
156  SCIP_Real eps;
157 
158  /* nothing can be tighter than an empty interval */
159  if( oldlb > oldub )
160  return FALSE;
161 
162  eps = REALABS(oldlb);
163  eps = MIN(oldub - oldlb, eps);
164  return EPSGT(newlb, oldlb, minstrength * MAX(eps, 1e-3));
165 }
166 
167 /** checks if a given new upper bound is tighter (w.r.t. given bound strengthening epsilon) than the old one (copied from scip/set.c) */
168 static
170  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
171  SCIP_Real newub, /**< new upper bound */
172  SCIP_Real oldlb, /**< old lower bound */
173  SCIP_Real oldub /**< old upper bound */
174  )
175 {
176  SCIP_Real eps;
177 
178  /* nothing can be tighter than an empty interval */
179  if( oldlb > oldub )
180  return FALSE;
181 
182  eps = REALABS(oldub);
183  eps = MIN(oldub - oldlb, eps);
184  return EPSLT(newub, oldub, minstrength * MAX(eps, 1e-3));
185 }
186 
187 /**@} */
188 
189 /**@name Expression curvature methods */
190 /**@{ */
191 
192 /** curvature names as strings */
193 static
194 const char* curvnames[4] =
195  {
196  "unknown",
197  "convex",
198  "concave",
199  "linear"
200  };
201 
202 #undef SCIPexprcurvAdd
203 
204 /** gives curvature for a sum of two functions with given curvature */
206  SCIP_EXPRCURV curv1, /**< curvature of first summand */
207  SCIP_EXPRCURV curv2 /**< curvature of second summand */
208  )
209 {
210  return (SCIP_EXPRCURV) (curv1 & curv2);
211 }
212 
213 /** gives the curvature for the negation of a function with given curvature */
215  SCIP_EXPRCURV curvature /**< curvature of function */
216  )
217 {
218  switch( curvature )
219  {
221  return SCIP_EXPRCURV_CONVEX;
222 
224  return SCIP_EXPRCURV_CONCAVE;
225 
228  /* can return curvature, do this below */
229  break;
230 
231  default:
232  SCIPerrorMessage("unknown curvature status.\n");
233  SCIPABORT();
234  }
235 
236  return curvature;
237 }
238 
239 /** gives curvature for a functions with given curvature multiplied by a constant factor */
241  SCIP_Real factor, /**< constant factor */
242  SCIP_EXPRCURV curvature /**< curvature of other factor */
243  )
244 {
245  if( factor == 0.0 )
246  return SCIP_EXPRCURV_LINEAR;
247  if( factor > 0.0 )
248  return curvature;
249  return SCIPexprcurvNegate(curvature);
250 }
251 
252 /** gives curvature for base^exponent for given bounds and curvature of base-function and constant exponent */
254  SCIP_INTERVAL basebounds, /**< bounds on base function */
255  SCIP_EXPRCURV basecurv, /**< curvature of base function */
256  SCIP_Real exponent /**< exponent */
257  )
258 {
259  SCIP_Bool expisint;
260 
261  assert(basebounds.inf <= basebounds.sup);
262 
263  if( exponent == 0.0 )
264  return SCIP_EXPRCURV_LINEAR;
265 
266  if( exponent == 1.0 )
267  return basecurv;
268 
269  expisint = EPSISINT(exponent, 0.0); /*lint !e835*/
270 
271  /* if exponent is fractional, then power is not defined for a negative base
272  * thus, consider only positive part of basebounds
273  */
274  if( !expisint && basebounds.inf < 0.0 )
275  {
276  basebounds.inf = 0.0;
277  if( basebounds.sup < 0.0 )
278  return SCIP_EXPRCURV_LINEAR;
279  }
280 
281  /* if basebounds contains 0.0, consider negative and positive interval separately, if possible */
282  if( basebounds.inf < 0.0 && basebounds.sup > 0.0 )
283  {
284  SCIP_INTERVAL leftbounds;
285  SCIP_INTERVAL rightbounds;
286 
287  /* something like x^(-2) may look convex on each side of zero, but is not convex on the whole interval due to the singularity at 0.0 */
288  if( exponent < 0.0 )
289  return SCIP_EXPRCURV_UNKNOWN;
290 
291  SCIPintervalSetBounds(&leftbounds, basebounds.inf, 0.0);
292  SCIPintervalSetBounds(&rightbounds, 0.0, basebounds.sup);
293 
294  return (SCIP_EXPRCURV) (SCIPexprcurvPower(leftbounds, basecurv, exponent) & SCIPexprcurvPower(rightbounds, basecurv, exponent));
295  }
296  assert(basebounds.inf >= 0.0 || basebounds.sup <= 0.0);
297 
298  /* (base^exponent)'' = exponent * ( (exponent-1) base^(exponent-2) (base')^2 + base^(exponent-1) base'' )
299  *
300  * if base'' is positive, i.e., base is convex, then
301  * - for base > 0.0 and exponent > 1.0, the second deriv. is positive -> convex
302  * - for base < 0.0 and exponent > 1.0, we can't say (first and second summand opposite signs)
303  * - for base > 0.0 and 0.0 < exponent < 1.0, we can't say (first sommand negative, second summand positive)
304  * - for base > 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
305  * - for base < 0.0 and exponent < 0.0 and even, the second deriv. is positive -> convex
306  * - for base < 0.0 and exponent < 0.0 and odd, the second deriv. is negative -> concave
307  *
308  * if base'' is negative, i.e., base is concave, then
309  * - for base > 0.0 and exponent > 1.0, we can't say (first summand positive, second summand negative)
310  * - for base < 0.0 and exponent > 1.0 and even, the second deriv. is positive -> convex
311  * - for base < 0.0 and exponent > 1.0 and odd, the second deriv. is negative -> concave
312  * - for base > 0.0 and 0.0 < exponent < 1.0, the second deriv. is negative -> concave
313  * - for base > 0.0 and exponent < 0.0, the second deriv. is positive -> convex
314  * - for base < 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
315  *
316  * if base'' is zero, i.e., base is linear, then
317  * (base^exponent)'' = exponent * (exponent-1) base^(exponent-2) (base')^2
318  * - just multiply signs
319  */
320 
321  if( basecurv == SCIP_EXPRCURV_LINEAR )
322  {
323  SCIP_Real sign;
324 
325  /* base^(exponent-2) is negative, if base < 0.0 and exponent is odd */
326  sign = exponent * (exponent - 1.0);
327  assert(basebounds.inf >= 0.0 || expisint);
328  if( basebounds.inf < 0.0 && ((int)exponent)%2 != 0 )
329  sign *= -1.0;
330  assert(sign != 0.0);
331 
332  return sign > 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
333  }
334 
335  if( basecurv == SCIP_EXPRCURV_CONVEX )
336  {
337  if( basebounds.sup <= 0.0 && exponent < 0.0 && expisint )
338  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
339  if( basebounds.inf >= 0.0 && exponent > 1.0 )
340  return SCIP_EXPRCURV_CONVEX ;
341  return SCIP_EXPRCURV_UNKNOWN;
342  }
343 
344  if( basecurv == SCIP_EXPRCURV_CONCAVE )
345  {
346  if( basebounds.sup <= 0.0 && exponent > 1.0 && expisint )
347  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
348  if( basebounds.inf >= 0.0 && exponent < 1.0 )
349  return exponent < 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
350  return SCIP_EXPRCURV_UNKNOWN;
351  }
352 
353  return SCIP_EXPRCURV_UNKNOWN;
354 }
355 
356 /** gives curvature for a monomial with given curvatures and bounds for each factor
357  *
358  * See Maranas and Floudas, Finding All Solutions of Nonlinearly Constrained Systems of Equations, JOGO 7, 1995
359  * for the categorization in the case that all factors are linear.
360  */
362  int nfactors, /**< number of factors in monomial */
363  SCIP_Real* exponents, /**< exponents in monomial, or NULL if all 1.0 */
364  int* factoridxs, /**< indices of factors (but not exponents), or NULL if identity mapping */
365  SCIP_EXPRCURV* factorcurv, /**< curvature of each factor */
366  SCIP_INTERVAL* factorbounds /**< bounds of each factor */
367  )
368 {
369  SCIP_Real mult;
370  SCIP_Real e;
371  SCIP_EXPRCURV curv;
372  SCIP_EXPRCURV fcurv;
373  int nnegative;
374  int npositive;
375  SCIP_Real sum;
376  SCIP_Bool expcurvpos;
377  SCIP_Bool expcurvneg;
378  int j;
379  int f;
380 
381  assert(nfactors >= 0);
382  assert(factorcurv != NULL || nfactors == 0);
383  assert(factorbounds != NULL || nfactors == 0);
384 
385  if( nfactors == 0 )
386  return SCIP_EXPRCURV_LINEAR;
387 
388  if( nfactors == 1 )
389  {
390  f = factoridxs != NULL ? factoridxs[0] : 0;
391  e = exponents != NULL ? exponents[0] : 1.0;
392  /* SCIPdebugMessage("monomial [%g,%g]^%g is %s\n",
393  factorbounds[f].inf, factorbounds[f].sup, e,
394  SCIPexprcurvGetName(SCIPexprcurvPower(factorbounds[f], factorcurv[f], e))); */
395  return SCIPexprcurvPower(factorbounds[f], factorcurv[f], e); /*lint !e613*/
396  }
397 
398  mult = 1.0;
399 
400  nnegative = 0; /* number of negative exponents */
401  npositive = 0; /* number of positive exponents */
402  sum = 0.0; /* sum of exponents */
403  expcurvpos = TRUE; /* whether exp_j * f_j''(x) >= 0 for all factors (assuming f_j >= 0) */
404  expcurvneg = TRUE; /* whether exp_j * f_j''(x) <= 0 for all factors (assuming f_j >= 0) */
405 
406  for( j = 0; j < nfactors; ++j )
407  {
408  f = factoridxs != NULL ? factoridxs[j] : j;
409  if( factorcurv[f] == SCIP_EXPRCURV_UNKNOWN ) /*lint !e613*/
410  return SCIP_EXPRCURV_UNKNOWN;
411  if( factorbounds[f].inf < 0.0 && factorbounds[f].sup > 0.0 ) /*lint !e613*/
412  return SCIP_EXPRCURV_UNKNOWN;
413 
414  e = exponents != NULL ? exponents[j] : 1.0;
415  if( e < 0.0 )
416  ++nnegative;
417  else
418  ++npositive;
419  sum += e;
420 
421  if( factorbounds[f].inf < 0.0 ) /*lint !e613*/
422  {
423  /* if argument is negative, then exponent should be integer */
424  assert(EPSISINT(e, 0.0)); /*lint !e835*/
425 
426  /* flip j'th argument: (f_j)^(exp_j) = (-1)^(exp_j) (-f_j)^(exp_j) */
427 
428  /* -f_j has negated curvature of f_j */
429  fcurv = SCIPexprcurvNegate(factorcurv[f]); /*lint !e613*/
430 
431  /* negate monomial, if exponent is odd, i.e., (-1)^(exp_j) = -1 */
432  if( (int)e % 2 != 0 )
433  mult *= -1.0;
434  }
435  else
436  {
437  fcurv = factorcurv[f]; /*lint !e613*/
438  }
439 
440  /* check if exp_j * fcurv is convex (>= 0) and/or concave */
441  fcurv = SCIPexprcurvMultiply(e, fcurv);
442  if( !(fcurv & SCIP_EXPRCURV_CONVEX) )
443  expcurvpos = FALSE;
444  if( !(fcurv & SCIP_EXPRCURV_CONCAVE) )
445  expcurvneg = FALSE;
446  }
447 
448  /* if all factors are linear, then a product f_j^exp_j with f_j >= 0 is convex if
449  * - all exponents are negative, or
450  * - all except one exponent j* are negative and exp_j* >= 1 - sum_{j!=j*}exp_j, but the latter is equivalent to sum_j exp_j >= 1
451  * further, the product is concave if
452  * - all exponents are positive and the sum of exponents is <= 1.0
453  *
454  * if factors are nonlinear, then we require additionally, that for convexity
455  * - each factor is convex if exp_j >= 0, or concave if exp_j <= 0, i.e., exp_j*f_j'' >= 0
456  * and for concavity, we require that
457  * - all factors are concave, i.e., exp_j*f_j'' <= 0
458  */
459 
460  if( nnegative == nfactors && expcurvpos )
461  curv = SCIP_EXPRCURV_CONVEX;
462  else if( nnegative == nfactors-1 && EPSGE(sum, 1.0, 1e-9) && expcurvpos )
463  curv = SCIP_EXPRCURV_CONVEX;
464  else if( npositive == nfactors && EPSLE(sum, 1.0, 1e-9) && expcurvneg )
465  curv = SCIP_EXPRCURV_CONCAVE;
466  else
467  curv = SCIP_EXPRCURV_UNKNOWN;
468  curv = SCIPexprcurvMultiply(mult, curv);
469 
470  return curv;
471 }
472 
473 /** gives name as string for a curvature */
475  SCIP_EXPRCURV curv /**< curvature */
476  )
477 {
478  assert(curv <= SCIP_EXPRCURV_LINEAR); /*lint !e685*/
479 
480  return curvnames[curv];
481 }
482 
483 /**@} */
484 
485 /**@name Quadratic expression data private methods */
486 /**@{ */
487 
488 /** creates SCIP_EXPRDATA_QUADRATIC data structure from given quadratic elements */
489 static
491  BMS_BLKMEM* blkmem, /**< block memory data structure */
492  SCIP_EXPRDATA_QUADRATIC** quadraticdata, /**< buffer to store pointer to quadratic data */
493  SCIP_Real constant, /**< constant */
494  int nchildren, /**< number of children */
495  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
496  int nquadelems, /**< number of quadratic elements */
497  SCIP_QUADELEM* quadelems /**< quadratic elements */
498  )
499 {
500  assert(blkmem != NULL);
501  assert(quadraticdata != NULL);
502  assert(quadelems != NULL || nquadelems == 0);
503  assert(nchildren >= 0);
504 
505  SCIP_ALLOC( BMSallocBlockMemory(blkmem, quadraticdata) );
506 
507  (*quadraticdata)->constant = constant;
508  (*quadraticdata)->lincoefs = NULL;
509  (*quadraticdata)->nquadelems = nquadelems;
510  (*quadraticdata)->quadelems = NULL;
511  (*quadraticdata)->sorted = (nquadelems <= 1);
512 
513  if( lincoefs != NULL )
514  {
515  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->lincoefs, lincoefs, nchildren) );
516  }
517 
518  if( nquadelems > 0 )
519  {
520  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->quadelems, quadelems, nquadelems) );
521  }
522 
523  return SCIP_OKAY;
524 }
525 
526 /** sorts quadratic elements in a SCIP_EXPRDATA_QUADRATIC data structure */
527 static
529  SCIP_EXPRDATA_QUADRATIC* quadraticdata /**< quadratic data */
530  )
531 {
532  assert(quadraticdata != NULL);
533 
534  if( quadraticdata->sorted )
535  {
536 #ifndef NDEBUG
537  int i;
538  for( i = 1; i < quadraticdata->nquadelems; ++i )
539  {
540  assert(quadraticdata->quadelems[i].idx1 <= quadraticdata->quadelems[i].idx2);
541  assert(quadraticdata->quadelems[i-1].idx1 <= quadraticdata->quadelems[i].idx1);
542  assert(quadraticdata->quadelems[i-1].idx1 < quadraticdata->quadelems[i].idx1 ||
543  quadraticdata->quadelems[i-1].idx2 <= quadraticdata->quadelems[i].idx2);
544  }
545 #endif
546  return;
547  }
548 
549  if( quadraticdata->nquadelems > 0 )
550  SCIPquadelemSort(quadraticdata->quadelems, quadraticdata->nquadelems);
551 
552  quadraticdata->sorted = TRUE;
553 }
554 
555 /**@} */
556 
557 /**@name Polynomial expression data private methods */
558 /**@{ */
559 
560 /** compares two monomials
561  *
562  * gives 0 if monomials are equal */
563 static
564 SCIP_DECL_SORTPTRCOMP(monomialdataCompare)
565 {
566  SCIP_EXPRDATA_MONOMIAL* monomial1;
567  SCIP_EXPRDATA_MONOMIAL* monomial2;
568 
569  int i;
570 
571  assert(elem1 != NULL);
572  assert(elem2 != NULL);
573 
574  monomial1 = (SCIP_EXPRDATA_MONOMIAL*)elem1;
575  monomial2 = (SCIP_EXPRDATA_MONOMIAL*)elem2;
576 
577  /* make sure, both monomials are equal */
578  SCIPexprSortMonomialFactors(monomial1);
579  SCIPexprSortMonomialFactors(monomial2);
580 
581  /* for the first factor where both monomials differ,
582  * we return either the difference in the child indices, if children are different
583  * or the sign of the difference in the exponents
584  */
585  for( i = 0; i < monomial1->nfactors && i < monomial2->nfactors; ++i )
586  {
587  if( monomial1->childidxs[i] != monomial2->childidxs[i] )
588  return monomial1->childidxs[i] - monomial2->childidxs[i];
589  if( monomial1->exponents[i] > monomial2->exponents[i] )
590  return 1;
591  else if( monomial1->exponents[i] < monomial2->exponents[i] )
592  return -1;
593  }
594 
595  /* if the factors of one monomial are a proper subset of the factors of the other monomial,
596  * we return the difference in the number of monomials
597  */
598  return monomial1->nfactors - monomial2->nfactors;
599 }
600 
601 /** ensures that the factors arrays of a monomial have at least a given size */
602 static
604  BMS_BLKMEM* blkmem, /**< block memory data structure */
605  SCIP_EXPRDATA_MONOMIAL* monomialdata, /**< monomial data */
606  int minsize /**< minimal size of factors arrays */
607  )
608 {
609  assert(blkmem != NULL);
610  assert(monomialdata != NULL);
611 
612  if( minsize > monomialdata->factorssize )
613  {
614  int newsize;
615 
616  newsize = calcGrowSize(minsize);
617  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->childidxs, monomialdata->factorssize, newsize) );
618  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->exponents, monomialdata->factorssize, newsize) );
619  monomialdata->factorssize = newsize;
620  }
621  assert(minsize <= monomialdata->factorssize);
622 
623  return SCIP_OKAY;
624 }
625 
626 /** creates SCIP_EXPRDATA_POLYNOMIAL data structure from given monomials */
627 static
629  BMS_BLKMEM* blkmem, /**< block memory data structure */
630  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
631  int nmonomials, /**< number of monomials */
632  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
633  SCIP_Real constant, /**< constant part */
634  SCIP_Bool copymonomials /**< whether to copy monomials, or copy only given pointers, in which case polynomialdata assumes ownership of monomial structure */
635  )
636 {
637  assert(blkmem != NULL);
638  assert(polynomialdata != NULL);
639  assert(monomials != NULL || nmonomials == 0);
640 
641  SCIP_ALLOC( BMSallocBlockMemory(blkmem, polynomialdata) );
642 
643  (*polynomialdata)->constant = constant;
644  (*polynomialdata)->nmonomials = nmonomials;
645  (*polynomialdata)->monomialssize = nmonomials;
646  (*polynomialdata)->monomials = NULL;
647  (*polynomialdata)->sorted = (nmonomials <= 1);
648 
649  if( nmonomials > 0 )
650  {
651  int i;
652 
653  if( copymonomials )
654  {
655  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, nmonomials) );
656 
657  for( i = 0; i < nmonomials; ++i )
658  {
659  assert(monomials[i] != NULL); /*lint !e613*/
660  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i],
661  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
662  }
663  }
664  else
665  {
666  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, monomials, nmonomials) );
667  }
668  }
669 
670  return SCIP_OKAY;
671 }
672 
673 /** creates a copy of a SCIP_EXPRDATA_POLYNOMIAL data structure */
674 static
676  BMS_BLKMEM* blkmem, /**< block memory data structure */
677  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
678  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata /**< polynomial data to copy */
679  )
680 {
681  assert(blkmem != NULL);
682  assert(polynomialdata != NULL);
683  assert(sourcepolynomialdata != NULL);
684 
685  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, polynomialdata, sourcepolynomialdata) );
686 
687  (*polynomialdata)->monomialssize = sourcepolynomialdata->nmonomials;
688  if( sourcepolynomialdata->nmonomials > 0 )
689  {
690  int i;
691 
692  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize) );
693 
694  for( i = 0; i < sourcepolynomialdata->nmonomials; ++i )
695  {
696  assert(sourcepolynomialdata->monomials[i] != NULL); /*lint !e613*/
697  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i], sourcepolynomialdata->monomials[i]->coef,
698  sourcepolynomialdata->monomials[i]->nfactors, sourcepolynomialdata->monomials[i]->childidxs, sourcepolynomialdata->monomials[i]->exponents) );
699  (*polynomialdata)->monomials[i]->sorted = sourcepolynomialdata->monomials[i]->sorted;
700  }
701  }
702  else
703  {
704  (*polynomialdata)->monomials = NULL;
705  }
706 
707  return SCIP_OKAY;
708 }
709 
710 /** frees a SCIP_EXPRDATA_POLYNOMIAL data structure */
711 static
713  BMS_BLKMEM* blkmem, /**< block memory data structure */
714  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata /**< pointer to polynomial data to free */
715  )
716 {
717  assert(blkmem != NULL);
718  assert(polynomialdata != NULL);
719  assert(*polynomialdata != NULL);
720 
721  if( (*polynomialdata)->monomialssize > 0 )
722  {
723  int i;
724 
725  for( i = 0; i < (*polynomialdata)->nmonomials; ++i )
726  {
727  assert((*polynomialdata)->monomials[i] != NULL);
728  SCIPexprFreeMonomial(blkmem, &(*polynomialdata)->monomials[i]);
729  assert((*polynomialdata)->monomials[i] == NULL);
730  }
731 
732  BMSfreeBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize);
733  }
734  assert((*polynomialdata)->monomials == NULL);
735 
736  BMSfreeBlockMemory(blkmem, polynomialdata);
737 }
738 
739 /** ensures that the monomials array of a polynomial has at least a given size */
740 static
742  BMS_BLKMEM* blkmem, /**< block memory data structure */
743  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
744  int minsize /**< minimal size of monomials array */
745  )
746 {
747  assert(blkmem != NULL);
748  assert(polynomialdata != NULL);
749 
750  ensureBlockMemoryArraySize(blkmem, &polynomialdata->monomials, &polynomialdata->monomialssize, minsize);
751  assert(minsize <= polynomialdata->monomialssize);
752 
753  return SCIP_OKAY;
754 }
755 
756 /** adds an array of monomials to a polynomial */
757 static
759  BMS_BLKMEM* blkmem, /**< block memory of expression */
760  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
761  int nmonomials, /**< number of monomials to add */
762  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
763  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
764  )
765 {
766  int i;
767 
768  assert(blkmem != NULL);
769  assert(polynomialdata != NULL);
770  assert(monomials != NULL || nmonomials == 0);
771 
772  if( nmonomials == 0 )
773  return SCIP_OKAY;
774 
775  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials + nmonomials) );
776  assert(polynomialdata->monomialssize >= polynomialdata->nmonomials + nmonomials);
777 
778  if( copymonomials )
779  {
780  for( i = 0; i < nmonomials; ++i )
781  {
782  assert(monomials[i] != NULL); /*lint !e613*/
783  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials + i],
784  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
785  }
786  }
787  else
788  {
789  BMScopyMemoryArray(&polynomialdata->monomials[polynomialdata->nmonomials], monomials, nmonomials); /*lint !e866*/
790  }
791  polynomialdata->nmonomials += nmonomials;
792 
793  polynomialdata->sorted = (polynomialdata->nmonomials <= 1);
794 
795  return SCIP_OKAY;
796 }
797 
798 /** ensures that monomials of a polynomial are sorted */
799 static
801  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata /**< polynomial expression */
802  )
803 {
804  assert(polynomialdata != NULL);
805 
806  if( polynomialdata->sorted )
807  {
808 #ifndef NDEBUG
809  int i;
810 
811  /* a polynom with more than one monoms can only be sorted if its monoms are sorted */
812  for( i = 1; i < polynomialdata->nmonomials; ++i )
813  {
814  assert(polynomialdata->monomials[i-1]->sorted);
815  assert(polynomialdata->monomials[i]->sorted);
816  assert(monomialdataCompare(polynomialdata->monomials[i-1], polynomialdata->monomials[i]) <= 0);
817  }
818 #endif
819  return;
820  }
821 
822  if( polynomialdata->nmonomials > 0 )
823  SCIPsortPtr((void**)polynomialdata->monomials, monomialdataCompare, polynomialdata->nmonomials);
824 
825  polynomialdata->sorted = TRUE;
826 }
827 
828 /** merges monomials that differ only in coefficient into a single monomial
829  *
830  * Eliminates monomials with coefficient between -eps and eps.
831  */
832 static
834  BMS_BLKMEM* blkmem, /**< block memory */
835  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
836  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
837  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
838  )
839 {
840  int i;
841  int offset;
842  int oldnfactors;
843 
844  assert(polynomialdata != NULL);
845  assert(eps >= 0.0);
846 
847  polynomialdataSortMonomials(polynomialdata);
848 
849  /* merge monomials by adding their coefficients, eliminate monomials with no factors or zero coefficient*/
850  offset = 0;
851  i = 0;
852  while( i + offset < polynomialdata->nmonomials )
853  {
854  if( offset > 0 )
855  {
856  assert(polynomialdata->monomials[i] == NULL);
857  assert(polynomialdata->monomials[i+offset] != NULL);
858  polynomialdata->monomials[i] = polynomialdata->monomials[i+offset];
859 #ifndef NDEBUG
860  polynomialdata->monomials[i+offset] = NULL;
861 #endif
862  }
863 
864  if( mergefactors )
865  {
866  oldnfactors = polynomialdata->monomials[i]->nfactors;
867  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i], eps);
868 
869  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
870  if( oldnfactors != polynomialdata->monomials[i]->nfactors )
871  polynomialdata->sorted = FALSE;
872  }
873 
874  while( i+offset+1 < polynomialdata->nmonomials )
875  {
876  assert(polynomialdata->monomials[i+offset+1] != NULL);
877  if( mergefactors )
878  {
879  oldnfactors = polynomialdata->monomials[i+offset+1]->nfactors;
880  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i+offset+1], eps);
881 
882  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
883  if( oldnfactors != polynomialdata->monomials[i+offset+1]->nfactors )
884  polynomialdata->sorted = FALSE;
885  }
886  if( monomialdataCompare((void*)polynomialdata->monomials[i], (void*)polynomialdata->monomials[i+offset+1]) != 0 )
887  break;
888  polynomialdata->monomials[i]->coef += polynomialdata->monomials[i+offset+1]->coef;
889  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i+offset+1]);
890  ++offset;
891  }
892 
893  if( polynomialdata->monomials[i]->nfactors == 0 )
894  {
895  /* constant monomial */
896  polynomialdata->constant += polynomialdata->monomials[i]->coef;
897  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
898  ++offset;
899  continue;
900  }
901 
902  if( EPSZ(polynomialdata->monomials[i]->coef, eps) )
903  {
904  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
905  ++offset;
906  continue;
907  }
908 
909  ++i;
910  }
911 
912 #ifndef NDEBUG
913  for( ; i < polynomialdata->nmonomials; ++i )
914  assert(polynomialdata->monomials[i] == NULL);
915 #endif
916 
917  polynomialdata->nmonomials -= offset;
918 
919  if( EPSZ(polynomialdata->constant, eps) )
920  polynomialdata->constant = 0.0;
921 }
922 
923 /** multiplies each summand of a polynomial by a given constant */
924 static
926  BMS_BLKMEM* blkmem, /**< block memory */
927  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
928  SCIP_Real factor /**< constant factor */
929  )
930 {
931  int i;
932 
933  assert(polynomialdata != NULL);
934 
935  if( factor == 1.0 )
936  return;
937 
938  if( factor == 0.0 )
939  {
940  for( i = 0; i < polynomialdata->nmonomials; ++i )
941  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
942  polynomialdata->nmonomials = 0;
943  }
944  else
945  {
946  for( i = 0; i < polynomialdata->nmonomials; ++i )
947  SCIPexprChgMonomialCoef(polynomialdata->monomials[i], polynomialdata->monomials[i]->coef * factor);
948  }
949 
950  polynomialdata->constant *= factor;
951 }
952 
953 /** multiplies each summand of a polynomial by a given monomial */
954 static
956  BMS_BLKMEM* blkmem, /**< block memory */
957  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
958  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
959  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
960  )
961 {
962  int i;
963 
964  assert(blkmem != NULL);
965  assert(factor != NULL);
966  assert(polynomialdata != NULL);
967 
968  if( factor->nfactors == 0 )
969  {
970  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factor->coef);
971  return SCIP_OKAY;
972  }
973 
974  /* multiply each monomial by factor */
975  for( i = 0; i < polynomialdata->nmonomials; ++i )
976  {
977  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i], factor, childmap) );
978  }
979 
980  /* add new monomial for constant multiplied by factor */
981  if( polynomialdata->constant != 0.0 )
982  {
983  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
984  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
985  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[polynomialdata->nmonomials], factor, childmap) );
986  ++polynomialdata->nmonomials;
987  polynomialdata->sorted = FALSE;
988  polynomialdata->constant = 0.0;
989  }
990 
991  return SCIP_OKAY;
992 }
993 
994 /** multiplies a polynomial by a polynomial
995  *
996  * Factors need to be different.
997  */
998 static
1000  BMS_BLKMEM* blkmem, /**< block memory */
1001  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1002  SCIP_EXPRDATA_POLYNOMIAL* factordata, /**< polynomial factor data */
1003  int* childmap /**< map children in factor to children in polynomialdata, or NULL for 1:1 */
1004  )
1005 {
1006  int i1;
1007  int i2;
1008  int orignmonomials;
1009 
1010  assert(blkmem != NULL);
1011  assert(polynomialdata != NULL);
1012  assert(factordata != NULL);
1013  assert(polynomialdata != factordata);
1014 
1015  if( factordata->nmonomials == 0 )
1016  {
1017  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factordata->constant);
1018  return SCIP_OKAY;
1019  }
1020 
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  (void) SCIPstrncpy((char*)(*varnames + 1), varname, (int)strlen(varname)+1);
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  /* coverity[var_deref_op] */
11850  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11851  break;
11852  }
11853 
11854  case SCIP_EXPR_INTPOWER:
11855  {
11856  assert(node->nchildren == 1);
11857  assert(childexprs != NULL);
11858  /* coverity[var_deref_op] */
11859  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11860  break;
11861  }
11862 
11863  case SCIP_EXPR_PLUS:
11864  case SCIP_EXPR_MINUS:
11865  case SCIP_EXPR_MUL:
11866  case SCIP_EXPR_DIV:
11867  case SCIP_EXPR_MIN:
11868  case SCIP_EXPR_MAX:
11869  {
11870  assert(node->nchildren == 2);
11871  assert(childexprs != NULL);
11872  /* coverity[var_deref_op] */
11873  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11874  break;
11875  }
11876 
11877  case SCIP_EXPR_SQUARE:
11878  case SCIP_EXPR_SQRT:
11879  case SCIP_EXPR_EXP:
11880  case SCIP_EXPR_LOG:
11881  case SCIP_EXPR_SIN:
11882  case SCIP_EXPR_COS:
11883  case SCIP_EXPR_TAN:
11884  /* case SCIP_EXPR_ERF: */
11885  /* case SCIP_EXPR_ERFI: */
11886  case SCIP_EXPR_ABS:
11887  case SCIP_EXPR_SIGN:
11888  {
11889  assert(node->nchildren == 1);
11890  assert(childexprs != NULL);
11891  /* coverity[var_deref_op] */
11892  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11893  break;
11894  }
11895 
11896  case SCIP_EXPR_SUM:
11897  case SCIP_EXPR_PRODUCT:
11898  {
11899  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11900  break;
11901  }
11902 
11903  case SCIP_EXPR_LINEAR:
11904  {
11905  assert(node->data.data != NULL);
11906 
11907  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11908  break;
11909  }
11910 
11911  case SCIP_EXPR_QUADRATIC:
11912  {
11913  SCIP_EXPRDATA_QUADRATIC* quaddata;
11914 
11915  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11916  assert(quaddata != NULL);
11917 
11918  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11919  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11920  break;
11921  }
11922 
11923  case SCIP_EXPR_POLYNOMIAL:
11924  {
11925  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11926 
11927  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11928  assert(polynomialdata != NULL);
11929 
11930  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11931  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11932 
11933  break;
11934  }
11935 
11936  case SCIP_EXPR_USER:
11937  {
11938  SCIP_EXPRDATA_USER* exprdata;
11939  SCIP_USEREXPRDATA* userdata;
11940 
11941  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11942  assert(exprdata != NULL);
11943 
11944  if( exprdata->copydata != NULL )
11945  {
11946  SCIP_CALL( exprdata->copydata(exprgraph->blkmem, node->nchildren, exprdata->userdata, &userdata) );
11947  }
11948  else
11949  userdata = exprdata->userdata;
11950 
11951  /* coverity[var_deref_op] */
11952  SCIP_CALL( SCIPexprCreateUser(exprgraph->blkmem, expr, node->nchildren, childexprs,
11953  userdata, exprdata->evalcapability, exprdata->eval, exprdata->inteval, exprdata->curv, exprdata->prop, exprdata->estimate, exprdata->copydata, exprdata->freedata, exprdata->print) );
11954 
11955  break;
11956  }
11957 
11958  case SCIP_EXPR_LAST:
11959  case SCIP_EXPR_PARAM:
11960  {
11961  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11962  return SCIP_ERROR;
11963  }
11964  }
11965 
11966  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11967 
11968  return SCIP_OKAY;
11969 }
11970 
11971 /** counts how often expression graph variables are used in a subtree of the expression graph
11972  *
11973  * @note The function does not clear the array first, but only increases already existing counts.
11974  */
11975 static
11977  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11978  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11979  )
11980 {
11981  int i;
11982 
11983  assert(node != NULL);
11984  assert(varsusage != NULL);
11985 
11986  if( node->op == SCIP_EXPR_VARIDX )
11987  {
11988  ++varsusage[node->data.intval];
11989  return;
11990  }
11991 
11992  for( i = 0; i < node->nchildren; ++i )
11993  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
11994 }
11995 
11996 /** checks whether a node can be put into a component when checking block separability of an expression
11997  *
11998  * If a variable used by node is already in another component, components are merged and component number is updated.
11999  */
12000 static
12002  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
12003  int* compnr, /**< component number to assign, may be reduced if variables overlap */
12004  int nchildcomps, /**< number of entries for which childcomps have been set already */
12005  int* childcomps, /**< component numbers of children */
12006  int nvars, /**< number of variables */
12007  int* varcomps /**< component numbers of variables */
12008  )
12009 {
12010  int varidx;
12011  int i;
12012 
12013  assert(node != NULL);
12014  assert(compnr != NULL);
12015  assert(*compnr >= 0);
12016  assert(childcomps != NULL);
12017  assert(varcomps != NULL);
12018 
12019  if( node->op != SCIP_EXPR_VARIDX )
12020  {
12021  for( i = 0; i < node->nchildren; ++i )
12022  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
12023  return;
12024  }
12025 
12026  varidx = node->data.intval;
12027  assert(varidx >= 0);
12028  assert(varidx < nvars);
12029 
12030  if( varcomps[varidx] == -1 )
12031  {
12032  /* first time we get to this variable, so set it's component to compnr and we are done */
12033  varcomps[varidx] = *compnr;
12034  return;
12035  }
12036 
12037  if( varcomps[varidx] == *compnr )
12038  {
12039  /* variable is already in current component, that's also good and we are done */
12040  return;
12041  }
12042 
12043  /* variable is already in another component, so have to merge component compnr into that component
12044  * do this by updating varcomps and childcomps */
12045  for( i = 0; i < nvars; ++i )
12046  if( varcomps[i] == *compnr )
12047  varcomps[i] = varcomps[varidx];
12048  for( i = 0; i < nchildcomps; ++i )
12049  if( childcomps[i] == *compnr )
12050  /* coverity[copy_paste_error] */
12051  childcomps[i] = varcomps[varidx];
12052  *compnr = varcomps[varidx];
12053 }
12054 
12055 /**@} */
12056 
12057 /**@name Expression graph private methods */
12058 /**@{ */
12059 
12060 /** assert that expression graph has at least a given depth */
12061 static
12063  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
12064  int mindepth /**< minimal depth that should be ensured */
12065  )
12066 {
12067  int olddepth;
12068 
12069  assert(exprgraph != NULL);
12070  assert(exprgraph->blkmem != NULL);
12071 
12072  if( mindepth <= exprgraph->depth )
12073  return SCIP_OKAY;
12074 
12075  olddepth = exprgraph->depth;
12076  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
12077  assert(exprgraph->depth >= mindepth);
12078 
12079  /* initialize new array entries to 0 and NULL, resp. */
12080  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12081  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12082  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12083 
12084  return SCIP_OKAY;
12085 }
12086 
12087 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
12088 static
12090  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12091  int varidx /**< variable index */
12092  )
12093 {
12094  SCIP_EXPRGRAPHNODE* varnode;
12095  void* var;
12096 
12097  assert(exprgraph != NULL);
12098  assert(varidx >= 0);
12099  assert(varidx < exprgraph->nvars);
12100 
12101  varnode = exprgraph->varnodes[varidx];
12102  assert(varnode->data.intval == varidx);
12103 
12104  var = exprgraph->vars[varidx];
12105 
12106  /* call varremove callback method, if set */
12107  if( exprgraph->exprgraphvarremove != NULL )
12108  {
12109  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
12110  }
12111 
12112  /* remove variable from hashmap */
12113  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
12114 
12115  /* move last variable to position varidx and give it the new index */
12116  if( varidx < exprgraph->nvars-1 )
12117  {
12118  /* call callback method, if set */
12119  if( exprgraph->exprgraphvarchgidx != NULL )
12120  {
12121  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
12122  }
12123 
12124  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
12125  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
12126  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
12127  exprgraph->varnodes[varidx]->data.intval = varidx;
12128  SCIP_CALL( SCIPhashmapSetImageInt(exprgraph->varidxs, exprgraph->vars[varidx], varidx) );
12129  }
12130  --exprgraph->nvars;
12131 
12132  return SCIP_OKAY;
12133 }
12134 
12135 /** moves a node in an expression graph to a different depth
12136  *
12137  * New depth must be larger than children depth.
12138  * Moves parent nodes to higher depth, if needed.
12139  * Variable nodes cannot be moved.
12140  */
12141 static
12143  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12144  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
12145  int newdepth /**< new depth to which to move node */
12146  )
12147 {
12148  int olddepth;
12149  int oldpos;
12150  int i;
12151 
12152  assert(exprgraph != NULL);
12153  assert(node != NULL);
12154  assert(node->depth >= 0); /* node should be in graph */
12155  assert(newdepth >= 0);
12156 
12157  /* if already on aimed depth, then don't need to move */
12158  if( node->depth == newdepth )
12159  return SCIP_OKAY;
12160 
12161  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
12162 
12163 #ifndef NDEBUG
12164  /* assert that children are at lower depth than new depth */
12165  for( i = 0; i < node->nchildren; ++i )
12166  assert(node->children[i]->depth < newdepth);
12167 #endif
12168 
12169  /* move parents to higher depth, if needed */
12170  for( i = 0; i < node->nparents; ++i )
12171  {
12172  if( node->parents[i]->depth <= newdepth )
12173  {
12174  /* move parent to depth+1 */
12175  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
12176  assert(node->parents[i]->depth > newdepth);
12177  }
12178  }
12179 
12180  /* ensure that graph is deep enough */
12181  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
12182  assert(exprgraph->depth > newdepth);
12183 
12184  olddepth = node->depth;
12185  oldpos = node->pos;
12186 
12187  /* add node to new depth */
12188  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
12189  node->depth = newdepth;
12190  node->pos = exprgraph->nnodes[newdepth];
12191  exprgraph->nodes[newdepth][node->pos] = node;
12192  ++exprgraph->nnodes[newdepth];
12193 
12194  /* 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) */
12195  for( i = 0; i < node->nchildren; ++i )
12196  node->children[i]->parentssorted = FALSE;
12197 
12198  /* move last node at previous depth to previous position, if it wasn't last */
12199  if( oldpos < exprgraph->nnodes[olddepth]-1 )
12200  {
12201  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
12202  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
12203 
12204  /* 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) */
12205  for( i = 0; i < exprgraph->nodes[olddepth][oldpos]->nchildren; ++i )
12206  exprgraph->nodes[olddepth][oldpos]->children[i]->parentssorted = FALSE;
12207  }
12208  --exprgraph->nnodes[olddepth];
12209 
12210  if( node->depth == 0 )
12211  {
12212  /* if at depth 0, then it need to be a node for either a constant or a variable */
12213  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
12214  if( node->op == SCIP_EXPR_CONST )
12215  {
12216  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
12217  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
12218  exprgraph->constnodes[exprgraph->nconsts] = node;
12219  ++exprgraph->nconsts;
12220  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
12221  }
12222  else
12223  {
12224  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
12225  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
12226  return SCIP_ERROR;
12227  }
12228 
12229  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
12230  node->curv = SCIP_EXPRCURV_LINEAR;
12231  }
12232 
12233  return SCIP_OKAY;
12234 }
12235 
12236 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
12237 static
12239  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12240  int nchildren, /**< number of children */
12241  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
12242  SCIP_EXPROP op, /**< operator */
12243  SCIP_EXPROPDATA opdata, /**< operator data */
12244  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
12245  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
12246  )
12247 {
12248  SCIP_EXPRGRAPHNODE** parentcands;
12249  int nparentcands;
12250  int parentcandssize;
12251  int i;
12252  int p;
12253 
12254  assert(exprgraph != NULL);
12255  assert(nchildren > 0);
12256  assert(children != NULL);
12257  assert(parent != NULL);
12258 
12259  *parent = NULL;
12260 
12261  /* create initial set of parent candidates as
12262  * all parents of first child that have the same operator type and the same number of children
12263  * additionally, some easy conditions for complex expression types:
12264  * if expression type is int/real/signpower, then compare also exponent,
12265  * if expression type is linear, then compare also constant part,
12266  * if expression type is quadratic, then compare also number of quadratic elements,
12267  * if expression type is polynomial, then compare also number of monmials and constant part
12268  */
12269  parentcandssize = children[0]->nparents;
12270  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
12271  nparentcands = 0;
12272  for( p = 0; p < children[0]->nparents; ++p )
12273  if( children[0]->parents[p]->op == op &&
12274  children[0]->parents[p]->nchildren == nchildren &&
12275  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
12276  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12277  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12278  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
12279  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
12280  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
12281  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
12282  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
12283  )
12284  {
12285  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
12286  }
12287 
12288  /* for all remaining children, remove parent candidates, that are not in their list of parents */
12289  for( i = 1; i < nchildren && nparentcands > 0; ++i )
12290  {
12291  p = 0;
12292  while( p < nparentcands )
12293  {
12294  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
12295  * otherwise keep candidate and check next one
12296  */
12297  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
12298  {
12299  parentcands[p] = parentcands[nparentcands-1];
12300  --nparentcands;
12301  }
12302  else
12303  ++p;
12304  }
12305  }
12306 
12307  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
12308 
12309  if( nparentcands == 0 )
12310  {
12311  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
12312  return SCIP_OKAY;
12313  }
12314 
12315  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
12316  * check if there is also one which corresponds to same expression and store that one in *parent
12317  */
12318  switch( op )
12319  {
12320  /* commutative operands with no data */
12321  case SCIP_EXPR_PLUS :
12322  case SCIP_EXPR_MUL :
12323  case SCIP_EXPR_MIN :
12324  case SCIP_EXPR_MAX :
12325  case SCIP_EXPR_SUM :
12326  case SCIP_EXPR_PRODUCT:
12327  case SCIP_EXPR_SQUARE :
12328  case SCIP_EXPR_SQRT :
12329  case SCIP_EXPR_EXP :
12330  case SCIP_EXPR_LOG :
12331  case SCIP_EXPR_SIN :
12332  case SCIP_EXPR_COS :
12333  case SCIP_EXPR_TAN :
12334  /* case SCIP_EXPR_ERF : */
12335  /* case SCIP_EXPR_ERFI : */
12336  case SCIP_EXPR_ABS :
12337  case SCIP_EXPR_SIGN :
12338  {
12339  /* sort childnodes, if needed for later */
12340  if( nchildren > 2 )
12341  SCIPsortPtr((void**)children, exprgraphnodecomp, nchildren);
12342  for( p = 0; p < nparentcands; ++p )
12343  {
12344  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12345  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12346 
12347  if( nchildren == 1 )
12348  {
12349  assert(parentcands[p]->children[0] == children[0]);
12350  /* same operand, same child, so same expression */
12351  *parent = parentcands[p];
12352  break;
12353  }
12354  else if( nchildren == 2 )
12355  {
12356  /* We know that every node in children is also a child of parentcands[p].
12357  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
12358  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
12359  */
12360  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
12361  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
12362  {
12363  *parent = parentcands[p];
12364  break;
12365  }
12366  }
12367  else
12368  {
12369  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
12370 
12371  /* sort children of parent candidate */
12372  SCIPsortPtr((void**)parentcands[p]->children, exprgraphnodecomp, nchildren);
12373 
12374  /* check if childnodes and parentcands[p]->children are the same */
12375  for( i = 0; i < nchildren; ++i )
12376  if( children[i] != parentcands[p]->children[i] )
12377  break;
12378  if( i == nchildren )
12379  {
12380  /* yeah, found an exact match */
12381  *parent = parentcands[p];
12382  break;
12383  }
12384  }
12385  }
12386 
12387  break;
12388  }
12389 
12390  /* non-commutative operands with two children */
12391  case SCIP_EXPR_MINUS :
12392  case SCIP_EXPR_DIV :
12393  {
12394  for( p = 0; p < nparentcands; ++p )
12395  {
12396  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12397  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
12398  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
12399  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
12400  {
12401  /* yeah, found one */
12402  *parent = parentcands[p];
12403  break;
12404  }
12405  }
12406 
12407  break;
12408  }
12409 
12410  /* operands with one child and data */
12411  case SCIP_EXPR_INTPOWER:
12412  {
12413  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12414  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12415  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12416  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
12417 
12418  /* yeah, have one with same exponent */
12419  *parent = parentcands[0];
12420 
12421  break;
12422  }
12423 
12424  case SCIP_EXPR_REALPOWER:
12425  case SCIP_EXPR_SIGNPOWER:
12426  {
12427  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12428  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12429  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12430  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
12431 
12432  /* yeah, have one with same exponent */
12433  *parent = parentcands[0];
12434 
12435  break;
12436  }
12437 
12438  /* commutative operands with n children and data */
12439  case SCIP_EXPR_LINEAR:
12440  {
12441  SCIP_Real* exprcoef;
12442  SCIP_Real* candcoef;
12443 
12444  exprcoef = (SCIP_Real*)opdata.data;
12445  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
12446  if( exprchildren != NULL )
12447  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, exprgraphnodecomp, nchildren);
12448  else
12449  SCIPsortPtrReal((void**)children, exprcoef, exprgraphnodecomp, nchildren);
12450  for( p = 0; p < nparentcands; ++p )
12451  {
12452  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12453  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12454 
12455  candcoef = (SCIP_Real*)parentcands[p]->data.data;
12456  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12457 
12458  /* sort children of parent candidate */
12459  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, exprgraphnodecomp, nchildren);
12460 
12461  /* check if children and coefficients in parent candidate and expression are the same */
12462  for( i = 0; i < nchildren; ++i )
12463  {
12464  if( children[i] != parentcands[p]->children[i] )
12465  break;
12466  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
12467  break;
12468  }
12469  if( i < nchildren )
12470  continue;
12471 
12472  /* yeah, found an exact match */
12473  *parent = parentcands[p];
12474  break;
12475  }
12476 
12477  break;
12478  }
12479 
12480  case SCIP_EXPR_QUADRATIC:
12481  {
12482  SCIP_EXPRDATA_QUADRATIC* exprdata;
12483  SCIP_Real* exprlincoef;
12484  SCIP_Real* candlincoef;
12485  SCIP_EXPRDATA_QUADRATIC* canddata;
12486  int* perm;
12487  int* invperm;
12488 
12489  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
12490  exprlincoef = exprdata->lincoefs;
12491 
12492  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
12493 
12494  /* sort expr->children and childnodes and store inverse permutation in invperm */
12495  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12496  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12497  for( i = 0; i < nchildren; ++i )
12498  invperm[i] = i; /*lint !e644*/
12499 
12500  if( exprlincoef != NULL )
12501  if( exprchildren != NULL )
12502  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12503  else
12504  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12505  else
12506  if( exprchildren != NULL )
12507  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12508  else
12509  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12510 
12511  /* compute permutation from its inverse */
12512  for( i = 0; i < nchildren; ++i )
12513  perm[invperm[i]] = i; /*lint !e644*/
12514 
12515  /* apply permuation to exprdata->quadelems and sort again */
12516  for( i = 0; i < exprdata->nquadelems; ++i )
12517  {
12518  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
12519  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
12520  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
12521  {
12522  int tmp;
12523  tmp = exprdata->quadelems[i].idx1;
12524  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
12525  exprdata->quadelems[i].idx2 = tmp;
12526  }
12527  }
12528  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
12529  exprdata->sorted = TRUE;
12530 
12531  for( p = 0; p < nparentcands; ++p )
12532  {
12533  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12534  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12535 
12536  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
12537  candlincoef = canddata->lincoefs;
12538  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
12539  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12540 
12541  /* sort parentcands[p]->children and store inverse permutation in invperm */
12542  for( i = 0; i < nchildren; ++i )
12543  invperm[i] = i;
12544 
12545  if( candlincoef != NULL )
12546  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, exprgraphnodecomp, parentcands[p]->nchildren);
12547  else
12548  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12549 
12550  /* compute permutation from its inverse */
12551  for( i = 0; i < nchildren; ++i )
12552  perm[invperm[i]] = i;
12553 
12554  /* apply permutation to canddata->quadelems */
12555  for( i = 0; i < canddata->nquadelems; ++i )
12556  {
12557  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
12558  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
12559  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
12560  {
12561  int tmp;
12562  tmp = canddata->quadelems[i].idx1;
12563  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
12564  canddata->quadelems[i].idx2 = tmp;
12565  }
12566  }
12567  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
12568  canddata->sorted = TRUE;
12569 
12570  /* check if children and linear coefficients in parent candidate and expression are the same */
12571  for( i = 0; i < nchildren; ++i )
12572  {
12573  if( children[i] != parentcands[p]->children[i] )
12574  break;
12575  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
12576  break;
12577  }
12578  if( i < nchildren )
12579  continue;
12580 
12581  assert(exprdata->nquadelems == canddata->nquadelems);
12582  for( i = 0; i < exprdata->nquadelems; ++i )
12583  {
12584  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
12585  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
12586  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
12587  break;
12588  }
12589  if( i == exprdata->nquadelems )
12590  {
12591  /* yeah, parentcands[p] is same quadratic expression as expr */
12592  *parent = parentcands[p];
12593  break;
12594  }
12595  }
12596 
12597  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12598  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12599 
12600  break;
12601  }
12602 
12603  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
12604  case SCIP_EXPR_POLYNOMIAL:
12605  {
12606  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
12607  SCIP_EXPRDATA_POLYNOMIAL* canddata;
12608  int* perm;
12609  int* invperm;
12610 
12611  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
12612 
12613  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
12614 
12615  /* sort exprchildren and childnodes and store inverse permutation in invperm */
12616  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12617  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12618  for( i = 0; i < nchildren; ++i )
12619  invperm[i] = i; /*lint !e644*/
12620 
12621  if( exprchildren != NULL )
12622  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12623  else
12624  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12625 
12626  /* compute permutation from its inverse */
12627  for( i = 0; i < nchildren; ++i )
12628  perm[invperm[i]] = i; /*lint !e644*/
12629 
12630  /* apply permutation to exprdata and sort again */
12631  polynomialdataApplyChildmap(exprdata, perm);
12632  polynomialdataSortMonomials(exprdata);
12633 
12634  for( p = 0; p < nparentcands; ++p )
12635  {
12636  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12637  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12638 
12639  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
12640  assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
12641  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12642 
12643  /* sort parentcands[p]->children and store inverse permutation in invperm */
12644  for( i = 0; i < nchildren; ++i )
12645  invperm[i] = i;
12646 
12647  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12648 
12649  /* compute permutation from its inverse */
12650  for( i = 0; i < nchildren; ++i )
12651  perm[invperm[i]] = i;
12652 
12653  /* apply permutation to canddata and sort again */
12654  polynomialdataApplyChildmap(canddata, perm);
12655  polynomialdataSortMonomials(canddata);
12656 
12657  /* check if children are equal */
12658  for( i = 0; i < nchildren; ++i )
12659  if( children[i] != parentcands[p]->children[i] )
12660  break;
12661  if( i < nchildren )
12662  continue;
12663 
12664  /* check if monomials are equal */
12665  for( i = 0; i < exprdata->nmonomials; ++i )
12666  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
12667  break;
12668  if( i == exprdata->nmonomials )
12669  {
12670  /* yeah, parentcands[p] is same polynomial expression as expr */
12671  *parent = parentcands[p];
12672  break;
12673  }
12674  }
12675 
12676  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12677  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12678 
12679  break;
12680  }
12681 
12682  case SCIP_EXPR_USER:
12683  {
12684  /* @todo need comparison function on user data to decide whether a parent candidate fits */
12685  break;
12686  }
12687 
12688  case SCIP_EXPR_VARIDX:
12689  case SCIP_EXPR_PARAM:
12690  case SCIP_EXPR_CONST:
12691  case SCIP_EXPR_LAST:
12692  SCIPerrorMessage("expression operand %d unexpected here\n", op);
12693  return SCIP_ERROR;
12694  }
12695 
12696  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
12697 
12698  return SCIP_OKAY;
12699 }
12700 
12701 /** adds an expression into an expression graph
12702  *
12703  * Enables corresponding nodes.
12704  */
12705 static
12707  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12708  SCIP_EXPR* expr, /**< expression to add */
12709  void** vars, /**< variables corresponding to VARIDX expressions */
12710  SCIP_Real* params, /**< parameter values */
12711  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
12712  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12713  )
12714 {
12715  SCIP_EXPRGRAPHNODE** childnodes;
12716  SCIP_Bool childisnew;
12717  SCIP_Bool nochildisnew;
12718  SCIP_EXPROPDATA opdata;
12719  int i;
12720 
12721  assert(exprgraph != NULL);
12722  assert(expr != NULL);
12723  assert(exprnode != NULL);
12724  assert(exprnodeisnew != NULL);
12725 
12726  if( expr->op == SCIP_EXPR_VARIDX )
12727  {
12728  /* find node corresponding to variable and add if not existing yet */
12729  assert(expr->nchildren == 0);
12730 
12731  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12732  assert(*exprnode != NULL);
12733  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12734  assert((*exprnode)->data.intval >= 0);
12735  assert((*exprnode)->data.intval < exprgraph->nvars);
12736  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12737 
12738  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12739 
12740  return SCIP_OKAY;
12741  }
12742 
12743  if( expr->op == SCIP_EXPR_CONST )
12744  {
12745  /* find node corresponding to constant and add if not existing yet */
12746  assert(expr->nchildren == 0);
12747 
12748  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12749  assert(*exprnode != NULL);
12750  assert((*exprnode)->op == SCIP_EXPR_CONST);
12751  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
12752 
12753  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12754 
12755  return SCIP_OKAY;
12756  }
12757 
12758  if( expr->op == SCIP_EXPR_PARAM )
12759  {
12760  /* find node corresponding to constant corresponding to parameter and add if not existing yet */
12761  assert(expr->nchildren == 0);
12762  assert(params != NULL);
12763 
12764  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, params[expr->data.intval], exprnode) );
12765  assert(*exprnode != NULL);
12766  assert((*exprnode)->op == SCIP_EXPR_CONST);
12767  assert((*exprnode)->data.dbl == params[expr->data.intval]); /*lint !e777*/
12768 
12769  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12770 
12771  return SCIP_OKAY;
12772  }
12773 
12774  /* expression should be variable or constant or have children */
12775  assert(expr->nchildren > 0);
12776 
12777  /* add children expressions into expression graph
12778  * check if we can find a common parent
12779  */
12780  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12781  nochildisnew = TRUE;
12782  for( i = 0; i < expr->nchildren; ++i )
12783  {
12784  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, params, &childnodes[i], &childisnew) ); /*lint !e644*/
12785  assert(childnodes[i] != NULL);
12786  nochildisnew &= !childisnew; /*lint !e514*/
12787  }
12788 
12789  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12790  if( nochildisnew )
12791  {
12792  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12793 
12794  if( *exprnode != NULL )
12795  {
12796  /* node already existing, make sure it is enabled */
12797  (*exprnode)->enabled = TRUE;
12798  *exprnodeisnew = FALSE;
12799 
12800  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12801  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12802  * SCIPdebugPrintf("\n");
12803  */
12804 
12805  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12806  return SCIP_OKAY;
12807  }
12808  }
12809 
12810  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12811 
12812  /* copy expression data */
12813  if( exprOpTable[expr->op].copydata != NULL )
12814  {
12815  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12816  }
12817  else
12818  {
12819  opdata = expr->data;
12820  }
12821 
12822  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12823  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12824  *exprnodeisnew = TRUE;
12825 
12826  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12827 
12828  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12829  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12830  * SCIPdebugPrintf("\n");
12831  */
12832 
12833  return SCIP_OKAY;
12834 }
12835 
12836 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12837 static
12839  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12840  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12841  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12842  )
12843 {
12844  SCIP_EXPRGRAPHNODE* node;
12845  int i;
12846  int p;
12847 
12848  assert(exprgraph != NULL);
12849  assert(clearreverseprop != NULL);
12850  assert(boundchanged != NULL);
12851 
12852  *boundchanged = FALSE;
12853  for( i = 0; i < exprgraph->nvars; ++i )
12854  {
12855  node = exprgraph->varnodes[i];
12856 
12857  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12858  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12859  {
12861  continue;
12862  }
12863 
12864  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12865  {
12866  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12867  SCIP_Real tmp;
12868 
12869  tmp = exprgraph->varbounds[i].inf;
12870  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12871  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12872  }
12873 
12874  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12875  +exprgraph->varbounds[i].sup > node->bounds.sup )
12876  {
12877  for( p = 0; p < node->nparents; ++p )
12879 
12880  node->bounds = exprgraph->varbounds[i];
12881  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12882 
12883  *boundchanged = TRUE;
12884 
12885  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12886  *clearreverseprop = TRUE;
12887  }
12888  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12889  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12890  {
12891  for( p = 0; p < node->nparents; ++p )
12893 
12894  node->bounds = exprgraph->varbounds[i];
12895  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12896 
12897  *boundchanged = TRUE;
12898  }
12899  else
12900  {
12901  node->bounds = exprgraph->varbounds[i];
12902  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12903  }
12904 
12906  }
12907 }
12908 
12909 /**@} */
12910 
12911 /**@name Expression graph node methods */
12912 /**@{ */
12913 
12914 /* In debug mode, the following methods are implemented as function calls to ensure
12915  * type validity.
12916  * In optimized mode, the methods are implemented as defines to improve performance.
12917  * However, we want to have them in the library anyways, so we have to undef the defines.
12918  */
12919 
12920 #undef SCIPexprgraphCaptureNode
12921 #undef SCIPexprgraphIsNodeEnabled
12922 #undef SCIPexprgraphGetNodeNChildren
12923 #undef SCIPexprgraphGetNodeChildren
12924 #undef SCIPexprgraphGetNodeNParents
12925 #undef SCIPexprgraphGetNodeParents
12926 #undef SCIPexprgraphGetNodeDepth
12927 #undef SCIPexprgraphGetNodePosition
12928 #undef SCIPexprgraphGetNodeOperator
12929 #undef SCIPexprgraphGetNodeOperatorIndex
12930 #undef SCIPexprgraphGetNodeOperatorReal
12931 #undef SCIPexprgraphGetNodeVar
12932 #undef SCIPexprgraphGetNodeRealPowerExponent
12933 #undef SCIPexprgraphGetNodeIntPowerExponent
12934 #undef SCIPexprgraphGetNodeSignPowerExponent
12935 #undef SCIPexprgraphGetNodeLinearCoefs
12936 #undef SCIPexprgraphGetNodeLinearConstant
12937 #undef SCIPexprgraphGetNodeQuadraticConstant
12938 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12939 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12940 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12941 #undef SCIPexprgraphGetNodePolynomialMonomials
12942 #undef SCIPexprgraphGetNodePolynomialNMonomials
12943 #undef SCIPexprgraphGetNodePolynomialConstant
12944 #undef SCIPexprgraphGetNodeUserData
12945 #undef SCIPexprgraphHasNodeUserEstimator
12946 #undef SCIPexprgraphGetNodeBounds
12947 #undef SCIPexprgraphGetNodeVal
12948 #undef SCIPexprgraphGetNodeCurvature
12949 
12950 /** captures node, i.e., increases number of uses */
12952  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12953  )
12954 {
12955  assert(node->nuses >= 0);
12956 
12957  SCIPdebugMessage("capture node %p\n", (void*)node);
12958 
12959  ++node->nuses;
12960 }
12961 
12962 /** returns whether a node is currently enabled */
12964  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12965  )
12966 {
12967  assert(node != NULL);
12968 
12969  return node->enabled;
12970 }
12971 
12972 /** gets number of children of a node in an expression graph */
12974  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12975  )
12976 {
12977  assert(node != NULL);
12978 
12979  return node->nchildren;
12980 }
12981 
12982 /** gets children of a node in an expression graph */
12984  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12985  )
12986 {
12987  assert(node != NULL);
12988 
12989  return node->children;
12990 }
12991 
12992 /** gets number of parents of a node in an expression graph */
12994  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12995  )
12996 {
12997  assert(node != NULL);
12998 
12999  return node->nparents;
13000 }
13001 
13002 /** gets parents of a node in an expression graph */
13004  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13005  )
13006 {
13007  assert(node != NULL);
13008 
13009  return node->parents;
13010 }
13011 
13012 /** gets depth of node in expression graph */
13014  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13015  )
13016 {
13017  assert(node != NULL);
13018 
13019  return node->depth;
13020 }
13021 
13022 /** gets position of node in expression graph at its depth level */
13024  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13025  )
13026 {
13027  assert(node != NULL);
13028 
13029  return node->pos;
13030 }
13031 
13032 /** gets operator of a node in an expression graph */
13034  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13035  )
13036 {
13037  assert(node != NULL);
13038 
13039  return node->op;
13040 }
13041 
13042 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
13044  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13045  )
13046 {
13047  assert(node != NULL);
13048  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
13049 
13050  return node->data.intval;
13051 }
13052 
13053 /** gives real belonging to a SCIP_EXPR_CONST operand */
13055  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13056  )
13057 {
13058  assert(node != NULL);
13059  assert(node->op == SCIP_EXPR_CONST);
13060 
13061  return node->data.dbl;
13062 }
13063 
13064 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
13066  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13067  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13068  )
13069 {
13070  assert(exprgraph != NULL);
13071  assert(node != NULL);
13072  assert(node->op == SCIP_EXPR_VARIDX);
13073  assert(node->data.intval >= 0);
13074  assert(node->data.intval < exprgraph->nvars);
13075 
13076  return exprgraph->vars[node->data.intval];
13077 }
13078 
13079 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
13081  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13082  )
13083 {
13084  assert(node != NULL);
13085  assert(node->op == SCIP_EXPR_REALPOWER);
13086 
13087  return node->data.dbl;
13088 }
13089 
13090 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
13092  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13093  )
13094 {
13095  assert(node != NULL);
13096  assert(node->op == SCIP_EXPR_INTPOWER);
13097 
13098  return node->data.intval;
13099 }
13100 
13101 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
13103  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13104  )
13105 {
13106  assert(node != NULL);
13107  assert(node->op == SCIP_EXPR_SIGNPOWER);
13108 
13109  return node->data.dbl;
13110 }
13111 
13112 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
13114  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13115  )
13116 {
13117  assert(node != NULL);
13118  assert(node->op == SCIP_EXPR_LINEAR);
13119 
13120  return (SCIP_Real*)node->data.data;
13121 }
13122 
13123 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
13125  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13126  )
13127 {
13128  assert(node != NULL);
13129  assert(node->op == SCIP_EXPR_LINEAR);
13130  assert(node->data.data != NULL);
13131 
13132  return ((SCIP_Real*)node->data.data)[node->nchildren];
13133 }
13134 
13135 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
13137  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13138  )
13139 {
13140  assert(node != NULL);
13141  assert(node->op == SCIP_EXPR_QUADRATIC);
13142  assert(node->data.data != NULL);
13143 
13144  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
13145 }
13146 
13147 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
13149  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13150  )
13151 {
13152  assert(node != NULL);
13153  assert(node->op == SCIP_EXPR_QUADRATIC);
13154  assert(node->data.data != NULL);
13155 
13156  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
13157 }
13158 
13159 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13161  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13162  )
13163 {
13164  assert(node != NULL);
13165  assert(node->op == SCIP_EXPR_QUADRATIC);
13166  assert(node->data.data != NULL);
13167 
13168  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
13169 }
13170 
13171 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13173  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13174  )
13175 {
13176  assert(node != NULL);
13177  assert(node->op == SCIP_EXPR_QUADRATIC);
13178  assert(node->data.data != NULL);
13179 
13180  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
13181 }
13182 
13183 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13185  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13186  )
13187 {
13188  assert(node != NULL);
13189  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13190  assert(node->data.data != NULL);
13191 
13192  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
13193 }
13194 
13195 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13197  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13198  )
13199 {
13200  assert(node != NULL);
13201  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13202  assert(node->data.data != NULL);
13203 
13204  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
13205 }
13206 
13207 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
13209  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13210  )
13211 {
13212  assert(node != NULL);
13213  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13214  assert(node->data.data != NULL);
13215 
13216  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
13217 }
13218 
13219 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
13220  *
13221  * Assumes that curvature of children and bounds of children and node itself are valid.
13222  */
13224  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13225  int monomialidx, /**< index of monomial */
13226  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
13227  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
13228  )
13229 {
13230  SCIP_EXPRDATA_MONOMIAL* monomial;
13231  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13232  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13233  SCIP_INTERVAL* childbounds = NULL;
13234  SCIP_EXPRCURV* childcurv = NULL;
13235  SCIP_EXPRGRAPHNODE* child;
13236  SCIP_RETCODE retcode = SCIP_OKAY;
13237  int i;
13238 
13239  assert(node != NULL);
13240  assert(node->depth >= 0); /* node should be in graph */
13241  assert(node->pos >= 0); /* node should be in graph */
13242  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13243  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
13244  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13245  assert(node->data.data != NULL);
13246  assert(monomialidx >= 0);
13247  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
13248  assert(curv != NULL);
13249 
13250  if( SCIPintervalIsEmpty(infinity, node->bounds) )
13251  {
13252  *curv = SCIP_EXPRCURV_LINEAR;
13253  return SCIP_OKAY;
13254  }
13255 
13256  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
13257  assert(monomial != NULL);
13258 
13259  /* if many children, get large enough memory to store children bounds */
13260  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13261  {
13262  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13263  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, monomial->nfactors), TERMINATE );
13264  }
13265  else
13266  {
13267  childbounds = childboundsstatic;
13268  childcurv = childcurvstatic;
13269  }
13270 
13271  /* assemble bounds and curvature of children */
13272  for( i = 0; i < monomial->nfactors; ++i )
13273  {
13274  child = node->children[monomial->childidxs[i]];
13275  assert(child != NULL);
13276 
13277  /* child should have valid and non-empty bounds */
13278  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13279  assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13280  /* nodes at depth 0 are always linear */
13281  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13282 
13283  childbounds[i] = child->bounds; /*lint !e644*/
13284  childcurv[i] = child->curv; /*lint !e644*/
13285  }
13286 
13287  /* check curvature */
13288  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13289  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13290 
13291  /* free memory, if allocated before */
13292 TERMINATE:
13293  if( childbounds != childboundsstatic )
13294  {
13295  BMSfreeMemoryArrayNull(&childbounds);
13296  BMSfreeMemoryArrayNull(&childcurv);
13297  }
13298 
13299  return retcode;
13300 }
13301 
13302 /** gives the user data belonging to a SCIP_EXPR_USER expression */
13304  SCIP_EXPRGRAPHNODE* node
13305  )
13306 {
13307  assert(node != NULL);
13308  assert(node->op == SCIP_EXPR_USER);
13309  assert(node->data.data != NULL);
13310 
13311  return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13312 }
13313 
13314 /** indicates whether a user expression has the estimator callback defined */
13316  SCIP_EXPRGRAPHNODE* node
13317  )
13318 {
13319  assert(node != NULL);
13320  assert(node->op == SCIP_EXPR_USER);
13321  assert(node->data.data != NULL);
13322 
13323  return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13324 }
13325 
13326 /** gets bounds of a node in an expression graph */
13328  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13329  )
13330 {
13331  assert(node != NULL);
13332 
13333  return node->bounds;
13334 }
13335 
13336 /** gets value of expression associated to node from last evaluation call */
13338  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13339  )
13340 {
13341  assert(node != NULL);
13342 
13343  return node->value;
13344 }
13345 
13346 /** gets curvature of expression associated to node from last curvature check call */
13348  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13349  )
13350 {
13351  assert(node != NULL);
13352 
13353  return node->curv;
13354 }
13355 
13356 /** creates an expression graph node */
13358  BMS_BLKMEM* blkmem, /**< block memory */
13359  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13360  SCIP_EXPROP op, /**< operator type of expression */
13361  ...
13362  )
13363 {
13364  va_list ap;
13365  SCIP_EXPROPDATA opdata;
13366 
13367  assert(blkmem != NULL);
13368  assert(node != NULL);
13369 
13370  *node = NULL;
13371 
13372  switch( op )
13373  {
13374  case SCIP_EXPR_VARIDX :
13375  case SCIP_EXPR_PARAM :
13376  case SCIP_EXPR_CONST :
13377  case SCIP_EXPR_LINEAR :
13378  case SCIP_EXPR_QUADRATIC :
13379  case SCIP_EXPR_POLYNOMIAL:
13380  case SCIP_EXPR_USER :
13381  {
13382  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
13383  SCIPABORT();
13384  return SCIP_ERROR; /*lint !e527*/
13385  }
13386 
13387  /* operands without data */
13388  case SCIP_EXPR_PLUS :
13389  case SCIP_EXPR_MINUS :
13390  case SCIP_EXPR_MUL :
13391  case SCIP_EXPR_DIV :
13392  case SCIP_EXPR_MIN :
13393  case SCIP_EXPR_MAX :
13394  case SCIP_EXPR_SQUARE :
13395  case SCIP_EXPR_SQRT :
13396  case SCIP_EXPR_EXP :
13397  case SCIP_EXPR_LOG :
13398  case SCIP_EXPR_SIN :
13399  case SCIP_EXPR_COS :
13400  case SCIP_EXPR_TAN :
13401  /* case SCIP_EXPR_ERF : */
13402  /* case SCIP_EXPR_ERFI: */
13403  case SCIP_EXPR_ABS :
13404  case SCIP_EXPR_SIGN :
13405  case SCIP_EXPR_SUM :
13406  case SCIP_EXPR_PRODUCT:
13407  opdata.data = NULL;
13408  break;
13409 
13410  case SCIP_EXPR_REALPOWER:
13411  case SCIP_EXPR_SIGNPOWER:
13412  {
13413  va_start(ap, op ); /*lint !e838*/
13414  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
13415  va_end( ap ); /*lint !e826*/
13416 
13417  break;
13418  }
13419 
13420  case SCIP_EXPR_INTPOWER:
13421  {
13422  va_start(ap, op ); /*lint !e838*/
13423  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
13424  va_end( ap ); /*lint !e826*/
13425 
13426  break;
13427  }
13428 
13429  case SCIP_EXPR_LAST:
13430  SCIPABORT();
13431  return SCIP_INVALIDDATA; /*lint !e527*/
13432  }
13433 
13434  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13435 
13436  return SCIP_OKAY;
13437 }
13438 
13439 /** creates an expression graph node for a linear expression */
13441  BMS_BLKMEM* blkmem, /**< block memory */
13442  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13443  int ncoefs, /**< number of coefficients */
13444  SCIP_Real* coefs, /**< coefficients of linear expression */
13445  SCIP_Real constant /**< constant of linear expression */
13446  )
13447 {
13448  SCIP_EXPROPDATA opdata;
13449  SCIP_Real* data;
13450 
13451  assert(blkmem != NULL);
13452  assert(node != NULL);
13453 
13454  /* we store the coefficients and the constant in a single array and make this our operand data */
13455  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13456  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
13457  data[ncoefs] = constant;
13458 
13459  opdata.data = data;
13460  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13461 
13462  return SCIP_OKAY;
13463 }
13464 
13465 /** creates an expression graph node for a quadratic expression */
13467  BMS_BLKMEM* blkmem, /**< block memory */
13468  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13469  int nchildren, /**< number of children */
13470  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
13471  int nquadelems, /**< number of quadratic elements */
13472  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
13473  SCIP_Real constant /**< constant */
13474  )
13475 {
13476  SCIP_EXPROPDATA opdata;
13478 
13479  assert(blkmem != NULL);
13480  assert(node != NULL);
13481  assert(quadelems != NULL || nquadelems == 0);
13482 
13483  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13484 
13485  opdata.data = data;
13486  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13487 
13488  return SCIP_OKAY;
13489 }
13490 
13491 /** creates an expression graph node for a polynomial expression */
13493  BMS_BLKMEM* blkmem, /**< block memory */
13494  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13495  int nmonomials, /**< number of monomials */
13496  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13497  SCIP_Real constant, /**< constant of polynomial */
13498  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13499  )
13500 {
13501  SCIP_EXPROPDATA opdata;
13503 
13504  assert(blkmem != NULL);
13505  assert(node != NULL);
13506  assert(monomials != NULL || nmonomials == 0);
13507 
13508  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13509 
13510  opdata.data = data;
13511  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13512 
13513  return SCIP_OKAY;
13514 }
13515 
13516 /** adds monomials to an expression graph node that is a polynomial expression */
13518  BMS_BLKMEM* blkmem, /**< block memory */
13519  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
13520  int nmonomials, /**< number of monomials */
13521  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13522  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13523  )
13524 {
13525  assert(blkmem != NULL);
13526  assert(node != NULL);
13528  assert(monomials != NULL || nmonomials == 0);
13529 
13530  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13531 
13532  return SCIP_OKAY;
13533 }
13534 
13535 /** creates an expression graph node for a user expression */
13537  BMS_BLKMEM* blkmem, /**< block memory */
13538  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13539  SCIP_USEREXPRDATA* data, /**< user data for expression, node assumes ownership */
13540  SCIP_EXPRINTCAPABILITY evalcapability, /**< evaluation capability */
13541  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
13542  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function */
13543  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
13544  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function */
13545  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13546  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13547  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
13548  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
13549  )
13550 {
13551  SCIP_EXPROPDATA opdata;
13552  SCIP_EXPRDATA_USER* exprdata;
13553 
13554  assert(blkmem != NULL);
13555  assert(node != NULL);
13556  assert(eval != NULL);
13557  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
13558  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13559  assert(copydata != NULL || data == NULL);
13560  assert(freedata != NULL || data == NULL);
13561 
13562  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13563 
13564  exprdata->userdata = data;
13565  exprdata->evalcapability = evalcapability;
13566  exprdata->eval = eval;
13567  exprdata->estimate = estimate;
13568  exprdata->inteval = inteval;
13569  exprdata->curv = curv;
13570  exprdata->prop = prop;
13571  exprdata->copydata = copydata;
13572  exprdata->freedata = freedata;
13573  exprdata->print = print;
13574 
13575  opdata.data = (void*) exprdata;
13576 
13577  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13578 
13579  return SCIP_OKAY;
13580 }
13581 
13582 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13583  *
13584  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13585  * If the node is a linear expression, it may be freed.
13586  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13587  * It is assumed that the user had captured the node.
13588  * It is assumed that the expression graph has been simplified before.
13589  */
13591  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13592  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
13593  int linvarssize, /**< length of linvars and lincoefs arrays */
13594  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
13595  void** linvars, /**< buffer to store variables of linear part */
13596  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
13597  SCIP_Real* constant /**< buffer to store constant part */
13598  )
13599 {
13600  int orignvars;
13601  int* varsusage;
13602  SCIP_EXPRGRAPHNODE* orignode;
13603  SCIP_Bool havechange;
13604  int i;
13605 
13606  assert(exprgraph != NULL);
13607  assert(node != NULL);
13608  assert(*node != NULL);
13609  assert((*node)->nuses > 0);
13610  assert(nlinvars != NULL);
13611  assert(linvars != NULL || linvarssize == 0);
13612  assert(lincoefs != NULL || linvarssize == 0);
13613  assert(constant != NULL);
13614 
13615  *constant = 0.0;
13616  *nlinvars = 0;
13617 
13618  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13619 
13620  /* do some obvious and easy cases */
13621  switch( (*node)->op )
13622  {
13623  case SCIP_EXPR_VARIDX:
13624  {
13625  if( linvarssize >= 1 )
13626  {
13627  *nlinvars = 1;
13628  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
13629  lincoefs[0] = 1.0; /*lint !e613*/
13630 
13631  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13632  }
13633  return SCIP_OKAY;
13634  }
13635 
13636  case SCIP_EXPR_CONST:
13637  {
13638  *constant = (*node)->data.dbl;
13639  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13640 
13641  return SCIP_OKAY;
13642  }
13643 
13644  case SCIP_EXPR_REALPOWER:
13645  case SCIP_EXPR_SIGNPOWER:
13646  {
13647  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13648  {
13649  *nlinvars = 1;
13650  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13651  lincoefs[0] = 1.0; /*lint !e613*/
13652 
13653  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13654  }
13655  return SCIP_OKAY;
13656  }
13657 
13658  case SCIP_EXPR_INTPOWER:
13659  {
13660  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13661  {
13662  *nlinvars = 1;
13663  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13664  lincoefs[0] = 1.0; /*lint !e613*/
13665 
13666  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13667  }
13668  return SCIP_OKAY;
13669  }
13670 
13671  case SCIP_EXPR_PLUS:
13672  {
13673  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13674  {
13675  *constant = (*node)->children[0]->data.dbl;
13676  *nlinvars = 1;
13677  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13678  lincoefs[0] = 1.0; /*lint !e613*/
13679 
13680  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13681 
13682  return SCIP_OKAY;
13683  }
13684  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13685  {
13686  *constant = (*node)->children[1]->data.dbl;
13687  *nlinvars = 1;
13688  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13689  lincoefs[0] = 1.0; /*lint !e613*/
13690 
13691  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13692 
13693  return SCIP_OKAY;
13694  }
13695  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13696  {
13697  *nlinvars = 2;
13698  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13699  lincoefs[0] = 1.0; /*lint !e613*/
13700  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13701  lincoefs[1] = 1.0; /*lint !e613*/
13702 
13703  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13704 
13705  return SCIP_OKAY;
13706  }
13707  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13708  {
13709  /* handle this one later */
13710  break;
13711  }
13712  return SCIP_OKAY;
13713  }
13714 
13715  case SCIP_EXPR_MINUS:
13716  {
13717  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13718  {
13719  *constant = (*node)->children[0]->data.dbl;
13720  *nlinvars = 1;
13721  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13722  lincoefs[0] = -1.0; /*lint !e613*/
13723 
13724  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13725 
13726  return SCIP_OKAY;
13727  }
13728  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13729  {
13730  *constant = -(*node)->children[1]->data.dbl;
13731  *nlinvars = 1;
13732  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13733  lincoefs[0] = 1.0; /*lint !e613*/
13734 
13735  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13736 
13737  return SCIP_OKAY;
13738  }
13739  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13740  {
13741  *nlinvars = 2;
13742  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13743  lincoefs[0] = 1.0; /*lint !e613*/
13744  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13745  lincoefs[1] = -1.0; /*lint !e613*/
13746 
13747  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13748 
13749  return SCIP_OKAY;
13750  }
13751  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13752  {
13753  /* handle this one later */
13754  break;
13755  }
13756  return SCIP_OKAY;
13757  }
13758 
13759  case SCIP_EXPR_MUL:
13760  {
13761  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13762  {
13763  *nlinvars = 1;
13764  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13765  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
13766 
13767  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13768  }
13769  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13770  {
13771  *nlinvars = 1;
13772  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13773  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
13774 
13775  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13776  }
13777  return SCIP_OKAY;
13778  }
13779 
13780  case SCIP_EXPR_DIV:
13781  {
13782  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13783  return SCIP_OKAY;
13784 
13785  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13786  {
13787  *nlinvars = 1;
13788  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13789  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
13790 
13791  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13792  }
13793  return SCIP_OKAY;
13794  }
13795 
13796  case SCIP_EXPR_SQUARE:
13797  case SCIP_EXPR_SQRT:
13798  case SCIP_EXPR_EXP:
13799  case SCIP_EXPR_LOG:
13800  case SCIP_EXPR_SIN:
13801  case SCIP_EXPR_COS:
13802  case SCIP_EXPR_TAN:
13803  /* case SCIP_EXPR_ERF: */
13804  /* case SCIP_EXPR_ERFI: */
13805  case SCIP_EXPR_ABS:
13806  case SCIP_EXPR_SIGN:
13807  case SCIP_EXPR_MIN:
13808  case SCIP_EXPR_MAX:
13809  return SCIP_OKAY;
13810 
13811  case SCIP_EXPR_PRODUCT:
13812  case SCIP_EXPR_USER:
13813  return SCIP_OKAY;
13814 
13815  case SCIP_EXPR_SUM:
13816  case SCIP_EXPR_LINEAR:
13817  case SCIP_EXPR_QUADRATIC:
13818  case SCIP_EXPR_POLYNOMIAL:
13819  default:
13820  {
13821  /* check if there is a child that is a variable */
13822  for( i = 0; i < (*node)->nchildren; ++i )
13823  {
13824  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13825  break;
13826  }
13827 
13828  if( i == (*node)->nchildren )
13829  return SCIP_OKAY;
13830 
13831  break;
13832  }
13833  } /*lint !e788*/
13834 
13835  /* count how often variables are used in this expression */
13836  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13837  orignvars = exprgraph->nvars;
13838  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13839  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
13840 
13841  exprgraphNodeGetVarsUsage(*node, varsusage);
13842 
13843  /* duplicate node if it has parents or more than one user */
13844  orignode = NULL;
13845  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13846  {
13847  SCIP_EXPROPDATA data;
13848 
13849  orignode = *node;
13850 
13851  if( exprOpTable[orignode->op].copydata != NULL )
13852  {
13853  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13854  }
13855  else
13856  data = orignode->data;
13857 
13858  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13859  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13860  SCIPexprgraphCaptureNode(*node);
13861  }
13862 
13863  havechange = FALSE;
13864  /* split up constant and linear part */
13865  switch( (*node)->op )
13866  {
13867  case SCIP_EXPR_PLUS:
13868  case SCIP_EXPR_MINUS:
13869  {
13870  SCIP_EXPRGRAPHNODE* varchild;
13871  SCIP_EXPRGRAPHNODE* otherchild;
13872  int varidx;
13873 
13874  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13875  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13876  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13877  assert(linvarssize >= 1);
13878 
13879  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13880  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13881  varidx = varchild->data.intval;
13882  /* if variable is used in other child (which should be nonlinear), we don't take it */
13883  if( varsusage[varidx] > 1 )
13884  break;
13885 
13886  /* add to linear variables */
13887  *nlinvars = 1;
13888  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13889  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13890  lincoefs[0] = -1.0; /*lint !e613*/
13891  else
13892  lincoefs[0] = 1.0; /*lint !e613*/
13893 
13894  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13895  {
13896  /* replace *node by otherchild */
13897  SCIPexprgraphCaptureNode(otherchild);
13898  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13899  *node = otherchild;
13900  }
13901  else
13902  {
13903  SCIP_Real* lindata;
13904 
13905  /* turn *node into linear expression -1.0 * otherchild */
13906 
13907  /* reduce to one child */
13908  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13909  (*node)->children[0] = otherchild;
13910  (*node)->nchildren = 1;
13911  (*node)->op = SCIP_EXPR_LINEAR;
13912 
13913  /* setup linear data -1.0 * child0 + 0.0 */
13914  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13915  lindata[0] = -1.0;
13916  lindata[1] = 0.0;
13917  (*node)->data.data = (void*)lindata;
13918 
13919  /* remove *node as parent of varchild */
13920  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13921  }
13922 
13923  havechange = TRUE;
13924 
13925  break;
13926  }
13927 
13928  case SCIP_EXPR_SUM:
13929  {
13930  int nchildren;
13931 
13932  i = 0;
13933  nchildren = (*node)->nchildren;
13934  while( i < nchildren )
13935  {
13936  /* sort out constants */
13937  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13938  {
13939  *constant += (*node)->children[i]->data.dbl;
13940  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13941 
13942  if( i < nchildren-1 )
13943  {
13944  (*node)->children[i] = (*node)->children[nchildren-1];
13945  (*node)->children[nchildren-1] = NULL;
13946  }
13947  --nchildren;
13948 
13949  continue;
13950  }
13951 
13952  /* keep every child that is not a constant or variable */
13953  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13954  {
13955  ++i;
13956  continue;
13957  }
13958 
13959  /* skip variables that are used in other parts of the expression */
13960  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13961  {
13962  ++i;
13963  continue;
13964  }
13965 
13966  /* move variable into linear part, if still space */
13967  if( *nlinvars < linvarssize )
13968  {
13969  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13970  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13971  ++*nlinvars;
13972 
13973  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13974  if( i < nchildren-1 )
13975  {
13976  (*node)->children[i] = (*node)->children[nchildren-1];
13977  (*node)->children[nchildren-1] = NULL;
13978  }
13979  --nchildren;
13980 
13981  continue;
13982  }
13983  }
13984  assert(i == nchildren);
13985 
13986  if( nchildren == 0 )
13987  {
13988  /* all children were removed */
13989  havechange = TRUE;
13990  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13991  (*node)->nchildren = 0;
13992  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13993  break;
13994  }
13995 
13996  if( nchildren < (*node)->nchildren )
13997  {
13998  /* some children were removed */
13999  havechange = TRUE;
14000  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14001  (*node)->nchildren = nchildren;
14002  }
14003 
14004  if( havechange && (*node)->nchildren == 1 )
14005  {
14006  /* replace node by its child */
14007  SCIP_EXPRGRAPHNODE* child;
14008 
14009  child = (*node)->children[0];
14010  SCIPexprgraphCaptureNode(child);
14011  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14012  *node = child;
14013 
14014  break;
14015  }
14016 
14017  break;
14018  }
14019 
14020  case SCIP_EXPR_LINEAR:
14021  {
14022  int nchildren;
14023  SCIP_Real* coefs;
14024 
14025  coefs = (SCIP_Real*)(*node)->data.data;
14026  assert(coefs != NULL);
14027 
14028  /* remove constant, if nonzero */
14029  if( coefs[(*node)->nchildren] != 0.0 )
14030  {
14031  *constant = coefs[(*node)->nchildren];
14032  coefs[(*node)->nchildren] = 0.0;
14033  havechange = TRUE;
14034  }
14035 
14036  i = 0;
14037  nchildren = (*node)->nchildren;
14038  while( i < nchildren )
14039  {
14040  /* sort out constants */
14041  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
14042  {
14043  *constant += coefs[i] * (*node)->children[i]->data.dbl;
14044  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14045 
14046  if( i < nchildren-1 )
14047  {
14048  (*node)->children[i] = (*node)->children[nchildren-1];
14049  (*node)->children[nchildren-1] = NULL;
14050  coefs[i] = coefs[nchildren-1];
14051  coefs[nchildren-1] = 0.0;
14052  }
14053  --nchildren;
14054 
14055  continue;
14056  }
14057 
14058  /* keep everything that is not a constant or variable */
14059  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14060  {
14061  ++i;
14062  continue;
14063  }
14064 
14065  /* skip variables that are used in other parts of the expression */
14066  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14067  {
14068  ++i;
14069  continue;
14070  }
14071 
14072  /* move variable into linear part, if still space */
14073  if( *nlinvars < linvarssize )
14074  {
14075  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14076  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
14077  ++*nlinvars;
14078 
14079  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14080  if( i < nchildren-1 )
14081  {
14082  (*node)->children[i] = (*node)->children[nchildren-1];
14083  (*node)->children[nchildren-1] = NULL;
14084  coefs[i] = coefs[nchildren-1];
14085  coefs[nchildren-1] = 0.0;
14086  }
14087  --nchildren;
14088 
14089  continue;
14090  }
14091  }
14092  assert(i == nchildren);
14093 
14094  if( nchildren == 0 )
14095  {
14096  /* all children were removed */
14097  havechange = TRUE;
14098  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14099  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
14100  (*node)->data.data = NULL;
14101  (*node)->nchildren = 0;
14102  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
14103  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14104  break;
14105  }
14106 
14107  if( nchildren < (*node)->nchildren )
14108  {
14109  /* some children were removed */
14110  havechange = TRUE;
14111  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14112  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
14113  coefs[nchildren] = 0.0;
14114  (*node)->data.data = (void*)coefs;
14115  (*node)->nchildren = nchildren;
14116  }
14117 
14118  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
14119  {
14120  /* replace node by its child */
14121  SCIP_EXPRGRAPHNODE* child;
14122 
14123  child = (*node)->children[0];
14124  SCIPexprgraphCaptureNode(child);
14125  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14126  *node = child;
14127 
14128  break;
14129  }
14130 
14131  break;
14132  }
14133 
14134  case SCIP_EXPR_QUADRATIC:
14135  {
14136  SCIP_EXPRDATA_QUADRATIC* quaddata;
14137  SCIP_Bool* childused;
14138  int* childmap;
14139  int nchildren;
14140 
14141  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
14142  assert(quaddata != NULL);
14143 
14144  /* remove constant, if nonzero */
14145  if( quaddata->constant != 0.0 )
14146  {
14147  *constant = quaddata->constant;
14148  quaddata->constant = 0.0;
14149  havechange = TRUE;
14150  }
14151 
14152  /* if there is no linear part or no space left for linear variables, then stop */
14153  if( quaddata->lincoefs != NULL || linvarssize == 0 )
14154  break;
14155 
14156  /* check which childs are used in quadratic terms */
14157  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14158  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14159 
14160  for( i = 0; i < quaddata->nquadelems; ++i )
14161  {
14162  childused[quaddata->quadelems[i].idx1] = TRUE;
14163  childused[quaddata->quadelems[i].idx2] = TRUE;
14164  }
14165 
14166  /* alloc space for mapping of children indices */
14167  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
14168 
14169  nchildren = (*node)->nchildren;
14170  for( i = 0; i < nchildren; ++i )
14171  {
14172  childmap[i] = i; /*lint !e644*/
14173  if( *nlinvars >= linvarssize )
14174  continue;
14175  /* skip child if not variable or also used in quadratic part or other parts of expression */
14176  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14177  continue;
14178  if( childused[i] )
14179  continue;
14180  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14181  continue;
14182 
14183  /* put variable into linear part */
14184  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14185  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
14186  quaddata->lincoefs[i] = 0.0;
14187  ++*nlinvars;
14188 
14189  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14190 
14191  /* move last child to position i */
14192  if( i < nchildren-1 )
14193  {
14194  (*node)->children[i] = (*node)->children[nchildren-1];
14195  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
14196  childused[i] = childused[nchildren-1];
14197  childmap[nchildren-1] = i;
14198  }
14199  --nchildren;
14200  childmap[i] = -1;
14201 
14202  havechange = TRUE;
14203  --i; /* look at i again */
14204  }
14205 
14206  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
14207 
14208  if( nchildren < (*node)->nchildren )
14209  {
14210  /* apply childmap to quadratic term */
14211  for( i = 0; i < quaddata->nquadelems; ++i )
14212  {
14213  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
14214  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
14215  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
14216  {
14217  int tmp;
14218  tmp = quaddata->quadelems[i].idx1;
14219  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
14220  quaddata->quadelems[i].idx2 = tmp;
14221  }
14222  }
14223  quaddata->sorted = FALSE;
14224  }
14225  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
14226 
14227  if( nchildren == 0 )
14228  {
14229  /* all children were removed (so it was actually a linear expression) */
14230  havechange = TRUE;
14231  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14232  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
14233  (*node)->data.data = NULL;
14234  (*node)->nchildren = 0;
14235  (*node)->op = SCIP_EXPR_SUM;
14236  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14237  break;
14238  }
14239 
14240  if( nchildren < (*node)->nchildren )
14241  {
14242  /* reduce number of children */
14243  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14244  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
14245  (*node)->nchildren = nchildren;
14246  }
14247 
14248  break;
14249  }
14250 
14251  case SCIP_EXPR_POLYNOMIAL:
14252  {
14253  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
14254  SCIP_EXPRDATA_MONOMIAL* monomial;
14255  SCIP_Bool* childused;
14256  int childidx;
14257  int j;
14258 
14259  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
14260  assert(polynomialdata != NULL);
14261 
14262  /* make sure linear monomials are merged */
14263  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14264 
14265  /* remove constant, if nonzero */
14266  if( polynomialdata->constant != 0.0 )
14267  {
14268  *constant = polynomialdata->constant;
14269  polynomialdata->constant = 0.0;
14270  havechange = TRUE;
14271  }
14272 
14273  /* if there is no space for linear variables, then stop */
14274  if( linvarssize == 0 )
14275  break;
14276 
14277  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14278  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14279  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14280  for( i = 0; i < polynomialdata->nmonomials; ++i )
14281  {
14282  monomial = polynomialdata->monomials[i];
14283  assert(monomial != NULL);
14284  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14285  continue;
14286  for( j = 0; j < monomial->nfactors; ++j )
14287  {
14288  assert(monomial->childidxs[j] >= 0);
14289  assert(monomial->childidxs[j] < (*node)->nchildren);
14290  childused[monomial->childidxs[j]] = TRUE;
14291  }
14292  }
14293 
14294  /* move linear monomials out of polynomial */
14295  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14296  {
14297  monomial = polynomialdata->monomials[i];
14298  assert(monomial != NULL);
14299 
14300  /* sort out constants */
14301  if( monomial->nfactors == 0 )
14302  {
14303  if( monomial->coef != 0.0 )
14304  {
14305  *constant += monomial->coef;
14306  havechange = TRUE;
14307  }
14308  continue;
14309  }
14310 
14311  if( monomial->nfactors != 1 )
14312  continue;
14313  if( monomial->exponents[0] != 1.0 )
14314  continue;
14315  childidx = monomial->childidxs[0];
14316  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14317  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14318  continue;
14319  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14320  continue;
14321 
14322  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14323 
14324  /* put variable into linear part */
14325  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
14326  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
14327  ++*nlinvars;
14328 
14329  monomial->coef = 0.0;
14330  monomial->nfactors = 0;
14331  polynomialdata->sorted = FALSE;
14332 
14333  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14334  (*node)->children[childidx] = NULL;
14335 
14336  havechange = TRUE;
14337  }
14338 
14339  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14340 
14341  if( *nlinvars > 0 )
14342  {
14343  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14344  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14346  }
14347 
14348  if( (*node)->nchildren == 0 )
14349  {
14350  assert(polynomialdata->nmonomials == 0);
14351  assert(polynomialdata->constant == 0.0);
14352  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14353  havechange = TRUE;
14354  break;
14355  }
14356 
14357  break;
14358  }
14359 
14360  default: ;
14361  } /*lint !e788*/
14362 
14363  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14364 
14365  if( orignode != NULL )
14366  {
14367  /* if node was duplicated, we need to forget about original or duplicate */
14368  if( !havechange )
14369  {
14370  /* if nothing has changed, then forget about duplicate */
14371  assert(*constant == 0.0);
14372  assert(*nlinvars == 0);
14373  assert(*node != NULL);
14374  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14375  *node = orignode;
14376  }
14377  else
14378  {
14379  /* if something changed, then release original node */
14380  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14381  }
14382  }
14383  else if( havechange && *node != NULL )
14384  {
14385  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14386  (*node)->value = SCIP_INVALID;
14387  (*node)->simplified = FALSE;
14388  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14389  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14390  exprgraph->needvarboundprop = TRUE;
14391  }
14392 
14393  return SCIP_OKAY;
14394 }
14395 
14396 /** moves parents from a one node to another node
14397  *
14398  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14399  * srcnode may be freed, if not captured.
14400  * It is assumed that targetnode represents the same expression as srcnode.
14401  */
14403  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14404  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
14405  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
14406  )
14407 {
14408  assert(exprgraph != NULL);
14409  assert(srcnode != NULL);
14410  assert(*srcnode != NULL);
14411  assert(targetnode != NULL);
14412 
14413  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14414  {
14415  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14416  {
14417  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14418  }
14419  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14420  }
14421  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14422 
14423  return SCIP_OKAY;
14424 }
14425 
14426 /** releases node, i.e., decreases number of uses
14427  *
14428  * node is freed if no parents and no other uses.
14429  * Children are recursively released if they have no other parents.
14430  * Nodes that are removed are also freed.
14431  * If node correspond to a variable, then the variable is removed from the expression graph;
14432  * similarly for constants.
14433  */
14435  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14436  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
14437  )
14438 {
14439  int i;
14440 
14441  assert(exprgraph != NULL);
14442  assert(node != NULL);
14443  assert(*node != NULL);
14444  assert((*node)->depth >= 0); /* node should be in graph */
14445  assert((*node)->pos >= 0); /* node should be in graph */
14446  assert((*node)->depth < exprgraph->depth);
14447  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14448  assert((*node)->nuses >= 1);
14449  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14450 
14451  SCIPdebugMessage("release node %p\n", (void*)*node);
14452 
14453  --(*node)->nuses;
14454 
14455  /* do nothing if node still has parents or is still in use */
14456  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14457  {
14458  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);
14459  *node = NULL;
14460  return SCIP_OKAY;
14461  }
14462 
14463  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14464 
14465  /* notify children about removal of its parent
14466  * they are also freed, if possible */
14467  for( i = 0; i < (*node)->nchildren; ++i )
14468  {
14469  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14470  (*node)->children[i] = NULL;
14471  }
14472 
14473  if( (*node)->op == SCIP_EXPR_VARIDX )
14474  {
14475  assert((*node)->depth == 0);
14476  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14477  }
14478  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14479  {
14480  int constidx;
14481 
14482  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14483  assert(constidx >= 0);
14484  assert(constidx < exprgraph->nconsts);
14485  assert(exprgraph->constnodes[constidx] == *node);
14486 
14487  /* move last constant to position constidx */
14488  if( constidx < exprgraph->nconsts-1 )
14489  {
14490  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14491  exprgraph->constssorted = (exprgraph->nconsts <= 2);
14492  }
14493  --exprgraph->nconsts;
14494  }
14495  else
14496  {
14497  /* only variables and constants are allowed at depth 0 */
14498  assert((*node)->depth > 0);
14499  }
14500 
14501  /* remove node from nodes array in expression graph */
14502  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14503  {
14504  /* move last node at depth of *node to position of *node */
14505  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14506  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14507 
14508  /* moving the node may change the order in the parents array of each child */
14509  for( i = 0; i < exprgraph->nodes[(*node)->depth][(*node)->pos]->nchildren; ++i )
14510  exprgraph->nodes[(*node)->depth][(*node)->pos]->children[i]->parentssorted = FALSE;
14511  }
14512  --exprgraph->nnodes[(*node)->depth];
14513 
14514  /* node is now not in graph anymore */
14515  (*node)->depth = -1;
14516  (*node)->pos = -1;
14517 
14518  /* free node */
14519  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14520 
14521  *node = NULL;
14522 
14523  return SCIP_OKAY;
14524 }
14525 
14526 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14527 /** frees a node of an expression graph */
14529  BMS_BLKMEM* blkmem, /**< block memory */
14530  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
14531  )
14532 {
14533  assert(blkmem != NULL);
14534  assert( node != NULL);
14535  assert(*node != NULL);
14536  assert((*node)->depth == -1); /* node should not be in graph anymore */
14537  assert((*node)->pos == -1); /* node should not be in graph anymore */
14538  assert((*node)->nuses == 0); /* node should not be in use */
14539 
14540  /* free operator data, if needed */
14541  if( exprOpTable[(*node)->op].freedata != NULL )
14542  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14543 
14544  /* free arrays of children and parent nodes */
14545  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14546  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
14547 
14548  /* free node struct */
14549  BMSfreeBlockMemory(blkmem, node);
14550 }
14551 
14552 /** enables a node and recursively all its children in an expression graph */
14554  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14555  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14556  )
14557 {
14558  int i;
14559 
14560  assert(exprgraph != NULL);
14561  assert(node != NULL);
14562  assert(node->depth >= 0);
14563  assert(node->pos >= 0);
14564 
14565  if( node->enabled )
14566  return;
14567 
14568  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14569 
14570  node->enabled = TRUE;
14571  for( i = 0; i < node->nchildren; ++i )
14572  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14573 
14574  /* make sure bounds are updated in next bound propagation round */
14575  SCIPintervalSetEntire(SCIP_REAL_MAX, &node->bounds);
14576  exprgraph->needvarboundprop = TRUE;
14577 }
14578 
14579 /** disables a node and recursively all children which have no enabled parents in an expression graph */
14581  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14582  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14583  )
14584 {
14585  int i;
14586 
14587  assert(exprgraph != NULL);
14588  assert(node != NULL);
14589  assert(node->depth >= 0);
14590  assert(node->pos >= 0);
14591 
14592  if( !node->enabled )
14593  return;
14594 
14595  /* workaround: don't disable nodes if there could be more users than the one who is disabling the node
14596  * otherwise, if there are several nonlinear constraints using the same expression graph node as root node,
14597  * we might get enabled constraints with disabled node
14598  */
14599  if( node->nuses > 1 )
14600  return;
14601 
14602  /* if all parents of node are disabled, then also node can be disabled */
14603  node->enabled = FALSE;
14604  for( i = 0; i < node->nparents; ++i )
14605  if( node->parents[i]->enabled )
14606  {
14607  node->enabled = TRUE;
14608  return;
14609  }
14610 
14611  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14612 
14613  for( i = 0; i < node->nchildren; ++i )
14614  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14615 }
14616 
14617 /** returns whether the node has siblings in the expression graph */
14619  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14620  )
14621 {
14622  int p;
14623 
14624  assert(node != NULL);
14625 
14626  for( p = 0; p < node->nparents; ++p )
14627  if( node->parents[p]->nchildren > 1 )
14628  return TRUE;
14629 
14630  return FALSE;
14631 }
14632 
14633 /** returns whether all children of an expression graph node are variable nodes
14634  *
14635  * Returns TRUE for nodes without children.
14636  */
14638  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14639  )
14640 {
14641  int i;
14642 
14643  assert(node != NULL);
14644 
14645  for( i = 0; i < node->nchildren; ++i )
14646  if( node->children[i]->op != SCIP_EXPR_VARIDX )
14647  return FALSE;
14648 
14649  return TRUE;
14650 }
14651 
14652 /** returns whether the node has an ancestor which has a nonlinear expression operand */
14654  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14655  )
14656 {
14657  int p;
14658 
14659  for( p = 0; p < node->nparents; ++p )
14660  {
14661  assert(node->parents[p]->depth > node->depth);
14662  switch( node->parents[p]->op )
14663  {
14664  case SCIP_EXPR_PLUS:
14665  case SCIP_EXPR_MINUS:
14666  case SCIP_EXPR_SUM:
14667  case SCIP_EXPR_LINEAR:
14669  return TRUE;
14670  break;
14671 
14672 #ifndef NDEBUG
14673  case SCIP_EXPR_VARIDX:
14674  case SCIP_EXPR_CONST:
14675  case SCIP_EXPR_PARAM:
14676  assert(0); /* these expressions cannot have children */
14677  break;
14678 #endif
14679 
14680  default:
14681  /* parent has nonlinear expression operand */
14682  return TRUE;
14683  }/*lint !e788*/
14684  }
14685 
14686  return FALSE;
14687 }
14688 
14689 /** prints an expression graph node */
14691  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14692  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14693  FILE* file /**< file to print to, or NULL for stdout */
14694  )
14695 {
14696  assert(node != NULL);
14697 
14698  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14699 }
14700 
14701 /** tightens the bounds in a node of the graph
14702  *
14703  * Preparation for reverse propagation.
14704  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14705  */
14707  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14708  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
14709  SCIP_INTERVAL nodebounds, /**< new bounds for node */
14710  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) */
14711  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14712  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14713  )
14714 {
14715  assert(exprgraph != NULL);
14716  assert(node != NULL);
14717  assert(node->depth >= 0);
14718  assert(node->pos >= 0);
14719  assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14720  assert(cutoff != NULL);
14721 
14722  *cutoff = FALSE;
14723 
14724  /* if node is disabled, then ignore new bounds */
14725  if( !node->enabled )
14726  {
14727  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14728  return;
14729  }
14730 
14731  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14732  (void*)node, node->depth, node->pos,
14733  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14734 
14735  /* bounds in node should be valid */
14736  assert(!(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
14737 
14738  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14739  {
14740  *cutoff = TRUE;
14741  SCIPdebugPrintf(" -> cutoff\n");
14742  return;
14743  }
14744 
14745  /* if minstrength is negative, always mark that node has recently tightened bounds,
14746  * if bounds are considerably improved or tightening leads to an empty interval,
14747  * mark that node has recently tightened bounds
14748  * if bounds are only slightly improved, set the status to tightened by parent,
14749  * so next propagateVarBound round will reset the bounds
14750  */
14751  if( minstrength < 0.0 )
14752  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE;
14753  else if(
14754  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14755  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14756  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT;
14757  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14758  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT;
14759 
14760  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14761  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14762 }
14763 
14764 /** ensures that bounds and curvature information in a node is uptodate
14765  *
14766  * Assumes that bounds and curvature in children are uptodate.
14767  */
14769  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14770  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14771  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14772  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14773  )
14774 {
14775  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14776  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14777  SCIP_INTERVAL* childbounds = NULL;
14778  SCIP_EXPRCURV* childcurv = NULL;
14779  SCIP_RETCODE retcode = SCIP_OKAY;
14780  int i;
14781 
14782  assert(node != NULL);
14783  assert(node->depth >= 0); /* node should be in graph */
14784  assert(node->pos >= 0); /* node should be in graph */
14785  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14786 
14787  if( node->depth == 0 )
14788  {
14789  /* we cannot update bound tightenings in variable nodes here */
14790  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14791  return SCIP_OKAY;
14792  }
14793 
14794  assert(node->op != SCIP_EXPR_VARIDX);
14795  assert(node->op != SCIP_EXPR_PARAM);
14796 
14797  /* if many children, get large enough memory to store children bounds */
14799  {
14800  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14801  SCIP_ALLOC_TERMINATE(retcode, BMSallocMemoryArray(&childcurv, node->nchildren), TERMINATE);
14802  }
14803  else
14804  {
14805  childbounds = childboundsstatic;
14806  childcurv = childcurvstatic;
14807  }
14808 
14809  /* assemble bounds and curvature of children */
14810  for( i = 0; i < node->nchildren; ++i )
14811  {
14812  /* child should have valid and non-empty bounds */
14814  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14815  /* nodes at depth 0 are always linear */
14816  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14817 
14818  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
14819  childcurv[i] = node->children[i]->curv; /*lint !e644*/
14820  }
14821 
14822  /* if we do not have valid bounds, then update
14823  * code below is copied from exprgraphNodeUpdateBounds */
14825  {
14826  SCIP_INTERVAL newbounds;
14827 
14828  /* calling interval evaluation function for this operand */
14829  assert( exprOpTable[node->op].inteval != NULL );
14830  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds), TERMINATE );
14831 
14832  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14833  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14834  *
14835  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14836  *
14837  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14838  */
14839  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14841  {
14842  for( i = 0; i < node->nparents; ++i )
14844 
14845  node->bounds = newbounds;
14846  }
14847  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14848  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14849  {
14850  for( i = 0; i < node->nparents; ++i )
14852 
14853  node->bounds = newbounds;
14854  }
14855  else
14856  {
14857  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14858  }
14859 
14860  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);
14861 
14862  /* node now has valid bounds */
14863  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
14864  }
14865 
14866  /* update curvature */
14867  if( SCIPintervalIsEmpty(infinity, node->bounds) )
14868  {
14869  node->curv = SCIP_EXPRCURV_LINEAR;
14870 
14871  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14872  }
14873  else
14874  {
14875  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv), TERMINATE );
14876 
14877  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14878  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14879  * SCIPdebugPrintf("\n");
14880  */
14881  }
14882 TERMINATE:
14883  /* free memory, if allocated before */
14884  if( childbounds != childboundsstatic )
14885  {
14886  BMSfreeMemoryArrayNull(&childbounds);
14887  BMSfreeMemoryArrayNull(&childcurv);
14888  }
14889 
14890  return retcode;
14891 }
14892 
14893 /**@} */
14894 
14895 /**@name Expression graph methods */
14896 /**@{ */
14897 
14898 /* In debug mode, the following methods are implemented as function calls to ensure
14899  * type validity.
14900  * In optimized mode, the methods are implemented as defines to improve performance.
14901  * However, we want to have them in the library anyways, so we have to undef the defines.
14902  */
14903 
14904 #undef SCIPexprgraphGetDepth
14905 #undef SCIPexprgraphGetNNodes
14906 #undef SCIPexprgraphGetNodes
14907 #undef SCIPexprgraphGetNVars
14908 #undef SCIPexprgraphGetVars
14909 #undef SCIPexprgraphGetVarNodes
14910 #undef SCIPexprgraphSetVarNodeValue
14911 #undef SCIPexprgraphSetVarsBounds
14912 #undef SCIPexprgraphSetVarBounds
14913 #undef SCIPexprgraphSetVarNodeBounds
14914 #undef SCIPexprgraphSetVarNodeLb
14915 #undef SCIPexprgraphSetVarNodeUb
14916 #undef SCIPexprgraphGetVarsBounds
14917 
14918 /** get current maximal depth of expression graph */
14920  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14921  )
14922 {
14923  assert(exprgraph != NULL);
14924 
14925  return exprgraph->depth;
14926 }
14927 
14928 /** gets array with number of nodes at each depth of expression graph */
14930  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14931  )
14932 {
14933  assert(exprgraph != NULL);
14934 
14935  return exprgraph->nnodes;
14936 }
14937 
14938 /** gets nodes of expression graph, one array per depth */
14940  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14941  )
14942 {
14943  assert(exprgraph != NULL);
14944 
14945  return exprgraph->nodes;
14946 }
14947 
14948 /** gets number of variables in expression graph */
14950  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14951  )
14952 {
14953  assert(exprgraph != NULL);
14954 
14955  return exprgraph->nvars;
14956 }
14957 
14958 /** gets array of variables in expression graph */
14960  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14961  )
14962 {
14963  assert(exprgraph != NULL);
14964 
14965  return exprgraph->vars;
14966 }
14967 
14968 /** gets array of expression graph nodes corresponding to variables */
14970  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14971  )
14972 {
14973  assert(exprgraph != NULL);
14974 
14975  return exprgraph->varnodes;
14976 }
14977 
14978 /** sets value for a single variable given as expression graph node */
14980  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14981  SCIP_Real value /**< new value for variable */
14982  )
14983 {
14984  assert(varnode != NULL);
14985  assert(varnode->op == SCIP_EXPR_VARIDX);
14986 
14987  varnode->value = value;
14988 }
14989 
14990 /** sets bounds for variables */
14992  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14993  SCIP_INTERVAL* varbounds /**< new bounds for variables */
14994  )
14995 {
14996  assert(exprgraph != NULL);
14997  assert(varbounds != NULL || exprgraph->nvars == 0);
14998 
14999  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
15000 }
15001 
15002 /** sets bounds for a single variable */
15004  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15005  void* var, /**< variable */
15006  SCIP_INTERVAL varbounds /**< new bounds of variable */
15007  )
15008 {
15009  int pos;
15010 
15011  assert(exprgraph != NULL);
15012  assert(var != NULL);
15013  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15014 
15015  pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15016  assert(pos < exprgraph->nvars);
15017  assert(exprgraph->vars[pos] == var);
15018 
15019  exprgraph->varbounds[pos] = varbounds;
15020 }
15021 
15022 /** sets bounds for a single variable given as expression graph node */
15024  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15025  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15026  SCIP_INTERVAL varbounds /**< new bounds of variable */
15027  )
15028 {
15029  int pos;
15030 
15031  assert(exprgraph != NULL);
15032  assert(varnode != NULL);
15033 
15034  pos = varnode->data.intval;
15035  assert(pos >= 0);
15036  assert(pos < exprgraph->nvars);
15037  assert(exprgraph->varnodes[pos] == varnode);
15038 
15039  exprgraph->varbounds[pos] = varbounds;
15040 }
15041 
15042 /** sets lower bound for a single variable given as expression graph node */
15044  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15045  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15046  SCIP_Real lb /**< new lower bound for variable */
15047  )
15048 {
15049  int pos;
15050 
15051  assert(exprgraph != NULL);
15052  assert(varnode != NULL);
15053 
15054  pos = varnode->data.intval;
15055  assert(pos >= 0);
15056  assert(pos < exprgraph->nvars);
15057  assert(exprgraph->varnodes[pos] == varnode);
15058 
15059  exprgraph->varbounds[pos].inf = lb;
15060 }
15061 
15062 /** sets upper bound for a single variable given as expression graph node */
15064  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15065  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15066  SCIP_Real ub /**< new upper bound for variable */
15067  )
15068 {
15069  int pos;
15070 
15071  assert(exprgraph != NULL);
15072  assert(varnode != NULL);
15073 
15074  pos = varnode->data.intval;
15075  assert(pos >= 0);
15076  assert(pos < exprgraph->nvars);
15077  assert(exprgraph->varnodes[pos] == varnode);
15078 
15079  exprgraph->varbounds[pos].sup = ub;
15080 }
15081 
15082 /** gets bounds that are stored for all variables */
15084  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
15085  )
15086 {
15087  return exprgraph->varbounds;
15088 }
15089 
15090 /** creates an empty expression graph */
15092  BMS_BLKMEM* blkmem, /**< block memory */
15093  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
15094  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
15095  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
15096  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /**< callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
15097  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /**< callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
15098  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /**< callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
15099  void* userdata /**< user data to pass to callback functions */
15100  )
15101 {
15102  assert(blkmem != NULL);
15103  assert(exprgraph != NULL);
15104 
15105  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
15106  BMSclearMemory(*exprgraph);
15107  (*exprgraph)->blkmem = blkmem;
15108 
15109  /* create nodes's arrays */
15110  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
15111  assert((*exprgraph)->depth >= 1);
15112 
15113  /* create var's arrays and hashmap */
15114  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
15115  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, (*exprgraph)->varssize) );
15116 
15117  /* empty array of constants is sorted */
15118  (*exprgraph)->constssorted = TRUE;
15119 
15120  /* store callback functions and user data */
15121  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
15122  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
15123  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
15124  (*exprgraph)->userdata = userdata;
15125 
15126  return SCIP_OKAY;
15127 }
15128 
15129 /** frees an expression graph */
15131  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
15132  )
15133 {
15134  BMS_BLKMEM* blkmem;
15135  int d;
15136 
15137  assert( exprgraph != NULL);
15138  assert(*exprgraph != NULL);
15139  assert((*exprgraph)->nvars == 0);
15140  assert((*exprgraph)->nconsts == 0);
15141 
15142  blkmem = (*exprgraph)->blkmem;
15143  assert(blkmem != NULL);
15144 
15145  /* free nodes arrays */
15146  for( d = 0; d < (*exprgraph)->depth; ++d )
15147  {
15148  assert((*exprgraph)->nnodes[d] == 0);
15149  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
15150  }
15151  assert((*exprgraph)->nodes != NULL);
15152  assert((*exprgraph)->nnodes != NULL);
15153  assert((*exprgraph)->nodessize != NULL);
15154  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
15155  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
15156  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
15157 
15158  /* free variables arrays and hashmap */
15159  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
15160  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
15161  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
15162  SCIPhashmapFree(&(*exprgraph)->varidxs);
15163 
15164  /* free constants array */
15165  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
15166 
15167  /* free graph struct */
15168  BMSfreeBlockMemory(blkmem, exprgraph);
15169 
15170  return SCIP_OKAY;
15171 }
15172 
15173 /** adds an expression graph node to an expression graph
15174  *
15175  * Expression graph assumes ownership of node.
15176  * Children are notified about new parent.
15177  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
15178  */
15180  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15181  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
15182  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
15183  int nchildren, /**< number of children */
15184  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
15185  )
15186 {
15187  SCIP_Bool childvalsvalid;
15188  int depth;
15189  int i;
15190 
15191  assert(exprgraph != NULL);
15192  assert(node != NULL);
15193  assert(node->pos < 0); /* node should have no position in graph yet */
15194  assert(node->depth < 0); /* node should have no position in graph yet */
15195  assert(node->nchildren == 0); /* node should not have stored children yet */
15196  assert(node->children == NULL); /* node should not have stored children yet */
15197  assert(node->nparents == 0); /* node should not have parents stored yet */
15198  assert(children != NULL || nchildren == 0);
15199 
15200  /* choose depth as maximal depth of children + 1, and at least mindepth */
15201  depth = MAX(0, mindepth);
15202  for( i = 0; i < nchildren; ++i )
15203  {
15204  if( children[i]->depth >= depth ) /*lint !e613*/
15205  depth = children[i]->depth + 1; /*lint !e613*/
15206  }
15207 
15208  /* ensure that expression graph is deep enough */
15209  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
15210  assert(exprgraph->depth > depth);
15211 
15212  /* ensure enough space for nodes at depth depth */
15213  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
15214 
15215  /* add node to graph */
15216  node->depth = depth;
15217  node->pos = exprgraph->nnodes[depth];
15218  exprgraph->nodes[depth][node->pos] = node;
15219  ++exprgraph->nnodes[depth];
15220 
15221  /* add as parent to children
15222  * and check if children has valid values */
15223  childvalsvalid = TRUE;
15224  for( i = 0; i < nchildren; ++i )
15225  {
15226  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
15227  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
15228  }
15229  /* store children */
15230  if( nchildren > 0 )
15231  {
15232  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
15233  node->nchildren = nchildren;
15234  }
15235 
15236  if( node->op == SCIP_EXPR_CONST )
15237  {
15238  /* set bounds to constant value of node */
15240  SCIPintervalSet(&node->bounds, node->data.dbl);
15241  }
15242  else
15243  {
15244  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
15247  exprgraph->needvarboundprop = TRUE;
15248  }
15249 
15250  /* if not a variable, set value of node according to values of children (if all have valid values) */
15251  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
15252  {
15253  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15254  }
15255 
15256  return SCIP_OKAY;
15257 }
15258 
15259 /** adds variables to an expression graph, if not existing yet
15260  *
15261  * Also already existing nodes are enabled.
15262  */
15264  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15265  int nvars, /**< number of variables to add */
15266  void** vars, /**< variables to add */
15267  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
15268  )
15269 {
15270  SCIP_EXPRGRAPHNODE* node;
15271  SCIP_EXPROPDATA opdata;
15272  int i;
15273 
15274  assert(exprgraph != NULL);
15275  assert(exprgraph->depth >= 1);
15276  assert(vars != NULL || nvars == 0);
15277 
15278  /* 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 */
15279  if( exprgraph->nvars == 0 )
15280  {
15281  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15282  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15283  }
15284 
15285  for( i = 0; i < nvars; ++i )
15286  {
15287  /* skip variables that exist already */
15288  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15289  {
15290  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
15291  assert(node != NULL);
15292 
15293  /* enable node */
15294  node->enabled = TRUE;
15295 
15296  if( varnodes != NULL )
15297  varnodes[i] = node;
15298 
15299  continue;
15300  }
15301 
15302  /* create new variable expression */
15303  opdata.intval = exprgraph->nvars;
15304  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15305 
15306  /* add expression node to expression graph at depth 0 */
15307  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15308 
15309  /* add variable node to vars arrays and hashmap */
15310  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15311  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
15312  exprgraph->varnodes[exprgraph->nvars] = node;
15313  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15314  SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[i], exprgraph->nvars) ); /*lint !e613*/
15315  ++exprgraph->nvars;
15316 
15317  if( varnodes != NULL )
15318  varnodes[i] = node;
15319 
15320  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15321 
15322  /* call callback method, if set */
15323  if( exprgraph->exprgraphvaradded != NULL )
15324  {
15325  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
15326  }
15327  }
15328 
15329  return SCIP_OKAY;
15330 }
15331 
15332 /** adds a constant to an expression graph, if not existing yet
15333  *
15334  * Also already existing nodes are enabled.
15335  */
15337  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15338  SCIP_Real constant, /**< constant to add */
15339  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
15340  )
15341 {
15342  SCIP_EXPROPDATA opdata;
15343 
15344  assert(exprgraph != NULL);
15345  assert(constnode != NULL);
15346 
15347  /* check if there is already an expression for this constant */
15348  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15349  {
15350  assert(*constnode != NULL);
15351  assert((*constnode)->op == SCIP_EXPR_CONST);
15352  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15353  (*constnode)->enabled = TRUE;
15354  return SCIP_OKAY;
15355  }
15356 
15357  /* create new node for constant */
15358  opdata.dbl = constant;
15359  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15360 
15361  /* add node to expression graph at depth 0 */
15362  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15363  assert((*constnode)->depth == 0);
15364  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
15365 
15366  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15367  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15368  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15369  ++exprgraph->nconsts;
15370  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15371 
15372  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15373 
15374  return SCIP_OKAY;
15375 }
15376 
15377 /** adds sum of expression trees into expression graph
15378  *
15379  * node will also be captured.
15380  *
15381  * @note Parameters will be converted into constants
15382  */
15384  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15385  int nexprtrees, /**< number of expression trees to add */
15386  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
15387  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
15388  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
15389  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) */
15390  )
15391 {
15392  SCIP_Bool allone;
15393 
15394  assert(exprgraph != NULL);
15395  assert(nexprtrees > 0);
15396  assert(exprtrees != NULL);
15397  assert(rootnode != NULL);
15398  assert(rootnodeisnew != NULL);
15399 
15400  *rootnode = NULL;
15401 
15402  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15403  {
15404  assert(exprtrees[0] != NULL);
15405  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15406 
15407  /* coverity[var_deref_model] */
15408  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, exprtrees[0]->params, rootnode, rootnodeisnew) );
15409  }
15410  else
15411  {
15412  SCIP_EXPROP op;
15413  SCIP_EXPRGRAPHNODE** rootnodes;
15414  SCIP_Bool rootnodeisnew_;
15415  int i;
15416 
15417  *rootnodeisnew = TRUE;
15418  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15419 
15420  allone = TRUE;
15421  for( i = 0; i < nexprtrees; ++i )
15422  {
15423  assert(exprtrees[i] != NULL);
15424  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15425 
15426  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, exprtrees[i]->params, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
15427  assert(rootnodes[i] != NULL);
15428  *rootnodeisnew &= rootnodeisnew_;
15429 
15430  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
15431  }
15432 
15433  /* decide which operand we want to use for the root node */
15434  if( coefs == NULL || allone )
15435  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15436  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15437  op = SCIP_EXPR_MINUS;
15438  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15439  {
15440  SCIP_EXPRGRAPHNODE* tmp;
15441 
15442  tmp = rootnodes[0];
15443  rootnodes[0] = rootnodes[1];
15444  rootnodes[1] = tmp;
15445  op = SCIP_EXPR_MINUS;
15446  }
15447  else
15448  op = SCIP_EXPR_LINEAR;
15449 
15450  if( op != SCIP_EXPR_LINEAR )
15451  {
15452  SCIP_EXPROPDATA data;
15453  data.data = NULL;
15454 
15455  if( !*rootnodeisnew )
15456  {
15457  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15458  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15459  }
15460 
15461  if( *rootnode == NULL )
15462  {
15463  /* create new node for sum of rootnodes and add to exprgraph */
15464  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15465  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15466  *rootnodeisnew = TRUE;
15467  }
15468  else
15469  {
15470  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15471  *rootnodeisnew = FALSE;
15472  }
15473  }
15474  else
15475  {
15476  SCIP_EXPROPDATA data;
15477  SCIP_Real* lindata;
15478 
15479  assert(op == SCIP_EXPR_LINEAR);
15480 
15481  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15482  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15483  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
15484  lindata[nexprtrees] = 0.0;
15485  data.data = lindata;
15486 
15487  if( !*rootnodeisnew )
15488  {
15489  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15490  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15491  }
15492 
15493  if( *rootnode == NULL )
15494  {
15495  /* create new node for linear combination of rootnodes and add to exprgraph */
15496  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15497  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15498  *rootnodeisnew = TRUE;
15499  }
15500  else
15501  {
15502  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15503  *rootnodeisnew = FALSE;
15504  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15505  }
15506  }
15507 
15508  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15509  }
15510  assert(*rootnode != NULL);
15511 
15512  SCIPexprgraphCaptureNode(*rootnode);
15513 
15514  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15515  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15516 
15517  return SCIP_OKAY;
15518 }
15519 
15520 /** replaces variable in expression graph by a linear sum of variables
15521  *
15522  * Variables will be added if not in the graph yet.
15523  */
15525  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15526  void* var, /**< variable to replace */
15527  int ncoefs, /**< number of coefficients in linear term */
15528  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
15529  void** vars, /**< variables in linear term */
15530  SCIP_Real constant /**< constant offset */
15531  )
15532 {
15533  SCIP_EXPRGRAPHNODE* varnode;
15534  SCIP_Real* lindata;
15535  int varidx;
15536  int i;
15537 
15538  assert(exprgraph != NULL);
15539  assert(var != NULL);
15540  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15541  assert(coefs != NULL || ncoefs == 0);
15542  assert(vars != NULL || ncoefs == 0);
15543 
15544  varidx = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15545  assert(varidx < exprgraph->nvars);
15546  assert(exprgraph->vars[varidx] == var);
15547  varnode = exprgraph->varnodes[varidx];
15548  assert(varnode != NULL);
15549  assert(varnode->data.intval == varidx);
15550 
15551  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
15552  {
15553  /* variable is replaced by constant or variable */
15554  SCIP_EXPRGRAPHNODE* node;
15555 
15556  /* check if there is already a node for this constant or variable */
15557  node = NULL;
15558  if( ncoefs == 0 )
15559  {
15560  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15561  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
15562  }
15563  else
15564  {
15565  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
15566  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
15567  }
15568 
15569  if( node != NULL )
15570  {
15571  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15572 
15573  /* tell parents of varnode to replace child varnode by node, this may free varnode */
15574  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15575 
15576  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15577  if( varnode != NULL )
15578  {
15579  assert(varnode->nuses > 0);
15580  assert(varnode->nparents == 0);
15581 
15582  /* remove variable (but don't free it's node) from graph */
15583  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15584 
15585  /* move varnode up to depth 1 */
15586  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15587 
15588  /* turn into EXPR_SUM expression */
15589  varnode->op = SCIP_EXPR_SUM;
15590  varnode->data.data = NULL;
15591  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
15592  varnode->children[0] = node;
15593  varnode->nchildren = 1;
15594  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15595 
15596  varnode->value = node->value;
15597  varnode->bounds = node->bounds;
15598  varnode->boundstatus = (node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID) ? SCIP_EXPRBOUNDSTATUS_VALID : SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
15599  }
15600  }
15601  else if( ncoefs == 0 )
15602  {
15603  /* turn node into EXPR_CONST node */
15604 
15605  /* remove variable (but don't free it's node) from graph */
15606  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15607 
15608  /* convert into EXPR_CONST node */
15609  varnode->op = SCIP_EXPR_CONST;
15610  varnode->data.dbl = constant;
15611 
15612  varnode->value = constant;
15613  SCIPintervalSet(&varnode->bounds, constant);
15615 
15616  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15617  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15618  exprgraph->constnodes[exprgraph->nconsts] = varnode;
15619  ++exprgraph->nconsts;
15620  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15621  }
15622  else
15623  {
15624  /* turn node into EXPR_VARIDX node for new variable */
15625 
15626  /* remove variable (but don't free it's node) from graph */
15627  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15628 
15629  varnode->data.intval = exprgraph->nvars;
15630 
15631  /* add variable node to vars arrays and hashmap */
15632  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15633  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
15634  exprgraph->varnodes[exprgraph->nvars] = varnode;
15635  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15636  SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[0], exprgraph->nvars) ); /*lint !e613*/
15637  ++exprgraph->nvars;
15638 
15639  /* call callback method, if set */
15640  if( exprgraph->exprgraphvaradded != NULL )
15641  {
15642  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
15643  }
15644  }
15645 
15646  /* mark varnode and its parents as not simplified */
15647  if( varnode != NULL )
15648  {
15649  varnode->simplified = FALSE;
15650  for( i = 0; i < varnode->nparents; ++i )
15651  varnode->parents[i]->simplified = FALSE;
15652  }
15653 
15654  return SCIP_OKAY;
15655  }
15656 
15657  /* turn varnode into EXPR_LINEAR */
15658 
15659  /* remove variable (but don't free it's node) from graph */
15660  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15661 
15662  /* move varnode up to depth 1 */
15663  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15664 
15665  /* convert into EXPR_LINEAR node */
15666  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15667  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
15668  lindata[ncoefs] = constant;
15669  varnode->data.data = (void*)lindata;
15670  varnode->op = SCIP_EXPR_LINEAR;
15671 
15672  /* add nodes corresponding to vars to expression graph, if not existing yet */
15673  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15674  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15675  varnode->nchildren = ncoefs;
15676 
15677  /* notify vars about new parent varnode */
15678  for( i = 0; i < ncoefs; ++i )
15679  {
15680  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15681  }
15682 
15683  /* set value and bounds to invalid, curvature can remain (still linear) */
15684  varnode->value = SCIP_INVALID;
15686 
15687  /* mark varnode and its parents as not simplified */
15688  varnode->simplified = FALSE;
15689  for( i = 0; i < varnode->nparents; ++i )
15690  varnode->parents[i]->simplified = FALSE;
15691 
15692  return SCIP_OKAY;
15693 }
15694 
15695 /** finds expression graph node corresponding to a variable */
15697  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15698  void* var, /**< variable to search for */
15699  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15700  )
15701 {
15702  int pos;
15703 
15704  assert(exprgraph != NULL);
15705  assert(var != NULL);
15706  assert(varnode != NULL);
15707 
15708  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15709  {
15710  *varnode = NULL;
15711  return FALSE;
15712  }
15713 
15714  pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15715  assert(pos < exprgraph->nvars);
15716 
15717  *varnode = exprgraph->varnodes[pos];
15718  assert(*varnode != NULL);
15719  assert((*varnode)->op == SCIP_EXPR_VARIDX);
15720 
15721  return TRUE;
15722 }
15723 
15724 /** finds expression graph node corresponding to a constant */
15726  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15727  SCIP_Real constant, /**< constant to search for */
15728  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15729  )
15730 {
15731  int left;
15732  int right;
15733  int middle;
15734 
15735  assert(exprgraph != NULL);
15736  assert(constnode != NULL);
15737  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
15738 
15739  exprgraphSortConstNodes(exprgraph);
15740  assert(exprgraph->constssorted);
15741 
15742  /* find node using binary search */
15743  left = 0;
15744  right = exprgraph->nconsts-1;
15745  *constnode = NULL;
15746 
15747  while( left <= right )
15748  {
15749  middle = (left+right)/2;
15750  assert(0 <= middle && middle < exprgraph->nconsts);
15751 
15752  if( constant < exprgraph->constnodes[middle]->data.dbl )
15753  right = middle - 1;
15754  else if( constant > exprgraph->constnodes[middle]->data.dbl )
15755  left = middle + 1;
15756  else
15757  {
15758  *constnode = exprgraph->constnodes[middle];
15759  break;
15760  }
15761  }
15762  if( left == right+1 )
15763  return FALSE;
15764 
15765  assert(*constnode != NULL);
15766  assert((*constnode)->op == SCIP_EXPR_CONST);
15767  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15768 
15769  return TRUE;
15770 }
15771 
15772 /** prints an expression graph in dot format */
15774  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15775  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15776  FILE* file, /**< file to print to, or NULL for stdout */
15777  const char** varnames /**< variable names, or NULL for generic names */
15778  )
15779 {
15780  int d;
15781  int i;
15782 
15783  assert(exprgraph != NULL);
15784 
15785  if( file == NULL )
15786  file = stdout;
15787 
15788  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15789  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15790 
15791  for( d = 0; d < exprgraph->depth; ++d )
15792  {
15793  if( exprgraph->nnodes[d] == 0 )
15794  continue;
15795 
15796  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15797  {
15798  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15799  }
15800  }
15801 
15802  /* tell dot that all nodes of depth 0 have the same rank */
15803  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15804  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15805  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15806  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15807 
15808  /* tell dot that all nodes without parent have the same rank */
15809  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15810  for( d = 0; d < exprgraph->depth; ++d )
15811  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15812  if( exprgraph->nodes[d][i]->nparents == 0 )
15813  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15814  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15815 
15816  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15817 
15818  return SCIP_OKAY;
15819 }
15820 
15821 /** evaluates nodes of expression graph for given values of variables */
15823  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15824  SCIP_Real* varvals /**< values for variables */
15825  )
15826 {
15827  int d;
15828  int i;
15829 
15830  assert(exprgraph != NULL);
15831  assert(varvals != NULL || exprgraph->nvars == 0);
15832 
15833  for( d = 0; d < exprgraph->depth; ++d )
15834  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15835  {
15836  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15837  }
15838 
15839  return SCIP_OKAY;
15840 }
15841 
15842 /** propagates bound changes in variables forward through the expression graph */
15844  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15845  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15846  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
15847  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15848  )
15849 {
15850  SCIP_EXPRGRAPHNODE* node;
15851  SCIP_Bool boundchanged;
15852  int d;
15853  int i;
15854 
15855  assert(exprgraph != NULL);
15856  assert(domainerror != NULL);
15857 
15858  *domainerror = FALSE;
15859 
15860  /* update bounds in varnodes of expression graph */
15861  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15862 
15863  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15864  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15865  {
15866  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15867  return SCIP_OKAY;
15868  }
15869 
15870  /* propagate bound changes, interrupt if we get to a node with empty bounds */
15871  for( d = 1; d < exprgraph->depth; ++d )
15872  {
15873  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15874  {
15875  node = exprgraph->nodes[d][i];
15876  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15877  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15878  {
15879  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15880  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15881  *domainerror = TRUE;
15882  return SCIP_OKAY;
15883  }
15884  }
15885  }
15886 
15887  exprgraph->needvarboundprop = FALSE;
15888 
15889  return SCIP_OKAY;
15890 }
15891 
15892 /** propagates bound changes in nodes backward through the graph
15893  *
15894  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15895  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15896  */
15898  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15899  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15900  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15901  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15902  )
15903 {
15904  SCIP_EXPRGRAPHNODE* node;
15905  int d;
15906  int i;
15907 
15908  assert(exprgraph != NULL);
15909  assert(cutoff != NULL);
15910 
15911  *cutoff = FALSE;
15912 
15913  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15914  {
15915  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15916  {
15917  node = exprgraph->nodes[d][i];
15918  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15919  }
15920  }
15921  if( *cutoff )
15922  return;
15923 }
15924 
15925 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15926  *
15927  * Implies update of bounds in expression graph.
15928  */
15930  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15931  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15932  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15933  )
15934 {
15935  SCIP_EXPRGRAPHNODE* node;
15936  SCIP_Bool boundchanged;
15937  int d;
15938  int i;
15939 
15940  assert(exprgraph != NULL);
15941 
15942  /* update bounds in varnodes of expression graph */
15943  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15944 
15945 #ifndef NDEBUG
15946  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15947  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15948 #endif
15949 
15950  for( d = 1; d < exprgraph->depth; ++d )
15951  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15952  {
15953  node = exprgraph->nodes[d][i];
15954  assert(node != NULL);
15955 
15956  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15957 
15958  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15959  {
15960  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15961  return SCIP_OKAY;
15962  }
15963  }
15964 
15965  return SCIP_OKAY;
15966 }
15967 
15968 /** aims at simplifying an expression graph
15969  *
15970  * 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)).
15971  */
15973  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15974  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15975  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15976  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15977  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15978  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15979  )
15980 {
15981  SCIP_EXPRGRAPHNODE* node;
15982  SCIP_Bool havechangenode;
15983  SCIP_Bool allsimplified;
15984  int d;
15985  int i;
15986  int j;
15987 
15988 #ifndef NDEBUG
15989  SCIP_Real* testx;
15990  SCIP_HASHMAP* testvalidx;
15991  SCIP_Real* testvals;
15992  SCIP_RANDNUMGEN* randnumgen;
15993  int testvalssize;
15994  int ntestvals;
15995 #endif
15996 
15997  assert(exprgraph != NULL);
15998  assert(eps >= 0.0);
15999  assert(havechange != NULL);
16000  assert(domainerror != NULL);
16001 
16002 #ifndef NDEBUG
16003  SCIP_CALL( SCIPrandomCreate(&randnumgen, exprgraph->blkmem, 862) ); /* see also #1848 */
16004  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
16005  testvals = NULL;
16006  ntestvals = 0;
16007  testvalssize = 0;
16008 
16009  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
16010  for( i = 0; i < exprgraph->nvars; ++i )
16011  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
16012  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
16013  for( d = 1; d < exprgraph->depth; ++d )
16014  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16015  {
16016  node = exprgraph->nodes[d][i];
16017  assert(node != NULL);
16018 
16019  /* 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 */
16020  if( node->nuses > 0 )
16021  {
16022  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
16023  SCIP_CALL( SCIPhashmapInsertInt(testvalidx, (void*)node, ntestvals) );
16024  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
16025  ++ntestvals;
16026  }
16027  }
16028 
16029  SCIPrandomFree(&randnumgen, exprgraph->blkmem);
16030 #endif
16031 
16032 #ifdef SCIP_OUTPUT
16033  {
16034  FILE* file;
16035  file = fopen("exprgraph_beforesimplify.dot", "w");
16036  if( file != NULL )
16037  {
16038  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16039  fclose(file);
16040  }
16041  }
16042 #endif
16043 
16044  *havechange = FALSE; /* we have not changed any node yet */
16045  *domainerror = FALSE; /* no domain errors encountered so far */
16046  allsimplified = TRUE; /* all nodes we looked at are simplified */
16047 
16048  /* call node simplifier from bottom up
16049  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
16050  */
16051  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
16052  {
16053  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16054  {
16055  node = exprgraph->nodes[d][i];
16056  assert(node != NULL);
16057 
16058  havechangenode = FALSE; /* node did not change yet */
16059 
16060  if( node->op != SCIP_EXPR_CONST )
16061  {
16062  /* skip nodes that are already simplified */
16063  if( node->simplified )
16064  continue;
16065 
16066  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
16067 
16068  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
16069  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
16070  assert(node->simplified == TRUE);
16071  *havechange |= havechangenode;
16072  }
16073 
16074  /* if node was or has been converted into constant, may move to depth 0 */
16075  if( node->op == SCIP_EXPR_CONST )
16076  {
16077  SCIP_EXPRGRAPHNODE* constnode;
16078 
16079  if( !SCIPisFinite(node->value) ) /*lint !e777*/
16080  {
16081  SCIPdebugMessage("Expression graph simplify turned node into NaN or inf.\n");
16082  *domainerror = TRUE;
16083  break;
16084  }
16085 
16086  /* check if there is already a node for this constant */
16087  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
16088  {
16089  assert(constnode->op == SCIP_EXPR_CONST);
16090  assert(constnode->data.dbl == node->value); /*lint !e777*/
16091 
16092  if( node->nparents > 0 )
16093  {
16094  /* move parents of this node to constnode, node may be freed if not in use */
16095  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
16096  /* node should have no parents anymore, so it should have been freed if not in use */
16097  assert(node == NULL || node->nuses > 0);
16098  havechangenode = TRUE;
16099 
16100  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
16101  if( node == NULL )
16102  {
16103  --i;
16104  continue;
16105  }
16106  }
16107  assert(node != NULL);
16108  assert(node->nuses > 0);
16109 
16110  if( constnode->nuses == 0 )
16111  {
16112  /* move node to depth 0, adding it to constnodes */
16113  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16114 
16115  /* move parents of constnode to node, so constnode is freed */
16116  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
16117  assert(constnode == NULL);
16118  havechangenode = TRUE;
16119 
16120  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16121  --i;
16122  continue;
16123  }
16124  }
16125  else
16126  {
16127  /* move to depth 0, adding it to constnodes */
16128  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16129 
16130  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16131  --i;
16132  }
16133  }
16134 
16135  /* if there was a change, mark parents as not simplified */
16136  if( havechangenode )
16137  for( j = 0; j < node->nparents; ++j )
16138  node->parents[j]->simplified = FALSE;
16139  }
16140  } /*lint !e850*/
16141 
16142  /* if we did nothing, clean up and escape from here */
16143  if( allsimplified || *domainerror )
16144  goto EXPRGRAPHSIMPLIFY_CLEANUP;
16145 
16146  /* @todo find duplicate subexpressions in expression graph */
16147 
16148  /* unconvert polynomials into simpler expressions, where possible */
16149  for( d = 1; d < exprgraph->depth; ++d )
16150  {
16151  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16152  {
16153  node = exprgraph->nodes[d][i];
16154  assert(node != NULL);
16155 
16156  if( node->op != SCIP_EXPR_POLYNOMIAL )
16157  continue;
16158 
16159  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
16160 
16161  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
16162  {
16163  /* node is identity w.r.t only child
16164  * replace node as child of parents by child of node
16165  */
16166 
16167  for( j = 0; node != NULL && j < node->nparents; ++j )
16168  {
16169  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
16170  }
16171  /* node should have no parents anymore, so it should have been freed if not in use */
16172  assert(node == NULL || node->nuses > 0);
16173 
16174  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
16175  if( node == NULL )
16176  --i;
16177  }
16178  }
16179  } /*lint !e850*/
16180 
16181 #ifdef SCIP_OUTPUT
16182  {
16183  FILE* file;
16184  file = fopen("exprgraph_aftersimplify.dot", "w");
16185  if( file != NULL )
16186  {
16187  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16188  fclose(file);
16189  }
16190  }
16191 #endif
16192 
16193 #ifndef NDEBUG
16194  for( d = 1; d < exprgraph->depth; ++d )
16195  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16196  {
16197  int idx;
16198  SCIP_Real testval_before;
16199  SCIP_Real testval_after;
16200 
16201  node = exprgraph->nodes[d][i];
16202  assert(node != NULL);
16203 
16204  SCIP_CALL( exprgraphNodeEval(node, NULL) );
16205 
16206  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
16207  if( node->nuses > 0 )
16208  {
16209  assert(SCIPhashmapExists(testvalidx, (void*)node));
16210 
16211  idx = SCIPhashmapGetImageInt(testvalidx, (void*)node);
16212  assert(idx < ntestvals);
16213  assert(testvals != NULL);
16214 
16215  testval_before = testvals[idx]; /*lint !e613*/
16216  testval_after = SCIPexprgraphGetNodeVal(node);
16217 
16218  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
16219  }
16220  }
16221 #endif
16222 
16223  EXPRGRAPHSIMPLIFY_CLEANUP:
16224 #ifndef NDEBUG
16225  BMSfreeMemoryArray(&testx);
16226  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
16227  SCIPhashmapFree(&testvalidx);
16228 #endif
16229 
16230  return SCIP_OKAY;
16231 }
16232 
16233 /** creates an expression tree from a given node in an expression graph */
16235  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16236  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
16237  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
16238  )
16239 {
16240  SCIP_EXPR* root;
16241  int nexprvars;
16242  int* varidx;
16243  int i;
16244 
16245  assert(exprgraph != NULL);
16246  assert(rootnode != NULL);
16247  assert(rootnode->depth >= 0);
16248  assert(rootnode->pos >= 0);
16249  assert(exprtree != NULL);
16250 
16251  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16252  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16253 
16254  /* initially, no variable appears in the expression tree */
16255  for( i = 0; i < exprgraph->nvars; ++i )
16256  varidx[i] = -1; /*lint !e644*/
16257  nexprvars = 0;
16258 
16259  /* create expression from the subgraph that has rootnode as root */
16260  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
16261 
16262  /* create expression tree for this expression */
16263  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
16264 
16265  /* copy variables into expression tree */
16266  if( nexprvars > 0 )
16267  {
16268  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
16269  for( i = 0; i < exprgraph->nvars; ++i )
16270  {
16271  assert(varidx[i] >= -1);
16272  assert(varidx[i] < nexprvars);
16273  if( varidx[i] >= 0 )
16274  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
16275  }
16276  }
16277 
16278  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16279 
16280  return SCIP_OKAY;
16281 }
16282 
16283 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16284  *
16285  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16286  */
16288  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16289  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16290  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16291  int* nexprtrees, /**< buffer to store number of expression trees */
16292  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16293  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16294  )
16295 {
16296  int ncomponents;
16297  int* childcomp;
16298  int* varcomp;
16299  int compnr;
16300  SCIP_Bool haveoverlap;
16301  int i;
16302  int j;
16303  int k;
16304 
16305  SCIP_EXPR** exprs;
16306  int nexprs;
16307  int* childmap;
16308  int* childmapinv;
16309  int* varidx;
16310  int nexprvars;
16311 
16312  assert(exprgraph != NULL);
16313  assert(node != NULL);
16314  assert(node->depth >= 0);
16315  assert(node->pos >= 0);
16316  assert(exprtreessize > 0);
16317  assert(nexprtrees != NULL);
16318  assert(exprtrees != NULL);
16319  assert(exprtreecoefs != NULL);
16320 
16321  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16322  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16323  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16324  ( node->op != SCIP_EXPR_PLUS &&
16325  node->op != SCIP_EXPR_MINUS &&
16326  node->op != SCIP_EXPR_SUM &&
16327  node->op != SCIP_EXPR_LINEAR &&
16328  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16329  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16330  {
16331  *nexprtrees = 1;
16332  exprtreecoefs[0] = 1.0;
16333  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16334 
16335  return SCIP_OKAY;
16336  }
16337 
16338  /* find components in node->children <-> variables graph */
16339  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16340  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16341  for( i = 0; i < exprgraph->nvars; ++i )
16342  varcomp[i] = -1; /*lint !e644*/
16343 
16344  haveoverlap = FALSE;
16345  for( i = 0; i < node->nchildren; ++i )
16346  {
16347  compnr = i;
16348  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
16349  assert(compnr >= 0);
16350  assert(compnr < node->nchildren);
16351  childcomp[i] = compnr;
16352 
16353  /* remember if component number was changed by CheckComponent */
16354  if( compnr != i )
16355  haveoverlap = TRUE;
16356  }
16357 
16358  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16359 
16360  if( node->op == SCIP_EXPR_QUADRATIC )
16361  {
16362  /* merge components for products of children from different components */
16364 
16365  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16366  assert(data != NULL);
16367 
16368  for( i = 0; i < data->nquadelems; ++i )
16369  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16370  {
16371  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16372  compnr = childcomp[data->quadelems[i].idx2];
16373  for( j = 0; j < node->nchildren; ++j )
16374  if( childcomp[j] == compnr )
16375  childcomp[j] = childcomp[data->quadelems[i].idx1];
16376  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16377  haveoverlap = TRUE;
16378  }
16379  }
16380  else if( node->op == SCIP_EXPR_POLYNOMIAL )
16381  {
16382  /* merge components for monomials of children from different components */
16384 
16385  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16386  assert(data != NULL);
16387 
16388  for( i = 0; i < data->nmonomials; ++i )
16389  for( j = 1; j < data->monomials[i]->nfactors; ++j )
16390  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16391  {
16392  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16393  compnr = childcomp[data->monomials[i]->childidxs[j]];
16394  for( k = 0; k < node->nchildren; ++k )
16395  if( childcomp[k] == compnr )
16396  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16397  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16398  haveoverlap = TRUE;
16399  }
16400  }
16401 
16402  if( haveoverlap )
16403  {
16404  /* some component numbers are unused, thus relabel and count final number of components */
16405  int* compmap;
16406 
16407  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16408  for( i = 0; i < node->nchildren; ++i )
16409  compmap[i] = -1; /*lint !e644*/
16410 
16411  ncomponents = 0;
16412  for( i = 0; i < node->nchildren; ++i )
16413  {
16414  if( compmap[childcomp[i]] == -1 )
16415  compmap[childcomp[i]] = ncomponents++;
16416  childcomp[i] = compmap[childcomp[i]];
16417  }
16418 
16419  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16420  }
16421  else
16422  {
16423  ncomponents = node->nchildren;
16424  }
16425 
16426  if( ncomponents == 1 )
16427  {
16428  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16429  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16430 
16431  *nexprtrees = 1;
16432  exprtreecoefs[0] = 1.0;
16433  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16434 
16435  return SCIP_OKAY;
16436  }
16437 
16438  if( ncomponents > exprtreessize )
16439  {
16440  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16441  for( i = 0; i < node->nchildren; ++i )
16442  if( childcomp[i] >= exprtreessize )
16443  childcomp[i] = exprtreessize-1;
16444  ncomponents = exprtreessize;
16445  }
16446 
16447  assert(ncomponents >= 2);
16448 
16449  /* setup expression trees for each component */
16450  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16451  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16452  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16453  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16454  for( i = 0; i < ncomponents; ++i )
16455  {
16456  /* initially, no variable appears in the expression tree */
16457  for( j = 0; j < exprgraph->nvars; ++j )
16458  varidx[j] = -1; /*lint !e644*/
16459  nexprvars = 0;
16460 
16461  /* collect expressions from children belonging to component i */
16462  nexprs = 0;
16463  for( j = 0; j < node->nchildren; ++j )
16464  {
16465  assert(childcomp[j] >= 0);
16466  assert(childcomp[j] < ncomponents);
16467  if( childcomp[j] != i )
16468  continue;
16469 
16470  /* create expression from the subgraph that has child j as root */
16471  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
16472  childmap[j] = nexprs; /*lint !e644*/
16473  childmapinv[nexprs] = j; /*lint !e644*/
16474  ++nexprs;
16475  }
16476 
16477  /* setup expression tree for component i */
16478  switch( node->op )
16479  {
16480  case SCIP_EXPR_PLUS:
16481  {
16482  assert(ncomponents == 2);
16483  assert(nexprs == 1);
16484 
16485  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16486  exprtreecoefs[i] = 1.0;
16487 
16488  break;
16489  }
16490 
16491  case SCIP_EXPR_MINUS:
16492  {
16493  assert(ncomponents == 2);
16494  assert(nexprs == 1);
16495 
16496  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16497  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16498  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16499  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16500 
16501  break;
16502  }
16503 
16504  case SCIP_EXPR_SUM:
16505  {
16506  if( nexprs == 1 )
16507  {
16508  /* component corresponds to exactly one child of node */
16509  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16510  }
16511  else
16512  {
16513  /* component corresponds to a sum of children of node */
16514  SCIP_EXPR* sumexpr;
16515 
16516  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16517  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16518  }
16519  exprtreecoefs[i] = 1.0;
16520 
16521  break;
16522  }
16523 
16524  case SCIP_EXPR_LINEAR:
16525  {
16526  SCIP_Real* nodecoefs;
16527  SCIP_EXPR* sumexpr;
16528 
16529  nodecoefs = (SCIP_Real*)node->data.data;
16530 
16531  /* if there is a constant, then we put it into the expression of the first component */
16532  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16533  {
16534  /* component corresponds to exactly one child of node */
16535  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16536  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16537  }
16538  else if( nexprs == 1 )
16539  {
16540  /* component corresponds to a sum of one child and a constant */
16541  assert(i == 0);
16542  assert(nodecoefs[node->nchildren] != 0.0);
16543  assert(nodecoefs[childmapinv[0]] != 0.0);
16544  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16545  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16546  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16547  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16548  }
16549  else
16550  {
16551  /* component corresponds to a linear combination of children of node */
16552 
16553  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16554  {
16555  /* if two expressions with equal sign, then create PLUS expression */
16556  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16557  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16558  }
16559  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16560  {
16561  /* if two expressions with opposite sign, then create MINUS expression */
16562  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16563  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16564  }
16565  else
16566  {
16567  /* assemble coefficents and create SUM or LINEAR expression */
16568  SCIP_Real* coefs;
16569  SCIP_Bool allcoefsequal;
16570 
16571  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16572  allcoefsequal = TRUE;
16573  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
16574  for( j = 0; j < nexprs; ++j )
16575  {
16576  coefs[j] = nodecoefs[childmapinv[j]];
16577  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
16578  }
16579 
16580  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16581  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16582  {
16583  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16584  exprtreecoefs[i] = coefs[0];
16585  }
16586  else
16587  {
16588  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16589  exprtreecoefs[i] = 1.0;
16590  }
16591 
16592  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16593  }
16594 
16595  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16596  }
16597 
16598  break;
16599  }
16600 
16601  case SCIP_EXPR_QUADRATIC:
16602  {
16603  SCIP_EXPR* quadexpr;
16605  SCIP_Real* lincoefs;
16606  SCIP_QUADELEM* quadelems;
16607  int nquadelems;
16608 
16609  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16610 
16611  exprtreecoefs[i] = 1.0;
16612 
16613  /* assemble coefficients corresponding to component i */
16614  if( nodedata->lincoefs != NULL )
16615  {
16616  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16617  for( j = 0; j < nexprs; ++j )
16618  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
16619  }
16620  else
16621  lincoefs = NULL;
16622 
16623  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16624  nquadelems = 0;
16625  for( j = 0; j < nodedata->nquadelems; ++j )
16626  {
16627  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16628  if( childcomp[nodedata->quadelems[j].idx1] != i )
16629  continue;
16630  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
16631  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16632  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16633  ++nquadelems;
16634  }
16635 
16636  /* put constant into first component */
16637  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16638  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16639 
16640  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16641  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16642 
16643  break;
16644  }
16645 
16646  case SCIP_EXPR_POLYNOMIAL:
16647  {
16648  SCIP_EXPR* polyexpr;
16650  SCIP_EXPRDATA_MONOMIAL** monomials;
16651  SCIP_Real constant;
16652  int nmonomials;
16653 
16654  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16655 
16656  constant = nodedata->constant;
16657  exprtreecoefs[i] = 1.0;
16658 
16659  /* collect monomials belonging to component i */
16660  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16661  nmonomials = 0;
16662  for( j = 0; j < nodedata->nmonomials; ++j )
16663  {
16664  if( nodedata->monomials[j]->nfactors == 0 )
16665  {
16666  constant += nodedata->monomials[j]->coef;
16667  continue;
16668  }
16669  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16670  continue;
16671 
16672  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16673  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
16674  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16675  {
16676  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16677  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16678  }
16679  ++nmonomials;
16680  }
16681 
16682  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16683  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16684 
16685  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16686 
16687  break;
16688  }
16689 
16690  default:
16691  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16692  return SCIP_ERROR;
16693  } /*lint !e788*/
16694 
16695  /* copy variables into expression tree */
16696  if( nexprvars > 0 )
16697  {
16698  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16699  for( j = 0; j < exprgraph->nvars; ++j )
16700  {
16701  assert(varidx[j] >= -1);
16702  assert(varidx[j] < nexprvars);
16703  if( varidx[j] >= 0 )
16704  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16705  }
16706  }
16707  }
16708 
16709  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16710  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16711  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16712  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16713  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16714 
16715  *nexprtrees = ncomponents;
16716 
16717  return SCIP_OKAY;
16718 }
16719 
16720 /** returns how often expression graph variables are used in a subtree of the expression graph */
16722  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16723  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
16724  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16725  )
16726 {
16727  assert(exprgraph != NULL);
16728  assert(node != NULL);
16729  assert(varsusage != NULL);
16730 
16731  BMSclearMemoryArray(varsusage, exprgraph->nvars);
16732 
16733  exprgraphNodeGetVarsUsage(node, varsusage);
16734 }
16735 
16736 /** gives the number of summands which the expression of an expression graph node consists of */
16738  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
16739  )
16740 {
16741  switch( node->op )
16742  {
16743  case SCIP_EXPR_PLUS:
16744  case SCIP_EXPR_MINUS:
16745  return 2;
16746 
16747  case SCIP_EXPR_SUM:
16748  case SCIP_EXPR_LINEAR:
16749  return node->nchildren;
16750 
16751  case SCIP_EXPR_QUADRATIC:
16752  {
16754 
16755  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16756  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16757  }
16758 
16759  case SCIP_EXPR_POLYNOMIAL:
16760  {
16762 
16763  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16764  return nodedata->nmonomials;
16765  }
16766 
16767  default:
16768  return 1;
16769  } /*lint !e788*/
16770 }
16771 
16772 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
16774  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16775  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16776  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16777  int* nexprtrees, /**< buffer to store number of expression trees */
16778  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16779  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16780  )
16781 {
16782  int* varidx;
16783  int nexprvars;
16784  int i;
16785 
16786  assert(exprgraph != NULL);
16787  assert(node != NULL);
16788  assert(node->depth >= 0);
16789  assert(node->pos >= 0);
16790  assert(exprtreessize > 0);
16791  assert(nexprtrees != NULL);
16792  assert(exprtrees != NULL);
16793  assert(exprtreecoefs != NULL);
16794 
16795  /* if node is not separable, fallback to SCIPexprgraphGetTree */
16796  if( node->op != SCIP_EXPR_PLUS &&
16797  node->op != SCIP_EXPR_MINUS &&
16798  node->op != SCIP_EXPR_SUM &&
16799  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16800  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16801  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16802  {
16803  *nexprtrees = 1;
16804  exprtreecoefs[0] = 1.0;
16805  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16806 
16807  return SCIP_OKAY;
16808  }
16809 
16810  switch( node->op )
16811  {
16812  case SCIP_EXPR_PLUS:
16813  {
16814  assert(exprtreessize >= 2);
16815 
16816  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16817  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16818 
16819  exprtreecoefs[0] = 1.0;
16820  exprtreecoefs[1] = 1.0;
16821 
16822  *nexprtrees = 2;
16823  break;
16824  }
16825 
16826  case SCIP_EXPR_MINUS:
16827  {
16828  assert(exprtreessize >= 2);
16829 
16830  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16831  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16832 
16833  exprtreecoefs[0] = 1.0;
16834  exprtreecoefs[1] = -1.0;
16835 
16836  *nexprtrees = 2;
16837  break;
16838  }
16839 
16840  case SCIP_EXPR_SUM:
16841  {
16842  assert(exprtreessize >= node->nchildren);
16843 
16844  for( i = 0; i < node->nchildren; ++i )
16845  {
16846  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16847  exprtreecoefs[i] = 1.0;
16848  }
16849 
16850  *nexprtrees = node->nchildren;
16851  break;
16852  }
16853 
16854  case SCIP_EXPR_LINEAR:
16855  {
16856  SCIP_Real* nodecoefs;
16857 
16858  assert(exprtreessize >= node->nchildren);
16859  assert(node->nchildren > 0);
16860 
16861  nodecoefs = (SCIP_Real*)node->data.data;
16862  assert(nodecoefs != NULL);
16863 
16864  for( i = 0; i < node->nchildren; ++i )
16865  {
16866  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16867  exprtreecoefs[i] = nodecoefs[i];
16868  }
16869 
16870  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16871  if( nodecoefs[node->nchildren] != 0.0 )
16872  {
16873  SCIP_EXPR* constexpr_;
16874 
16875  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16876  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16877  }
16878 
16879  *nexprtrees = node->nchildren;
16880  break;
16881  }
16882 
16883  case SCIP_EXPR_QUADRATIC:
16884  {
16886  SCIP_Real* lincoefs;
16887  SCIP_QUADELEM* quadelems;
16888  int nquadelems;
16889  SCIP_EXPR* expr;
16890  int j;
16891 
16892  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16893  lincoefs = nodedata->lincoefs;
16894  quadelems = nodedata->quadelems;
16895  nquadelems = nodedata->nquadelems;
16896 
16897  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16898  assert(node->nchildren > 0);
16899 
16900  *nexprtrees = 0;
16901  if( lincoefs != NULL )
16902  {
16903  for( i = 0; i < node->nchildren; ++i )
16904  {
16905  if( lincoefs[i] == 0.0 )
16906  continue;
16907  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16908  exprtreecoefs[*nexprtrees] = lincoefs[i];
16909  ++*nexprtrees;
16910  }
16911  }
16912 
16913  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16914  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16915 
16916  for( i = 0; i < nquadelems; ++i )
16917  {
16918  /* initially, no variable appears in the expression tree */
16919  for( j = 0; j < exprgraph->nvars; ++j )
16920  varidx[j] = -1; /*lint !e644*/
16921  nexprvars = 0;
16922 
16923  /* create expression from the subgraph at quadelems[i].idx1 */
16924  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16925 
16926  if( quadelems[i].idx1 == quadelems[i].idx2 )
16927  {
16928  /* create expression for square of expr */
16929  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16930  }
16931  else
16932  {
16933  SCIP_EXPR* expr2;
16934 
16935  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16936  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16937  /* create expression for product */
16938  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16939  }
16940 
16941  /* create expression tree for expr */
16942  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16943 
16944  /* copy variables into expression tree */
16945  if( nexprvars > 0 )
16946  {
16947  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16948  for( j = 0; j < exprgraph->nvars; ++j )
16949  {
16950  assert(varidx[j] >= -1);
16951  assert(varidx[j] < nexprvars);
16952  if( varidx[j] >= 0 )
16953  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16954  }
16955  }
16956 
16957  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16958 
16959  ++*nexprtrees;
16960  }
16961 
16962  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16963  if( nodedata->constant != 0.0 )
16964  {
16965  SCIP_EXPR* constexpr_;
16966 
16967  assert(*nexprtrees > 0);
16968  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16969  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16970  }
16971 
16972  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16973 
16974  break;
16975  }
16976 
16977  case SCIP_EXPR_POLYNOMIAL:
16978  {
16980  SCIP_EXPRDATA_MONOMIAL** monomials;
16981  SCIP_Real constant;
16982  int nmonomials;
16983  SCIP_EXPR* expr;
16984  int* childidxs;
16985  int j;
16986 
16987  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16988  monomials = nodedata->monomials;
16989  nmonomials = nodedata->nmonomials;
16990  constant = nodedata->constant;
16991 
16992  assert(exprtreessize >= nmonomials);
16993  assert(node->nchildren > 0);
16994 
16995  *nexprtrees = 0;
16996 
16997  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16998  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16999 
17000  for( i = 0; i < nmonomials; ++i )
17001  {
17002  /* initially, no variable appears in the expression tree */
17003  for( j = 0; j < exprgraph->nvars; ++j )
17004  varidx[j] = -1;
17005  nexprvars = 0;
17006 
17007  if( monomials[i]->nfactors == 1 )
17008  {
17009  /* create expression from the subgraph at only factor */
17010  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17011 
17012  /* put exponent in, if not 1.0 */
17013  if( monomials[i]->exponents[0] == 1.0 )
17014  ;
17015  else if( monomials[i]->exponents[0] == 2.0 )
17016  {
17017  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
17018  }
17019  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
17020  {
17021  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
17022  }
17023  else
17024  {
17025  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
17026  }
17027  }
17028  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
17029  {
17030  SCIP_EXPR* expr2;
17031 
17032  /* create expressions for both factors */
17033  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17034  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
17035 
17036  /* create expression for product of factors */
17037  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
17038  }
17039  else
17040  {
17041  SCIP_EXPRDATA_MONOMIAL* monomial;
17042  SCIP_EXPR** exprs;
17043  int f;
17044 
17045  /* create expression for each factor, assemble varidx and nexprvars
17046  * create child indices (= identity) */
17047  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
17048  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
17049  for( f = 0; f < monomials[i]->nfactors; ++f )
17050  {
17051  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
17052  childidxs[f] = f; /*lint !e644*/
17053  }
17054 
17055  /* create monomial and polynomial expression for this monomial
17056  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
17057  */
17058  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
17059  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
17060  constant = 0.0;
17061 
17062  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
17063  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
17064  }
17065 
17066  /* create expression tree for expr */
17067  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
17068 
17069  /* copy variables into expression tree */
17070  if( nexprvars > 0 )
17071  {
17072  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
17073  for( j = 0; j < exprgraph->nvars; ++j )
17074  {
17075  assert(varidx[j] >= -1);
17076  assert(varidx[j] < nexprvars);
17077  if( varidx[j] >= 0 )
17078  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
17079  }
17080  }
17081 
17082  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
17083 
17084  ++*nexprtrees;
17085  }
17086 
17087  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
17088  if( constant != 0.0 )
17089  {
17090  SCIP_EXPR* constexpr_;
17091 
17092  assert(*nexprtrees > 0);
17093  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
17094  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
17095  }
17096 
17097  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
17098 
17099  break;
17100  }
17101 
17102  default:
17103  SCIPerrorMessage("unexpected operator type %d\n", node->op);
17104  return SCIP_ERROR;
17105  } /*lint !e788*/
17106 
17107  return SCIP_OKAY;
17108 }
17109 
17110 /**@} */
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:13337
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15843
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:15524
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:456
#define NULL
Definition: def.h:246
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:14979
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:15179
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:16773
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:15263
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:137
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:14768
static SCIP_RETCODE polynomialdataMultiplyByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:955
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3174
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:2364
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:12973
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:14949
static SCIP_RETCODE exprgraphEnsureDepth(SCIP_EXPRGRAPH *exprgraph, int mindepth)
Definition: expr.c:12062
void SCIPsortPtrPtrRealInt(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_MAXSTRLEN
Definition: def.h:267
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:129
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:14919
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:15336
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:15023
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:12951
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:13466
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:15897
#define FALSE
Definition: def.h:72
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:2891
#define EPSEQ(x, y, eps)
Definition: def.h:182
#define EPSISINT(x, eps)
Definition: def.h:194
#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:14969
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10561
static void exprgraphNodeCheckSeparabilityComponent(SCIP_EXPRGRAPHNODE *node, int *compnr, int nchildcomps, int *childcomps, int nvars, int *varcomps)
Definition: expr.c:12001
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10253
static SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11332
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13102
#define TRUE
Definition: def.h:71
#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
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3009
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:12993
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:13327
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15822
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:14929
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:112
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:186
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:10323
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:448
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15383
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
int SCIPstrncpy(char *t, const char *s, int size)
Definition: misc.c:10296
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:15130
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13196
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:12838
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:14402
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:2113
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:3240
#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:13033
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:13184
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:15091
#define SCIP_ALLOC_ABORT(x)
Definition: def.h:348
#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:13043
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:13124
#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:450
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13208
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:14653
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13347
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:15725
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:14991
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:136
SCIP_RETCODE SCIPexprgraphCheckCurvature(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop)
Definition: expr.c:15929
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:13536
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:14939
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16737
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:13315
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:2925
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:9592
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:181
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:13440
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16287
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_CALL(x)
Definition: def.h:358
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12963
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:15083
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:14706
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:14618
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:13223
#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:13054
#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:13136
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:453
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:69
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:14637
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:442
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:15043
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:455
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:10354
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:216
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:16721
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:15063
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:13590
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:184
void SCIPexprgraphFreeNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14528
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:14580
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:123
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:2425
#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:118
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:13065
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:9630
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13148
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2163
#define SCIP_REAL_MAX
Definition: def.h:158
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:13091
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13003
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:183
#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:12706
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:185
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:130
SCIP_EXPRINTDATA * interpreterdata
Definition: struct_expr.h:63
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3256
#define exprcurvCos
Definition: expr.c:2105
#define MAX(x, y)
Definition: def.h:215
SCIP_Bool SCIPexprgraphFindVarNode(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_EXPRGRAPHNODE **varnode)
Definition: expr.c:15696
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8204
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13113
#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:13023
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:13517
SCIP_Bool parentssorted
Definition: struct_expr.h:134
#define SCIP_VARTYPE_CONTINUOUS_CHAR
Definition: def.h:131
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:13492
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:13303
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:13357
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:14434
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 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:16234
#define SCIP_DECL_USEREXPRCOPYDATA(x)
Definition: type_expr.h:293
#define SCIP_Real
Definition: def.h:157
#define EPSROUND(x, eps)
Definition: def.h:192
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:379
SCIP_RETCODE SCIPrandomCreate(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem, unsigned int initialseed)
Definition: misc.c:9576
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12983
#define SCIP_INVALID
Definition: def.h:177
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:14690
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:1826
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:10108
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:128
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:15972
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:12142
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:440
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:13080
SCIP_RETCODE SCIPexprintFreeData(SCIP_EXPRINTDATA **interpreterdata)
#define EPSFLOOR(x, eps)
Definition: def.h:190
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:119
static SCIP_DECL_HASHGETKEY(exprparseVarTableGetKey)
Definition: expr.c:4914
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:426
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13172
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3098
#define SCIP_ALLOC_TERMINATE(retcode, x, TERM)
Definition: def.h:389
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:337
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14959
#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:369
#define SCIPABORT()
Definition: def.h:330
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:12238
static void exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:11976
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15773
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:446
void SCIPintervalSetRoundingModeDownwards(void)
#define EPSZ(x, eps)
Definition: def.h:187
#define ABS(x)
Definition: def.h:211
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:13013
#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:15003
void SCIPsortIntReal(int *intarray, SCIP_Real *realarray, int len)
static SCIP_RETCODE exprgraphRemoveVar(SCIP_EXPRGRAPH *exprgraph, int varidx)
Definition: expr.c:12089
#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:14553
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13160