Scippy

SCIP

Solving Constraint Integer Programs

expr.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2018 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file nlpi/expr.c
17  * @brief methods for expressions, expression trees, expression graphs, and related
18  * @author Stefan Vigerske
19  * @author Thorsten Gellermann
20  * @author Ingmar Vierhaus (exprparse)
21  */
22 
23 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24 
25 #include <stdarg.h>
26 #include <string.h>
27 #include <math.h>
28 #include <ctype.h>
29 
30 #include "nlpi/pub_expr.h"
31 #include "nlpi/struct_expr.h"
32 #include "nlpi/exprinterpret.h"
33 
34 #include "scip/intervalarith.h"
35 #include "scip/pub_misc.h"
36 #include "scip/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 SUM */
3910  *op = SCIP_EXPR_SUM;
3911 
3912  return SCIP_OKAY;
3913  }
3914  }
3915 
3916  /* turn polynomial into linear expression */
3917  {
3918  SCIP_Real* lindata;
3919 
3920  /* monomial merging should ensure that each child appears in at most one monomial,
3921  * that monomials are ordered according to the child index, and that constant monomials have been removed
3922  */
3923 
3924  /* setup data of linear expression */
3925  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &lindata, polynomialdata->nmonomials + 1) );
3926 
3927  for( i = 0; i < polynomialdata->nmonomials; ++i )
3928  {
3929  assert(polynomialdata->monomials[i]->childidxs[0] == i);
3930  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3931  lindata[i] = polynomialdata->monomials[i]->coef; /*lint !e644*/
3932  }
3933  lindata[i] = polynomialdata->constant;
3934 
3935  polynomialdataFree(blkmem, &polynomialdata);
3936  *op = SCIP_EXPR_LINEAR;
3937  data->data = (void*)lindata;
3938 
3939  return SCIP_OKAY;
3940  }
3941  }
3942 
3943  if( maxdegree == 2 && (polynomialdata->nmonomials > 1 || polynomialdata->constant != 0.0 || polynomialdata->monomials[0]->coef != 1.0) )
3944  {
3945  /* polynomial is quadratic expression with more than one summand or with a constant or a square or bilinear term with coefficient != 1.0, so turn into SCIP_EXPR_QUADRATIC */
3946  SCIP_EXPRDATA_QUADRATIC* quaddata;
3947  int quadelemidx;
3948 
3949  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &quaddata) );
3950  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->quadelems, polynomialdata->nmonomials - nlinmonomials) );
3951  quaddata->nquadelems = polynomialdata->nmonomials - nlinmonomials;
3952  quaddata->constant = polynomialdata->constant;
3953  quaddata->sorted = FALSE; /* quadratic data is sorted different than polynomials */
3954 
3955  if( nlinmonomials > 0 )
3956  {
3957  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->lincoefs, nchildren) );
3958  BMSclearMemoryArray(quaddata->lincoefs, nchildren);
3959  }
3960  else
3961  quaddata->lincoefs = NULL;
3962 
3963  quadelemidx = 0;
3964  for( i = 0; i < polynomialdata->nmonomials; ++i )
3965  {
3966  assert(polynomialdata->monomials[i]->nfactors == 1 || polynomialdata->monomials[i]->nfactors == 2);
3967  if( polynomialdata->monomials[i]->nfactors == 1 )
3968  {
3969  if( polynomialdata->monomials[i]->exponents[0] == 1.0 )
3970  {
3971  /* monomial is a linear term */
3972  assert(quaddata->lincoefs != NULL);
3973  quaddata->lincoefs[polynomialdata->monomials[i]->childidxs[0]] += polynomialdata->monomials[i]->coef;
3974  }
3975  else
3976  {
3977  /* monomial should be a square term */
3978  assert(polynomialdata->monomials[i]->exponents[0] == 2.0);
3979  assert(quadelemidx < quaddata->nquadelems);
3980  quaddata->quadelems[quadelemidx].idx1 = polynomialdata->monomials[i]->childidxs[0];
3981  quaddata->quadelems[quadelemidx].idx2 = polynomialdata->monomials[i]->childidxs[0];
3982  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3983  ++quadelemidx;
3984  }
3985  }
3986  else
3987  {
3988  /* monomial should be a bilinear term */
3989  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3990  assert(polynomialdata->monomials[i]->exponents[1] == 1.0);
3991  assert(quadelemidx < quaddata->nquadelems);
3992  quaddata->quadelems[quadelemidx].idx1 = MIN(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3993  quaddata->quadelems[quadelemidx].idx2 = MAX(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3994  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3995  ++quadelemidx;
3996  }
3997  }
3998  assert(quadelemidx == quaddata->nquadelems);
3999 
4000  polynomialdataFree(blkmem, &polynomialdata);
4001 
4002  *op = SCIP_EXPR_QUADRATIC;
4003  data->data = (void*)quaddata;
4004 
4005  return SCIP_OKAY;
4006  }
4007 
4008  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 1 && polynomialdata->monomials[0]->coef == 1.0 )
4009  {
4010  /* polynomial is product of children */
4011  monomial = polynomialdata->monomials[0];
4012  assert(monomial->nfactors == nchildren);
4013 
4014  if( monomial->nfactors == 1 )
4015  {
4016  /* polynomial is x^k for some k */
4017  assert(monomial->exponents[0] != 1.0); /* should have been handled before */
4018  assert(monomial->childidxs[0] == 0);
4019 
4020  if( monomial->exponents[0] == 2.0 )
4021  {
4022  /* polynomial is x^2, so turn into SCIP_EXPR_SQUARE */
4023 
4024  polynomialdataFree(blkmem, &polynomialdata);
4025  data->data = NULL;
4026 
4027  *op = SCIP_EXPR_SQUARE;
4028 
4029  return SCIP_OKAY;
4030  }
4031 
4032  if( EPSISINT(monomial->exponents[0], 0.0) ) /*lint !e835*/
4033  {
4034  /* k is an integer, so turn into SCIP_EXPR_INTPOWER */
4035  int exponent;
4036 
4037  exponent = (int)EPSROUND(monomial->exponents[0], 0.0); /*lint !e835*/
4038 
4039  polynomialdataFree(blkmem, &polynomialdata);
4040 
4041  *op = SCIP_EXPR_INTPOWER;
4042  data->intval = exponent;
4043 
4044  return SCIP_OKAY;
4045  }
4046 
4047  if( monomial->exponents[0] == 0.5 )
4048  {
4049  /* polynomial is sqrt(x), so turn into SCIP_EXPR_SQRT */
4050 
4051  polynomialdataFree(blkmem, &polynomialdata);
4052  data->data = NULL;
4053 
4054  *op = SCIP_EXPR_SQRT;
4055 
4056  return SCIP_OKAY;
4057  }
4058 
4059  {
4060  /* polynomial is x^a with a some real number, so turn into SCIP_EXPR_REALPOWER */
4061  SCIP_Real exponent;
4062 
4063  exponent = monomial->exponents[0];
4064 
4065  polynomialdataFree(blkmem, &polynomialdata);
4066 
4067  *op = SCIP_EXPR_REALPOWER;
4068  data->dbl = exponent;
4069 
4070  return SCIP_OKAY;
4071  }
4072  }
4073 
4074  if( maxdegree == 2 && monomial->nfactors == 2 )
4075  {
4076  /* polynomial is product of two children, so turn into SCIP_EXPR_MUL */
4077  assert(monomial->exponents[0] == 1.0);
4078  assert(monomial->exponents[1] == 1.0);
4079 
4080  polynomialdataFree(blkmem, &polynomialdata);
4081  data->data = NULL;
4082 
4083  *op = SCIP_EXPR_MUL;
4084 
4085  return SCIP_OKAY;
4086  }
4087 
4088  if( maxdegree == monomial->nfactors )
4089  {
4090  /* polynomial is a product of n children, so turn into SCIP_EXPR_PRODUCT */
4091 
4092  polynomialdataFree(blkmem, &polynomialdata);
4093  data->data = NULL;
4094 
4095  *op = SCIP_EXPR_PRODUCT;
4096 
4097  return SCIP_OKAY;
4098  }
4099 
4100  if( monomial->nfactors == 2 && monomial->exponents[0] == 1.0 && monomial->exponents[1] == -1.0 )
4101  {
4102  /* polynomial is x/y, so turn into SCIP_EXPR_DIV */
4103  assert(monomial->childidxs[0] == 0);
4104  assert(monomial->childidxs[1] == 1);
4105 
4106  polynomialdataFree(blkmem, &polynomialdata);
4107  data->data = NULL;
4108 
4109  *op = SCIP_EXPR_DIV;
4110 
4111  return SCIP_OKAY;
4112  }
4113 
4114  if( monomial->nfactors == 2 && monomial->exponents[0] == -1.0 && monomial->exponents[1] == 1.0 )
4115  {
4116  /* polynomial is y/x, so turn into SCIP_EXPR_DIV */
4117  void* tmp;
4118 
4119  assert(monomial->childidxs[0] == 0);
4120  assert(monomial->childidxs[1] == 1);
4121 
4122  polynomialdataFree(blkmem, &polynomialdata);
4123  data->data = NULL;
4124 
4125  /* swap children */
4126  tmp = children[1]; /*lint !e613*/
4127  children[1] = children[0]; /*lint !e613*/
4128  children[0] = tmp; /*lint !e613*/
4129 
4130  *op = SCIP_EXPR_DIV;
4131 
4132  return SCIP_OKAY;
4133  }
4134  }
4135 
4136  return SCIP_OKAY;
4137 }
4138 
4139 /** adds copies of expressions to the array of children of a sum, product, linear, quadratic, or polynomial expression
4140  *
4141  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
4142  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
4143  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
4144  */
4145 static
4147  BMS_BLKMEM* blkmem, /**< block memory */
4148  SCIP_EXPR* expr, /**< quadratic or polynomial expression */
4149  int nexprs, /**< number of expressions to add */
4150  SCIP_EXPR** exprs, /**< expressions to add */
4151  SCIP_Bool comparechildren, /**< whether to compare expressions with already existing children (no effect for sum and product) */
4152  SCIP_Real eps, /**< which epsilon to use when comparing expressions */
4153  int* childmap /**< array where to store mapping of indices from exprs to children array in expr, or NULL if not of interest */
4154  )
4155 {
4156  int i;
4157 
4158  assert(blkmem != NULL);
4159  assert(expr != NULL);
4160  assert(expr->op == SCIP_EXPR_SUM || expr->op == SCIP_EXPR_PRODUCT || expr->op == SCIP_EXPR_LINEAR || expr->op == SCIP_EXPR_QUADRATIC || expr->op == SCIP_EXPR_POLYNOMIAL);
4161  assert(exprs != NULL || nexprs == 0);
4162 
4163  if( nexprs == 0 )
4164  return SCIP_OKAY;
4165 
4166  switch( expr->op )
4167  {
4168  case SCIP_EXPR_SUM:
4169  case SCIP_EXPR_PRODUCT:
4170  {
4171  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4172  for( i = 0; i < nexprs; ++i )
4173  {
4174  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren + i], exprs[i]) ); /*lint !e613*/
4175  if( childmap != NULL )
4176  childmap[i] = expr->nchildren + i;
4177  }
4178  expr->nchildren += nexprs;
4179 
4180  break;
4181  }
4182 
4183  case SCIP_EXPR_LINEAR:
4184  case SCIP_EXPR_QUADRATIC:
4185  case SCIP_EXPR_POLYNOMIAL:
4186  {
4187  int j;
4188  int orignchildren;
4189  SCIP_Bool existsalready;
4190 
4191  orignchildren = expr->nchildren;
4192  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4193 
4194  for( i = 0; i < nexprs; ++i )
4195  {
4196  existsalready = FALSE;
4197  if( comparechildren )
4198  for( j = 0; j < orignchildren; ++j )
4199  /* during simplification of polynomials, their may be NULL's in children array */
4200  if( expr->children[j] != NULL && SCIPexprAreEqual(expr->children[j], exprs[i], eps) ) /*lint !e613*/
4201  {
4202  existsalready = TRUE;
4203  break;
4204  }
4205 
4206  if( !existsalready )
4207  {
4208  /* add copy of exprs[j] to children array */
4209  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren], exprs[i]) ); /*lint !e613*/
4210  if( childmap != NULL )
4211  childmap[i] = expr->nchildren;
4212  ++expr->nchildren;
4213  }
4214  else
4215  {
4216  if( childmap != NULL )
4217  childmap[i] = j; /*lint !e644*/
4218  if( expr->op == SCIP_EXPR_LINEAR )
4219  {
4220  /* if linear expression, increase coefficient by 1.0 */
4221  ((SCIP_Real*)expr->data.data)[j] += 1.0;
4222  }
4223  }
4224  }
4225 
4226  /* shrink children array to actually used size */
4227  assert(comparechildren || expr->nchildren == orignchildren + nexprs);
4228  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, orignchildren + nexprs, expr->nchildren) );
4229 
4230  if( expr->op == SCIP_EXPR_LINEAR && expr->nchildren > orignchildren )
4231  {
4232  /* if linear expression, then add 1.0 coefficients for new expressions */
4233  SCIP_Real* data;
4234 
4235  data = (SCIP_Real*)expr->data.data;
4236  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, expr->nchildren + 1) );
4237  data[expr->nchildren] = data[orignchildren]; /* move constant from old end to new end */
4238  for( i = orignchildren; i < expr->nchildren; ++i )
4239  data[i] = 1.0;
4240  expr->data.data = (void*)data;
4241  }
4242  else if( expr->op == SCIP_EXPR_QUADRATIC && expr->nchildren > orignchildren )
4243  {
4244  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
4246 
4247  data = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
4248  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, expr->nchildren) );
4249  BMSclearMemoryArray(&data->lincoefs[orignchildren], expr->nchildren - orignchildren); /*lint !e866*/
4250  }
4251 
4252  break;
4253  }
4254 
4255  default:
4256  SCIPerrorMessage("exprsimplifyAddChildren cannot be called for operand %d\n", expr->op);
4257  return SCIP_INVALIDDATA;
4258  } /*lint !e788*/
4259 
4260  return SCIP_OKAY;
4261 }
4262 
4263 /** converts expressions into polynomials, where possible and obvious */
4264 static
4266  BMS_BLKMEM* blkmem, /**< block memory data structure */
4267  SCIP_EXPR* expr /**< expression to convert */
4268  )
4269 {
4270  int i;
4271 
4272  assert(expr != NULL);
4273 
4274  for( i = 0; i < expr->nchildren; ++i )
4275  {
4277  }
4278 
4279  SCIP_CALL( exprConvertToPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren) );
4280 
4281  return SCIP_OKAY;
4282 }
4283 
4284 /** removes duplicate children in a polynomial expression
4285  *
4286  * Leaves NULL's in children array.
4287  */
4288 static
4290  BMS_BLKMEM* blkmem, /**< block memory data structure */
4291  SCIP_EXPR* expr, /**< expression */
4292  SCIP_Real eps /**< threshold for zero */
4293  )
4294 {
4295  SCIP_Bool foundduplicates;
4296  int* childmap;
4297  int i;
4298  int j;
4299 
4300  assert(blkmem != NULL);
4301  assert(expr != NULL);
4302  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4303 
4304  if( expr->nchildren == 0 )
4305  return SCIP_OKAY;
4306 
4307  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4308 
4309  foundduplicates = FALSE;
4310  for( i = 0; i < expr->nchildren; ++i )
4311  {
4312  if( expr->children[i] == NULL )
4313  continue;
4314  childmap[i] = i; /*lint !e644*/
4315 
4316  for( j = i+1; j < expr->nchildren; ++j )
4317  {
4318  if( expr->children[j] == NULL )
4319  continue;
4320 
4321  if( SCIPexprAreEqual(expr->children[i], expr->children[j], eps) )
4322  {
4323  /* forget about expr j and remember that is to be replaced by i */
4324  SCIPexprFreeDeep(blkmem, &expr->children[j]);
4325  childmap[j] = i;
4326  foundduplicates = TRUE;
4327  }
4328  }
4329  }
4330 
4331  /* apply childmap to monomials */
4332  if( foundduplicates )
4334 
4335  /* free childmap */
4336  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4337 
4338  return SCIP_OKAY;
4339 }
4340 
4341 /** eliminates NULL's in children array and shrinks it to actual size */
4342 static
4344  BMS_BLKMEM* blkmem, /**< block memory data structure */
4345  SCIP_EXPR* expr /**< expression */
4346  )
4347 {
4348  int* childmap;
4349  int lastnonnull;
4350  int i;
4351 
4352  assert(blkmem != NULL);
4353  assert(expr != NULL);
4354  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4355 
4356  if( expr->nchildren == 0 )
4357  return SCIP_OKAY;
4358 
4359  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4360 
4361  /* close gaps in children array */
4362  lastnonnull = expr->nchildren-1;
4363  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4364  --lastnonnull;
4365  for( i = 0; i <= lastnonnull; ++i )
4366  {
4367  if( expr->children[i] != NULL )
4368  {
4369  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
4370  continue;
4371  }
4372  assert(expr->children[lastnonnull] != NULL);
4373 
4374  /* move child at lastnonnull to position i */
4375  expr->children[i] = expr->children[lastnonnull];
4376  expr->children[lastnonnull] = NULL;
4377  childmap[lastnonnull] = i;
4378 
4379  /* update lastnonnull */
4380  --lastnonnull;
4381  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4382  --lastnonnull;
4383  }
4384  assert(i > lastnonnull);
4385 
4386  /* apply childmap to monomials */
4387  if( lastnonnull < expr->nchildren-1 )
4389 
4390  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4391 
4392  /* shrink children array */
4393  if( lastnonnull >= 0 )
4394  {
4395  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, lastnonnull+1) );
4396  expr->nchildren = lastnonnull+1;
4397  }
4398  else
4399  {
4400  BMSfreeBlockMemoryArray(blkmem, &expr->children, expr->nchildren);
4401  expr->nchildren = 0;
4402  }
4403 
4404  return SCIP_OKAY;
4405 }
4406 
4407 /** checks which children are still in use and frees those which are not */
4408 static
4410  BMS_BLKMEM* blkmem, /**< block memory data structure */
4411  SCIP_EXPR* expr /**< polynomial expression */
4412  )
4413 {
4414  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4415  SCIP_EXPRDATA_MONOMIAL* monomial;
4416  SCIP_Bool* childinuse;
4417  int i;
4418  int j;
4419 
4420  assert(blkmem != NULL);
4421  assert(expr != NULL);
4422 
4423  if( expr->nchildren == 0 )
4424  return SCIP_OKAY;
4425 
4426  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4427  assert(polynomialdata != NULL);
4428 
4429  /* check which children are still in use */
4430  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, expr->nchildren) );
4431  BMSclearMemoryArray(childinuse, expr->nchildren); /*lint !e644*/
4432  for( i = 0; i < polynomialdata->nmonomials; ++i )
4433  {
4434  monomial = polynomialdata->monomials[i];
4435  assert(monomial != NULL);
4436 
4437  for( j = 0; j < monomial->nfactors; ++j )
4438  {
4439  assert(monomial->childidxs[j] >= 0);
4440  assert(monomial->childidxs[j] < expr->nchildren);
4441  childinuse[monomial->childidxs[j]] = TRUE;
4442  }
4443  }
4444 
4445  /* free children that are not used in any monomial */
4446  for( i = 0; i < expr->nchildren; ++i )
4447  if( expr->children[i] != NULL && !childinuse[i] )
4448  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4449 
4450  BMSfreeBlockMemoryArray(blkmem, &childinuse, expr->nchildren);
4451 
4452  return SCIP_OKAY;
4453 }
4454 
4455 /** flattens polynomials in polynomials, check for constants in non-polynomials expressions
4456  *
4457  * exprsimplifyConvertToPolynomials should have been called before to eliminate simple polynomial operands.
4458  */
4459 static
4461  BMS_BLKMEM* blkmem, /**< block memory data structure */
4462  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4463  SCIP_EXPR* expr, /**< expression */
4464  SCIP_Real eps, /**< threshold, under which values are treat as 0 */
4465  int maxexpansionexponent/**< maximal exponent for which we still expand non-monomial polynomials */
4466  )
4467 {
4468  int i;
4469 
4470  assert(expr != NULL);
4471 
4472  for( i = 0; i < expr->nchildren; ++i )
4473  {
4474  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr->children[i], eps, maxexpansionexponent) );
4475  }
4476 
4477  switch( SCIPexprGetOperator(expr) )
4478  {
4479  case SCIP_EXPR_VARIDX:
4480  case SCIP_EXPR_CONST:
4481  case SCIP_EXPR_PARAM:
4482  case SCIP_EXPR_PLUS:
4483  case SCIP_EXPR_MINUS:
4484  case SCIP_EXPR_MUL:
4485  case SCIP_EXPR_DIV:
4486  case SCIP_EXPR_SQUARE:
4487  case SCIP_EXPR_SQRT:
4488  case SCIP_EXPR_INTPOWER:
4489  case SCIP_EXPR_REALPOWER:
4490  case SCIP_EXPR_SIGNPOWER:
4491  break;
4492 
4493  case SCIP_EXPR_EXP:
4494  case SCIP_EXPR_LOG:
4495  case SCIP_EXPR_SIN:
4496  case SCIP_EXPR_COS:
4497  case SCIP_EXPR_TAN:
4498  /* case SCIP_EXPR_ERF: */
4499  /* case SCIP_EXPR_ERFI: */
4500  case SCIP_EXPR_ABS:
4501  case SCIP_EXPR_SIGN:
4502  {
4503  /* check if argument is a constant */
4504  if( (expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) ||
4505  expr->children[0]->op == SCIP_EXPR_CONST )
4506  {
4507  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4508  SCIP_Real exprval;
4509 
4510  /* since child0 has no children and it's polynomial was flattened, it should have no monomials */
4511  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4512 
4513  /* evaluate expression in constant polynomial */
4514  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4515 
4516  /* create polynomial */
4517  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4518 
4519  expr->op = SCIP_EXPR_POLYNOMIAL;
4520  expr->data.data = (void*)polynomialdata;
4521 
4522  /* forget child */
4523  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4524  BMSfreeBlockMemoryArray(blkmem, &expr->children, 1);
4525  expr->nchildren = 0;
4526  }
4527 
4528  break;
4529  }
4530 
4531  case SCIP_EXPR_MIN:
4532  case SCIP_EXPR_MAX:
4533  {
4534  /* check if both arguments are constants */
4535  if( ((expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) || expr->children[0]->op == SCIP_EXPR_CONST) &&
4536  ((expr->children[1]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[1]) == 0) || expr->children[1]->op == SCIP_EXPR_CONST) )
4537  {
4538  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4539  SCIP_Real exprval;
4540 
4541  /* since children have no children and it's polynomial was flattened, it should have no monomials */
4542  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4543  assert(expr->children[1]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[1]) == 0);
4544 
4545  /* evaluate expression in constants */
4546  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4547 
4548  /* create polynomial */
4549  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4550 
4551  expr->op = SCIP_EXPR_POLYNOMIAL;
4552  expr->data.data = (void*)polynomialdata;
4553 
4554  /* forget children */
4555  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4556  SCIPexprFreeDeep(blkmem, &expr->children[1]);
4557  BMSfreeBlockMemoryArray(blkmem, &expr->children, 2);
4558  expr->nchildren = 0;
4559  }
4560 
4561  break;
4562  }
4563 
4564  case SCIP_EXPR_SUM:
4565  case SCIP_EXPR_PRODUCT:
4566  case SCIP_EXPR_LINEAR:
4567  case SCIP_EXPR_QUADRATIC:
4568  case SCIP_EXPR_USER:
4569  break;
4570 
4571  case SCIP_EXPR_POLYNOMIAL:
4572  {
4573  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4574  SCIP_EXPRDATA_MONOMIAL* monomial;
4575  SCIP_Bool removechild;
4576  int* childmap;
4577  int childmapsize;
4578  int j;
4579 
4580  /* simplify current polynomial */
4582  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4583 
4584  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4585  assert(polynomialdata != NULL);
4586 
4587  SCIPdebugMessage("expand factors in expression ");
4588  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4589  SCIPdebugPrintf("\n");
4590 
4591  childmap = NULL;
4592  childmapsize = 0;
4593 
4594  /* resolve children that are constants
4595  * we do this first, because it reduces the degree and number of factors in the monomials,
4596  * thereby allowing some expansions of polynomials that may not be possible otherwise, e.g., turning c0*c1 with c0=quadratic and c1=constant into a single monomial
4597  */
4598  for( i = 0; i < expr->nchildren; ++i )
4599  {
4600  if( expr->children[i] == NULL )
4601  continue;
4602 
4603  if( SCIPexprGetOperator(expr->children[i]) != SCIP_EXPR_CONST )
4604  continue;
4605 
4606  removechild = TRUE; /* we intend to delete children[i] */
4607 
4608  if( childmapsize < expr->children[i]->nchildren )
4609  {
4610  int newsize;
4611 
4612  newsize = calcGrowSize(expr->children[i]->nchildren);
4613  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4614  childmapsize = newsize;
4615  }
4616 
4617  /* put constant of child i into every monomial where child i is used */
4618  for( j = 0; j < polynomialdata->nmonomials; ++j )
4619  {
4620  int factorpos;
4621  SCIP_Bool success;
4622 
4623  monomial = polynomialdata->monomials[j];
4624  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4625  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4626 
4627  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4628  {
4629  assert(factorpos >= 0);
4630  assert(factorpos < monomial->nfactors);
4631  /* assert that factors have been merged */
4632  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4633  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4634 
4635  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4636  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4637  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4638 
4639  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && SCIPexprGetOpReal(expr->children[i]) < 0.0 ) /*lint !e835*/
4640  {
4641  /* if constant is negative and our exponent is not integer, then cannot do expansion */
4642  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n",
4643  SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4644  success = FALSE;
4645  }
4646  else
4647  {
4648  monomial->coef *= pow(SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4649 
4650  /* move last factor to position factorpos */
4651  if( factorpos < monomial->nfactors-1 )
4652  {
4653  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
4654  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
4655  }
4656  --monomial->nfactors;
4657  monomial->sorted = FALSE;
4658  polynomialdata->sorted = FALSE;
4659 
4660  success = TRUE;
4661  }
4662 
4663  if( !success )
4664  removechild = FALSE;
4665  }
4666  }
4667 
4668  /* forget about child i, if it is not used anymore */
4669  if( removechild )
4670  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4671 
4672  /* simplify current polynomial again */
4673  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4674  }
4675 
4676  /* try to resolve children that are polynomials itself */
4677  for( i = 0; i < expr->nchildren; ++i )
4678  {
4679  if( expr->children[i] == NULL )
4680  continue;
4681 
4683  continue;
4684 
4685  removechild = TRUE; /* we intend to delete children[i] */
4686 
4687  if( childmapsize < expr->children[i]->nchildren )
4688  {
4689  int newsize;
4690 
4691  newsize = calcGrowSize(expr->children[i]->nchildren);
4692  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4693  childmapsize = newsize;
4694  }
4695 
4696  /* add children of child i */
4697  SCIP_CALL( exprsimplifyAddChildren(blkmem, expr, expr->children[i]->nchildren, expr->children[i]->children, TRUE, eps, childmap) );
4698 
4699  /* put polynomial of child i into every monomial where child i is used */
4700  j = 0;
4701  while( j < polynomialdata->nmonomials )
4702  {
4703  int factorpos;
4704  SCIP_Bool success;
4705 
4706  monomial = polynomialdata->monomials[j];
4707  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4708  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4709 
4710  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4711  {
4712  assert(factorpos >= 0);
4713  assert(factorpos < monomial->nfactors);
4714  /* assert that factors have been merged */
4715  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4716  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4717 
4718  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4719  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4720  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4721 
4722  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
4723  (SCIP_EXPRDATA_POLYNOMIAL*)expr->children[i]->data.data, childmap, maxexpansionexponent, &success) );
4724 
4725  if( !success )
4726  {
4727  removechild = FALSE;
4728  ++j;
4729  }
4730  }
4731  else
4732  ++j;
4733 
4734  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
4735  * we thus repeat with index j, if a factor was successfully expanded
4736  */
4737  }
4738 
4739  /* forget about child i, if it is not used anymore */
4740  if( removechild )
4741  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4742 
4743  /* simplify current polynomial again */
4744  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4745  }
4746 
4747  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
4748 
4749  /* free children that are not in use anymore */
4751 
4752  /* remove NULLs from children array */
4754 
4755  /* if no children left, then it's a constant polynomial -> change into EXPR_CONST */
4756  if( expr->nchildren == 0 )
4757  {
4758  SCIP_Real val;
4759 
4760  /* if no children, then it should also have no monomials */
4761  assert(polynomialdata->nmonomials == 0);
4762 
4763  val = polynomialdata->constant;
4764  polynomialdataFree(blkmem, &polynomialdata);
4765 
4766  expr->op = SCIP_EXPR_CONST;
4767  expr->data.dbl = val;
4768  }
4769 
4770  SCIPdebugMessage("-> ");
4771  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4772  SCIPdebugPrintf("\n");
4773 
4774  break;
4775  }
4776 
4777  case SCIP_EXPR_LAST:
4778  break;
4779  } /*lint !e788*/
4780 
4781  return SCIP_OKAY;
4782 }
4783 
4784 /** separates linear monomials from an expression, if it is a polynomial expression
4785  *
4786  * Separates only those linear terms whose variable is not used otherwise in the expression.
4787  */
4788 static
4790  BMS_BLKMEM* blkmem, /**< block memory data structure */
4791  SCIP_EXPR* expr, /**< expression */
4792  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
4793  int nvars, /**< number of variables in expression */
4794  int* nlinvars, /**< buffer to store number of linear variables in linear part */
4795  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part */
4796  SCIP_Real* lincoefs /**< array to store coefficients of linear part */
4797  )
4798 {
4799  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4800  SCIP_EXPRDATA_MONOMIAL* monomial;
4801  int* varsusage;
4802  int* childusage;
4803  int childidx;
4804  int i;
4805  int j;
4806 
4807  assert(blkmem != NULL);
4808  assert(expr != NULL);
4809  assert(nlinvars != NULL);
4810  assert(linidxs != NULL);
4811  assert(lincoefs != NULL);
4812 
4813  *nlinvars = 0;
4814 
4816  return SCIP_OKAY;
4817 
4818  if( SCIPexprGetNChildren(expr) == 0 )
4819  return SCIP_OKAY;
4820 
4821  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4822  assert(polynomialdata != NULL);
4823 
4824  /* get variable usage */
4825  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &varsusage, nvars) );
4826  BMSclearMemoryArray(varsusage, nvars); /*lint !e644*/
4827  SCIPexprGetVarsUsage(expr, varsusage);
4828 
4829  /* get child usage: how often each child is used in the polynomial */
4830  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childusage, expr->nchildren) );
4831  BMSclearMemoryArray(childusage, expr->nchildren); /*lint !e644*/
4832  for( i = 0; i < polynomialdata->nmonomials; ++i )
4833  {
4834  monomial = polynomialdata->monomials[i];
4835  assert(monomial != NULL);
4836  for( j = 0; j < monomial->nfactors; ++j )
4837  {
4838  assert(monomial->childidxs[j] >= 0);
4839  assert(monomial->childidxs[j] < expr->nchildren);
4840  ++childusage[monomial->childidxs[j]];
4841  }
4842  }
4843 
4844  /* move linear monomials out of polynomial */
4845  for( i = 0; i < polynomialdata->nmonomials; ++i )
4846  {
4847  monomial = polynomialdata->monomials[i];
4848  assert(monomial != NULL);
4849  if( monomial->nfactors != 1 )
4850  continue;
4851  if( monomial->exponents[0] != 1.0 )
4852  continue;
4853  childidx = monomial->childidxs[0];
4854  if( SCIPexprGetOperator(expr->children[childidx]) != SCIP_EXPR_VARIDX )
4855  continue;
4856 
4857  /* we are at a linear monomial in a variable */
4858  assert(SCIPexprGetOpIndex(expr->children[childidx]) < nvars);
4859  if( childusage[childidx] == 1 && varsusage[SCIPexprGetOpIndex(expr->children[childidx])] == 1 )
4860  {
4861  /* if the child expression is not used in another monomial (which would due to merging be not linear)
4862  * and if the variable is not used somewhere else in the tree,
4863  * then move this monomial into linear part and free child
4864  */
4865  linidxs[*nlinvars] = SCIPexprGetOpIndex(expr->children[childidx]);
4866  lincoefs[*nlinvars] = monomial->coef;
4867  ++*nlinvars;
4868 
4869  SCIPexprFreeDeep(blkmem, &expr->children[childidx]);
4870  monomial->coef = 0.0;
4871  monomial->nfactors = 0;
4872  }
4873  }
4874 
4875  BMSfreeBlockMemoryArray(blkmem, &varsusage, nvars);
4876  BMSfreeBlockMemoryArray(blkmem, &childusage, expr->nchildren);
4877 
4878  if( *nlinvars > 0 )
4879  {
4880  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
4881  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, FALSE);
4883  }
4884 
4885  return SCIP_OKAY;
4886 }
4887 
4888 /** converts polynomial expressions back into simpler expressions, where possible */
4889 static
4891  BMS_BLKMEM* blkmem, /**< block memory data structure */
4892  SCIP_EXPR* expr /**< expression to convert back */
4893  )
4894 {
4895  int i;
4896 
4897  assert(blkmem != NULL);
4898  assert(expr != NULL);
4899 
4900  for( i = 0; i < expr->nchildren; ++i )
4901  {
4903  }
4904 
4905  if( expr->op != SCIP_EXPR_POLYNOMIAL )
4906  return SCIP_OKAY;
4907 
4908  SCIP_CALL( exprUnconvertPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren, (void**)expr->children) );
4909 
4910  return SCIP_OKAY;
4911 }
4912 
4913 static
4914 SCIP_DECL_HASHGETKEY( exprparseVarTableGetKey )
4915 { /*lint --e{715}*/
4916  return (void*)((char*)elem + sizeof(int));
4917 }
4918 
4919 /** parses a variable name from a string and creates corresponding expression
4920  *
4921  * Creates a new variable index if variable not seen before, updates varnames and vartable structures.
4922  */
4923 static
4925  BMS_BLKMEM* blkmem, /**< block memory data structure */
4926  const char** str, /**< pointer to the string to be parsed */
4927  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
4928  int* nvars, /**< running number of encountered variables so far */
4929  int** varnames, /**< pointer to buffer to store new variable names */
4930  int* varnameslength, /**< pointer to length of the varnames buffer array */
4931  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
4932  SCIP_Real coefficient, /**< coefficient to be used when creating the expression */
4933  const char* varnameendptr /**< if a <varname> should be parsed, set this to NULL. Then, str points to the '<'
4934  else, str should point to the first letter of the varname, and varnameendptr should
4935  point one char behind the last char of the variable name */
4936  )
4937 {
4938  int namelength;
4939  int varidx;
4940  char varname[SCIP_MAXSTRLEN];
4941  void* element;
4942 
4943  assert(blkmem != NULL);
4944  assert(str != NULL);
4945  assert(expr != NULL);
4946  assert(nvars != NULL);
4947  assert(varnames != NULL);
4948  assert(vartable != NULL);
4949 
4950  if( varnameendptr == NULL )
4951  {
4952  ++*str;
4953  varnameendptr = *str;
4954  while( varnameendptr[0] != '>' )
4955  ++varnameendptr;
4956  }
4957 
4958  namelength = varnameendptr - *str; /*lint !e712*/
4959  if( namelength >= SCIP_MAXSTRLEN )
4960  {
4961  SCIPerrorMessage("Variable name %.*s is too long for buffer in exprparseReadVariable.\n", namelength, str);
4962  return SCIP_READERROR;
4963  }
4964 
4965  memcpy(varname, *str, namelength * sizeof(char));
4966  varname[namelength] = '\0';
4967 
4968  element = SCIPhashtableRetrieve(vartable, varname);
4969  if( element != NULL )
4970  {
4971  /* variable is old friend */
4972  assert(strcmp((char*)element + sizeof(int), varname) == 0);
4973 
4974  varidx = *(int*)element;
4975  }
4976  else
4977  {
4978  /* variable is new */
4979  varidx = *nvars;
4980 
4981  (*varnameslength) -= (int)(1 + (strlen(varname) + 1) / sizeof(int) + 1);
4982  if( *varnameslength < 0 )
4983  {
4984  SCIPerrorMessage("Buffer in exprparseReadVariable is too short for varaible name %.*s.\n", namelength, str);
4985  return SCIP_READERROR;
4986  }
4987 
4988  /* store index of variable and variable name in varnames buffer */
4989  **varnames = varidx;
4990  strcpy((char*)(*varnames + 1), varname);
4991 
4992  /* insert variable into hashtable */
4993  SCIP_CALL( SCIPhashtableInsert(vartable, (void*)*varnames) );
4994 
4995  ++*nvars;
4996  *varnames += 1 + (strlen(varname) + 1) / sizeof(int) + 1;
4997  }
4998 
4999  /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
5000  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_VARIDX, varidx) ); /*lint !e613*/
5001  if( coefficient != 1.0 )
5002  {
5003  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, expr, &coefficient, 0.0) );
5004  }
5005 
5006  /* Move pointer to char behind end of variable */
5007  *str = varnameendptr + 1;
5008 
5009  /* consprint sometimes prints a variable type identifier which we don't need */
5010  if( (*str)[0] == '[' && (*str)[2] == ']' &&
5011  ((*str)[1] == SCIP_VARTYPE_BINARY_CHAR ||
5012  (*str)[1] == SCIP_VARTYPE_INTEGER_CHAR ||
5013  (*str)[1] == SCIP_VARTYPE_IMPLINT_CHAR ||
5014  (*str)[1] == SCIP_VARTYPE_CONTINUOUS_CHAR ) )
5015  *str += 3;
5016 
5017  return SCIP_OKAY;
5018 }
5019 
5020 /** if str[0] points to an opening parenthesis, this function sets endptr to point to the matching closing bracket in str
5021  *
5022  * Searches for at most length characters.
5023  */
5024 static
5026  const char* str, /**< pointer to the string to be parsed */
5027  const char** endptr, /**< pointer to point to the closing parenthesis */
5028  int length /**< length of the string to be parsed */
5029  )
5030 {
5031  int nopenbrackets;
5032 
5033  assert(str[0] == '(');
5034 
5035  *endptr = str;
5036 
5037  /* find the end of this expression */
5038  nopenbrackets = 0;
5039  while( (*endptr - str ) < length && !(nopenbrackets == 1 && *endptr[0] == ')') )
5040  {
5041  if( *endptr[0] == '(')
5042  ++nopenbrackets;
5043  if( *endptr[0] == ')')
5044  --nopenbrackets;
5045  ++*endptr;
5046  }
5047 
5048  if( *endptr[0] != ')' )
5049  {
5050  SCIPerrorMessage("unable to find closing parenthesis in unbalanced expression %.*s\n", length, str);
5051  return SCIP_READERROR;
5052  }
5053 
5054  return SCIP_OKAY;
5055 }
5056 
5057 /** this function sets endptr to point to the next separating comma in str
5058  *
5059  * That is, for a given string like "x+f(x,y),z", endptr will point to the comma before "z"
5060  *
5061  * Searches for at most length characters.
5062  */
5063 static
5065  const char* str, /**< pointer to the string to be parsed */
5066  const char** endptr, /**< pointer to point to the comma */
5067  int length /**< length of the string to be parsed */
5068  )
5069 {
5070  int nopenbrackets;
5071 
5072  *endptr = str;
5073 
5074  /* find a comma without open brackets */
5075  nopenbrackets = 0;
5076  while( (*endptr - str ) < length && !(nopenbrackets == 0 && *endptr[0] == ',') )
5077  {
5078  if( *endptr[0] == '(')
5079  ++nopenbrackets;
5080  if( *endptr[0] == ')')
5081  --nopenbrackets;
5082  ++*endptr;
5083  }
5084 
5085  if( *endptr[0] != ',' )
5086  {
5087  SCIPerrorMessage("unable to find separating comma in unbalanced expression %.*s\n", length, str);
5088  return SCIP_READERROR;
5089  }
5090 
5091  return SCIP_OKAY;
5092 }
5093 
5094 /** parses an expression from a string */
5095 static
5097  BMS_BLKMEM* blkmem, /**< block memory data structure */
5098  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
5099  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
5100  const char* str, /**< pointer to the string to be parsed */
5101  int length, /**< length of the string to be parsed */
5102  const char* lastchar, /**< pointer to the last char of str that should be parsed */
5103  int* nvars, /**< running number of encountered variables so far */
5104  int** varnames, /**< pointer to buffer to store new variable names */
5105  int* varnameslength, /**< pointer to length of the varnames buffer array */
5106  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
5107  int recursiondepth /**< current recursion depth */
5108  )
5109 { /*lint --e{712,747}*/
5110  SCIP_EXPR* arg1;
5111  SCIP_EXPR* arg2;
5112  const char* subexpptr;
5113  const char* subexpendptr;
5114  const char* strstart;
5115  const char* endptr;
5116  char* nonconstendptr;
5117  SCIP_Real number;
5118  int subexplength;
5119  int nopenbrackets;
5120 
5121  assert(blkmem != NULL);
5122  assert(expr != NULL);
5123  assert(str != NULL);
5124  assert(lastchar >= str);
5125  assert(nvars != NULL);
5126  assert(varnames != NULL);
5127  assert(vartable != NULL);
5128 
5129  assert(recursiondepth < 100);
5130 
5131  strstart = str; /* might be needed for error message... */
5132 
5133  SCIPdebugMessage("exprParse (%i): parsing %.*s\n", recursiondepth, (int) (lastchar-str + 1), str);
5134 
5135  /* ignore whitespace */
5136  while( isspace((unsigned char)*str) )
5137  ++str;
5138 
5139  /* look for a sum or difference not contained in brackets */
5140  subexpptr = str;
5141  nopenbrackets = 0;
5142 
5143  /* find the end of this expression
5144  * a '+' right at the beginning indicates a coefficient, not treated here, or a summation
5145  */
5146  while( subexpptr != lastchar && !(nopenbrackets == 0 && (subexpptr[0] == '+' || subexpptr[0] == '-') && subexpptr != str) )
5147  {
5148  if( subexpptr[0] == '(')
5149  ++nopenbrackets;
5150  if( subexpptr[0] == ')')
5151  --nopenbrackets;
5152  ++subexpptr;
5153  }
5154 
5155  if( subexpptr != lastchar )
5156  {
5157  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str, (int) ((subexpptr - 1) - str + 1), subexpptr - 1, nvars,
5158  varnames, varnameslength, vartable, recursiondepth + 1) );
5159 
5160  if( subexpptr[0] == '+' )
5161  ++subexpptr;
5162  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, subexpptr , (int) (lastchar - (subexpptr ) + 1), lastchar, nvars,
5163  varnames, varnameslength, vartable, recursiondepth + 1) );
5164 
5165  /* make new expression from two arguments
5166  * we always use add, because we leave the operator between the found expressions in the second argument
5167  * this way, we do not have to worry about ''minus brackets'' in the case of more then two summands:
5168  * a - b - c = a + (-b -c)
5169  */
5170  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5171 
5172  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5173  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5174  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5175 
5176  return SCIP_OKAY;
5177  }
5178 
5179  /* check for a bracketed subexpression */
5180  if( str[0] == '(' )
5181  {
5182  nopenbrackets = 0;
5183 
5184  subexplength = -1; /* we do not want the closing bracket in the string */
5185  subexpptr = str + 1; /* leave out opening bracket */
5186 
5187  /* find the end of this expression */
5188  while( subexplength < length && !(nopenbrackets == 1 && str[0] == ')') )
5189  {
5190  if( str[0] == '(' )
5191  ++nopenbrackets;
5192  if( str[0] == ')' )
5193  --nopenbrackets;
5194  ++str;
5195  ++subexplength;
5196  }
5197  subexpendptr = str - 1; /* leave out closing bracket */
5198 
5199  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, subexpptr, subexplength, subexpendptr, nvars, varnames,
5200  varnameslength, vartable, recursiondepth + 1) );
5201  ++str;
5202  }
5203  else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+')
5204  && (isdigit((unsigned char)str[1]) || str[1] == ' ')) )
5205  {
5206  /* check if there is a lonely minus coming, indicating a -1.0 */
5207  if( str[0] == '-' && str[1] == ' ' )
5208  {
5209  number = -1.0;
5210  nonconstendptr = (char*) str + 1;
5211  }
5212  /* check if there is a number coming */
5213  else if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5214  {
5215  SCIPerrorMessage("error parsing number from <%s>\n", str);
5216  return SCIP_READERROR;
5217  }
5218  str = nonconstendptr;
5219 
5220  /* ignore whitespace */
5221  while( isspace((unsigned char)*str) && str != lastchar )
5222  ++str;
5223 
5224  if( str[0] != '*' && str[0] != '/' && str[0] != '+' && str[0] != '-' && str[0] != '^' )
5225  {
5226  if( str < lastchar )
5227  {
5228  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, str, (int)(lastchar - str) + 1, lastchar, nvars, varnames,
5229  varnameslength, vartable, recursiondepth + 1) );
5230  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, *expr, number) );
5231  }
5232  else
5233  {
5234  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5235  }
5236  str = lastchar + 1;
5237  }
5238  else
5239  {
5240  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5241  }
5242  }
5243  else if( str[0] == '<' )
5244  {
5245  /* check if expressions begins with a variable */
5246  SCIP_CALL( exprparseReadVariable(blkmem, &str, expr, nvars, varnames, varnameslength, vartable, 1.0, NULL) );
5247  }
5248  /* four character operators */
5249  else if( strncmp(str, "sqrt", 4) == 0 )
5250  {
5251  str += 4;
5252  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5253  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5254  varnameslength, vartable, recursiondepth + 1) );
5255  str = endptr + 1;
5256 
5257  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQRT, arg1) );
5258  }
5259  /* three character operators with 1 argument */
5260  else if(
5261  strncmp(str, "abs", 3) == 0 ||
5262  strncmp(str, "cos", 3) == 0 ||
5263  strncmp(str, "exp", 3) == 0 ||
5264  strncmp(str, "log", 3) == 0 ||
5265  strncmp(str, "sin", 3) == 0 ||
5266  strncmp(str, "sqr", 3) == 0 ||
5267  strncmp(str, "tan", 3) == 0 )
5268  {
5269  const char* opname = str;
5270 
5271  str += 3;
5272  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5273  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5274  varnameslength, vartable, recursiondepth + 1) );
5275  str = endptr + 1;
5276 
5277  if( strncmp(opname, "abs", 3) == 0 )
5278  {
5279  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_ABS, arg1) );
5280  }
5281  else if( strncmp(opname, "cos", 3) == 0 )
5282  {
5283  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_COS, arg1) );
5284  }
5285  else if( strncmp(opname, "exp", 3) == 0 )
5286  {
5287  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, arg1) );
5288  }
5289  else if( strncmp(opname, "log", 3) == 0 )
5290  {
5291  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5292  }
5293  else if( strncmp(opname, "sin", 3) == 0 )
5294  {
5295  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIN, arg1) );
5296  }
5297  else if( strncmp(opname, "sqr", 3) == 0 )
5298  {
5299  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQUARE, arg1) );
5300  }
5301  else
5302  {
5303  assert(strncmp(opname, "tan", 3) == 0);
5304  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_TAN, arg1) );
5305  }
5306  }
5307  /* three character operators with 2 arguments */
5308  else if(
5309  strncmp(str, "max", 3) == 0 ||
5310  strncmp(str, "min", 3) == 0 )
5311  {
5312  /* we have a string of the form "min(...,...)" or "max(...,...)"
5313  * first find the closing parenthesis, then the comma
5314  */
5315  const char* comma;
5316  SCIP_EXPROP op;
5317 
5318  op = (str[1] == 'a' ? SCIP_EXPR_MAX : SCIP_EXPR_MIN);
5319 
5320  str += 3;
5321  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5322 
5323  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5324 
5325  /* parse first argument [str+1..comma-1] */
5326  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5327  varnameslength, vartable, recursiondepth + 1) );
5328 
5329  /* parse second argument [comma+1..endptr] */
5330  ++comma;
5331  while( comma < endptr && *comma == ' ' )
5332  ++comma;
5333 
5334  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, comma, endptr - comma, endptr - 1, nvars, varnames,
5335  varnameslength, vartable, recursiondepth + 1) );
5336 
5337  SCIP_CALL( SCIPexprCreate(blkmem, expr, op, arg1, arg2) );
5338 
5339  str = endptr + 1;
5340  }
5341  else if( strncmp(str, "power", 5) == 0 )
5342  {
5343  /* we have a string of the form "power(...,integer)" (thus, intpower)
5344  * first find the closing parenthesis, then the comma
5345  */
5346  const char* comma;
5347  int exponent;
5348 
5349  str += 5;
5350  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5351 
5352  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5353 
5354  /* parse first argument [str+1..comma-1] */
5355  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5356  varnameslength, vartable, recursiondepth + 1) );
5357 
5358  ++comma;
5359  /* parse second argument [comma, endptr-1]: it needs to be an integer */
5360  while( comma < endptr && *comma == ' ' )
5361  ++comma;
5362  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5363  {
5364  SCIPerrorMessage("error parsing integer exponent from <%s>\n", comma);
5365  }
5366  if( !SCIPstrToIntValue(comma, &exponent, &nonconstendptr) )
5367  {
5368  SCIPerrorMessage("error parsing integer from <%s>\n", comma);
5369  return SCIP_READERROR;
5370  }
5371 
5372  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, exponent) );
5373 
5374  str = endptr + 1;
5375  }
5376  else if( strncmp(str, "realpower", 9) == 0 || strncmp(str, "signpower", 9) == 0 )
5377  {
5378  /* we have a string of the form "realpower(...,double)" or "signpower(...,double)"
5379  * first find the closing parenthesis, then the comma
5380  */
5381  const char* opname = str;
5382  const char* comma;
5383 
5384  str += 9;
5385  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5386 
5387  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5388 
5389  /* parse first argument [str+1..comma-1] */
5390  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5391  varnameslength, vartable, recursiondepth + 1) );
5392 
5393  ++comma;
5394  /* parse second argument [comma, endptr-1]: it needs to be an number */
5395  while( comma < endptr && *comma == ' ' )
5396  ++comma;
5397  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5398  {
5399  SCIPerrorMessage("error parsing number exponent from <%s>\n", comma);
5400  }
5401  if( !SCIPstrToRealValue(comma, &number, &nonconstendptr) )
5402  {
5403  SCIPerrorMessage("error parsing number from <%s>\n", comma);
5404  return SCIP_READERROR;
5405  }
5406 
5407  if( strncmp(opname, "realpower", 9) == 0 )
5408  {
5409  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, number) );
5410  }
5411  else
5412  {
5413  assert(strncmp(opname, "signpower", 9) == 0);
5414  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIGNPOWER, arg1, number) );
5415  }
5416 
5417  str = endptr + 1;
5418  }
5419  else if( isalpha(*str) || *str == '_' || *str == '#' )
5420  {
5421  /* check for a variable, that was not recognized earlier because somebody omitted the '<' and '>' we need for
5422  * SCIPparseVarName, making everyones life harder;
5423  * we allow only variable names starting with a character or underscore here
5424  */
5425  const char* varnamestartptr = str;
5426 
5427  /* allow only variable names containing characters, digits, hash marks, and underscores here */
5428  while( isalnum(str[0]) || str[0] == '_' || str[0] == '#' )
5429  ++str;
5430 
5431  SCIP_CALL( exprparseReadVariable(blkmem, &varnamestartptr, expr, nvars, varnames, varnameslength,
5432  vartable, 1.0, str) );
5433  }
5434  else
5435  {
5436  SCIPerrorMessage("parsing of invalid expression %.*s.\n", (int) (lastchar - str + 1), str);
5437  return SCIP_READERROR;
5438  }
5439 
5440  /* if we are one char behind lastchar, we are done */
5441  if( str == lastchar + 1)
5442  {
5443  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5444  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5445  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5446 
5447  return SCIP_OKAY;
5448  }
5449 
5450  /* check if we are still in bounds */
5451  if( str > lastchar + 1)
5452  {
5453  SCIPerrorMessage("error finding first expression in \"%.*s\" took us outside of given subexpression length\n", length, strstart);
5454  return SCIP_READERROR;
5455  }
5456 
5457  /* ignore whitespace */
5458  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5459  ++str;
5460 
5461  /* maybe now we're done? */
5462  if( str >= lastchar + 1)
5463  {
5464  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5465  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5466  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5467 
5468  return SCIP_OKAY;
5469  }
5470 
5471  if( str[0] == '^' )
5472  {
5473  /* a '^' behind the found expression indicates a power */
5474  SCIP_Real constant;
5475 
5476  arg1 = *expr;
5477  ++str;
5478  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5479  ++str;
5480 
5481  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5482  {
5483  /* there is a number coming */
5484  if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5485  {
5486  SCIPerrorMessage("error parsing number from <%s>\n", str);
5487  return SCIP_READERROR;
5488  }
5489 
5490  SCIP_CALL( SCIPexprCreate(blkmem, &arg2, SCIP_EXPR_CONST, number) );
5491  str = nonconstendptr;
5492 
5493  constant = SCIPexprGetOpReal(arg2);
5494  SCIPexprFreeDeep(blkmem, &arg2);
5495 
5496  /* expr^number is intpower or realpower */
5497  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5498  {
5499  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5500  }
5501  else
5502  {
5503  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5504  }
5505  }
5506  else if( str[0] == '(' )
5507  {
5508  /* we use exprParse to evaluate the exponent */
5509 
5510  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5511  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5512  varnameslength, vartable, recursiondepth + 1) );
5513 
5514  if( SCIPexprGetOperator(arg2) != SCIP_EXPR_CONST )
5515  {
5516  /* reformulate arg1^arg2 as exp(arg2 * log(arg1)) */
5517  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5518  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, *expr, arg2) );
5519  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, *expr) );
5520  }
5521  else
5522  {
5523  /* expr^number is intpower or realpower */
5524  constant = SCIPexprGetOpReal(arg2);
5525  SCIPexprFreeDeep(blkmem, &arg2);
5526  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5527  {
5528  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5529  }
5530  else
5531  {
5532  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5533  }
5534  }
5535  str = endptr + 1;
5536  }
5537  else
5538  {
5539  SCIPerrorMessage("unexpected string following ^ in %.*s\n", length, str);
5540  return SCIP_READERROR;
5541  }
5542 
5543  /* ignore whitespace */
5544  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5545  ++str;
5546  }
5547 
5548  /* check for a two argument operator that is not a multiplication */
5549  if( str <= lastchar && (str[0] == '+' || str[0] == '-' || str[0] == '/') )
5550  {
5551  char op;
5552 
5553  op = str[0];
5554  arg1 = *expr;
5555 
5556  /* step forward over the operator to go to the beginning of the second argument */
5557  ++str;
5558 
5559  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5560  varnameslength, vartable, recursiondepth + 1) );
5561  str = lastchar + 1;
5562 
5563  /* make new expression from two arguments */
5564  if( op == '+')
5565  {
5566  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5567  }
5568  else if( op == '-')
5569  {
5570  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, -1.0, arg2, 0.0) );
5571  }
5572  else if( op == '*' )
5573  {
5574  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5575  {
5576  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5577  }
5578  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5579  {
5580  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5581  }
5582  else
5583  {
5584  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5585  }
5586  }
5587  else
5588  {
5589  assert(op == '/');
5590 
5591  if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5592  {
5593  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, 1.0 / SCIPexprGetOpReal(arg2)) );
5594  SCIPexprFreeShallow(blkmem, &arg2);
5595  }
5596  else
5597  {
5598  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_DIV, arg1, arg2) );
5599  }
5600  }
5601  }
5602 
5603  /* ignore whitespace */
5604  while( isspace((unsigned char)*str) )
5605  ++str;
5606 
5607  /* we are either done or we have a multiplication? */
5608  if( str >= lastchar + 1 )
5609  {
5610  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5611  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5612  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5613 
5614  return SCIP_OKAY;
5615  }
5616 
5617  /* if there is a part of the string left to be parsed, we assume that this as a multiplication */
5618  arg1 = *expr;
5619 
5620  /* stepping over multiplication operator if needed */
5621  if( str[0] == '*' )
5622  {
5623  ++str;
5624  }
5625  else if( str[0] != '(' )
5626  {
5627  SCIPdebugMessage("No operator found, assuming a multiplication before %.*s\n", (int) (lastchar - str + 1), str);
5628  }
5629 
5630  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5631  varnameslength, vartable, recursiondepth + 1) );
5632 
5633  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5634  {
5635  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5636  SCIPexprFreeDeep(blkmem, &arg1);
5637  }
5638  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5639  {
5640  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5641  SCIPexprFreeDeep(blkmem, &arg2);
5642  }
5643  else
5644  {
5645  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5646  }
5647 
5648  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5649  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5650  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5651 
5652  return SCIP_OKAY;
5653 }
5654 
5655 /**@} */
5656 
5657 /**@name Expression methods */
5658 /**@{ */
5659 
5660 /* In debug mode, the following methods are implemented as function calls to ensure
5661  * type validity.
5662  * In optimized mode, the methods are implemented as defines to improve performance.
5663  * However, we want to have them in the library anyways, so we have to undef the defines.
5664  */
5665 
5666 #undef SCIPexprGetOperator
5667 #undef SCIPexprGetNChildren
5668 #undef SCIPexprGetChildren
5669 #undef SCIPexprGetOpIndex
5670 #undef SCIPexprGetOpReal
5671 #undef SCIPexprGetOpData
5672 #undef SCIPexprGetRealPowerExponent
5673 #undef SCIPexprGetIntPowerExponent
5674 #undef SCIPexprGetSignPowerExponent
5675 #undef SCIPexprGetLinearCoefs
5676 #undef SCIPexprGetLinearConstant
5677 #undef SCIPexprGetQuadElements
5678 #undef SCIPexprGetQuadConstant
5679 #undef SCIPexprGetQuadLinearCoefs
5680 #undef SCIPexprGetNQuadElements
5681 #undef SCIPexprGetMonomials
5682 #undef SCIPexprGetNMonomials
5683 #undef SCIPexprGetPolynomialConstant
5684 #undef SCIPexprGetMonomialCoef
5685 #undef SCIPexprGetMonomialNFactors
5686 #undef SCIPexprGetMonomialChildIndices
5687 #undef SCIPexprGetMonomialExponents
5688 #undef SCIPexprGetUserData
5689 #undef SCIPexprHasUserEstimator
5690 #undef SCIPexprGetUserEvalCapability
5691 
5692 /** gives operator of expression */
5694  SCIP_EXPR* expr /**< expression */
5695  )
5696 {
5697  assert(expr != NULL);
5698 
5699  return expr->op;
5700 }
5701 
5702 /** gives number of children of an expression */
5704  SCIP_EXPR* expr /**< expression */
5705  )
5706 {
5707  assert(expr != NULL);
5708 
5709  return expr->nchildren;
5710 }
5711 
5712 /** gives pointer to array with children of an expression */
5714  SCIP_EXPR* expr /**< expression */
5715  )
5716 {
5717  assert(expr != NULL);
5718 
5719  return expr->children;
5720 }
5721 
5722 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
5724  SCIP_EXPR* expr /**< expression */
5725  )
5726 {
5727  assert(expr != NULL);
5728  assert(expr->op == SCIP_EXPR_VARIDX || expr->op == SCIP_EXPR_PARAM);
5729 
5730  return expr->data.intval;
5731 }
5732 
5733 /** gives real belonging to a SCIP_EXPR_CONST operand */
5735  SCIP_EXPR* expr /**< expression */
5736  )
5737 {
5738  assert(expr != NULL);
5739  assert(expr->op == SCIP_EXPR_CONST);
5740 
5741  return expr->data.dbl;
5742 }
5743 
5744 /** gives void* belonging to a complex operand */
5746  SCIP_EXPR* expr /**< expression */
5747  )
5748 {
5749  assert(expr != NULL);
5750  assert(expr->op >= SCIP_EXPR_SUM); /* only complex operands store their data as void* */
5751 
5752  return expr->data.data;
5753 }
5754 
5755 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
5757  SCIP_EXPR* expr /**< expression */
5758  )
5759 {
5760  assert(expr != NULL);
5761  assert(expr->op == SCIP_EXPR_REALPOWER);
5762 
5763  return expr->data.dbl;
5764 }
5765 
5766 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
5768  SCIP_EXPR* expr /**< expression */
5769  )
5770 {
5771  assert(expr != NULL);
5772  assert(expr->op == SCIP_EXPR_INTPOWER);
5773 
5774  return expr->data.intval;
5775 }
5776 
5777 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
5779  SCIP_EXPR* expr /**< expression */
5780  )
5781 {
5782  assert(expr != NULL);
5783  assert(expr->op == SCIP_EXPR_SIGNPOWER);
5784 
5785  return expr->data.dbl;
5786 }
5787 
5788 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
5790  SCIP_EXPR* expr /**< expression */
5791  )
5792 {
5793  assert(expr != NULL);
5794  assert(expr->op == SCIP_EXPR_LINEAR);
5795  assert(expr->data.data != NULL);
5796 
5797  /* the coefficients are stored in the first nchildren elements of the array stored as expression data */
5798  return (SCIP_Real*)expr->data.data;
5799 }
5800 
5801 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
5803  SCIP_EXPR* expr /**< expression */
5804  )
5805 {
5806  assert(expr != NULL);
5807  assert(expr->op == SCIP_EXPR_LINEAR);
5808  assert(expr->data.data != NULL);
5809 
5810  /* the constant is stored in the nchildren's element of the array stored as expression data */
5811  return ((SCIP_Real*)expr->data.data)[expr->nchildren];
5812 }
5813 
5814 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5816  SCIP_EXPR* expr /**< quadratic expression */
5817  )
5818 {
5819  assert(expr != NULL);
5820  assert(expr->op == SCIP_EXPR_QUADRATIC);
5821  assert(expr->data.data != NULL);
5822 
5823  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->quadelems;
5824 }
5825 
5826 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
5828  SCIP_EXPR* expr /**< quadratic expression */
5829  )
5830 {
5831  assert(expr != NULL);
5832  assert(expr->op == SCIP_EXPR_QUADRATIC);
5833  assert(expr->data.data != NULL);
5834 
5835  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->constant;
5836 }
5837 
5838 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression
5839  * can be NULL if all coefficients are 0.0 */
5841  SCIP_EXPR* expr /**< quadratic expression */
5842  )
5843 {
5844  assert(expr != NULL);
5845  assert(expr->op == SCIP_EXPR_QUADRATIC);
5846  assert(expr->data.data != NULL);
5847 
5848  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->lincoefs;
5849 }
5850 
5851 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5853  SCIP_EXPR* expr /**< quadratic expression */
5854  )
5855 {
5856  assert(expr != NULL);
5857  assert(expr->op == SCIP_EXPR_QUADRATIC);
5858  assert(expr->data.data != NULL);
5859 
5860  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->nquadelems;
5861 }
5862 
5863 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5865  SCIP_EXPR* expr /**< expression */
5866  )
5867 {
5868  assert(expr != NULL);
5869  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5870  assert(expr->data.data != NULL);
5871 
5872  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->monomials;
5873 }
5874 
5875 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5877  SCIP_EXPR* expr /**< expression */
5878  )
5879 {
5880  assert(expr != NULL);
5881  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5882  assert(expr->data.data != NULL);
5883 
5884  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->nmonomials;
5885 }
5886 
5887 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
5889  SCIP_EXPR* expr /**< expression */
5890  )
5891 {
5892  assert(expr != NULL);
5893  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5894  assert(expr->data.data != NULL);
5895 
5896  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant;
5897 }
5898 
5899 /** gets coefficient of a monomial */
5901  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5902  )
5903 {
5904  assert(monomial != NULL);
5905 
5906  return monomial->coef;
5907 }
5908 
5909 /** gets number of factors of a monomial */
5911  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5912  )
5913 {
5914  assert(monomial != NULL);
5915 
5916  return monomial->nfactors;
5917 }
5918 
5919 /** gets indices of children corresponding to factors of a monomial */
5921  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5922  )
5923 {
5924  assert(monomial != NULL);
5925 
5926  return monomial->childidxs;
5927 }
5928 
5929 /** gets exponents in factors of a monomial */
5931  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5932  )
5933 {
5934  assert(monomial != NULL);
5935 
5936  return monomial->exponents;
5937 }
5938 
5939 /** gets user data of a user expression */
5941  SCIP_EXPR* expr
5942  )
5943 {
5944  assert(expr != NULL);
5945  assert(expr->data.data != NULL);
5946 
5947  return ((SCIP_EXPRDATA_USER*)expr->data.data)->userdata;
5948 }
5949 
5950 /** indicates whether a user expression has the estimator callback defined */
5952  SCIP_EXPR* expr
5953  )
5954 {
5955  assert(expr != NULL);
5956  assert(expr->data.data != NULL);
5957 
5958  return ((SCIP_EXPRDATA_USER*)expr->data.data)->estimate != NULL;
5959 }
5960 
5961 /** gives the evaluation capability of a user expression */
5963  SCIP_EXPR* expr
5964  )
5965 {
5966  assert(expr != NULL);
5967  assert(expr->data.data != NULL);
5968 
5969  return ((SCIP_EXPRDATA_USER*)expr->data.data)->evalcapability;
5970 }
5971 
5972 /** creates a simple expression */
5974  BMS_BLKMEM* blkmem, /**< block memory data structure */
5975  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
5976  SCIP_EXPROP op, /**< operand of expression */
5977  ... /**< arguments of operand */
5978  )
5979 {
5980  va_list ap;
5981  SCIP_EXPR** children;
5982  SCIP_EXPROPDATA opdata;
5983 
5984  assert(blkmem != NULL);
5985  assert(expr != NULL);
5986 
5987  switch( op )
5988  {
5989  case SCIP_EXPR_VARIDX:
5990  case SCIP_EXPR_PARAM:
5991  {
5992  va_start( ap, op ); /*lint !e838*/
5993  opdata.intval = va_arg( ap, int ); /*lint !e416 !e826*/
5994  va_end( ap ); /*lint !e826*/
5995 
5996  assert( opdata.intval >= 0 );
5997 
5998  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5999  break;
6000  }
6001 
6002  case SCIP_EXPR_CONST:
6003  {
6004  va_start(ap, op ); /*lint !e838*/
6005  opdata.dbl = va_arg( ap, SCIP_Real ); /*lint !e416 !e826*/
6006  va_end( ap ); /*lint !e826*/
6007 
6008  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
6009  break;
6010  }
6011 
6012  /* operands with two children */
6013  case SCIP_EXPR_PLUS :
6014  case SCIP_EXPR_MINUS :
6015  case SCIP_EXPR_MUL :
6016  case SCIP_EXPR_DIV :
6017  case SCIP_EXPR_MIN :
6018  case SCIP_EXPR_MAX :
6019  {
6020  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 2) ); /*lint !e506*/
6021 
6022  va_start(ap, op ); /*lint !e838*/
6023  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6024  children[1] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6025  assert(children[0] != NULL);
6026  assert(children[1] != NULL);
6027  va_end( ap ); /*lint !e826*/
6028  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6029 
6030  SCIP_CALL( exprCreate( blkmem, expr, op, 2, children, opdata ) );
6031  break;
6032  }
6033 
6034  /* operands with one child */
6035  case SCIP_EXPR_SQUARE:
6036  case SCIP_EXPR_SQRT :
6037  case SCIP_EXPR_EXP :
6038  case SCIP_EXPR_LOG :
6039  case SCIP_EXPR_SIN :
6040  case SCIP_EXPR_COS :
6041  case SCIP_EXPR_TAN :
6042  /* case SCIP_EXPR_ERF : */
6043  /* case SCIP_EXPR_ERFI : */
6044  case SCIP_EXPR_ABS :
6045  case SCIP_EXPR_SIGN :
6046  {
6047  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6048 
6049  va_start(ap, op ); /*lint !e838*/
6050  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6051  assert(children[0] != NULL);
6052  va_end( ap ); /*lint !e826*/
6053  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6054 
6055  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6056  break;
6057  }
6058 
6059  case SCIP_EXPR_REALPOWER:
6060  case SCIP_EXPR_SIGNPOWER:
6061  {
6062  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6063 
6064  va_start(ap, op ); /*lint !e838*/
6065  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6066  assert(children[0] != NULL);
6067  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
6068  va_end( ap ); /*lint !e826*/
6069 
6070  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6071  break;
6072  }
6073 
6074  case SCIP_EXPR_INTPOWER:
6075  {
6076  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6077 
6078  va_start(ap, op ); /*lint !e838*/
6079  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6080  assert(children[0] != NULL);
6081  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
6082  va_end( ap ); /*lint !e826*/
6083 
6084  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6085  break;
6086  }
6087 
6088  /* complex operands */
6089  case SCIP_EXPR_SUM :
6090  case SCIP_EXPR_PRODUCT:
6091  {
6092  int nchildren;
6093  SCIP_EXPR** childrenarg;
6094 
6095  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6096 
6097  va_start(ap, op ); /*lint !e838*/
6098  /* first argument should be number of children */
6099  nchildren = va_arg( ap, int ); /*lint !e416 !e826*/
6100  assert(nchildren >= 0);
6101 
6102  /* for a sum or product of 0 terms we can finish here */
6103  if( nchildren == 0 )
6104  {
6105  SCIP_RETCODE retcode;
6106  retcode = exprCreate( blkmem, expr, op, 0, NULL, opdata);
6107  va_end( ap ); /*lint !e826*/
6108  SCIP_CALL( retcode );
6109  break;
6110  }
6111 
6112  /* next argument should be array of children expressions */
6113  childrenarg = va_arg( ap, SCIP_EXPR** ); /*lint !e416 !e826*/
6114  assert(childrenarg != NULL);
6115  va_end( ap ); /*lint !e826*/
6116 
6117  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &children, childrenarg, nchildren) );
6118 
6119  SCIP_CALL( exprCreate( blkmem, expr, op, nchildren, children, opdata) );
6120  break;
6121  }
6122 
6123  case SCIP_EXPR_LINEAR :
6124  case SCIP_EXPR_QUADRATIC:
6125  case SCIP_EXPR_POLYNOMIAL:
6126  case SCIP_EXPR_USER:
6127  {
6128  SCIPerrorMessage("cannot create complex expression linear, quadratic, polynomial, or user with SCIPexprCreate\n");
6129  return SCIP_INVALIDDATA;
6130  }
6131 
6132  case SCIP_EXPR_LAST:
6133  SCIPABORT();
6134  break;
6135  }
6136 
6137  return SCIP_OKAY;
6138 }
6139 
6140 /** copies an expression including its children */
6142  BMS_BLKMEM* blkmem, /**< block memory data structure */
6143  SCIP_EXPR** targetexpr, /**< buffer to store pointer to copied expression */
6144  SCIP_EXPR* sourceexpr /**< expression to copy */
6145  )
6146 {
6147  assert(blkmem != NULL);
6148  assert(targetexpr != NULL);
6149  assert(sourceexpr != NULL);
6150 
6151  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targetexpr, sourceexpr) );
6152 
6153  if( sourceexpr->nchildren )
6154  {
6155  int i;
6156 
6157  /* alloc memory for children expressions */
6158  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetexpr)->children, sourceexpr->nchildren) );
6159 
6160  /* copy children expressions */
6161  for( i = 0; i < sourceexpr->nchildren; ++i )
6162  {
6163  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targetexpr)->children[i], sourceexpr->children[i]) );
6164  }
6165  }
6166  else
6167  {
6168  assert((*targetexpr)->children == NULL); /* otherwise, sourceexpr->children was not NULL, which is wrong */
6169  }
6170 
6171  /* call operands data copy callback for complex operands
6172  * for simple operands BMSduplicate above should have done the job
6173  */
6174  if( exprOpTable[sourceexpr->op].copydata != NULL )
6175  {
6176  SCIP_CALL( exprOpTable[sourceexpr->op].copydata(blkmem, sourceexpr->nchildren, sourceexpr->data, &(*targetexpr)->data) );
6177  }
6178 
6179  return SCIP_OKAY;
6180 }
6181 
6182 /** frees an expression including its children */
6184  BMS_BLKMEM* blkmem, /**< block memory data structure */
6185  SCIP_EXPR** expr /**< pointer to expression to free */
6186  )
6187 {
6188  assert(blkmem != NULL);
6189  assert(expr != NULL);
6190  assert(*expr != NULL);
6191 
6192  /* call operands data free callback, if given */
6193  if( exprOpTable[(*expr)->op].freedata != NULL )
6194  {
6195  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6196  }
6197 
6198  if( (*expr)->nchildren )
6199  {
6200  int i;
6201 
6202  assert( (*expr)->children != NULL );
6203 
6204  for( i = 0; i < (*expr)->nchildren; ++i )
6205  {
6206  SCIPexprFreeDeep(blkmem, &(*expr)->children[i]);
6207  assert((*expr)->children[i] == NULL);
6208  }
6209 
6210  BMSfreeBlockMemoryArray(blkmem, &(*expr)->children, (*expr)->nchildren);
6211  }
6212  else
6213  {
6214  assert( (*expr)->children == NULL );
6215  }
6216 
6217  BMSfreeBlockMemory(blkmem, expr);
6218 }
6219 
6220 /** frees an expression but not its children */
6222  BMS_BLKMEM* blkmem, /**< block memory data structure */
6223  SCIP_EXPR** expr /**< pointer to expression to free */
6224  )
6225 {
6226  assert(blkmem != NULL);
6227  assert(expr != NULL);
6228  assert(*expr != NULL);
6229 
6230  /* call operands data free callback, if given */
6231  if( exprOpTable[(*expr)->op].freedata != NULL )
6232  {
6233  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6234  }
6235 
6236  BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->nchildren);
6237 
6238  BMSfreeBlockMemory(blkmem, expr);
6239 }
6240 
6241 /** creates an expression from the addition of two given expression, with coefficients, and a constant
6242  *
6243  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6244  * Favors creation and maintaining of SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6245  */
6247  BMS_BLKMEM* blkmem, /**< block memory data structure */
6248  SCIP_EXPR** expr, /**< pointer to store pointer to created expression */
6249  SCIP_Real coef1, /**< coefficient of first term */
6250  SCIP_EXPR* term1, /**< expression of first term, or NULL */
6251  SCIP_Real coef2, /**< coefficient of second term */
6252  SCIP_EXPR* term2, /**< expression of second term, or NULL */
6253  SCIP_Real constant /**< constant term to add */
6254  )
6255 {
6256  assert(blkmem != NULL);
6257  assert(expr != NULL);
6258 
6259  /* @todo could do something special with quadratic and polynomial expressions */
6260 
6261  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_CONST )
6262  {
6263  constant += coef1 * SCIPexprGetOpReal(term1);
6264  SCIPexprFreeDeep(blkmem, &term1);
6265  }
6266 
6267  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_CONST )
6268  {
6269  constant += coef2 * SCIPexprGetOpReal(term2);
6270  SCIPexprFreeDeep(blkmem, &term2);
6271  }
6272 
6273  if( term1 == NULL && term2 == NULL )
6274  {
6275  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, constant) );
6276  return SCIP_OKAY;
6277  }
6278 
6279  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && coef1 != 1.0 )
6280  {
6281  /* multiply coefficients and constant of linear expression term1 by coef1 */
6282  SCIP_Real* data;
6283  int i;
6284 
6285  data = (SCIP_Real*)term1->data.data;
6286  assert(data != NULL);
6287 
6288  /* loop one more index to multiply also constant of linear expression */
6289  for( i = 0; i <= term1->nchildren; ++i )
6290  data[i] *= coef1;
6291 
6292  coef1 = 1.0;
6293  }
6294 
6295  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR && coef2 != 1.0 )
6296  {
6297  /* multiply coefficients and constant of linear expression term2 by coef2 */
6298  SCIP_Real* data;
6299  int i;
6300 
6301  data = (SCIP_Real*)term2->data.data;
6302  assert(data != NULL);
6303 
6304  /* loop one more index to multiply also constant of linear expression */
6305  for( i = 0; i <= term2->nchildren; ++i )
6306  data[i] *= coef2;
6307 
6308  coef2 = 1.0;
6309  }
6310 
6311  if( term1 == NULL || term2 == NULL )
6312  {
6313  if( term1 == NULL )
6314  {
6315  term1 = term2;
6316  coef1 = coef2;
6317  }
6318  if( constant != 0.0 || coef1 != 1.0 )
6319  {
6320  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6321  {
6322  assert(coef1 == 1.0);
6323 
6324  /* add constant to existing linear expression */
6325  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 0, NULL, NULL, constant) );
6326  *expr = term1;
6327  }
6328  else
6329  {
6330  /* create new linear expression for coef1 * term1 + constant */
6331  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term1, &coef1, constant) );
6332  }
6333  }
6334  else
6335  {
6336  assert(constant == 0.0);
6337  assert(coef1 == 1.0);
6338  *expr = term1;
6339  }
6340 
6341  return SCIP_OKAY;
6342  }
6343 
6345  {
6346  /* add 2nd linear expression to first one */
6347  assert(coef1 == 1.0);
6348  assert(coef2 == 1.0);
6349 
6351  SCIPexprFreeShallow(blkmem, &term2);
6352 
6353  *expr = term1;
6354 
6355  return SCIP_OKAY;
6356  }
6357 
6358  if( SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
6359  {
6360  /* if only term2 is linear, then swap */
6361  SCIP_EXPR* tmp;
6362 
6363  tmp = term2;
6364  assert(coef2 == 1.0);
6365 
6366  term2 = term1;
6367  coef2 = coef1;
6368  term1 = tmp;
6369  coef1 = 1.0;
6370  }
6371 
6372  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6373  {
6374  /* add coef2*term2 as extra child to linear expression term1 */
6375  assert(coef1 == 1.0);
6376 
6377  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 1, &coef2, &term2, constant) );
6378  *expr = term1;
6379 
6380  return SCIP_OKAY;
6381  }
6382 
6383  /* both terms are not linear, then create new linear term for sum */
6384  {
6385  SCIP_Real coefs[2];
6386  SCIP_EXPR* children[2];
6387 
6388  coefs[0] = coef1;
6389  coefs[1] = coef2;
6390  children[0] = term1;
6391  children[1] = term2;
6392 
6393  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 2, children, coefs, constant) );
6394  }
6395 
6396  return SCIP_OKAY;
6397 }
6398 
6399 /** creates an expression from the multiplication of an expression with a constant
6400  *
6401  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6402  * Favors creation and maintaining SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6403  */
6405  BMS_BLKMEM* blkmem, /**< block memory data structure */
6406  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
6407  SCIP_EXPR* term, /**< term to multiply by factor */
6408  SCIP_Real factor /**< factor */
6409  )
6410 {
6411  assert(blkmem != NULL);
6412  assert(expr != NULL);
6413  assert(term != NULL);
6414 
6415  if( factor == 0.0 )
6416  {
6417  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, 0.0) );
6418 
6419  SCIPexprFreeDeep(blkmem, &term);
6420 
6421  return SCIP_OKAY;
6422  }
6423  if( factor == 1.0 )
6424  {
6425  *expr = term;
6426  return SCIP_OKAY;
6427  }
6428 
6429  switch( SCIPexprGetOperator(term) )
6430  {
6431  case SCIP_EXPR_CONST :
6432  {
6433  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, factor * SCIPexprGetOpReal(term)) );
6434  SCIPexprFreeDeep(blkmem, &term);
6435  break;
6436  }
6437 
6438  case SCIP_EXPR_LINEAR :
6439  {
6440  SCIP_Real* data;
6441  int i;
6442 
6443  data = (SCIP_Real*)term->data.data;
6444  assert(data != NULL);
6445 
6446  /* loop one more index to multiply also constant of linear expression */
6447  for( i = 0; i <= SCIPexprGetNChildren(term); ++i )
6448  data[i] *= factor;
6449 
6450  *expr = term;
6451  break;
6452  }
6453 
6454  case SCIP_EXPR_QUADRATIC :
6455  {
6457  int i;
6458 
6459  data = (SCIP_EXPRDATA_QUADRATIC*)term->data.data;
6460 
6461  data->constant *= factor;
6462 
6463  if( data->lincoefs != NULL )
6464  for( i = 0; i < term->nchildren; ++i )
6465  data->lincoefs[i] *= factor;
6466 
6467  for( i = 0; i < data->nquadelems; ++i )
6468  data->quadelems[i].coef *= factor;
6469 
6470  *expr = term;
6471  break;
6472  }
6473 
6474  case SCIP_EXPR_POLYNOMIAL :
6475  {
6477  int i;
6478 
6479  data = (SCIP_EXPRDATA_POLYNOMIAL*)term->data.data;
6480 
6481  data->constant *= factor;
6482 
6483  for( i = 0; i < data->nmonomials; ++i )
6484  data->monomials[i]->coef *= factor;
6485 
6486  *expr = term;
6487  break;
6488  }
6489 
6490  default:
6491  {
6492  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term, &factor, 0.0) );
6493  break;
6494  }
6495 
6496  } /*lint !e788 */
6497 
6498  return SCIP_OKAY;
6499 }
6500 
6501 /** creates a SCIP_EXPR_LINEAR expression that is (affine) linear in its children: constant + sum_i coef_i child_i */
6503  BMS_BLKMEM* blkmem, /**< block memory data structure */
6504  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6505  int nchildren, /**< number of children */
6506  SCIP_EXPR** children, /**< children of expression */
6507  SCIP_Real* coefs, /**< coefficients of children */
6508  SCIP_Real constant /**< constant part */
6509  )
6510 {
6511  SCIP_EXPROPDATA opdata;
6512  SCIP_EXPR** childrencopy;
6513  SCIP_Real* data;
6514 
6515  assert(nchildren >= 0);
6516  assert(children != NULL || nchildren == 0);
6517  assert(coefs != NULL || nchildren == 0);
6518 
6519  if( nchildren > 0 )
6520  {
6521  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6522  }
6523  else
6524  childrencopy = NULL;
6525 
6526  /* we store the coefficients and the constant in a single array and make this our operand data */
6527  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, nchildren + 1) );
6528  BMScopyMemoryArray(data, coefs, nchildren); /*lint !e644*/
6529  data[nchildren] = constant;
6530 
6531  opdata.data = (void*)data;
6532 
6533  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_LINEAR, nchildren, childrencopy, opdata) );
6534 
6535  return SCIP_OKAY;
6536 }
6537 
6538 /** adds new terms to a linear expression */
6540  BMS_BLKMEM* blkmem, /**< block memory */
6541  SCIP_EXPR* expr, /**< linear expression */
6542  int nchildren, /**< number of children to add */
6543  SCIP_Real* coefs, /**< coefficients of additional children */
6544  SCIP_EXPR** children, /**< additional children expressions */
6545  SCIP_Real constant /**< constant to add */
6546  )
6547 {
6548  SCIP_Real* data;
6549 
6550  assert(blkmem != NULL);
6551  assert(expr != NULL);
6552  assert(expr->op == SCIP_EXPR_LINEAR);
6553  assert(nchildren >= 0);
6554  assert(coefs != NULL || nchildren == 0);
6555  assert(children != NULL || nchildren == 0);
6556 
6557  data = (SCIP_Real*)expr->data.data;
6558  assert(data != NULL);
6559 
6560  /* handle simple case of adding a constant */
6561  if( nchildren == 0 )
6562  {
6563  data[expr->nchildren] += constant;
6564 
6565  return SCIP_OKAY;
6566  }
6567 
6568  /* add new children to expr's children array */
6569  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nchildren) );
6570  BMScopyMemoryArray(&expr->children[expr->nchildren], children, nchildren); /*lint !e866*/
6571 
6572  /* add constant and new coefs to expr's data array */
6573  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, expr->nchildren + 1, expr->nchildren + nchildren + 1) );
6574  data[expr->nchildren + nchildren] = data[expr->nchildren] + constant;
6575  BMScopyMemoryArray(&data[expr->nchildren], coefs, nchildren); /*lint !e866*/
6576  expr->data.data = (void*)data;
6577 
6578  expr->nchildren += nchildren;
6579 
6580  return SCIP_OKAY;
6581 }
6582 
6583 /** creates a SCIP_EXPR_QUADRATIC expression: constant + sum_i coef_i child_i + sum_i coef_i child1_i child2_i */
6585  BMS_BLKMEM* blkmem, /**< block memory data structure */
6586  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6587  int nchildren, /**< number of children */
6588  SCIP_EXPR** children, /**< children of expression */
6589  SCIP_Real constant, /**< constant */
6590  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
6591  int nquadelems, /**< number of quadratic elements */
6592  SCIP_QUADELEM* quadelems /**< quadratic elements specifying coefficients and child indices */
6593  )
6594 {
6595  SCIP_EXPROPDATA opdata;
6596  SCIP_EXPR** childrencopy;
6598 
6599  assert(nchildren >= 0);
6600  assert(children != NULL || nchildren == 0);
6601  assert(quadelems != NULL || nquadelems == 0);
6602 
6603  if( nchildren > 0 )
6604  {
6605  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6606  }
6607  else
6608  childrencopy = NULL;
6609 
6610  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
6611 
6612  opdata.data = (void*)data;
6613 
6614  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_QUADRATIC, nchildren, childrencopy, opdata) );
6615 
6616  return SCIP_OKAY;
6617 }
6618 
6619 /** ensures that quadratic elements of a quadratic expression are sorted */
6621  SCIP_EXPR* expr /**< quadratic expression */
6622  )
6623 {
6624  assert(expr != NULL);
6625  assert(expr->op == SCIP_EXPR_QUADRATIC);
6626  assert(expr->data.data != NULL);
6627 
6629 }
6630 
6631 /** creates a SCIP_EXPR_POLYNOMIAL expression from an array of monomials: constant + sum_i monomial_i */
6633  BMS_BLKMEM* blkmem, /**< block memory data structure */
6634  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6635  int nchildren, /**< number of children */
6636  SCIP_EXPR** children, /**< children of expression */
6637  int nmonomials, /**< number of monomials */
6638  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
6639  SCIP_Real constant, /**< constant part */
6640  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6641  )
6642 {
6643  SCIP_EXPROPDATA opdata;
6644  SCIP_EXPR** childrencopy;
6646 
6647  assert(nchildren >= 0);
6648  assert(children != NULL || nchildren == 0);
6649  assert(monomials != NULL || nmonomials == 0);
6650 
6651  if( nchildren > 0 )
6652  {
6653  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6654  }
6655  else
6656  childrencopy = NULL;
6657 
6658  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
6659  opdata.data = (void*)data;
6660 
6661  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_POLYNOMIAL, nchildren, childrencopy, opdata) );
6662 
6663  return SCIP_OKAY;
6664 }
6665 
6666 /** adds an array of monomials to a SCIP_EXPR_POLYNOMIAL expression */
6668  BMS_BLKMEM* blkmem, /**< block memory of expression */
6669  SCIP_EXPR* expr, /**< expression */
6670  int nmonomials, /**< number of monomials to add */
6671  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
6672  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6673  )
6674 {
6675  assert(blkmem != NULL);
6676  assert(expr != NULL);
6677  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6678  assert(monomials != NULL || nmonomials == 0);
6679 
6680  if( nmonomials == 0 )
6681  return SCIP_OKAY;
6682 
6683  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, nmonomials, monomials, copymonomials) );
6684 
6685  return SCIP_OKAY;
6686 }
6687 
6688 /** changes the constant in a SCIP_EXPR_POLYNOMIAL expression */
6690  SCIP_EXPR* expr, /**< expression */
6691  SCIP_Real constant /**< new value for constant */
6692  )
6693 {
6694  assert(expr != NULL);
6695  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6696  assert(expr->data.data != NULL);
6697 
6698  ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant = constant;
6699 }
6700 
6701 /** multiplies each summand of a polynomial by a given constant */
6703  BMS_BLKMEM* blkmem, /**< block memory */
6704  SCIP_EXPR* expr, /**< polynomial expression */
6705  SCIP_Real factor /**< constant factor */
6706  )
6707 {
6708  assert(expr != NULL);
6709  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6710  assert(expr->data.data != NULL);
6711 
6712  polynomialdataMultiplyByConstant(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor);
6713 }
6714 
6715 /** multiplies each summand of a polynomial by a given monomial */
6717  BMS_BLKMEM* blkmem, /**< block memory */
6718  SCIP_EXPR* expr, /**< polynomial expression */
6719  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
6720  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6721  )
6722 {
6723  assert(blkmem != NULL);
6724  assert(factor != NULL);
6725  assert(expr != NULL);
6726  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6727  assert(expr->data.data != NULL);
6728 
6729  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor, childmap) );
6730 
6731  return SCIP_OKAY;
6732 }
6733 
6734 /** multiplies this polynomial by a polynomial
6735  *
6736  * Factor needs to be different from expr.
6737  * Children of factor need to be children of expr already, w.r.t. an optional mapping of child indices.
6738  */
6740  BMS_BLKMEM* blkmem, /**< block memory */
6741  SCIP_EXPR* expr, /**< polynomial expression */
6742  SCIP_EXPR* factor, /**< polynomial factor */
6743  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6744  )
6745 {
6746  assert(blkmem != NULL);
6747  assert(expr != NULL);
6748  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6749  assert(expr->data.data != NULL);
6750  assert(factor != NULL);
6751  assert(factor->op == SCIP_EXPR_POLYNOMIAL);
6752  assert(factor->data.data != NULL);
6753  assert(expr != factor);
6754 
6755 #ifndef NDEBUG
6756  if( childmap == NULL )
6757  {
6758  int i;
6759  assert(factor->nchildren == expr->nchildren);
6760  for( i = 0; i < factor->nchildren; ++i )
6761  assert(SCIPexprAreEqual(expr->children[i], factor->children[i], 0.0));
6762  }
6763  else
6764  {
6765  int i;
6766  for( i = 0; i < factor->nchildren; ++i )
6767  {
6768  assert(childmap[i] >= 0);
6769  assert(childmap[i] < expr->nchildren);
6770  assert(SCIPexprAreEqual(expr->children[childmap[i]], factor->children[i], 0.0));
6771  }
6772  }
6773 #endif
6774 
6776 
6777  return SCIP_OKAY;
6778 }
6779 
6780 /** takes a power of the polynomial
6781  *
6782  * Exponent need to be an integer.
6783  * Polynomial needs to be a monomial, if exponent is negative.
6784  */
6786  BMS_BLKMEM* blkmem, /**< block memory */
6787  SCIP_EXPR* expr, /**< polynomial expression */
6788  int exponent /**< exponent of power operation */
6789  )
6790 {
6791  assert(blkmem != NULL);
6792  assert(expr != NULL);
6793  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6794  assert(expr->data.data != NULL);
6795 
6796  SCIP_CALL( polynomialdataPower(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, exponent) );
6797 
6798  return SCIP_OKAY;
6799 }
6800 
6801 /** merges monomials in a polynomial expression that differ only in coefficient into a single monomial
6802  *
6803  * Eliminates monomials with coefficient between -eps and eps.
6804  */
6806  BMS_BLKMEM* blkmem, /**< block memory */
6807  SCIP_EXPR* expr, /**< polynomial expression */
6808  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
6809  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
6810  )
6811 {
6812  assert(expr != NULL);
6813  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6814  assert(expr->data.data != NULL);
6815 
6816  polynomialdataMergeMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, eps, mergefactors);
6817 }
6818 
6819 /** checks if two monomials are equal */
6821  SCIP_EXPRDATA_MONOMIAL* monomial1, /**< first monomial */
6822  SCIP_EXPRDATA_MONOMIAL* monomial2, /**< second monomial */
6823  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6824  )
6825 {
6826  int i;
6827 
6828  assert(monomial1 != NULL);
6829  assert(monomial2 != NULL);
6830 
6831  if( monomial1->nfactors != monomial2->nfactors )
6832  return FALSE;
6833 
6834  if( !EPSEQ(monomial1->coef, monomial2->coef, eps) )
6835  return FALSE;
6836 
6837  SCIPexprSortMonomialFactors(monomial1);
6838  SCIPexprSortMonomialFactors(monomial2);
6839 
6840  for( i = 0; i < monomial1->nfactors; ++i )
6841  {
6842  if( monomial1->childidxs[i] != monomial2->childidxs[i] ||
6843  !EPSEQ(monomial1->exponents[i], monomial2->exponents[i], eps) )
6844  return FALSE;
6845  }
6846 
6847  return TRUE;
6848 }
6849 
6850 /** changes coefficient of monomial */
6852  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6853  SCIP_Real newcoef /**< new coefficient */
6854  )
6855 {
6856  assert(monomial != NULL);
6857 
6858  monomial->coef = newcoef;
6859 }
6860 
6861 /** adds factors to a monomial */
6863  BMS_BLKMEM* blkmem, /**< block memory */
6864  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6865  int nfactors, /**< number of factors to add */
6866  int* childidxs, /**< indices of children corresponding to factors */
6867  SCIP_Real* exponents /**< exponent in each factor */
6868  )
6869 {
6870  assert(monomial != NULL);
6871  assert(nfactors >= 0);
6872  assert(childidxs != NULL || nfactors == 0);
6873  assert(exponents != NULL || nfactors == 0);
6874 
6875  if( nfactors == 0 )
6876  return SCIP_OKAY;
6877 
6878  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + nfactors) );
6879  assert(monomial->nfactors + nfactors <= monomial->factorssize);
6880 
6881  BMScopyMemoryArray(&monomial->childidxs[monomial->nfactors], childidxs, nfactors); /*lint !e866*/
6882  BMScopyMemoryArray(&monomial->exponents[monomial->nfactors], exponents, nfactors); /*lint !e866*/
6883 
6884  monomial->nfactors += nfactors;
6885  monomial->sorted = (monomial->nfactors <= 1);
6886 
6887  return SCIP_OKAY;
6888 }
6889 
6890 /** multiplies a monomial with a monomial */
6892  BMS_BLKMEM* blkmem, /**< block memory */
6893  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6894  SCIP_EXPRDATA_MONOMIAL* factor, /**< factor monomial */
6895  int* childmap /**< map to apply to children in factor, or NULL for 1:1 */
6896  )
6897 {
6898  assert(monomial != NULL);
6899  assert(factor != NULL);
6900 
6901  if( factor->coef == 0.0 )
6902  {
6903  monomial->nfactors = 0;
6904  monomial->coef = 0.0;
6905  return SCIP_OKAY;
6906  }
6907 
6908  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, factor->nfactors, factor->childidxs, factor->exponents) );
6909 
6910  if( childmap != NULL )
6911  {
6912  int i;
6913  for( i = monomial->nfactors - factor->nfactors; i < monomial->nfactors; ++i )
6914  monomial->childidxs[i] = childmap[monomial->childidxs[i]];
6915  }
6916 
6917  monomial->coef *= factor->coef;
6918 
6919  return SCIP_OKAY;
6920 }
6921 
6922 /** replaces the monomial by a power of the monomial
6923  *
6924  * Allows only integers as exponent.
6925  */
6927  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6928  int exponent /**< integer exponent of power operation */
6929  )
6930 {
6931  int i;
6932 
6933  assert(monomial != NULL);
6934 
6935  if( exponent == 1 )
6936  return;
6937 
6938  if( exponent == 0 )
6939  {
6940  /* x^0 = 1, unless x = 0; 0^0 = 0 */
6941  if( monomial->coef != 0.0 )
6942  monomial->coef = 1.0;
6943  monomial->nfactors = 0;
6944  return;
6945  }
6946 
6947  monomial->coef = pow(monomial->coef, (SCIP_Real)exponent);
6948  for( i = 0; i < monomial->nfactors; ++i )
6949  monomial->exponents[i] *= exponent;
6950 }
6951 
6952 /** merges factors that correspond to the same child by adding exponents
6953  *
6954  * Eliminates factors with exponent between -eps and eps.
6955  */
6957  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6958  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6959  )
6960 {
6961  int i;
6962  int offset;
6963 
6964  assert(monomial != NULL);
6965  assert(eps >= 0.0);
6966 
6967  SCIPexprSortMonomialFactors(monomial);
6968 
6969  /* merge factors with same child index by adding up their exponents
6970  * delete factors with exponent 0.0 */
6971  offset = 0;
6972  i = 0;
6973  while( i + offset < monomial->nfactors )
6974  {
6975  if( offset > 0 )
6976  {
6977  assert(monomial->childidxs[i] == -1);
6978  assert(monomial->childidxs[i+offset] >= 0);
6979  monomial->childidxs[i] = monomial->childidxs[i+offset];
6980  monomial->exponents[i] = monomial->exponents[i+offset];
6981 #ifndef NDEBUG
6982  monomial->childidxs[i+offset] = -1;
6983 #endif
6984  }
6985 
6986  while( i+offset+1 < monomial->nfactors && monomial->childidxs[i] == monomial->childidxs[i+offset+1] )
6987  {
6988  monomial->exponents[i] += monomial->exponents[i+offset+1];
6989 #ifndef NDEBUG
6990  monomial->childidxs[i+offset+1] = -1;
6991 #endif
6992  ++offset;
6993  }
6994 
6995  if( EPSZ(monomial->exponents[i], eps) )
6996  {
6997 #ifndef NDEBUG
6998  monomial->childidxs[i] = -1;
6999 #endif
7000  ++offset;
7001  continue;
7002  }
7003  else if( EPSISINT(monomial->exponents[i], eps) )
7004  monomial->exponents[i] = EPSROUND(monomial->exponents[i], eps);
7005 
7006  ++i;
7007  }
7008 
7009 #ifndef NDEBUG
7010  for( ; i < monomial->nfactors; ++i )
7011  assert(monomial->childidxs[i] == -1);
7012 #endif
7013 
7014  monomial->nfactors -= offset;
7015 
7016  if( EPSEQ(monomial->coef, 1.0, eps) )
7017  monomial->coef = 1.0;
7018  else if( EPSEQ(monomial->coef, -1.0, eps) )
7019  monomial->coef = -1.0;
7020 }
7021 
7022 /** ensures that monomials of a polynomial are sorted */
7024  SCIP_EXPR* expr /**< polynomial expression */
7025  )
7026 {
7027  assert(expr != NULL);
7028  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
7029  assert(expr->data.data != NULL);
7030 
7032 }
7033 
7034 /** creates a monomial */
7036  BMS_BLKMEM* blkmem, /**< block memory */
7037  SCIP_EXPRDATA_MONOMIAL** monomial, /**< buffer where to store pointer to new monomial */
7038  SCIP_Real coef, /**< coefficient of monomial */
7039  int nfactors, /**< number of factors in monomial */
7040  int* childidxs, /**< indices of children corresponding to factors, or NULL if identity */
7041  SCIP_Real* exponents /**< exponent in each factor, or NULL if all 1.0 */
7042  )
7043 {
7044  assert(blkmem != NULL);
7045  assert(monomial != NULL);
7046 
7047  SCIP_ALLOC( BMSallocBlockMemory(blkmem, monomial) );
7048 
7049  (*monomial)->coef = coef;
7050  (*monomial)->nfactors = nfactors;
7051  (*monomial)->factorssize = nfactors;
7052  (*monomial)->sorted = (nfactors <= 1);
7053 
7054  if( nfactors > 0 )
7055  {
7056  if( childidxs != NULL )
7057  {
7058  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->childidxs, childidxs, nfactors) );
7059  }
7060  else
7061  {
7062  int i;
7063 
7064  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->childidxs, nfactors) );
7065  for( i = 0; i < nfactors; ++i )
7066  (*monomial)->childidxs[i] = i;
7067  }
7068 
7069  if( exponents != NULL )
7070  {
7071  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->exponents, exponents, nfactors) );
7072  }
7073  else
7074  {
7075  int i;
7076 
7077  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->exponents, nfactors) );
7078  for( i = 0; i < nfactors; ++i )
7079  (*monomial)->exponents[i] = 1.0;
7080  }
7081  }
7082  else
7083  {
7084  (*monomial)->childidxs = NULL;
7085  (*monomial)->exponents = NULL;
7086  }
7087 
7088  return SCIP_OKAY;
7089 }
7090 
7091 /** frees a monomial */
7093  BMS_BLKMEM* blkmem, /**< block memory */
7094  SCIP_EXPRDATA_MONOMIAL** monomial /**< pointer to monomial that should be freed */
7095  )
7096 {
7097  assert(blkmem != NULL);
7098  assert( monomial != NULL);
7099  assert(*monomial != NULL);
7100 
7101  if( (*monomial)->factorssize > 0 )
7102  {
7103  assert((*monomial)->childidxs != NULL);
7104  assert((*monomial)->exponents != NULL);
7105 
7106  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->childidxs, (*monomial)->factorssize);
7107  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->exponents, (*monomial)->factorssize);
7108  }
7109  assert((*monomial)->childidxs == NULL);
7110  assert((*monomial)->exponents == NULL);
7111 
7112  BMSfreeBlockMemory(blkmem, monomial);
7113 }
7114 
7115 /** ensures that factors in a monomial are sorted */
7117  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
7118  )
7119 {
7120  assert(monomial != NULL);
7121 
7122  if( monomial->sorted )
7123  return;
7124 
7125  if( monomial->nfactors > 0 )
7126  SCIPsortIntReal(monomial->childidxs, monomial->exponents, monomial->nfactors);
7127 
7128  monomial->sorted = TRUE;
7129 }
7130 
7131 /** finds a factor corresponding to a given child index in a monomial
7132  *
7133  * Note that if the factors have not been merged, the position of some factor corresponding to a given child is given.
7134  * Returns TRUE if a factor is found, FALSE if not.
7135  */
7137  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
7138  int childidx, /**< index of the child which factor to search for */
7139  int* pos /**< buffer to store position of factor */
7140  )
7141 {
7142  assert(monomial != NULL);
7143 
7144  if( monomial->nfactors == 0 )
7145  return FALSE;
7146 
7147  SCIPexprSortMonomialFactors(monomial);
7148 
7149  return SCIPsortedvecFindInt(monomial->childidxs, childidx, monomial->nfactors, pos);
7150 }
7151 
7152 /** creates a user expression */
7154  BMS_BLKMEM* blkmem, /**< block memory data structure */
7155  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
7156  int nchildren, /**< number of children */
7157  SCIP_EXPR** children, /**< children of expression */
7158  SCIP_USEREXPRDATA* data, /**< user data for expression, expression assumes ownership */
7159  SCIP_EXPRINTCAPABILITY evalcapability, /**< capability of evaluation functions (partially redundant, currently) */
7160  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
7161  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function, or NULL if not implemented */
7162  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
7163  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function, or NULL if not implemented */
7164  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
7165  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
7166  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
7167  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
7168  )
7169 {
7170  SCIP_EXPROPDATA opdata;
7171  SCIP_EXPRDATA_USER* userexprdata;
7172  SCIP_EXPR** childrencopy;
7173 
7174  assert(blkmem != NULL);
7175  assert(expr != NULL);
7176  assert(eval != NULL);
7177  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
7178  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
7179  assert(curv != NULL);
7180  assert(copydata != NULL || data == NULL);
7181  assert(freedata != NULL || data == NULL);
7182 
7183  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &userexprdata) );
7184 
7185  userexprdata->userdata = data;
7186  userexprdata->evalcapability = evalcapability;
7187  userexprdata->eval = eval;
7188  userexprdata->inteval = inteval;
7189  userexprdata->curv = curv;
7190  userexprdata->prop = prop;
7191  userexprdata->estimate = estimate;
7192  userexprdata->copydata = copydata;
7193  userexprdata->freedata = freedata;
7194  userexprdata->print = print;
7195 
7196  opdata.data = (void*) userexprdata;
7197 
7198  if( nchildren == 0 )
7199  {
7200  SCIP_CALL( exprCreate(blkmem, expr, SCIP_EXPR_USER, 0, NULL, opdata) );
7201  return SCIP_OKAY;
7202  }
7203  assert(children != NULL);
7204 
7205  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
7206 
7207  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_USER, nchildren, childrencopy, opdata) );
7208 
7209  return SCIP_OKAY;
7210 }
7211 
7212 /** indicates whether the expression contains a SCIP_EXPR_PARAM */
7214  SCIP_EXPR* expr /**< expression */
7215  )
7216 {
7217  int i;
7218 
7219  assert(expr != NULL);
7220 
7221  if( expr->op == SCIP_EXPR_PARAM )
7222  return TRUE;
7223 
7224  for( i = 0; i < expr->nchildren; ++i )
7225  if( SCIPexprHasParam(expr->children[i]) )
7226  return TRUE;
7227 
7228  return FALSE;
7229 }
7230 
7231 /** gets maximal degree of expression, or SCIP_EXPR_DEGREEINFINITY if not a polynomial */
7233  SCIP_EXPR* expr, /**< expression */
7234  int* maxdegree /**< buffer to store maximal degree */
7235  )
7236 {
7237  int child1;
7238  int child2;
7239 
7240  assert(expr != NULL);
7241  assert(maxdegree != NULL);
7242 
7243  switch( expr->op )
7244  {
7245  case SCIP_EXPR_VARIDX:
7246  *maxdegree = 1;
7247  break;
7248 
7249  case SCIP_EXPR_CONST:
7250  case SCIP_EXPR_PARAM:
7251  *maxdegree = 0;
7252  break;
7253 
7254  case SCIP_EXPR_PLUS:
7255  case SCIP_EXPR_MINUS:
7256  {
7257  assert(expr->children[0] != NULL);
7258  assert(expr->children[1] != NULL);
7259 
7260  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7261  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7262 
7263  *maxdegree = MAX(child1, child2);
7264  break;
7265  }
7266 
7267  case SCIP_EXPR_MUL:
7268  {
7269  assert(expr->children[0] != NULL);
7270  assert(expr->children[1] != NULL);
7271 
7272  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7273  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7274 
7275  *maxdegree = child1 + child2;
7276  break;
7277  }
7278 
7279  case SCIP_EXPR_DIV:
7280  {
7281  assert(expr->children[0] != NULL);
7282  assert(expr->children[1] != NULL);
7283 
7284  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7285  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7286 
7287  /* if not division by constant, then it is not a polynomial */
7288  *maxdegree = (child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : child1;
7289  break;
7290  }
7291 
7292  case SCIP_EXPR_SQUARE:
7293  {
7294  assert(expr->children[0] != NULL);
7295 
7296  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7297 
7298  *maxdegree = 2 * child1;
7299  break;
7300  }
7301 
7302  case SCIP_EXPR_SQRT:
7303  {
7304  assert(expr->children[0] != NULL);
7305 
7306  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7307 
7308  /* if not squareroot of constant, then no polynomial */
7309  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7310  break;
7311  }
7312 
7313  case SCIP_EXPR_REALPOWER:
7314  {
7315  assert(expr->children[0] != NULL);
7316 
7317  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7318 
7319  /* constant ^ constant has degree 0 */
7320  if( child1 == 0 )
7321  {
7322  *maxdegree = 0;
7323  break;
7324  }
7325 
7326  /* non-polynomial ^ constant is not a polynomial */
7327  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7328  {
7329  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7330  break;
7331  }
7332 
7333  /* so it is polynomial ^ constant
7334  * let's see whether the constant is integral */
7335 
7336  if( expr->data.dbl == 0.0 ) /* polynomial ^ 0 == 0 */
7337  *maxdegree = 0;
7338  else if( expr->data.dbl > 0.0 && (int)expr->data.dbl == expr->data.dbl ) /* natural exponent gives polynomial again */ /*lint !e777*/
7339  *maxdegree = child1 * (int)expr->data.dbl;
7340  else /* negative or nonintegral exponent does not give polynomial */
7341  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7342 
7343  break;
7344  }
7345 
7346  case SCIP_EXPR_INTPOWER:
7347  {
7348  assert(expr->children[0] != NULL);
7349 
7350  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7351 
7352  /* constant ^ integer or something ^ 0 has degree 0 */
7353  if( child1 == 0 || expr->data.intval == 0 )
7354  {
7355  *maxdegree = 0;
7356  break;
7357  }
7358 
7359  /* non-polynomial ^ integer or something ^ negative is not a polynomial */
7360  if( child1 >= SCIP_EXPR_DEGREEINFINITY || expr->data.intval < 0 )
7361  {
7362  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7363  break;
7364  }
7365 
7366  /* so it is polynomial ^ natural, which gives a polynomial again */
7367  *maxdegree = child1 * expr->data.intval;
7368 
7369  break;
7370  }
7371 
7372  case SCIP_EXPR_SIGNPOWER:
7373  {
7374  assert(expr->children[0] != NULL);
7375 
7376  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7377 
7378  /* if child is not constant, then it is no polynomial */
7379  *maxdegree = child1 != 0 ? SCIP_EXPR_DEGREEINFINITY : 0;
7380  break;
7381  }
7382 
7383  case SCIP_EXPR_EXP:
7384  case SCIP_EXPR_LOG:
7385  case SCIP_EXPR_SIN:
7386  case SCIP_EXPR_COS:
7387  case SCIP_EXPR_TAN:
7388  /* case SCIP_EXPR_ERF: */
7389  /* case SCIP_EXPR_ERFI: */
7390  case SCIP_EXPR_ABS:
7391  case SCIP_EXPR_SIGN:
7392  case SCIP_EXPR_USER:
7393  {
7394  assert(expr->children[0] != NULL);
7395 
7396  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7397 
7398  /* if argument is not a constant, then no polynomial, otherwise it is a constant */
7399  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7400  break;
7401  }
7402 
7403  case SCIP_EXPR_MIN:
7404  case SCIP_EXPR_MAX:
7405  {
7406  assert(expr->children[0] != NULL);
7407  assert(expr->children[1] != NULL);
7408 
7409  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7410  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7411 
7412  /* if any of the operands is not constant, then it is no polynomial */
7413  *maxdegree = (child1 != 0 || child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7414  break;
7415  }
7416 
7417  case SCIP_EXPR_SUM:
7418  case SCIP_EXPR_LINEAR:
7419  {
7420  int i;
7421 
7422  *maxdegree = 0;
7423  for( i = 0; i < expr->nchildren && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7424  {
7425  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7426  if( child1 > *maxdegree )
7427  *maxdegree = child1;
7428  }
7429 
7430  break;
7431  }
7432 
7433  case SCIP_EXPR_PRODUCT:
7434  {
7435  int i;
7436 
7437  *maxdegree = 0;
7438  for( i = 0; i < expr->nchildren; ++i )
7439  {
7440  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7441  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7442  {
7443  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7444  break;
7445  }
7446  *maxdegree += child1;
7447  }
7448 
7449  break;
7450  }
7451 
7452  case SCIP_EXPR_QUADRATIC:
7453  {
7454  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7455  int childidx;
7456  int quadidx;
7457 
7458  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7459 
7460  /* make sure quadratic elements are sorted */
7461  quadraticdataSort(quadraticdata);
7462 
7463  *maxdegree = 0;
7464  quadidx = 0;
7465  for( childidx = 0; childidx < expr->nchildren; ++childidx )
7466  {
7467  /* if no linear or no quadratic coefficient with current child on first position, then nothing to do */
7468  if( (quadraticdata->lincoefs == NULL || quadraticdata->lincoefs[childidx] == 0.0) &&
7469  (quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 > childidx) )
7470  continue;
7471 
7472  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[childidx], &child1) );
7473  if( child1 == SCIP_EXPR_DEGREEINFINITY )
7474  {
7475  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7476  break;
7477  }
7478 
7479  while( quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 == childidx )
7480  {
7481  if( quadraticdata->quadelems[quadidx].idx2 == childidx )
7482  {
7483  /* square term */
7484  if( 2*child1 > *maxdegree )
7485  *maxdegree = 2*child1;
7486  }
7487  else
7488  {
7489  /* bilinear term */
7490  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[quadraticdata->quadelems[quadidx].idx2], &child2) );
7491  if( child2 == SCIP_EXPR_DEGREEINFINITY )
7492  {
7493  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7494  break;
7495  }
7496  if( child1 + child2 > *maxdegree )
7497  *maxdegree = child1 + child2;
7498  }
7499  ++quadidx;
7500  }
7501  if( *maxdegree == SCIP_EXPR_DEGREEINFINITY )
7502  break;
7503  }
7504 
7505  break;
7506  }
7507 
7508  case SCIP_EXPR_POLYNOMIAL:
7509  {
7510  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7511  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7512  int monomialdegree;
7513  int i;
7514  int j;
7515 
7516  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7517 
7518  *maxdegree = 0;
7519  for( i = 0; i < polynomialdata->nmonomials && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7520  {
7521  monomialdata = polynomialdata->monomials[i];
7522  assert(monomialdata != NULL);
7523 
7524  /* compute degree of monomial = sum of degree of factors */
7525  monomialdegree = 0;
7526  for( j = 0; j < monomialdata->nfactors; ++j )
7527  {
7528  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[monomialdata->childidxs[j]], &child1) );
7529 
7530  /* if the exponent of the factor is not a natural number and the child is not constant (degree 0),
7531  * then we report that we are not really a polynomial */
7532  if( child1 != 0 && (monomialdata->exponents[j] < 0.0 || (int)monomialdata->exponents[j] != monomialdata->exponents[j]) )
7533  {
7534  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7535  break;
7536  }
7537 
7538  monomialdegree += child1 * (int)monomialdata->exponents[j];
7539  }
7540 
7541  if( monomialdegree > *maxdegree )
7542  *maxdegree = monomialdegree;
7543  }
7544 
7545  break;
7546  }
7547 
7548  case SCIP_EXPR_LAST:
7549  SCIPABORT();
7550  break;
7551  }
7552 
7553  return SCIP_OKAY;
7554 }
7555 
7556 /** counts usage of variables in expression */
7558  SCIP_EXPR* expr, /**< expression to update */
7559  int* varsusage /**< array with counters of variable usage */
7560  )
7561 {
7562  int i;
7563 
7564  assert(expr != NULL);
7565  assert(varsusage != NULL);
7566 
7567  if( expr->op == SCIP_EXPR_VARIDX )
7568  {
7569  ++varsusage[expr->data.intval];
7570  }
7571 
7572  for( i = 0; i < expr->nchildren; ++i )
7573  SCIPexprGetVarsUsage(expr->children[i], varsusage);
7574 }
7575 
7576 /** compares whether two expressions are the same
7577  *
7578  * Inconclusive, i.e., may give FALSE even if expressions are equivalent (x*y != y*x).
7579  */
7581  SCIP_EXPR* expr1, /**< first expression */
7582  SCIP_EXPR* expr2, /**< second expression */
7583  SCIP_Real eps /**< threshold under which numbers are assumed to be zero */
7584  )
7585 {
7586  assert(expr1 != NULL);
7587  assert(expr2 != NULL);
7588 
7589  if( expr1 == expr2 )
7590  return TRUE;
7591 
7592  if( expr1->op != expr2->op )
7593  return FALSE;
7594 
7595  switch( expr1->op )
7596  {
7597  case SCIP_EXPR_VARIDX:
7598  case SCIP_EXPR_PARAM:
7599  return expr1->data.intval == expr2->data.intval;
7600 
7601  case SCIP_EXPR_CONST:
7602  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps);
7603 
7604  /* operands with two children */
7605  case SCIP_EXPR_PLUS :
7606  case SCIP_EXPR_MINUS :
7607  case SCIP_EXPR_MUL :
7608  case SCIP_EXPR_DIV :
7609  case SCIP_EXPR_MIN :
7610  case SCIP_EXPR_MAX :
7611  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps) && SCIPexprAreEqual(expr1->children[1], expr2->children[1], eps);
7612 
7613  /* operands with one child */
7614  case SCIP_EXPR_SQUARE:
7615  case SCIP_EXPR_SQRT :
7616  case SCIP_EXPR_EXP :
7617  case SCIP_EXPR_LOG :
7618  case SCIP_EXPR_SIN :
7619  case SCIP_EXPR_COS :
7620  case SCIP_EXPR_TAN :
7621  /* case SCIP_EXPR_ERF : */
7622  /* case SCIP_EXPR_ERFI : */
7623  case SCIP_EXPR_ABS :
7624  case SCIP_EXPR_SIGN :
7625  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7626 
7627  case SCIP_EXPR_REALPOWER:
7628  case SCIP_EXPR_SIGNPOWER:
7629  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps) && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7630 
7631  case SCIP_EXPR_INTPOWER:
7632  return expr1->data.intval == expr2->data.intval && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7633 
7634  /* complex operands */
7635  case SCIP_EXPR_SUM :
7636  case SCIP_EXPR_PRODUCT:
7637  {
7638  int i;
7639 
7640  /* @todo sort children and have sorted flag in data? */
7641 
7642  if( expr1->nchildren != expr2->nchildren )
7643  return FALSE;
7644 
7645  for( i = 0; i < expr1->nchildren; ++i )
7646  {
7647  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7648  return FALSE;
7649  }
7650 
7651  return TRUE;
7652  }
7653 
7654  case SCIP_EXPR_LINEAR :
7655  {
7656  SCIP_Real* data1;
7657  SCIP_Real* data2;
7658  int i;
7659 
7660  /* @todo sort children and have sorted flag in data? */
7661 
7662  if( expr1->nchildren != expr2->nchildren )
7663  return FALSE;
7664 
7665  data1 = (SCIP_Real*)expr1->data.data;
7666  data2 = (SCIP_Real*)expr2->data.data;
7667 
7668  /* check if constant and coefficients are equal */
7669  for( i = 0; i < expr1->nchildren + 1; ++i )
7670  if( !EPSEQ(data1[i], data2[i], eps) )
7671  return FALSE;
7672 
7673  /* check if children are equal */
7674  for( i = 0; i < expr1->nchildren; ++i )
7675  {
7676  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7677  return FALSE;
7678  }
7679 
7680  return TRUE;
7681  }
7682 
7683  case SCIP_EXPR_QUADRATIC:
7684  {
7685  SCIP_EXPRDATA_QUADRATIC* data1;
7686  SCIP_EXPRDATA_QUADRATIC* data2;
7687  int i;
7688 
7689  if( expr1->nchildren != expr2->nchildren )
7690  return FALSE;
7691 
7692  data1 = (SCIP_EXPRDATA_QUADRATIC*)expr1->data.data;
7693  data2 = (SCIP_EXPRDATA_QUADRATIC*)expr2->data.data;
7694 
7695  if( data1->nquadelems != data2->nquadelems )
7696  return FALSE;
7697 
7698  if( !EPSEQ(data1->constant, data2->constant, eps) )
7699  return FALSE;
7700 
7701  /* check if linear part is equal */
7702  if( data1->lincoefs != NULL || data2->lincoefs != NULL )
7703  for( i = 0; i < expr1->nchildren; ++i )
7704  {
7705  if( data1->lincoefs == NULL )
7706  {
7707  if( !EPSZ(data2->lincoefs[i], eps) )
7708  return FALSE;
7709  }
7710  else if( data2->lincoefs == NULL )
7711  {
7712  if( !EPSZ(data1->lincoefs[i], eps) )
7713  return FALSE;
7714  }
7715  else if( !EPSEQ(data1->lincoefs[i], data2->lincoefs[i], eps) )
7716  return FALSE;
7717  }
7718 
7719  SCIPexprSortQuadElems(expr1);
7720  SCIPexprSortQuadElems(expr2);
7721 
7722  /* check if quadratic elements are equal */
7723  for( i = 0; i < data1->nquadelems; ++i )
7724  if( data1->quadelems[i].idx1 != data2->quadelems[i].idx1 ||
7725  data1->quadelems[i].idx2 != data2->quadelems[i].idx2 ||
7726  !EPSEQ(data1->quadelems[i].coef, data2->quadelems[i].coef, eps) )
7727  return FALSE;
7728 
7729  /* check if children are equal */
7730  for( i = 0; i < expr1->nchildren; ++i )
7731  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7732  return FALSE;
7733 
7734  return TRUE;
7735  }
7736 
7737  case SCIP_EXPR_POLYNOMIAL:
7738  {
7739  SCIP_EXPRDATA_POLYNOMIAL* data1;
7740  SCIP_EXPRDATA_POLYNOMIAL* data2;
7741  int i;
7742 
7743  if( expr1->nchildren != expr2->nchildren )
7744  return FALSE;
7745 
7746  data1 = (SCIP_EXPRDATA_POLYNOMIAL*)expr1->data.data;
7747  data2 = (SCIP_EXPRDATA_POLYNOMIAL*)expr2->data.data;
7748 
7749  if( data1->nmonomials != data2->nmonomials )
7750  return FALSE;
7751 
7752  if( !EPSEQ(data1->constant, data2->constant, eps) )
7753  return FALSE;
7754 
7755  /* make sure polynomials are sorted */
7756  SCIPexprSortMonomials(expr1);
7757  SCIPexprSortMonomials(expr2);
7758 
7759  /* check if monomials are equal */
7760  for( i = 0; i < data1->nmonomials; ++i )
7761  {
7762  if( !SCIPexprAreMonomialsEqual(data1->monomials[i], data2->monomials[i], eps) )
7763  return FALSE;
7764  }
7765 
7766  /* check if children are equal */
7767  for( i = 0; i < expr1->nchildren; ++i )
7768  {
7769  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7770  return FALSE;
7771  }
7772 
7773  return TRUE;
7774  }
7775 
7776  case SCIP_EXPR_USER:
7777  {
7778  /* @todo could implement this via another user callback */
7779  return FALSE;
7780  }
7781 
7782  case SCIP_EXPR_LAST:
7783  break;
7784  }
7785 
7786  SCIPerrorMessage("this should never happen\n");
7787  SCIPABORT();
7788  return FALSE; /*lint !e527*/
7789 }
7790 
7791 /** aims at simplifying an expression and splitting of a linear expression
7792  *
7793  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
7794  */
7796  BMS_BLKMEM* blkmem, /**< block memory data structure */
7797  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7798  SCIP_EXPR* expr, /**< expression */
7799  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
7800  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
7801  int nvars, /**< number of variables in expression */
7802  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
7803  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
7804  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
7805  )
7806 {
7807  assert(blkmem != NULL);
7808  assert(expr != NULL);
7809  assert(eps >= 0.0);
7810 
7811  SCIPdebugMessage("simplify expression: ");
7812  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7813  SCIPdebugPrintf("\n");
7814 
7816 
7817  SCIPdebugMessage("converted to polynomials: ");
7818  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7819  SCIPdebugPrintf("\n");
7820 
7821  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr, eps, maxexpansionexponent) );
7822 
7823  SCIPdebugMessage("polynomials flattened: ");
7824  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7825  SCIPdebugPrintf("\n");
7826 
7827  if( nlinvars != NULL )
7828  {
7829  /* separate linear part from root polynomial */
7830  SCIP_CALL( exprsimplifySeparateLinearFromPolynomial(blkmem, expr, eps, nvars, nlinvars, linidxs, lincoefs) );
7831 
7832  SCIPdebugMessage("separated linear part: ");
7833  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7834  SCIPdebugPrintf("\n");
7835  }
7836 
7838 
7839  SCIPdebugMessage("converted back from polynomials: ");
7840  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7841  SCIPdebugPrintf("\n");
7842 
7843  return SCIP_OKAY;
7844 }
7845 
7846 /** evaluates an expression w.r.t. given values for children expressions */
7848  SCIP_EXPR* expr, /**< expression */
7849  SCIP_Real* argvals, /**< values for children, can be NULL if the expression has no children */
7850  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression operand is not a variable */
7851  SCIP_Real* param, /**< values for parameters, can be NULL if the expression operand is not a parameter */
7852  SCIP_Real* val /**< buffer to store value */
7853  )
7854 {
7855  assert(expr != NULL);
7856  assert(argvals != NULL || expr->nchildren == 0);
7857 
7858  /* evaluate this expression */
7859  assert( exprOpTable[expr->op].eval != NULL );
7860  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, argvals, varvals, param, val) );
7861 
7862  return SCIP_OKAY;
7863 }
7864 
7865 /** evaluates an expression w.r.t. a point */
7867  SCIP_EXPR* expr, /**< expression */
7868  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression is constant */
7869  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7870  SCIP_Real* val /**< buffer to store value */
7871  )
7872 {
7873  int i;
7875  SCIP_Real* buf;
7876 
7877  /* if many children, get large enough memory to store argument values */
7879  {
7880  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7881  }
7882  else
7883  {
7884  buf = staticbuf;
7885  }
7886 
7887  /* evaluate children */
7888  for( i = 0; i < expr->nchildren; ++i )
7889  {
7890  SCIP_CALL( SCIPexprEval(expr->children[i], varvals, param, &buf[i]) ); /*lint !e644*/
7891  }
7892 
7893  /* evaluate this expression */
7894  assert( exprOpTable[expr->op].eval != NULL );
7895  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, buf, varvals, param, val) );
7896 
7897  /* free memory, if allocated before */
7898  if( staticbuf != buf )
7899  {
7900  BMSfreeMemoryArray(&buf);
7901  }
7902 
7903  return SCIP_OKAY;
7904 }
7905 
7906 /** evaluates an expression w.r.t. given interval values for children expressions */
7908  SCIP_EXPR* expr, /**< expression */
7909  SCIP_Real infinity, /**< value to use for infinity */
7910  SCIP_INTERVAL* argvals, /**< interval values for children, can be NULL if the expression has no children */
7911  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7912  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7913  SCIP_INTERVAL* val /**< buffer to store value */
7914  )
7915 {
7916  assert(expr != NULL);
7917  assert(argvals != NULL || expr->nchildren == 0);
7918 
7919  /* evaluate this expression */
7920  assert( exprOpTable[expr->op].inteval != NULL );
7921  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, argvals, varvals, param, val) );
7922 
7923  return SCIP_OKAY;
7924 }
7925 
7926 /** evaluates an expression w.r.t. an interval */
7928  SCIP_EXPR* expr, /**< expression */
7929  SCIP_Real infinity, /**< value to use for infinity */
7930  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7931  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7932  SCIP_INTERVAL* val /**< buffer to store value */
7933  )
7934 {
7935  int i;
7937  SCIP_INTERVAL* buf;
7938 
7939  /* if many children, get large enough memory to store argument values */
7941  {
7942  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7943  }
7944  else
7945  {
7946  buf = staticbuf;
7947  }
7948 
7949  /* evaluate children */
7950  for( i = 0; i < expr->nchildren; ++i )
7951  {
7952  SCIP_CALL( SCIPexprEvalInt(expr->children[i], infinity, varvals, param, &buf[i]) ); /*lint !e644*/
7953  }
7954 
7955  /* evaluate this expression */
7956  assert( exprOpTable[expr->op].inteval != NULL );
7957  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, buf, varvals, param, val) );
7958 
7959  /* free memory, if allocated before */
7960  if( staticbuf != buf )
7961  {
7962  BMSfreeMemoryArray(&buf);
7963  }
7964 
7965  return SCIP_OKAY;
7966 }
7967 
7968 /** evaluates a user expression w.r.t. given values for children expressions */
7970  SCIP_EXPR* expr, /**< expression */
7971  SCIP_Real* argvals, /**< values for children */
7972  SCIP_Real* val, /**< buffer to store function value */
7973  SCIP_Real* gradient, /**< buffer to store gradient values, or NULL if not requested */
7974  SCIP_Real* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7975  )
7976 {
7977  SCIP_EXPRDATA_USER* exprdata;
7978 
7979  assert(expr != NULL);
7980  assert(expr->op == SCIP_EXPR_USER);
7981  assert(argvals != NULL || expr->nchildren == 0);
7982 
7983  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7984  assert(exprdata->eval != NULL);
7985 
7986  SCIP_CALL( exprdata->eval(exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7987 
7988  return SCIP_OKAY;
7989 }
7990 
7991 /** evaluates a user expression w.r.t. an interval */
7993  SCIP_EXPR* expr, /**< expression */
7994  SCIP_Real infinity, /**< value to use for infinity */
7995  SCIP_INTERVAL* argvals, /**< values for children */
7996  SCIP_INTERVAL* val, /**< buffer to store value */
7997  SCIP_INTERVAL* gradient, /**< buffer to store gradient values, or NULL if not requested */
7998  SCIP_INTERVAL* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7999  )
8000 {
8001  SCIP_EXPRDATA_USER* exprdata;
8002 
8003  assert(expr != NULL);
8004  assert(expr->op == SCIP_EXPR_USER);
8005  assert(argvals != NULL || expr->nchildren == 0);
8006 
8007  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8008 
8009  if( exprdata->inteval == NULL )
8010  {
8011  int i;
8012 
8013  for( i = 0; i < expr->nchildren; ++i )
8014  SCIPintervalSetEntire(infinity, &argvals[i]); /*lint !e613*/
8015  }
8016  else
8017  {
8018  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
8019  }
8020 
8021  return SCIP_OKAY;
8022 }
8023 
8024 /** internal curvature check method */
8025 static
8027  SCIP_EXPR* expr, /**< expression to check */
8028  SCIP_Real infinity, /**< value to use for infinity */
8029  SCIP_INTERVAL* varbounds, /**< domains of variables */
8030  SCIP_INTERVAL* childbounds, /**< child bounds buffer array */
8031  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
8032  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8033  SCIP_EXPRCURV* childcurv, /**< buffer array for curvature of children */
8034  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
8035  )
8036 {
8037  int i;
8038 
8039  assert(childbounds != NULL);
8040  assert(childcurv != NULL);
8041 
8042  /* check curvature and compute bounds of children
8043  * constant children can be considered as always linear */
8044  for( i = 0; i < expr->nchildren; ++i )
8045  {
8046  SCIP_CALL( SCIPexprCheckCurvature(expr->children[i], infinity, varbounds, param, &childcurv[i], &childbounds[i]) ); /*lint !e644*/
8047  if( childbounds[i].inf == childbounds[i].sup ) /*lint !e777*/
8048  childcurv[i] = SCIP_EXPRCURV_LINEAR;
8049  }
8050 
8051  /* get curvature and bounds of expr */
8052  assert(exprOpTable[expr->op].curv != NULL);
8053  assert(exprOpTable[expr->op].inteval != NULL);
8054 
8055  SCIP_CALL( exprOpTable[expr->op].curv(infinity, expr->data, expr->nchildren, childbounds, childcurv, curv) );
8056  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, childbounds, varbounds, param, bounds) );
8057 
8058  return SCIP_OKAY;
8059 }
8060 
8061 /** tries to determine the curvature type of an expression w.r.t. given variable domains */
8063  SCIP_EXPR* expr, /**< expression to check */
8064  SCIP_Real infinity, /**< value to use for infinity */
8065  SCIP_INTERVAL* varbounds, /**< domains of variables */
8066  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
8067  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8068  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
8069  )
8070 {
8072  SCIP_INTERVAL* childbounds = NULL;
8074  SCIP_EXPRCURV* childcurv = NULL;
8075  SCIP_RETCODE retcode = SCIP_OKAY;
8076 
8077  assert(expr != NULL);
8078  assert(curv != NULL);
8079  assert(bounds != NULL);
8080 
8081  /* if many children, get large enough memory to store argument values */
8083  {
8084  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, expr->nchildren) );
8085  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, expr->nchildren), TERMINATE );
8086  }
8087  else
8088  {
8089  childbounds = childboundsbuf;
8090  childcurv = childcurvbuf;
8091  }
8092 
8093  retcode = doCheckCurvature(expr, infinity, varbounds, childbounds, param, curv, childcurv, bounds);
8094 
8095 TERMINATE:
8096  /* free memory, if allocated before */
8097  if( childboundsbuf != childbounds )
8098  {
8099  BMSfreeMemoryArrayNull(&childcurv);
8100  BMSfreeMemoryArrayNull(&childbounds);
8101  }
8102 
8103  return retcode;
8104 }
8105 
8106 /** under-/overestimates a user expression w.r.t. to given values and bounds for children expressions */
8108  SCIP_EXPR* expr, /**< expression */
8109  SCIP_Real infinity, /**< value to use for infinity */
8110  SCIP_Real* argvals, /**< values for children */
8111  SCIP_INTERVAL* argbounds, /**< bounds for children */
8112  SCIP_Bool overestimate, /**< whether to overestimate the expression */
8113  SCIP_Real* coeffs, /**< buffer to store the linear coefficients for each child expression that gives a valid under-/overestimator */
8114  SCIP_Real* constant, /**< buffer to store the constant value of the linear under-/overestimator */
8115  SCIP_Bool* success /**< buffer to store whether an estimator was successfully computed */
8116  )
8117 {
8118  SCIP_EXPRDATA_USER* exprdata;
8119 
8120  assert(expr != NULL);
8121  assert(expr->op == SCIP_EXPR_USER);
8122  assert(argvals != NULL || expr->nchildren == 0);
8123  assert(argbounds != NULL || expr->nchildren == 0);
8124 
8125  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8126 
8127  if( exprdata->estimate != NULL )
8128  {
8129  SCIP_CALL( exprdata->estimate(infinity, exprdata->userdata, expr->nchildren, argvals, argbounds, overestimate, coeffs, constant, success ) );
8130  }
8131  else
8132  {
8133  *success = FALSE;
8134  }
8135 
8136  return SCIP_OKAY;
8137 }
8138 
8139 /** substitutes variables (SCIP_EXPR_VARIDX) by expressions
8140  *
8141  * Note that only the children of the given expr are checked!
8142  * A variable with index i is replaced by a copy of substexprs[i], if the latter is not NULL.
8143  * If substexprs[i] == NULL, then the variable expression i is not touched.
8144  */
8146  BMS_BLKMEM* blkmem, /**< block memory data structure */
8147  SCIP_EXPR* expr, /**< expression, which of the children may be replaced */
8148  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8149  )
8150 {
8151  int i;
8152 
8153  assert(blkmem != NULL);
8154  assert(expr != NULL);
8155  assert(substexprs != NULL);
8156 
8157  for( i = 0; i < expr->nchildren; ++i )
8158  {
8159  if( expr->children[i]->op == SCIP_EXPR_VARIDX )
8160  {
8161  int varidx;
8162  varidx = expr->children[i]->data.intval;
8163 
8164  assert(varidx >= 0);
8165  if( substexprs[varidx] != NULL )
8166  {
8167  /* replace child i by copy of substexprs[expr->children[i]->opdata.intval] */
8168  SCIPexprFreeDeep(blkmem, &expr->children[i]);
8169  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[i], substexprs[varidx]) );
8170  }
8171  }
8172  else
8173  {
8174  /* call recursively */
8175  SCIP_CALL( SCIPexprSubstituteVars(blkmem, expr->children[i], substexprs) );
8176  }
8177  }
8178 
8179  return SCIP_OKAY;
8180 }
8181 
8182 /** updates variable indices in expression tree */
8184  SCIP_EXPR* expr, /**< expression to update */
8185  int* newindices /**< new indices of variables */
8186  )
8187 {
8188  int i;
8189 
8190  assert(expr != NULL);
8191  assert(newindices != NULL);
8192 
8193  if( expr->op == SCIP_EXPR_VARIDX )
8194  {
8195  expr->data.intval = newindices[expr->data.intval];
8196  assert(expr->data.intval >= 0);
8197  }
8198 
8199  for( i = 0; i < expr->nchildren; ++i )
8200  SCIPexprReindexVars(expr->children[i], newindices);
8201 }
8202 
8203 /** updates parameter indices in expression tree */
8205  SCIP_EXPR* expr, /**< expression to update */
8206  int* newindices /**< new indices of variables */
8207  )
8208 {
8209  int i;
8210 
8211  assert(expr != NULL);
8212  assert(newindices != NULL);
8213 
8214  if( expr->op == SCIP_EXPR_PARAM )
8215  {
8216  expr->data.intval = newindices[expr->data.intval];
8217  assert(expr->data.intval >= 0);
8218  }
8219 
8220  for( i = 0; i < expr->nchildren; ++i )
8221  SCIPexprReindexParams(expr->children[i], newindices);
8222 }
8223 
8224 /** prints an expression */
8226  SCIP_EXPR* expr, /**< expression */
8227  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8228  FILE* file, /**< file for printing, or NULL for stdout */
8229  const char** varnames, /**< names of variables, or NULL for default names */
8230  const char** paramnames, /**< names of parameters, or NULL for default names */
8231  SCIP_Real* paramvals /**< values of parameters, or NULL for not printing */
8232  )
8233 {
8234  assert( expr != NULL );
8235 
8236  switch( expr->op )
8237  {
8238  /* @Note: 'expr->data.intval' is either between 0 and number of variables-1, if it uses the varnames array, or
8239  * between 0 and number of params in the expression tree, if it uses the paramnames array
8240  * because, here, we cannot get the values above we cannot assert them
8241  */
8242  case SCIP_EXPR_VARIDX:
8243  if( varnames != NULL )
8244  {
8245  assert(varnames[expr->data.intval] != NULL);
8246  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", varnames[expr->data.intval]);
8247  }
8248  else
8249  {
8250  SCIPmessageFPrintInfo(messagehdlr, file, "var%d", expr->data.intval);
8251  }
8252  break;
8253 
8254  case SCIP_EXPR_PARAM:
8255  if( paramnames != NULL )
8256  {
8257  assert(paramnames[expr->data.intval] != NULL);
8258  SCIPmessageFPrintInfo(messagehdlr, file, "%s", paramnames[expr->data.intval]);
8259  }
8260  else
8261  {
8262  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", expr->data.intval );
8263  }
8264  if( paramvals != NULL )
8265  {
8266  SCIPmessageFPrintInfo(messagehdlr, file, "[%g]", paramvals[expr->data.intval] );
8267  }
8268  break;
8269 
8270  case SCIP_EXPR_CONST:
8271  if (expr->data.dbl < 0.0 )
8272  SCIPmessageFPrintInfo(messagehdlr, file, "(%g)", expr->data.dbl );
8273  else
8274  SCIPmessageFPrintInfo(messagehdlr, file, "%g", expr->data.dbl );
8275  break;
8276 
8277  case SCIP_EXPR_PLUS:
8278  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8279  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8280  SCIPmessageFPrintInfo(messagehdlr, file, " + ");
8281  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8282  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8283  break;
8284 
8285  case SCIP_EXPR_MINUS:
8286  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8287  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8288  SCIPmessageFPrintInfo(messagehdlr, file, " - ");
8289  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8290  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8291  break;
8292 
8293  case SCIP_EXPR_MUL:
8294  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8295  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8296  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8297  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8298  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8299  break;
8300 
8301  case SCIP_EXPR_DIV:
8302  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8303  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8304  SCIPmessageFPrintInfo(messagehdlr, file, " / ");
8305  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8306  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8307  break;
8308 
8309  case SCIP_EXPR_REALPOWER:
8310  case SCIP_EXPR_SIGNPOWER:
8311  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8312  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8313  SCIPmessageFPrintInfo(messagehdlr, file, ", %g)", expr->data.dbl);
8314  break;
8315 
8316  case SCIP_EXPR_INTPOWER:
8317  SCIPmessageFPrintInfo(messagehdlr, file, "power(");
8318  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8319  SCIPmessageFPrintInfo(messagehdlr, file, ", %d)", expr->data.intval);
8320  break;
8321 
8322  case SCIP_EXPR_SQUARE:
8323  case SCIP_EXPR_SQRT:
8324  case SCIP_EXPR_EXP:
8325  case SCIP_EXPR_LOG:
8326  case SCIP_EXPR_SIN:
8327  case SCIP_EXPR_COS:
8328  case SCIP_EXPR_TAN:
8329  /* case SCIP_EXPR_ERF: */
8330  /* case SCIP_EXPR_ERFI: */
8331  case SCIP_EXPR_MIN:
8332  case SCIP_EXPR_MAX:
8333  case SCIP_EXPR_ABS:
8334  case SCIP_EXPR_SIGN:
8335  {
8336  int i;
8337 
8338  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8339 
8340  for( i = 0; i < expr->nchildren; ++i )
8341  {
8342  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8343  if( i + 1 < expr->nchildren )
8344  {
8345  SCIPmessageFPrintInfo(messagehdlr, file, ", ");
8346  }
8347  }
8348 
8349  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8350  break;
8351  }
8352 
8353  case SCIP_EXPR_SUM:
8354  case SCIP_EXPR_PRODUCT:
8355  {
8356  switch( expr->nchildren )
8357  {
8358  case 0:
8359  SCIPmessageFPrintInfo(messagehdlr, file, expr->op == SCIP_EXPR_SUM ? "0" : "1");
8360  break;
8361  case 1:
8362  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8363  break;
8364  default:
8365  {
8366  int i;
8367  char opstr[SCIP_MAXSTRLEN];
8368 
8369  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8370  for( i = 0; i < expr->nchildren; ++i )
8371  {
8372  if( i > 0 )
8373  {
8374  (void) SCIPsnprintf(opstr, SCIP_MAXSTRLEN, "%s", expr->op == SCIP_EXPR_SUM ? " + " : " * ");
8375  SCIPmessageFPrintInfo(messagehdlr, file, opstr);
8376  }
8377  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8378  }
8379  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8380  }
8381  }
8382  break;
8383  }
8384 
8385  case SCIP_EXPR_LINEAR:
8386  {
8387  SCIP_Real constant;
8388  int i;
8389 
8390  constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
8391 
8392  if( expr->nchildren == 0 )
8393  {
8394  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
8395  break;
8396  }
8397 
8398  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8399 
8400  if( constant != 0.0 )
8401  {
8402  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
8403  }
8404 
8405  for( i = 0; i < expr->nchildren; ++i )
8406  {
8407  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", ((SCIP_Real*)expr->data.data)[i]);
8408  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8409  }
8410 
8411  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8412  break;
8413  }
8414 
8415  case SCIP_EXPR_QUADRATIC:
8416  {
8417  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
8418  int i;
8419 
8420  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
8421  assert(quadraticdata != NULL);
8422 
8423  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8424 
8425  if( quadraticdata->constant != 0.0 )
8426  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->constant);
8427 
8428  if( quadraticdata->lincoefs != NULL )
8429  for( i = 0; i < expr->nchildren; ++i )
8430  {
8431  if( quadraticdata->lincoefs[i] == 0.0 )
8432  continue;
8433  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->lincoefs[i]);
8434  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8435  }
8436 
8437  for( i = 0; i < quadraticdata->nquadelems; ++i )
8438  {
8439  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->quadelems[i].coef);
8440  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
8441  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
8442  {
8443  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
8444  }
8445  else
8446  {
8447  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8448  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
8449  }
8450  }
8451 
8452  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8453  break;
8454  }
8455 
8456  case SCIP_EXPR_POLYNOMIAL:
8457  {
8458  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
8459  SCIP_EXPRDATA_MONOMIAL* monomialdata;
8460  int i;
8461  int j;
8462 
8463  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8464 
8465  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
8466  assert(polynomialdata != NULL);
8467 
8468  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
8469  {
8470  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", polynomialdata->constant);
8471  }
8472 
8473  for( i = 0; i < polynomialdata->nmonomials; ++i )
8474  {
8475  monomialdata = polynomialdata->monomials[i];
8476  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g", monomialdata->coef);
8477 
8478  for( j = 0; j < monomialdata->nfactors; ++j )
8479  {
8480  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8481 
8482  SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
8483  if( monomialdata->exponents[j] < 0.0 )
8484  {
8485  SCIPmessageFPrintInfo(messagehdlr, file, "^(%.20g)", monomialdata->exponents[j]);
8486  }
8487  else if( monomialdata->exponents[j] != 1.0 )
8488  {
8489  SCIPmessageFPrintInfo(messagehdlr, file, "^%.20g", monomialdata->exponents[j]);
8490  }
8491  }
8492  }
8493 
8494  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8495  break;
8496  }
8497 
8498  case SCIP_EXPR_USER:
8499  {
8500  SCIP_EXPRDATA_USER* exprdata;
8501  int i;
8502 
8503  exprdata = (SCIP_EXPRDATA_USER*)expr->data.data;
8504  assert(exprdata != NULL);
8505 
8506  if( exprdata->print != NULL )
8507  {
8508  exprdata->print(exprdata->userdata, messagehdlr, file);
8509  }
8510  else
8511  {
8512  SCIPmessageFPrintInfo(messagehdlr, file, "user");
8513  }
8514 
8515  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8516  for( i = 0; i < expr->nchildren; ++i )
8517  {
8518  if( i > 0 )
8519  {
8520  SCIPmessageFPrintInfo(messagehdlr, file, ",");
8521  }
8522  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8523  }
8524  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8525 
8526  break;
8527  }
8528 
8529  case SCIP_EXPR_LAST:
8530  {
8531  SCIPerrorMessage("invalid expression\n");
8532  SCIPABORT();
8533  }
8534  }
8535 }
8536 
8537 /** parses an expression from a string */
8539  BMS_BLKMEM* blkmem, /**< block memory data structure */
8540  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8541  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
8542  const char* str, /**< pointer to the string to be parsed */
8543  const char* lastchar, /**< pointer to the last char of str that should be parsed */
8544  int* nvars, /**< buffer to store number of variables */
8545  int* varnames, /**< buffer to store variable names, prefixed by index (as int) */
8546  int varnameslength /**< length of the varnames buffer array */
8547  )
8548 {
8549  SCIP_HASHTABLE* vartable;
8550  SCIP_RETCODE retcode;
8551 
8552  assert(blkmem != NULL);
8553  assert(expr != NULL);
8554  assert(str != NULL);
8555  assert(lastchar != NULL);
8556  assert(nvars != NULL);
8557  assert(varnames != NULL);
8558 
8559  *nvars = 0;
8560 
8561  /* create a hash table for variable names and corresponding expression index
8562  * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
8563  */
8564  SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString,
8565  SCIPhashKeyValString, NULL) );
8566 
8567  retcode = exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames,
8568  &varnameslength, vartable, 0);
8569 
8570  SCIPhashtableFree(&vartable);
8571 
8572  return retcode;
8573 }
8574 
8575 
8576 /**@} */
8577 
8578 /**@name Expression tree methods */
8579 /**@{ */
8580 
8581 /* In debug mode, the following methods are implemented as function calls to ensure
8582  * type validity.
8583  * In optimized mode, the methods are implemented as defines to improve performance.
8584  * However, we want to have them in the library anyways, so we have to undef the defines.
8585  */
8586 
8587 #undef SCIPexprtreeGetRoot
8588 #undef SCIPexprtreeGetNVars
8589 #undef SCIPexprtreeGetNParams
8590 #undef SCIPexprtreeGetParamVals
8591 #undef SCIPexprtreeSetParamVal
8592 #undef SCIPexprtreeGetInterpreterData
8593 #undef SCIPexprtreeSetInterpreterData
8594 #undef SCIPexprtreeFreeInterpreterData
8595 #undef SCIPexprtreeHasParam
8596 #undef SCIPexprtreeGetMaxDegree
8597 #undef SCIPexprtreeEval
8598 #undef SCIPexprtreeEvalInt
8599 #undef SCIPexprtreePrint
8600 
8601 /** returns root expression of an expression tree */
8603  SCIP_EXPRTREE* tree /**< expression tree */
8604  )
8605 {
8606  assert(tree != NULL);
8607 
8608  return tree->root;
8609 }
8610 
8611 /** returns number of variables in expression tree */
8613  SCIP_EXPRTREE* tree /**< expression tree */
8614  )
8615 {
8616  assert(tree != NULL);
8617 
8618  return tree->nvars;
8619 }
8620 
8621 /** returns number of parameters in expression tree */
8623  SCIP_EXPRTREE* tree /**< expression tree */
8624  )
8625 {
8626  assert(tree != NULL);
8627 
8628  return tree->nparams;
8629 }
8630 
8631 /** returns values of parameters or NULL if none */
8633  SCIP_EXPRTREE* tree /**< expression tree */
8634  )
8635 {
8636  assert(tree != NULL);
8637 
8638  return tree->params;
8639 }
8640 
8641 /** sets value of a single parameter in expression tree */
8643  SCIP_EXPRTREE* tree, /**< expression tree */
8644  int paramidx, /**< index of parameter */
8645  SCIP_Real paramval /**< new value of parameter */
8646  )
8647 {
8648  assert(tree != NULL);
8649  assert(paramidx >= 0);
8650  assert(paramidx < tree->nparams);
8651  assert(tree->params != NULL);
8652 
8653  tree->params[paramidx] = paramval;
8654 }
8655 
8656 /** gets data of expression tree interpreter, or NULL if not set */
8658  SCIP_EXPRTREE* tree /**< expression tree */
8659  )
8660 {
8661  assert(tree != NULL);
8662 
8663  return tree->interpreterdata;
8664 }
8665 
8666 /** sets data of expression tree interpreter */
8668  SCIP_EXPRTREE* tree, /**< expression tree */
8669  SCIP_EXPRINTDATA* interpreterdata /**< expression interpreter data */
8670  )
8671 {
8672  assert(tree != NULL);
8673  assert(interpreterdata != NULL);
8674  assert(tree->interpreterdata == NULL);
8675 
8676  tree->interpreterdata = interpreterdata;
8677 }
8678 
8679 /** frees data of expression tree interpreter, if any */
8681  SCIP_EXPRTREE* tree /**< expression tree */
8682  )
8683 {
8684  if( tree->interpreterdata != NULL )
8685  {
8687  assert(tree->interpreterdata == NULL);
8688  }
8689 
8690  return SCIP_OKAY;
8691 }
8692 
8693 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
8695  SCIP_EXPRTREE* tree /**< expression tree */
8696  )
8697 {
8698  assert(tree != NULL);
8699 
8700  return SCIPexprHasParam(tree->root);
8701 }
8702 
8703 /** Gives maximal degree of expression in expression tree.
8704  *
8705  * If constant expression, gives 0,
8706  * if linear expression, gives 1,
8707  * if polynomial expression, gives its maximal degree,
8708  * otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8709  */
8711  SCIP_EXPRTREE* tree, /**< expression tree */
8712  int* maxdegree /**< buffer to store maximal degree */
8713  )
8714 {
8715  assert(tree != NULL);
8716 
8717  SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8718 
8719  return SCIP_OKAY;
8720 }
8721 
8722 /** evaluates an expression tree w.r.t. a point */
8724  SCIP_EXPRTREE* tree, /**< expression tree */
8725  SCIP_Real* varvals, /**< values for variables */
8726  SCIP_Real* val /**< buffer to store expression tree value */
8727  )
8728 {
8729  assert(tree != NULL);
8730  assert(varvals != NULL || tree->nvars == 0);
8731  assert(val != NULL);
8732 
8733  SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8734 
8735  return SCIP_OKAY;
8736 }
8737 
8738 /** evaluates an expression tree w.r.t. an interval */
8740  SCIP_EXPRTREE* tree, /**< expression tree */
8741  SCIP_Real infinity, /**< value for infinity */
8742  SCIP_INTERVAL* varvals, /**< intervals for variables */
8743  SCIP_INTERVAL* val /**< buffer to store expression tree value */
8744  )
8745 {
8746  assert(tree != NULL);
8747  assert(varvals != NULL || tree->nvars == 0);
8748  assert(val != NULL);
8749 
8750  SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8751 
8752  return SCIP_OKAY;
8753 }
8754 
8755 /** prints an expression tree */
8757  SCIP_EXPRTREE* tree, /**< expression tree */
8758  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8759  FILE* file, /**< file for printing, or NULL for stdout */
8760  const char** varnames, /**< names of variables, or NULL for default names */
8761  const char** paramnames /**< names of parameters, or NULL for default names */
8762  )
8763 {
8764  assert(tree != NULL);
8765 
8766  SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8767 }
8768 
8769 
8770 /** creates an expression tree */
8772  BMS_BLKMEM* blkmem, /**< block memory data structure */
8773  SCIP_EXPRTREE** tree, /**< buffer to store address of created expression tree */
8774  SCIP_EXPR* root, /**< pointer to root expression, not copied deep !, can be NULL */
8775  int nvars, /**< number of variables in variable mapping */
8776  int nparams, /**< number of parameters in expression */
8777  SCIP_Real* params /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8778  )
8779 {
8780  assert(blkmem != NULL);
8781  assert(tree != NULL);
8782 
8783  SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8784 
8785  (*tree)->blkmem = blkmem;
8786  (*tree)->root = root;
8787  (*tree)->nvars = nvars;
8788  (*tree)->vars = NULL;
8789  (*tree)->nparams = nparams;
8790  (*tree)->interpreterdata = NULL;
8791 
8792  if( params != NULL )
8793  {
8794  assert(nparams > 0);
8795  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8796  }
8797  else if( nparams > 0 )
8798  {
8799  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8800  BMSclearMemoryArray((*tree)->params, nparams);
8801  }
8802  else
8803  {
8804  assert(nparams == 0);
8805  (*tree)->params = NULL;
8806  }
8807 
8808  return SCIP_OKAY;
8809 }
8810 
8811 /** copies an expression tree */
8813  BMS_BLKMEM* blkmem, /**< block memory that should be used in new expression tree */
8814  SCIP_EXPRTREE** targettree, /**< buffer to store address of copied expression tree */
8815  SCIP_EXPRTREE* sourcetree /**< expression tree to copy */
8816  )
8817 {
8818  assert(blkmem != NULL);
8819  assert(targettree != NULL);
8820  assert(sourcetree != NULL);
8821 
8822  /* copy expression tree "header" */
8823  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8824 
8825  /* we may have a new block memory; and we do not want to keep the others interpreter data */
8826  (*targettree)->blkmem = blkmem;
8827  (*targettree)->interpreterdata = NULL;
8828 
8829  /* copy variables, if any */
8830  if( sourcetree->vars != NULL )
8831  {
8832  assert(sourcetree->nvars > 0);
8833 
8834  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8835  }
8836 
8837  /* copy parameters, if any */
8838  if( sourcetree->params != NULL )
8839  {
8840  assert(sourcetree->nparams > 0);
8841 
8842  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8843  }
8844 
8845  /* copy expression */
8846  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8847 
8848  return SCIP_OKAY;
8849 }
8850 
8851 /** frees an expression tree */
8853  SCIP_EXPRTREE** tree /**< pointer to expression tree that is freed */
8854  )
8855 {
8856  assert( tree != NULL);
8857  assert(*tree != NULL);
8858 
8860 
8861  if( (*tree)->root != NULL )
8862  {
8863  SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8864  assert((*tree)->root == NULL);
8865  }
8866 
8867  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars, (*tree)->nvars );
8868  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8869 
8870  BMSfreeBlockMemory((*tree)->blkmem, tree);
8871 
8872  return SCIP_OKAY;
8873 }
8874 
8875 /** sets number and values of all parameters in expression tree */
8877  SCIP_EXPRTREE* tree, /**< expression tree */
8878  int nparams, /**< number of parameters */
8879  SCIP_Real* paramvals /**< values of parameters, can be NULL if nparams == 0 */
8880  )
8881 {
8882  assert(tree != NULL);
8883  assert(paramvals != NULL || nparams == 0);
8884 
8885  if( nparams == 0 )
8886  {
8887  BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8888  }
8889  else if( tree->params != NULL )
8890  {
8891  SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8892  BMScopyMemoryArray(tree->params, paramvals, nparams);
8893  }
8894  else
8895  {
8896  SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8897  }
8898 
8899  tree->nparams = nparams;
8900  assert(tree->params != NULL || tree->nparams == 0);
8901 
8902  return SCIP_OKAY;
8903 }
8904 
8905 
8906 /** gives the number of usages for each variable in the expression tree */
8908  SCIP_EXPRTREE* tree, /**< expression tree */
8909  int* varsusage /**< array where to store for each variable how often it is used in the tree */
8910  )
8911 {
8912  assert(tree != NULL);
8913  assert(varsusage != NULL);
8914 
8915  if( tree->nvars == 0 )
8916  return;
8917 
8918  BMSclearMemoryArray(varsusage, tree->nvars);
8919  SCIPexprGetVarsUsage(tree->root, varsusage);
8920 }
8921 
8922 /** aims at simplifying an expression and splitting of a linear expression
8923  *
8924  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
8925  */
8927  SCIP_EXPRTREE* tree, /**< expression tree */
8928  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8929  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
8930  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8931  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8932  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8933  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
8934  )
8935 {
8936 #ifndef NDEBUG
8937  SCIP_RANDNUMGEN* randnumgen;
8938  SCIP_Real* testx;
8939  SCIP_Real testval_before;
8940  SCIP_Real testval_after;
8941  int i;
8942 #endif
8943 
8944  assert(tree != NULL);
8945 
8946 #ifndef NDEBUG
8947  SCIP_CALL( SCIPrandomCreate(&randnumgen, tree->blkmem, 42) );
8948 
8949  SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) ); /*lint !e666*/
8950  for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8951  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
8952  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8953 
8954  SCIPrandomFree(&randnumgen, tree->blkmem);
8955 #endif
8956 
8957  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8958  SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8959 
8960 #ifndef NDEBUG
8961  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8962  if( nlinvars != NULL && testval_before == testval_before ) /*lint !e777*/
8963  for( i = 0; i < *nlinvars; ++i )
8964  testval_after += lincoefs[i] * testx[linidxs[i]];
8965  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
8966  BMSfreeMemoryArray(&testx);
8967 #endif
8968 
8969  /* removing something from the the tree may invalidate the interpreter data */
8970  if( nlinvars != NULL && *nlinvars > 0 )
8972 
8973  return SCIP_OKAY;
8974 }
8975 
8976 /** adds an expression to the root expression of the tree
8977  *
8978  * The root is replaced with an SCIP_EXPR_PLUS expression which has the previous root and the given expression (or a copy of it) as children.
8979  */
8981  SCIP_EXPRTREE* tree, /**< expression tree */
8982  SCIP_EXPR* expr, /**< expression to add to tree */
8983  SCIP_Bool copyexpr /**< whether expression should be copied */
8984  )
8985 {
8986  assert(tree != NULL);
8987  assert(tree->root != 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  SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
8998 
8999  return SCIP_OKAY;
9000 }
9001 
9002 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
9004  SCIP_EXPRTREE* tree, /**< expression tree */
9005  SCIP_Real infinity, /**< value for infinity */
9006  SCIP_INTERVAL* varbounds, /**< domains of variables */
9007  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
9008  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression, or NULL if not needed */
9009  )
9010 {
9011  SCIP_INTERVAL exprbounds;
9012 
9013  assert(tree != NULL);
9014  assert(tree->root != NULL);
9015 
9016  SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
9017 
9018  if( bounds != NULL )
9019  *bounds = exprbounds;
9020 
9021  return SCIP_OKAY;
9022 }
9023 
9024 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
9025  *
9026  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL.
9027  * If substexprs[i] == NULL, then the variable expression i is not touched.
9028  */
9030  SCIP_EXPRTREE* tree, /**< expression tree */
9031  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
9032  )
9033 {
9034  assert(tree != NULL);
9035  assert(tree->root != NULL);
9036 
9037  if( tree->root->op == SCIP_EXPR_VARIDX )
9038  {
9039  int varidx;
9040 
9041  varidx = tree->root->data.intval;
9042  assert(varidx >= 0);
9043  if( substexprs[varidx] != NULL )
9044  {
9045  /* substitute root expression */
9046  SCIPexprFreeDeep(tree->blkmem, &tree->root);
9047  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
9048  }
9049  }
9050  else
9051  {
9052  /* check children (and grandchildren and so on...) of root expression */
9053  SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
9054  }
9055 
9056  /* substitution of variables should invalidate interpreter data */
9058 
9059  return SCIP_OKAY;
9060 }
9061 
9062 /**@} */
9063 
9064 /**@name Quadratic element methods */
9065 /**@{ */
9066 
9067 /** comparing two quadratic elements
9068  *
9069  * 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
9070  */
9071 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
9072 
9073 /** swaps two quadratic elements */
9074 #define QUADELEMS_SWAP(x,y) \
9075  { \
9076  SCIP_QUADELEM temp = x; \
9077  x = y; \
9078  y = temp; \
9079  }
9080 
9081 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
9082 static
9084  SCIP_QUADELEM* elems, /**< array to be sorted */
9085  int start, /**< starting index */
9086  int end /**< ending index */
9087  )
9088 {
9089  assert(start <= end);
9090 
9091  /* use quick sort for long lists */
9092  while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
9093  {
9094  SCIP_QUADELEM pivotkey;
9095  int lo;
9096  int hi;
9097  int mid;
9098 
9099  /* select pivot element */
9100  mid = (start+end)/2;
9101  pivotkey = elems[mid];
9102 
9103  /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
9104  lo = start;
9105  hi = end;
9106  for( ;; )
9107  {
9108  while( lo < end && QUADELEMS_ISBETTER(elems[lo], pivotkey) )
9109  lo++;
9110  while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
9111  hi--;
9112 
9113  if( lo >= hi )
9114  break;
9115 
9116  QUADELEMS_SWAP(elems[lo], elems[hi]);
9117 
9118  lo++;
9119  hi--;
9120  }
9121  assert(hi == lo-1 || hi == start);
9122 
9123  /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
9124  while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
9125  lo++;
9126 
9127  /* make sure that we have at least one element in the smaller partition */
9128  if( lo == start )
9129  {
9130  /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
9131  assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
9132  assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
9133  QUADELEMS_SWAP(elems[lo], elems[mid]);
9134  lo++;
9135  }
9136 
9137  /* sort the smaller partition by a recursive call, sort the larger part without recursion */
9138  if( hi - start <= end - lo )
9139  {
9140  /* sort [start,hi] with a recursive call */
9141  if( start < hi )
9142  quadelemsQuickSort(elems, start, hi);
9143 
9144  /* now focus on the larger part [lo,end] */
9145  start = lo;
9146  }
9147  else
9148  {
9149  /* sort [lo,end] with a recursive call */
9150  if( lo < end )
9151  quadelemsQuickSort(elems, lo, end);
9152 
9153  /* now focus on the larger part [start,hi] */
9154  end = hi;
9155  }
9156  }
9157 
9158  /* use shell sort on the remaining small list */
9159  if( end - start >= 1 )
9160  {
9161  static const int incs[3] = {1, 5, 19}; /* sequence of increments */
9162  int k;
9163 
9164  for( k = 2; k >= 0; --k )
9165  {
9166  int h;
9167  int i;
9168 
9169  for( h = incs[k], i = h + start; i <= end; ++i )
9170  {
9171  int j;
9172  SCIP_QUADELEM tempkey = elems[i];
9173 
9174  j = i;
9175  while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
9176  {
9177  elems[j] = elems[j-h];
9178  j -= h;
9179  }
9180 
9181  elems[j] = tempkey;
9182  }
9183  }
9184  }
9185 }
9186 
9187 /** sorts an array of quadratic elements
9188  *
9189  * The elements are sorted such that the first index is increasing and
9190  * such that among elements with the same first index, the second index is increasing.
9191  * For elements with same first and second index, the order is not defined.
9192  */
9194  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9195  int nquadelems /**< number of quadratic elements */
9196  )
9197 {
9198  if( nquadelems == 0 )
9199  return;
9200 
9201 #ifndef NDEBUG
9202  {
9203  int i;
9204  for( i = 0; i < nquadelems; ++i )
9205  assert(quadelems[i].idx1 <= quadelems[i].idx2);
9206  }
9207 #endif
9208 
9209  quadelemsQuickSort(quadelems, 0, nquadelems-1);
9210 }
9211 
9212 /** Finds an index pair in a sorted array of quadratic elements.
9213  *
9214  * If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
9215  * 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.
9216  * Assumes that idx1 <= idx2.
9217  */
9219  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9220  int idx1, /**< index of first variable in element to search for */
9221  int idx2, /**< index of second variable in element to search for */
9222  int nquadelems, /**< number of quadratic elements in array */
9223  int* pos /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
9224  )
9225 {
9226  int left;
9227  int right;
9228 
9229  assert(quadelems != NULL || nquadelems == 0);
9230  assert(idx1 <= idx2);
9231 
9232  if( nquadelems == 0 )
9233  {
9234  if( pos != NULL )
9235  *pos = 0;
9236  return FALSE;
9237  }
9238 
9239  left = 0;
9240  right = nquadelems - 1;
9241  while( left <= right )
9242  {
9243  int middle;
9244 
9245  middle = (left+right)/2;
9246  assert(0 <= middle && middle < nquadelems);
9247 
9248  if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) ) /*lint !e613*/
9249  right = middle - 1;
9250  else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) ) /*lint !e613*/
9251  left = middle + 1;
9252  else
9253  {
9254  if( pos != NULL )
9255  *pos = middle;
9256  return TRUE;
9257  }
9258  }
9259  assert(left == right+1);
9260 
9261  if( pos != NULL )
9262  *pos = left;
9263  return FALSE;
9264 }
9265 
9266 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
9267  *
9268  * Assumes that elements have been sorted before.
9269  */
9271  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9272  int nquadelems, /**< number of quadratic elements */
9273  int* nquadelemsnew /**< pointer to store new (reduced) number of quadratic elements */
9274  )
9275 {
9276  int i;
9277  int next;
9278 
9279  assert(quadelems != NULL);
9280  assert(nquadelemsnew != NULL);
9281  assert(nquadelems >= 0);
9282 
9283  i = 0;
9284  next = 0;
9285  while( next < nquadelems )
9286  {
9287  /* assert that array is sorted */
9288  assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
9289  (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
9290 
9291  /* skip elements with coefficient 0.0 */
9292  if( quadelems[next].coef == 0.0 )
9293  {
9294  ++next;
9295  continue;
9296  }
9297 
9298  /* if next element has same index as previous one, add it to the previous one */
9299  if( i >= 1 &&
9300  quadelems[i-1].idx1 == quadelems[next].idx1 &&
9301  quadelems[i-1].idx2 == quadelems[next].idx2 )
9302  {
9303  quadelems[i-1].coef += quadelems[next].coef;
9304  ++next;
9305  continue;
9306  }
9307 
9308  /* otherwise, move next element to current position */
9309  quadelems[i] = quadelems[next];
9310  ++i;
9311  ++next;
9312  }
9313  assert(next == nquadelems);
9314 
9315  /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
9316  *nquadelemsnew = i;
9317 }
9318 
9319 /**@} */
9320 
9321 /**@name Expression graph node private methods */
9322 /**@{ */
9323 
9324 /** adds a parent to an expression graph node */
9325 static
9327  BMS_BLKMEM* blkmem, /**< block memory */
9328  SCIP_EXPRGRAPHNODE* node, /**< expression graph node where to add a parent */
9329  SCIP_EXPRGRAPHNODE* parent /**< parent node */
9330  )
9331 {
9332  assert(blkmem != NULL);
9333  assert(node != NULL);
9334  assert(node->depth >= 0);
9335  assert(node->pos >= 0);
9336  assert(parent != NULL);
9337  assert(parent->depth >= 0);
9338  assert(parent->pos >= 0);
9339  assert(parent->depth > node->depth); /* a parent node need to have larger depth */
9340 
9341  ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
9342  assert(node->nparents < node->parentssize);
9343 
9344  node->parents[node->nparents] = parent;
9345  ++node->nparents;
9346 
9347  /* update sorted flag */
9348  node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (exprgraphnodecomp((void*)node->parents[node->nparents-2], (void*)parent) <= 0));
9349 
9350  return SCIP_OKAY;
9351 }
9352 
9353 /** ensures that array of parents in a node is sorted */
9354 static
9356  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
9357  )
9358 {
9359  assert(node != NULL);
9360 
9361  if( node->parentssorted )
9362  {
9363 #ifndef NDEBUG
9364  int i;
9365  for( i = 1; i < node->nparents; ++i )
9366  assert(exprgraphnodecomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
9367 #endif
9368  return;
9369  }
9370 
9371  SCIPsortPtr((void**)node->parents, exprgraphnodecomp, node->nparents);
9372 
9373  node->parentssorted = TRUE;
9374 }
9375 
9376 /** removes a parent from an expression graph node
9377  *
9378  * If the node is not used and has no other parents, then it is freed.
9379  */
9380 static
9382  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9383  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to remove a parent, *node will be set to NULL */
9384  SCIP_EXPRGRAPHNODE* parent /**< parent node to remove */
9385  )
9386 {
9387  SCIP_EXPRGRAPHNODE* node_;
9388  int pos;
9389 
9390  assert(exprgraph != NULL);
9391  assert(node != NULL);
9392  assert(*node != NULL);
9393  assert((*node)->depth >= 0);
9394  assert((*node)->pos >= 0);
9395  assert((*node)->nparents > 0);
9396  assert(parent != NULL);
9397  assert(parent->depth >= 0);
9398  assert(parent->pos >= 0);
9399  assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
9400 
9401  /* find parent */
9402  exprgraphNodeSortParents(*node);
9403  (void) SCIPsortedvecFindPtr((void**)(*node)->parents, exprgraphnodecomp, (void*)parent, (*node)->nparents, &pos);
9404  assert(pos >= 0);
9405  assert(pos < (*node)->nparents);
9406  assert((*node)->parents[pos] == parent);
9407 
9408  /* move last parent to pos, if pos is before last
9409  * update sorted flag */
9410  if( pos < (*node)->nparents-1 )
9411  {
9412  (*node)->parents[pos] = (*node)->parents[(*node)->nparents-1];
9413  (*node)->parentssorted = ((*node)->nparents <= 2);
9414  }
9415  --(*node)->nparents;
9416 
9417  /* keep pointer to *node in case it is still used */
9418  node_ = (*node)->nuses > 0 ? *node : NULL;
9419 
9420  /* capture and release node so it is freed if possible */
9421  SCIPexprgraphCaptureNode(*node);
9422  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
9423 
9424  /* restore pointer, if node still exists */
9425  *node = node_;
9426 
9427  return SCIP_OKAY;
9428 }
9429 
9430 /** checks if a node is parent of a node */
9431 static
9433  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9434  SCIP_EXPRGRAPHNODE* parent /**< parent to look for */
9435  )
9436 {
9437  int pos;
9438 
9439  assert(node != NULL);
9440  assert(parent != NULL);
9441 
9442  /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
9443  if( node->depth >= parent->depth || node->nparents == 0 )
9444  return FALSE;
9445  assert(node->parents != NULL);
9446 
9447  /* ensure parents array is sorted */
9449 
9450  return SCIPsortedvecFindPtr((void**)node->parents, exprgraphnodecomp, (void*)parent, node->nparents, &pos);
9451 }
9452 
9453 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
9454  *
9455  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
9456  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
9457  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
9458  *
9459  * It is assumed that node and all exprs are in the expression graph already.
9460  * It is assumed that all expressions that are added have lower depth than node.
9461  */
9462 static
9464  BMS_BLKMEM* blkmem, /**< block memory */
9465  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9466  int nexprs, /**< number of children to add */
9467  SCIP_EXPRGRAPHNODE** exprs, /**< children nodes to add */
9468  int* childmap /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
9469  )
9470 {
9471  int i;
9472  int j;
9473  int orignchildren;
9474  SCIP_Bool existsalready;
9475 
9476  assert(blkmem != NULL);
9477  assert(node != NULL);
9478  assert(node->depth > 0);
9479  assert(node->pos >= 0);
9480  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);
9481  assert(exprs != NULL || nexprs == 0);
9482 
9483  if( nexprs == 0 )
9484  return SCIP_OKAY;
9485 
9486  orignchildren = node->nchildren;
9487  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
9488 
9489  for( i = 0; i < nexprs; ++i )
9490  {
9491  assert(exprs[i]->depth >= 0); /*lint !e613*/
9492  assert(exprs[i]->pos >= 0); /*lint !e613*/
9493  assert(exprs[i]->depth < node->depth); /*lint !e613*/
9494 
9495  /* check if exprs[i] is a child already, if not SUM or PRODUCT */
9496  existsalready = FALSE;
9497  if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
9498  for( j = 0; j < orignchildren; ++j )
9499  /* during simplification of polynomials, their may be NULL's in children array */
9500  if( node->children[j] != NULL && node->children[j] == exprs[i] ) /*lint !e613*/
9501  {
9502  existsalready = TRUE;
9503  break;
9504  }
9505 
9506  if( !existsalready )
9507  {
9508  /* add exprs[i] to children array */
9509  node->children[node->nchildren] = exprs[i]; /*lint !e613*/
9510  SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) ); /*lint !e613*/
9511  if( childmap != NULL )
9512  childmap[i] = node->nchildren;
9513  ++node->nchildren;
9514  }
9515  else
9516  {
9517  if( childmap != NULL )
9518  childmap[i] = j; /*lint !e644*/
9519  if( node->op == SCIP_EXPR_LINEAR )
9520  {
9521  /* if linear expression, increase coefficient by 1.0 */
9522  ((SCIP_Real*)node->data.data)[j] += 1.0;
9523  }
9524  }
9525  }
9526 
9527  /* shrink children array to actually used size */
9528  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
9529 
9530  if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
9531  {
9532  /* if linear expression, then add 1.0 coefficients for new expressions */
9533  SCIP_Real* data;
9534 
9535  data = (SCIP_Real*)node->data.data;
9536  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
9537  data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
9538  for( i = orignchildren; i < node->nchildren; ++i )
9539  data[i] = 1.0;
9540  node->data.data = (void*)data;
9541  }
9542  else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
9543  {
9544  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
9546 
9547  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9548  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
9549  BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren); /*lint !e866*/
9550  }
9551 
9552  node->simplified = FALSE;
9553 
9554  return SCIP_OKAY;
9555 }
9556 
9557 /** replaces a child node by another node
9558  *
9559  * Assumes that both nodes represent the same expression.
9560  * If this node was the last parent of oldchild and oldchild is not in use, then it is freed.
9561  * newchild must have deeper depth than node.
9562  */
9563 static
9565  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9566  SCIP_EXPRGRAPHNODE* node, /**< pointer to expression graph node */
9567  SCIP_EXPRGRAPHNODE** oldchild, /**< child node that should be replaced, it may be freed */
9568  SCIP_EXPRGRAPHNODE* newchild /**< node that should take position of oldchild */
9569  )
9570 {
9571  int i;
9572 
9573  assert(exprgraph != NULL);
9574  assert(node != NULL);
9575  assert(oldchild != NULL);
9576  assert(*oldchild != NULL);
9577  assert(newchild != NULL);
9578 
9579  if( *oldchild == newchild )
9580  return SCIP_OKAY;
9581 
9582  SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
9583 
9584  /* search for oldchild in children array */
9585  for( i = 0; i < node->nchildren; ++i )
9586  {
9587  if( node->children[i] == *oldchild )
9588  {
9589  /* add as parent to newchild */
9590  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
9591 
9592  /* remove as parent from oldchild */
9593  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
9594 
9595  /* set newchild as child i */
9596  node->children[i] = newchild;
9597 
9598  /* we're done */
9599  break;
9600  }
9601  }
9602  assert(i < node->nchildren); /* assert that oldchild has been found in children array */
9603 
9604  node->simplified = FALSE;
9605 
9606  return SCIP_OKAY;
9607 }
9608 
9609 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
9610  *
9611  * A node is larger than another node, if their corresponding constants are related that way.
9612  */
9613 static
9614 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
9615 {
9616  assert(elem1 != NULL);
9617  assert(elem2 != NULL);
9618  assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
9619  assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
9620  assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9621  assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9622 
9623  if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9624  return 1;
9625  else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9626  return -1;
9627  else
9628  return 0;
9629 }
9630 
9631 /** sort array of nodes that holds constants */
9632 static
9634  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
9635  )
9636 {
9637  assert(exprgraph != NULL);
9638 
9639  if( exprgraph->constssorted )
9640  return;
9641 
9642  SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
9643 
9644  exprgraph->constssorted = TRUE;
9645 }
9646 
9647 /** finds position of expression graph node corresponding to a constant in constnodes array */
9648 static
9650  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9651  SCIP_EXPRGRAPHNODE* node, /**< node to search for */
9652  int* pos /**< buffer to store position of node, if found */
9653  )
9654 {
9655  int left;
9656  int right;
9657  int middle;
9658 
9659  assert(exprgraph != NULL);
9660  assert(node != NULL);
9661  assert(node->op == SCIP_EXPR_CONST);
9662  assert(node->depth == 0);
9663  assert(node->pos >= 0);
9664  assert(pos != NULL);
9665 
9666  exprgraphSortConstNodes(exprgraph);
9667  assert(exprgraph->constssorted);
9668 
9669  /* find a node with constant node->data.dbl using binary search */
9670  left = 0;
9671  right = exprgraph->nconsts-1;
9672  *pos = -1;
9673  while( left <= right )
9674  {
9675  middle = (left+right)/2;
9676  assert(0 <= middle && middle < exprgraph->nconsts);
9677 
9678  if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9679  right = middle - 1;
9680  else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9681  left = middle + 1;
9682  else
9683  {
9684  *pos = middle;
9685  break;
9686  }
9687  }
9688  assert(left == right+1 || *pos >= 0);
9689  if( left == right+1 )
9690  return FALSE;
9691 
9692  /* search left of *pos to find node */
9693  while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl ) /*lint !e777*/
9694  --*pos;
9695  /* search right of *pos to find node */
9696  while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl ) /*lint !e777*/
9697  ++*pos;
9698 
9699  return exprgraph->constnodes[*pos] == node;
9700 }
9701 
9702 /** creates an expression graph node */
9703 static
9705  BMS_BLKMEM* blkmem, /**< block memory */
9706  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
9707  SCIP_EXPROP op, /**< operator type of expression */
9708  SCIP_EXPROPDATA opdata /**< operator data of expression */
9709  )
9710 {
9711  assert(blkmem != NULL);
9712  assert(node != NULL);
9713 
9714  SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9715  BMSclearMemory(*node);
9716 
9717  (*node)->op = op;
9718  (*node)->data = opdata;
9719 
9720  /* mark graph position as not in graph yet */
9721  (*node)->depth = -1;
9722  (*node)->pos = -1;
9723 
9724  /* arrays of length 0 are trivially sorted */
9725  (*node)->parentssorted = TRUE;
9726 
9727  /* set bounds interval to entire */
9728  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9729  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9730 
9731  /* set initial value to invalid */
9732  (*node)->value = SCIP_INVALID;
9733 
9734  /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9735  if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9736  (*node)->curv = SCIP_EXPRCURV_LINEAR;
9737  else
9738  (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9739 
9740  /* per default, a node is enabled */
9741  (*node)->enabled = TRUE;
9742 
9743  return SCIP_OKAY;
9744 }
9745 
9746 /** prints the expression corresponding to a node (not recursively) */
9747 static
9749  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9750  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9751  FILE* file, /**< file to print to, or NULL for stdout */
9752  const char** varnames, /**< variable names, or NULL for generic names */
9753  SCIP_Bool printchildrenbounds /**< whether to print bounds of children */
9754  )
9755 {
9756  int i;
9757 
9758  assert(node != NULL);
9759 
9760  switch( node->op )
9761  {
9762  case SCIP_EXPR_VARIDX:
9763  if( varnames != NULL )
9764  {
9765  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9766  }
9767  else
9768  SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9769  break;
9770 
9771  case SCIP_EXPR_CONST:
9772  SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9773  break;
9774 
9775  case SCIP_EXPR_PARAM:
9776  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9777  break;
9778 
9779  case SCIP_EXPR_PLUS:
9780  if( printchildrenbounds )
9781  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9782  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9783  if( printchildrenbounds )
9784  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9785  break;
9786 
9787  case SCIP_EXPR_MINUS:
9788  if( printchildrenbounds )
9789  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9790  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9791  if( printchildrenbounds )
9792  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9793  break;
9794 
9795  case SCIP_EXPR_MUL:
9796  if( printchildrenbounds )
9797  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9798  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9799  if( printchildrenbounds )
9800  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9801  break;
9802 
9803  case SCIP_EXPR_DIV:
9804  if( printchildrenbounds )
9805  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9806  SCIPmessageFPrintInfo(messagehdlr, file, "/");
9807  if( printchildrenbounds )
9808  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9809  break;
9810 
9811  case SCIP_EXPR_SQUARE:
9812  if( printchildrenbounds )
9813  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9814  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9815  break;
9816 
9817  case SCIP_EXPR_REALPOWER:
9818  if( printchildrenbounds )
9819  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9820  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9821  break;
9822 
9823  case SCIP_EXPR_SIGNPOWER:
9824  if( printchildrenbounds )
9825  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9826  node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9827  else
9828  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9829  break;
9830 
9831  case SCIP_EXPR_INTPOWER:
9832  SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9833  if( printchildrenbounds )
9834  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9835  SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9836  break;
9837 
9838  case SCIP_EXPR_SQRT:
9839  case SCIP_EXPR_EXP:
9840  case SCIP_EXPR_LOG:
9841  case SCIP_EXPR_SIN:
9842  case SCIP_EXPR_COS:
9843  case SCIP_EXPR_TAN:
9844  /* SCIP_EXPR_ERF = 20, */ /**< gaussian error function (1 operand) */
9845  /* SCIP_EXPR_ERFI = 21, */ /**< imaginary part of gaussian error function (1 operand) */
9846  case SCIP_EXPR_MIN:
9847  case SCIP_EXPR_MAX:
9848  case SCIP_EXPR_ABS:
9849  case SCIP_EXPR_SIGN:
9850  SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9851  if( printchildrenbounds )
9852  {
9853  SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9854  if( node->nchildren == 2 )
9855  SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9856  SCIPmessageFPrintInfo(messagehdlr, file, ")");
9857  }
9858  break;
9859 
9860  case SCIP_EXPR_SUM:
9861  if( printchildrenbounds )
9862  for( i = 0; i < node->nchildren; ++i )
9863  {
9864  if( i > 0 )
9865  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9866  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9867  }
9868  else
9869  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9870  break;
9871 
9872  case SCIP_EXPR_PRODUCT:
9873  if( printchildrenbounds )
9874  for( i = 0; i < node->nchildren; ++i )
9875  {
9876  if( i > 0 )
9877  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9878  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9879  }
9880  else
9881  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9882  break;
9883 
9884  case SCIP_EXPR_LINEAR:
9885  {
9886  SCIP_Real constant;
9887 
9888  constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9889 
9890  if( constant != 0.0 || node->nchildren == 0 )
9891  SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9892 
9893  for( i = 0; i < node->nchildren; ++i )
9894  {
9895  if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9896  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9897  else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9898  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9899  else
9900  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9901  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9902  if( printchildrenbounds )
9903  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9904  }
9905 
9906  break;
9907  }
9908 
9909  case SCIP_EXPR_QUADRATIC:
9910  {
9911  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9912 
9913  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9914  assert(quadraticdata != NULL);
9915 
9916  if( quadraticdata->constant != 0.0 )
9917  SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9918 
9919  if( quadraticdata->lincoefs != NULL )
9920  for( i = 0; i < node->nchildren; ++i )
9921  {
9922  if( quadraticdata->lincoefs[i] == 0.0 )
9923  continue;
9924  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9925  if( printchildrenbounds )
9926  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9927  }
9928 
9929  for( i = 0; i < quadraticdata->nquadelems; ++i )
9930  {
9931  if( quadraticdata->quadelems[i].coef == 1.0 )
9932  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9933  else if( quadraticdata->quadelems[i].coef == -1.0 )
9934  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9935  else
9936  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9937  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9938  if( printchildrenbounds )
9939  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9940  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9941  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9942  else
9943  {
9944  SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9945  if( printchildrenbounds )
9946  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9947  }
9948  }
9949 
9950  break;
9951  }
9952 
9953  case SCIP_EXPR_POLYNOMIAL:
9954  {
9955  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9956  SCIP_EXPRDATA_MONOMIAL* monomialdata;
9957  int j;
9958 
9959  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9960  assert(polynomialdata != NULL);
9961 
9962  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
9963  {
9964  SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
9965  }
9966 
9967  for( i = 0; i < polynomialdata->nmonomials; ++i )
9968  {
9969  monomialdata = polynomialdata->monomials[i];
9970  if( monomialdata->coef == 1.0 )
9971  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9972  else if( monomialdata->coef == -1.0 )
9973  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9974  else
9975  SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
9976 
9977  for( j = 0; j < monomialdata->nfactors; ++j )
9978  {
9979  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
9980  if( printchildrenbounds )
9981  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
9982  if( monomialdata->exponents[j] < 0.0 )
9983  SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
9984  else if( monomialdata->exponents[j] != 1.0 )
9985  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
9986  }
9987  }
9988 
9989  break;
9990  }
9991 
9992  case SCIP_EXPR_LAST:
9993  SCIPABORT();
9994  break;
9995 
9996  default:
9997  SCIPmessageFPrintInfo(messagehdlr, file, "%s", SCIPexpropGetName(node->op));
9998  break;
9999  } /*lint !e788*/
10000 }
10001 
10002 /** prints a node of an expression graph */
10003 static
10005  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10006  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10007  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
10008  FILE* file, /**< file to print to, or NULL for stdout */
10009  const char** varnames /**< variable names, or NULL for generic names */
10010  )
10011 {
10012  SCIP_Real color;
10013  int i;
10014 
10015  assert(exprgraph != NULL);
10016  assert(node != NULL);
10017  assert(file != NULL);
10018 
10019  color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
10020  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
10021 
10022  exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
10023 
10024  SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
10026  SCIPmessageFPrintInfo(messagehdlr, file, "!");
10028  SCIPmessageFPrintInfo(messagehdlr, file, "*");
10030  SCIPmessageFPrintInfo(messagehdlr, file, "+");
10031 
10032  SCIPmessageFPrintInfo(messagehdlr, file, "\"");
10033 
10034  if( !node->enabled )
10035  SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
10036 
10037  SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
10038 
10039  /* add edges from node to children */
10040  for( i = 0; i < node->nchildren; ++i )
10041  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);
10042 }
10043 
10044 /** evaluate node of expression graph w.r.t. values stored in children */
10045 static
10047  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10048  SCIP_Real* varvals /**< values for variables */
10049  )
10050 {
10051  int i;
10053  SCIP_Real* buf;
10054 
10055  assert(node != NULL);
10056 
10057  /* if many children, get large enough memory to store argument values */
10059  {
10060  SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
10061  }
10062  else
10063  {
10064  buf = staticbuf;
10065  }
10066 
10067  /* get values of children */
10068  for( i = 0; i < node->nchildren; ++i )
10069  {
10070  assert(node->children[i]->value != SCIP_INVALID); /*lint !e777*/
10071  buf[i] = node->children[i]->value; /*lint !e644*/
10072  }
10073 
10074  /* evaluate this expression */
10075  assert(exprOpTable[node->op].eval != NULL);
10076  SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
10077  assert(node->value != SCIP_INVALID); /*lint !e777*/
10078 
10079  /* free memory, if allocated before */
10080  if( staticbuf != buf )
10081  {
10082  BMSfreeMemoryArray(&buf);
10083  }
10084 
10085  return SCIP_OKAY;
10086 }
10087 
10088 /** evaluates node including subtree */
10089 static
10091  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10092  SCIP_Real* varvals /**< values for variables */
10093  )
10094 {
10095  int i;
10096 
10097  assert(node != NULL);
10098 
10099  for( i = 0; i < node->nchildren; ++i )
10100  {
10101  SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
10102  }
10103 
10104  SCIP_CALL( exprgraphNodeEval(node, varvals) );
10105 
10106  return SCIP_OKAY;
10107 }
10108 
10109 /** updates bounds of a node if a children has changed its bounds */
10110 static
10112  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10113  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10114  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
10115  SCIP_Bool parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
10116  )
10117 {
10118  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
10119  SCIP_INTERVAL* childbounds;
10120  SCIP_INTERVAL newbounds;
10121  int i;
10122 
10123  assert(node != NULL);
10124  assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
10125  assert(node->pos >= 0); /* node should be in graph */
10126  assert(node->op != SCIP_EXPR_VARIDX);
10127  assert(node->op != SCIP_EXPR_PARAM);
10128 
10129  /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
10130  * if node is disabled, then also do nothing */
10131  if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
10132  return SCIP_OKAY;
10133 
10134  /* if many children, get large enough memory to store children bounds */
10136  {
10137  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
10138  }
10139  else
10140  {
10141  childbounds = childboundsstatic;
10142  }
10143 
10144  /* assemble bounds of children */
10145  for( i = 0; i < node->nchildren; ++i )
10146  {
10147  /* child should have valid and non-empty bounds */
10149  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10150 
10151  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
10152  }
10153 
10154  /* call interval evaluation function for this operand */
10155  assert( exprOpTable[node->op].inteval != NULL );
10156  SCIPintervalSet(&newbounds, 0.0);
10157  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
10158 
10159  /* free memory, if allocated before */
10160  if( childbounds != childboundsstatic )
10161  {
10162  BMSfreeMemoryArray(&childbounds);
10163  }
10164 
10165  /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
10166 
10167  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
10168  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
10169  *
10170  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
10171  *
10172  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
10173  */
10174  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
10175  ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
10176  {
10177  for( i = 0; i < node->nparents; ++i )
10179 
10180  node->bounds = newbounds;
10181  }
10182  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
10183  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
10184  {
10185  for( i = 0; i < node->nparents; ++i )
10187 
10188  node->bounds = newbounds;
10189  }
10190  else
10191  {
10192  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
10193  }
10194 
10195  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);
10196 
10197  /* node now has valid bounds */
10198  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
10199 
10200  return SCIP_OKAY;
10201 }
10202 
10203 /** propagate bounds of a node into children by reverting the nodes expression */
10204 static
10206  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10207  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
10208  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10209  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
10210  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
10211  )
10212 {
10213  SCIP_INTERVAL childbounds;
10214  int i;
10215 
10216  assert(exprgraph != NULL);
10217  assert(node != NULL);
10218  assert(node->depth >= 0); /* node should be in graph */
10219  assert(node->pos >= 0); /* node should be in graph */
10220  assert(minstrength >= 0.0);
10221  assert(cutoff != NULL);
10222  assert(!SCIPintervalIsEmpty(infinity, node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
10223  assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
10224 
10225  /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
10227  return;
10228 
10229  /* if node is not enabled, then do nothing */
10230  if( !node->enabled )
10231  return;
10232 
10233  /* tell children that they should propagate their bounds even if not tightened */
10235  minstrength = -1.0;
10236 
10237  /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
10239 
10240  /* 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);
10241  * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10242  * SCIPdebugPrintf("\n");
10243  */
10244 
10245  /* @todo add callback to exprOpTable for this */
10246 
10247  switch( node->op )
10248  {
10249  case SCIP_EXPR_VARIDX:
10250  case SCIP_EXPR_CONST:
10251  case SCIP_EXPR_PARAM:
10252  /* cannot propagate bound changes further */
10253  break;
10254 
10255  case SCIP_EXPR_PLUS:
10256  {
10257  assert(node->nchildren == 2);
10258  /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
10259 
10260  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10261  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10262 
10263  if( *cutoff )
10264  break;
10265 
10266  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10267  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10268 
10269  break;
10270  }
10271 
10272  case SCIP_EXPR_MINUS:
10273  {
10274  assert(node->nchildren == 2);
10275  /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
10276 
10277  SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10278  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10279 
10280  if( *cutoff )
10281  break;
10282 
10283  SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10284  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10285 
10286  break;
10287  }
10288 
10289  case SCIP_EXPR_MUL:
10290  {
10291  assert(node->nchildren == 2);
10292  /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
10293 
10294  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10295  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10296 
10297  if( *cutoff )
10298  break;
10299 
10300  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10301  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10302 
10303  break;
10304  }
10305 
10306  case SCIP_EXPR_DIV:
10307  {
10308  assert(node->nchildren == 2);
10309  /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
10310 
10311  SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10312  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10313 
10314  if( *cutoff )
10315  break;
10316 
10317  SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10318  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10319 
10320  break;
10321  }
10322 
10323  case SCIP_EXPR_SQUARE:
10324  {
10325  assert(node->nchildren == 1);
10326  /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
10327 
10328  if( node->bounds.sup < 0.0 )
10329  {
10330  *cutoff = TRUE;
10331  break;
10332  }
10333 
10334  SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
10335  if( node->children[0]->bounds.inf <= -childbounds.inf )
10336  SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
10337  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10338 
10339  break;
10340  }
10341 
10342  case SCIP_EXPR_SQRT:
10343  {
10344  assert(node->nchildren == 1);
10345  /* f = sqrt(c0) -> c0 = f^2 */
10346 
10347  SCIPintervalSquare(infinity, &childbounds, node->bounds);
10348  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10349 
10350  break;
10351  }
10352 
10353  case SCIP_EXPR_REALPOWER:
10354  {
10355  assert(node->nchildren == 1);
10356 
10357  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
10358 
10359  if( SCIPintervalIsEmpty(infinity, childbounds) )
10360  {
10361  *cutoff = TRUE;
10362  break;
10363  }
10364  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10365 
10366  break;
10367  }
10368 
10369  case SCIP_EXPR_SIGNPOWER:
10370  {
10371  assert(node->nchildren == 1);
10372 
10373  if( node->data.dbl != 0.0 )
10374  {
10375  SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
10376  }
10377  else
10378  {
10379  /* behaves like SCIP_EXPR_SIGN */
10380  SCIPintervalSetBounds(&childbounds,
10381  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10382  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10383  }
10384 
10385  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10386 
10387  break;
10388  }
10389 
10390  case SCIP_EXPR_INTPOWER:
10391  {
10392  assert(node->nchildren == 1);
10393 
10394  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
10395 
10396  if( SCIPintervalIsEmpty(infinity, childbounds) )
10397  {
10398  *cutoff = TRUE;
10399  break;
10400  }
10401  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10402 
10403  break;
10404  }
10405 
10406  case SCIP_EXPR_EXP:
10407  {
10408  assert(node->nchildren == 1);
10409  /* f = exp(c0) -> c0 = log(f) */
10410 
10411  if( node->bounds.sup < 0.0 )
10412  {
10413  *cutoff = TRUE;
10414  break;
10415  }
10416 
10417  SCIPintervalLog(infinity, &childbounds, node->bounds);
10418  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10419 
10420  break;
10421  }
10422 
10423  case SCIP_EXPR_LOG:
10424  {
10425  assert(node->nchildren == 1);
10426  /* f = log(c0) -> c0 = exp(f) */
10427 
10428  SCIPintervalExp(infinity, &childbounds, node->bounds);
10429  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10430 
10431  break;
10432  }
10433 
10434  case SCIP_EXPR_SIN:
10435  case SCIP_EXPR_COS:
10436  case SCIP_EXPR_TAN:
10437  /* case SCIP_EXPR_ERF: */
10438  /* case SCIP_EXPR_ERFI: */
10439  {
10440  assert(node->nchildren == 1);
10441 
10442  /* @todo implement */
10443 
10444  break;
10445  }
10446 
10447  case SCIP_EXPR_ABS:
10448  {
10449  assert(node->nchildren == 1);
10450 
10451  /* use identity if child bounds are non-negative */
10452  if( node->children[0]->bounds.inf >= 0 )
10453  {
10454  SCIPintervalSetBounds(&childbounds, node->bounds.inf, node->bounds.sup);
10455  }
10456  /* use -identity if child bounds are non-positive */
10457  else if( node->children[0]->bounds.sup <= 0 )
10458  {
10459  assert(node->bounds.inf <= node->bounds.sup);
10460  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, -node->bounds.inf);
10461  }
10462  /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
10463  else
10464  {
10465  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
10466  }
10467 
10468  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10469 
10470  break;
10471  }
10472 
10473  case SCIP_EXPR_SIGN:
10474  {
10475  assert(node->nchildren == 1);
10476  /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
10477 
10478  SCIPintervalSetBounds(&childbounds,
10479  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10480  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10481  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10482 
10483  break;
10484  }
10485 
10486  case SCIP_EXPR_MIN:
10487  {
10488  assert(node->nchildren == 2);
10489  /* f = min(c0,c1) -> f <= c0, f <= c1
10490  * if c1 > f -> c0 = f
10491  * if c0 > f -> c1 = f
10492  */
10493 
10494  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10495  node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10496  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10497 
10498  if( *cutoff )
10499  break;
10500 
10501  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10502  node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10503  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10504 
10505  break;
10506  }
10507 
10508  case SCIP_EXPR_MAX:
10509  {
10510  assert(node->nchildren == 2);
10511  /* f = max(c0, c1) -> f >= c0, f >= c1
10512  * if c1 < f -> c0 = f
10513  * if c0 < f -> c1 = f
10514  */
10515 
10516  SCIPintervalSetBounds(&childbounds,
10517  node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10518  node->bounds.sup);
10519  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10520 
10521  SCIPintervalSetBounds(&childbounds,
10522  node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10523  node->bounds.sup);
10524  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10525 
10526  break;
10527  }
10528 
10529  case SCIP_EXPR_SUM:
10530  {
10531  SCIP_ROUNDMODE prevroundmode;
10532 
10533  /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
10534 
10535  SCIP_Real minlinactivity;
10536  SCIP_Real maxlinactivity;
10537  int minlinactivityinf;
10538  int maxlinactivityinf;
10539 
10540  if( node->nchildren == 0 )
10541  break;
10542 
10543  if( SCIPintervalIsEntire(infinity, node->bounds) )
10544  break;
10545 
10546  minlinactivity = 0.0;
10547  maxlinactivity = 0.0;
10548  minlinactivityinf = 0;
10549  maxlinactivityinf = 0;
10550 
10551  prevroundmode = SCIPintervalGetRoundingMode();
10553 
10554  for( i = 0; i < node->nchildren; ++i )
10555  {
10556  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10557 
10558  /* minimal activity is only useful if node has a finite upper bound */
10559  if( node->bounds.sup < infinity )
10560  {
10561  if( node->children[i]->bounds.inf <= -infinity )
10562  {
10563  ++minlinactivityinf;
10564  }
10565  else
10566  {
10567  assert(node->children[i]->bounds.inf < infinity);
10568  minlinactivity += node->children[i]->bounds.inf;
10569  }
10570  }
10571 
10572  /* maximal activity is only useful if node has a finite lower bound
10573  * we compute negated maximal activity here so we can keep downward rounding
10574  */
10575  if( node->bounds.inf > -infinity )
10576  {
10577  if( node->children[i]->bounds.sup >= infinity )
10578  {
10579  ++maxlinactivityinf;
10580  }
10581  else
10582  {
10583  assert(node->children[i]->bounds.sup > -infinity);
10584  maxlinactivity -= node->children[i]->bounds.sup;
10585  }
10586  }
10587  }
10588  maxlinactivity = -maxlinactivity; /* correct sign */
10589 
10590  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10591  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10592  ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10593  )
10594  {
10595  SCIPintervalSetRoundingMode(prevroundmode);
10596  break;
10597  }
10598 
10599  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10600  {
10601  /* upper bounds of c_i is
10602  * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
10603  * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
10604  */
10605  SCIPintervalSetEntire(infinity, &childbounds);
10606  if( node->bounds.sup < infinity )
10607  {
10608  /* we are still in downward rounding mode, so negate and negate to get upward rounding */
10609  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10610  {
10611  assert(minlinactivityinf == 1);
10612  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
10613  }
10614  else if( minlinactivityinf == 0 )
10615  {
10616  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
10617  }
10618  }
10619 
10620  /* lower bounds of c_i is
10621  * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
10622  * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
10623  */
10624  if( node->bounds.inf > -infinity )
10625  {
10626  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10627  {
10628  assert(maxlinactivityinf == 1);
10629  childbounds.inf = node->bounds.inf - maxlinactivity;
10630  }
10631  else if( maxlinactivityinf == 0 )
10632  {
10633  childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
10634  }
10635  }
10636 
10637  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10638  }
10639 
10640  SCIPintervalSetRoundingMode(prevroundmode);
10641 
10642  break;
10643  }
10644 
10645  case SCIP_EXPR_PRODUCT:
10646  {
10647  int j;
10648  /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
10649 
10650  /* too expensive (runtime here is quadratic in number of children) */
10651  if( node->nchildren > 10 )
10652  break;
10653 
10654  /* useless */
10655  if( SCIPintervalIsEntire(infinity, node->bounds) )
10656  break;
10657 
10658  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10659  {
10660  /* compute prod_{j:j!=i} c_j */
10661  SCIPintervalSet(&childbounds, 1.0);
10662  for( j = 0; j < node->nchildren; ++j )
10663  {
10664  if( i == j )
10665  continue;
10666  SCIPintervalMul(infinity, &childbounds, childbounds, node->children[j]->bounds);
10667 
10668  /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
10669  if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
10670  break;
10671  }
10672 
10673  if( j == node->nchildren )
10674  {
10675  SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
10676  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10677  }
10678  }
10679 
10680  break;
10681  }
10682 
10683  case SCIP_EXPR_LINEAR:
10684  {
10685  SCIP_ROUNDMODE prevroundmode;
10686  SCIP_Real* coefs;
10687 
10688  /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10689 
10690  SCIP_Real minlinactivity;
10691  SCIP_Real maxlinactivity;
10692  int minlinactivityinf;
10693  int maxlinactivityinf;
10694 
10695  if( node->nchildren == 0 )
10696  break;
10697 
10698  if( SCIPintervalIsEntire(infinity, node->bounds) )
10699  break;
10700 
10701  coefs = (SCIP_Real*)node->data.data;
10702 
10703  minlinactivity = coefs[node->nchildren];
10704  maxlinactivity = -coefs[node->nchildren];
10705  minlinactivityinf = 0;
10706  maxlinactivityinf = 0;
10707 
10708  prevroundmode = SCIPintervalGetRoundingMode();
10710 
10711  for( i = 0; i < node->nchildren; ++i )
10712  {
10713  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10714 
10715  /* minimal activity is only useful if node has a finite upper bound */
10716  if( node->bounds.sup < infinity )
10717  {
10718  if( coefs[i] >= 0.0 )
10719  {
10720  if( node->children[i]->bounds.inf <= -infinity )
10721  {
10722  ++minlinactivityinf;
10723  }
10724  else
10725  {
10726  assert(node->children[i]->bounds.inf < infinity);
10727  minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10728  }
10729  }
10730  else
10731  {
10732  if( node->children[i]->bounds.sup >= infinity )
10733  {
10734  ++minlinactivityinf;
10735  }
10736  else
10737  {
10738  assert(node->children[i]->bounds.sup > -infinity);
10739  minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10740  }
10741  }
10742  }
10743 
10744  /* maximal activity is only useful if node has a finite lower bound
10745  * we compute negated maximal activity here so we can keep downward rounding
10746  */
10747  if( node->bounds.inf > -infinity )
10748  {
10749  if( coefs[i] >= 0.0 )
10750  {
10751  if( node->children[i]->bounds.sup >= infinity )
10752  {
10753  ++maxlinactivityinf;
10754  }
10755  else
10756  {
10757  assert(node->children[i]->bounds.sup > -infinity);
10758  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.sup;
10759  }
10760  }
10761  else
10762  {
10763  if( node->children[i]->bounds.inf <= -infinity )
10764  {
10765  ++maxlinactivityinf;
10766  }
10767  else
10768  {
10769  assert(node->children[i]->bounds.inf < infinity);
10770  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.inf;
10771  }
10772  }
10773  }
10774  }
10775  maxlinactivity = SCIPintervalNegateReal(maxlinactivity); /* correct sign */
10776 
10777  /* SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]; bounds = [%10g,%10g]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf, node->bounds.inf, node->bounds.sup); */
10778 
10779  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10780  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10781  (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10782  )
10783  {
10784  SCIPintervalSetRoundingMode(prevroundmode);
10785  break;
10786  }
10787 
10788  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10789  {
10790  SCIP_INTERVAL ac;
10791 
10792  if( coefs[i] == 0.0 )
10793  continue;
10794 
10795  /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10796  SCIPintervalSet(&ac, 0.0);
10797  if( coefs[i] >= 0.0 )
10798  {
10799  if( node->children[i]->bounds.inf > -infinity )
10800  ac.inf = coefs[i] * node->children[i]->bounds.inf;
10801  if( node->children[i]->bounds.sup < infinity )
10803  }
10804  else
10805  {
10806  if( node->children[i]->bounds.sup < infinity )
10807  ac.inf = coefs[i] * node->children[i]->bounds.sup;
10808  if( node->children[i]->bounds.inf > -infinity )
10809  ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10810  }
10811 
10812  SCIPintervalSetEntire(infinity, &childbounds);
10813  if( coefs[i] > 0.0 )
10814  {
10815  /* upper bounds of c_i is
10816  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10817  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10818  */
10819  if( node->bounds.sup < infinity )
10820  {
10821  /* we are still in downward rounding mode, so negate to get upward rounding */
10822  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10823  {
10824  assert(minlinactivityinf == 1);
10825  childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10826  }
10827  else if( minlinactivityinf == 0 )
10828  {
10829  childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10830  }
10831  }
10832 
10833  /* lower bounds of c_i is
10834  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10835  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10836  */
10837  if( node->bounds.inf > -infinity )
10838  {
10839  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10840  {
10841  assert(maxlinactivityinf == 1);
10842  childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10843  }
10844  else if( maxlinactivityinf == 0 )
10845  {
10846  childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10847  }
10848  }
10849  }
10850  else
10851  {
10852  /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10853  * thus, we do (b-a)/(-c) in downward rounding
10854  */
10855  /* lower bounds of c_i is
10856  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10857  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10858  */
10859  if( node->bounds.sup < infinity )
10860  {
10861  if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10862  {
10863  assert(minlinactivityinf == 1);
10864  childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10865  }
10866  else if( minlinactivityinf == 0 )
10867  {
10868  childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10869  }
10870  }
10871 
10872  /* upper bounds of c_i is
10873  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10874  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10875  */
10876  if( node->bounds.inf > -infinity )
10877  {
10878  /* we are still in downward rounding mode, so negate to get upward rounding */
10879  if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10880  {
10881  assert(maxlinactivityinf == 1);
10882  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10883  }
10884  else if( maxlinactivityinf == 0 )
10885  {
10886  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10887  }
10888  }
10889  }
10890 
10891  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10892  }
10893 
10894  SCIPintervalSetRoundingMode(prevroundmode);
10895 
10896  break;
10897  }
10898 
10899  case SCIP_EXPR_QUADRATIC:
10900  {
10901  SCIP_EXPRDATA_QUADRATIC* quaddata;
10902  SCIP_INTERVAL tmp;
10903  SCIP_INTERVAL a;
10904  SCIP_INTERVAL b;
10905  SCIP_INTERVAL c;
10906  SCIP_QUADELEM* quadelems;
10907  int nquadelems;
10908  SCIP_Real* lincoefs;
10909  int k;
10910 
10911  /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10912  * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10913  */
10914 
10915  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10916  quadelems = quaddata->quadelems;
10917  nquadelems = quaddata->nquadelems;
10918  lincoefs = quaddata->lincoefs;
10919 
10920  /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10921  if( nquadelems > 10 )
10922  break;
10923 
10924  if( SCIPintervalIsEntire(infinity, node->bounds) )
10925  break;
10926 
10927  if( node->nchildren == 2 && nquadelems > 0 )
10928  {
10929  /* if it's a bivariate quadratic expression with bilinear term, do something special */
10930  SCIP_Real ax; /* square coefficient of first child */
10931  SCIP_Real ay; /* square coefficient of second child */
10932  SCIP_Real axy; /* bilinear coefficient */
10933 
10934  ax = 0.0;
10935  ay = 0.0;
10936  axy = 0.0;
10937  for( i = 0; i < nquadelems; ++i )
10938  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10939  ax += quadelems[i].coef;
10940  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10941  ay += quadelems[i].coef;
10942  else
10943  axy += quadelems[i].coef;
10944 
10945  c = node->bounds;
10946  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10947 
10948  /* compute bounds for x */
10950  infinity, &childbounds, ax, ay, axy,
10951  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10952  c, node->children[0]->bounds, node->children[1]->bounds
10953  );
10954  if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10955  {
10956  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",
10957  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10958  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10959  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10960  );
10961  }
10962 
10963  if( SCIPintervalIsEmpty(infinity, childbounds) )
10964  *cutoff = TRUE;
10965  else
10966  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10967  if( *cutoff )
10968  break;
10969 
10970  /* compute bounds for y */
10972  infinity, &childbounds, ay, ax, axy,
10973  lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
10974  c, node->children[1]->bounds, node->children[0]->bounds
10975  );
10976 
10977  if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
10978  {
10979  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",
10980  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10981  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10982  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10983  );
10984  }
10985 
10986  if( SCIPintervalIsEmpty(infinity, childbounds) )
10987  *cutoff = TRUE;
10988  else
10989  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10990  if( *cutoff )
10991  break;
10992 
10993  break;
10994  }
10995 
10996  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10997  {
10998  SCIPintervalSet(&a, 0.0);
10999  SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
11000  c = node->bounds;
11001  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
11002 
11003  /* move linear terms not corresponding to i into c
11004  * @todo do this faster, see EXPR_LINEAR
11005  */
11006  if( lincoefs != NULL )
11007  for( k = 0; k < node->nchildren; ++k )
11008  if( i != k && lincoefs[k] != 0.0 )
11009  {
11010  SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
11011  SCIPintervalSub(infinity, &c, c, tmp);
11012  }
11013 
11014  for( k = 0; k < nquadelems; ++k )
11015  {
11016  if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
11017  {
11018  SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
11019  }
11020  else if( quadelems[k].idx1 == i )
11021  {
11022  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
11023  SCIPintervalAdd(infinity, &b, b, tmp);
11024  }
11025  else if( quadelems[k].idx2 == i )
11026  {
11027  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
11028  SCIPintervalAdd(infinity, &b, b, tmp);
11029  }
11030  else if( quadelems[k].idx1 == quadelems[k].idx2 )
11031  {
11032  SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
11033  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11034  SCIPintervalSub(infinity, &c, c, tmp);
11035  }
11036  else
11037  {
11038  SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
11039  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11040  SCIPintervalSub(infinity, &c, c, tmp);
11041  }
11042  }
11043 
11044  SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
11045  a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
11046  SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c);
11047  if( SCIPintervalIsEmpty(infinity, childbounds) )
11048  *cutoff = TRUE;
11049  else
11050  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11051  }
11052 
11053  break;
11054  }
11055 
11056  case SCIP_EXPR_POLYNOMIAL:
11057  {
11058  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11059  SCIP_EXPRDATA_MONOMIAL** monomials;
11060  SCIP_EXPRDATA_MONOMIAL* monomial;
11061  int nmonomials;
11062  int j;
11063  int k;
11064  SCIP_Real n;
11065  int nexpisdoublen;
11066  int nexpishalfn;
11067  char abc_flag;
11068 
11069  SCIP_INTERVAL monomialcoef;
11070  SCIP_INTERVAL tmp;
11071  SCIP_INTERVAL a;
11072  SCIP_INTERVAL b;
11073  SCIP_INTERVAL c;
11074 
11075  /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
11076  * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
11077  *
11078  * we determine n by setting n to the first exponent of x that we see
11079  * then we count how often we see x^(2n) and x^(n/2)
11080  * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
11081  */
11082 
11083  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11084  monomials = polynomialdata->monomials;
11085  nmonomials = polynomialdata->nmonomials;
11086 
11087  if( SCIPintervalIsEntire(infinity, node->bounds) )
11088  break;
11089 
11090  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11091  {
11092  n = 0.0;
11093  nexpisdoublen = 0;
11094  nexpishalfn = 0;
11095  for( j = 0; j < nmonomials; ++j )
11096  {
11097  monomial = monomials[j];
11098  for( k = 0; k < monomial->nfactors; ++k )
11099  {
11100  if( monomial->childidxs[k] == i )
11101  {
11102  if( n == 0.0 )
11103  n = monomial->exponents[k];
11104  else if( n == 2*monomial->exponents[k] ) /*lint !e777*/
11105  ++nexpishalfn;
11106  else if( 2*n == monomial->exponents[k] ) /*lint !e777*/
11107  ++nexpisdoublen;
11108  }
11109  }
11110  }
11111 
11112  if( n == 0.0 )
11113  {
11114  /* child does not appear in polynomial -> cannot deduce bound */
11115  continue;
11116  }
11117 
11118  /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
11119  if( nexpishalfn > nexpisdoublen )
11120  n /= 2.0;
11121 
11122  SCIPintervalSet(&a, 0.0);
11123  SCIPintervalSet(&b, 0.0);
11124  SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
11125 
11126  for( j = 0; j < nmonomials; ++j )
11127  {
11128  monomial = monomials[j];
11129  SCIPintervalSet(&monomialcoef, monomial->coef);
11130  abc_flag = 'c';
11131  for( k = 0; k < monomial->nfactors; ++k )
11132  {
11133  if( monomial->childidxs[k] == i )
11134  {
11135  assert(abc_flag == 'c'); /* child should appear only once per monom */
11136  if( n > 0.0 )
11137  {
11138  if( monomial->exponents[k] > 2.0*n )
11139  {
11140  abc_flag = 'a';
11141  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11142  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11143  }
11144  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11145  {
11146  abc_flag = 'a';
11147  }
11148  else if( monomial->exponents[k] > n )
11149  {
11150  abc_flag = 'b';
11151  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11152  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11153  }
11154  else if( monomial->exponents[k] == n ) /*lint !e777*/
11155  {
11156  abc_flag = 'b';
11157  }
11158  else
11159  {
11160  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11161  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11162  }
11163  }
11164  else
11165  {
11166  assert(n < 0.0);
11167  if( monomial->exponents[k] < 2.0*n )
11168  {
11169  abc_flag = 'a';
11170  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11171  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11172  }
11173  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11174  {
11175  abc_flag = 'a';
11176  }
11177  else if( monomial->exponents[k] < n )
11178  {
11179  abc_flag = 'b';
11180  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11181  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11182  }
11183  else if( monomial->exponents[k] == n ) /*lint !e777*/
11184  {
11185  abc_flag = 'b';
11186  }
11187  else
11188  {
11189  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11190  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11191  }
11192  }
11193  }
11194  else
11195  {
11196  SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
11197  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11198  }
11199  }
11200 
11201  if( abc_flag == 'a' )
11202  {
11203  SCIPintervalAdd(infinity, &a, a, monomialcoef);
11204  /* if monomialcoef is such that a exceeds value for infinity, then stop */
11205  if( a.inf >= infinity || a.sup <= -infinity )
11206  break;
11207  }
11208  else if( abc_flag == 'b' )
11209  {
11210  SCIPintervalAdd(infinity, &b, b, monomialcoef);
11211  /* if monomialcoef is such that b exceeds value for infinity, then stop */
11212  if( b.inf >= infinity || b.sup <= -infinity )
11213  break;
11214  }
11215  else
11216  {
11217  SCIPintervalSub(infinity, &c, c, monomialcoef);
11218  /* if monomialcoef is such that c exceeds value for infinity, then stop */
11219  if( c.inf >= infinity || c.sup <= -infinity )
11220  break;
11221  }
11222  }
11223 
11224  /* if we run out of numbers (within -infinity,infinity) above, then stop */
11225  if( j < nmonomials )
11226  continue;
11227 
11228  /* now have equation a*child^(2n) + b*child^n = c
11229  * solve a*y^2 + b*y = c, then child^n = y
11230  */
11231  SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g]",
11232  a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup);
11233  SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c);
11234  SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
11235 
11236  if( SCIPintervalIsEmpty(infinity, tmp) )
11237  {
11238  *cutoff = TRUE;
11239  break;
11240  }
11241 
11242  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
11243  SCIPdebugPrintf(" -> c%d = [%10g, %10g]\n", i, childbounds.inf, childbounds.sup);
11244  if( SCIPintervalIsEmpty(infinity, childbounds) )
11245  {
11246  SCIPdebugMessage(" -> cutoff\n");
11247  *cutoff = TRUE;
11248  break;
11249  }
11250 
11251  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11252 
11253  /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
11254  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11255  SCIPdebugPrintf("\n"); */
11256  }
11257 
11258  break;
11259  }
11260 
11261  case SCIP_EXPR_USER:
11262  {
11263  SCIP_INTERVAL* childrenbounds;
11264  SCIP_EXPRDATA_USER* exprdata;
11265  int c;
11266 
11267  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11268 
11269  /* do nothing if callback not implemented */
11270  if( exprdata->prop == NULL )
11271  break;
11272 
11273  /* if only one child, do faster */
11274  if( node->nchildren == 1 )
11275  {
11276  childbounds = node->children[0]->bounds;
11277  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, 1, &childbounds, node->bounds, cutoff) );
11278 
11279  if( !*cutoff )
11280  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11281 
11282  break;
11283  }
11284 
11285  SCIP_ALLOC_ABORT( BMSallocBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren) );
11286  for( c = 0; c < node->nchildren; ++c )
11287  childrenbounds[c] = node->children[c]->bounds;
11288 
11289  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, node->nchildren, childrenbounds, node->bounds, cutoff) );
11290 
11291  for( c = 0; !*cutoff && c < node->nchildren; ++c )
11292  {
11293  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[c], childrenbounds[c], minstrength, infinity, cutoff);
11294  }
11295 
11296  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren);
11297 
11298  break;
11299  }
11300 
11301  case SCIP_EXPR_LAST:
11302  SCIPABORT();
11303  break;
11304  }
11305 }
11306 
11307 /** removes duplicate children in a polynomial expression node
11308  *
11309  * Leaves NULL's in children array.
11310  */
11311 static
11313  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11314  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11315  )
11316 {
11317  SCIP_Bool foundduplicates;
11318  int* childmap;
11319  int i;
11320  int j;
11321 
11322  assert(exprgraph != NULL);
11323  assert(node != NULL);
11324  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11325 
11326  if( node->nchildren == 0 )
11327  return SCIP_OKAY;
11328 
11329  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
11330 
11331  foundduplicates = FALSE;
11332  for( i = 0; i < node->nchildren; ++i )
11333  {
11334  if( node->children[i] == NULL )
11335  continue;
11336  childmap[i] = i; /*lint !e644*/
11337 
11338  for( j = i+1; j < node->nchildren; ++j )
11339  {
11340  if( node->children[j] == NULL )
11341  continue;
11342 
11343  if( node->children[i] == node->children[j] )
11344  {
11345  /* node should be parent of children[j] at least twice,
11346  * so we remove it once
11347  */
11348  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
11349  node->children[j] = NULL;
11350  assert(exprgraphNodeIsParent(node->children[i], node));
11351 
11352  childmap[j] = i;
11353  foundduplicates = TRUE;
11354  }
11355  }
11356  }
11357 
11358  /* apply childmap to monomials */
11359  if( foundduplicates )
11361 
11362  /* free childmap */
11363  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
11364 
11365  return SCIP_OKAY;
11366 }
11367 
11368 /** eliminates NULL's in children array and shrinks it to actual size */
11369 static
11371  BMS_BLKMEM* blkmem, /**< block memory */
11372  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11373  )
11374 {
11375  int* childmap;
11376  int lastnonnull;
11377  int i;
11378 
11379  assert(blkmem != NULL);
11380  assert(node != NULL);
11381  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11382 
11383  if( node->nchildren == 0 )
11384  return SCIP_OKAY;
11385 
11386  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
11387 
11388  /* close gaps in children array */
11389  lastnonnull = node->nchildren-1;
11390  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11391  --lastnonnull;
11392  for( i = 0; i <= lastnonnull; ++i )
11393  {
11394  if( node->children[i] != NULL )
11395  {
11396  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
11397  continue;
11398  }
11399  assert(node->children[lastnonnull] != NULL);
11400 
11401  /* move child at lastnonnull to position i */
11402  node->children[i] = node->children[lastnonnull];
11403  node->children[lastnonnull] = NULL;
11404  childmap[lastnonnull] = i;
11405 
11406  /* update lastnonnull */
11407  --lastnonnull;
11408  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11409  --lastnonnull;
11410  }
11411  assert(i > lastnonnull);
11412 
11413  /* apply childmap to monomials */
11414  if( lastnonnull < node->nchildren-1 )
11416 
11417  BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
11418 
11419  /* shrink children array */
11420  if( lastnonnull >= 0 )
11421  {
11422  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
11423  node->nchildren = lastnonnull+1;
11424  }
11425  else
11426  {
11427  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11428  node->nchildren = 0;
11429  }
11430 
11431  return SCIP_OKAY;
11432 }
11433 
11434 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
11435  *
11436  * Converts node into polynomial, if possible and not constant.
11437  */
11438 static
11440  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11441  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
11442  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
11443  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
11444  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
11445  SCIP_Bool* havechange /**< flag to set if the node has been changed */
11446  )
11447 {
11448  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11449  SCIP_EXPRDATA_MONOMIAL* monomial;
11450  BMS_BLKMEM* blkmem;
11451  SCIP_Bool removechild;
11452  SCIP_Bool* childinuse;
11453  int* childmap;
11454  int childmapsize;
11455  int i;
11456  int j;
11457  int orignchildren;
11458 
11459  assert(exprgraph != NULL);
11460  assert(node != NULL);
11461  assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
11462  assert(havechange != NULL);
11463 
11464  blkmem = exprgraph->blkmem;
11465  assert(blkmem != NULL);
11466 
11467  SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
11468 
11469  /* if all children are constants, then turn this node into constant */
11470  for( i = 0; i < node->nchildren; ++i )
11471  if( node->children[i]->op != SCIP_EXPR_CONST )
11472  break;
11473  if( node->nchildren > 0 && i == node->nchildren )
11474  {
11475  /* get value of node */
11477  assert(node->value != SCIP_INVALID); /*lint !e777*/
11478 
11479  SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
11480  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11481  SCIPdebugPrintf("\n");
11482 
11483  /* free expression data */
11484  if( exprOpTable[node->op].freedata != NULL )
11485  exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
11486 
11487  /* disconnect from children */
11488  for( i = 0; i < node->nchildren; ++i )
11489  {
11490  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11491  }
11492  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11493  node->nchildren = 0;
11494 
11495  /* turn into constant expression */
11496  node->op = SCIP_EXPR_CONST;
11497  node->data.dbl = node->value;
11498 
11499  *havechange = TRUE;
11500  node->simplified = TRUE;
11501 
11502  return SCIP_OKAY;
11503  }
11504 
11505  /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
11506  * @todo log(product) -> sum(log)
11507  * @todo product(exp) -> exp(sum)
11508  * @todo exp(x)^p -> exp(p*x)
11509  * @todo exp(const*log(x)) -> x^const
11510  */
11511 
11512  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
11513 
11514  if( node->op != SCIP_EXPR_POLYNOMIAL )
11515  {
11516  node->simplified = TRUE;
11517  return SCIP_OKAY;
11518  }
11519 
11520  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11521  assert(polynomialdata != NULL);
11522 
11523  orignchildren = node->nchildren;
11524 
11525  /* check if we have duplicate children and merge */
11527  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11528 
11529  SCIPdebugMessage("expand factors in expression node ");
11530  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11531  SCIPdebugPrintf("\n");
11532 
11533  childmap = NULL;
11534  childmapsize = 0;
11535 
11536  /* resolve children that are constants
11537  * we do this first, because it reduces the degree and number of factors in the monomials,
11538  * 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
11539  */
11540  for( i = 0; i < node->nchildren; ++i )
11541  {
11542  if( node->children[i] == NULL )
11543  continue;
11544 
11545  /* convert children to polynomial, if not constant or polynomial
11546  * if child was simplified in this round, it may have already been converted, and then nothing happens
11547  * but if child was already simplified, then it was not converted, and thus we try it here
11548  */
11549  if( node->children[i]->op != SCIP_EXPR_CONST )
11550  continue;
11551 
11552  SCIPdebugMessage("expand child %d in expression node ", i);
11553  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11554  SCIPdebugPrintf("\n\tchild = ");
11555  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11556  SCIPdebugPrintf("\n");
11557 
11558  removechild = TRUE; /* we intend to release children[i] */
11559 
11560  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11561 
11562  /* put constant of child i into every monomial where child i is used */
11563  for( j = 0; j < polynomialdata->nmonomials; ++j )
11564  {
11565  int factorpos;
11566 
11567  monomial = polynomialdata->monomials[j];
11568  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11569  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11570 
11571  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11572  {
11573  assert(factorpos >= 0);
11574  assert(factorpos < monomial->nfactors);
11575  /* assert that factors have been merged */
11576  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11577  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11578 
11579  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11580 
11581  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 ) /*lint !e835*/
11582  {
11583  /* if constant is negative and our exponent is not integer, then cannot do expansion */
11584  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
11585  removechild = FALSE;
11586  }
11587  else
11588  {
11589  monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
11590 
11591  /* move last factor to position factorpos */
11592  if( factorpos < monomial->nfactors-1 )
11593  {
11594  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
11595  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
11596  }
11597  --monomial->nfactors;
11598  monomial->sorted = FALSE;
11599  polynomialdata->sorted = FALSE;
11600 
11601  *havechange = TRUE;
11602  }
11603  }
11604  }
11605 
11606  /* forget about child i, if it is not used anymore */
11607  if( removechild )
11608  {
11609  /* remove node from list of parents of child i */
11610  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11611  node->children[i] = NULL;
11612  }
11613 
11614  /* simplify current polynomial again */
11615  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11616  }
11617 
11618  /* resolve children that are polynomials itself */
11619  for( i = 0; i < node->nchildren; ++i )
11620  {
11621  if( node->children[i] == NULL )
11622  continue;
11623 
11624  /* convert children to polynomial, if not constant or polynomial
11625  * if child was simplified in this round, it may have already been converted, and then nothing happens
11626  * but if child was already simplified, then it was not converted, and thus we try it here
11627  */
11628  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
11629 
11630  if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
11631  continue;
11632 
11633  SCIPdebugMessage("expand child %d in expression node %p = ", i, (void*)node);
11634  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11635  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n\tchild = ") );
11636  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11637  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
11638 
11639  removechild = TRUE; /* we intend to release children[i] */
11640 
11641  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11642 
11643  /* add children of child i to node */
11644  SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
11645 
11646  /* put polynomial of child i into every monomial where child i is used */
11647  j = 0;
11648  while( j < polynomialdata->nmonomials )
11649  {
11650  int factorpos;
11651  SCIP_Bool success;
11652 
11653  monomial = polynomialdata->monomials[j];
11654  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11655  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11656 
11657  /* make sure factors are merged, should only be potentially necessary if not sorted, see also #1848 */
11658  if( !monomial->sorted )
11659  SCIPexprMergeMonomialFactors(monomial, eps);
11660 
11661  if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11662  {
11663  ++j;
11664  continue;
11665  }
11666 
11667  assert(factorpos >= 0);
11668  assert(factorpos < monomial->nfactors);
11669  /* assert that factors have been merged */
11670  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11671  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11672 
11673  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11674 
11675  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
11676  (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
11677 
11678  if( !success )
11679  {
11680  removechild = FALSE;
11681  ++j;
11682  }
11683  else
11684  *havechange = TRUE;
11685 
11686  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
11687  * we thus repeat with index j, if a factor was successfully expanded
11688  */
11689  }
11690 
11691  /* forget about child i, if it is not used anymore */
11692  if( removechild )
11693  {
11694  /* remove node from list of parents of child i */
11695  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11696  node->children[i] = NULL;
11697  }
11698  }
11699 
11700  /* simplify current polynomial again */
11701  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11702 
11703  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
11704 
11705  /* check which children are still in use */
11706  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
11707  BMSclearMemoryArray(childinuse, node->nchildren); /*lint !e644*/
11708  for( i = 0; i < polynomialdata->nmonomials; ++i )
11709  {
11710  monomial = polynomialdata->monomials[i];
11711  assert(monomial != NULL);
11712 
11713  for( j = 0; j < monomial->nfactors; ++j )
11714  {
11715  assert(monomial->childidxs[j] >= 0);
11716  assert(monomial->childidxs[j] < node->nchildren);
11717  childinuse[monomial->childidxs[j]] = TRUE;
11718  }
11719  }
11720 
11721  /* free children that are not used in any monomial */
11722  for( i = 0; i < node->nchildren; ++i )
11723  if( node->children[i] != NULL && !childinuse[i] )
11724  {
11725  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11726  node->children[i] = NULL;
11727  }
11728 
11729  BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
11730 
11731  /* remove NULLs from children array */
11733 
11734  /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
11735  if( node->nchildren == 0 )
11736  {
11737  SCIP_Real val;
11738 
11739  /* if no children, then it should also have no monomials */
11740  assert(polynomialdata->nmonomials == 0);
11741 
11742  val = polynomialdata->constant;
11743  polynomialdataFree(blkmem, &polynomialdata);
11744 
11745  node->op = SCIP_EXPR_CONST;
11746  node->data.dbl = val;
11747  node->value = val;
11748  }
11749 
11750  /* if no factor in a monomial was replaced, the number of children should not have changed
11751  * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11752  */
11753  *havechange |= (node->nchildren < orignchildren); /*lint !e514*/
11754 
11755  node->simplified = TRUE;
11756 
11757  SCIPdebugMessage("-> %p = ", (void*)node);
11758  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11759  SCIPdebugPrintf("\n");
11760 
11761  return SCIP_OKAY;
11762 }
11763 
11764 /** creates an expression from a given node in an expression graph
11765  *
11766  * Assembles mapping of variables from graph to tree.
11767  */
11768 static
11770  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11771  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which expression should be created */
11772  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
11773  int* nexprvars, /**< current number of variables in expression */
11774  int* varidx /**< current mapping of variable indices from graph to expression */
11775  )
11776 {
11777  SCIP_EXPR** childexprs;
11778  int i;
11779 
11780  assert(exprgraph != NULL);
11781  assert(node != NULL);
11782  assert(expr != NULL);
11783  assert(nexprvars != NULL);
11784  assert(*nexprvars >= 0);
11785  assert(varidx != NULL);
11786 
11787  childexprs = NULL;
11788  if( node->nchildren > 0 )
11789  {
11790  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11791  for( i = 0; i < node->nchildren; ++i )
11792  {
11793  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) ); /*lint !e613*/
11794  }
11795  }
11796 
11797  switch( node->op )
11798  {
11799  case SCIP_EXPR_VARIDX:
11800  {
11801  /* check if the variable already has an index assigned in the expression tree
11802  * if not, create one and increase nexprvars
11803  */
11804  assert(node->data.intval >= 0);
11805  assert(node->data.intval < exprgraph->nvars);
11806  assert(varidx[node->data.intval] >= -1);
11807  assert(varidx[node->data.intval] < *nexprvars);
11808  if( varidx[node->data.intval] == -1 )
11809  {
11810  varidx[node->data.intval] = *nexprvars;
11811  ++*nexprvars;
11812  }
11813 
11814  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11815  break;
11816  }
11817 
11818  case SCIP_EXPR_CONST:
11819  {
11820  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11821  break;
11822  }
11823 
11824  case SCIP_EXPR_REALPOWER:
11825  case SCIP_EXPR_SIGNPOWER:
11826  {
11827  assert(node->nchildren == 1);
11828  assert(childexprs != NULL);
11829  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11830  break;
11831  }
11832 
11833  case SCIP_EXPR_INTPOWER:
11834  {
11835  assert(node->nchildren == 1);
11836  assert(childexprs != NULL);
11837  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11838  break;
11839  }
11840 
11841  case SCIP_EXPR_PLUS:
11842  case SCIP_EXPR_MINUS:
11843  case SCIP_EXPR_MUL:
11844  case SCIP_EXPR_DIV:
11845  case SCIP_EXPR_MIN:
11846  case SCIP_EXPR_MAX:
11847  {
11848  assert(node->nchildren == 2);
11849  assert(childexprs != NULL);
11850  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11851  break;
11852  }
11853 
11854  case SCIP_EXPR_SQUARE:
11855  case SCIP_EXPR_SQRT:
11856  case SCIP_EXPR_EXP:
11857  case SCIP_EXPR_LOG:
11858  case SCIP_EXPR_SIN:
11859  case SCIP_EXPR_COS:
11860  case SCIP_EXPR_TAN:
11861  /* case SCIP_EXPR_ERF: */
11862  /* case SCIP_EXPR_ERFI: */
11863  case SCIP_EXPR_ABS:
11864  case SCIP_EXPR_SIGN:
11865  {
11866  assert(node->nchildren == 1);
11867  assert(childexprs != NULL);
11868  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11869  break;
11870  }
11871 
11872  case SCIP_EXPR_SUM:
11873  case SCIP_EXPR_PRODUCT:
11874  {
11875  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11876  break;
11877  }
11878 
11879  case SCIP_EXPR_LINEAR:
11880  {
11881  assert(node->data.data != NULL);
11882 
11883  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11884  break;
11885  }
11886 
11887  case SCIP_EXPR_QUADRATIC:
11888  {
11889  SCIP_EXPRDATA_QUADRATIC* quaddata;
11890 
11891  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11892  assert(quaddata != NULL);
11893 
11894  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11895  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11896  break;
11897  }
11898 
11899  case SCIP_EXPR_POLYNOMIAL:
11900  {
11901  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11902 
11903  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11904  assert(polynomialdata != NULL);
11905 
11906  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11907  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11908 
11909  break;
11910  }
11911 
11912  case SCIP_EXPR_USER:
11913  {
11914  SCIP_EXPRDATA_USER* exprdata;
11915  SCIP_USEREXPRDATA* userdata;
11916 
11917  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11918  assert(exprdata != NULL);
11919 
11920  if( exprdata->copydata != NULL )
11921  {
11922  SCIP_CALL( exprdata->copydata(exprgraph->blkmem, node->nchildren, exprdata->userdata, &userdata) );
11923  }
11924  else
11925  userdata = exprdata->userdata;
11926 
11927  SCIP_CALL( SCIPexprCreateUser(exprgraph->blkmem, expr, node->nchildren, childexprs,
11928  userdata, exprdata->evalcapability, exprdata->eval, exprdata->inteval, exprdata->curv, exprdata->prop, exprdata->estimate, exprdata->copydata, exprdata->freedata, exprdata->print) );
11929 
11930  break;
11931  }
11932 
11933  case SCIP_EXPR_LAST:
11934  case SCIP_EXPR_PARAM:
11935  {
11936  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11937  return SCIP_ERROR;
11938  }
11939  }
11940 
11941  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11942 
11943  return SCIP_OKAY;
11944 }
11945 
11946 /** counts how often expression graph variables are used in a subtree of the expression graph
11947  *
11948  * @note The function does not clear the array first, but only increases already existing counts.
11949  */
11950 static
11952  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11953  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11954  )
11955 {
11956  int i;
11957 
11958  assert(node != NULL);
11959  assert(varsusage != NULL);
11960 
11961  if( node->op == SCIP_EXPR_VARIDX )
11962  {
11963  ++varsusage[node->data.intval];
11964  return;
11965  }
11966 
11967  for( i = 0; i < node->nchildren; ++i )
11968  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
11969 }
11970 
11971 /** checks whether a node can be put into a component when checking block separability of an expression
11972  *
11973  * If a variable used by node is already in another component, components are merged and component number is updated.
11974  */
11975 static
11977  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
11978  int* compnr, /**< component number to assign, may be reduced if variables overlap */
11979  int nchildcomps, /**< number of entries for which childcomps have been set already */
11980  int* childcomps, /**< component numbers of children */
11981  int nvars, /**< number of variables */
11982  int* varcomps /**< component numbers of variables */
11983  )
11984 {
11985  int varidx;
11986  int i;
11987 
11988  assert(node != NULL);
11989  assert(compnr != NULL);
11990  assert(*compnr >= 0);
11991  assert(childcomps != NULL);
11992  assert(varcomps != NULL);
11993 
11994  if( node->op != SCIP_EXPR_VARIDX )
11995  {
11996  for( i = 0; i < node->nchildren; ++i )
11997  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
11998  return;
11999  }
12000 
12001  varidx = node->data.intval;
12002  assert(varidx >= 0);
12003  assert(varidx < nvars);
12004 
12005  if( varcomps[varidx] == -1 )
12006  {
12007  /* first time we get to this variable, so set it's component to compnr and we are done */
12008  varcomps[varidx] = *compnr;
12009  return;
12010  }
12011 
12012  if( varcomps[varidx] == *compnr )
12013  {
12014  /* variable is already in current component, that's also good and we are done */
12015  return;
12016  }
12017 
12018  /* variable is already in another component, so have to merge component compnr into that component
12019  * do this by updating varcomps and childcomps */
12020  for( i = 0; i < nvars; ++i )
12021  if( varcomps[i] == *compnr )
12022  varcomps[i] = varcomps[varidx];
12023  for( i = 0; i < nchildcomps; ++i )
12024  if( childcomps[i] == *compnr )
12025  childcomps[i] = varcomps[varidx];
12026  *compnr = varcomps[varidx];
12027 }
12028 
12029 /**@} */
12030 
12031 /**@name Expression graph private methods */
12032 /**@{ */
12033 
12034 /** assert that expression graph has at least a given depth */
12035 static
12037  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
12038  int mindepth /**< minimal depth that should be ensured */
12039  )
12040 {
12041  int olddepth;
12042 
12043  assert(exprgraph != NULL);
12044  assert(exprgraph->blkmem != NULL);
12045 
12046  if( mindepth <= exprgraph->depth )
12047  return SCIP_OKAY;
12048 
12049  olddepth = exprgraph->depth;
12050  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
12051  assert(exprgraph->depth >= mindepth);
12052 
12053  /* initialize new array entries to 0 and NULL, resp. */
12054  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12055  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12056  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12057 
12058  return SCIP_OKAY;
12059 }
12060 
12061 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
12062 static
12064  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12065  int varidx /**< variable index */
12066  )
12067 {
12068  SCIP_EXPRGRAPHNODE* varnode;
12069  void* var;
12070 
12071  assert(exprgraph != NULL);
12072  assert(varidx >= 0);
12073  assert(varidx < exprgraph->nvars);
12074 
12075  varnode = exprgraph->varnodes[varidx];
12076  assert(varnode->data.intval == varidx);
12077 
12078  var = exprgraph->vars[varidx];
12079 
12080  /* call varremove callback method, if set */
12081  if( exprgraph->exprgraphvarremove != NULL )
12082  {
12083  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
12084  }
12085 
12086  /* remove variable from hashmap */
12087  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
12088 
12089  /* move last variable to position varidx and give it the new index */
12090  if( varidx < exprgraph->nvars-1 )
12091  {
12092  /* call callback method, if set */
12093  if( exprgraph->exprgraphvarchgidx != NULL )
12094  {
12095  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
12096  }
12097 
12098  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
12099  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
12100  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
12101  exprgraph->varnodes[varidx]->data.intval = varidx;
12102  SCIP_CALL( SCIPhashmapSetImage(exprgraph->varidxs, exprgraph->vars[varidx], (void*)(size_t)(varidx)) );
12103  }
12104  --exprgraph->nvars;
12105 
12106  return SCIP_OKAY;
12107 }
12108 
12109 /** moves a node in an expression graph to a different depth
12110  *
12111  * New depth must be larger than children depth.
12112  * Moves parent nodes to higher depth, if needed.
12113  * Variable nodes cannot be moved.
12114  */
12115 static
12117  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12118  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
12119  int newdepth /**< new depth to which to move node */
12120  )
12121 {
12122  int olddepth;
12123  int oldpos;
12124  int i;
12125 
12126  assert(exprgraph != NULL);
12127  assert(node != NULL);
12128  assert(node->depth >= 0); /* node should be in graph */
12129  assert(newdepth >= 0);
12130 
12131  /* if already on aimed depth, then don't need to move */
12132  if( node->depth == newdepth )
12133  return SCIP_OKAY;
12134 
12135  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
12136 
12137 #ifndef NDEBUG
12138  /* assert that children are at lower depth than new depth */
12139  for( i = 0; i < node->nchildren; ++i )
12140  assert(node->children[i]->depth < newdepth);
12141 #endif
12142 
12143  /* move parents to higher depth, if needed */
12144  for( i = 0; i < node->nparents; ++i )
12145  {
12146  if( node->parents[i]->depth <= newdepth )
12147  {
12148  /* move parent to depth+1 */
12149  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
12150  assert(node->parents[i]->depth > newdepth);
12151  }
12152  }
12153 
12154  /* ensure that graph is deep enough */
12155  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
12156  assert(exprgraph->depth > newdepth);
12157 
12158  olddepth = node->depth;
12159  oldpos = node->pos;
12160 
12161  /* add node to new depth */
12162  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
12163  node->depth = newdepth;
12164  node->pos = exprgraph->nnodes[newdepth];
12165  exprgraph->nodes[newdepth][node->pos] = node;
12166  ++exprgraph->nnodes[newdepth];
12167 
12168  /* 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) */
12169  for( i = 0; i < node->nchildren; ++i )
12170  node->children[i]->parentssorted = FALSE;
12171 
12172  /* move last node at previous depth to previous position, if it wasn't last */
12173  if( oldpos < exprgraph->nnodes[olddepth]-1 )
12174  {
12175  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
12176  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
12177 
12178  /* 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) */
12179  for( i = 0; i < exprgraph->nodes[olddepth][oldpos]->nchildren; ++i )
12180  exprgraph->nodes[olddepth][oldpos]->children[i]->parentssorted = FALSE;
12181  }
12182  --exprgraph->nnodes[olddepth];
12183 
12184  if( node->depth == 0 )
12185  {
12186  /* if at depth 0, then it need to be a node for either a constant or a variable */
12187  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
12188  if( node->op == SCIP_EXPR_CONST )
12189  {
12190  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
12191  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
12192  exprgraph->constnodes[exprgraph->nconsts] = node;
12193  ++exprgraph->nconsts;
12194  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
12195  }
12196  else
12197  {
12198  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
12199  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
12200  return SCIP_ERROR;
12201  }
12202 
12203  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
12204  node->curv = SCIP_EXPRCURV_LINEAR;
12205  }
12206 
12207  return SCIP_OKAY;
12208 }
12209 
12210 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
12211 static
12213  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12214  int nchildren, /**< number of children */
12215  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
12216  SCIP_EXPROP op, /**< operator */
12217  SCIP_EXPROPDATA opdata, /**< operator data */
12218  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
12219  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
12220  )
12221 {
12222  SCIP_EXPRGRAPHNODE** parentcands;
12223  int nparentcands;
12224  int parentcandssize;
12225  int i;
12226  int p;
12227 
12228  assert(exprgraph != NULL);
12229  assert(nchildren > 0);
12230  assert(children != NULL);
12231  assert(parent != NULL);
12232 
12233  *parent = NULL;
12234 
12235  /* create initial set of parent candidates as
12236  * all parents of first child that have the same operator type and the same number of children
12237  * additionally, some easy conditions for complex expression types:
12238  * if expression type is int/real/signpower, then compare also exponent,
12239  * if expression type is linear, then compare also constant part,
12240  * if expression type is quadratic, then compare also number of quadratic elements,
12241  * if expression type is polynomial, then compare also number of monmials and constant part
12242  */
12243  parentcandssize = children[0]->nparents;
12244  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
12245  nparentcands = 0;
12246  for( p = 0; p < children[0]->nparents; ++p )
12247  if( children[0]->parents[p]->op == op &&
12248  children[0]->parents[p]->nchildren == nchildren &&
12249  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
12250  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12251  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12252  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
12253  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
12254  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
12255  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
12256  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
12257  )
12258  {
12259  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
12260  }
12261 
12262  /* for all remaining children, remove parent candidates, that are not in their list of parents */
12263  for( i = 1; i < nchildren && nparentcands > 0; ++i )
12264  {
12265  p = 0;
12266  while( p < nparentcands )
12267  {
12268  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
12269  * otherwise keep candidate and check next one
12270  */
12271  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
12272  {
12273  parentcands[p] = parentcands[nparentcands-1];
12274  --nparentcands;
12275  }
12276  else
12277  ++p;
12278  }
12279  }
12280 
12281  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
12282 
12283  if( nparentcands == 0 )
12284  {
12285  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
12286  return SCIP_OKAY;
12287  }
12288 
12289  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
12290  * check if there is also one which corresponds to same expression and store that one in *parent
12291  */
12292  switch( op )
12293  {
12294  /* commutative operands with no data */
12295  case SCIP_EXPR_PLUS :
12296  case SCIP_EXPR_MUL :
12297  case SCIP_EXPR_MIN :
12298  case SCIP_EXPR_MAX :
12299  case SCIP_EXPR_SUM :
12300  case SCIP_EXPR_PRODUCT:
12301  case SCIP_EXPR_SQUARE :
12302  case SCIP_EXPR_SQRT :
12303  case SCIP_EXPR_EXP :
12304  case SCIP_EXPR_LOG :
12305  case SCIP_EXPR_SIN :
12306  case SCIP_EXPR_COS :
12307  case SCIP_EXPR_TAN :
12308  /* case SCIP_EXPR_ERF : */
12309  /* case SCIP_EXPR_ERFI : */
12310  case SCIP_EXPR_ABS :
12311  case SCIP_EXPR_SIGN :
12312  {
12313  /* sort childnodes, if needed for later */
12314  if( nchildren > 2 )
12315  SCIPsortPtr((void**)children, exprgraphnodecomp, nchildren);
12316  for( p = 0; p < nparentcands; ++p )
12317  {
12318  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12319  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12320 
12321  if( nchildren == 1 )
12322  {
12323  assert(parentcands[p]->children[0] == children[0]);
12324  /* same operand, same child, so same expression */
12325  *parent = parentcands[p];
12326  break;
12327  }
12328  else if( nchildren == 2 )
12329  {
12330  /* We know that every node in children is also a child of parentcands[p].
12331  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
12332  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
12333  */
12334  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
12335  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
12336  {
12337  *parent = parentcands[p];
12338  break;
12339  }
12340  }
12341  else
12342  {
12343  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
12344 
12345  /* sort children of parent candidate */
12346  SCIPsortPtr((void**)parentcands[p]->children, exprgraphnodecomp, nchildren);
12347 
12348  /* check if childnodes and parentcands[p]->children are the same */
12349  for( i = 0; i < nchildren; ++i )
12350  if( children[i] != parentcands[p]->children[i] )
12351  break;
12352  if( i == nchildren )
12353  {
12354  /* yeah, found an exact match */
12355  *parent = parentcands[p];
12356  break;
12357  }
12358  }
12359  }
12360 
12361  break;
12362  }
12363 
12364  /* non-commutative operands with two children */
12365  case SCIP_EXPR_MINUS :
12366  case SCIP_EXPR_DIV :
12367  {
12368  for( p = 0; p < nparentcands; ++p )
12369  {
12370  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12371  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
12372  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
12373  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
12374  {
12375  /* yeah, found one */
12376  *parent = parentcands[p];
12377  break;
12378  }
12379  }
12380 
12381  break;
12382  }
12383 
12384  /* operands with one child and data */
12385  case SCIP_EXPR_INTPOWER:
12386  {
12387  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12388  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12389  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12390  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
12391 
12392  /* yeah, have one with same exponent */
12393  *parent = parentcands[0];
12394 
12395  break;
12396  }
12397 
12398  case SCIP_EXPR_REALPOWER:
12399  case SCIP_EXPR_SIGNPOWER:
12400  {
12401  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12402  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12403  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12404  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
12405 
12406  /* yeah, have one with same exponent */
12407  *parent = parentcands[0];
12408 
12409  break;
12410  }
12411 
12412  /* commutative operands with n children and data */
12413  case SCIP_EXPR_LINEAR:
12414  {
12415  SCIP_Real* exprcoef;
12416  SCIP_Real* candcoef;
12417 
12418  exprcoef = (SCIP_Real*)opdata.data;
12419  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
12420  if( exprchildren != NULL )
12421  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, exprgraphnodecomp, nchildren);
12422  else
12423  SCIPsortPtrReal((void**)children, exprcoef, exprgraphnodecomp, nchildren);
12424  for( p = 0; p < nparentcands; ++p )
12425  {
12426  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12427  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12428 
12429  candcoef = (SCIP_Real*)parentcands[p]->data.data;
12430  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12431 
12432  /* sort children of parent candidate */
12433  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, exprgraphnodecomp, nchildren);
12434 
12435  /* check if children and coefficients in parent candidate and expression are the same */
12436  for( i = 0; i < nchildren; ++i )
12437  {
12438  if( children[i] != parentcands[p]->children[i] )
12439  break;
12440  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
12441  break;
12442  }
12443  if( i < nchildren )
12444  continue;
12445 
12446  /* yeah, found an exact match */
12447  *parent = parentcands[p];
12448  break;
12449  }
12450 
12451  break;
12452  }
12453 
12454  case SCIP_EXPR_QUADRATIC:
12455  {
12456  SCIP_EXPRDATA_QUADRATIC* exprdata;
12457  SCIP_Real* exprlincoef;
12458  SCIP_Real* candlincoef;
12459  SCIP_EXPRDATA_QUADRATIC* canddata;
12460  int* perm;
12461  int* invperm;
12462 
12463  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
12464  exprlincoef = exprdata->lincoefs;
12465 
12466  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
12467 
12468  /* sort expr->children and childnodes and store inverse permutation in invperm */
12469  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12470  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12471  for( i = 0; i < nchildren; ++i )
12472  invperm[i] = i; /*lint !e644*/
12473 
12474  if( exprlincoef != NULL )
12475  if( exprchildren != NULL )
12476  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12477  else
12478  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12479  else
12480  if( exprchildren != NULL )
12481  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12482  else
12483  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12484 
12485  /* compute permutation from its inverse */
12486  for( i = 0; i < nchildren; ++i )
12487  perm[invperm[i]] = i; /*lint !e644*/
12488 
12489  /* apply permuation to exprdata->quadelems and sort again */
12490  for( i = 0; i < exprdata->nquadelems; ++i )
12491  {
12492  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
12493  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
12494  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
12495  {
12496  int tmp;
12497  tmp = exprdata->quadelems[i].idx1;
12498  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
12499  exprdata->quadelems[i].idx2 = tmp;
12500  }
12501  }
12502  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
12503  exprdata->sorted = TRUE;
12504 
12505  for( p = 0; p < nparentcands; ++p )
12506  {
12507  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12508  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12509 
12510  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
12511  candlincoef = canddata->lincoefs;
12512  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
12513  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12514 
12515  /* sort parentcands[p]->children and store inverse permutation in invperm */
12516  for( i = 0; i < nchildren; ++i )
12517  invperm[i] = i;
12518 
12519  if( candlincoef != NULL )
12520  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, exprgraphnodecomp, parentcands[p]->nchildren);
12521  else
12522  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12523 
12524  /* compute permutation from its inverse */
12525  for( i = 0; i < nchildren; ++i )
12526  perm[invperm[i]] = i;
12527 
12528  /* apply permutation to canddata->quadelems */
12529  for( i = 0; i < canddata->nquadelems; ++i )
12530  {
12531  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
12532  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
12533  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
12534  {
12535  int tmp;
12536  tmp = canddata->quadelems[i].idx1;
12537  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
12538  canddata->quadelems[i].idx2 = tmp;
12539  }
12540  }
12541  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
12542  canddata->sorted = TRUE;
12543 
12544  /* check if children and linear coefficients in parent candidate and expression are the same */
12545  for( i = 0; i < nchildren; ++i )
12546  {
12547  if( children[i] != parentcands[p]->children[i] )
12548  break;
12549  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
12550  break;
12551  }
12552  if( i < nchildren )
12553  continue;
12554 
12555  assert(exprdata->nquadelems == canddata->nquadelems);
12556  for( i = 0; i < exprdata->nquadelems; ++i )
12557  {
12558  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
12559  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
12560  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
12561  break;
12562  }
12563  if( i == exprdata->nquadelems )
12564  {
12565  /* yeah, parentcands[p] is same quadratic expression as expr */
12566  *parent = parentcands[p];
12567  break;
12568  }
12569  }
12570 
12571  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12572  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12573 
12574  break;
12575  }
12576 
12577  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
12578  case SCIP_EXPR_POLYNOMIAL:
12579  {
12580  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
12581  SCIP_EXPRDATA_POLYNOMIAL* canddata;
12582  int* perm;
12583  int* invperm;
12584 
12585  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
12586 
12587  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
12588 
12589  /* sort exprchildren and childnodes and store inverse permutation in invperm */
12590  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12591  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12592  for( i = 0; i < nchildren; ++i )
12593  invperm[i] = i; /*lint !e644*/
12594 
12595  if( exprchildren != NULL )
12596  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12597  else
12598  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12599 
12600  /* compute permutation from its inverse */
12601  for( i = 0; i < nchildren; ++i )
12602  perm[invperm[i]] = i; /*lint !e644*/
12603 
12604  /* apply permutation to exprdata and sort again */
12605  polynomialdataApplyChildmap(exprdata, perm);
12606  polynomialdataSortMonomials(exprdata);
12607 
12608  for( p = 0; p < nparentcands; ++p )
12609  {
12610  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12611  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12612 
12613  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
12614  assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
12615  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12616 
12617  /* sort parentcands[p]->children and store inverse permutation in invperm */
12618  for( i = 0; i < nchildren; ++i )
12619  invperm[i] = i;
12620 
12621  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12622 
12623  /* compute permutation from its inverse */
12624  for( i = 0; i < nchildren; ++i )
12625  perm[invperm[i]] = i;
12626 
12627  /* apply permutation to canddata and sort again */
12628  polynomialdataApplyChildmap(canddata, perm);
12629  polynomialdataSortMonomials(canddata);
12630 
12631  /* check if children are equal */
12632  for( i = 0; i < nchildren; ++i )
12633  if( children[i] != parentcands[p]->children[i] )
12634  break;
12635  if( i < nchildren )
12636  continue;
12637 
12638  /* check if monomials are equal */
12639  for( i = 0; i < exprdata->nmonomials; ++i )
12640  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
12641  break;
12642  if( i == exprdata->nmonomials )
12643  {
12644  /* yeah, parentcands[p] is same polynomial expression as expr */
12645  *parent = parentcands[p];
12646  break;
12647  }
12648  }
12649 
12650  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12651  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12652 
12653  break;
12654  }
12655 
12656  case SCIP_EXPR_USER:
12657  {
12658  /* @todo need comparison function on user data to decide whether a parent candidate fits */
12659  break;
12660  }
12661 
12662  case SCIP_EXPR_VARIDX:
12663  case SCIP_EXPR_PARAM:
12664  case SCIP_EXPR_CONST:
12665  case SCIP_EXPR_LAST:
12666  SCIPerrorMessage("expression operand %d unexpected here\n", op);
12667  return SCIP_ERROR;
12668  }
12669 
12670  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
12671 
12672  return SCIP_OKAY;
12673 }
12674 
12675 /** adds an expression into an expression graph
12676  *
12677  * Enables corresponding nodes.
12678  */
12679 static
12681  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12682  SCIP_EXPR* expr, /**< expression to add */
12683  void** vars, /**< variables corresponding to VARIDX expressions */
12684  SCIP_Real* params, /**< parameter values */
12685  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
12686  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12687  )
12688 {
12689  SCIP_EXPRGRAPHNODE** childnodes;
12690  SCIP_Bool childisnew;
12691  SCIP_Bool nochildisnew;
12692  SCIP_EXPROPDATA opdata;
12693  int i;
12694 
12695  assert(exprgraph != NULL);
12696  assert(expr != NULL);
12697  assert(exprnode != NULL);
12698  assert(exprnodeisnew != NULL);
12699 
12700  if( expr->op == SCIP_EXPR_VARIDX )
12701  {
12702  /* find node corresponding to variable and add if not existing yet */
12703  assert(expr->nchildren == 0);
12704 
12705  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12706  assert(*exprnode != NULL);
12707  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12708  assert((*exprnode)->data.intval >= 0);
12709  assert((*exprnode)->data.intval < exprgraph->nvars);
12710  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12711 
12712  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12713 
12714  return SCIP_OKAY;
12715  }
12716 
12717  if( expr->op == SCIP_EXPR_CONST )
12718  {
12719  /* find node corresponding to constant and add if not existing yet */
12720  assert(expr->nchildren == 0);
12721 
12722  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12723  assert(*exprnode != NULL);
12724  assert((*exprnode)->op == SCIP_EXPR_CONST);
12725  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
12726 
12727  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12728 
12729  return SCIP_OKAY;
12730  }
12731 
12732  if( expr->op == SCIP_EXPR_PARAM )
12733  {
12734  /* find node corresponding to constant corresponding to parameter and add if not existing yet */
12735  assert(expr->nchildren == 0);
12736  assert(params != NULL);
12737 
12738  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, params[expr->data.intval], exprnode) );
12739  assert(*exprnode != NULL);
12740  assert((*exprnode)->op == SCIP_EXPR_CONST);
12741  assert((*exprnode)->data.dbl == params[expr->data.intval]); /*lint !e777*/
12742 
12743  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12744 
12745  return SCIP_OKAY;
12746  }
12747 
12748  /* expression should be variable or constant or have children */
12749  assert(expr->nchildren > 0);
12750 
12751  /* add children expressions into expression graph
12752  * check if we can find a common parent
12753  */
12754  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12755  nochildisnew = TRUE;
12756  for( i = 0; i < expr->nchildren; ++i )
12757  {
12758  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, params, &childnodes[i], &childisnew) ); /*lint !e644*/
12759  assert(childnodes[i] != NULL);
12760  nochildisnew &= !childisnew; /*lint !e514*/
12761  }
12762 
12763  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12764  if( nochildisnew )
12765  {
12766  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12767 
12768  if( *exprnode != NULL )
12769  {
12770  /* node already existing, make sure it is enabled */
12771  (*exprnode)->enabled = TRUE;
12772  *exprnodeisnew = FALSE;
12773 
12774  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12775  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12776  * SCIPdebugPrintf("\n");
12777  */
12778 
12779  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12780  return SCIP_OKAY;
12781  }
12782  }
12783 
12784  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12785 
12786  /* copy expression data */
12787  if( exprOpTable[expr->op].copydata != NULL )
12788  {
12789  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12790  }
12791  else
12792  {
12793  opdata = expr->data;
12794  }
12795 
12796  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12797  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12798  *exprnodeisnew = TRUE;
12799 
12800  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12801 
12802  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12803  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12804  * SCIPdebugPrintf("\n");
12805  */
12806 
12807  return SCIP_OKAY;
12808 }
12809 
12810 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12811 static
12813  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12814  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12815  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12816  )
12817 {
12818  SCIP_EXPRGRAPHNODE* node;
12819  int i;
12820  int p;
12821 
12822  assert(exprgraph != NULL);
12823  assert(clearreverseprop != NULL);
12824  assert(boundchanged != NULL);
12825 
12826  *boundchanged = FALSE;
12827  for( i = 0; i < exprgraph->nvars; ++i )
12828  {
12829  node = exprgraph->varnodes[i];
12830 
12831  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12832  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12833  {
12835  continue;
12836  }
12837 
12838  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12839  {
12840  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12841  SCIP_Real tmp;
12842 
12843  tmp = exprgraph->varbounds[i].inf;
12844  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12845  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12846  }
12847 
12848  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12849  +exprgraph->varbounds[i].sup > node->bounds.sup )
12850  {
12851  for( p = 0; p < node->nparents; ++p )
12853 
12854  node->bounds = exprgraph->varbounds[i];
12855  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12856 
12857  *boundchanged = TRUE;
12858 
12859  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12860  *clearreverseprop = TRUE;
12861  }
12862  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12863  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12864  {
12865  for( p = 0; p < node->nparents; ++p )
12867 
12868  node->bounds = exprgraph->varbounds[i];
12869  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12870 
12871  *boundchanged = TRUE;
12872  }
12873  else
12874  {
12875  node->bounds = exprgraph->varbounds[i];
12876  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12877  }
12878 
12880  }
12881 }
12882 
12883 /**@} */
12884 
12885 /**@name Expression graph node methods */
12886 /**@{ */
12887 
12888 /* In debug mode, the following methods are implemented as function calls to ensure
12889  * type validity.
12890  * In optimized mode, the methods are implemented as defines to improve performance.
12891  * However, we want to have them in the library anyways, so we have to undef the defines.
12892  */
12893 
12894 #undef SCIPexprgraphCaptureNode
12895 #undef SCIPexprgraphIsNodeEnabled
12896 #undef SCIPexprgraphGetNodeNChildren
12897 #undef SCIPexprgraphGetNodeChildren
12898 #undef SCIPexprgraphGetNodeNParents
12899 #undef SCIPexprgraphGetNodeParents
12900 #undef SCIPexprgraphGetNodeDepth
12901 #undef SCIPexprgraphGetNodePosition
12902 #undef SCIPexprgraphGetNodeOperator
12903 #undef SCIPexprgraphGetNodeOperatorIndex
12904 #undef SCIPexprgraphGetNodeOperatorReal
12905 #undef SCIPexprgraphGetNodeVar
12906 #undef SCIPexprgraphGetNodeRealPowerExponent
12907 #undef SCIPexprgraphGetNodeIntPowerExponent
12908 #undef SCIPexprgraphGetNodeSignPowerExponent
12909 #undef SCIPexprgraphGetNodeLinearCoefs
12910 #undef SCIPexprgraphGetNodeLinearConstant
12911 #undef SCIPexprgraphGetNodeQuadraticConstant
12912 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12913 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12914 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12915 #undef SCIPexprgraphGetNodePolynomialMonomials
12916 #undef SCIPexprgraphGetNodePolynomialNMonomials
12917 #undef SCIPexprgraphGetNodePolynomialConstant
12918 #undef SCIPexprgraphGetNodeUserData
12919 #undef SCIPexprgraphHasNodeUserEstimator
12920 #undef SCIPexprgraphGetNodeBounds
12921 #undef SCIPexprgraphGetNodeVal
12922 #undef SCIPexprgraphGetNodeCurvature
12923 
12924 /** captures node, i.e., increases number of uses */
12926  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12927  )
12928 {
12929  assert(node->nuses >= 0);
12930 
12931  SCIPdebugMessage("capture node %p\n", (void*)node);
12932 
12933  ++node->nuses;
12934 }
12935 
12936 /** returns whether a node is currently enabled */
12938  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12939  )
12940 {
12941  assert(node != NULL);
12942 
12943  return node->enabled;
12944 }
12945 
12946 /** gets number of children of a node in an expression graph */
12948  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12949  )
12950 {
12951  assert(node != NULL);
12952 
12953  return node->nchildren;
12954 }
12955 
12956 /** gets children of a node in an expression graph */
12958  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12959  )
12960 {
12961  assert(node != NULL);
12962 
12963  return node->children;
12964 }
12965 
12966 /** gets number of parents of a node in an expression graph */
12968  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12969  )
12970 {
12971  assert(node != NULL);
12972 
12973  return node->nparents;
12974 }
12975 
12976 /** gets parents of a node in an expression graph */
12978  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12979  )
12980 {
12981  assert(node != NULL);
12982 
12983  return node->parents;
12984 }
12985 
12986 /** gets depth of node in expression graph */
12988  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12989  )
12990 {
12991  assert(node != NULL);
12992 
12993  return node->depth;
12994 }
12995 
12996 /** gets position of node in expression graph at its depth level */
12998  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12999  )
13000 {
13001  assert(node != NULL);
13002 
13003  return node->pos;
13004 }
13005 
13006 /** gets operator of a node in an expression graph */
13008  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13009  )
13010 {
13011  assert(node != NULL);
13012 
13013  return node->op;
13014 }
13015 
13016 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
13018  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13019  )
13020 {
13021  assert(node != NULL);
13022  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
13023 
13024  return node->data.intval;
13025 }
13026 
13027 /** gives real belonging to a SCIP_EXPR_CONST operand */
13029  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13030  )
13031 {
13032  assert(node != NULL);
13033  assert(node->op == SCIP_EXPR_CONST);
13034 
13035  return node->data.dbl;
13036 }
13037 
13038 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
13040  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13041  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13042  )
13043 {
13044  assert(exprgraph != NULL);
13045  assert(node != NULL);
13046  assert(node->op == SCIP_EXPR_VARIDX);
13047  assert(node->data.intval >= 0);
13048  assert(node->data.intval < exprgraph->nvars);
13049 
13050  return exprgraph->vars[node->data.intval];
13051 }
13052 
13053 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
13055  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13056  )
13057 {
13058  assert(node != NULL);
13059  assert(node->op == SCIP_EXPR_REALPOWER);
13060 
13061  return node->data.dbl;
13062 }
13063 
13064 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
13066  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13067  )
13068 {
13069  assert(node != NULL);
13070  assert(node->op == SCIP_EXPR_INTPOWER);
13071 
13072  return node->data.intval;
13073 }
13074 
13075 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
13077  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13078  )
13079 {
13080  assert(node != NULL);
13081  assert(node->op == SCIP_EXPR_SIGNPOWER);
13082 
13083  return node->data.dbl;
13084 }
13085 
13086 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
13088  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13089  )
13090 {
13091  assert(node != NULL);
13092  assert(node->op == SCIP_EXPR_LINEAR);
13093 
13094  return (SCIP_Real*)node->data.data;
13095 }
13096 
13097 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
13099  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13100  )
13101 {
13102  assert(node != NULL);
13103  assert(node->op == SCIP_EXPR_LINEAR);
13104  assert(node->data.data != NULL);
13105 
13106  return ((SCIP_Real*)node->data.data)[node->nchildren];
13107 }
13108 
13109 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
13111  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13112  )
13113 {
13114  assert(node != NULL);
13115  assert(node->op == SCIP_EXPR_QUADRATIC);
13116  assert(node->data.data != NULL);
13117 
13118  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
13119 }
13120 
13121 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
13123  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13124  )
13125 {
13126  assert(node != NULL);
13127  assert(node->op == SCIP_EXPR_QUADRATIC);
13128  assert(node->data.data != NULL);
13129 
13130  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
13131 }
13132 
13133 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13135  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13136  )
13137 {
13138  assert(node != NULL);
13139  assert(node->op == SCIP_EXPR_QUADRATIC);
13140  assert(node->data.data != NULL);
13141 
13142  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
13143 }
13144 
13145 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13147  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13148  )
13149 {
13150  assert(node != NULL);
13151  assert(node->op == SCIP_EXPR_QUADRATIC);
13152  assert(node->data.data != NULL);
13153 
13154  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
13155 }
13156 
13157 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13159  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13160  )
13161 {
13162  assert(node != NULL);
13163  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13164  assert(node->data.data != NULL);
13165 
13166  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
13167 }
13168 
13169 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13171  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13172  )
13173 {
13174  assert(node != NULL);
13175  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13176  assert(node->data.data != NULL);
13177 
13178  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
13179 }
13180 
13181 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
13183  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13184  )
13185 {
13186  assert(node != NULL);
13187  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13188  assert(node->data.data != NULL);
13189 
13190  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
13191 }
13192 
13193 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
13194  *
13195  * Assumes that curvature of children and bounds of children and node itself are valid.
13196  */
13198  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13199  int monomialidx, /**< index of monomial */
13200  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
13201  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
13202  )
13203 {
13204  SCIP_EXPRDATA_MONOMIAL* monomial;
13205  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13206  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13207  SCIP_INTERVAL* childbounds = NULL;
13208  SCIP_EXPRCURV* childcurv = NULL;
13209  SCIP_EXPRGRAPHNODE* child;
13210  SCIP_RETCODE retcode = SCIP_OKAY;
13211  int i;
13212 
13213  assert(node != NULL);
13214  assert(node->depth >= 0); /* node should be in graph */
13215  assert(node->pos >= 0); /* node should be in graph */
13216  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13217  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
13218  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13219  assert(node->data.data != NULL);
13220  assert(monomialidx >= 0);
13221  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
13222  assert(curv != NULL);
13223 
13224  if( SCIPintervalIsEmpty(infinity, node->bounds) )
13225  {
13226  *curv = SCIP_EXPRCURV_LINEAR;
13227  return SCIP_OKAY;
13228  }
13229 
13230  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
13231  assert(monomial != NULL);
13232 
13233  /* if many children, get large enough memory to store children bounds */
13234  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13235  {
13236  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13237  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, monomial->nfactors), TERMINATE );
13238  }
13239  else
13240  {
13241  childbounds = childboundsstatic;
13242  childcurv = childcurvstatic;
13243  }
13244 
13245  /* assemble bounds and curvature of children */
13246  for( i = 0; i < monomial->nfactors; ++i )
13247  {
13248  child = node->children[monomial->childidxs[i]];
13249  assert(child != NULL);
13250 
13251  /* child should have valid and non-empty bounds */
13252  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13253  assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13254  /* nodes at depth 0 are always linear */
13255  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13256 
13257  childbounds[i] = child->bounds; /*lint !e644*/
13258  childcurv[i] = child->curv; /*lint !e644*/
13259  }
13260 
13261  /* check curvature */
13262  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13263  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13264 
13265  /* free memory, if allocated before */
13266 TERMINATE:
13267  if( childbounds != childboundsstatic )
13268  {
13269  BMSfreeMemoryArrayNull(&childbounds);
13270  BMSfreeMemoryArrayNull(&childcurv);
13271  }
13272 
13273  return retcode;
13274 }
13275 
13276 /** gives the user data belonging to a SCIP_EXPR_USER expression */
13278  SCIP_EXPRGRAPHNODE* node
13279  )
13280 {
13281  assert(node != NULL);
13282  assert(node->op == SCIP_EXPR_USER);
13283  assert(node->data.data != NULL);
13284 
13285  return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13286 }
13287 
13288 /** indicates whether a user expression has the estimator callback defined */
13290  SCIP_EXPRGRAPHNODE* node
13291  )
13292 {
13293  assert(node != NULL);
13294  assert(node->op == SCIP_EXPR_USER);
13295  assert(node->data.data != NULL);
13296 
13297  return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13298 }
13299 
13300 /** gets bounds of a node in an expression graph */
13302  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13303  )
13304 {
13305  assert(node != NULL);
13306 
13307  return node->bounds;
13308 }
13309 
13310 /** gets value of expression associated to node from last evaluation call */
13312  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13313  )
13314 {
13315  assert(node != NULL);
13316 
13317  return node->value;
13318 }
13319 
13320 /** gets curvature of expression associated to node from last curvature check call */
13322  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13323  )
13324 {
13325  assert(node != NULL);
13326 
13327  return node->curv;
13328 }
13329 
13330 /** creates an expression graph node */
13332  BMS_BLKMEM* blkmem, /**< block memory */
13333  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13334  SCIP_EXPROP op, /**< operator type of expression */
13335  ...
13336  )
13337 {
13338  va_list ap;
13339  SCIP_EXPROPDATA opdata;
13340 
13341  assert(blkmem != NULL);
13342  assert(node != NULL);
13343 
13344  *node = NULL;
13345 
13346  switch( op )
13347  {
13348  case SCIP_EXPR_VARIDX :
13349  case SCIP_EXPR_PARAM :
13350  case SCIP_EXPR_CONST :
13351  case SCIP_EXPR_LINEAR :
13352  case SCIP_EXPR_QUADRATIC :
13353  case SCIP_EXPR_POLYNOMIAL:
13354  case SCIP_EXPR_USER :
13355  {
13356  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
13357  SCIPABORT();
13358  return SCIP_ERROR; /*lint !e527*/
13359  }
13360 
13361  /* operands without data */
13362  case SCIP_EXPR_PLUS :
13363  case SCIP_EXPR_MINUS :
13364  case SCIP_EXPR_MUL :
13365  case SCIP_EXPR_DIV :
13366  case SCIP_EXPR_MIN :
13367  case SCIP_EXPR_MAX :
13368  case SCIP_EXPR_SQUARE :
13369  case SCIP_EXPR_SQRT :
13370  case SCIP_EXPR_EXP :
13371  case SCIP_EXPR_LOG :
13372  case SCIP_EXPR_SIN :
13373  case SCIP_EXPR_COS :
13374  case SCIP_EXPR_TAN :
13375  /* case SCIP_EXPR_ERF : */
13376  /* case SCIP_EXPR_ERFI: */
13377  case SCIP_EXPR_ABS :
13378  case SCIP_EXPR_SIGN :
13379  case SCIP_EXPR_SUM :
13380  case SCIP_EXPR_PRODUCT:
13381  opdata.data = NULL;
13382  break;
13383 
13384  case SCIP_EXPR_REALPOWER:
13385  case SCIP_EXPR_SIGNPOWER:
13386  {
13387  va_start(ap, op ); /*lint !e838*/
13388  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
13389  va_end( ap ); /*lint !e826*/
13390 
13391  break;
13392  }
13393 
13394  case SCIP_EXPR_INTPOWER:
13395  {
13396  va_start(ap, op ); /*lint !e838*/
13397  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
13398  va_end( ap ); /*lint !e826*/
13399 
13400  break;
13401  }
13402 
13403  case SCIP_EXPR_LAST:
13404  SCIPABORT();
13405  return SCIP_INVALIDDATA; /*lint !e527*/
13406  }
13407 
13408  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13409 
13410  return SCIP_OKAY;
13411 }
13412 
13413 /** creates an expression graph node for a linear expression */
13415  BMS_BLKMEM* blkmem, /**< block memory */
13416  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13417  int ncoefs, /**< number of coefficients */
13418  SCIP_Real* coefs, /**< coefficients of linear expression */
13419  SCIP_Real constant /**< constant of linear expression */
13420  )
13421 {
13422  SCIP_EXPROPDATA opdata;
13423  SCIP_Real* data;
13424 
13425  assert(blkmem != NULL);
13426  assert(node != NULL);
13427 
13428  /* we store the coefficients and the constant in a single array and make this our operand data */
13429  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13430  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
13431  data[ncoefs] = constant;
13432 
13433  opdata.data = data;
13434  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13435 
13436  return SCIP_OKAY;
13437 }
13438 
13439 /** creates an expression graph node for a quadratic expression */
13441  BMS_BLKMEM* blkmem, /**< block memory */
13442  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13443  int nchildren, /**< number of children */
13444  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
13445  int nquadelems, /**< number of quadratic elements */
13446  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
13447  SCIP_Real constant /**< constant */
13448  )
13449 {
13450  SCIP_EXPROPDATA opdata;
13452 
13453  assert(blkmem != NULL);
13454  assert(node != NULL);
13455  assert(quadelems != NULL || nquadelems == 0);
13456 
13457  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13458 
13459  opdata.data = data;
13460  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13461 
13462  return SCIP_OKAY;
13463 }
13464 
13465 /** creates an expression graph node for a polynomial expression */
13467  BMS_BLKMEM* blkmem, /**< block memory */
13468  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13469  int nmonomials, /**< number of monomials */
13470  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13471  SCIP_Real constant, /**< constant of polynomial */
13472  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13473  )
13474 {
13475  SCIP_EXPROPDATA opdata;
13477 
13478  assert(blkmem != NULL);
13479  assert(node != NULL);
13480  assert(monomials != NULL || nmonomials == 0);
13481 
13482  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13483 
13484  opdata.data = data;
13485  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13486 
13487  return SCIP_OKAY;
13488 }
13489 
13490 /** adds monomials to an expression graph node that is a polynomial expression */
13492  BMS_BLKMEM* blkmem, /**< block memory */
13493  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
13494  int nmonomials, /**< number of monomials */
13495  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13496  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13497  )
13498 {
13499  assert(blkmem != NULL);
13500  assert(node != NULL);
13502  assert(monomials != NULL || nmonomials == 0);
13503 
13504  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13505 
13506  return SCIP_OKAY;
13507 }
13508 
13509 /** creates an expression graph node for a user expression */
13511  BMS_BLKMEM* blkmem, /**< block memory */
13512  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13513  SCIP_USEREXPRDATA* data, /**< user data for expression, node assumes ownership */
13514  SCIP_EXPRINTCAPABILITY evalcapability, /**< evaluation capability */
13515  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
13516  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function */
13517  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
13518  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function */
13519  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13520  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13521  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
13522  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
13523  )
13524 {
13525  SCIP_EXPROPDATA opdata;
13526  SCIP_EXPRDATA_USER* exprdata;
13527 
13528  assert(blkmem != NULL);
13529  assert(node != NULL);
13530  assert(eval != NULL);
13531  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
13532  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13533  assert(copydata != NULL || data == NULL);
13534  assert(freedata != NULL || data == NULL);
13535 
13536  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13537 
13538  exprdata->userdata = data;
13539  exprdata->evalcapability = evalcapability;
13540  exprdata->eval = eval;
13541  exprdata->estimate = estimate;
13542  exprdata->inteval = inteval;
13543  exprdata->curv = curv;
13544  exprdata->prop = prop;
13545  exprdata->copydata = copydata;
13546  exprdata->freedata = freedata;
13547  exprdata->print = print;
13548 
13549  opdata.data = (void*) exprdata;
13550 
13551  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13552 
13553  return SCIP_OKAY;
13554 }
13555 
13556 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13557  *
13558  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13559  * If the node is a linear expression, it may be freed.
13560  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13561  * It is assumed that the user had captured the node.
13562  * It is assumed that the expression graph has been simplified before.
13563  */
13565  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13566  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
13567  int linvarssize, /**< length of linvars and lincoefs arrays */
13568  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
13569  void** linvars, /**< buffer to store variables of linear part */
13570  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
13571  SCIP_Real* constant /**< buffer to store constant part */
13572  )
13573 {
13574  int orignvars;
13575  int* varsusage;
13576  SCIP_EXPRGRAPHNODE* orignode;
13577  SCIP_Bool havechange;
13578  int i;
13579 
13580  assert(exprgraph != NULL);
13581  assert(node != NULL);
13582  assert(*node != NULL);
13583  assert((*node)->nuses > 0);
13584  assert(nlinvars != NULL);
13585  assert(linvars != NULL || linvarssize == 0);
13586  assert(lincoefs != NULL || linvarssize == 0);
13587  assert(constant != NULL);
13588 
13589  *constant = 0.0;
13590  *nlinvars = 0;
13591 
13592  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13593 
13594  /* do some obvious and easy cases */
13595  switch( (*node)->op )
13596  {
13597  case SCIP_EXPR_VARIDX:
13598  {
13599  if( linvarssize >= 1 )
13600  {
13601  *nlinvars = 1;
13602  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
13603  lincoefs[0] = 1.0; /*lint !e613*/
13604 
13605  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13606  }
13607  return SCIP_OKAY;
13608  }
13609 
13610  case SCIP_EXPR_CONST:
13611  {
13612  *constant = (*node)->data.dbl;
13613  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13614 
13615  return SCIP_OKAY;
13616  }
13617 
13618  case SCIP_EXPR_REALPOWER:
13619  case SCIP_EXPR_SIGNPOWER:
13620  {
13621  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13622  {
13623  *nlinvars = 1;
13624  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13625  lincoefs[0] = 1.0; /*lint !e613*/
13626 
13627  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13628  }
13629  return SCIP_OKAY;
13630  }
13631 
13632  case SCIP_EXPR_INTPOWER:
13633  {
13634  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13635  {
13636  *nlinvars = 1;
13637  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13638  lincoefs[0] = 1.0; /*lint !e613*/
13639 
13640  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13641  }
13642  return SCIP_OKAY;
13643  }
13644 
13645  case SCIP_EXPR_PLUS:
13646  {
13647  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13648  {
13649  *constant = (*node)->children[0]->data.dbl;
13650  *nlinvars = 1;
13651  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13652  lincoefs[0] = 1.0; /*lint !e613*/
13653 
13654  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13655 
13656  return SCIP_OKAY;
13657  }
13658  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13659  {
13660  *constant = (*node)->children[1]->data.dbl;
13661  *nlinvars = 1;
13662  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13663  lincoefs[0] = 1.0; /*lint !e613*/
13664 
13665  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13666 
13667  return SCIP_OKAY;
13668  }
13669  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13670  {
13671  *nlinvars = 2;
13672  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13673  lincoefs[0] = 1.0; /*lint !e613*/
13674  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13675  lincoefs[1] = 1.0; /*lint !e613*/
13676 
13677  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13678 
13679  return SCIP_OKAY;
13680  }
13681  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13682  {
13683  /* handle this one later */
13684  break;
13685  }
13686  return SCIP_OKAY;
13687  }
13688 
13689  case SCIP_EXPR_MINUS:
13690  {
13691  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13692  {
13693  *constant = (*node)->children[0]->data.dbl;
13694  *nlinvars = 1;
13695  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13696  lincoefs[0] = -1.0; /*lint !e613*/
13697 
13698  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13699 
13700  return SCIP_OKAY;
13701  }
13702  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13703  {
13704  *constant = -(*node)->children[1]->data.dbl;
13705  *nlinvars = 1;
13706  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13707  lincoefs[0] = 1.0; /*lint !e613*/
13708 
13709  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13710 
13711  return SCIP_OKAY;
13712  }
13713  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13714  {
13715  *nlinvars = 2;
13716  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13717  lincoefs[0] = 1.0; /*lint !e613*/
13718  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13719  lincoefs[1] = -1.0; /*lint !e613*/
13720 
13721  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13722 
13723  return SCIP_OKAY;
13724  }
13725  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13726  {
13727  /* handle this one later */
13728  break;
13729  }
13730  return SCIP_OKAY;
13731  }
13732 
13733  case SCIP_EXPR_MUL:
13734  {
13735  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13736  {
13737  *nlinvars = 1;
13738  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13739  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
13740 
13741  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13742  }
13743  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13744  {
13745  *nlinvars = 1;
13746  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13747  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
13748 
13749  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13750  }
13751  return SCIP_OKAY;
13752  }
13753 
13754  case SCIP_EXPR_DIV:
13755  {
13756  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13757  return SCIP_OKAY;
13758 
13759  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13760  {
13761  *nlinvars = 1;
13762  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13763  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
13764 
13765  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13766  }
13767  return SCIP_OKAY;
13768  }
13769 
13770  case SCIP_EXPR_SQUARE:
13771  case SCIP_EXPR_SQRT:
13772  case SCIP_EXPR_EXP:
13773  case SCIP_EXPR_LOG:
13774  case SCIP_EXPR_SIN:
13775  case SCIP_EXPR_COS:
13776  case SCIP_EXPR_TAN:
13777  /* case SCIP_EXPR_ERF: */
13778  /* case SCIP_EXPR_ERFI: */
13779  case SCIP_EXPR_ABS:
13780  case SCIP_EXPR_SIGN:
13781  case SCIP_EXPR_MIN:
13782  case SCIP_EXPR_MAX:
13783  return SCIP_OKAY;
13784 
13785  case SCIP_EXPR_PRODUCT:
13786  case SCIP_EXPR_USER:
13787  return SCIP_OKAY;
13788 
13789  case SCIP_EXPR_SUM:
13790  case SCIP_EXPR_LINEAR:
13791  case SCIP_EXPR_QUADRATIC:
13792  case SCIP_EXPR_POLYNOMIAL:
13793  default:
13794  {
13795  /* check if there is a child that is a variable */
13796  for( i = 0; i < (*node)->nchildren; ++i )
13797  {
13798  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13799  break;
13800  }
13801 
13802  if( i == (*node)->nchildren )
13803  return SCIP_OKAY;
13804 
13805  break;
13806  }
13807  } /*lint !e788*/
13808 
13809  /* count how often variables are used in this expression */
13810  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13811  orignvars = exprgraph->nvars;
13812  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13813  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
13814 
13815  exprgraphNodeGetVarsUsage(*node, varsusage);
13816 
13817  /* duplicate node if it has parents or more than one user */
13818  orignode = NULL;
13819  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13820  {
13821  SCIP_EXPROPDATA data;
13822 
13823  orignode = *node;
13824 
13825  if( exprOpTable[orignode->op].copydata != NULL )
13826  {
13827  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13828  }
13829  else
13830  data = orignode->data;
13831 
13832  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13833  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13834  SCIPexprgraphCaptureNode(*node);
13835  }
13836 
13837  havechange = FALSE;
13838  /* split up constant and linear part */
13839  switch( (*node)->op )
13840  {
13841  case SCIP_EXPR_PLUS:
13842  case SCIP_EXPR_MINUS:
13843  {
13844  SCIP_EXPRGRAPHNODE* varchild;
13845  SCIP_EXPRGRAPHNODE* otherchild;
13846  int varidx;
13847 
13848  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13849  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13850  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13851  assert(linvarssize >= 1);
13852 
13853  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13854  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13855  varidx = varchild->data.intval;
13856  /* if variable is used in other child (which should be nonlinear), we don't take it */
13857  if( varsusage[varidx] > 1 )
13858  break;
13859 
13860  /* add to linear variables */
13861  *nlinvars = 1;
13862  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13863  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13864  lincoefs[0] = -1.0; /*lint !e613*/
13865  else
13866  lincoefs[0] = 1.0; /*lint !e613*/
13867 
13868  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13869  {
13870  /* replace *node by otherchild */
13871  SCIPexprgraphCaptureNode(otherchild);
13872  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13873  *node = otherchild;
13874  }
13875  else
13876  {
13877  SCIP_Real* lindata;
13878 
13879  /* turn *node into linear expression -1.0 * otherchild */
13880 
13881  /* reduce to one child */
13882  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13883  (*node)->children[0] = otherchild;
13884  (*node)->nchildren = 1;
13885  (*node)->op = SCIP_EXPR_LINEAR;
13886 
13887  /* setup linear data -1.0 * child0 + 0.0 */
13888  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13889  lindata[0] = -1.0;
13890  lindata[1] = 0.0;
13891  (*node)->data.data = (void*)lindata;
13892 
13893  /* remove *node as parent of varchild */
13894  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13895  }
13896 
13897  havechange = TRUE;
13898 
13899  break;
13900  }
13901 
13902  case SCIP_EXPR_SUM:
13903  {
13904  int nchildren;
13905 
13906  i = 0;
13907  nchildren = (*node)->nchildren;
13908  while( i < nchildren )
13909  {
13910  /* sort out constants */
13911  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13912  {
13913  *constant += (*node)->children[i]->data.dbl;
13914  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13915 
13916  if( i < nchildren-1 )
13917  {
13918  (*node)->children[i] = (*node)->children[nchildren-1];
13919  (*node)->children[nchildren-1] = NULL;
13920  }
13921  --nchildren;
13922 
13923  continue;
13924  }
13925 
13926  /* keep every child that is not a constant or variable */
13927  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13928  {
13929  ++i;
13930  continue;
13931  }
13932 
13933  /* skip variables that are used in other parts of the expression */
13934  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13935  {
13936  ++i;
13937  continue;
13938  }
13939 
13940  /* move variable into linear part, if still space */
13941  if( *nlinvars < linvarssize )
13942  {
13943  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13944  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13945  ++*nlinvars;
13946 
13947  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13948  if( i < nchildren-1 )
13949  {
13950  (*node)->children[i] = (*node)->children[nchildren-1];
13951  (*node)->children[nchildren-1] = NULL;
13952  }
13953  --nchildren;
13954 
13955  continue;
13956  }
13957  }
13958  assert(i == nchildren);
13959 
13960  if( nchildren == 0 )
13961  {
13962  /* all children were removed */
13963  havechange = TRUE;
13964  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13965  (*node)->nchildren = 0;
13966  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13967  break;
13968  }
13969 
13970  if( nchildren < (*node)->nchildren )
13971  {
13972  /* some children were removed */
13973  havechange = TRUE;
13974  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13975  (*node)->nchildren = nchildren;
13976  }
13977 
13978  if( havechange && (*node)->nchildren == 1 )
13979  {
13980  /* replace node by its child */
13981  SCIP_EXPRGRAPHNODE* child;
13982 
13983  child = (*node)->children[0];
13984  SCIPexprgraphCaptureNode(child);
13985  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13986  *node = child;
13987 
13988  break;
13989  }
13990 
13991  break;
13992  }
13993 
13994  case SCIP_EXPR_LINEAR:
13995  {
13996  int nchildren;
13997  SCIP_Real* coefs;
13998 
13999  coefs = (SCIP_Real*)(*node)->data.data;
14000  assert(coefs != NULL);
14001 
14002  /* remove constant, if nonzero */
14003  if( coefs[(*node)->nchildren] != 0.0 )
14004  {
14005  *constant = coefs[(*node)->nchildren];
14006  coefs[(*node)->nchildren] = 0.0;
14007  havechange = TRUE;
14008  }
14009 
14010  i = 0;
14011  nchildren = (*node)->nchildren;
14012  while( i < nchildren )
14013  {
14014  /* sort out constants */
14015  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
14016  {
14017  *constant += coefs[i] * (*node)->children[i]->data.dbl;
14018  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14019 
14020  if( i < nchildren-1 )
14021  {
14022  (*node)->children[i] = (*node)->children[nchildren-1];
14023  (*node)->children[nchildren-1] = NULL;
14024  coefs[i] = coefs[nchildren-1];
14025  coefs[nchildren-1] = 0.0;
14026  }
14027  --nchildren;
14028 
14029  continue;
14030  }
14031 
14032  /* keep everything that is not a constant or variable */
14033  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14034  {
14035  ++i;
14036  continue;
14037  }
14038 
14039  /* skip variables that are used in other parts of the expression */
14040  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14041  {
14042  ++i;
14043  continue;
14044  }
14045 
14046  /* move variable into linear part, if still space */
14047  if( *nlinvars < linvarssize )
14048  {
14049  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14050  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
14051  ++*nlinvars;
14052 
14053  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14054  if( i < nchildren-1 )
14055  {
14056  (*node)->children[i] = (*node)->children[nchildren-1];
14057  (*node)->children[nchildren-1] = NULL;
14058  coefs[i] = coefs[nchildren-1];
14059  coefs[nchildren-1] = 0.0;
14060  }
14061  --nchildren;
14062 
14063  continue;
14064  }
14065  }
14066  assert(i == nchildren);
14067 
14068  if( nchildren == 0 )
14069  {
14070  /* all children were removed */
14071  havechange = TRUE;
14072  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14073  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
14074  (*node)->data.data = NULL;
14075  (*node)->nchildren = 0;
14076  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
14077  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14078  break;
14079  }
14080 
14081  if( nchildren < (*node)->nchildren )
14082  {
14083  /* some children were removed */
14084  havechange = TRUE;
14085  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14086  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
14087  coefs[nchildren] = 0.0;
14088  (*node)->data.data = (void*)coefs;
14089  (*node)->nchildren = nchildren;
14090  }
14091 
14092  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
14093  {
14094  /* replace node by its child */
14095  SCIP_EXPRGRAPHNODE* child;
14096 
14097  child = (*node)->children[0];
14098  SCIPexprgraphCaptureNode(child);
14099  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14100  *node = child;
14101 
14102  break;
14103  }
14104 
14105  break;
14106  }
14107 
14108  case SCIP_EXPR_QUADRATIC:
14109  {
14110  SCIP_EXPRDATA_QUADRATIC* quaddata;
14111  SCIP_Bool* childused;
14112  int* childmap;
14113  int nchildren;
14114 
14115  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
14116  assert(quaddata != NULL);
14117 
14118  /* remove constant, if nonzero */
14119  if( quaddata->constant != 0.0 )
14120  {
14121  *constant = quaddata->constant;
14122  quaddata->constant = 0.0;
14123  havechange = TRUE;
14124  }
14125 
14126  /* if there is no linear part or no space left for linear variables, then stop */
14127  if( quaddata->lincoefs != NULL || linvarssize == 0 )
14128  break;
14129 
14130  /* check which childs are used in quadratic terms */
14131  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14132  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14133 
14134  for( i = 0; i < quaddata->nquadelems; ++i )
14135  {
14136  childused[quaddata->quadelems[i].idx1] = TRUE;
14137  childused[quaddata->quadelems[i].idx2] = TRUE;
14138  }
14139 
14140  /* alloc space for mapping of children indices */
14141  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
14142 
14143  nchildren = (*node)->nchildren;
14144  for( i = 0; i < nchildren; ++i )
14145  {
14146  childmap[i] = i; /*lint !e644*/
14147  if( *nlinvars >= linvarssize )
14148  continue;
14149  /* skip child if not variable or also used in quadratic part or other parts of expression */
14150  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14151  continue;
14152  if( childused[i] )
14153  continue;
14154  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14155  continue;
14156 
14157  /* put variable into linear part */
14158  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14159  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
14160  quaddata->lincoefs[i] = 0.0;
14161  ++*nlinvars;
14162 
14163  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14164 
14165  /* move last child to position i */
14166  if( i < nchildren-1 )
14167  {
14168  (*node)->children[i] = (*node)->children[nchildren-1];
14169  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
14170  childused[i] = childused[nchildren-1];
14171  childmap[nchildren-1] = i;
14172  }
14173  --nchildren;
14174  childmap[i] = -1;
14175 
14176  havechange = TRUE;
14177  --i; /* look at i again */
14178  }
14179 
14180  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
14181 
14182  if( nchildren < (*node)->nchildren )
14183  {
14184  /* apply childmap to quadratic term */
14185  for( i = 0; i < quaddata->nquadelems; ++i )
14186  {
14187  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
14188  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
14189  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
14190  {
14191  int tmp;
14192  tmp = quaddata->quadelems[i].idx1;
14193  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
14194  quaddata->quadelems[i].idx2 = tmp;
14195  }
14196  }
14197  quaddata->sorted = FALSE;
14198  }
14199  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
14200 
14201  if( nchildren == 0 )
14202  {
14203  /* all children were removed (so it was actually a linear expression) */
14204  havechange = TRUE;
14205  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14206  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
14207  (*node)->data.data = NULL;
14208  (*node)->nchildren = 0;
14209  (*node)->op = SCIP_EXPR_SUM;
14210  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14211  break;
14212  }
14213 
14214  if( nchildren < (*node)->nchildren )
14215  {
14216  /* reduce number of children */
14217  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14218  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
14219  (*node)->nchildren = nchildren;
14220  }
14221 
14222  break;
14223  }
14224 
14225  case SCIP_EXPR_POLYNOMIAL:
14226  {
14227  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
14228  SCIP_EXPRDATA_MONOMIAL* monomial;
14229  SCIP_Bool* childused;
14230  int childidx;
14231  int j;
14232 
14233  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
14234  assert(polynomialdata != NULL);
14235 
14236  /* make sure linear monomials are merged */
14237  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14238 
14239  /* remove constant, if nonzero */
14240  if( polynomialdata->constant != 0.0 )
14241  {
14242  *constant = polynomialdata->constant;
14243  polynomialdata->constant = 0.0;
14244  havechange = TRUE;
14245  }
14246 
14247  /* if there is no space for linear variables, then stop */
14248  if( linvarssize == 0 )
14249  break;
14250 
14251  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14252  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14253  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14254  for( i = 0; i < polynomialdata->nmonomials; ++i )
14255  {
14256  monomial = polynomialdata->monomials[i];
14257  assert(monomial != NULL);
14258  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14259  continue;
14260  for( j = 0; j < monomial->nfactors; ++j )
14261  {
14262  assert(monomial->childidxs[j] >= 0);
14263  assert(monomial->childidxs[j] < (*node)->nchildren);
14264  childused[monomial->childidxs[j]] = TRUE;
14265  }
14266  }
14267 
14268  /* move linear monomials out of polynomial */
14269  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14270  {
14271  monomial = polynomialdata->monomials[i];
14272  assert(monomial != NULL);
14273 
14274  /* sort out constants */
14275  if( monomial->nfactors == 0 )
14276  {
14277  if( monomial->coef != 0.0 )
14278  {
14279  *constant += monomial->coef;
14280  havechange = TRUE;
14281  }
14282  continue;
14283  }
14284 
14285  if( monomial->nfactors != 1 )
14286  continue;
14287  if( monomial->exponents[0] != 1.0 )
14288  continue;
14289  childidx = monomial->childidxs[0];
14290  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14291  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14292  continue;
14293  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14294  continue;
14295 
14296  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14297 
14298  /* put variable into linear part */
14299  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
14300  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
14301  ++*nlinvars;
14302 
14303  monomial->coef = 0.0;
14304  monomial->nfactors = 0;
14305  polynomialdata->sorted = FALSE;
14306 
14307  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14308  (*node)->children[childidx] = NULL;
14309 
14310  havechange = TRUE;
14311  }
14312 
14313  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14314 
14315  if( *nlinvars > 0 )
14316  {
14317  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14318  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14320  }
14321 
14322  if( (*node)->nchildren == 0 )
14323  {
14324  assert(polynomialdata->nmonomials == 0);
14325  assert(polynomialdata->constant == 0.0);
14326  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14327  havechange = TRUE;
14328  break;
14329  }
14330 
14331  break;
14332  }
14333 
14334  default: ;
14335  } /*lint !e788*/
14336 
14337  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14338 
14339  if( orignode != NULL )
14340  {
14341  /* if node was duplicated, we need to forget about original or duplicate */
14342  if( !havechange )
14343  {
14344  /* if nothing has changed, then forget about duplicate */
14345  assert(*constant == 0.0);
14346  assert(*nlinvars == 0);
14347  assert(*node != NULL);
14348  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14349  *node = orignode;
14350  }
14351  else
14352  {
14353  /* if something changed, then release original node */
14354  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14355  }
14356  }
14357  else if( havechange && *node != NULL )
14358  {
14359  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14360  (*node)->value = SCIP_INVALID;
14361  (*node)->simplified = FALSE;
14362  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14363  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14364  exprgraph->needvarboundprop = TRUE;
14365  }
14366 
14367  return SCIP_OKAY;
14368 }
14369 
14370 /** moves parents from a one node to another node
14371  *
14372  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14373  * srcnode may be freed, if not captured.
14374  * It is assumed that targetnode represents the same expression as srcnode.
14375  */
14377  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14378  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
14379  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
14380  )
14381 {
14382  assert(exprgraph != NULL);
14383  assert(srcnode != NULL);
14384  assert(*srcnode != NULL);
14385  assert(targetnode != NULL);
14386 
14387  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14388  {
14389  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14390  {
14391  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14392  }
14393  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14394  }
14395  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14396 
14397  return SCIP_OKAY;
14398 }
14399 
14400 /** releases node, i.e., decreases number of uses
14401  *
14402  * node is freed if no parents and no other uses.
14403  * Children are recursively released if they have no other parents.
14404  * Nodes that are removed are also freed.
14405  * If node correspond to a variable, then the variable is removed from the expression graph;
14406  * similarly for constants.
14407  */
14409  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14410  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
14411  )
14412 {
14413  int i;
14414 
14415  assert(exprgraph != NULL);
14416  assert(node != NULL);
14417  assert(*node != NULL);
14418  assert((*node)->depth >= 0); /* node should be in graph */
14419  assert((*node)->pos >= 0); /* node should be in graph */
14420  assert((*node)->depth < exprgraph->depth);
14421  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14422  assert((*node)->nuses >= 1);
14423  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14424 
14425  SCIPdebugMessage("release node %p\n", (void*)*node);
14426 
14427  --(*node)->nuses;
14428 
14429  /* do nothing if node still has parents or is still in use */
14430  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14431  {
14432  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);
14433  *node = NULL;
14434  return SCIP_OKAY;
14435  }
14436 
14437  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14438 
14439  /* notify children about removal of its parent
14440  * they are also freed, if possible */
14441  for( i = 0; i < (*node)->nchildren; ++i )
14442  {
14443  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14444  (*node)->children[i] = NULL;
14445  }
14446 
14447  if( (*node)->op == SCIP_EXPR_VARIDX )
14448  {
14449  assert((*node)->depth == 0);
14450  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14451  }
14452  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14453  {
14454  int constidx;
14455 
14456  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14457  assert(constidx >= 0);
14458  assert(constidx < exprgraph->nconsts);
14459  assert(exprgraph->constnodes[constidx] == *node);
14460 
14461  /* move last constant to position constidx */
14462  if( constidx < exprgraph->nconsts-1 )
14463  {
14464  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14465  exprgraph->constssorted = (exprgraph->nconsts <= 2);
14466  }
14467  --exprgraph->nconsts;
14468  }
14469  else
14470  {
14471  /* only variables and constants are allowed at depth 0 */
14472  assert((*node)->depth > 0);
14473  }
14474 
14475  /* remove node from nodes array in expression graph */
14476  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14477  {
14478  /* move last node at depth of *node to position of *node */
14479  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14480  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14481 
14482  /* moving the node may change the order in the parents array of each child */
14483  for( i = 0; i < exprgraph->nodes[(*node)->depth][(*node)->pos]->nchildren; ++i )
14484  exprgraph->nodes[(*node)->depth][(*node)->pos]->children[i]->parentssorted = FALSE;
14485  }
14486  --exprgraph->nnodes[(*node)->depth];
14487 
14488  /* node is now not in graph anymore */
14489  (*node)->depth = -1;
14490  (*node)->pos = -1;
14491 
14492  /* free node */
14493  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14494 
14495  *node = NULL;
14496 
14497  return SCIP_OKAY;
14498 }
14499 
14500 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14501 /** frees a node of an expression graph */
14503  BMS_BLKMEM* blkmem, /**< block memory */
14504  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
14505  )
14506 {
14507  assert(blkmem != NULL);
14508  assert( node != NULL);
14509  assert(*node != NULL);
14510  assert((*node)->depth == -1); /* node should not be in graph anymore */
14511  assert((*node)->pos == -1); /* node should not be in graph anymore */
14512  assert((*node)->nuses == 0); /* node should not be in use */
14513 
14514  /* free operator data, if needed */
14515  if( exprOpTable[(*node)->op].freedata != NULL )
14516  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14517 
14518  /* free arrays of children and parent nodes */
14519  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14520  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
14521 
14522  /* free node struct */
14523  BMSfreeBlockMemory(blkmem, node);
14524 }
14525 
14526 /** enables a node and recursively all its children in an expression graph */
14528  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14529  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14530  )
14531 {
14532  int i;
14533 
14534  assert(exprgraph != NULL);
14535  assert(node != NULL);
14536  assert(node->depth >= 0);
14537  assert(node->pos >= 0);
14538 
14539  if( node->enabled )
14540  return;
14541 
14542  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14543 
14544  node->enabled = TRUE;
14545  for( i = 0; i < node->nchildren; ++i )
14546  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14547 
14548  /* make sure bounds are updated in next bound propagation round */
14549  SCIPintervalSetEntire(SCIP_REAL_MAX, &node->bounds);
14550  exprgraph->needvarboundprop = TRUE;
14551 }
14552 
14553 /** disables a node and recursively all children which have no enabled parents in an expression graph */
14555  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14556  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14557  )
14558 {
14559  int i;
14560 
14561  assert(exprgraph != NULL);
14562  assert(node != NULL);
14563  assert(node->depth >= 0);
14564  assert(node->pos >= 0);
14565 
14566  if( !node->enabled )
14567  return;
14568 
14569  /* workaround: don't disable nodes if there could be more users than the one who is disabling the node
14570  * otherwise, if there are several nonlinear constraints using the same expression graph node as root node,
14571  * we might get enabled constraints with disabled node
14572  */
14573  if( node->nuses > 1 )
14574  return;
14575 
14576  /* if all parents of node are disabled, then also node can be disabled */
14577  node->enabled = FALSE;
14578  for( i = 0; i < node->nparents; ++i )
14579  if( node->parents[i]->enabled )
14580  {
14581  node->enabled = TRUE;
14582  return;
14583  }
14584 
14585  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14586 
14587  for( i = 0; i < node->nchildren; ++i )
14588  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14589 }
14590 
14591 /** returns whether the node has siblings in the expression graph */
14593  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14594  )
14595 {
14596  int p;
14597 
14598  assert(node != NULL);
14599 
14600  for( p = 0; p < node->nparents; ++p )
14601  if( node->parents[p]->nchildren > 1 )
14602  return TRUE;
14603 
14604  return FALSE;
14605 }
14606 
14607 /** returns whether all children of an expression graph node are variable nodes
14608  *
14609  * Returns TRUE for nodes without children.
14610  */
14612  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14613  )
14614 {
14615  int i;
14616 
14617  assert(node != NULL);
14618 
14619  for( i = 0; i < node->nchildren; ++i )
14620  if( node->children[i]->op != SCIP_EXPR_VARIDX )
14621  return FALSE;
14622 
14623  return TRUE;
14624 }
14625 
14626 /** returns whether the node has an ancestor which has a nonlinear expression operand */
14628  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14629  )
14630 {
14631  int p;
14632 
14633  for( p = 0; p < node->nparents; ++p )
14634  {
14635  assert(node->parents[p]->depth > node->depth);
14636  switch( node->parents[p]->op )
14637  {
14638  case SCIP_EXPR_PLUS:
14639  case SCIP_EXPR_MINUS:
14640  case SCIP_EXPR_SUM:
14641  case SCIP_EXPR_LINEAR:
14643  return TRUE;
14644  break;
14645 
14646 #ifndef NDEBUG
14647  case SCIP_EXPR_VARIDX:
14648  case SCIP_EXPR_CONST:
14649  case SCIP_EXPR_PARAM:
14650  assert(0); /* these expressions cannot have children */
14651  break;
14652 #endif
14653 
14654  default:
14655  /* parent has nonlinear expression operand */
14656  return TRUE;
14657  }/*lint !e788*/
14658  }
14659 
14660  return FALSE;
14661 }
14662 
14663 /** prints an expression graph node */
14665  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14666  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14667  FILE* file /**< file to print to, or NULL for stdout */
14668  )
14669 {
14670  assert(node != NULL);
14671 
14672  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14673 }
14674 
14675 /** tightens the bounds in a node of the graph
14676  *
14677  * Preparation for reverse propagation.
14678  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14679  */
14681  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14682  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
14683  SCIP_INTERVAL nodebounds, /**< new bounds for node */
14684  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) */
14685  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14686  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14687  )
14688 {
14689  assert(exprgraph != NULL);
14690  assert(node != NULL);
14691  assert(node->depth >= 0);
14692  assert(node->pos >= 0);
14693  assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14694  assert(cutoff != NULL);
14695 
14696  *cutoff = FALSE;
14697 
14698  /* if node is disabled, then ignore new bounds */
14699  if( !node->enabled )
14700  {
14701  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14702  return;
14703  }
14704 
14705  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14706  (void*)node, node->depth, node->pos,
14707  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14708 
14709  /* bounds in node should be valid */
14710  assert(!(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
14711 
14712  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14713  {
14714  *cutoff = TRUE;
14715  SCIPdebugPrintf(" -> cutoff\n");
14716  return;
14717  }
14718 
14719  /* if minstrength is negative, always mark that node has recently tightened bounds,
14720  * if bounds are considerably improved or tightening leads to an empty interval,
14721  * mark that node has recently tightened bounds
14722  * if bounds are only slightly improved, set the status to tightened by parent,
14723  * so next propagateVarBound round will reset the bounds
14724  */
14725  if( minstrength < 0.0 )
14726  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE;
14727  else if(
14728  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14729  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14730  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT;
14731  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14732  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT;
14733 
14734  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14735  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14736 }
14737 
14738 /** ensures that bounds and curvature information in a node is uptodate
14739  *
14740  * Assumes that bounds and curvature in children are uptodate.
14741  */
14743  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14744  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14745  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14746  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14747  )
14748 {
14749  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14750  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14751  SCIP_INTERVAL* childbounds = NULL;
14752  SCIP_EXPRCURV* childcurv = NULL;
14753  SCIP_RETCODE retcode = SCIP_OKAY;
14754  int i;
14755 
14756  assert(node != NULL);
14757  assert(node->depth >= 0); /* node should be in graph */
14758  assert(node->pos >= 0); /* node should be in graph */
14759  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14760 
14761  if( node->depth == 0 )
14762  {
14763  /* we cannot update bound tightenings in variable nodes here */
14764  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14765  return SCIP_OKAY;
14766  }
14767 
14768  assert(node->op != SCIP_EXPR_VARIDX);
14769  assert(node->op != SCIP_EXPR_PARAM);
14770 
14771  /* if many children, get large enough memory to store children bounds */
14773  {
14774  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14775  SCIP_ALLOC_TERMINATE(retcode, BMSallocMemoryArray(&childcurv, node->nchildren), TERMINATE);
14776  }
14777  else
14778  {
14779  childbounds = childboundsstatic;
14780  childcurv = childcurvstatic;
14781  }
14782 
14783  /* assemble bounds and curvature of children */
14784  for( i = 0; i < node->nchildren; ++i )
14785  {
14786  /* child should have valid and non-empty bounds */
14788  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14789  /* nodes at depth 0 are always linear */
14790  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14791 
14792  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
14793  childcurv[i] = node->children[i]->curv; /*lint !e644*/
14794  }
14795 
14796  /* if we do not have valid bounds, then update
14797  * code below is copied from exprgraphNodeUpdateBounds */
14799  {
14800  SCIP_INTERVAL newbounds;
14801 
14802  /* calling interval evaluation function for this operand */
14803  assert( exprOpTable[node->op].inteval != NULL );
14804  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds), TERMINATE );
14805 
14806  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14807  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14808  *
14809  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14810  *
14811  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14812  */
14813  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14815  {
14816  for( i = 0; i < node->nparents; ++i )
14818 
14819  node->bounds = newbounds;
14820  }
14821  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14822  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14823  {
14824  for( i = 0; i < node->nparents; ++i )
14826 
14827  node->bounds = newbounds;
14828  }
14829  else
14830  {
14831  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14832  }
14833 
14834  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);
14835 
14836  /* node now has valid bounds */
14837  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
14838  }
14839 
14840  /* update curvature */
14841  if( SCIPintervalIsEmpty(infinity, node->bounds) )
14842  {
14843  node->curv = SCIP_EXPRCURV_LINEAR;
14844 
14845  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14846  }
14847  else
14848  {
14849  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv), TERMINATE );
14850 
14851  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14852  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14853  * SCIPdebugPrintf("\n");
14854  */
14855  }
14856 TERMINATE:
14857  /* free memory, if allocated before */
14858  if( childbounds != childboundsstatic )
14859  {
14860  BMSfreeMemoryArrayNull(&childbounds);
14861  BMSfreeMemoryArrayNull(&childcurv);
14862  }
14863 
14864  return retcode;
14865 }
14866 
14867 /**@} */
14868 
14869 /**@name Expression graph methods */
14870 /**@{ */
14871 
14872 /* In debug mode, the following methods are implemented as function calls to ensure
14873  * type validity.
14874  * In optimized mode, the methods are implemented as defines to improve performance.
14875  * However, we want to have them in the library anyways, so we have to undef the defines.
14876  */
14877 
14878 #undef SCIPexprgraphGetDepth
14879 #undef SCIPexprgraphGetNNodes
14880 #undef SCIPexprgraphGetNodes
14881 #undef SCIPexprgraphGetNVars
14882 #undef SCIPexprgraphGetVars
14883 #undef SCIPexprgraphGetVarNodes
14884 #undef SCIPexprgraphSetVarNodeValue
14885 #undef SCIPexprgraphSetVarsBounds
14886 #undef SCIPexprgraphSetVarBounds
14887 #undef SCIPexprgraphSetVarNodeBounds
14888 #undef SCIPexprgraphSetVarNodeLb
14889 #undef SCIPexprgraphSetVarNodeUb
14890 #undef SCIPexprgraphGetVarsBounds
14891 
14892 /** get current maximal depth of expression graph */
14894  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14895  )
14896 {
14897  assert(exprgraph != NULL);
14898 
14899  return exprgraph->depth;
14900 }
14901 
14902 /** gets array with number of nodes at each depth of expression graph */
14904  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14905  )
14906 {
14907  assert(exprgraph != NULL);
14908 
14909  return exprgraph->nnodes;
14910 }
14911 
14912 /** gets nodes of expression graph, one array per depth */
14914  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14915  )
14916 {
14917  assert(exprgraph != NULL);
14918 
14919  return exprgraph->nodes;
14920 }
14921 
14922 /** gets number of variables in expression graph */
14924  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14925  )
14926 {
14927  assert(exprgraph != NULL);
14928 
14929  return exprgraph->nvars;
14930 }
14931 
14932 /** gets array of variables in expression graph */
14934  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14935  )
14936 {
14937  assert(exprgraph != NULL);
14938 
14939  return exprgraph->vars;
14940 }
14941 
14942 /** gets array of expression graph nodes corresponding to variables */
14944  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14945  )
14946 {
14947  assert(exprgraph != NULL);
14948 
14949  return exprgraph->varnodes;
14950 }
14951 
14952 /** sets value for a single variable given as expression graph node */
14954  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14955  SCIP_Real value /**< new value for variable */
14956  )
14957 {
14958  assert(varnode != NULL);
14959  assert(varnode->op == SCIP_EXPR_VARIDX);
14960 
14961  varnode->value = value;
14962 }
14963 
14964 /** sets bounds for variables */
14966  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14967  SCIP_INTERVAL* varbounds /**< new bounds for variables */
14968  )
14969 {
14970  assert(exprgraph != NULL);
14971  assert(varbounds != NULL || exprgraph->nvars == 0);
14972 
14973  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
14974 }
14975 
14976 /** sets bounds for a single variable */
14978  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14979  void* var, /**< variable */
14980  SCIP_INTERVAL varbounds /**< new bounds of variable */
14981  )
14982 {
14983  int pos;
14984 
14985  assert(exprgraph != NULL);
14986  assert(var != NULL);
14987  assert(SCIPhashmapExists(exprgraph->varidxs, var));
14988 
14989  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
14990  assert(pos < exprgraph->nvars);
14991  assert(exprgraph->vars[pos] == var);
14992 
14993  exprgraph->varbounds[pos] = varbounds;
14994 }
14995 
14996 /** sets bounds for a single variable given as expression graph node */
14998  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14999  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15000  SCIP_INTERVAL varbounds /**< new bounds of variable */
15001  )
15002 {
15003  int pos;
15004 
15005  assert(exprgraph != NULL);
15006  assert(varnode != NULL);
15007 
15008  pos = varnode->data.intval;
15009  assert(pos >= 0);
15010  assert(pos < exprgraph->nvars);
15011  assert(exprgraph->varnodes[pos] == varnode);
15012 
15013  exprgraph->varbounds[pos] = varbounds;
15014 }
15015 
15016 /** sets lower bound for a single variable given as expression graph node */
15018  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15019  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15020  SCIP_Real lb /**< new lower bound for variable */
15021  )
15022 {
15023  int pos;
15024 
15025  assert(exprgraph != NULL);
15026  assert(varnode != NULL);
15027 
15028  pos = varnode->data.intval;
15029  assert(pos >= 0);
15030  assert(pos < exprgraph->nvars);
15031  assert(exprgraph->varnodes[pos] == varnode);
15032 
15033  exprgraph->varbounds[pos].inf = lb;
15034 }
15035 
15036 /** sets upper bound for a single variable given as expression graph node */
15038  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15039  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15040  SCIP_Real ub /**< new upper bound for variable */
15041  )
15042 {
15043  int pos;
15044 
15045  assert(exprgraph != NULL);
15046  assert(varnode != NULL);
15047 
15048  pos = varnode->data.intval;
15049  assert(pos >= 0);
15050  assert(pos < exprgraph->nvars);
15051  assert(exprgraph->varnodes[pos] == varnode);
15052 
15053  exprgraph->varbounds[pos].sup = ub;
15054 }
15055 
15056 /** gets bounds that are stored for all variables */
15058  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
15059  )
15060 {
15061  return exprgraph->varbounds;
15062 }
15063 
15064 /** creates an empty expression graph */
15066  BMS_BLKMEM* blkmem, /**< block memory */
15067  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
15068  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
15069  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
15070  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /**< callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
15071  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /**< callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
15072  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /**< callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
15073  void* userdata /**< user data to pass to callback functions */
15074  )
15075 {
15076  assert(blkmem != NULL);
15077  assert(exprgraph != NULL);
15078 
15079  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
15080  BMSclearMemory(*exprgraph);
15081  (*exprgraph)->blkmem = blkmem;
15082 
15083  /* create nodes's arrays */
15084  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
15085  assert((*exprgraph)->depth >= 1);
15086 
15087  /* create var's arrays and hashmap */
15088  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
15089  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, (*exprgraph)->varssize) );
15090 
15091  /* empty array of constants is sorted */
15092  (*exprgraph)->constssorted = TRUE;
15093 
15094  /* store callback functions and user data */
15095  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
15096  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
15097  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
15098  (*exprgraph)->userdata = userdata;
15099 
15100  return SCIP_OKAY;
15101 }
15102 
15103 /** frees an expression graph */
15105  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
15106  )
15107 {
15108  BMS_BLKMEM* blkmem;
15109  int d;
15110 
15111  assert( exprgraph != NULL);
15112  assert(*exprgraph != NULL);
15113  assert((*exprgraph)->nvars == 0);
15114  assert((*exprgraph)->nconsts == 0);
15115 
15116  blkmem = (*exprgraph)->blkmem;
15117  assert(blkmem != NULL);
15118 
15119  /* free nodes arrays */
15120  for( d = 0; d < (*exprgraph)->depth; ++d )
15121  {
15122  assert((*exprgraph)->nnodes[d] == 0);
15123  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
15124  }
15125  assert((*exprgraph)->nodes != NULL);
15126  assert((*exprgraph)->nnodes != NULL);
15127  assert((*exprgraph)->nodessize != NULL);
15128  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
15129  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
15130  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
15131 
15132  /* free variables arrays and hashmap */
15133  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
15134  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
15135  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
15136  SCIPhashmapFree(&(*exprgraph)->varidxs);
15137 
15138  /* free constants array */
15139  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
15140 
15141  /* free graph struct */
15142  BMSfreeBlockMemory(blkmem, exprgraph);
15143 
15144  return SCIP_OKAY;
15145 }
15146 
15147 /** adds an expression graph node to an expression graph
15148  *
15149  * Expression graph assumes ownership of node.
15150  * Children are notified about new parent.
15151  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
15152  */
15154  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15155  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
15156  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
15157  int nchildren, /**< number of children */
15158  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
15159  )
15160 {
15161  SCIP_Bool childvalsvalid;
15162  int depth;
15163  int i;
15164 
15165  assert(exprgraph != NULL);
15166  assert(node != NULL);
15167  assert(node->pos < 0); /* node should have no position in graph yet */
15168  assert(node->depth < 0); /* node should have no position in graph yet */
15169  assert(node->nchildren == 0); /* node should not have stored children yet */
15170  assert(node->children == NULL); /* node should not have stored children yet */
15171  assert(node->nparents == 0); /* node should not have parents stored yet */
15172  assert(children != NULL || nchildren == 0);
15173 
15174  /* choose depth as maximal depth of children + 1, and at least mindepth */
15175  depth = MAX(0, mindepth);
15176  for( i = 0; i < nchildren; ++i )
15177  {
15178  if( children[i]->depth >= depth ) /*lint !e613*/
15179  depth = children[i]->depth + 1; /*lint !e613*/
15180  }
15181 
15182  /* ensure that expression graph is deep enough */
15183  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
15184  assert(exprgraph->depth > depth);
15185 
15186  /* ensure enough space for nodes at depth depth */
15187  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
15188 
15189  /* add node to graph */
15190  node->depth = depth;
15191  node->pos = exprgraph->nnodes[depth];
15192  exprgraph->nodes[depth][node->pos] = node;
15193  ++exprgraph->nnodes[depth];
15194 
15195  /* add as parent to children
15196  * and check if children has valid values */
15197  childvalsvalid = TRUE;
15198  for( i = 0; i < nchildren; ++i )
15199  {
15200  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
15201  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
15202  }
15203  /* store children */
15204  if( nchildren > 0 )
15205  {
15206  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
15207  node->nchildren = nchildren;
15208  }
15209 
15210  if( node->op == SCIP_EXPR_CONST )
15211  {
15212  /* set bounds to constant value of node */
15214  SCIPintervalSet(&node->bounds, node->data.dbl);
15215  }
15216  else
15217  {
15218  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
15221  exprgraph->needvarboundprop = TRUE;
15222  }
15223 
15224  /* if not a variable, set value of node according to values of children (if all have valid values) */
15225  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
15226  {
15227  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15228  }
15229 
15230  return SCIP_OKAY;
15231 }
15232 
15233 /** adds variables to an expression graph, if not existing yet
15234  *
15235  * Also already existing nodes are enabled.
15236  */
15238  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15239  int nvars, /**< number of variables to add */
15240  void** vars, /**< variables to add */
15241  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
15242  )
15243 {
15244  SCIP_EXPRGRAPHNODE* node;
15245  SCIP_EXPROPDATA opdata;
15246  int i;
15247 
15248  assert(exprgraph != NULL);
15249  assert(exprgraph->depth >= 1);
15250  assert(vars != NULL || nvars == 0);
15251 
15252  /* 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 */
15253  if( exprgraph->nvars == 0 )
15254  {
15255  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15256  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15257  }
15258 
15259  for( i = 0; i < nvars; ++i )
15260  {
15261  /* skip variables that exist already */
15262  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15263  {
15264  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
15265  assert(node != NULL);
15266 
15267  /* enable node */
15268  node->enabled = TRUE;
15269 
15270  if( varnodes != NULL )
15271  varnodes[i] = node;
15272 
15273  continue;
15274  }
15275 
15276  /* create new variable expression */
15277  opdata.intval = exprgraph->nvars;
15278  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15279 
15280  /* add expression node to expression graph at depth 0 */
15281  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15282 
15283  /* add variable node to vars arrays and hashmap */
15284  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15285  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
15286  exprgraph->varnodes[exprgraph->nvars] = node;
15287  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15288  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[i], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15289  ++exprgraph->nvars;
15290 
15291  if( varnodes != NULL )
15292  varnodes[i] = node;
15293 
15294  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15295 
15296  /* call callback method, if set */
15297  if( exprgraph->exprgraphvaradded != NULL )
15298  {
15299  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
15300  }
15301  }
15302 
15303  return SCIP_OKAY;
15304 }
15305 
15306 /** adds a constant to an expression graph, if not existing yet
15307  *
15308  * Also already existing nodes are enabled.
15309  */
15311  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15312  SCIP_Real constant, /**< constant to add */
15313  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
15314  )
15315 {
15316  SCIP_EXPROPDATA opdata;
15317 
15318  assert(exprgraph != NULL);
15319  assert(constnode != NULL);
15320 
15321  /* check if there is already an expression for this constant */
15322  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15323  {
15324  assert(*constnode != NULL);
15325  assert((*constnode)->op == SCIP_EXPR_CONST);
15326  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15327  (*constnode)->enabled = TRUE;
15328  return SCIP_OKAY;
15329  }
15330 
15331  /* create new node for constant */
15332  opdata.dbl = constant;
15333  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15334 
15335  /* add node to expression graph at depth 0 */
15336  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15337  assert((*constnode)->depth == 0);
15338  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
15339 
15340  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15341  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15342  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15343  ++exprgraph->nconsts;
15344  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15345 
15346  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15347 
15348  return SCIP_OKAY;
15349 }
15350 
15351 /** adds sum of expression trees into expression graph
15352  *
15353  * node will also be captured.
15354  *
15355  * @note Parameters will be converted into constants
15356  */
15358  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15359  int nexprtrees, /**< number of expression trees to add */
15360  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
15361  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
15362  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
15363  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) */
15364  )
15365 {
15366  SCIP_Bool allone;
15367 
15368  assert(exprgraph != NULL);
15369  assert(nexprtrees > 0);
15370  assert(exprtrees != NULL);
15371  assert(rootnode != NULL);
15372  assert(rootnodeisnew != NULL);
15373 
15374  *rootnode = NULL;
15375 
15376  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15377  {
15378  assert(exprtrees[0] != NULL);
15379  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15380 
15381  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, exprtrees[0]->params, rootnode, rootnodeisnew) );
15382  }
15383  else
15384  {
15385  SCIP_EXPROP op;
15386  SCIP_EXPRGRAPHNODE** rootnodes;
15387  SCIP_Bool rootnodeisnew_;
15388  int i;
15389 
15390  *rootnodeisnew = TRUE;
15391  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15392 
15393  allone = TRUE;
15394  for( i = 0; i < nexprtrees; ++i )
15395  {
15396  assert(exprtrees[i] != NULL);
15397  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15398 
15399  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, exprtrees[i]->params, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
15400  assert(rootnodes[i] != NULL);
15401  *rootnodeisnew &= rootnodeisnew_;
15402 
15403  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
15404  }
15405 
15406  /* decide which operand we want to use for the root node */
15407  if( coefs == NULL || allone )
15408  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15409  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15410  op = SCIP_EXPR_MINUS;
15411  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15412  {
15413  SCIP_EXPRGRAPHNODE* tmp;
15414 
15415  tmp = rootnodes[0];
15416  rootnodes[0] = rootnodes[1];
15417  rootnodes[1] = tmp;
15418  op = SCIP_EXPR_MINUS;
15419  }
15420  else
15421  op = SCIP_EXPR_LINEAR;
15422 
15423  if( op != SCIP_EXPR_LINEAR )
15424  {
15425  SCIP_EXPROPDATA data;
15426  data.data = NULL;
15427 
15428  if( !*rootnodeisnew )
15429  {
15430  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15431  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15432  }
15433 
15434  if( *rootnode == NULL )
15435  {
15436  /* create new node for sum of rootnodes and add to exprgraph */
15437  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15438  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15439  *rootnodeisnew = TRUE;
15440  }
15441  else
15442  {
15443  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15444  *rootnodeisnew = FALSE;
15445  }
15446  }
15447  else
15448  {
15449  SCIP_EXPROPDATA data;
15450  SCIP_Real* lindata;
15451 
15452  assert(op == SCIP_EXPR_LINEAR);
15453 
15454  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15455  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15456  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
15457  lindata[nexprtrees] = 0.0;
15458  data.data = lindata;
15459 
15460  if( !*rootnodeisnew )
15461  {
15462  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15463  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15464  }
15465 
15466  if( *rootnode == NULL )
15467  {
15468  /* create new node for linear combination of rootnodes and add to exprgraph */
15469  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15470  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15471  *rootnodeisnew = TRUE;
15472  }
15473  else
15474  {
15475  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15476  *rootnodeisnew = FALSE;
15477  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15478  }
15479  }
15480 
15481  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15482  }
15483  assert(*rootnode != NULL);
15484 
15485  SCIPexprgraphCaptureNode(*rootnode);
15486 
15487  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15488  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15489 
15490  return SCIP_OKAY;
15491 }
15492 
15493 /** replaces variable in expression graph by a linear sum of variables
15494  *
15495  * Variables will be added if not in the graph yet.
15496  */
15498  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15499  void* var, /**< variable to replace */
15500  int ncoefs, /**< number of coefficients in linear term */
15501  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
15502  void** vars, /**< variables in linear term */
15503  SCIP_Real constant /**< constant offset */
15504  )
15505 {
15506  SCIP_EXPRGRAPHNODE* varnode;
15507  SCIP_Real* lindata;
15508  int varidx;
15509  int i;
15510 
15511  assert(exprgraph != NULL);
15512  assert(var != NULL);
15513  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15514  assert(coefs != NULL || ncoefs == 0);
15515  assert(vars != NULL || ncoefs == 0);
15516 
15517  varidx = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15518  assert(varidx < exprgraph->nvars);
15519  assert(exprgraph->vars[varidx] == var);
15520  varnode = exprgraph->varnodes[varidx];
15521  assert(varnode != NULL);
15522  assert(varnode->data.intval == varidx);
15523 
15524  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
15525  {
15526  /* variable is replaced by constant or variable */
15527  SCIP_EXPRGRAPHNODE* node;
15528 
15529  /* check if there is already a node for this constant or variable */
15530  node = NULL;
15531  if( ncoefs == 0 )
15532  {
15533  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15534  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
15535  }
15536  else
15537  {
15538  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
15539  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
15540  }
15541 
15542  if( node != NULL )
15543  {
15544  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15545 
15546  /* tell parents of varnode to replace child varnode by node, this may free varnode */
15547  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15548 
15549  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15550  if( varnode != NULL )
15551  {
15552  assert(varnode->nuses > 0);
15553  assert(varnode->nparents == 0);
15554 
15555  /* remove variable (but don't free it's node) from graph */
15556  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15557 
15558  /* move varnode up to depth 1 */
15559  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15560 
15561  /* turn into EXPR_SUM expression */
15562  varnode->op = SCIP_EXPR_SUM;
15563  varnode->data.data = NULL;
15564  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
15565  varnode->children[0] = node;
15566  varnode->nchildren = 1;
15567  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15568 
15569  varnode->value = node->value;
15570  varnode->bounds = node->bounds;
15571  varnode->boundstatus = (node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID) ? SCIP_EXPRBOUNDSTATUS_VALID : SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
15572  }
15573  }
15574  else if( ncoefs == 0 )
15575  {
15576  /* turn node into EXPR_CONST node */
15577 
15578  /* remove variable (but don't free it's node) from graph */
15579  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15580 
15581  /* convert into EXPR_CONST node */
15582  varnode->op = SCIP_EXPR_CONST;
15583  varnode->data.dbl = constant;
15584 
15585  varnode->value = constant;
15586  SCIPintervalSet(&varnode->bounds, constant);
15588 
15589  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15590  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15591  exprgraph->constnodes[exprgraph->nconsts] = varnode;
15592  ++exprgraph->nconsts;
15593  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15594  }
15595  else
15596  {
15597  /* turn node into EXPR_VARIDX node for new variable */
15598 
15599  /* remove variable (but don't free it's node) from graph */
15600  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15601 
15602  varnode->data.intval = exprgraph->nvars;
15603 
15604  /* add variable node to vars arrays and hashmap */
15605  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15606  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
15607  exprgraph->varnodes[exprgraph->nvars] = varnode;
15608  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15609  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[0], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15610  ++exprgraph->nvars;
15611 
15612  /* call callback method, if set */
15613  if( exprgraph->exprgraphvaradded != NULL )
15614  {
15615  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
15616  }
15617  }
15618 
15619  /* mark varnode and its parents as not simplified */
15620  if( varnode != NULL )
15621  {
15622  varnode->simplified = FALSE;
15623  for( i = 0; i < varnode->nparents; ++i )
15624  varnode->parents[i]->simplified = FALSE;
15625  }
15626 
15627  return SCIP_OKAY;
15628  }
15629 
15630  /* turn varnode into EXPR_LINEAR */
15631 
15632  /* remove variable (but don't free it's node) from graph */
15633  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15634 
15635  /* move varnode up to depth 1 */
15636  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15637 
15638  /* convert into EXPR_LINEAR node */
15639  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15640  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
15641  lindata[ncoefs] = constant;
15642  varnode->data.data = (void*)lindata;
15643  varnode->op = SCIP_EXPR_LINEAR;
15644 
15645  /* add nodes corresponding to vars to expression graph, if not existing yet */
15646  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15647  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15648  varnode->nchildren = ncoefs;
15649 
15650  /* notify vars about new parent varnode */
15651  for( i = 0; i < ncoefs; ++i )
15652  {
15653  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15654  }
15655 
15656  /* set value and bounds to invalid, curvature can remain (still linear) */
15657  varnode->value = SCIP_INVALID;
15659 
15660  /* mark varnode and its parents as not simplified */
15661  varnode->simplified = FALSE;
15662  for( i = 0; i < varnode->nparents; ++i )
15663  varnode->parents[i]->simplified = FALSE;
15664 
15665  return SCIP_OKAY;
15666 }
15667 
15668 /** finds expression graph node corresponding to a variable */
15670  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15671  void* var, /**< variable to search for */
15672  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15673  )
15674 {
15675  int pos;
15676 
15677  assert(exprgraph != NULL);
15678  assert(var != NULL);
15679  assert(varnode != NULL);
15680 
15681  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15682  {
15683  *varnode = NULL;
15684  return FALSE;
15685  }
15686 
15687  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15688  assert(pos < exprgraph->nvars);
15689 
15690  *varnode = exprgraph->varnodes[pos];
15691  assert(*varnode != NULL);
15692  assert((*varnode)->op == SCIP_EXPR_VARIDX);
15693 
15694  return TRUE;
15695 }
15696 
15697 /** finds expression graph node corresponding to a constant */
15699  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15700  SCIP_Real constant, /**< constant to search for */
15701  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15702  )
15703 {
15704  int left;
15705  int right;
15706  int middle;
15707 
15708  assert(exprgraph != NULL);
15709  assert(constnode != NULL);
15710  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
15711 
15712  exprgraphSortConstNodes(exprgraph);
15713  assert(exprgraph->constssorted);
15714 
15715  /* find node using binary search */
15716  left = 0;
15717  right = exprgraph->nconsts-1;
15718  *constnode = NULL;
15719 
15720  while( left <= right )
15721  {
15722  middle = (left+right)/2;
15723  assert(0 <= middle && middle < exprgraph->nconsts);
15724 
15725  if( constant < exprgraph->constnodes[middle]->data.dbl )
15726  right = middle - 1;
15727  else if( constant > exprgraph->constnodes[middle]->data.dbl )
15728  left = middle + 1;
15729  else
15730  {
15731  *constnode = exprgraph->constnodes[middle];
15732  break;
15733  }
15734  }
15735  if( left == right+1 )
15736  return FALSE;
15737 
15738  assert(*constnode != NULL);
15739  assert((*constnode)->op == SCIP_EXPR_CONST);
15740  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15741 
15742  return TRUE;
15743 }
15744 
15745 /** prints an expression graph in dot format */
15747  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15748  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15749  FILE* file, /**< file to print to, or NULL for stdout */
15750  const char** varnames /**< variable names, or NULL for generic names */
15751  )
15752 {
15753  int d;
15754  int i;
15755 
15756  assert(exprgraph != NULL);
15757 
15758  if( file == NULL )
15759  file = stdout;
15760 
15761  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15762  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15763 
15764  for( d = 0; d < exprgraph->depth; ++d )
15765  {
15766  if( exprgraph->nnodes[d] == 0 )
15767  continue;
15768 
15769  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15770  {
15771  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15772  }
15773  }
15774 
15775  /* tell dot that all nodes of depth 0 have the same rank */
15776  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15777  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15778  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15779  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15780 
15781  /* tell dot that all nodes without parent have the same rank */
15782  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15783  for( d = 0; d < exprgraph->depth; ++d )
15784  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15785  if( exprgraph->nodes[d][i]->nparents == 0 )
15786  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15787  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15788 
15789  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15790 
15791  return SCIP_OKAY;
15792 }
15793 
15794 /** evaluates nodes of expression graph for given values of variables */
15796  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15797  SCIP_Real* varvals /**< values for variables */
15798  )
15799 {
15800  int d;
15801  int i;
15802 
15803  assert(exprgraph != NULL);
15804  assert(varvals != NULL || exprgraph->nvars == 0);
15805 
15806  for( d = 0; d < exprgraph->depth; ++d )
15807  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15808  {
15809  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15810  }
15811 
15812  return SCIP_OKAY;
15813 }
15814 
15815 /** propagates bound changes in variables forward through the expression graph */
15817  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15818  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15819  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
15820  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15821  )
15822 {
15823  SCIP_EXPRGRAPHNODE* node;
15824  SCIP_Bool boundchanged;
15825  int d;
15826  int i;
15827 
15828  assert(exprgraph != NULL);
15829  assert(domainerror != NULL);
15830 
15831  *domainerror = FALSE;
15832 
15833  /* update bounds in varnodes of expression graph */
15834  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15835 
15836  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15837  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15838  {
15839  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15840  return SCIP_OKAY;
15841  }
15842 
15843  /* propagate bound changes, interrupt if we get to a node with empty bounds */
15844  for( d = 1; d < exprgraph->depth; ++d )
15845  {
15846  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15847  {
15848  node = exprgraph->nodes[d][i];
15849  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15850  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15851  {
15852  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15853  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15854  *domainerror = TRUE;
15855  return SCIP_OKAY;
15856  }
15857  }
15858  }
15859 
15860  exprgraph->needvarboundprop = FALSE;
15861 
15862  return SCIP_OKAY;
15863 }
15864 
15865 /** propagates bound changes in nodes backward through the graph
15866  *
15867  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15868  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15869  */
15871  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15872  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15873  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15874  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15875  )
15876 {
15877  SCIP_EXPRGRAPHNODE* node;
15878  int d;
15879  int i;
15880 
15881  assert(exprgraph != NULL);
15882  assert(cutoff != NULL);
15883 
15884  *cutoff = FALSE;
15885 
15886  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15887  {
15888  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15889  {
15890  node = exprgraph->nodes[d][i];
15891  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15892  }
15893  }
15894  if( *cutoff )
15895  return;
15896 }
15897 
15898 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15899  *
15900  * Implies update of bounds in expression graph.
15901  */
15903  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15904  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15905  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15906  )
15907 {
15908  SCIP_EXPRGRAPHNODE* node;
15909  SCIP_Bool boundchanged;
15910  int d;
15911  int i;
15912 
15913  assert(exprgraph != NULL);
15914 
15915  /* update bounds in varnodes of expression graph */
15916  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15917 
15918 #ifndef NDEBUG
15919  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15920  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15921 #endif
15922 
15923  for( d = 1; d < exprgraph->depth; ++d )
15924  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15925  {
15926  node = exprgraph->nodes[d][i];
15927  assert(node != NULL);
15928 
15929  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15930 
15931  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15932  {
15933  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15934  return SCIP_OKAY;
15935  }
15936  }
15937 
15938  return SCIP_OKAY;
15939 }
15940 
15941 /** aims at simplifying an expression graph
15942  *
15943  * 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)).
15944  */
15946  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15947  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15948  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15949  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15950  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15951  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15952  )
15953 {
15954  SCIP_EXPRGRAPHNODE* node;
15955  SCIP_Bool havechangenode;
15956  SCIP_Bool allsimplified;
15957  int d;
15958  int i;
15959  int j;
15960 
15961 #ifndef NDEBUG
15962  SCIP_Real* testx;
15963  SCIP_HASHMAP* testvalidx;
15964  SCIP_Real* testvals;
15965  SCIP_RANDNUMGEN* randnumgen;
15966  int testvalssize;
15967  int ntestvals;
15968 #endif
15969 
15970  assert(exprgraph != NULL);
15971  assert(eps >= 0.0);
15972  assert(havechange != NULL);
15973  assert(domainerror != NULL);
15974 
15975 #ifndef NDEBUG
15976  SCIP_CALL( SCIPrandomCreate(&randnumgen, exprgraph->blkmem, 862) ); /* see also #1848 */
15977  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
15978  testvals = NULL;
15979  ntestvals = 0;
15980  testvalssize = 0;
15981 
15982  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
15983  for( i = 0; i < exprgraph->nvars; ++i )
15984  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
15985  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
15986  for( d = 1; d < exprgraph->depth; ++d )
15987  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15988  {
15989  node = exprgraph->nodes[d][i];
15990  assert(node != NULL);
15991 
15992  /* 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 */
15993  if( node->nuses > 0 )
15994  {
15995  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
15996  SCIP_CALL( SCIPhashmapInsert(testvalidx, (void*)node, (void*)(size_t)ntestvals) );
15997  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
15998  ++ntestvals;
15999  }
16000  }
16001 
16002  SCIPrandomFree(&randnumgen, exprgraph->blkmem);
16003 #endif
16004 
16005 #ifdef SCIP_OUTPUT
16006  {
16007  FILE* file;
16008  file = fopen("exprgraph_beforesimplify.dot", "w");
16009  if( file != NULL )
16010  {
16011  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16012  fclose(file);
16013  }
16014  }
16015 #endif
16016 
16017  *havechange = FALSE; /* we have not changed any node yet */
16018  *domainerror = FALSE; /* no domain errors encountered so far */
16019  allsimplified = TRUE; /* all nodes we looked at are simplified */
16020 
16021  /* call node simplifier from bottom up
16022  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
16023  */
16024  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
16025  {
16026  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16027  {
16028  node = exprgraph->nodes[d][i];
16029  assert(node != NULL);
16030 
16031  havechangenode = FALSE; /* node did not change yet */
16032 
16033  if( node->op != SCIP_EXPR_CONST )
16034  {
16035  /* skip nodes that are already simplified */
16036  if( node->simplified )
16037  continue;
16038 
16039  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
16040 
16041  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
16042  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
16043  assert(node->simplified == TRUE);
16044  *havechange |= havechangenode;
16045  }
16046 
16047  /* if node was or has been converted into constant, may move to depth 0 */
16048  if( node->op == SCIP_EXPR_CONST )
16049  {
16050  SCIP_EXPRGRAPHNODE* constnode;
16051 
16052  if( !SCIPisFinite(node->value) ) /*lint !e777*/
16053  {
16054  SCIPdebugMessage("Expression graph simplify turned node into NaN or inf.\n");
16055  *domainerror = TRUE;
16056  break;
16057  }
16058 
16059  /* check if there is already a node for this constant */
16060  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
16061  {
16062  assert(constnode->op == SCIP_EXPR_CONST);
16063  assert(constnode->data.dbl == node->value); /*lint !e777*/
16064 
16065  if( node->nparents > 0 )
16066  {
16067  /* move parents of this node to constnode, node may be freed if not in use */
16068  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
16069  /* node should have no parents anymore, so it should have been freed if not in use */
16070  assert(node == NULL || node->nuses > 0);
16071  havechangenode = TRUE;
16072 
16073  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
16074  if( node == NULL )
16075  {
16076  --i;
16077  continue;
16078  }
16079  }
16080  assert(node != NULL);
16081  assert(node->nuses > 0);
16082 
16083  if( constnode->nuses == 0 )
16084  {
16085  /* move node to depth 0, adding it to constnodes */
16086  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16087 
16088  /* move parents of constnode to node, so constnode is freed */
16089  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
16090  assert(constnode == NULL);
16091  havechangenode = TRUE;
16092 
16093  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16094  --i;
16095  continue;
16096  }
16097  }
16098  else
16099  {
16100  /* move to depth 0, adding it to constnodes */
16101  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16102 
16103  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16104  --i;
16105  }
16106  }
16107 
16108  /* if there was a change, mark parents as not simplified */
16109  if( havechangenode )
16110  for( j = 0; j < node->nparents; ++j )
16111  node->parents[j]->simplified = FALSE;
16112  }
16113  } /*lint !e850*/
16114 
16115  /* if we did nothing, clean up and escape from here */
16116  if( allsimplified || *domainerror )
16117  goto EXPRGRAPHSIMPLIFY_CLEANUP;
16118 
16119  /* @todo find duplicate subexpressions in expression graph */
16120 
16121  /* unconvert polynomials into simpler expressions, where possible */
16122  for( d = 1; d < exprgraph->depth; ++d )
16123  {
16124  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16125  {
16126  node = exprgraph->nodes[d][i];
16127  assert(node != NULL);
16128 
16129  if( node->op != SCIP_EXPR_POLYNOMIAL )
16130  continue;
16131 
16132  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
16133 
16134  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
16135  {
16136  /* node is identity w.r.t only child
16137  * replace node as child of parents by child of node
16138  */
16139 
16140  for( j = 0; node != NULL && j < node->nparents; ++j )
16141  {
16142  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
16143  }
16144  /* node should have no parents anymore, so it should have been freed if not in use */
16145  assert(node == NULL || node->nuses > 0);
16146 
16147  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
16148  if( node == NULL )
16149  --i;
16150  }
16151  }
16152  } /*lint !e850*/
16153 
16154 #ifdef SCIP_OUTPUT
16155  {
16156  FILE* file;
16157  file = fopen("exprgraph_aftersimplify.dot", "w");
16158  if( file != NULL )
16159  {
16160  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16161  fclose(file);
16162  }
16163  }
16164 #endif
16165 
16166 #ifndef NDEBUG
16167  for( d = 1; d < exprgraph->depth; ++d )
16168  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16169  {
16170  int idx;
16171  SCIP_Real testval_before;
16172  SCIP_Real testval_after;
16173 
16174  node = exprgraph->nodes[d][i];
16175  assert(node != NULL);
16176 
16177  SCIP_CALL( exprgraphNodeEval(node, NULL) );
16178 
16179  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
16180  if( node->nuses > 0 )
16181  {
16182  assert(SCIPhashmapExists(testvalidx, (void*)node));
16183 
16184  idx = (int)(size_t)(void*)SCIPhashmapGetImage(testvalidx, (void*)node);
16185  assert(idx < ntestvals);
16186 
16187  testval_before = testvals[idx]; /*lint !e613*/
16188  testval_after = SCIPexprgraphGetNodeVal(node);
16189 
16190  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
16191  }
16192  }
16193 #endif
16194 
16195  EXPRGRAPHSIMPLIFY_CLEANUP:
16196 #ifndef NDEBUG
16197  BMSfreeMemoryArray(&testx);
16198  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
16199  SCIPhashmapFree(&testvalidx);
16200 #endif
16201 
16202  return SCIP_OKAY;
16203 }
16204 
16205 /** creates an expression tree from a given node in an expression graph */
16207  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16208  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
16209  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
16210  )
16211 {
16212  SCIP_EXPR* root;
16213  int nexprvars;
16214  int* varidx;
16215  int i;
16216 
16217  assert(exprgraph != NULL);
16218  assert(rootnode != NULL);
16219  assert(rootnode->depth >= 0);
16220  assert(rootnode->pos >= 0);
16221  assert(exprtree != NULL);
16222 
16223  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16224  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16225 
16226  /* initially, no variable appears in the expression tree */
16227  for( i = 0; i < exprgraph->nvars; ++i )
16228  varidx[i] = -1; /*lint !e644*/
16229  nexprvars = 0;
16230 
16231  /* create expression from the subgraph that has rootnode as root */
16232  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
16233 
16234  /* create expression tree for this expression */
16235  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
16236 
16237  /* copy variables into expression tree */
16238  if( nexprvars > 0 )
16239  {
16240  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
16241  for( i = 0; i < exprgraph->nvars; ++i )
16242  {
16243  assert(varidx[i] >= -1);
16244  assert(varidx[i] < nexprvars);
16245  if( varidx[i] >= 0 )
16246  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
16247  }
16248  }
16249 
16250  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16251 
16252  return SCIP_OKAY;
16253 }
16254 
16255 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16256  *
16257  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16258  */
16260  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16261  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16262  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16263  int* nexprtrees, /**< buffer to store number of expression trees */
16264  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16265  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16266  )
16267 {
16268  int ncomponents;
16269  int* childcomp;
16270  int* varcomp;
16271  int compnr;
16272  SCIP_Bool haveoverlap;
16273  int i;
16274  int j;
16275  int k;
16276 
16277  SCIP_EXPR** exprs;
16278  int nexprs;
16279  int* childmap;
16280  int* childmapinv;
16281  int* varidx;
16282  int nexprvars;
16283 
16284  assert(exprgraph != NULL);
16285  assert(node != NULL);
16286  assert(node->depth >= 0);
16287  assert(node->pos >= 0);
16288  assert(exprtreessize > 0);
16289  assert(nexprtrees != NULL);
16290  assert(exprtrees != NULL);
16291  assert(exprtreecoefs != NULL);
16292 
16293  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16294  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16295  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16296  ( node->op != SCIP_EXPR_PLUS &&
16297  node->op != SCIP_EXPR_MINUS &&
16298  node->op != SCIP_EXPR_SUM &&
16299  node->op != SCIP_EXPR_LINEAR &&
16300  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16301  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16302  {
16303  *nexprtrees = 1;
16304  exprtreecoefs[0] = 1.0;
16305  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16306 
16307  return SCIP_OKAY;
16308  }
16309 
16310  /* find components in node->children <-> variables graph */
16311  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16312  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16313  for( i = 0; i < exprgraph->nvars; ++i )
16314  varcomp[i] = -1; /*lint !e644*/
16315 
16316  haveoverlap = FALSE;
16317  for( i = 0; i < node->nchildren; ++i )
16318  {
16319  compnr = i;
16320  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
16321  assert(compnr >= 0);
16322  assert(compnr < node->nchildren);
16323  childcomp[i] = compnr;
16324 
16325  /* remember if component number was changed by CheckComponent */
16326  if( compnr != i )
16327  haveoverlap = TRUE;
16328  }
16329 
16330  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16331 
16332  if( node->op == SCIP_EXPR_QUADRATIC )
16333  {
16334  /* merge components for products of children from different components */
16336 
16337  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16338  assert(data != NULL);
16339 
16340  for( i = 0; i < data->nquadelems; ++i )
16341  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16342  {
16343  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16344  compnr = childcomp[data->quadelems[i].idx2];
16345  for( j = 0; j < node->nchildren; ++j )
16346  if( childcomp[j] == compnr )
16347  childcomp[j] = childcomp[data->quadelems[i].idx1];
16348  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16349  haveoverlap = TRUE;
16350  }
16351  }
16352  else if( node->op == SCIP_EXPR_POLYNOMIAL )
16353  {
16354  /* merge components for monomials of children from different components */
16356 
16357  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16358  assert(data != NULL);
16359 
16360  for( i = 0; i < data->nmonomials; ++i )
16361  for( j = 1; j < data->monomials[i]->nfactors; ++j )
16362  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16363  {
16364  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16365  compnr = childcomp[data->monomials[i]->childidxs[j]];
16366  for( k = 0; k < node->nchildren; ++k )
16367  if( childcomp[k] == compnr )
16368  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16369  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16370  haveoverlap = TRUE;
16371  }
16372  }
16373 
16374  if( haveoverlap )
16375  {
16376  /* some component numbers are unused, thus relabel and count final number of components */
16377  int* compmap;
16378 
16379  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16380  for( i = 0; i < node->nchildren; ++i )
16381  compmap[i] = -1; /*lint !e644*/
16382 
16383  ncomponents = 0;
16384  for( i = 0; i < node->nchildren; ++i )
16385  {
16386  if( compmap[childcomp[i]] == -1 )
16387  compmap[childcomp[i]] = ncomponents++;
16388  childcomp[i] = compmap[childcomp[i]];
16389  }
16390 
16391  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16392  }
16393  else
16394  {
16395  ncomponents = node->nchildren;
16396  }
16397 
16398  if( ncomponents == 1 )
16399  {
16400  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16401  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16402 
16403  *nexprtrees = 1;
16404  exprtreecoefs[0] = 1.0;
16405  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16406 
16407  return SCIP_OKAY;
16408  }
16409 
16410  if( ncomponents > exprtreessize )
16411  {
16412  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16413  for( i = 0; i < node->nchildren; ++i )
16414  if( childcomp[i] >= exprtreessize )
16415  childcomp[i] = exprtreessize-1;
16416  ncomponents = exprtreessize;
16417  }
16418 
16419  assert(ncomponents >= 2);
16420 
16421  /* setup expression trees for each component */
16422  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16423  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16424  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16425  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16426  for( i = 0; i < ncomponents; ++i )
16427  {
16428  /* initially, no variable appears in the expression tree */
16429  for( j = 0; j < exprgraph->nvars; ++j )
16430  varidx[j] = -1; /*lint !e644*/
16431  nexprvars = 0;
16432 
16433  /* collect expressions from children belonging to component i */
16434  nexprs = 0;
16435  for( j = 0; j < node->nchildren; ++j )
16436  {
16437  assert(childcomp[j] >= 0);
16438  assert(childcomp[j] < ncomponents);
16439  if( childcomp[j] != i )
16440  continue;
16441 
16442  /* create expression from the subgraph that has child j as root */
16443  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
16444  childmap[j] = nexprs; /*lint !e644*/
16445  childmapinv[nexprs] = j; /*lint !e644*/
16446  ++nexprs;
16447  }
16448 
16449  /* setup expression tree for component i */
16450  switch( node->op )
16451  {
16452  case SCIP_EXPR_PLUS:
16453  {
16454  assert(ncomponents == 2);
16455  assert(nexprs == 1);
16456 
16457  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16458  exprtreecoefs[i] = 1.0;
16459 
16460  break;
16461  }
16462 
16463  case SCIP_EXPR_MINUS:
16464  {
16465  assert(ncomponents == 2);
16466  assert(nexprs == 1);
16467 
16468  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16469  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16470  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16471  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16472 
16473  break;
16474  }
16475 
16476  case SCIP_EXPR_SUM:
16477  {
16478  if( nexprs == 1 )
16479  {
16480  /* component corresponds to exactly one child of node */
16481  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16482  }
16483  else
16484  {
16485  /* component corresponds to a sum of children of node */
16486  SCIP_EXPR* sumexpr;
16487 
16488  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16489  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16490  }
16491  exprtreecoefs[i] = 1.0;
16492 
16493  break;
16494  }
16495 
16496  case SCIP_EXPR_LINEAR:
16497  {
16498  SCIP_Real* nodecoefs;
16499  SCIP_EXPR* sumexpr;
16500 
16501  nodecoefs = (SCIP_Real*)node->data.data;
16502 
16503  /* if there is a constant, then we put it into the expression of the first component */
16504  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16505  {
16506  /* component corresponds to exactly one child of node */
16507  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16508  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16509  }
16510  else if( nexprs == 1 )
16511  {
16512  /* component corresponds to a sum of one child and a constant */
16513  assert(i == 0);
16514  assert(nodecoefs[node->nchildren] != 0.0);
16515  assert(nodecoefs[childmapinv[0]] != 0.0);
16516  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16517  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16518  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16519  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16520  }
16521  else
16522  {
16523  /* component corresponds to a linear combination of children of node */
16524 
16525  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16526  {
16527  /* if two expressions with equal sign, then create PLUS expression */
16528  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16529  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16530  }
16531  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16532  {
16533  /* if two expressions with opposite sign, then create MINUS expression */
16534  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16535  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16536  }
16537  else
16538  {
16539  /* assemble coefficents and create SUM or LINEAR expression */
16540  SCIP_Real* coefs;
16541  SCIP_Bool allcoefsequal;
16542 
16543  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16544  allcoefsequal = TRUE;
16545  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
16546  for( j = 0; j < nexprs; ++j )
16547  {
16548  coefs[j] = nodecoefs[childmapinv[j]];
16549  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
16550  }
16551 
16552  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16553  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16554  {
16555  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16556  exprtreecoefs[i] = coefs[0];
16557  }
16558  else
16559  {
16560  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16561  exprtreecoefs[i] = 1.0;
16562  }
16563 
16564  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16565  }
16566 
16567  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16568  }
16569 
16570  break;
16571  }
16572 
16573  case SCIP_EXPR_QUADRATIC:
16574  {
16575  SCIP_EXPR* quadexpr;
16577  SCIP_Real* lincoefs;
16578  SCIP_QUADELEM* quadelems;
16579  int nquadelems;
16580 
16581  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16582 
16583  exprtreecoefs[i] = 1.0;
16584 
16585  /* assemble coefficients corresponding to component i */
16586  if( nodedata->lincoefs != NULL )
16587  {
16588  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16589  for( j = 0; j < nexprs; ++j )
16590  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
16591  }
16592  else
16593  lincoefs = NULL;
16594 
16595  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16596  nquadelems = 0;
16597  for( j = 0; j < nodedata->nquadelems; ++j )
16598  {
16599  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16600  if( childcomp[nodedata->quadelems[j].idx1] != i )
16601  continue;
16602  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
16603  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16604  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16605  ++nquadelems;
16606  }
16607 
16608  /* put constant into first component */
16609  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16610  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16611 
16612  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16613  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16614 
16615  break;
16616  }
16617 
16618  case SCIP_EXPR_POLYNOMIAL:
16619  {
16620  SCIP_EXPR* polyexpr;
16622  SCIP_EXPRDATA_MONOMIAL** monomials;
16623  SCIP_Real constant;
16624  int nmonomials;
16625 
16626  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16627 
16628  constant = nodedata->constant;
16629  exprtreecoefs[i] = 1.0;
16630 
16631  /* collect monomials belonging to component i */
16632  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16633  nmonomials = 0;
16634  for( j = 0; j < nodedata->nmonomials; ++j )
16635  {
16636  if( nodedata->monomials[j]->nfactors == 0 )
16637  {
16638  constant += nodedata->monomials[j]->coef;
16639  continue;
16640  }
16641  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16642  continue;
16643 
16644  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16645  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
16646  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16647  {
16648  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16649  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16650  }
16651  ++nmonomials;
16652  }
16653 
16654  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16655  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16656 
16657  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16658 
16659  break;
16660  }
16661 
16662  default:
16663  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16664  return SCIP_ERROR;
16665  } /*lint !e788*/
16666 
16667  /* copy variables into expression tree */
16668  if( nexprvars > 0 )
16669  {
16670  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16671  for( j = 0; j < exprgraph->nvars; ++j )
16672  {
16673  assert(varidx[j] >= -1);
16674  assert(varidx[j] < nexprvars);
16675  if( varidx[j] >= 0 )
16676  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16677  }
16678  }
16679  }
16680 
16681  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16682  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16683  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16684  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16685  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16686 
16687  *nexprtrees = ncomponents;
16688 
16689  return SCIP_OKAY;
16690 }
16691 
16692 /** returns how often expression graph variables are used in a subtree of the expression graph */
16694  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16695  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
16696  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16697  )
16698 {
16699  assert(exprgraph != NULL);
16700  assert(node != NULL);
16701  assert(varsusage != NULL);
16702 
16703  BMSclearMemoryArray(varsusage, exprgraph->nvars);
16704 
16705  exprgraphNodeGetVarsUsage(node, varsusage);
16706 }
16707 
16708 /** gives the number of summands which the expression of an expression graph node consists of */
16710  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
16711  )
16712 {
16713  switch( node->op )
16714  {
16715  case SCIP_EXPR_PLUS:
16716  case SCIP_EXPR_MINUS:
16717  return 2;
16718 
16719  case SCIP_EXPR_SUM:
16720  case SCIP_EXPR_LINEAR:
16721  return node->nchildren;
16722 
16723  case SCIP_EXPR_QUADRATIC:
16724  {
16726 
16727  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16728  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16729  }
16730 
16731  case SCIP_EXPR_POLYNOMIAL:
16732  {
16734 
16735  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16736  return nodedata->nmonomials;
16737  }
16738 
16739  default:
16740  return 1;
16741  } /*lint !e788*/
16742 }
16743 
16744 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
16746  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16747  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16748  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16749  int* nexprtrees, /**< buffer to store number of expression trees */
16750  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16751  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16752  )
16753 {
16754  int* varidx;
16755  int nexprvars;
16756  int i;
16757 
16758  assert(exprgraph != NULL);
16759  assert(node != NULL);
16760  assert(node->depth >= 0);
16761  assert(node->pos >= 0);
16762  assert(exprtreessize > 0);
16763  assert(nexprtrees != NULL);
16764  assert(exprtrees != NULL);
16765  assert(exprtreecoefs != NULL);
16766 
16767  /* if node is not separable, fallback to SCIPexprgraphGetTree */
16768  if( node->op != SCIP_EXPR_PLUS &&
16769  node->op != SCIP_EXPR_MINUS &&
16770  node->op != SCIP_EXPR_SUM &&
16771  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16772  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16773  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16774  {
16775  *nexprtrees = 1;
16776  exprtreecoefs[0] = 1.0;
16777  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16778 
16779  return SCIP_OKAY;
16780  }
16781 
16782  switch( node->op )
16783  {
16784  case SCIP_EXPR_PLUS:
16785  {
16786  assert(exprtreessize >= 2);
16787 
16788  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16789  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16790 
16791  exprtreecoefs[0] = 1.0;
16792  exprtreecoefs[1] = 1.0;
16793 
16794  *nexprtrees = 2;
16795  break;
16796  }
16797 
16798  case SCIP_EXPR_MINUS:
16799  {
16800  assert(exprtreessize >= 2);
16801 
16802  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16803  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16804 
16805  exprtreecoefs[0] = 1.0;
16806  exprtreecoefs[1] = -1.0;
16807 
16808  *nexprtrees = 2;
16809  break;
16810  }
16811 
16812  case SCIP_EXPR_SUM:
16813  {
16814  assert(exprtreessize >= node->nchildren);
16815 
16816  for( i = 0; i < node->nchildren; ++i )
16817  {
16818  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16819  exprtreecoefs[i] = 1.0;
16820  }
16821 
16822  *nexprtrees = node->nchildren;
16823  break;
16824  }
16825 
16826  case SCIP_EXPR_LINEAR:
16827  {
16828  SCIP_Real* nodecoefs;
16829 
16830  assert(exprtreessize >= node->nchildren);
16831  assert(node->nchildren > 0);
16832 
16833  nodecoefs = (SCIP_Real*)node->data.data;
16834  assert(nodecoefs != NULL);
16835 
16836  for( i = 0; i < node->nchildren; ++i )
16837  {
16838  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16839  exprtreecoefs[i] = nodecoefs[i];
16840  }
16841 
16842  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16843  if( nodecoefs[node->nchildren] != 0.0 )
16844  {
16845  SCIP_EXPR* constexpr_;
16846 
16847  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16848  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16849  }
16850 
16851  *nexprtrees = node->nchildren;
16852  break;
16853  }
16854 
16855  case SCIP_EXPR_QUADRATIC:
16856  {
16858  SCIP_Real* lincoefs;
16859  SCIP_QUADELEM* quadelems;
16860  int nquadelems;
16861  SCIP_EXPR* expr;
16862  int j;
16863 
16864  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16865  lincoefs = nodedata->lincoefs;
16866  quadelems = nodedata->quadelems;
16867  nquadelems = nodedata->nquadelems;
16868 
16869  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16870  assert(node->nchildren > 0);
16871 
16872  *nexprtrees = 0;
16873  if( lincoefs != NULL )
16874  {
16875  for( i = 0; i < node->nchildren; ++i )
16876  {
16877  if( lincoefs[i] == 0.0 )
16878  continue;
16879  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16880  exprtreecoefs[*nexprtrees] = lincoefs[i];
16881  ++*nexprtrees;
16882  }
16883  }
16884 
16885  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16886  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16887 
16888  for( i = 0; i < nquadelems; ++i )
16889  {
16890  /* initially, no variable appears in the expression tree */
16891  for( j = 0; j < exprgraph->nvars; ++j )
16892  varidx[j] = -1; /*lint !e644*/
16893  nexprvars = 0;
16894 
16895  /* create expression from the subgraph at quadelems[i].idx1 */
16896  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16897 
16898  if( quadelems[i].idx1 == quadelems[i].idx2 )
16899  {
16900  /* create expression for square of expr */
16901  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16902  }
16903  else
16904  {
16905  SCIP_EXPR* expr2;
16906 
16907  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16908  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16909  /* create expression for product */
16910  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16911  }
16912 
16913  /* create expression tree for expr */
16914  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16915 
16916  /* copy variables into expression tree */
16917  if( nexprvars > 0 )
16918  {
16919  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16920  for( j = 0; j < exprgraph->nvars; ++j )
16921  {
16922  assert(varidx[j] >= -1);
16923  assert(varidx[j] < nexprvars);
16924  if( varidx[j] >= 0 )
16925  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16926  }
16927  }
16928 
16929  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16930 
16931  ++*nexprtrees;
16932  }
16933 
16934  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16935  if( nodedata->constant != 0.0 )
16936  {
16937  SCIP_EXPR* constexpr_;
16938 
16939  assert(*nexprtrees > 0);
16940  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16941  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16942  }
16943 
16944  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16945 
16946  break;
16947  }
16948 
16949  case SCIP_EXPR_POLYNOMIAL:
16950  {
16952  SCIP_EXPRDATA_MONOMIAL** monomials;
16953  SCIP_Real constant;
16954  int nmonomials;
16955  SCIP_EXPR* expr;
16956  int* childidxs;
16957  int j;
16958 
16959  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16960  monomials = nodedata->monomials;
16961  nmonomials = nodedata->nmonomials;
16962  constant = nodedata->constant;
16963 
16964  assert(exprtreessize >= nmonomials);
16965  assert(node->nchildren > 0);
16966 
16967  *nexprtrees = 0;
16968 
16969  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16970  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16971 
16972  for( i = 0; i < nmonomials; ++i )
16973  {
16974  /* initially, no variable appears in the expression tree */
16975  for( j = 0; j < exprgraph->nvars; ++j )
16976  varidx[j] = -1;
16977  nexprvars = 0;
16978 
16979  if( monomials[i]->nfactors == 1 )
16980  {
16981  /* create expression from the subgraph at only factor */
16982  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16983 
16984  /* put exponent in, if not 1.0 */
16985  if( monomials[i]->exponents[0] == 1.0 )
16986  ;
16987  else if( monomials[i]->exponents[0] == 2.0 )
16988  {
16989  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16990  }
16991  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
16992  {
16993  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
16994  }
16995  else
16996  {
16997  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
16998  }
16999  }
17000  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
17001  {
17002  SCIP_EXPR* expr2;
17003 
17004  /* create expressions for both factors */
17005  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17006  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
17007 
17008  /* create expression for product of factors */
17009  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
17010  }
17011  else
17012  {
17013  SCIP_EXPRDATA_MONOMIAL* monomial;
17014  SCIP_EXPR** exprs;
17015  int f;
17016 
17017  /* create expression for each factor, assemble varidx and nexprvars
17018  * create child indices (= identity) */
17019  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
17020  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
17021  for( f = 0; f < monomials[i]->nfactors; ++f )
17022  {
17023  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
17024  childidxs[f] = f; /*lint !e644*/
17025  }
17026 
17027  /* create monomial and polynomial expression for this monomial
17028  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
17029  */
17030  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
17031  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
17032  constant = 0.0;
17033 
17034  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
17035  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
17036  }
17037 
17038  /* create expression tree for expr */
17039  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
17040 
17041  /* copy variables into expression tree */
17042  if( nexprvars > 0 )
17043  {
17044  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
17045  for( j = 0; j < exprgraph->nvars; ++j )
17046  {
17047  assert(varidx[j] >= -1);
17048  assert(varidx[j] < nexprvars);
17049  if( varidx[j] >= 0 )
17050  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
17051  }
17052  }
17053 
17054  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
17055 
17056  ++*nexprtrees;
17057  }
17058 
17059  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
17060  if( constant != 0.0 )
17061  {
17062  SCIP_EXPR* constexpr_;
17063 
17064  assert(*nexprtrees > 0);
17065  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
17066  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
17067  }
17068 
17069  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
17070 
17071  break;
17072  }
17073 
17074  default:
17075  SCIPerrorMessage("unexpected operator type %d\n", node->op);
17076  return SCIP_ERROR;
17077  } /*lint !e788*/
17078 
17079  return SCIP_OKAY;
17080 }
17081 
17082 /**@} */
void SCIPintervalSignPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_EXPRBOUNDSTATUS_CHILDRELAXED
Definition: type_expr.h:211
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13311
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15816
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:9193
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15497
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:9074
void SCIPintervalMax(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:449
SCIP_EXPROPDATA data
Definition: struct_expr.h:51
static void exprgraphSortConstNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:9633
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14953
static SCIP_RETCODE exprgraphNodeAddParent(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9326
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:15153
void SCIPintervalSign(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define QUADELEMS_ISBETTER(a, b)
Definition: expr.c:9071
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:16745
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:15237
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:130
methods to interpret (evaluate) an expression tree "fast"
void SCIPexprtreePrint(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, const char **paramnames)
Definition: expr.c:8756
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5920
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:14742
static SCIP_RETCODE polynomialdataMultiplyByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:955
static SCIP_RETCODE exprUnconvertPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren, void **children)
Definition: expr.c:3761
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2265
SCIP_Bool constssorted
Definition: struct_expr.h:174
static SCIP_RETCODE doCheckCurvature(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_INTERVAL *childbounds, SCIP_Real *param, SCIP_EXPRCURV *curv, SCIP_EXPRCURV *childcurv, SCIP_INTERVAL *bounds)
Definition: expr.c:8026
static SCIP_RETCODE exprgraphNodeAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nexprs, SCIP_EXPRGRAPHNODE **exprs, int *childmap)
Definition: expr.c:9463
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12947
static SCIP_RETCODE exprgraphNodeCreateExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPR **expr, int *nexprvars, int *varidx)
Definition: expr.c:11769
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:219
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:14923
static SCIP_RETCODE exprgraphEnsureDepth(SCIP_EXPRGRAPH *exprgraph, int mindepth)
Definition: expr.c:12036
void SCIPsortPtrPtrRealInt(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_MAXSTRLEN
Definition: def.h:259
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:11439
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_VARTYPE_INTEGER_CHAR
Definition: def.h:121
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
SCIP_Real * exponents
Definition: struct_expr.h:95
#define SCIP_DECL_USEREXPREVAL(x)
Definition: type_expr.h:246
#define SCIP_DECL_USEREXPRPRINT(x)
Definition: type_expr.h:308
int SCIPexprgraphGetDepth(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14893
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:11370
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:15310
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:14997
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:12925
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:13440
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:15870
#define FALSE
Definition: def.h:64
void SCIPintervalMul(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2793
#define EPSEQ(x, y, eps)
Definition: def.h:174
#define EPSISINT(x, eps)
Definition: def.h:186
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT
Definition: type_expr.h:212
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:14943
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10289
static void exprgraphNodeCheckSeparabilityComponent(SCIP_EXPRGRAPHNODE *node, int *compnr, int nchildcomps, int *childcomps, int nvars, int *varcomps)
Definition: expr.c:11976
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10011
static SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11312
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13076
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static int calcGrowSize(int num)
Definition: expr.c:106
static SCIP_RETCODE exprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op, int nchildren, SCIP_EXPR **children, SCIP_EXPROPDATA opdata)
Definition: expr.c:3292
void SCIPsortPtrPtrInt(void **ptrarray1, void **ptrarray2, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPexprtreeCopy(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **targettree, SCIP_EXPRTREE *sourcetree)
Definition: expr.c:8812
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12967
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:13301
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15795
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:259
void SCIPintervalPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int * SCIPexprgraphGetNNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14903
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:105
SCIP_RETCODE SCIPexprEvalInt(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7927
#define EPSGE(x, y, eps)
Definition: def.h:178
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:10051
void SCIPexprSortMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:7116
static void polynomialdataApplyChildmap(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int *childmap)
Definition: expr.c:1158
#define SCIPdebugMessage
Definition: pub_message.h:77
static SCIP_DECL_EXPRCURV(exprcurvDefault)
Definition: expr.c:1418
SCIP_EXPRDATA_MONOMIAL ** monomials
Definition: struct_expr.h:80
static struct exprOpTableElement exprOpTable[]
Definition: expr.c:3216
#define SIGN(x)
Definition: expr.c:46
#define BMSduplicateBlockMemory(mem, ptr, source)
Definition: memory.h:441
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15357
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2931
SCIP_RETCODE SCIPexprMultiplyMonomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6891
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8771
SCIP_Bool SCIPquadelemSortedFind(SCIP_QUADELEM *quadelems, int idx1, int idx2, int nquadelems, int *pos)
Definition: expr.c:9218
unsigned int SCIP_EXPRINTCAPABILITY
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8642
BMS_BLKMEM * blkmem
Definition: struct_expr.h:157
SCIP_EXPRCURV curv
Definition: struct_expr.h:144
SCIP_EXPR * root
Definition: struct_expr.h:58
#define exprevalIntTan
Definition: expr.c:2120
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:15104
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13170
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:10004
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:12812
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:14376
SCIP_EXPRCURV SCIPexprcurvMonomial(int nfactors, SCIP_Real *exponents, int *factoridxs, SCIP_EXPRCURV *factorcurv, SCIP_INTERVAL *factorbounds)
Definition: expr.c:361
SCIP_EXPRDATA_MONOMIAL ** SCIPexprGetMonomials(SCIP_EXPR *expr)
Definition: expr.c:5864
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2014
static SCIP_DECL_EXPREVAL(exprevalVar)
Definition: expr.c:1427
public methods for expressions, expression trees, expression graphs, and related stuff ...
SCIP_EXPRCURV SCIPexprcurvMultiply(SCIP_Real factor, SCIP_EXPRCURV curvature)
Definition: expr.c:240
int SCIPexprGetMonomialNFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5910
int SCIPexprGetIntPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5767
void SCIPintervalSin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3025
#define SCIP_EXPRINTCAPABILITY_INTFUNCVALUE
SCIP_RETCODE SCIPexprtreeCheckCurvature(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:9003
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13007
static SCIP_RETCODE exprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op, SCIP_EXPROPDATA opdata)
Definition: expr.c:9704
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13158
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:15065
#define SCIP_ALLOC_ABORT(x)
Definition: def.h:340
#define SCIP_DECL_EXPRGRAPHVARADDED(x)
Definition: type_expr.h:181
SCIP_HASHMAP * varidxs
Definition: struct_expr.h:169
int SCIPexprgraphGetNodeOperatorIndex(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13017
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:102
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:13098
#define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize)
Definition: expr.c:87
SCIP_Real * params
Definition: struct_expr.h:62
#define BMSduplicateBlockMemoryArray(mem, ptr, source, num)
Definition: memory.h:443
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13182
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:14627
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13321
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:15698
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:14965
union SCIP_ExprOpData SCIP_EXPROPDATA
Definition: type_expr.h:90
static SCIP_Bool isUbBetter(SCIP_Real minstrength, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:169
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:129
SCIP_RETCODE SCIPexprgraphCheckCurvature(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop)
Definition: expr.c:15902
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:89
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:13510
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:14913
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16709
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:13289
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
SCIP_Real SCIPexprGetQuadConstant(SCIP_EXPR *expr)
Definition: expr.c:5827
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2826
static SCIP_RETCODE exprgraphNodeReplaceChild(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE **oldchild, SCIP_EXPRGRAPHNODE *newchild)
Definition: expr.c:9564
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:9350
static SCIP_Bool exprgraphNodeIsParent(SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9432
static void polynomialdataFree(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata)
Definition: expr.c:712
#define REALABS(x)
Definition: def.h:173
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:13414
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16259
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_CALL(x)
Definition: def.h:350
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12937
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:15057
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_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:14680
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:10111
#define SCIP_DECL_USEREXPRCURV(x)
Definition: type_expr.h:270
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:14592
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:13197
#define SCIP_DECL_USEREXPRESTIMATE(x)
Definition: type_expr.h:234
#define SCIP_DECL_USEREXPRPROP(x)
Definition: type_expr.h:282
SCIP_Real SCIPexprgraphGetNodeOperatorReal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13028
#define SCIP_EXPRBOUNDSTATUS_VALID
Definition: type_expr.h:209
SCIP_RETCODE SCIPexprAdd(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_Real coef1, SCIP_EXPR *term1, SCIP_Real coef2, SCIP_EXPR *term2, SCIP_Real constant)
Definition: expr.c:6246
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13110
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:446
SCIP_RETCODE SCIPexprMultiplyPolynomialByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR *factor, int *childmap)
Definition: expr.c:6739
void SCIPexprMergeMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real eps)
Definition: expr.c:6956
void SCIPintervalCos(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_EXPRINTCAPABILITY SCIPexprGetUserEvalCapability(SCIP_EXPR *expr)
Definition: expr.c:5962
public data structures and miscellaneous methods
static void polynomialdataMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:833
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:5713
SCIP_Real SCIPexprGetSignPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5778
SCIP_EXPRGRAPHNODE ** children
Definition: struct_expr.h:128
#define SCIP_Bool
Definition: def.h:61
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:10046
SCIP_USEREXPRDATA * userdata
Definition: struct_expr.h:103
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14611
SCIPInterval sin(const SCIPInterval &x)
#define BMSallocBlockMemoryArray(mem, ptr, num)
Definition: memory.h:435
void SCIPexprSortQuadElems(SCIP_EXPR *expr)
Definition: expr.c:6620
static SCIP_RETCODE monomialdataEnsureFactorsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomialdata, int minsize)
Definition: expr.c:603
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:15017
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:9381
BMS_BLKMEM * blkmem
Definition: struct_expr.h:57
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8657
SCIP_RETCODE SCIPexprtreeFreeInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8680
void SCIPintervalSolveBivariateQuadExpressionAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
#define BMSfreeBlockMemoryArray(mem, ptr, num)
Definition: memory.h:448
void SCIPquadelemSqueeze(SCIP_QUADELEM *quadelems, int nquadelems, int *nquadelemsnew)
Definition: expr.c:9270
SCIP_Bool SCIPexprHasUserEstimator(SCIP_EXPR *expr)
Definition: expr.c:5951
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10082
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
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:16693
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:15037
static SCIP_Bool exprgraphFindConstNodePos(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *pos)
Definition: expr.c:9649
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:13564
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:176
void SCIPexprgraphFreeNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14502
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:10205
#define SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED
Definition: type_expr.h:210
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14554
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:116
SCIPInterval log(const SCIPInterval &x)
SCIP_USEREXPRDATA * SCIPexprGetUserData(SCIP_EXPR *expr)
Definition: expr.c:5940
SCIP_RETCODE SCIPexprtreeAddExpr(SCIP_EXPRTREE *tree, SCIP_EXPR *expr, SCIP_Bool copyexpr)
Definition: expr.c:8980
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2326
#define SCIP_EXPR_DEGREEINFINITY
Definition: type_expr.h:114
SCIP_EXPROPDATA data
Definition: struct_expr.h:120
SCIP_EXPRGRAPHNODE ** parents
Definition: struct_expr.h:133
static long * number
void SCIPintervalAbs(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define BMSclearMemory(ptr)
Definition: memory.h:111
SCIP_Real SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5900
static SCIP_RETCODE polynomialdataCopy(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *sourcepolynomialdata)
Definition: expr.c:675
static SCIP_RETCODE polynomialdataExpandMonomialFactor(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int monomialpos, int factorpos, SCIP_EXPRDATA_POLYNOMIAL *factorpolynomial, int *childmap, int maxexpansionexponent, SCIP_Bool *success)
Definition: expr.c:1187
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13039
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:9388
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13122
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2064
#define SCIP_REAL_MAX
Definition: def.h:150
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:13065
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12977
SCIP_QUADELEM * quadelems
Definition: struct_expr.h:71
static void exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:9355
#define EPSLT(x, y, eps)
Definition: def.h:175
#define SCIP_DECL_EXPRGRAPHVARREMOVE(x)
Definition: type_expr.h:191
static SCIP_RETCODE exprgraphAddExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPR *expr, void **vars, SCIP_Real *params, SCIP_EXPRGRAPHNODE **exprnode, SCIP_Bool *exprnodeisnew)
Definition: expr.c:12680
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:177
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:93
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:122
SCIP_EXPRINTDATA * interpreterdata
Definition: struct_expr.h:63
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3041
#define exprcurvCos
Definition: expr.c:2105
SCIP_Bool SCIPexprgraphFindVarNode(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_EXPRGRAPHNODE **varnode)
Definition: expr.c:15669
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8204
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13087
#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:12997
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:13491
SCIP_Bool parentssorted
Definition: struct_expr.h:134
#define SCIP_VARTYPE_CONTINUOUS_CHAR
Definition: def.h:123
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:13466
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:13277
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:13331
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:14408
int SCIPexprGetNMonomials(SCIP_EXPR *expr)
Definition: expr.c:5876
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE
Definition: type_expr.h:214
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:608
SCIP_RETCODE SCIPhashmapSetImage(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2971
SCIP_RETCODE SCIPexprtreeSimplify(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:8926
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:16206
#define SCIP_DECL_USEREXPRCOPYDATA(x)
Definition: type_expr.h:291
#define SCIP_Real
Definition: def.h:149
#define EPSROUND(x, eps)
Definition: def.h:184
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:371
SCIP_RETCODE SCIPrandomCreate(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem, unsigned int initialseed)
Definition: misc.c:9334
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12957
#define SCIP_INVALID
Definition: def.h:169
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:14664
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:9029
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:1768
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:10090
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:120
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:15945
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:12116
static SCIP_RETCODE exprparseFindClosingParenthesis(const char *str, const char **endptr, int length)
Definition: expr.c:5025
SCIP_RETCODE SCIPexprAddToLinear(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nchildren, SCIP_Real *coefs, SCIP_EXPR **children, SCIP_Real constant)
Definition: expr.c:6539
static SCIP_RETCODE exprsimplifyAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nexprs, SCIP_EXPR **exprs, SCIP_Bool comparechildren, SCIP_Real eps, int *childmap)
Definition: expr.c:4146
#define nnodes
Definition: gastrans.c:65
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:433
SCIP_RETCODE SCIPexprMultiplyPolynomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6716
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13054
SCIP_RETCODE SCIPexprintFreeData(SCIP_EXPRINTDATA **interpreterdata)
#define EPSFLOOR(x, eps)
Definition: def.h:182
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2874
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:112
static SCIP_DECL_HASHGETKEY(exprparseVarTableGetKey)
Definition: expr.c:4914
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:419
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13146
#define SCIP_ALLOC_TERMINATE(retcode, x, TERM)
Definition: def.h:381
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:329
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14933
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT
Definition: type_expr.h:213
SCIP_RETCODE SCIPexprCreateLinear(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:6502
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_ALLOC(x)
Definition: def.h:361
#define SCIPABORT()
Definition: def.h:322
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:9083
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:9748
#define SCIP_DECL_USEREXPRFREEDATA(x)
Definition: type_expr.h:299
static SCIP_RETCODE exprgraphFindParentByOperator(SCIP_EXPRGRAPH *exprgraph, int nchildren, SCIP_EXPRGRAPHNODE **children, SCIP_EXPROP op, SCIP_EXPROPDATA opdata, SCIP_EXPR **exprchildren, SCIP_EXPRGRAPHNODE **parent)
Definition: expr.c:12212
static void exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:11951
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15746
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:439
void SCIPintervalSetRoundingModeDownwards(void)
#define EPSZ(x, eps)
Definition: def.h:179
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:12987
#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:14977
void SCIPsortIntReal(int *intarray, SCIP_Real *realarray, int len)
static SCIP_RETCODE exprgraphRemoveVar(SCIP_EXPRGRAPH *exprgraph, int varidx)
Definition: expr.c:12063
#define SCIP_DECL_EXPRGRAPHVARCHGIDX(x)
Definition: type_expr.h:203
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
void SCIPexprgraphEnableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14527
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13134