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-2020 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file nlpi/expr.c
17  * @ingroup OTHER_CFILES
18  * @brief methods for expressions, expression trees, expression graphs, and related
19  * @author Stefan Vigerske
20  * @author Thorsten Gellermann
21  * @author Ingmar Vierhaus (exprparse)
22  */
23 
24 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
25 
26 #include <stdarg.h>
27 #include <string.h>
28 #include <math.h>
29 #include <ctype.h>
30 
31 #include "nlpi/pub_expr.h"
32 #include "nlpi/struct_expr.h"
33 #include "nlpi/exprinterpret.h"
34 
35 #include "scip/intervalarith.h"
36 #include "scip/pub_misc.h"
37 #include "scip/misc.h"
38 #include "scip/pub_message.h"
39 
40 
41 #define SCIP_EXPRESSION_MAXCHILDEST 16 /**< estimate on maximal number of children */
42 
43 /** sign of a value (-1 or +1)
44  *
45  * 0.0 has sign +1
46  */
47 #define SIGN(x) ((x) >= 0.0 ? 1.0 : -1.0)
48 
49 /** ensures that a block memory array has at least a given size
50  *
51  * if cursize is 0, then *array1 can be NULL
52  */
53 #define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize) \
54  do { \
55  int __newsize; \
56  assert((blkmem) != NULL); \
57  if( *(cursize) >= (minsize) ) \
58  break; \
59  __newsize = calcGrowSize(minsize); \
60  assert(__newsize >= (minsize)); \
61  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
62  *(cursize) = __newsize; \
63  } while( FALSE )
64 
65 #ifdef SCIP_DISABLED_CODE /* this macro is currently not used, which offends lint, so disable it */
66 /** ensures that two block memory arrays have at least a given size
67  *
68  * if cursize is 0, then arrays can be NULL
69  */
70 #define ensureBlockMemoryArraySize2(blkmem, array1, array2, cursize, minsize) \
71  do { \
72  int __newsize; \
73  assert((blkmem) != NULL); \
74  if( *(cursize) >= (minsize) ) \
75  break; \
76  __newsize = calcGrowSize(minsize); \
77  assert(__newsize >= (minsize)); \
78  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
79  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
80  *(cursize) = __newsize; \
81  } while( FALSE )
82 #endif
83 
84 /** ensures that three block memory arrays have at least a given size
85  *
86  * if cursize is 0, then arrays can be NULL
87  */
88 #define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize) \
89  do { \
90  int __newsize; \
91  assert((blkmem) != NULL); \
92  if( *(cursize) >= (minsize) ) \
93  break; \
94  __newsize = calcGrowSize(minsize); \
95  assert(__newsize >= (minsize)); \
96  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
97  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
98  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array3, *(cursize), __newsize) ); \
99  *(cursize) = __newsize; \
100  } while( FALSE )
101 
102 /**@name Miscellaneous private methods */
103 /**@{ */
104 
105 /** calculate memory size for dynamically allocated arrays (copied from scip/set.c) */
106 static
108  int num /**< minimum number of entries to store */
109  )
110 {
111  int size;
112 
113  /* calculate the size with this loop, such that the resulting numbers are always the same (-> block memory) */
114  size = 4;
115  while( size < num )
116  size = (int)(1.2 * size + 4);
117 
118  return size;
119 }
120 
121 /** expression graph nodes comparison to use in sorting methods
122  *
123  * The nodes need to have been added to the expression graph (depth,pos >= 0).
124  * The better node is the one with the lower depth and lower position, if depth is equal.
125  */
126 static
127 SCIP_DECL_SORTPTRCOMP(exprgraphnodecomp)
128 {
129  SCIP_EXPRGRAPHNODE* node1 = (SCIP_EXPRGRAPHNODE*)elem1;
130  SCIP_EXPRGRAPHNODE* node2 = (SCIP_EXPRGRAPHNODE*)elem2;
131 
132  assert(node1 != NULL);
133  assert(node2 != NULL);
134  assert(node1->depth >= 0);
135  assert(node1->pos >= 0);
136  assert(node2->depth >= 0);
137  assert(node2->pos >= 0);
138 
139  if( node1->depth != node2->depth )
140  return node1->depth - node2->depth;
141 
142  /* there should be no two nodes on the same position */
143  assert((node1->pos != node2->pos) || (node1 == node2));
144 
145  return node1->pos - node2->pos;
146 }
147 
148 /** 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) */
149 static
151  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
152  SCIP_Real newlb, /**< new lower bound */
153  SCIP_Real oldlb, /**< old lower bound */
154  SCIP_Real oldub /**< old upper bound */
155  )
156 {
157  SCIP_Real eps;
158 
159  /* nothing can be tighter than an empty interval */
160  if( oldlb > oldub )
161  return FALSE;
162 
163  eps = REALABS(oldlb);
164  eps = MIN(oldub - oldlb, eps);
165  return EPSGT(newlb, oldlb, minstrength * MAX(eps, 1e-3));
166 }
167 
168 /** 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) */
169 static
171  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
172  SCIP_Real newub, /**< new upper bound */
173  SCIP_Real oldlb, /**< old lower bound */
174  SCIP_Real oldub /**< old upper bound */
175  )
176 {
177  SCIP_Real eps;
178 
179  /* nothing can be tighter than an empty interval */
180  if( oldlb > oldub )
181  return FALSE;
182 
183  eps = REALABS(oldub);
184  eps = MIN(oldub - oldlb, eps);
185  return EPSLT(newub, oldub, minstrength * MAX(eps, 1e-3));
186 }
187 
188 /**@} */
189 
190 /**@name Expression curvature methods */
191 /**@{ */
192 
193 /** curvature names as strings */
194 static
195 const char* curvnames[4] =
196  {
197  "unknown",
198  "convex",
199  "concave",
200  "linear"
201  };
202 
203 #undef SCIPexprcurvAdd
204 
205 /** gives curvature for a sum of two functions with given curvature */
207  SCIP_EXPRCURV curv1, /**< curvature of first summand */
208  SCIP_EXPRCURV curv2 /**< curvature of second summand */
209  )
210 {
211  return (SCIP_EXPRCURV) (curv1 & curv2);
212 }
213 
214 /** gives the curvature for the negation of a function with given curvature */
216  SCIP_EXPRCURV curvature /**< curvature of function */
217  )
218 {
219  switch( curvature )
220  {
222  return SCIP_EXPRCURV_CONVEX;
223 
225  return SCIP_EXPRCURV_CONCAVE;
226 
229  /* can return curvature, do this below */
230  break;
231 
232  default:
233  SCIPerrorMessage("unknown curvature status.\n");
234  SCIPABORT();
235  }
236 
237  return curvature;
238 }
239 
240 /** gives curvature for a functions with given curvature multiplied by a constant factor */
242  SCIP_Real factor, /**< constant factor */
243  SCIP_EXPRCURV curvature /**< curvature of other factor */
244  )
245 {
246  if( factor == 0.0 )
247  return SCIP_EXPRCURV_LINEAR;
248  if( factor > 0.0 )
249  return curvature;
250  return SCIPexprcurvNegate(curvature);
251 }
252 
253 /** gives curvature for base^exponent for given bounds and curvature of base-function and constant exponent */
255  SCIP_INTERVAL basebounds, /**< bounds on base function */
256  SCIP_EXPRCURV basecurv, /**< curvature of base function */
257  SCIP_Real exponent /**< exponent */
258  )
259 {
260  SCIP_Bool expisint;
261 
262  assert(basebounds.inf <= basebounds.sup);
263 
264  if( exponent == 0.0 )
265  return SCIP_EXPRCURV_LINEAR;
266 
267  if( exponent == 1.0 )
268  return basecurv;
269 
270  expisint = EPSISINT(exponent, 0.0); /*lint !e835*/
271 
272  /* if exponent is fractional, then power is not defined for a negative base
273  * thus, consider only positive part of basebounds
274  */
275  if( !expisint && basebounds.inf < 0.0 )
276  {
277  basebounds.inf = 0.0;
278  if( basebounds.sup < 0.0 )
279  return SCIP_EXPRCURV_LINEAR;
280  }
281 
282  /* if basebounds contains 0.0, consider negative and positive interval separately, if possible */
283  if( basebounds.inf < 0.0 && basebounds.sup > 0.0 )
284  {
285  SCIP_INTERVAL leftbounds;
286  SCIP_INTERVAL rightbounds;
287 
288  /* 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 */
289  if( exponent < 0.0 )
290  return SCIP_EXPRCURV_UNKNOWN;
291 
292  SCIPintervalSetBounds(&leftbounds, basebounds.inf, 0.0);
293  SCIPintervalSetBounds(&rightbounds, 0.0, basebounds.sup);
294 
295  return (SCIP_EXPRCURV) (SCIPexprcurvPower(leftbounds, basecurv, exponent) & SCIPexprcurvPower(rightbounds, basecurv, exponent));
296  }
297  assert(basebounds.inf >= 0.0 || basebounds.sup <= 0.0);
298 
299  /* (base^exponent)'' = exponent * ( (exponent-1) base^(exponent-2) (base')^2 + base^(exponent-1) base'' )
300  *
301  * if base'' is positive, i.e., base is convex, then
302  * - for base > 0.0 and exponent > 1.0, the second deriv. is positive -> convex
303  * - for base < 0.0 and exponent > 1.0, we can't say (first and second summand opposite signs)
304  * - for base > 0.0 and 0.0 < exponent < 1.0, we can't say (first sommand negative, second summand positive)
305  * - for base > 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
306  * - for base < 0.0 and exponent < 0.0 and even, the second deriv. is positive -> convex
307  * - for base < 0.0 and exponent < 0.0 and odd, the second deriv. is negative -> concave
308  *
309  * if base'' is negative, i.e., base is concave, then
310  * - for base > 0.0 and exponent > 1.0, we can't say (first summand positive, second summand negative)
311  * - for base < 0.0 and exponent > 1.0 and even, the second deriv. is positive -> convex
312  * - for base < 0.0 and exponent > 1.0 and odd, the second deriv. is negative -> concave
313  * - for base > 0.0 and 0.0 < exponent < 1.0, the second deriv. is negative -> concave
314  * - for base > 0.0 and exponent < 0.0, the second deriv. is positive -> convex
315  * - for base < 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
316  *
317  * if base'' is zero, i.e., base is linear, then
318  * (base^exponent)'' = exponent * (exponent-1) base^(exponent-2) (base')^2
319  * - just multiply signs
320  */
321 
322  if( basecurv == SCIP_EXPRCURV_LINEAR )
323  {
324  SCIP_Real sign;
325 
326  /* base^(exponent-2) is negative, if base < 0.0 and exponent is odd */
327  sign = exponent * (exponent - 1.0);
328  assert(basebounds.inf >= 0.0 || expisint);
329  if( basebounds.inf < 0.0 && ((int)exponent)%2 != 0 )
330  sign *= -1.0;
331  assert(sign != 0.0);
332 
333  return sign > 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
334  }
335 
336  if( basecurv == SCIP_EXPRCURV_CONVEX )
337  {
338  if( basebounds.sup <= 0.0 && exponent < 0.0 && expisint )
339  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
340  if( basebounds.inf >= 0.0 && exponent > 1.0 )
341  return SCIP_EXPRCURV_CONVEX ;
342  return SCIP_EXPRCURV_UNKNOWN;
343  }
344 
345  if( basecurv == SCIP_EXPRCURV_CONCAVE )
346  {
347  if( basebounds.sup <= 0.0 && exponent > 1.0 && expisint )
348  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
349  if( basebounds.inf >= 0.0 && exponent < 1.0 )
350  return exponent < 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
351  return SCIP_EXPRCURV_UNKNOWN;
352  }
353 
354  return SCIP_EXPRCURV_UNKNOWN;
355 }
356 
357 /** gives curvature for a monomial with given curvatures and bounds for each factor
358  *
359  * See Maranas and Floudas, Finding All Solutions of Nonlinearly Constrained Systems of Equations, JOGO 7, 1995
360  * for the categorization in the case that all factors are linear.
361  */
363  int nfactors, /**< number of factors in monomial */
364  SCIP_Real* exponents, /**< exponents in monomial, or NULL if all 1.0 */
365  int* factoridxs, /**< indices of factors (but not exponents), or NULL if identity mapping */
366  SCIP_EXPRCURV* factorcurv, /**< curvature of each factor */
367  SCIP_INTERVAL* factorbounds /**< bounds of each factor */
368  )
369 {
370  SCIP_Real mult;
371  SCIP_Real e;
372  SCIP_EXPRCURV curv;
373  SCIP_EXPRCURV fcurv;
374  int nnegative;
375  int npositive;
376  SCIP_Real sum;
377  SCIP_Bool expcurvpos;
378  SCIP_Bool expcurvneg;
379  int j;
380  int f;
381 
382  assert(nfactors >= 0);
383  assert(factorcurv != NULL || nfactors == 0);
384  assert(factorbounds != NULL || nfactors == 0);
385 
386  if( nfactors == 0 )
387  return SCIP_EXPRCURV_LINEAR;
388 
389  if( nfactors == 1 )
390  {
391  f = factoridxs != NULL ? factoridxs[0] : 0;
392  e = exponents != NULL ? exponents[0] : 1.0;
393  /* SCIPdebugMessage("monomial [%g,%g]^%g is %s\n",
394  factorbounds[f].inf, factorbounds[f].sup, e,
395  SCIPexprcurvGetName(SCIPexprcurvPower(factorbounds[f], factorcurv[f], e))); */
396  return SCIPexprcurvPower(factorbounds[f], factorcurv[f], e); /*lint !e613*/
397  }
398 
399  mult = 1.0;
400 
401  nnegative = 0; /* number of negative exponents */
402  npositive = 0; /* number of positive exponents */
403  sum = 0.0; /* sum of exponents */
404  expcurvpos = TRUE; /* whether exp_j * f_j''(x) >= 0 for all factors (assuming f_j >= 0) */
405  expcurvneg = TRUE; /* whether exp_j * f_j''(x) <= 0 for all factors (assuming f_j >= 0) */
406 
407  for( j = 0; j < nfactors; ++j )
408  {
409  f = factoridxs != NULL ? factoridxs[j] : j;
410  if( factorcurv[f] == SCIP_EXPRCURV_UNKNOWN ) /*lint !e613*/
411  return SCIP_EXPRCURV_UNKNOWN;
412  if( factorbounds[f].inf < 0.0 && factorbounds[f].sup > 0.0 ) /*lint !e613*/
413  return SCIP_EXPRCURV_UNKNOWN;
414 
415  e = exponents != NULL ? exponents[j] : 1.0;
416  if( e < 0.0 )
417  ++nnegative;
418  else
419  ++npositive;
420  sum += e;
421 
422  if( factorbounds[f].inf < 0.0 ) /*lint !e613*/
423  {
424  /* if argument is negative, then exponent should be integer */
425  assert(EPSISINT(e, 0.0)); /*lint !e835*/
426 
427  /* flip j'th argument: (f_j)^(exp_j) = (-1)^(exp_j) (-f_j)^(exp_j) */
428 
429  /* -f_j has negated curvature of f_j */
430  fcurv = SCIPexprcurvNegate(factorcurv[f]); /*lint !e613*/
431 
432  /* negate monomial, if exponent is odd, i.e., (-1)^(exp_j) = -1 */
433  if( (int)e % 2 != 0 )
434  mult *= -1.0;
435  }
436  else
437  {
438  fcurv = factorcurv[f]; /*lint !e613*/
439  }
440 
441  /* check if exp_j * fcurv is convex (>= 0) and/or concave */
442  fcurv = SCIPexprcurvMultiply(e, fcurv);
443  if( !(fcurv & SCIP_EXPRCURV_CONVEX) )
444  expcurvpos = FALSE;
445  if( !(fcurv & SCIP_EXPRCURV_CONCAVE) )
446  expcurvneg = FALSE;
447  }
448 
449  /* if all factors are linear, then a product f_j^exp_j with f_j >= 0 is convex if
450  * - all exponents are negative, or
451  * - 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
452  * further, the product is concave if
453  * - all exponents are positive and the sum of exponents is <= 1.0
454  *
455  * if factors are nonlinear, then we require additionally, that for convexity
456  * - each factor is convex if exp_j >= 0, or concave if exp_j <= 0, i.e., exp_j*f_j'' >= 0
457  * and for concavity, we require that
458  * - all factors are concave, i.e., exp_j*f_j'' <= 0
459  */
460 
461  if( nnegative == nfactors && expcurvpos )
462  curv = SCIP_EXPRCURV_CONVEX;
463  else if( nnegative == nfactors-1 && EPSGE(sum, 1.0, 1e-9) && expcurvpos )
464  curv = SCIP_EXPRCURV_CONVEX;
465  else if( npositive == nfactors && EPSLE(sum, 1.0, 1e-9) && expcurvneg )
466  curv = SCIP_EXPRCURV_CONCAVE;
467  else
468  curv = SCIP_EXPRCURV_UNKNOWN;
469  curv = SCIPexprcurvMultiply(mult, curv);
470 
471  return curv;
472 }
473 
474 /** gives name as string for a curvature */
476  SCIP_EXPRCURV curv /**< curvature */
477  )
478 {
479  assert(curv <= SCIP_EXPRCURV_LINEAR); /*lint !e685*/
480 
481  return curvnames[curv];
482 }
483 
484 /**@} */
485 
486 /**@name Quadratic expression data private methods */
487 /**@{ */
488 
489 /** creates SCIP_EXPRDATA_QUADRATIC data structure from given quadratic elements */
490 static
492  BMS_BLKMEM* blkmem, /**< block memory data structure */
493  SCIP_EXPRDATA_QUADRATIC** quadraticdata, /**< buffer to store pointer to quadratic data */
494  SCIP_Real constant, /**< constant */
495  int nchildren, /**< number of children */
496  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
497  int nquadelems, /**< number of quadratic elements */
498  SCIP_QUADELEM* quadelems /**< quadratic elements */
499  )
500 {
501  assert(blkmem != NULL);
502  assert(quadraticdata != NULL);
503  assert(quadelems != NULL || nquadelems == 0);
504  assert(nchildren >= 0);
505 
506  SCIP_ALLOC( BMSallocBlockMemory(blkmem, quadraticdata) );
507 
508  (*quadraticdata)->constant = constant;
509  (*quadraticdata)->lincoefs = NULL;
510  (*quadraticdata)->nquadelems = nquadelems;
511  (*quadraticdata)->quadelems = NULL;
512  (*quadraticdata)->sorted = (nquadelems <= 1);
513 
514  if( lincoefs != NULL )
515  {
516  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->lincoefs, lincoefs, nchildren) );
517  }
518 
519  if( nquadelems > 0 )
520  {
521  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->quadelems, quadelems, nquadelems) );
522  }
523 
524  return SCIP_OKAY;
525 }
526 
527 /** sorts quadratic elements in a SCIP_EXPRDATA_QUADRATIC data structure */
528 static
530  SCIP_EXPRDATA_QUADRATIC* quadraticdata /**< quadratic data */
531  )
532 {
533  assert(quadraticdata != NULL);
534 
535  if( quadraticdata->sorted )
536  {
537 #ifndef NDEBUG
538  int i;
539  for( i = 1; i < quadraticdata->nquadelems; ++i )
540  {
541  assert(quadraticdata->quadelems[i].idx1 <= quadraticdata->quadelems[i].idx2);
542  assert(quadraticdata->quadelems[i-1].idx1 <= quadraticdata->quadelems[i].idx1);
543  assert(quadraticdata->quadelems[i-1].idx1 < quadraticdata->quadelems[i].idx1 ||
544  quadraticdata->quadelems[i-1].idx2 <= quadraticdata->quadelems[i].idx2);
545  }
546 #endif
547  return;
548  }
549 
550  if( quadraticdata->nquadelems > 0 )
551  SCIPquadelemSort(quadraticdata->quadelems, quadraticdata->nquadelems);
552 
553  quadraticdata->sorted = TRUE;
554 }
555 
556 /**@} */
557 
558 /**@name Polynomial expression data private methods */
559 /**@{ */
560 
561 /** compares two monomials
562  *
563  * gives 0 if monomials are equal */
564 static
565 SCIP_DECL_SORTPTRCOMP(monomialdataCompare)
566 {
567  SCIP_EXPRDATA_MONOMIAL* monomial1;
568  SCIP_EXPRDATA_MONOMIAL* monomial2;
569 
570  int i;
571 
572  assert(elem1 != NULL);
573  assert(elem2 != NULL);
574 
575  monomial1 = (SCIP_EXPRDATA_MONOMIAL*)elem1;
576  monomial2 = (SCIP_EXPRDATA_MONOMIAL*)elem2;
577 
578  /* make sure, both monomials are equal */
579  SCIPexprSortMonomialFactors(monomial1);
580  SCIPexprSortMonomialFactors(monomial2);
581 
582  /* for the first factor where both monomials differ,
583  * we return either the difference in the child indices, if children are different
584  * or the sign of the difference in the exponents
585  */
586  for( i = 0; i < monomial1->nfactors && i < monomial2->nfactors; ++i )
587  {
588  if( monomial1->childidxs[i] != monomial2->childidxs[i] )
589  return monomial1->childidxs[i] - monomial2->childidxs[i];
590  if( monomial1->exponents[i] > monomial2->exponents[i] )
591  return 1;
592  else if( monomial1->exponents[i] < monomial2->exponents[i] )
593  return -1;
594  }
595 
596  /* if the factors of one monomial are a proper subset of the factors of the other monomial,
597  * we return the difference in the number of monomials
598  */
599  return monomial1->nfactors - monomial2->nfactors;
600 }
601 
602 /** ensures that the factors arrays of a monomial have at least a given size */
603 static
605  BMS_BLKMEM* blkmem, /**< block memory data structure */
606  SCIP_EXPRDATA_MONOMIAL* monomialdata, /**< monomial data */
607  int minsize /**< minimal size of factors arrays */
608  )
609 {
610  assert(blkmem != NULL);
611  assert(monomialdata != NULL);
612 
613  if( minsize > monomialdata->factorssize )
614  {
615  int newsize;
616 
617  newsize = calcGrowSize(minsize);
618  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->childidxs, monomialdata->factorssize, newsize) );
619  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->exponents, monomialdata->factorssize, newsize) );
620  monomialdata->factorssize = newsize;
621  }
622  assert(minsize <= monomialdata->factorssize);
623 
624  return SCIP_OKAY;
625 }
626 
627 /** creates SCIP_EXPRDATA_POLYNOMIAL data structure from given monomials */
628 static
630  BMS_BLKMEM* blkmem, /**< block memory data structure */
631  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
632  int nmonomials, /**< number of monomials */
633  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
634  SCIP_Real constant, /**< constant part */
635  SCIP_Bool copymonomials /**< whether to copy monomials, or copy only given pointers, in which case polynomialdata assumes ownership of monomial structure */
636  )
637 {
638  assert(blkmem != NULL);
639  assert(polynomialdata != NULL);
640  assert(monomials != NULL || nmonomials == 0);
641 
642  SCIP_ALLOC( BMSallocBlockMemory(blkmem, polynomialdata) );
643 
644  (*polynomialdata)->constant = constant;
645  (*polynomialdata)->nmonomials = nmonomials;
646  (*polynomialdata)->monomialssize = nmonomials;
647  (*polynomialdata)->monomials = NULL;
648  (*polynomialdata)->sorted = (nmonomials <= 1);
649 
650  if( nmonomials > 0 )
651  {
652  int i;
653 
654  if( copymonomials )
655  {
656  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, nmonomials) );
657 
658  for( i = 0; i < nmonomials; ++i )
659  {
660  assert(monomials[i] != NULL); /*lint !e613*/
661  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i],
662  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
663  }
664  }
665  else
666  {
667  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, monomials, nmonomials) );
668  }
669  }
670 
671  return SCIP_OKAY;
672 }
673 
674 /** creates a copy of a SCIP_EXPRDATA_POLYNOMIAL data structure */
675 static
677  BMS_BLKMEM* blkmem, /**< block memory data structure */
678  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
679  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata /**< polynomial data to copy */
680  )
681 {
682  assert(blkmem != NULL);
683  assert(polynomialdata != NULL);
684  assert(sourcepolynomialdata != NULL);
685 
686  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, polynomialdata, sourcepolynomialdata) );
687 
688  (*polynomialdata)->monomialssize = sourcepolynomialdata->nmonomials;
689  if( sourcepolynomialdata->nmonomials > 0 )
690  {
691  int i;
692 
693  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize) );
694 
695  for( i = 0; i < sourcepolynomialdata->nmonomials; ++i )
696  {
697  assert(sourcepolynomialdata->monomials[i] != NULL); /*lint !e613*/
698  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i], sourcepolynomialdata->monomials[i]->coef,
699  sourcepolynomialdata->monomials[i]->nfactors, sourcepolynomialdata->monomials[i]->childidxs, sourcepolynomialdata->monomials[i]->exponents) );
700  (*polynomialdata)->monomials[i]->sorted = sourcepolynomialdata->monomials[i]->sorted;
701  }
702  }
703  else
704  {
705  (*polynomialdata)->monomials = NULL;
706  }
707 
708  return SCIP_OKAY;
709 }
710 
711 /** frees a SCIP_EXPRDATA_POLYNOMIAL data structure */
712 static
714  BMS_BLKMEM* blkmem, /**< block memory data structure */
715  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata /**< pointer to polynomial data to free */
716  )
717 {
718  assert(blkmem != NULL);
719  assert(polynomialdata != NULL);
720  assert(*polynomialdata != NULL);
721 
722  if( (*polynomialdata)->monomialssize > 0 )
723  {
724  int i;
725 
726  for( i = 0; i < (*polynomialdata)->nmonomials; ++i )
727  {
728  assert((*polynomialdata)->monomials[i] != NULL);
729  SCIPexprFreeMonomial(blkmem, &(*polynomialdata)->monomials[i]);
730  assert((*polynomialdata)->monomials[i] == NULL);
731  }
732 
733  BMSfreeBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize);
734  }
735  assert((*polynomialdata)->monomials == NULL);
736 
737  BMSfreeBlockMemory(blkmem, polynomialdata);
738 }
739 
740 /** ensures that the monomials array of a polynomial has at least a given size */
741 static
743  BMS_BLKMEM* blkmem, /**< block memory data structure */
744  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
745  int minsize /**< minimal size of monomials array */
746  )
747 {
748  assert(blkmem != NULL);
749  assert(polynomialdata != NULL);
750 
751  ensureBlockMemoryArraySize(blkmem, &polynomialdata->monomials, &polynomialdata->monomialssize, minsize);
752  assert(minsize <= polynomialdata->monomialssize);
753 
754  return SCIP_OKAY;
755 }
756 
757 /** adds an array of monomials to a polynomial */
758 static
760  BMS_BLKMEM* blkmem, /**< block memory of expression */
761  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
762  int nmonomials, /**< number of monomials to add */
763  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
764  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
765  )
766 {
767  int i;
768 
769  assert(blkmem != NULL);
770  assert(polynomialdata != NULL);
771  assert(monomials != NULL || nmonomials == 0);
772 
773  if( nmonomials == 0 )
774  return SCIP_OKAY;
775 
776  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials + nmonomials) );
777  assert(polynomialdata->monomialssize >= polynomialdata->nmonomials + nmonomials);
778 
779  if( copymonomials )
780  {
781  for( i = 0; i < nmonomials; ++i )
782  {
783  assert(monomials[i] != NULL); /*lint !e613*/
784  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials + i],
785  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
786  }
787  }
788  else
789  {
790  BMScopyMemoryArray(&polynomialdata->monomials[polynomialdata->nmonomials], monomials, nmonomials); /*lint !e866*/
791  }
792  polynomialdata->nmonomials += nmonomials;
793 
794  polynomialdata->sorted = (polynomialdata->nmonomials <= 1);
795 
796  return SCIP_OKAY;
797 }
798 
799 /** ensures that monomials of a polynomial are sorted */
800 static
802  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata /**< polynomial expression */
803  )
804 {
805  assert(polynomialdata != NULL);
806 
807  if( polynomialdata->sorted )
808  {
809 #ifndef NDEBUG
810  int i;
811 
812  /* a polynom with more than one monoms can only be sorted if its monoms are sorted */
813  for( i = 1; i < polynomialdata->nmonomials; ++i )
814  {
815  assert(polynomialdata->monomials[i-1]->sorted);
816  assert(polynomialdata->monomials[i]->sorted);
817  assert(monomialdataCompare(polynomialdata->monomials[i-1], polynomialdata->monomials[i]) <= 0);
818  }
819 #endif
820  return;
821  }
822 
823  if( polynomialdata->nmonomials > 0 )
824  SCIPsortPtr((void**)polynomialdata->monomials, monomialdataCompare, polynomialdata->nmonomials);
825 
826  polynomialdata->sorted = TRUE;
827 }
828 
829 /** merges monomials that differ only in coefficient into a single monomial
830  *
831  * Eliminates monomials with coefficient between -eps and eps.
832  */
833 static
835  BMS_BLKMEM* blkmem, /**< block memory */
836  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
837  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
838  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
839  )
840 {
841  int i;
842  int offset;
843  int oldnfactors;
844 
845  assert(polynomialdata != NULL);
846  assert(eps >= 0.0);
847 
848  polynomialdataSortMonomials(polynomialdata);
849 
850  /* merge monomials by adding their coefficients, eliminate monomials with no factors or zero coefficient*/
851  offset = 0;
852  i = 0;
853  while( i + offset < polynomialdata->nmonomials )
854  {
855  if( offset > 0 )
856  {
857  assert(polynomialdata->monomials[i] == NULL);
858  assert(polynomialdata->monomials[i+offset] != NULL);
859  polynomialdata->monomials[i] = polynomialdata->monomials[i+offset];
860 #ifndef NDEBUG
861  polynomialdata->monomials[i+offset] = NULL;
862 #endif
863  }
864 
865  if( mergefactors )
866  {
867  oldnfactors = polynomialdata->monomials[i]->nfactors;
868  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i], eps);
869 
870  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
871  if( oldnfactors != polynomialdata->monomials[i]->nfactors )
872  polynomialdata->sorted = FALSE;
873  }
874 
875  while( i+offset+1 < polynomialdata->nmonomials )
876  {
877  assert(polynomialdata->monomials[i+offset+1] != NULL);
878  if( mergefactors )
879  {
880  oldnfactors = polynomialdata->monomials[i+offset+1]->nfactors;
881  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i+offset+1], eps);
882 
883  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
884  if( oldnfactors != polynomialdata->monomials[i+offset+1]->nfactors )
885  polynomialdata->sorted = FALSE;
886  }
887  if( monomialdataCompare((void*)polynomialdata->monomials[i], (void*)polynomialdata->monomials[i+offset+1]) != 0 )
888  break;
889  polynomialdata->monomials[i]->coef += polynomialdata->monomials[i+offset+1]->coef;
890  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i+offset+1]);
891  ++offset;
892  }
893 
894  if( polynomialdata->monomials[i]->nfactors == 0 )
895  {
896  /* constant monomial */
897  polynomialdata->constant += polynomialdata->monomials[i]->coef;
898  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
899  ++offset;
900  continue;
901  }
902 
903  if( EPSZ(polynomialdata->monomials[i]->coef, eps) )
904  {
905  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
906  ++offset;
907  continue;
908  }
909 
910  ++i;
911  }
912 
913 #ifndef NDEBUG
914  for( ; i < polynomialdata->nmonomials; ++i )
915  assert(polynomialdata->monomials[i] == NULL);
916 #endif
917 
918  polynomialdata->nmonomials -= offset;
919 
920  if( EPSZ(polynomialdata->constant, eps) )
921  polynomialdata->constant = 0.0;
922 }
923 
924 /** multiplies each summand of a polynomial by a given constant */
925 static
927  BMS_BLKMEM* blkmem, /**< block memory */
928  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
929  SCIP_Real factor /**< constant factor */
930  )
931 {
932  int i;
933 
934  assert(polynomialdata != NULL);
935 
936  if( factor == 1.0 )
937  return;
938 
939  if( factor == 0.0 )
940  {
941  for( i = 0; i < polynomialdata->nmonomials; ++i )
942  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
943  polynomialdata->nmonomials = 0;
944  }
945  else
946  {
947  for( i = 0; i < polynomialdata->nmonomials; ++i )
948  SCIPexprChgMonomialCoef(polynomialdata->monomials[i], polynomialdata->monomials[i]->coef * factor);
949  }
950 
951  polynomialdata->constant *= factor;
952 }
953 
954 /** multiplies each summand of a polynomial by a given monomial */
955 static
957  BMS_BLKMEM* blkmem, /**< block memory */
958  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
959  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
960  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
961  )
962 {
963  int i;
964 
965  assert(blkmem != NULL);
966  assert(factor != NULL);
967  assert(polynomialdata != NULL);
968 
969  if( factor->nfactors == 0 )
970  {
971  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factor->coef);
972  return SCIP_OKAY;
973  }
974 
975  /* multiply each monomial by factor */
976  for( i = 0; i < polynomialdata->nmonomials; ++i )
977  {
978  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i], factor, childmap) );
979  }
980 
981  /* add new monomial for constant multiplied by factor */
982  if( polynomialdata->constant != 0.0 )
983  {
984  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
985  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
986  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[polynomialdata->nmonomials], factor, childmap) );
987  ++polynomialdata->nmonomials;
988  polynomialdata->sorted = FALSE;
989  polynomialdata->constant = 0.0;
990  }
991 
992  return SCIP_OKAY;
993 }
994 
995 /** multiplies a polynomial by a polynomial
996  *
997  * Factors need to be different.
998  */
999 static
1001  BMS_BLKMEM* blkmem, /**< block memory */
1002  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1003  SCIP_EXPRDATA_POLYNOMIAL* factordata, /**< polynomial factor data */
1004  int* childmap /**< map children in factor to children in polynomialdata, or NULL for 1:1 */
1005  )
1006 {
1007  int i1;
1008  int i2;
1009  int orignmonomials;
1010 
1011  assert(blkmem != NULL);
1012  assert(polynomialdata != NULL);
1013  assert(factordata != NULL);
1014  assert(polynomialdata != factordata);
1015 
1016  if( factordata->nmonomials == 0 )
1017  {
1018  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factordata->constant);
1019  return SCIP_OKAY;
1020  }
1021  assert(factordata->monomials != NULL);
1022 
1023  if( factordata->nmonomials == 1 && factordata->constant == 0.0 )
1024  {
1025  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, polynomialdata, factordata->monomials[0], childmap) );
1026  return SCIP_OKAY;
1027  }
1028 
1029  /* turn constant into a monomial, so we can assume below that constant is 0.0 */
1030  if( polynomialdata->constant != 0.0 )
1031  {
1032  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
1033  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
1034  ++polynomialdata->nmonomials;
1035  polynomialdata->sorted = FALSE;
1036  polynomialdata->constant = 0.0;
1037  }
1038 
1039  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials * (factordata->nmonomials + (factordata->constant == 0.0 ? 0 : 1))) );
1040 
1041  /* for each monomial in factordata (except the last, if factordata->constant is 0),
1042  * duplicate monomials from polynomialdata and multiply them by the monomial for factordata */
1043  orignmonomials = polynomialdata->nmonomials;
1044  for( i2 = 0; i2 < factordata->nmonomials; ++i2 )
1045  {
1046  /* add a copy of original monomials to end of polynomialdata's monomials array */
1047  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 */
1048  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, orignmonomials, polynomialdata->monomials, TRUE) );
1049  assert(polynomialdata->nmonomials == (i2+2) * orignmonomials);
1050 
1051  /* multiply each copied monomial by current monomial from factordata */
1052  for( i1 = (i2+1) * orignmonomials; i1 < (i2+2) * orignmonomials; ++i1 )
1053  {
1054  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1055  }
1056 
1057  if( factordata->constant == 0.0 && i2 == factordata->nmonomials - 2 )
1058  {
1059  ++i2;
1060  break;
1061  }
1062  }
1063 
1064  if( factordata->constant != 0.0 )
1065  {
1066  assert(i2 == factordata->nmonomials);
1067  /* multiply original monomials in polynomialdata by constant in factordata */
1068  for( i1 = 0; i1 < orignmonomials; ++i1 )
1069  SCIPexprChgMonomialCoef(polynomialdata->monomials[i1], polynomialdata->monomials[i1]->coef * factordata->constant);
1070  }
1071  else
1072  {
1073  assert(i2 == factordata->nmonomials - 1);
1074  /* multiply original monomials in polynomialdata by last monomial in factordata */
1075  for( i1 = 0; i1 < orignmonomials; ++i1 )
1076  {
1077  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1078  }
1079  }
1080 
1081  return SCIP_OKAY;
1082 }
1083 
1084 /** takes a power of a polynomial
1085  *
1086  * Exponent needs to be an integer,
1087  * polynomial needs to be a monomial, if exponent is negative.
1088  */
1089 static
1091  BMS_BLKMEM* blkmem, /**< block memory */
1092  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1093  int exponent /**< exponent of power operation */
1094  )
1095 {
1096  SCIP_EXPRDATA_POLYNOMIAL* factor;
1097  int i;
1098 
1099  assert(blkmem != NULL);
1100  assert(polynomialdata != NULL);
1101 
1102  if( exponent == 0 )
1103  {
1104  /* x^0 = 1, except if x = 0 */
1105  if( polynomialdata->nmonomials == 0 && polynomialdata->constant == 0.0 )
1106  {
1107  polynomialdata->constant = 0.0;
1108  }
1109  else
1110  {
1111  polynomialdata->constant = 1.0;
1112 
1113  for( i = 0; i < polynomialdata->nmonomials; ++i )
1114  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
1115  polynomialdata->nmonomials = 0;
1116  }
1117 
1118  return SCIP_OKAY;
1119  }
1120 
1121  if( exponent == 1 )
1122  return SCIP_OKAY;
1123 
1124  if( polynomialdata->nmonomials == 1 && polynomialdata->constant == 0.0 )
1125  {
1126  /* polynomial is a single monomial */
1127  SCIPexprMonomialPower(polynomialdata->monomials[0], exponent);
1128  return SCIP_OKAY;
1129  }
1130 
1131  if( polynomialdata->nmonomials == 0 )
1132  {
1133  /* polynomial is a constant */
1134  polynomialdata->constant = pow(polynomialdata->constant, (SCIP_Real)exponent);
1135  return SCIP_OKAY;
1136  }
1137 
1138  assert(exponent >= 2); /* negative exponents not allowed if more than one monom */
1139 
1140  /* todo improve, look how SCIPintervalPowerScalar in intervalarith.c does it */
1141 
1142  /* get copy of our polynomial */
1143  SCIP_CALL( polynomialdataCopy(blkmem, &factor, polynomialdata) );
1144 
1145  /* do repeated multiplication */
1146  for( i = 2; i <= exponent; ++i )
1147  {
1148  SCIP_CALL( polynomialdataMultiplyByPolynomial(blkmem, polynomialdata, factor, NULL) );
1149  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
1150  }
1151 
1152  /* free copy again */
1153  polynomialdataFree(blkmem, &factor);
1154 
1155  return SCIP_OKAY;
1156 }
1157 
1158 /** applies a mapping of child indices to the indices used in polynomial monomials */
1159 static
1161  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1162  int* childmap /**< mapping of child indices */
1163  )
1164 {
1165  SCIP_EXPRDATA_MONOMIAL* monomial;
1166  int i;
1167  int j;
1168 
1169  assert(polynomialdata != NULL);
1170 
1171  for( i = 0; i < polynomialdata->nmonomials; ++i )
1172  {
1173  monomial = polynomialdata->monomials[i];
1174  assert(monomial != NULL);
1175 
1176  for( j = 0; j < monomial->nfactors; ++j )
1177  {
1178  monomial->childidxs[j] = childmap[monomial->childidxs[j]];
1179  assert(monomial->childidxs[j] >= 0);
1180  }
1181  monomial->sorted = FALSE;
1182  }
1183 
1184  polynomialdata->sorted = FALSE;
1185 }
1186 
1187 /** replaces a factor in a monomial by a polynomial and expands the result */
1188 static
1190  BMS_BLKMEM* blkmem, /**< block memory data structure */
1191  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1192  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data where to expand a monomial */
1193  int monomialpos, /**< position of monomial which factor to expand */
1194  int factorpos, /**< position of factor in monomial to expand */
1195  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomial,/**< polynomial that should replace factor */
1196  int* childmap, /**< map of child indices in factorpolynomial to children of polynomial */
1197  int maxexpansionexponent,/**< maximal exponent for which polynomials (with > 1 summands) are expanded */
1198  SCIP_Bool* success /**< buffer to store whether expansion has been done */
1199  )
1200 {
1201  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomialcopy;
1202  SCIP_EXPRDATA_MONOMIAL* monomial;
1203  int i;
1204 
1205  assert(blkmem != NULL);
1206  assert(polynomialdata != NULL);
1207  assert(factorpolynomial != NULL);
1208  assert(childmap != NULL || factorpolynomial->nmonomials == 0);
1209  assert(success != NULL);
1210  assert(monomialpos >= 0);
1211  assert(monomialpos < polynomialdata->nmonomials);
1212  assert(factorpos >= 0);
1213 
1214  monomial = polynomialdata->monomials[monomialpos];
1215  assert(monomial != NULL);
1216  assert(factorpos < monomial->nfactors);
1217 
1218  *success = TRUE;
1219 
1220  if( factorpolynomial->nmonomials == 0 )
1221  {
1222  /* factorpolynomial is a constant */
1223 
1224  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && factorpolynomial->constant < 0.0 ) /*lint !e835*/
1225  {
1226  /* if polynomial is a negative constant and our exponent is not integer, then cannot do expansion */
1227  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", factorpolynomial->constant, monomial->exponents[factorpos]);
1228  *success = FALSE;
1229  return SCIP_OKAY;
1230  }
1231  monomial->coef *= pow(factorpolynomial->constant, monomial->exponents[factorpos]);
1232 
1233  /* move last factor to position factorpos */
1234  if( factorpos < monomial->nfactors-1 )
1235  {
1236  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1237  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1238  }
1239  --monomial->nfactors;
1240  monomial->sorted = FALSE;
1241  polynomialdata->sorted = FALSE;
1242 
1243  return SCIP_OKAY;
1244  }
1245 
1246  if( factorpolynomial->constant == 0.0 && factorpolynomial->nmonomials == 1 )
1247  {
1248  /* factorpolynomial is a single monomial */
1249  SCIP_EXPRDATA_MONOMIAL* factormonomial;
1250  int childidx;
1251  SCIP_Real exponent;
1252 
1253  factormonomial = factorpolynomial->monomials[0];
1254  assert(factormonomial != NULL);
1255 
1256  if( !EPSISINT(monomial->exponents[factorpos], 0.0) ) /*lint !e835*/
1257  {
1258  if( factormonomial->coef < 0.0 )
1259  {
1260  /* if coefficient of monomial is negative and our exponent is not integer, then do not do expansion
1261  * @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
1262  */
1263  *success = FALSE;
1264  return SCIP_OKAY;
1265  }
1266  if( factormonomial->nfactors > 1 )
1267  {
1268  /* @todo if there is an even number of factors in factormonomial that are negative, then they always multiply to something positive
1269  * however, we cannot expand them as below, since we cannot compute the single powers
1270  * since we do not have the bounds on the factors here, we skip expansion in this case
1271  * MINLPLib instances tls2,4,6 are examples where we are loosing here (do not recognize convexity)
1272  */
1273  *success = FALSE;
1274  return SCIP_OKAY;
1275  }
1276  }
1277 
1278  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + factormonomial->nfactors) );
1279 
1280  for( i = 0; i < factormonomial->nfactors; ++i )
1281  {
1282  childidx = childmap[factormonomial->childidxs[i]]; /*lint !e613*/
1283  /* can do this because monomial->exponents[factorpos] is assumed to be integer or factormonomial has positive coefficient and only one factor
1284  * thus, if factormonomial->exponents[i] is fractional, then we can assume that it's argument is positive
1285  */
1286  exponent = factormonomial->exponents[i] * monomial->exponents[factorpos];
1287  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
1288  }
1289 
1290  monomial->coef *= pow(factormonomial->coef, monomial->exponents[factorpos]);
1291 
1292  /* move last factor to position factorpos */
1293  if( factorpos < monomial->nfactors-1 )
1294  {
1295  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1296  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1297  }
1298  --monomial->nfactors;
1299  monomial->sorted = FALSE;
1300  polynomialdata->sorted = FALSE;
1301 
1302  return SCIP_OKAY;
1303  }
1304 
1305  /* if exponent is negative or fractional and the polynomial is not just a monomial, then we cannot do expansion */
1306  if( !EPSISINT(monomial->exponents[factorpos], 0.0) || monomial->exponents[factorpos] < 0.0 ) /*lint !e835*/
1307  {
1308  *success = FALSE;
1309  return SCIP_OKAY;
1310  }
1311 
1312  /* if exponent is too large, skip expansion */
1313  if( monomial->exponents[factorpos] > maxexpansionexponent )
1314  {
1315  *success = FALSE;
1316  return SCIP_OKAY;
1317  }
1318 
1319  /* check whether maximal degree of expansion would exceed maxexpansionexponent
1320  * that is, assume monomial is f1^a1 f2^a2 ... and we want to expand f1 = (g11^beta11 g12^beta12... + g21^beta21 g22^beta22 ... + ...)
1321  * then we do this only if all ai and all beta are > 0.0 and a1 max(beta11+beta12+..., beta21+beta22+..., ...) + a2 + ... < maxexpansionexponent
1322  * exception (there need to be one) is if monomial is just f1
1323  */
1324  if( maxexpansionexponent < INT_MAX && (monomial->nfactors > 1 || monomial->exponents[factorpos] != 1.0) )
1325  {
1326  SCIP_Real restdegree;
1327  SCIP_Real degree;
1328  int j;
1329 
1330  restdegree = -monomial->exponents[factorpos];
1331  for( i = 0; i < monomial->nfactors; ++i )
1332  {
1333  if( monomial->exponents[i] < 0.0 )
1334  {
1335  /* ai < 0.0 */
1336  SCIPdebugMessage("skip expansion because factor %d in monomial has negative exponent\n", i);
1337  *success = FALSE;
1338  return SCIP_OKAY;
1339  }
1340  restdegree += monomial->exponents[i];
1341  }
1342 
1343  for( i = 0; i < factorpolynomial->nmonomials; ++i )
1344  {
1345  degree = 0.0;
1346  for( j = 0; j < factorpolynomial->monomials[i]->nfactors; ++j )
1347  {
1348  if( factorpolynomial->monomials[i]->exponents[j] < 0.0 )
1349  {
1350  /* beta_ij < 0.0 */
1351  SCIPdebugMessage("skip expansion because %d'th factor in %d'th monomial of factorpolynomial is negative\n", i, j);
1352  *success = FALSE;
1353  return SCIP_OKAY;
1354  }
1355  degree += factorpolynomial->monomials[i]->exponents[j];
1356  }
1357  if( degree * monomial->exponents[factorpos] + restdegree > maxexpansionexponent )
1358  {
1359  /* (beta_i1+beta_i2+...)*monomial->exponents[factorpos] + rest > maxexpansion */
1360  SCIPdebugMessage("skip expansion because degree of %d'th monomial would yield degree %g > max = %d in expansion\n",
1361  i, degree * monomial->exponents[factorpos] + restdegree, maxexpansionexponent);
1362  *success = FALSE;
1363  return SCIP_OKAY;
1364  }
1365  }
1366  }
1367 
1368  /* create a copy of factor */
1369  SCIP_CALL( polynomialdataCopy(blkmem, &factorpolynomialcopy, factorpolynomial) );
1370  /* apply childmap to copy */
1371  polynomialdataApplyChildmap(factorpolynomialcopy, childmap);
1372  /* create power of factor */
1373  SCIP_CALL( polynomialdataPower(blkmem, factorpolynomialcopy, (int)EPSFLOOR(monomial->exponents[factorpos], 0.0)) ); /*lint !e835*/
1374 
1375  /* remove factor from monomial by moving last factor to position factorpos */
1376  if( factorpos < monomial->nfactors-1 )
1377  {
1378  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1379  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1380  }
1381  --monomial->nfactors;
1382  monomial->sorted = FALSE;
1383 
1384  /* multiply factor with this reduced monomial */
1385  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, factorpolynomialcopy, monomial, NULL) );
1386 
1387  /* remove monomial from polynomial and move last monomial to monomialpos */
1388  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[monomialpos]);
1389  if( monomialpos < polynomialdata->nmonomials-1 )
1390  polynomialdata->monomials[monomialpos] = polynomialdata->monomials[polynomialdata->nmonomials-1];
1391  --polynomialdata->nmonomials;
1392  polynomialdata->sorted = FALSE;
1393 
1394  /* add factorpolynomialcopy to polynomial */
1395  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, factorpolynomialcopy->nmonomials, factorpolynomialcopy->monomials, FALSE) );
1396  polynomialdata->constant += factorpolynomialcopy->constant;
1397 
1398  factorpolynomialcopy->nmonomials = 0;
1399  polynomialdataFree(blkmem, &factorpolynomialcopy);
1400 
1401  return SCIP_OKAY;
1402 }
1403 
1404 /**@} */
1405 
1406 /**@name Expression operand private methods */
1407 /**@{ */
1408 
1409 /** a default implementation of expression interval evaluation that always gives a correct result */
1410 static
1411 SCIP_DECL_EXPRINTEVAL( exprevalIntDefault )
1412 { /*lint --e{715}*/
1414 
1415  return SCIP_OKAY;
1416 }
1417 
1418 /** a default implementation of expression curvature check that always gives a correct result */
1419 static
1420 SCIP_DECL_EXPRCURV( exprcurvDefault )
1421 { /*lint --e{715}*/
1422  *result = SCIP_EXPRCURV_UNKNOWN;
1423 
1424  return SCIP_OKAY;
1425 }
1426 
1427 /** point evaluation for EXPR_VAR */
1428 static
1429 SCIP_DECL_EXPREVAL( exprevalVar )
1430 { /*lint --e{715}*/
1431  assert(result != NULL);
1432  assert(varvals != NULL);
1433 
1434  *result = varvals[opdata.intval];
1435 
1436  return SCIP_OKAY;
1437 }
1438 
1439 /** interval evaluation for EXPR_VAR */
1440 static
1441 SCIP_DECL_EXPRINTEVAL( exprevalIntVar )
1442 { /*lint --e{715}*/
1443  assert(result != NULL);
1444  assert(varvals != NULL);
1445 
1446  *result = varvals[opdata.intval];
1447 
1448  return SCIP_OKAY;
1449 }
1450 
1451 /** curvature for EXPR_VAR */
1452 static
1453 SCIP_DECL_EXPRCURV( exprcurvVar )
1454 { /*lint --e{715}*/
1455  assert(result != NULL);
1456 
1457  *result = SCIP_EXPRCURV_LINEAR;
1458 
1459  return SCIP_OKAY;
1460 }
1461 
1462 /** point evaluation for EXPR_CONST */
1463 static
1464 SCIP_DECL_EXPREVAL( exprevalConst )
1465 { /*lint --e{715}*/
1466  assert(result != NULL);
1467 
1468  *result = opdata.dbl;
1469 
1470  return SCIP_OKAY;
1471 }
1472 
1473 /** interval evaluation for EXPR_CONST */
1474 static
1475 SCIP_DECL_EXPRINTEVAL( exprevalIntConst )
1476 { /*lint --e{715}*/
1477  assert(result != NULL);
1478 
1479  SCIPintervalSet(result, opdata.dbl);
1480 
1481  return SCIP_OKAY;
1482 }
1483 
1484 /** curvature for EXPR_CONST */
1485 static
1486 SCIP_DECL_EXPRCURV( exprcurvConst )
1487 { /*lint --e{715}*/
1488  assert(result != NULL);
1489 
1490  *result = SCIP_EXPRCURV_LINEAR;
1491 
1492  return SCIP_OKAY;
1493 }
1494 
1495 /** point evaluation for EXPR_PARAM */
1496 static
1497 SCIP_DECL_EXPREVAL( exprevalParam )
1498 { /*lint --e{715}*/
1499  assert(result != NULL);
1500  assert(paramvals != NULL );
1501 
1502  *result = paramvals[opdata.intval];
1503 
1504  return SCIP_OKAY;
1505 }
1506 
1507 /** interval evaluation for EXPR_PARAM */
1508 static
1509 SCIP_DECL_EXPRINTEVAL( exprevalIntParam )
1510 { /*lint --e{715}*/
1511  assert(result != NULL);
1512  assert(paramvals != NULL );
1513 
1514  SCIPintervalSet(result, paramvals[opdata.intval]);
1515 
1516  return SCIP_OKAY;
1517 }
1518 
1519 /** curvature for EXPR_PARAM */
1520 static
1521 SCIP_DECL_EXPRCURV( exprcurvParam )
1522 { /*lint --e{715}*/
1523  assert(result != NULL);
1524 
1525  *result = SCIP_EXPRCURV_LINEAR;
1526 
1527  return SCIP_OKAY;
1528 }
1529 
1530 /** point evaluation for EXPR_PLUS */
1531 static
1532 SCIP_DECL_EXPREVAL( exprevalPlus )
1533 { /*lint --e{715}*/
1534  assert(result != NULL);
1535  assert(argvals != NULL);
1536 
1537  *result = argvals[0] + argvals[1];
1538 
1539  return SCIP_OKAY;
1540 }
1541 
1542 /** interval evaluation for EXPR_PLUS */
1543 static
1544 SCIP_DECL_EXPRINTEVAL( exprevalIntPlus )
1545 { /*lint --e{715}*/
1546  assert(result != NULL);
1547  assert(argvals != NULL);
1548 
1549  SCIPintervalAdd(infinity, result, argvals[0], argvals[1]);
1550 
1551  return SCIP_OKAY;
1552 }
1553 
1554 /** curvature for EXPR_PLUS */
1555 static
1556 SCIP_DECL_EXPRCURV( exprcurvPlus )
1557 { /*lint --e{715}*/
1558  assert(result != NULL);
1559  assert(argcurv != NULL);
1560 
1561  *result = SCIPexprcurvAdd(argcurv[0], argcurv[1]);
1562 
1563  return SCIP_OKAY;
1564 }
1565 
1566 /** point evaluation for EXPR_MINUS */
1567 static
1568 SCIP_DECL_EXPREVAL( exprevalMinus )
1569 { /*lint --e{715}*/
1570  assert(result != NULL);
1571  assert(argvals != NULL);
1572 
1573  *result = argvals[0] - argvals[1];
1574 
1575  return SCIP_OKAY;
1576 }
1577 
1578 /** interval evaluation for EXPR_MINUS */
1579 static
1580 SCIP_DECL_EXPRINTEVAL( exprevalIntMinus )
1581 { /*lint --e{715}*/
1582  assert(result != NULL);
1583  assert(argvals != NULL);
1584 
1585  SCIPintervalSub(infinity, result, argvals[0], argvals[1]);
1586 
1587  return SCIP_OKAY;
1588 }
1589 
1590 /** curvature for EXPR_MINUS */
1591 static
1592 SCIP_DECL_EXPRCURV( exprcurvMinus )
1593 { /*lint --e{715}*/
1594  assert(result != NULL);
1595  assert(argcurv != NULL);
1596 
1597  *result = SCIPexprcurvAdd(argcurv[0], SCIPexprcurvNegate(argcurv[1]));
1598 
1599  return SCIP_OKAY;
1600 }
1601 
1602 /** point evaluation for EXPR_MUL */
1603 static
1604 SCIP_DECL_EXPREVAL( exprevalMult )
1605 { /*lint --e{715}*/
1606  assert(result != NULL);
1607  assert(argvals != NULL);
1608 
1609  *result = argvals[0] * argvals[1];
1610 
1611  return SCIP_OKAY;
1612 }
1613 
1614 /** interval evaluation for EXPR_MUL */
1615 static
1616 SCIP_DECL_EXPRINTEVAL( exprevalIntMult )
1617 { /*lint --e{715}*/
1618  assert(result != NULL);
1619  assert(argvals != NULL);
1620 
1621  SCIPintervalMul(infinity, result, argvals[0], argvals[1]);
1622 
1623  return SCIP_OKAY;
1624 }
1625 
1626 /** curvature for EXPR_MUL */
1627 static
1628 SCIP_DECL_EXPRCURV( exprcurvMult )
1629 { /*lint --e{715}*/
1630  assert(result != NULL);
1631  assert(argcurv != NULL);
1632  assert(argbounds != NULL);
1633 
1634  /* if one factor is constant, then product is
1635  * - linear, if constant is 0.0
1636  * - same curvature as other factor, if constant is positive
1637  * - negated curvature of other factor, if constant is negative
1638  *
1639  * if both factors are not constant, then product may not be convex nor concave
1640  */
1641  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1642  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1643  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1644  *result = SCIPexprcurvMultiply(argbounds[0].inf, argcurv[1]);
1645  else
1646  *result = SCIP_EXPRCURV_UNKNOWN;
1647 
1648  return SCIP_OKAY;
1649 }
1650 
1651 /** point evaluation for EXPR_DIV */
1652 static
1653 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1654 __attribute__((no_sanitize_undefined))
1655 #endif
1656 SCIP_DECL_EXPREVAL( exprevalDiv )
1657 { /*lint --e{715}*/
1658  assert(result != NULL);
1659  assert(argvals != NULL);
1660 
1661  *result = argvals[0] / argvals[1];
1662 
1663  return SCIP_OKAY;
1664 }
1665 
1666 /** interval evaluation for EXPR_DIV */
1667 static
1668 SCIP_DECL_EXPRINTEVAL( exprevalIntDiv )
1669 { /*lint --e{715}*/
1670  assert(result != NULL);
1671  assert(argvals != NULL);
1672 
1673  SCIPintervalDiv(infinity, result, argvals[0], argvals[1]);
1674 
1675  return SCIP_OKAY;
1676 }
1677 
1678 /** curvature for EXPR_DIV */
1679 static
1680 SCIP_DECL_EXPRCURV( exprcurvDiv )
1681 { /*lint --e{715}*/
1682  assert(result != NULL);
1683  assert(argcurv != NULL);
1684  assert(argbounds != NULL);
1685 
1686  /* if denominator is constant, then quotient has curvature sign(denominator) * curv(nominator)
1687  *
1688  * if nominator is a constant, then quotient is
1689  * - sign(nominator) * convex, if denominator is concave and positive
1690  * - sign(nominator) * concave, if denominator is convex and negative
1691  *
1692  * if denominator is positive but convex, then we don't know, e.g.,
1693  * - 1/x^2 is convex for x>=0
1694  * - 1/(1+(x-1)^2) is neither convex nor concave for x >= 0
1695  *
1696  * if both nominator and denominator are not constant, then quotient may not be convex nor concave
1697  */
1698  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1699  {
1700  /* denominator is constant */
1701  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1702  }
1703  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1704  {
1705  /* nominator is constant */
1706  if( argbounds[1].inf >= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
1707  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONVEX);
1708  else if( argbounds[1].sup <= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
1709  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONCAVE);
1710  else
1711  *result = SCIP_EXPRCURV_UNKNOWN;
1712  }
1713  else
1714  {
1715  /* denominator and nominator not constant */
1716  *result = SCIP_EXPRCURV_UNKNOWN;
1717  }
1718 
1719  return SCIP_OKAY;
1720 }
1721 
1722 /** point evaluation for EXPR_SQUARE */
1723 static
1724 SCIP_DECL_EXPREVAL( exprevalSquare )
1725 { /*lint --e{715}*/
1726  assert(result != NULL);
1727  assert(argvals != NULL);
1728 
1729  *result = argvals[0] * argvals[0];
1730 
1731  return SCIP_OKAY;
1732 }
1733 
1734 /** interval evaluation for EXPR_SQUARE */
1735 static
1736 SCIP_DECL_EXPRINTEVAL( exprevalIntSquare )
1737 { /*lint --e{715}*/
1738  assert(result != NULL);
1739  assert(argvals != NULL);
1740 
1741  SCIPintervalSquare(infinity, result, argvals[0]);
1742 
1743  return SCIP_OKAY;
1744 }
1745 
1746 /** curvature for EXPR_SQUARE */
1747 static
1748 SCIP_DECL_EXPRCURV( exprcurvSquare )
1749 { /*lint --e{715}*/
1750  assert(result != NULL);
1751  assert(argcurv != NULL);
1752  assert(argbounds != NULL);
1753 
1754  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], 2.0);
1755 
1756  return SCIP_OKAY;
1757 }
1758 
1759 /** point evaluation for EXPR_SQRT */
1760 static
1761 SCIP_DECL_EXPREVAL( exprevalSquareRoot )
1762 { /*lint --e{715}*/
1763  assert(result != NULL);
1764  assert(argvals != NULL);
1765 
1766  *result = sqrt(argvals[0]);
1767 
1768  return SCIP_OKAY;
1769 }
1770 
1771 /** interval evaluation for EXPR_SQRT */
1772 static
1773 SCIP_DECL_EXPRINTEVAL( exprevalIntSquareRoot )
1774 { /*lint --e{715}*/
1775  assert(result != NULL);
1776  assert(argvals != NULL);
1777 
1778  SCIPintervalSquareRoot(infinity, result, argvals[0]);
1779 
1780  return SCIP_OKAY;
1781 }
1782 
1783 /** curvature for EXPR_SQRT */
1784 static
1785 SCIP_DECL_EXPRCURV( exprcurvSquareRoot )
1786 { /*lint --e{715}*/
1787  assert(result != NULL);
1788  assert(argcurv != NULL);
1789 
1790  /* square-root is concave, if child is concave
1791  * otherwise, we don't know
1792  */
1793 
1794  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
1795  *result = SCIP_EXPRCURV_CONCAVE;
1796  else
1797  *result = SCIP_EXPRCURV_UNKNOWN;
1798 
1799  return SCIP_OKAY;
1800 }
1801 
1802 /** point evaluation for EXPR_REALPOWER */
1803 static
1804 SCIP_DECL_EXPREVAL( exprevalRealPower )
1805 { /*lint --e{715}*/
1806  assert(result != NULL);
1807  assert(argvals != NULL);
1808 
1809  *result = pow(argvals[0], opdata.dbl);
1810 
1811  return SCIP_OKAY;
1812 }
1813 
1814 /** interval evaluation for EXPR_REALPOWER */
1815 static
1816 SCIP_DECL_EXPRINTEVAL( exprevalIntRealPower )
1817 { /*lint --e{715}*/
1818  assert(result != NULL);
1819  assert(argvals != NULL);
1820 
1821  SCIPintervalPowerScalar(infinity, result, argvals[0], opdata.dbl);
1822 
1823  return SCIP_OKAY;
1824 }
1825 
1826 /** curvature for EXPR_REALPOWER */
1827 static
1828 SCIP_DECL_EXPRCURV( exprcurvRealPower )
1829 { /*lint --e{715}*/
1830  assert(result != NULL);
1831  assert(argcurv != NULL);
1832  assert(argbounds != NULL);
1833 
1834  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], opdata.dbl);
1835 
1836  return SCIP_OKAY;
1837 }
1838 
1839 /** point evaluation for EXPR_INTPOWER */
1840 static
1841 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1842 __attribute__((no_sanitize_undefined))
1843 #endif
1844 SCIP_DECL_EXPREVAL( exprevalIntPower )
1845 { /*lint --e{715}*/
1846  assert(result != NULL);
1847  assert(argvals != NULL);
1848 
1849  switch( opdata.intval )
1850  {
1851  case -1:
1852  *result = 1.0 / argvals[0];
1853  return SCIP_OKAY;
1854 
1855  case 0:
1856  *result = 1.0;
1857  return SCIP_OKAY;
1858 
1859  case 1:
1860  *result = argvals[0];
1861  return SCIP_OKAY;
1862 
1863  case 2:
1864  *result = argvals[0] * argvals[0];
1865  return SCIP_OKAY;
1866 
1867  default:
1868  *result = pow(argvals[0], (SCIP_Real)opdata.intval);
1869  }
1870 
1871  return SCIP_OKAY;
1872 }
1873 
1874 /** interval evaluation for EXPR_INTPOWER */
1875 static
1876 SCIP_DECL_EXPRINTEVAL( exprevalIntIntPower )
1877 { /*lint --e{715}*/
1878  assert(result != NULL);
1879  assert(argvals != NULL);
1880 
1881  SCIPintervalPowerScalar(infinity, result, argvals[0], (SCIP_Real)opdata.intval);
1882 
1883  return SCIP_OKAY;
1884 }
1885 
1886 /** curvature for EXPR_INTPOWER */
1887 static
1888 SCIP_DECL_EXPRCURV( exprcurvIntPower )
1889 { /*lint --e{715}*/
1890  assert(result != NULL);
1891  assert(argcurv != NULL);
1892  assert(argbounds != NULL);
1893 
1894  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], (SCIP_Real)opdata.intval);
1895 
1896  return SCIP_OKAY;
1897 }
1898 
1899 /** point evaluation for EXPR_SIGNPOWER */
1900 static
1901 SCIP_DECL_EXPREVAL( exprevalSignPower )
1902 { /*lint --e{715}*/
1903  assert(result != NULL);
1904  assert(argvals != NULL);
1905 
1906  if( argvals[0] > 0 )
1907  *result = pow( argvals[0], opdata.dbl);
1908  else
1909  *result = -pow(-argvals[0], opdata.dbl);
1910 
1911  return SCIP_OKAY;
1912 }
1913 
1914 /** interval evaluation for EXPR_SIGNPOWER */
1915 static
1916 SCIP_DECL_EXPRINTEVAL( exprevalIntSignPower )
1917 { /*lint --e{715}*/
1918  assert(result != NULL);
1919  assert(argvals != NULL);
1920 
1921  SCIPintervalSignPowerScalar(infinity, result, argvals[0], opdata.dbl);
1922 
1923  return SCIP_OKAY;
1924 }
1925 
1926 /** curvature for EXPR_SIGNPOWER */
1927 static
1928 SCIP_DECL_EXPRCURV( exprcurvSignPower )
1929 { /*lint --e{715}*/
1930  SCIP_INTERVAL tmp;
1931  SCIP_EXPRCURV left;
1932  SCIP_EXPRCURV right;
1933 
1934  assert(result != NULL);
1935  assert(argcurv != NULL);
1936  assert(argbounds != NULL);
1937 
1938  /* for x <= 0, signpower(x,c) = -(-x)^c
1939  * for x >= 0, signpower(x,c) = ( x)^c
1940  *
1941  * thus, get curvatures for both parts and "intersect" them
1942  */
1943 
1944  if( argbounds[0].inf < 0 )
1945  {
1946  SCIPintervalSetBounds(&tmp, 0.0, -argbounds[0].inf);
1947  left = SCIPexprcurvNegate(SCIPexprcurvPower(tmp, SCIPexprcurvNegate(argcurv[0]), opdata.dbl));
1948  }
1949  else
1950  {
1951  left = SCIP_EXPRCURV_LINEAR;
1952  }
1953 
1954  if( argbounds[0].sup > 0 )
1955  {
1956  SCIPintervalSetBounds(&tmp, 0.0, argbounds[0].sup);
1957  right = SCIPexprcurvPower(tmp, argcurv[0], opdata.dbl);
1958  }
1959  else
1960  {
1961  right = SCIP_EXPRCURV_LINEAR;
1962  }
1963 
1964  *result = (SCIP_EXPRCURV) (left & right);
1965 
1966  return SCIP_OKAY;
1967 }
1968 
1969 /** point evaluation for EXPR_EXP */
1970 static
1971 SCIP_DECL_EXPREVAL( exprevalExp )
1972 { /*lint --e{715}*/
1973  assert(result != NULL);
1974  assert(argvals != NULL);
1975 
1976  *result = exp(argvals[0]);
1977 
1978  return SCIP_OKAY;
1979 }
1980 
1981 /** interval evaluation for EXPR_EXP */
1982 static
1983 SCIP_DECL_EXPRINTEVAL( exprevalIntExp )
1984 { /*lint --e{715}*/
1985  assert(result != NULL);
1986  assert(argvals != NULL);
1987 
1988  SCIPintervalExp(infinity, result, argvals[0]);
1989 
1990  return SCIP_OKAY;
1991 }
1992 
1993 /** curvature for EXPR_EXP */
1994 static
1995 SCIP_DECL_EXPRCURV( exprcurvExp )
1996 { /*lint --e{715}*/
1997  assert(result != NULL);
1998  assert(argcurv != NULL);
1999 
2000  /* expression is convex if child is convex
2001  * otherwise, we don't know
2002  */
2003  if( argcurv[0] & SCIP_EXPRCURV_CONVEX )
2004  *result = SCIP_EXPRCURV_CONVEX;
2005  else
2006  *result = SCIP_EXPRCURV_UNKNOWN;
2007 
2008  return SCIP_OKAY;
2009 }
2010 
2011 /** point evaluation for EXPR_LOG */
2012 static
2013 SCIP_DECL_EXPREVAL( exprevalLog )
2014 { /*lint --e{715}*/
2015  assert(result != NULL);
2016  assert(argvals != NULL);
2017 
2018  *result = log(argvals[0]);
2019 
2020  return SCIP_OKAY;
2021 }
2022 
2023 /** interval evaluation for EXPR_LOG */
2024 static
2025 SCIP_DECL_EXPRINTEVAL( exprevalIntLog )
2026 { /*lint --e{715}*/
2027  assert(result != NULL);
2028  assert(argvals != NULL);
2029 
2030  SCIPintervalLog(infinity, result, argvals[0]);
2031 
2032  return SCIP_OKAY;
2033 }
2034 
2035 /** curvature for EXPR_LOG */
2036 static
2037 SCIP_DECL_EXPRCURV( exprcurvLog )
2038 { /*lint --e{715}*/
2039  assert(result != NULL);
2040  assert(argcurv != NULL);
2041 
2042  /* expression is concave if child is concave
2043  * otherwise, we don't know
2044  */
2045  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
2046  *result = SCIP_EXPRCURV_CONCAVE;
2047  else
2048  *result = SCIP_EXPRCURV_UNKNOWN;
2049 
2050  return SCIP_OKAY;
2051 }
2052 
2053 /** point evaluation for EXPR_SIN */
2054 static
2055 SCIP_DECL_EXPREVAL( exprevalSin )
2056 { /*lint --e{715}*/
2057  assert(result != NULL);
2058  assert(argvals != NULL);
2059 
2060  *result = sin(argvals[0]);
2061 
2062  return SCIP_OKAY;
2063 }
2064 
2065 /** interval evaluation for EXPR_SIN */
2066 static
2067 SCIP_DECL_EXPRINTEVAL( exprevalIntSin )
2068 { /*lint --e{715}*/
2069  assert(result != NULL);
2070  assert(argvals != NULL);
2071  assert(nargs == 1);
2072 
2073  SCIPintervalSin(infinity, result, *argvals);
2074 
2075  return SCIP_OKAY;
2076 }
2077 
2078 /* @todo implement exprcurvSin */
2079 #define exprcurvSin exprcurvDefault
2080 
2081 /** point evaluation for EXPR_COS */
2082 static
2083 SCIP_DECL_EXPREVAL( exprevalCos )
2084 { /*lint --e{715}*/
2085  assert(result != NULL);
2086  assert(argvals != NULL);
2087 
2088  *result = cos(argvals[0]);
2089 
2090  return SCIP_OKAY;
2091 }
2092 
2093 /** interval evaluation for EXPR_COS */
2094 static
2095 SCIP_DECL_EXPRINTEVAL( exprevalIntCos )
2096 { /*lint --e{715}*/
2097  assert(result != NULL);
2098  assert(argvals != NULL);
2099  assert(nargs == 1);
2100 
2101  SCIPintervalCos(infinity, result, *argvals);
2102 
2103  return SCIP_OKAY;
2104 }
2105 
2106 /* @todo implement exprcurvCos */
2107 #define exprcurvCos exprcurvDefault
2108 
2109 /** point evaluation for EXPR_TAN */
2110 static
2111 SCIP_DECL_EXPREVAL( exprevalTan )
2112 { /*lint --e{715}*/
2113  assert(result != NULL);
2114  assert(argvals != NULL);
2115 
2116  *result = tan(argvals[0]);
2117 
2118  return SCIP_OKAY;
2119 }
2120 
2121 /* @todo implement SCIPintervalTan */
2122 #define exprevalIntTan exprevalIntDefault
2123 
2124 /* @todo implement exprcurvTan */
2125 #define exprcurvTan exprcurvDefault
2126 
2127 /* erf and erfi do not seem to exist on every system, and we cannot really handle them anyway, so they are currently disabled */
2128 #ifdef SCIP_DISABLED_CODE
2129 static
2130 SCIP_DECL_EXPREVAL( exprevalErf )
2131 { /*lint --e{715}*/
2132  assert(result != NULL);
2133  assert(argvals != NULL);
2134 
2135  *result = erf(argvals[0]);
2136 
2137  return SCIP_OKAY;
2138 }
2139 
2140 /* @todo implement SCIPintervalErf */
2141 #define exprevalIntErf exprevalIntDefault
2142 
2143 /* @todo implement SCIPintervalErf */
2144 #define exprcurvErf exprcurvDefault
2145 
2146 static
2147 SCIP_DECL_EXPREVAL( exprevalErfi )
2148 { /*lint --e{715}*/
2149  assert(result != NULL);
2150  assert(argvals != NULL);
2151 
2152  /* @TODO implement erfi evaluation */
2153  SCIPerrorMessage("erfi not implemented");
2154 
2155  return SCIP_ERROR;
2156 }
2157 
2158 /* @todo implement SCIPintervalErfi */
2159 #define exprevalIntErfi NULL
2160 
2161 #define exprcurvErfi exprcurvDefault
2162 #endif
2163 
2164 /** point evaluation for EXPR_MIN */
2165 static
2166 SCIP_DECL_EXPREVAL( exprevalMin )
2167 { /*lint --e{715}*/
2168  assert(result != NULL);
2169  assert(argvals != NULL);
2170 
2171  *result = MIN(argvals[0], argvals[1]);
2172 
2173  return SCIP_OKAY;
2174 }
2175 
2176 /** interval evaluation for EXPR_MIN */
2177 static
2178 SCIP_DECL_EXPRINTEVAL( exprevalIntMin )
2179 { /*lint --e{715}*/
2180  assert(result != NULL);
2181  assert(argvals != NULL);
2182 
2183  SCIPintervalMin(infinity, result, argvals[0], argvals[1]);
2184 
2185  return SCIP_OKAY;
2186 }
2187 
2188 /** curvature for EXPR_MIN */
2189 static
2190 SCIP_DECL_EXPRCURV( exprcurvMin )
2191 { /*lint --e{715}*/
2192  assert(result != NULL);
2193  assert(argcurv != NULL);
2194 
2195  /* the minimum of two concave functions is concave
2196  * otherwise, we don't know
2197  */
2198 
2199  if( (argcurv[0] & SCIP_EXPRCURV_CONCAVE) && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
2200  *result = SCIP_EXPRCURV_CONCAVE;
2201  else
2202  *result = SCIP_EXPRCURV_UNKNOWN;
2203 
2204  return SCIP_OKAY;
2205 }
2206 
2207 /** point evaluation for EXPR_MAX */
2208 static
2209 SCIP_DECL_EXPREVAL( exprevalMax )
2210 { /*lint --e{715}*/
2211  assert(result != NULL);
2212  assert(argvals != NULL);
2213 
2214  *result = MAX(argvals[0], argvals[1]);
2215 
2216  return SCIP_OKAY;
2217 }
2218 
2219 /** interval evaluation for EXPR_MAX */
2220 static
2221 SCIP_DECL_EXPRINTEVAL( exprevalIntMax )
2222 { /*lint --e{715}*/
2223  assert(result != NULL);
2224  assert(argvals != NULL);
2225 
2226  SCIPintervalMax(infinity, result, argvals[0], argvals[1]);
2227 
2228  return SCIP_OKAY;
2229 }
2230 
2231 /** curvature for EXPR_MAX */
2232 static
2233 SCIP_DECL_EXPRCURV( exprcurvMax )
2234 { /*lint --e{715}*/
2235  assert(result != NULL);
2236  assert(argcurv != NULL);
2237 
2238  /* the maximum of two convex functions is convex
2239  * otherwise, we don't know
2240  */
2241  if( (argcurv[0] & SCIP_EXPRCURV_CONVEX) && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
2242  *result = SCIP_EXPRCURV_CONVEX;
2243  else
2244  *result = SCIP_EXPRCURV_UNKNOWN;
2245 
2246  return SCIP_OKAY;
2247 }
2248 
2249 /** point evaluation for EXPR_ABS */
2250 static
2251 SCIP_DECL_EXPREVAL( exprevalAbs )
2252 { /*lint --e{715}*/
2253  assert(result != NULL);
2254  assert(argvals != NULL);
2255 
2256  *result = ABS(argvals[0]);
2257 
2258  return SCIP_OKAY;
2259 }
2260 
2261 /** interval evaluation for EXPR_ABS */
2262 static
2263 SCIP_DECL_EXPRINTEVAL( exprevalIntAbs )
2264 { /*lint --e{715}*/
2265  assert(result != NULL);
2266  assert(argvals != NULL);
2267 
2268  SCIPintervalAbs(infinity, result, argvals[0]);
2269 
2270  return SCIP_OKAY;
2271 }
2272 
2273 /** curvature for EXPR_ABS */
2274 static
2275 SCIP_DECL_EXPRCURV( exprcurvAbs )
2276 { /*lint --e{715}*/
2277  assert(result != NULL);
2278  assert(argcurv != NULL);
2279  assert(argbounds != NULL);
2280 
2281  /* if child is only negative, then abs(child) = -child
2282  * if child is only positive, then abs(child) = child
2283  * if child is both positive and negative, but also linear, then abs(child) is convex
2284  * otherwise, we don't know
2285  */
2286  if( argbounds[0].sup <= 0.0 )
2287  *result = SCIPexprcurvMultiply(-1.0, argcurv[0]);
2288  else if( argbounds[0].inf >= 0.0 )
2289  *result = argcurv[0];
2290  else if( argcurv[0] == SCIP_EXPRCURV_LINEAR )
2291  *result = SCIP_EXPRCURV_CONVEX;
2292  else
2293  *result = SCIP_EXPRCURV_UNKNOWN;
2294 
2295  return SCIP_OKAY;
2296 }
2297 
2298 /** point evaluation for EXPR_SIGN */
2299 static
2300 SCIP_DECL_EXPREVAL( exprevalSign )
2301 { /*lint --e{715}*/
2302  assert(result != NULL);
2303  assert(argvals != NULL);
2304 
2305  *result = SIGN(argvals[0]);
2306 
2307  return SCIP_OKAY;
2308 }
2309 
2310 /** interval evaluation for EXPR_SIGN */
2311 static
2312 SCIP_DECL_EXPRINTEVAL( exprevalIntSign )
2313 { /*lint --e{715}*/
2314  assert(result != NULL);
2315  assert(argvals != NULL);
2316 
2317  SCIPintervalSign(infinity, result, argvals[0]);
2318 
2319  return SCIP_OKAY;
2320 }
2321 
2322 /** curvature for EXPR_SIGN */
2323 static
2324 SCIP_DECL_EXPRCURV( exprcurvSign )
2325 { /*lint --e{715}*/
2326  assert(result != NULL);
2327  assert(argbounds != NULL);
2328 
2329  /* if sign of child is clear, then sign is linear otherwise, we don't know */
2330  if( argbounds[0].sup <= 0.0 || argbounds[0].inf >= 0.0 )
2331  *result = SCIP_EXPRCURV_LINEAR;
2332  else
2333  *result = SCIP_EXPRCURV_UNKNOWN;
2334 
2335  return SCIP_OKAY;
2336 }
2337 
2338 /** point evaluation for EXPR_SUM */
2339 static
2340 SCIP_DECL_EXPREVAL( exprevalSum )
2341 { /*lint --e{715}*/
2342  int i;
2343 
2344  assert(result != NULL);
2345  assert(argvals != NULL);
2346 
2347  *result = 0.0;
2348  for( i = 0; i < nargs; ++i )
2349  *result += argvals[i];
2350 
2351  return SCIP_OKAY;
2352 }
2353 
2354 /** interval evaluation for EXPR_SUM */
2355 static
2356 SCIP_DECL_EXPRINTEVAL( exprevalIntSum )
2357 { /*lint --e{715}*/
2358  int i;
2359 
2360  assert(result != NULL);
2361  assert(argvals != NULL);
2362 
2363  SCIPintervalSet(result, 0.0);
2364 
2365  for( i = 0; i < nargs; ++i )
2366  SCIPintervalAdd(infinity, result, *result, argvals[i]);
2367 
2368  return SCIP_OKAY;
2369 }
2370 
2371 /** curvature for EXPR_SUM */
2372 static
2373 SCIP_DECL_EXPRCURV( exprcurvSum )
2374 { /*lint --e{715}*/
2375  int i;
2376 
2377  assert(result != NULL);
2378  assert(argcurv != NULL);
2379 
2380  *result = SCIP_EXPRCURV_LINEAR;
2381 
2382  for( i = 0; i < nargs; ++i )
2383  *result = SCIPexprcurvAdd(*result, argcurv[i]);
2384 
2385  return SCIP_OKAY;
2386 }
2387 
2388 /** point evaluation for EXPR_PRODUCT */
2389 static
2390 SCIP_DECL_EXPREVAL( exprevalProduct )
2391 { /*lint --e{715}*/
2392  int i;
2393 
2394  assert(result != NULL);
2395  assert(argvals != NULL);
2396 
2397  *result = 1.0;
2398  for( i = 0; i < nargs; ++i )
2399  *result *= argvals[i];
2400 
2401  return SCIP_OKAY;
2402 }
2403 
2404 /** interval evaluation for EXPR_PRODUCT */
2405 static
2406 SCIP_DECL_EXPRINTEVAL( exprevalIntProduct )
2407 { /*lint --e{715}*/
2408  int i;
2409 
2410  assert(result != NULL);
2411  assert(argvals != NULL);
2412 
2413  SCIPintervalSet(result, 1.0);
2414 
2415  for( i = 0; i < nargs; ++i )
2416  SCIPintervalMul(infinity, result, *result, argvals[i]);
2417 
2418  return SCIP_OKAY;
2419 }
2420 
2421 /** curvature for EXPR_PRODUCT */
2422 static
2423 SCIP_DECL_EXPRCURV( exprcurvProduct )
2424 { /*lint --e{715}*/
2425  SCIP_Bool hadnonconst;
2426  SCIP_Real constants;
2427  int i;
2428 
2429  assert(result != NULL);
2430  assert(argcurv != NULL);
2431  assert(argbounds != NULL);
2432 
2433  /* if all factors are constant, then product is linear (even constant)
2434  * if only one factor is not constant, then product is curvature of this factor, multiplied by sign of product of remaining factors
2435  */
2436  *result = SCIP_EXPRCURV_LINEAR;
2437  hadnonconst = FALSE;
2438  constants = 1.0;
2439 
2440  for( i = 0; i < nargs; ++i )
2441  {
2442  if( argbounds[i].inf == argbounds[i].sup ) /*lint !e777*/
2443  {
2444  constants *= argbounds[i].inf;
2445  }
2446  else if( !hadnonconst )
2447  {
2448  /* first non-constant child */
2449  *result = argcurv[i];
2450  hadnonconst = TRUE;
2451  }
2452  else
2453  {
2454  /* more than one non-constant child, thus don't know curvature */
2455  *result = SCIP_EXPRCURV_UNKNOWN;
2456  break;
2457  }
2458  }
2459 
2460  *result = SCIPexprcurvMultiply(constants, *result);
2461 
2462  return SCIP_OKAY;
2463 }
2464 
2465 /** point evaluation for EXPR_LINEAR */
2466 static
2467 SCIP_DECL_EXPREVAL( exprevalLinear )
2468 { /*lint --e{715}*/
2469  SCIP_Real* coef;
2470  int i;
2471 
2472  assert(result != NULL);
2473  assert(argvals != NULL || nargs == 0);
2474  assert(opdata.data != NULL);
2475 
2476  coef = &((SCIP_Real*)opdata.data)[nargs];
2477 
2478  *result = *coef;
2479  for( i = nargs-1, --coef; i >= 0; --i, --coef )
2480  *result += *coef * argvals[i]; /*lint !e613*/
2481 
2482  assert(++coef == (SCIP_Real*)opdata.data);
2483 
2484  return SCIP_OKAY;
2485 }
2486 
2487 /** interval evaluation for EXPR_LINEAR */
2488 static
2489 SCIP_DECL_EXPRINTEVAL( exprevalIntLinear )
2490 { /*lint --e{715}*/
2491  assert(result != NULL);
2492  assert(argvals != NULL || nargs == 0);
2493  assert(opdata.data != NULL);
2494 
2495  SCIPintervalScalprodScalars(infinity, result, nargs, argvals, (SCIP_Real*)opdata.data);
2496  SCIPintervalAddScalar(infinity, result, *result, ((SCIP_Real*)opdata.data)[nargs]);
2497 
2498  return SCIP_OKAY;
2499 }
2500 
2501 /** curvature for EXPR_LINEAR */
2502 static
2503 SCIP_DECL_EXPRCURV( exprcurvLinear )
2504 { /*lint --e{715}*/
2505  SCIP_Real* data;
2506  int i;
2507 
2508  assert(result != NULL);
2509  assert(argcurv != NULL);
2510 
2511  data = (SCIP_Real*)opdata.data;
2512  assert(data != NULL);
2513 
2514  *result = SCIP_EXPRCURV_LINEAR;
2515 
2516  for( i = 0; i < nargs; ++i )
2517  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(data[i], argcurv[i]));
2518 
2519  return SCIP_OKAY;
2520 }
2521 
2522 /** expression data copy for EXPR_LINEAR */
2523 static
2524 SCIP_DECL_EXPRCOPYDATA( exprCopyDataLinear )
2525 { /*lint --e{715}*/
2526  SCIP_Real* targetdata;
2527 
2528  assert(blkmem != NULL);
2529  assert(nchildren >= 0);
2530  assert(opdatatarget != NULL);
2531 
2532  /* for a linear expression, we need to copy the array that holds the coefficients and constant term */
2533  assert(opdatasource.data != NULL);
2534  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &targetdata, (SCIP_Real*)opdatasource.data, nchildren + 1) ); /*lint !e866*/
2535  opdatatarget->data = targetdata;
2536 
2537  return SCIP_OKAY;
2538 }
2539 
2540 /** expression data free for EXPR_LINEAR */
2541 static
2542 SCIP_DECL_EXPRFREEDATA( exprFreeDataLinear )
2543 { /*lint --e{715}*/
2544  SCIP_Real* freedata;
2545 
2546  assert(blkmem != NULL);
2547  assert(nchildren >= 0);
2548 
2549  freedata = (SCIP_Real*)opdata.data;
2550  assert(freedata != NULL);
2551 
2552  BMSfreeBlockMemoryArray(blkmem, &freedata, nchildren + 1); /*lint !e866*/
2553 }
2554 
2555 /** point evaluation for EXPR_QUADRATIC */
2556 static
2557 SCIP_DECL_EXPREVAL( exprevalQuadratic )
2558 { /*lint --e{715}*/
2559  SCIP_EXPRDATA_QUADRATIC* quaddata;
2560  SCIP_Real* lincoefs;
2561  SCIP_QUADELEM* quadelems;
2562  int nquadelems;
2563  int i;
2564 
2565  assert(result != NULL);
2566  assert(argvals != NULL || nargs == 0);
2567 
2568  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2569  assert(quaddata != NULL);
2570 
2571  lincoefs = quaddata->lincoefs;
2572  nquadelems = quaddata->nquadelems;
2573  quadelems = quaddata->quadelems;
2574 
2575  assert(quadelems != NULL || nquadelems == 0);
2576  assert(argvals != NULL || nquadelems == 0);
2577 
2578  *result = quaddata->constant;
2579 
2580  if( lincoefs != NULL )
2581  {
2582  for( i = nargs-1; i >= 0; --i )
2583  *result += lincoefs[i] * argvals[i]; /*lint !e613*/
2584  }
2585 
2586  for( i = 0; i < nquadelems; ++i, ++quadelems ) /*lint !e613*/
2587  *result += quadelems->coef * argvals[quadelems->idx1] * argvals[quadelems->idx2]; /*lint !e613*/
2588 
2589  return SCIP_OKAY;
2590 }
2591 
2592 /** interval evaluation for EXPR_QUADRATIC */
2593 static
2594 SCIP_DECL_EXPRINTEVAL( exprevalIntQuadratic )
2595 { /*lint --e{715}*/
2596  SCIP_EXPRDATA_QUADRATIC* quaddata;
2597  SCIP_Real* lincoefs;
2598  SCIP_QUADELEM* quadelems;
2599  int nquadelems;
2600  int i;
2601  int argidx;
2602  SCIP_Real sqrcoef;
2603  SCIP_INTERVAL lincoef;
2604  SCIP_INTERVAL tmp;
2605 
2606  assert(result != NULL);
2607  assert(argvals != NULL || nargs == 0);
2608 
2609  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2610  assert(quaddata != NULL);
2611 
2612  lincoefs = quaddata->lincoefs;
2613  nquadelems = quaddata->nquadelems;
2614  quadelems = quaddata->quadelems;
2615 
2616  assert(quadelems != NULL || nquadelems == 0);
2617  assert(argvals != NULL || nargs == 0);
2618 
2619  /* something fast for case of only one child */
2620  if( nargs == 1 )
2621  {
2622  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[0] : 0.0);
2623 
2624  sqrcoef = 0.0;
2625  for( i = 0; i < nquadelems; ++i )
2626  {
2627  assert(quadelems[i].idx1 == 0); /*lint !e613*/
2628  assert(quadelems[i].idx2 == 0); /*lint !e613*/
2629  sqrcoef += quadelems[i].coef; /*lint !e613*/
2630  }
2631 
2632  SCIPintervalQuad(infinity, result, sqrcoef, lincoef, argvals[0]); /*lint !e613*/
2633  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2634 
2635  return SCIP_OKAY;
2636  }
2637 
2638  if( nargs == 2 && nquadelems > 0 )
2639  {
2640  /* if it's a bivariate quadratic expression with bilinear term, do something special */
2641  SCIP_Real ax; /* square coefficient of first child */
2642  SCIP_Real ay; /* square coefficient of second child */
2643  SCIP_Real axy; /* bilinear coefficient */
2644 
2645  ax = 0.0;
2646  ay = 0.0;
2647  axy = 0.0;
2648  for( i = 0; i < nquadelems; ++i )
2649  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 ) /*lint !e613*/
2650  ax += quadelems[i].coef; /*lint !e613*/
2651  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 ) /*lint !e613*/
2652  ay += quadelems[i].coef; /*lint !e613*/
2653  else
2654  axy += quadelems[i].coef; /*lint !e613*/
2655 
2656  SCIPintervalQuadBivar(infinity, result, ax, ay, axy,
2657  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2658  argvals[0], argvals[1]); /*lint !e613*/
2659  SCIPdebugMessage("%g x^2 + %g y^2 + %g x y + %g x + %g y = [%g,%g] for x = [%g,%g], y = [%g,%g]\n",
2660  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2661  result->inf, result->sup, argvals[0].inf, argvals[0].sup, argvals[1].inf, argvals[1].sup); /*lint !e613*/
2662 
2663  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2664 
2665  return SCIP_OKAY;
2666  }
2667 
2668  /* make sure coefficients are sorted */
2669  quadraticdataSort(quaddata);
2670 
2671  SCIPintervalSet(result, quaddata->constant);
2672 
2673  /* for each argument, we collect it's linear index from lincoefs, it's square coefficients and all factors from bilinear terms
2674  * then we compute the interval sqrcoef*x^2 + lincoef*x and add it to result
2675  * @todo split quadratic expression into bivariate quadratic terms and apply the above method
2676  */
2677  i = 0;
2678  for( argidx = 0; argidx < nargs; ++argidx )
2679  {
2680  if( i == nquadelems || quadelems[i].idx1 > argidx ) /*lint !e613*/
2681  {
2682  /* there are no quadratic terms with argidx in its first argument, that should be easy to handle */
2683  if( lincoefs != NULL )
2684  {
2685  SCIPintervalMulScalar(infinity, &tmp, argvals[argidx], lincoefs[argidx]); /*lint !e613*/
2686  SCIPintervalAdd(infinity, result, *result, tmp);
2687  }
2688  continue;
2689  }
2690 
2691  sqrcoef = 0.0;
2692  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[argidx] : 0.0);
2693 
2694  assert(i < nquadelems && quadelems[i].idx1 == argidx); /*lint !e613*/
2695  do
2696  {
2697  if( quadelems[i].idx2 == argidx ) /*lint !e613*/
2698  {
2699  sqrcoef += quadelems[i].coef; /*lint !e613*/
2700  }
2701  else
2702  {
2703  SCIPintervalMulScalar(infinity, &tmp, argvals[quadelems[i].idx2], quadelems[i].coef); /*lint !e613*/
2704  SCIPintervalAdd(infinity, &lincoef, lincoef, tmp);
2705  }
2706  ++i;
2707  }
2708  while( i < nquadelems && quadelems[i].idx1 == argidx ); /*lint !e613*/
2709  assert(i == nquadelems || quadelems[i].idx1 > argidx); /*lint !e613*/
2710 
2711  SCIPintervalQuad(infinity, &tmp, sqrcoef, lincoef, argvals[argidx]); /*lint !e613*/
2712  SCIPintervalAdd(infinity, result, *result, tmp);
2713  }
2714  assert(i == nquadelems);
2715 
2716  return SCIP_OKAY;
2717 }
2718 
2719 /** curvature for EXPR_QUADRATIC */
2720 static
2721 SCIP_DECL_EXPRCURV( exprcurvQuadratic )
2722 { /*lint --e{715}*/
2724  SCIP_QUADELEM* quadelems;
2725  int nquadelems;
2726  SCIP_Real* lincoefs;
2727  int i;
2728 
2729  assert(result != NULL);
2730  assert(argcurv != NULL);
2731  assert(argbounds != NULL);
2732 
2733  data = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2734  assert(data != NULL);
2735 
2736  lincoefs = data->lincoefs;
2737  quadelems = data->quadelems;
2738  nquadelems = data->nquadelems;
2739 
2740  *result = SCIP_EXPRCURV_LINEAR;
2741 
2742  if( lincoefs != NULL )
2743  for( i = 0; i < nargs; ++i )
2744  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(lincoefs[i], argcurv[i]));
2745 
2746  /* @todo could try cholesky factorization if all children linear...
2747  * @todo should then cache the result
2748  */
2749  for( i = 0; i < nquadelems && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
2750  {
2751  if( quadelems[i].coef == 0.0 )
2752  continue;
2753 
2754  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup && /*lint !e777*/
2755  +argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup
2756  ) /*lint !e777*/
2757  {
2758  /* both factors are constants -> curvature does not change */
2759  continue;
2760  }
2761 
2762  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup ) /*lint !e777*/
2763  {
2764  /* first factor is constant, second is not -> add curvature of second */
2765  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx1].inf, argcurv[quadelems[i].idx2]));
2766  }
2767  else if( argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup ) /*lint !e777*/
2768  {
2769  /* first factor is not constant, second is -> add curvature of first */
2770  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx2].inf, argcurv[quadelems[i].idx1]));
2771  }
2772  else if( quadelems[i].idx1 == quadelems[i].idx2 )
2773  {
2774  /* both factors not constant, but the same (square term) */
2775  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef, SCIPexprcurvPower(argbounds[quadelems[i].idx1], argcurv[quadelems[i].idx1], 2.0)));
2776  }
2777  else
2778  {
2779  /* two different non-constant factors -> can't tell about curvature */
2780  *result = SCIP_EXPRCURV_UNKNOWN;
2781  }
2782  }
2783 
2784  return SCIP_OKAY;
2785 }
2786 
2787 /** expression data copy for EXPR_QUADRATIC */
2788 static
2789 SCIP_DECL_EXPRCOPYDATA( exprCopyDataQuadratic )
2790 { /*lint --e{715}*/
2791  SCIP_EXPRDATA_QUADRATIC* sourcedata;
2792 
2793  assert(blkmem != NULL);
2794  assert(opdatatarget != NULL);
2795 
2796  sourcedata = (SCIP_EXPRDATA_QUADRATIC*)opdatasource.data;
2797  assert(sourcedata != NULL);
2798 
2799  SCIP_CALL( quadraticdataCreate(blkmem, (SCIP_EXPRDATA_QUADRATIC**)&opdatatarget->data,
2800  sourcedata->constant, nchildren, sourcedata->lincoefs, sourcedata->nquadelems, sourcedata->quadelems) );
2801 
2802  return SCIP_OKAY;
2803 }
2804 
2805 /** expression data free for EXPR_QUADRATIC */
2806 static
2807 SCIP_DECL_EXPRFREEDATA( exprFreeDataQuadratic )
2808 { /*lint --e{715}*/
2809  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
2810 
2811  assert(blkmem != NULL);
2812  assert(nchildren >= 0);
2813 
2814  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2815  assert(quadraticdata != NULL);
2816 
2817  if( quadraticdata->lincoefs != NULL )
2818  {
2819  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->lincoefs, nchildren);
2820  }
2821 
2822  if( quadraticdata->nquadelems > 0 )
2823  {
2824  assert(quadraticdata->quadelems != NULL);
2825  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->quadelems, quadraticdata->nquadelems);
2826  }
2827 
2828  BMSfreeBlockMemory(blkmem, &quadraticdata);
2829 }
2830 
2831 /** point evaluation for EXPR_POLYNOMIAL */
2832 static
2833 SCIP_DECL_EXPREVAL( exprevalPolynomial )
2834 { /*lint --e{715}*/
2835  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2836  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2837  SCIP_Real childval;
2838  SCIP_Real exponent;
2839  SCIP_Real monomialval;
2840  int i;
2841  int j;
2842 
2843  assert(result != NULL);
2844  assert(argvals != NULL || nargs == 0);
2845  assert(opdata.data != NULL);
2846 
2847  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2848  assert(polynomialdata != NULL);
2849 
2850  *result = polynomialdata->constant;
2851 
2852  for( i = 0; i < polynomialdata->nmonomials; ++i )
2853  {
2854  monomialdata = polynomialdata->monomials[i];
2855  assert(monomialdata != NULL);
2856 
2857  monomialval = monomialdata->coef;
2858  for( j = 0; j < monomialdata->nfactors; ++j )
2859  {
2860  assert(monomialdata->childidxs[j] >= 0);
2861  assert(monomialdata->childidxs[j] < nargs);
2862 
2863  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2864  if( childval == 1.0 ) /* 1^anything == 1 */
2865  continue;
2866 
2867  exponent = monomialdata->exponents[j];
2868 
2869  if( childval == 0.0 )
2870  {
2871  if( exponent > 0.0 )
2872  {
2873  /* 0^positive == 0 */
2874  monomialval = 0.0;
2875  break;
2876  }
2877  else if( exponent < 0.0 )
2878  {
2879  /* 0^negative = nan (or should it be +inf?, doesn't really matter) */
2880 #ifdef NAN
2881  *result = NAN;
2882 #else
2883  /* cppcheck-suppress wrongmathcall */
2884  *result = pow(0.0, -1.0);
2885 #endif
2886  return SCIP_OKAY;
2887  }
2888  /* 0^0 == 1 */
2889  continue;
2890  }
2891 
2892  /* cover some special exponents separately to avoid calling expensive pow function */
2893  if( exponent == 0.0 )
2894  continue;
2895  if( exponent == 1.0 )
2896  {
2897  monomialval *= childval;
2898  continue;
2899  }
2900  if( exponent == 2.0 )
2901  {
2902  monomialval *= childval * childval;
2903  continue;
2904  }
2905  if( exponent == 0.5 )
2906  {
2907  monomialval *= sqrt(childval);
2908  continue;
2909  }
2910  if( exponent == -1.0 )
2911  {
2912  monomialval /= childval;
2913  continue;
2914  }
2915  if( exponent == -2.0 )
2916  {
2917  monomialval /= childval * childval;
2918  continue;
2919  }
2920  monomialval *= pow(childval, exponent);
2921  }
2922 
2923  *result += monomialval;
2924  }
2925 
2926  return SCIP_OKAY;
2927 }
2928 
2929 /** interval evaluation for EXPR_POLYNOMIAL */
2930 static
2931 SCIP_DECL_EXPRINTEVAL( exprevalIntPolynomial )
2932 { /*lint --e{715}*/
2933  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2934  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2935  SCIP_INTERVAL childval;
2936  SCIP_INTERVAL monomialval;
2937  SCIP_Real exponent;
2938  int i;
2939  int j;
2940 
2941  assert(result != NULL);
2942  assert(argvals != NULL || nargs == 0);
2943  assert(opdata.data != NULL);
2944 
2945  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2946  assert(polynomialdata != NULL);
2947 
2948  SCIPintervalSet(result, polynomialdata->constant);
2949 
2950  for( i = 0; i < polynomialdata->nmonomials; ++i )
2951  {
2952  monomialdata = polynomialdata->monomials[i];
2953  assert(monomialdata != NULL);
2954 
2955  SCIPintervalSet(&monomialval, monomialdata->coef);
2956  for( j = 0; j < monomialdata->nfactors && !SCIPintervalIsEntire(infinity, monomialval); ++j )
2957  {
2958  assert(monomialdata->childidxs[j] >= 0);
2959  assert(monomialdata->childidxs[j] < nargs);
2960 
2961  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2962 
2963  exponent = monomialdata->exponents[j];
2964 
2965  /* cover some special exponents separately to avoid calling expensive pow function */
2966  if( exponent == 0.0 )
2967  continue;
2968 
2969  if( exponent == 1.0 )
2970  {
2971  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2972  continue;
2973  }
2974 
2975  if( exponent == 2.0 )
2976  {
2977  SCIPintervalSquare(infinity, &childval, childval);
2978  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2979  continue;
2980  }
2981 
2982  if( exponent == 0.5 )
2983  {
2984  SCIPintervalSquareRoot(infinity, &childval, childval);
2985  if( SCIPintervalIsEmpty(infinity, childval) )
2986  {
2987  SCIPintervalSetEmpty(result);
2988  return SCIP_OKAY;
2989  }
2990  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2991  continue;
2992  }
2993  else if( exponent == -1.0 )
2994  {
2995  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2996  }
2997  else if( exponent == -2.0 )
2998  {
2999  SCIPintervalSquare(infinity, &childval, childval);
3000  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
3001  }
3002  else
3003  {
3004  SCIPintervalPowerScalar(infinity, &childval, childval, exponent);
3005  if( SCIPintervalIsEmpty(infinity, childval) )
3006  {
3007  SCIPintervalSetEmpty(result);
3008  return SCIP_OKAY;
3009  }
3010  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
3011  }
3012 
3013  /* the cases in which monomialval gets empty should have been catched */
3014  assert(!SCIPintervalIsEmpty(infinity, monomialval));
3015  }
3016 
3017  SCIPintervalAdd(infinity, result, *result, monomialval);
3018  }
3019 
3020  return SCIP_OKAY;
3021 }
3022 
3023 /** curvature for EXPR_POLYNOMIAL */
3024 static
3025 SCIP_DECL_EXPRCURV( exprcurvPolynomial )
3026 { /*lint --e{715}*/
3028  SCIP_EXPRDATA_MONOMIAL** monomials;
3029  SCIP_EXPRDATA_MONOMIAL* monomial;
3030  int nmonomials;
3031  int i;
3032 
3033  assert(result != NULL);
3034  assert(argcurv != NULL);
3035  assert(argbounds != NULL);
3036 
3037  data = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3038  assert(data != NULL);
3039 
3040  monomials = data->monomials;
3041  nmonomials = data->nmonomials;
3042 
3043  *result = SCIP_EXPRCURV_LINEAR;
3044 
3045  for( i = 0; i < nmonomials && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
3046  {
3047  /* we assume that some simplifier was running, so that monomials do not have constants in their factors and such that all factors are different
3048  * (result would still be correct)
3049  */
3050  monomial = monomials[i];
3051  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(monomial->coef, SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, monomial->childidxs, argcurv, argbounds)));
3052  }
3053 
3054  return SCIP_OKAY;
3055 }
3056 
3057 /** expression data copy for EXPR_POLYNOMIAL */
3058 static
3059 SCIP_DECL_EXPRCOPYDATA( exprCopyDataPolynomial )
3060 { /*lint --e{715}*/
3061  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata;
3062  SCIP_EXPRDATA_POLYNOMIAL* targetpolynomialdata;
3063 
3064  assert(blkmem != NULL);
3065  assert(opdatatarget != NULL);
3066 
3067  sourcepolynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdatasource.data;
3068  assert(sourcepolynomialdata != NULL);
3069 
3070  SCIP_CALL( polynomialdataCopy(blkmem, &targetpolynomialdata, sourcepolynomialdata) );
3071 
3072  opdatatarget->data = (void*)targetpolynomialdata;
3073 
3074  return SCIP_OKAY;
3075 }
3076 
3077 /** expression data free for EXPR_POLYNOMIAL */
3078 static
3079 SCIP_DECL_EXPRFREEDATA( exprFreeDataPolynomial )
3080 { /*lint --e{715}*/
3081  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3082 
3083  assert(blkmem != NULL);
3084 
3085  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3086  assert(polynomialdata != NULL);
3087 
3088  polynomialdataFree(blkmem, &polynomialdata);
3089 }
3090 
3091 /** point evaluation for user expression */
3092 static
3093 SCIP_DECL_EXPREVAL( exprevalUser )
3094 { /*lint --e{715}*/
3095  SCIP_EXPRDATA_USER* exprdata;
3096 
3097  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3098 
3099  SCIP_CALL( exprdata->eval(exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3100 
3101  return SCIP_OKAY;
3102 }
3103 
3104 /** interval evaluation for user expression */
3105 static
3106 SCIP_DECL_EXPRINTEVAL( exprevalIntUser )
3107 { /*lint --e{715}*/
3108  SCIP_EXPRDATA_USER* exprdata;
3109 
3110  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3111 
3112  if( exprdata->inteval != NULL )
3113  {
3114  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3115  }
3116  else
3117  {
3118  /* if user does not provide interval evaluation, then return a result that is always correct */
3120  }
3121 
3122  return SCIP_OKAY;
3123 }
3124 
3125 /** curvature check for user expression */
3126 static
3127 SCIP_DECL_EXPRCURV( exprcurvUser )
3128 {
3129  SCIP_EXPRDATA_USER* exprdata;
3130 
3131  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3132 
3133  if( exprdata->curv != NULL )
3134  {
3135  SCIP_CALL( exprdata->curv(infinity, exprdata->userdata, nargs, argbounds, argcurv, result) );
3136  }
3137  else
3138  {
3139  /* if user does not provide curvature check, then return unknown (which is handled like indefinite) */
3140  *result = SCIP_EXPRCURV_UNKNOWN;
3141  }
3142 
3143  return SCIP_OKAY;
3144 }
3145 
3146 /** data copy for user expression */
3147 static
3148 SCIP_DECL_EXPRCOPYDATA( exprCopyDataUser )
3149 {
3150  SCIP_EXPRDATA_USER* exprdatasource;
3151  SCIP_EXPRDATA_USER* exprdatatarget;
3152 
3153  assert(blkmem != NULL);
3154  assert(opdatatarget != NULL);
3155 
3156  exprdatasource = (SCIP_EXPRDATA_USER*)opdatasource.data;
3157  assert(exprdatasource != NULL);
3158 
3159  /* duplicate expression data */
3160  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, &exprdatatarget, exprdatasource) );
3161 
3162  /* duplicate user expression data, if any */
3163  if( exprdatasource->copydata != NULL )
3164  {
3165  SCIP_CALL( exprdatasource->copydata(blkmem, nchildren, exprdatasource->userdata, &exprdatatarget->userdata) );
3166  }
3167  else
3168  {
3169  /* if no copy function for data, then there has to be no data */
3170  assert(exprdatatarget->userdata == NULL);
3171  }
3172 
3173  opdatatarget->data = (void*)exprdatatarget;
3174 
3175  return SCIP_OKAY;
3176 }
3177 
3178 /** data free for user expression */
3179 static
3180 SCIP_DECL_EXPRFREEDATA( exprFreeDataUser )
3181 {
3182  SCIP_EXPRDATA_USER* exprdata;
3183 
3184  assert(blkmem != NULL);
3185 
3186  exprdata = (SCIP_EXPRDATA_USER*)opdata.data;
3187 
3188  /* free user expression data, if any */
3189  if( exprdata->freedata != NULL )
3190  {
3191  exprdata->freedata(blkmem, nchildren, exprdata->userdata);
3192  }
3193  else
3194  {
3195  assert(exprdata->userdata == NULL);
3196  }
3197 
3198  /* free expression data */
3199  BMSfreeBlockMemory(blkmem, &exprdata);
3200 }
3201 
3202 /** element in table of expression operands */
3203 struct exprOpTableElement
3204 {
3205  const char* name; /**< name of operand (used for printing) */
3206  int nargs; /**< number of arguments (negative if not fixed) */
3207  SCIP_DECL_EXPREVAL ((*eval)); /**< evaluation function */
3208  SCIP_DECL_EXPRINTEVAL ((*inteval)); /**< interval evaluation function */
3209  SCIP_DECL_EXPRCURV ((*curv)); /**< curvature check function */
3210  SCIP_DECL_EXPRCOPYDATA ((*copydata)); /**< expression data copy function, or NULL to only opdata union */
3211  SCIP_DECL_EXPRFREEDATA ((*freedata)); /**< expression data free function, or NULL if nothing to free */
3212 };
3213 
3214 #define EXPROPEMPTY {NULL, -1, NULL, NULL, NULL, NULL, NULL}
3215 
3216 /** table containing for each operand the name, the number of children, and some evaluation functions */
3217 static
3218 struct exprOpTableElement exprOpTable[] =
3219  {
3220  EXPROPEMPTY,
3221  { "variable", 0, exprevalVar, exprevalIntVar, exprcurvVar, NULL, NULL },
3222  { "constant", 0, exprevalConst, exprevalIntConst, exprcurvConst, NULL, NULL },
3223  { "parameter", 0, exprevalParam, exprevalIntParam, exprcurvParam, NULL, NULL },
3225  { "plus", 2, exprevalPlus, exprevalIntPlus, exprcurvPlus, NULL, NULL },
3226  { "minus", 2, exprevalMinus, exprevalIntMinus, exprcurvMinus, NULL, NULL },
3227  { "mul", 2, exprevalMult, exprevalIntMult, exprcurvMult, NULL, NULL },
3228  { "div", 2, exprevalDiv, exprevalIntDiv, exprcurvDiv, NULL, NULL },
3229  { "sqr", 1, exprevalSquare, exprevalIntSquare, exprcurvSquare, NULL, NULL },
3230  { "sqrt", 1, exprevalSquareRoot, exprevalIntSquareRoot, exprcurvSquareRoot, NULL, NULL },
3231  { "realpower", 1, exprevalRealPower, exprevalIntRealPower, exprcurvRealPower, NULL, NULL },
3232  { "intpower", 1, exprevalIntPower, exprevalIntIntPower, exprcurvIntPower, NULL, NULL },
3233  { "signpower", 1, exprevalSignPower, exprevalIntSignPower, exprcurvSignPower, NULL, NULL },
3234  { "exp", 1, exprevalExp, exprevalIntExp, exprcurvExp, NULL, NULL },
3235  { "log", 1, exprevalLog, exprevalIntLog, exprcurvLog, NULL, NULL },
3236  { "sin", 1, exprevalSin, exprevalIntSin, exprcurvSin, NULL, NULL },
3237  { "cos", 1, exprevalCos, exprevalIntCos, exprcurvCos, NULL, NULL },
3238  { "tan", 1, exprevalTan, exprevalIntTan, exprcurvTan, NULL, NULL },
3239  /* { "erf", 1, exprevalErf, exprevalIntErf, exprcurvErf, NULL, NULL }, */
3240  /* { "erfi", 1, exprevalErfi, exprevalIntErfi exprcurvErfi, NULL, NULL }, */
3242  { "min", 2, exprevalMin, exprevalIntMin, exprcurvMin, NULL, NULL },
3243  { "max", 2, exprevalMax, exprevalIntMax, exprcurvMax, NULL, NULL },
3244  { "abs", 1, exprevalAbs, exprevalIntAbs, exprcurvAbs, NULL, NULL },
3245  { "sign", 1, exprevalSign, exprevalIntSign, exprcurvSign, NULL, NULL },
3251  { "sum", -2, exprevalSum, exprevalIntSum, exprcurvSum, NULL, NULL },
3252  { "prod", -2, exprevalProduct, exprevalIntProduct, exprcurvProduct, NULL, NULL },
3253  { "linear", -2, exprevalLinear, exprevalIntLinear, exprcurvLinear, exprCopyDataLinear, exprFreeDataLinear },
3254  { "quadratic", -2, exprevalQuadratic, exprevalIntQuadratic, exprcurvQuadratic, exprCopyDataQuadratic, exprFreeDataQuadratic },
3255  { "polynomial", -2, exprevalPolynomial, exprevalIntPolynomial, exprcurvPolynomial, exprCopyDataPolynomial, exprFreeDataPolynomial },
3256  { "user", -2, exprevalUser, exprevalIntUser, exprcurvUser, exprCopyDataUser, exprFreeDataUser }
3257  };
3258 
3259 /**@} */
3260 
3261 /**@name Expression operand methods */
3262 /**@{ */
3263 
3264 /** gives the name of an operand as string */
3265 const char* SCIPexpropGetName(
3266  SCIP_EXPROP op /**< expression operand */
3267  )
3268 {
3269  assert(op < SCIP_EXPR_LAST);
3270 
3271  return exprOpTable[op].name;
3272 }
3273 
3274 /** gives the number of children of a simple operand */
3276  SCIP_EXPROP op /**< expression operand */
3277  )
3278 {
3279  assert(op < SCIP_EXPR_LAST);
3280 
3281  return exprOpTable[op].nargs;
3282 }
3283 
3284 /**@} */
3285 
3286 /**@name Expressions private methods */
3287 /**@{ */
3288 
3289 /** creates an expression
3290  *
3291  * Note, that the expression is allocated but for the children only the pointer is copied.
3292  */
3293 static
3295  BMS_BLKMEM* blkmem, /**< block memory data structure */
3296  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
3297  SCIP_EXPROP op, /**< operand of expression */
3298  int nchildren, /**< number of children */
3299  SCIP_EXPR** children, /**< children */
3300  SCIP_EXPROPDATA opdata /**< operand data */
3301  )
3302 {
3303  assert(blkmem != NULL);
3304  assert(expr != NULL);
3305  assert(children != NULL || nchildren == 0);
3306  assert(children == NULL || nchildren > 0);
3307 
3308  SCIP_ALLOC( BMSallocBlockMemory(blkmem, expr) );
3309 
3310  (*expr)->op = op;
3311  (*expr)->nchildren = nchildren;
3312  (*expr)->children = children;
3313  (*expr)->data = opdata;
3314 
3315  return SCIP_OKAY;
3316 }
3317 
3318 /** tries to convert a given (operator,operatordata) pair into a polynomial operator with corresponding data
3319  *
3320  * Does not do this for constants.
3321  * If conversion is not possible or operator is already polynomial, *op and *data are
3322  * left untouched.
3323  */
3324 static
3326  BMS_BLKMEM* blkmem, /**< block memory */
3327  SCIP_EXPROP* op, /**< pointer to expression operator */
3328  SCIP_EXPROPDATA* data, /**< pointer to expression data */
3329  int nchildren /**< number of children of operator */
3330  )
3331 {
3332  assert(blkmem != NULL);
3333  assert(op != NULL);
3334  assert(data != NULL);
3335 
3336  switch( *op )
3337  {
3338  case SCIP_EXPR_VARIDX:
3339  case SCIP_EXPR_PARAM:
3340  case SCIP_EXPR_CONST:
3341  break;
3342 
3343  case SCIP_EXPR_PLUS:
3344  {
3345  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3346  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3347  int childidx;
3348  SCIP_Real exponent;
3349 
3350  assert(nchildren == 2);
3351 
3352  /* create monomial for first child */
3353  childidx = 0;
3354  exponent = 1.0;
3355  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3356 
3357  /* create monomial for second child */
3358  childidx = 1;
3359  exponent = 1.0;
3360  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], 1.0, 1, &childidx, &exponent) );
3361 
3362  /* create polynomial for sum of children */
3363  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3364 
3365  *op = SCIP_EXPR_POLYNOMIAL;
3366  data->data = (void*)polynomialdata;
3367 
3368  break;
3369  }
3370 
3371  case SCIP_EXPR_MINUS:
3372  {
3373  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3374  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3375  int childidx;
3376  SCIP_Real exponent;
3377 
3378  assert(nchildren == 2);
3379 
3380  /* create monomial for first child */
3381  childidx = 0;
3382  exponent = 1.0;
3383  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3384 
3385  /* create monomial for second child */
3386  childidx = 1;
3387  exponent = 1.0;
3388  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], -1.0, 1, &childidx, &exponent) );
3389 
3390  /* create polynomial for difference of children */
3391  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3392 
3393  *op = SCIP_EXPR_POLYNOMIAL;
3394  data->data = (void*)polynomialdata;
3395 
3396  break;
3397  }
3398 
3399  case SCIP_EXPR_MUL:
3400  {
3401  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3402  SCIP_EXPRDATA_MONOMIAL* monomial;
3403  int childidx[2];
3404  SCIP_Real exponent[2];
3405 
3406  assert(nchildren == 2);
3407 
3408  /* create monomial for product of children */
3409  childidx[0] = 0;
3410  childidx[1] = 1;
3411  exponent[0] = 1.0;
3412  exponent[1] = 1.0;
3413  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3414 
3415  /* create polynomial */
3416  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3417 
3418  *op = SCIP_EXPR_POLYNOMIAL;
3419  data->data = (void*)polynomialdata;
3420 
3421  break;
3422  }
3423 
3424  case SCIP_EXPR_DIV:
3425  {
3426  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3427  SCIP_EXPRDATA_MONOMIAL* monomial;
3428  int childidx[2];
3429  SCIP_Real exponent[2];
3430 
3431  assert(nchildren == 2);
3432 
3433  /* create monomial for division of children */
3434  childidx[0] = 0;
3435  childidx[1] = 1;
3436  exponent[0] = 1.0;
3437  exponent[1] = -1.0;
3438  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3439 
3440  /* create polynomial */
3441  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3442 
3443  *op = SCIP_EXPR_POLYNOMIAL;
3444  data->data = (void*)polynomialdata;
3445 
3446  break;
3447  }
3448 
3449  case SCIP_EXPR_SQUARE:
3450  {
3451  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3452  SCIP_EXPRDATA_MONOMIAL* monomial;
3453  int childidx;
3454  SCIP_Real exponent;
3455 
3456  assert(nchildren == 1);
3457 
3458  /* create monomial for square of child */
3459  childidx = 0;
3460  exponent = 2.0;
3461  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3462 
3463  /* create polynomial */
3464  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3465 
3466  *op = SCIP_EXPR_POLYNOMIAL;
3467  data->data = (void*)polynomialdata;
3468 
3469  break;
3470  }
3471 
3472  case SCIP_EXPR_SQRT:
3473  {
3474  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3475  SCIP_EXPRDATA_MONOMIAL* monomial;
3476  int childidx;
3477  SCIP_Real exponent;
3478 
3479  assert(nchildren == 1);
3480 
3481  /* create monomial for square root of child */
3482  childidx = 0;
3483  exponent = 0.5;
3484  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3485 
3486  /* create polynomial */
3487  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3488 
3489  *op = SCIP_EXPR_POLYNOMIAL;
3490  data->data = (void*)polynomialdata;
3491 
3492  break;
3493  }
3494 
3495  case SCIP_EXPR_REALPOWER:
3496  {
3497  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3498  SCIP_EXPRDATA_MONOMIAL* monomial;
3499  int childidx;
3500 
3501  assert(nchildren == 1);
3502 
3503  /* convert to child0 to the power of exponent */
3504 
3505  /* create monomial for power of first child */
3506  childidx = 0;
3507  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &data->dbl) );
3508 
3509  /* create polynomial */
3510  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3511 
3512  *op = SCIP_EXPR_POLYNOMIAL;
3513  data->data = (void*)polynomialdata;
3514 
3515  break;
3516  }
3517 
3518  case SCIP_EXPR_SIGNPOWER:
3519  {
3520  SCIP_Real exponent;
3521 
3522  assert(nchildren == 1);
3523 
3524  /* check if exponent is an odd integer */
3525  exponent = data->dbl;
3526  if( EPSISINT(exponent, 0.0) && (int)exponent % 2 != 0 ) /*lint !e835*/
3527  {
3528  /* convert to child0 to the power of exponent, since sign is kept by taking power */
3529  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3530  SCIP_EXPRDATA_MONOMIAL* monomial;
3531  int childidx;
3532 
3533  /* create monomial for power of first child */
3534  childidx = 0;
3535  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3536 
3537  /* create polynomial */
3538  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3539 
3540  *op = SCIP_EXPR_POLYNOMIAL;
3541  data->data = (void*)polynomialdata;
3542  }
3543  /* if exponent is not an odd integer constant, then keep it as signpower expression */
3544  break;
3545  }
3546 
3547  case SCIP_EXPR_INTPOWER:
3548  {
3549  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3550  SCIP_EXPRDATA_MONOMIAL* monomial;
3551  int childidx;
3552  SCIP_Real exponent;
3553 
3554  assert(nchildren == 1);
3555 
3556  /* create monomial for power of child */
3557  childidx = 0;
3558  exponent = data->intval;
3559  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3560 
3561  /* create polynomial */
3562  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3563 
3564  *op = SCIP_EXPR_POLYNOMIAL;
3565  data->data = (void*)polynomialdata;
3566 
3567  break;
3568  }
3569 
3570  case SCIP_EXPR_EXP:
3571  case SCIP_EXPR_LOG:
3572  case SCIP_EXPR_SIN:
3573  case SCIP_EXPR_COS:
3574  case SCIP_EXPR_TAN:
3575  /* case SCIP_EXPR_ERF: */
3576  /* case SCIP_EXPR_ERFI: */
3577  case SCIP_EXPR_MIN:
3578  case SCIP_EXPR_MAX:
3579  case SCIP_EXPR_ABS:
3580  case SCIP_EXPR_SIGN:
3581  case SCIP_EXPR_USER:
3582  break;
3583 
3584  case SCIP_EXPR_SUM:
3585  {
3586  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3587  SCIP_EXPRDATA_MONOMIAL* monomial;
3588  int childidx;
3589  int i;
3590  SCIP_Real exponent;
3591 
3592  /* create empty polynomial */
3593  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, 0.0, FALSE) );
3594  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3595  assert(polynomialdata->monomialssize >= nchildren);
3596 
3597  /* add summands as monomials */
3598  childidx = 0;
3599  exponent = 1.0;
3600  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3601  for( i = 0; i < nchildren; ++i )
3602  {
3603  monomial->childidxs[0] = i;
3604  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3605  }
3606  SCIPexprFreeMonomial(blkmem, &monomial);
3607 
3608  *op = SCIP_EXPR_POLYNOMIAL;
3609  data->data = (void*)polynomialdata;
3610 
3611  break;
3612  }
3613 
3614  case SCIP_EXPR_PRODUCT:
3615  {
3616  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3617  SCIP_EXPRDATA_MONOMIAL* monomial;
3618  int childidx;
3619  int i;
3620  SCIP_Real exponent;
3621 
3622  /* create monomial */
3623  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 0, NULL, NULL) );
3624  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, nchildren) );
3625  exponent = 1.0;
3626  for( i = 0; i < nchildren; ++i )
3627  {
3628  childidx = i;
3629  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
3630  }
3631 
3632  /* create polynomial */
3633  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3634 
3635  *op = SCIP_EXPR_POLYNOMIAL;
3636  data->data = (void*)polynomialdata;
3637 
3638  break;
3639  }
3640 
3641  case SCIP_EXPR_LINEAR:
3642  {
3643  SCIP_Real* lineardata;
3644  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3645  SCIP_EXPRDATA_MONOMIAL* monomial;
3646  int childidx;
3647  int i;
3648  SCIP_Real exponent;
3649 
3650  /* get coefficients of linear term */
3651  lineardata = (SCIP_Real*)data->data;
3652  assert(lineardata != NULL);
3653 
3654  /* create polynomial consisting of constant from linear term */
3655  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, lineardata[nchildren], FALSE) );
3656  /* ensure space for linear coefficients */
3657  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3658  assert(polynomialdata->monomialssize >= nchildren);
3659 
3660  /* add summands as monomials */
3661  childidx = 0;
3662  exponent = 1.0;
3663  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3664  for( i = 0; i < nchildren; ++i )
3665  {
3666  monomial->coef = lineardata[i];
3667  monomial->childidxs[0] = i;
3668  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3669  }
3670  SCIPexprFreeMonomial(blkmem, &monomial);
3671 
3672  /* free linear expression data */
3673  exprFreeDataLinear(blkmem, nchildren, *data);
3674 
3675  *op = SCIP_EXPR_POLYNOMIAL;
3676  data->data = (void*)polynomialdata;
3677 
3678  break;
3679  }
3680 
3681  case SCIP_EXPR_QUADRATIC:
3682  {
3683  SCIP_EXPRDATA_QUADRATIC* quaddata;
3684  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3685  SCIP_EXPRDATA_MONOMIAL* squaremonomial;
3686  SCIP_EXPRDATA_MONOMIAL* bilinmonomial;
3687  SCIP_EXPRDATA_MONOMIAL* linmonomial;
3688  int childidx[2];
3689  SCIP_Real exponent[2];
3690  int i;
3691 
3692  /* get data of quadratic expression */
3693  quaddata = (SCIP_EXPRDATA_QUADRATIC*)data->data;
3694  assert(quaddata != NULL);
3695 
3696  /* create empty polynomial */
3697  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, quaddata->constant, FALSE) );
3698  /* ensure space for linear and quadratic terms */
3699  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, (quaddata->lincoefs != NULL ? nchildren : 0) + quaddata->nquadelems) );
3700  assert(polynomialdata->monomialssize >= quaddata->nquadelems);
3701 
3702  childidx[0] = 0;
3703  childidx[1] = 0;
3704 
3705  /* create monomial templates */
3706  exponent[0] = 2.0;
3707  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &squaremonomial, 1.0, 1, childidx, exponent) );
3708  exponent[0] = 1.0;
3709  exponent[1] = 1.0;
3710  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &bilinmonomial, 1.0, 2, childidx, exponent) );
3711  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &linmonomial, 1.0, 1, childidx, exponent) );
3712 
3713  /* add linear terms as monomials */
3714  if( quaddata->lincoefs != NULL )
3715  for( i = 0; i < nchildren; ++i )
3716  if( quaddata->lincoefs[i] != 0.0 )
3717  {
3718  linmonomial->childidxs[0] = i;
3719  linmonomial->coef = quaddata->lincoefs[i];
3720  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &linmonomial, TRUE) );
3721  }
3722 
3723  /* add quadratic terms as monomials */
3724  for( i = 0; i < quaddata->nquadelems; ++i )
3725  {
3726  if( quaddata->quadelems[i].idx1 == quaddata->quadelems[i].idx2 )
3727  {
3728  squaremonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3729  squaremonomial->coef = quaddata->quadelems[i].coef;
3730  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &squaremonomial, TRUE) );
3731  }
3732  else
3733  {
3734  bilinmonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3735  bilinmonomial->childidxs[1] = quaddata->quadelems[i].idx2;
3736  bilinmonomial->coef = quaddata->quadelems[i].coef;
3737  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &bilinmonomial, TRUE) );
3738  }
3739  }
3740  SCIPexprFreeMonomial(blkmem, &squaremonomial);
3741  SCIPexprFreeMonomial(blkmem, &bilinmonomial);
3742  SCIPexprFreeMonomial(blkmem, &linmonomial);
3743 
3744  /* free quadratic expression data */
3745  exprFreeDataQuadratic(blkmem, nchildren, *data);
3746 
3747  *op = SCIP_EXPR_POLYNOMIAL;
3748  data->data = (void*)polynomialdata;
3749 
3750  break;
3751  }
3752 
3753  case SCIP_EXPR_POLYNOMIAL:
3754  case SCIP_EXPR_LAST:
3755  break;
3756  } /*lint !e788*/
3757 
3758  return SCIP_OKAY;
3759 }
3760 
3761 /** converts polynomial expression back into simpler expression, if possible */
3762 static
3764  BMS_BLKMEM* blkmem, /**< block memory data structure */
3765  SCIP_EXPROP* op, /**< pointer to expression operator */
3766  SCIP_EXPROPDATA* data, /**< pointer to expression data holding polynomial data */
3767  int nchildren, /**< number of children of operator */
3768  void** children /**< children array */
3769  )
3770 {
3771  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3772  SCIP_EXPRDATA_MONOMIAL* monomial;
3773  int maxdegree;
3774  int nlinmonomials;
3775  int i;
3776  int j;
3777 
3778  assert(blkmem != NULL);
3779  assert(op != NULL);
3780  assert(*op == SCIP_EXPR_POLYNOMIAL);
3781  assert(data != NULL);
3782  assert(children != NULL || nchildren == 0);
3783 
3784  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)data->data;
3785  assert(polynomialdata != NULL);
3786 
3787  /* make sure monomials are sorted and merged */
3788  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
3789 
3790  /* if no monomials, then leave as it is */
3791  if( polynomialdata->nmonomials == 0 )
3792  return SCIP_OKAY;
3793 
3794  /* check maximal degree of polynomial only - not considering children expressions
3795  * check number of linear monomials */
3796  maxdegree = 0;
3797  nlinmonomials = 0;
3798  for( i = 0; i < polynomialdata->nmonomials; ++i )
3799  {
3800  int monomialdegree;
3801 
3802  monomial = polynomialdata->monomials[i];
3803  assert(monomial != NULL);
3804 
3805  monomialdegree = 0;
3806  for(j = 0; j < monomial->nfactors; ++j )
3807  {
3808  if( !EPSISINT(monomial->exponents[j], 0.0) || monomial->exponents[j] < 0.0 ) /*lint !e835*/
3809  {
3810  monomialdegree = SCIP_EXPR_DEGREEINFINITY;
3811  break;
3812  }
3813 
3814  monomialdegree += (int)EPSROUND(monomial->exponents[j], 0.0); /*lint !e835*/
3815  }
3816 
3817  if( monomialdegree == SCIP_EXPR_DEGREEINFINITY )
3818  {
3819  maxdegree = SCIP_EXPR_DEGREEINFINITY;
3820  break;
3821  }
3822 
3823  if( monomialdegree == 1 )
3824  ++nlinmonomials;
3825 
3826  if( monomialdegree > maxdegree )
3827  maxdegree = monomialdegree;
3828  }
3829  assert(maxdegree > 0 );
3830 
3831  if( maxdegree == 1 )
3832  {
3833  /* polynomial is a linear expression in children */
3834 
3835  /* polynomial simplification and monomial merging should ensure that monomial i corresponds to child i and that there are not unused children */
3836  assert(polynomialdata->nmonomials == nchildren);
3837  assert(polynomialdata->nmonomials == nlinmonomials);
3838 
3839  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3840  {
3841  /* polynomial is addition of two expressions, so turn into SCIP_EXPR_PLUS */
3842  assert(polynomialdata->monomials[0]->nfactors == 1);
3843  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3844  assert(polynomialdata->monomials[1]->nfactors == 1);
3845  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3846 
3847  polynomialdataFree(blkmem, &polynomialdata);
3848  data->data = NULL;
3849 
3850  /* change operator type to PLUS */
3851  *op = SCIP_EXPR_PLUS;
3852 
3853  return SCIP_OKAY;
3854  }
3855 
3856  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == -1.0 )
3857  {
3858  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3859  assert(polynomialdata->monomials[0]->nfactors == 1);
3860  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3861  assert(polynomialdata->monomials[1]->nfactors == 1);
3862  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3863 
3864  polynomialdataFree(blkmem, &polynomialdata);
3865  data->data = NULL;
3866 
3867  /* change operator type to MINUS */
3868  *op = SCIP_EXPR_MINUS;
3869 
3870  return SCIP_OKAY;
3871  }
3872 
3873  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == -1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3874  {
3875  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3876  void* tmp;
3877 
3878  assert(polynomialdata->monomials[0]->nfactors == 1);
3879  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3880  assert(polynomialdata->monomials[1]->nfactors == 1);
3881  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3882 
3883  polynomialdataFree(blkmem, &polynomialdata);
3884  data->data = NULL;
3885 
3886  /* swap children */
3887  tmp = children[1]; /*lint !e613*/
3888  children[1] = children[0]; /*lint !e613*/
3889  children[0] = tmp; /*lint !e613*/
3890 
3891  /* change operator type to MINUS */
3892  *op = SCIP_EXPR_MINUS;
3893 
3894  return SCIP_OKAY;
3895  }
3896 
3897  if( polynomialdata->constant == 0.0 )
3898  {
3899  /* check if all monomials have coefficient 1.0 */
3900  for( i = 0; i < polynomialdata->nmonomials; ++i )
3901  if( polynomialdata->monomials[i]->coef != 1.0 )
3902  break;
3903 
3904  if( i == polynomialdata->nmonomials )
3905  {
3906  /* polynomial is sum of children, so turn into SCIP_EXPR_SUM */
3907 
3908  polynomialdataFree(blkmem, &polynomialdata);
3909  data->data = NULL;
3910 
3911  /* change operator type to MINUS */
3912  *op = SCIP_EXPR_SUM;
3913 
3914  return SCIP_OKAY;
3915  }
3916  }
3917 
3918  /* turn polynomial into linear expression */
3919  {
3920  SCIP_Real* lindata;
3921 
3922  /* monomial merging should ensure that each child appears in at most one monomial,
3923  * that monomials are ordered according to the child index, and that constant monomials have been removed
3924  */
3925 
3926  /* setup data of linear expression */
3927  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &lindata, polynomialdata->nmonomials + 1) );
3928 
3929  for( i = 0; i < polynomialdata->nmonomials; ++i )
3930  {
3931  assert(polynomialdata->monomials[i]->childidxs[0] == i);
3932  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3933  lindata[i] = polynomialdata->monomials[i]->coef; /*lint !e644*/
3934  }
3935  lindata[i] = polynomialdata->constant;
3936 
3937  polynomialdataFree(blkmem, &polynomialdata);
3938  *op = SCIP_EXPR_LINEAR;
3939  data->data = (void*)lindata;
3940 
3941  return SCIP_OKAY;
3942  }
3943  }
3944 
3945  if( maxdegree == 2 && (polynomialdata->nmonomials > 1 || polynomialdata->constant != 0.0 || polynomialdata->monomials[0]->coef != 1.0) )
3946  {
3947  /* 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 */
3948  SCIP_EXPRDATA_QUADRATIC* quaddata;
3949  int quadelemidx;
3950 
3951  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &quaddata) );
3952  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->quadelems, polynomialdata->nmonomials - nlinmonomials) );
3953  quaddata->nquadelems = polynomialdata->nmonomials - nlinmonomials;
3954  quaddata->constant = polynomialdata->constant;
3955  quaddata->sorted = FALSE; /* quadratic data is sorted different than polynomials */
3956 
3957  if( nlinmonomials > 0 )
3958  {
3959  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->lincoefs, nchildren) );
3960  BMSclearMemoryArray(quaddata->lincoefs, nchildren);
3961  }
3962  else
3963  quaddata->lincoefs = NULL;
3964 
3965  quadelemidx = 0;
3966  for( i = 0; i < polynomialdata->nmonomials; ++i )
3967  {
3968  assert(polynomialdata->monomials[i]->nfactors == 1 || polynomialdata->monomials[i]->nfactors == 2);
3969  if( polynomialdata->monomials[i]->nfactors == 1 )
3970  {
3971  if( polynomialdata->monomials[i]->exponents[0] == 1.0 )
3972  {
3973  /* monomial is a linear term */
3974  assert(quaddata->lincoefs != NULL);
3975  quaddata->lincoefs[polynomialdata->monomials[i]->childidxs[0]] += polynomialdata->monomials[i]->coef;
3976  }
3977  else
3978  {
3979  /* monomial should be a square term */
3980  assert(polynomialdata->monomials[i]->exponents[0] == 2.0);
3981  assert(quadelemidx < quaddata->nquadelems);
3982  quaddata->quadelems[quadelemidx].idx1 = polynomialdata->monomials[i]->childidxs[0];
3983  quaddata->quadelems[quadelemidx].idx2 = polynomialdata->monomials[i]->childidxs[0];
3984  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3985  ++quadelemidx;
3986  }
3987  }
3988  else
3989  {
3990  /* monomial should be a bilinear term */
3991  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3992  assert(polynomialdata->monomials[i]->exponents[1] == 1.0);
3993  assert(quadelemidx < quaddata->nquadelems);
3994  quaddata->quadelems[quadelemidx].idx1 = MIN(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3995  quaddata->quadelems[quadelemidx].idx2 = MAX(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3996  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3997  ++quadelemidx;
3998  }
3999  }
4000  assert(quadelemidx == quaddata->nquadelems);
4001 
4002  polynomialdataFree(blkmem, &polynomialdata);
4003 
4004  *op = SCIP_EXPR_QUADRATIC;
4005  data->data = (void*)quaddata;
4006 
4007  return SCIP_OKAY;
4008  }
4009 
4010  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 1 && polynomialdata->monomials[0]->coef == 1.0 )
4011  {
4012  /* polynomial is product of children */
4013  monomial = polynomialdata->monomials[0];
4014  assert(monomial->nfactors == nchildren);
4015 
4016  if( monomial->nfactors == 1 )
4017  {
4018  /* polynomial is x^k for some k */
4019  assert(monomial->exponents[0] != 1.0); /* should have been handled before */
4020  assert(monomial->childidxs[0] == 0);
4021 
4022  if( monomial->exponents[0] == 2.0 )
4023  {
4024  /* polynomial is x^2, so turn into SCIP_EXPR_SQUARE */
4025 
4026  polynomialdataFree(blkmem, &polynomialdata);
4027  data->data = NULL;
4028 
4029  *op = SCIP_EXPR_SQUARE;
4030 
4031  return SCIP_OKAY;
4032  }
4033 
4034  if( EPSISINT(monomial->exponents[0], 0.0) ) /*lint !e835*/
4035  {
4036  /* k is an integer, so turn into SCIP_EXPR_INTPOWER */
4037  int exponent;
4038 
4039  exponent = (int)EPSROUND(monomial->exponents[0], 0.0); /*lint !e835*/
4040 
4041  polynomialdataFree(blkmem, &polynomialdata);
4042 
4043  *op = SCIP_EXPR_INTPOWER;
4044  data->intval = exponent;
4045 
4046  return SCIP_OKAY;
4047  }
4048 
4049  if( monomial->exponents[0] == 0.5 )
4050  {
4051  /* polynomial is sqrt(x), so turn into SCIP_EXPR_SQRT */
4052 
4053  polynomialdataFree(blkmem, &polynomialdata);
4054  data->data = NULL;
4055 
4056  *op = SCIP_EXPR_SQRT;
4057 
4058  return SCIP_OKAY;
4059  }
4060 
4061  {
4062  /* polynomial is x^a with a some real number, so turn into SCIP_EXPR_REALPOWER */
4063  SCIP_Real exponent;
4064 
4065  exponent = monomial->exponents[0];
4066 
4067  polynomialdataFree(blkmem, &polynomialdata);
4068 
4069  *op = SCIP_EXPR_REALPOWER;
4070  data->dbl = exponent;
4071 
4072  return SCIP_OKAY;
4073  }
4074  }
4075 
4076  if( maxdegree == 2 && monomial->nfactors == 2 )
4077  {
4078  /* polynomial is product of two children, so turn into SCIP_EXPR_MUL */
4079  assert(monomial->exponents[0] == 1.0);
4080  assert(monomial->exponents[1] == 1.0);
4081 
4082  polynomialdataFree(blkmem, &polynomialdata);
4083  data->data = NULL;
4084 
4085  *op = SCIP_EXPR_MUL;
4086 
4087  return SCIP_OKAY;
4088  }
4089 
4090  if( maxdegree == monomial->nfactors )
4091  {
4092  /* polynomial is a product of n children, so turn into SCIP_EXPR_PRODUCT */
4093 
4094  polynomialdataFree(blkmem, &polynomialdata);
4095  data->data = NULL;
4096 
4097  *op = SCIP_EXPR_PRODUCT;
4098 
4099  return SCIP_OKAY;
4100  }
4101 
4102  if( monomial->nfactors == 2 && monomial->exponents[0] == 1.0 && monomial->exponents[1] == -1.0 )
4103  {
4104  /* polynomial is x/y, so turn into SCIP_EXPR_DIV */
4105  assert(monomial->childidxs[0] == 0);
4106  assert(monomial->childidxs[1] == 1);
4107 
4108  polynomialdataFree(blkmem, &polynomialdata);
4109  data->data = NULL;
4110 
4111  *op = SCIP_EXPR_DIV;
4112 
4113  return SCIP_OKAY;
4114  }
4115 
4116  if( monomial->nfactors == 2 && monomial->exponents[0] == -1.0 && monomial->exponents[1] == 1.0 )
4117  {
4118  /* polynomial is y/x, so turn into SCIP_EXPR_DIV */
4119  void* tmp;
4120 
4121  assert(monomial->childidxs[0] == 0);
4122  assert(monomial->childidxs[1] == 1);
4123 
4124  polynomialdataFree(blkmem, &polynomialdata);
4125  data->data = NULL;
4126 
4127  /* swap children */
4128  tmp = children[1]; /*lint !e613*/
4129  children[1] = children[0]; /*lint !e613*/
4130  children[0] = tmp; /*lint !e613*/
4131 
4132  *op = SCIP_EXPR_DIV;
4133 
4134  return SCIP_OKAY;
4135  }
4136  }
4137 
4138  return SCIP_OKAY;
4139 }
4140 
4141 /** adds copies of expressions to the array of children of a sum, product, linear, quadratic, or polynomial expression
4142  *
4143  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
4144  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
4145  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
4146  */
4147 static
4149  BMS_BLKMEM* blkmem, /**< block memory */
4150  SCIP_EXPR* expr, /**< quadratic or polynomial expression */
4151  int nexprs, /**< number of expressions to add */
4152  SCIP_EXPR** exprs, /**< expressions to add */
4153  SCIP_Bool comparechildren, /**< whether to compare expressions with already existing children (no effect for sum and product) */
4154  SCIP_Real eps, /**< which epsilon to use when comparing expressions */
4155  int* childmap /**< array where to store mapping of indices from exprs to children array in expr, or NULL if not of interest */
4156  )
4157 {
4158  int i;
4159 
4160  assert(blkmem != NULL);
4161  assert(expr != NULL);
4162  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);
4163  assert(exprs != NULL || nexprs == 0);
4164 
4165  if( nexprs == 0 )
4166  return SCIP_OKAY;
4167 
4168  switch( expr->op )
4169  {
4170  case SCIP_EXPR_SUM:
4171  case SCIP_EXPR_PRODUCT:
4172  {
4173  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4174  for( i = 0; i < nexprs; ++i )
4175  {
4176  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren + i], exprs[i]) ); /*lint !e613*/
4177  if( childmap != NULL )
4178  childmap[i] = expr->nchildren + i;
4179  }
4180  expr->nchildren += nexprs;
4181 
4182  break;
4183  }
4184 
4185  case SCIP_EXPR_LINEAR:
4186  case SCIP_EXPR_QUADRATIC:
4187  case SCIP_EXPR_POLYNOMIAL:
4188  {
4189  int j;
4190  int orignchildren;
4191  SCIP_Bool existsalready;
4192 
4193  orignchildren = expr->nchildren;
4194  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4195 
4196  for( i = 0; i < nexprs; ++i )
4197  {
4198  existsalready = FALSE;
4199  if( comparechildren )
4200  for( j = 0; j < orignchildren; ++j )
4201  /* during simplification of polynomials, their may be NULL's in children array */
4202  if( expr->children[j] != NULL && SCIPexprAreEqual(expr->children[j], exprs[i], eps) ) /*lint !e613*/
4203  {
4204  existsalready = TRUE;
4205  break;
4206  }
4207 
4208  if( !existsalready )
4209  {
4210  /* add copy of exprs[j] to children array */
4211  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren], exprs[i]) ); /*lint !e613*/
4212  if( childmap != NULL )
4213  childmap[i] = expr->nchildren;
4214  ++expr->nchildren;
4215  }
4216  else
4217  {
4218  if( childmap != NULL )
4219  childmap[i] = j; /*lint !e644*/
4220  if( expr->op == SCIP_EXPR_LINEAR )
4221  {
4222  /* if linear expression, increase coefficient by 1.0 */
4223  ((SCIP_Real*)expr->data.data)[j] += 1.0;
4224  }
4225  }
4226  }
4227 
4228  /* shrink children array to actually used size */
4229  assert(comparechildren || expr->nchildren == orignchildren + nexprs);
4230  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, orignchildren + nexprs, expr->nchildren) );
4231 
4232  if( expr->op == SCIP_EXPR_LINEAR && expr->nchildren > orignchildren )
4233  {
4234  /* if linear expression, then add 1.0 coefficients for new expressions */
4235  SCIP_Real* data;
4236 
4237  data = (SCIP_Real*)expr->data.data;
4238  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, expr->nchildren + 1) );
4239  data[expr->nchildren] = data[orignchildren]; /* move constant from old end to new end */
4240  for( i = orignchildren; i < expr->nchildren; ++i )
4241  data[i] = 1.0;
4242  expr->data.data = (void*)data;
4243  }
4244  else if( expr->op == SCIP_EXPR_QUADRATIC && expr->nchildren > orignchildren )
4245  {
4246  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
4248 
4249  data = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
4250  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, expr->nchildren) );
4251  BMSclearMemoryArray(&data->lincoefs[orignchildren], expr->nchildren - orignchildren); /*lint !e866*/
4252  }
4253 
4254  break;
4255  }
4256 
4257  default:
4258  SCIPerrorMessage("exprsimplifyAddChildren cannot be called for operand %d\n", expr->op);
4259  return SCIP_INVALIDDATA;
4260  } /*lint !e788*/
4261 
4262  return SCIP_OKAY;
4263 }
4264 
4265 /** converts expressions into polynomials, where possible and obvious */
4266 static
4268  BMS_BLKMEM* blkmem, /**< block memory data structure */
4269  SCIP_EXPR* expr /**< expression to convert */
4270  )
4271 {
4272  int i;
4273 
4274  assert(expr != NULL);
4275 
4276  for( i = 0; i < expr->nchildren; ++i )
4277  {
4279  }
4280 
4281  SCIP_CALL( exprConvertToPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren) );
4282 
4283  return SCIP_OKAY;
4284 }
4285 
4286 /** removes duplicate children in a polynomial expression
4287  *
4288  * Leaves NULL's in children array.
4289  */
4290 static
4292  BMS_BLKMEM* blkmem, /**< block memory data structure */
4293  SCIP_EXPR* expr, /**< expression */
4294  SCIP_Real eps /**< threshold for zero */
4295  )
4296 {
4297  SCIP_Bool foundduplicates;
4298  int* childmap;
4299  int i;
4300  int j;
4301 
4302  assert(blkmem != NULL);
4303  assert(expr != NULL);
4304  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4305 
4306  if( expr->nchildren == 0 )
4307  return SCIP_OKAY;
4308 
4309  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4310 
4311  foundduplicates = FALSE;
4312  for( i = 0; i < expr->nchildren; ++i )
4313  {
4314  if( expr->children[i] == NULL )
4315  continue;
4316  childmap[i] = i; /*lint !e644*/
4317 
4318  for( j = i+1; j < expr->nchildren; ++j )
4319  {
4320  if( expr->children[j] == NULL )
4321  continue;
4322 
4323  if( SCIPexprAreEqual(expr->children[i], expr->children[j], eps) )
4324  {
4325  /* forget about expr j and remember that is to be replaced by i */
4326  SCIPexprFreeDeep(blkmem, &expr->children[j]);
4327  childmap[j] = i;
4328  foundduplicates = TRUE;
4329  }
4330  }
4331  }
4332 
4333  /* apply childmap to monomials */
4334  if( foundduplicates )
4336 
4337  /* free childmap */
4338  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4339 
4340  return SCIP_OKAY;
4341 }
4342 
4343 /** eliminates NULL's in children array and shrinks it to actual size */
4344 static
4346  BMS_BLKMEM* blkmem, /**< block memory data structure */
4347  SCIP_EXPR* expr /**< expression */
4348  )
4349 {
4350  int* childmap;
4351  int lastnonnull;
4352  int i;
4353 
4354  assert(blkmem != NULL);
4355  assert(expr != NULL);
4356  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4357 
4358  if( expr->nchildren == 0 )
4359  return SCIP_OKAY;
4360 
4361  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4362 
4363  /* close gaps in children array */
4364  lastnonnull = expr->nchildren-1;
4365  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4366  --lastnonnull;
4367  for( i = 0; i <= lastnonnull; ++i )
4368  {
4369  if( expr->children[i] != NULL )
4370  {
4371  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
4372  continue;
4373  }
4374  assert(expr->children[lastnonnull] != NULL);
4375 
4376  /* move child at lastnonnull to position i */
4377  expr->children[i] = expr->children[lastnonnull];
4378  expr->children[lastnonnull] = NULL;
4379  childmap[lastnonnull] = i;
4380 
4381  /* update lastnonnull */
4382  --lastnonnull;
4383  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4384  --lastnonnull;
4385  }
4386  assert(i > lastnonnull);
4387 
4388  /* apply childmap to monomials */
4389  if( lastnonnull < expr->nchildren-1 )
4391 
4392  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4393 
4394  /* shrink children array */
4395  if( lastnonnull >= 0 )
4396  {
4397  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, lastnonnull+1) );
4398  expr->nchildren = lastnonnull+1;
4399  }
4400  else
4401  {
4402  BMSfreeBlockMemoryArray(blkmem, &expr->children, expr->nchildren);
4403  expr->nchildren = 0;
4404  }
4405 
4406  return SCIP_OKAY;
4407 }
4408 
4409 /** checks which children are still in use and frees those which are not */
4410 static
4412  BMS_BLKMEM* blkmem, /**< block memory data structure */
4413  SCIP_EXPR* expr /**< polynomial expression */
4414  )
4415 {
4416  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4417  SCIP_EXPRDATA_MONOMIAL* monomial;
4418  SCIP_Bool* childinuse;
4419  int i;
4420  int j;
4421 
4422  assert(blkmem != NULL);
4423  assert(expr != NULL);
4424 
4425  if( expr->nchildren == 0 )
4426  return SCIP_OKAY;
4427 
4428  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4429  assert(polynomialdata != NULL);
4430 
4431  /* check which children are still in use */
4432  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, expr->nchildren) );
4433  BMSclearMemoryArray(childinuse, expr->nchildren); /*lint !e644*/
4434  for( i = 0; i < polynomialdata->nmonomials; ++i )
4435  {
4436  monomial = polynomialdata->monomials[i];
4437  assert(monomial != NULL);
4438 
4439  for( j = 0; j < monomial->nfactors; ++j )
4440  {
4441  assert(monomial->childidxs[j] >= 0);
4442  assert(monomial->childidxs[j] < expr->nchildren);
4443  childinuse[monomial->childidxs[j]] = TRUE;
4444  }
4445  }
4446 
4447  /* free children that are not used in any monomial */
4448  for( i = 0; i < expr->nchildren; ++i )
4449  if( expr->children[i] != NULL && !childinuse[i] )
4450  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4451 
4452  BMSfreeBlockMemoryArray(blkmem, &childinuse, expr->nchildren);
4453 
4454  return SCIP_OKAY;
4455 }
4456 
4457 /** flattens polynomials in polynomials, check for constants in non-polynomials expressions
4458  *
4459  * exprsimplifyConvertToPolynomials should have been called before to eliminate simple polynomial operands.
4460  */
4461 static
4463  BMS_BLKMEM* blkmem, /**< block memory data structure */
4464  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4465  SCIP_EXPR* expr, /**< expression */
4466  SCIP_Real eps, /**< threshold, under which values are treat as 0 */
4467  int maxexpansionexponent/**< maximal exponent for which we still expand non-monomial polynomials */
4468  )
4469 {
4470  int i;
4471 
4472  assert(expr != NULL);
4473 
4474  for( i = 0; i < expr->nchildren; ++i )
4475  {
4476  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr->children[i], eps, maxexpansionexponent) );
4477  }
4478 
4479  switch( SCIPexprGetOperator(expr) )
4480  {
4481  case SCIP_EXPR_VARIDX:
4482  case SCIP_EXPR_CONST:
4483  case SCIP_EXPR_PARAM:
4484  case SCIP_EXPR_PLUS:
4485  case SCIP_EXPR_MINUS:
4486  case SCIP_EXPR_MUL:
4487  case SCIP_EXPR_DIV:
4488  case SCIP_EXPR_SQUARE:
4489  case SCIP_EXPR_SQRT:
4490  case SCIP_EXPR_INTPOWER:
4491  case SCIP_EXPR_REALPOWER:
4492  case SCIP_EXPR_SIGNPOWER:
4493  break;
4494 
4495  case SCIP_EXPR_EXP:
4496  case SCIP_EXPR_LOG:
4497  case SCIP_EXPR_SIN:
4498  case SCIP_EXPR_COS:
4499  case SCIP_EXPR_TAN:
4500  /* case SCIP_EXPR_ERF: */
4501  /* case SCIP_EXPR_ERFI: */
4502  case SCIP_EXPR_ABS:
4503  case SCIP_EXPR_SIGN:
4504  {
4505  /* check if argument is a constant */
4506  if( (expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) ||
4507  expr->children[0]->op == SCIP_EXPR_CONST )
4508  {
4509  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4510  SCIP_Real exprval;
4511 
4512  /* since child0 has no children and it's polynomial was flattened, it should have no monomials */
4513  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4514 
4515  /* evaluate expression in constant polynomial */
4516  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4517 
4518  /* create polynomial */
4519  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4520 
4521  expr->op = SCIP_EXPR_POLYNOMIAL;
4522  expr->data.data = (void*)polynomialdata;
4523 
4524  /* forget child */
4525  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4526  BMSfreeBlockMemoryArray(blkmem, &expr->children, 1);
4527  expr->nchildren = 0;
4528  }
4529 
4530  break;
4531  }
4532 
4533  case SCIP_EXPR_MIN:
4534  case SCIP_EXPR_MAX:
4535  {
4536  /* check if both arguments are constants */
4537  if( ((expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) || expr->children[0]->op == SCIP_EXPR_CONST) &&
4538  ((expr->children[1]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[1]) == 0) || expr->children[1]->op == SCIP_EXPR_CONST) )
4539  {
4540  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4541  SCIP_Real exprval;
4542 
4543  /* since children have no children and it's polynomial was flattened, it should have no monomials */
4544  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4545  assert(expr->children[1]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[1]) == 0);
4546 
4547  /* evaluate expression in constants */
4548  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4549 
4550  /* create polynomial */
4551  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4552 
4553  expr->op = SCIP_EXPR_POLYNOMIAL;
4554  expr->data.data = (void*)polynomialdata;
4555 
4556  /* forget children */
4557  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4558  SCIPexprFreeDeep(blkmem, &expr->children[1]);
4559  BMSfreeBlockMemoryArray(blkmem, &expr->children, 2);
4560  expr->nchildren = 0;
4561  }
4562 
4563  break;
4564  }
4565 
4566  case SCIP_EXPR_SUM:
4567  case SCIP_EXPR_PRODUCT:
4568  case SCIP_EXPR_LINEAR:
4569  case SCIP_EXPR_QUADRATIC:
4570  case SCIP_EXPR_USER:
4571  break;
4572 
4573  case SCIP_EXPR_POLYNOMIAL:
4574  {
4575  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4576  SCIP_EXPRDATA_MONOMIAL* monomial;
4577  SCIP_Bool removechild;
4578  int* childmap;
4579  int childmapsize;
4580  int j;
4581 
4582  /* simplify current polynomial */
4584  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4585 
4586  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4587  assert(polynomialdata != NULL);
4588 
4589  SCIPdebugMessage("expand factors in expression ");
4590  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4591  SCIPdebugPrintf("\n");
4592 
4593  childmap = NULL;
4594  childmapsize = 0;
4595 
4596  /* resolve children that are constants
4597  * we do this first, because it reduces the degree and number of factors in the monomials,
4598  * 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
4599  */
4600  for( i = 0; i < expr->nchildren; ++i )
4601  {
4602  if( expr->children[i] == NULL )
4603  continue;
4604 
4605  if( SCIPexprGetOperator(expr->children[i]) != SCIP_EXPR_CONST )
4606  continue;
4607 
4608  removechild = TRUE; /* we intend to delete children[i] */
4609 
4610  if( childmapsize < expr->children[i]->nchildren )
4611  {
4612  int newsize;
4613 
4614  newsize = calcGrowSize(expr->children[i]->nchildren);
4615  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4616  childmapsize = newsize;
4617  }
4618 
4619  /* put constant of child i into every monomial where child i is used */
4620  for( j = 0; j < polynomialdata->nmonomials; ++j )
4621  {
4622  int factorpos;
4623  SCIP_Bool success;
4624 
4625  monomial = polynomialdata->monomials[j];
4626  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4627  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4628 
4629  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4630  {
4631  assert(factorpos >= 0);
4632  assert(factorpos < monomial->nfactors);
4633  /* assert that factors have been merged */
4634  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4635  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4636 
4637  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4638  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4639  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4640 
4641  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && SCIPexprGetOpReal(expr->children[i]) < 0.0 ) /*lint !e835*/
4642  {
4643  /* if constant is negative and our exponent is not integer, then cannot do expansion */
4644  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n",
4645  SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4646  success = FALSE;
4647  }
4648  else
4649  {
4650  monomial->coef *= pow(SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4651 
4652  /* move last factor to position factorpos */
4653  if( factorpos < monomial->nfactors-1 )
4654  {
4655  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
4656  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
4657  }
4658  --monomial->nfactors;
4659  monomial->sorted = FALSE;
4660  polynomialdata->sorted = FALSE;
4661 
4662  success = TRUE;
4663  }
4664 
4665  if( !success )
4666  removechild = FALSE;
4667  }
4668  }
4669 
4670  /* forget about child i, if it is not used anymore */
4671  if( removechild )
4672  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4673 
4674  /* simplify current polynomial again */
4675  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4676  }
4677 
4678  /* try to resolve children that are polynomials itself */
4679  for( i = 0; i < expr->nchildren; ++i )
4680  {
4681  if( expr->children[i] == NULL )
4682  continue;
4683 
4685  continue;
4686 
4687  removechild = TRUE; /* we intend to delete children[i] */
4688 
4689  if( childmapsize < expr->children[i]->nchildren )
4690  {
4691  int newsize;
4692 
4693  newsize = calcGrowSize(expr->children[i]->nchildren);
4694  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4695  childmapsize = newsize;
4696  }
4697 
4698  /* add children of child i */
4699  SCIP_CALL( exprsimplifyAddChildren(blkmem, expr, expr->children[i]->nchildren, expr->children[i]->children, TRUE, eps, childmap) );
4700 
4701  /* put polynomial of child i into every monomial where child i is used */
4702  j = 0;
4703  while( j < polynomialdata->nmonomials )
4704  {
4705  int factorpos;
4706  SCIP_Bool success;
4707 
4708  monomial = polynomialdata->monomials[j];
4709  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4710  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4711 
4712  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4713  {
4714  assert(factorpos >= 0);
4715  assert(factorpos < monomial->nfactors);
4716  /* assert that factors have been merged */
4717  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4718  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4719 
4720  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4721  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4722  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4723 
4724  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
4725  (SCIP_EXPRDATA_POLYNOMIAL*)expr->children[i]->data.data, childmap, maxexpansionexponent, &success) );
4726 
4727  if( !success )
4728  {
4729  removechild = FALSE;
4730  ++j;
4731  }
4732  }
4733  else
4734  ++j;
4735 
4736  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
4737  * we thus repeat with index j, if a factor was successfully expanded
4738  */
4739  }
4740 
4741  /* forget about child i, if it is not used anymore */
4742  if( removechild )
4743  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4744 
4745  /* simplify current polynomial again */
4746  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4747  }
4748 
4749  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
4750 
4751  /* free children that are not in use anymore */
4753 
4754  /* remove NULLs from children array */
4756 
4757  /* if no children left, then it's a constant polynomial -> change into EXPR_CONST */
4758  if( expr->nchildren == 0 )
4759  {
4760  SCIP_Real val;
4761 
4762  /* if no children, then it should also have no monomials */
4763  assert(polynomialdata->nmonomials == 0);
4764 
4765  val = polynomialdata->constant;
4766  polynomialdataFree(blkmem, &polynomialdata);
4767 
4768  expr->op = SCIP_EXPR_CONST;
4769  expr->data.dbl = val;
4770  }
4771 
4772  SCIPdebugMessage("-> ");
4773  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4774  SCIPdebugPrintf("\n");
4775 
4776  break;
4777  }
4778 
4779  case SCIP_EXPR_LAST:
4780  break;
4781  } /*lint !e788*/
4782 
4783  return SCIP_OKAY;
4784 }
4785 
4786 /** separates linear monomials from an expression, if it is a polynomial expression
4787  *
4788  * Separates only those linear terms whose variable is not used otherwise in the expression.
4789  */
4790 static
4792  BMS_BLKMEM* blkmem, /**< block memory data structure */
4793  SCIP_EXPR* expr, /**< expression */
4794  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
4795  int nvars, /**< number of variables in expression */
4796  int* nlinvars, /**< buffer to store number of linear variables in linear part */
4797  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part */
4798  SCIP_Real* lincoefs /**< array to store coefficients of linear part */
4799  )
4800 {
4801  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4802  SCIP_EXPRDATA_MONOMIAL* monomial;
4803  int* varsusage;
4804  int* childusage;
4805  int childidx;
4806  int i;
4807  int j;
4808 
4809  assert(blkmem != NULL);
4810  assert(expr != NULL);
4811  assert(nlinvars != NULL);
4812  assert(linidxs != NULL);
4813  assert(lincoefs != NULL);
4814 
4815  *nlinvars = 0;
4816 
4818  return SCIP_OKAY;
4819 
4820  if( SCIPexprGetNChildren(expr) == 0 )
4821  return SCIP_OKAY;
4822 
4823  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4824  assert(polynomialdata != NULL);
4825 
4826  /* get variable usage */
4827  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &varsusage, nvars) );
4828  BMSclearMemoryArray(varsusage, nvars); /*lint !e644*/
4829  SCIPexprGetVarsUsage(expr, varsusage);
4830 
4831  /* get child usage: how often each child is used in the polynomial */
4832  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childusage, expr->nchildren) );
4833  BMSclearMemoryArray(childusage, expr->nchildren); /*lint !e644*/
4834  for( i = 0; i < polynomialdata->nmonomials; ++i )
4835  {
4836  monomial = polynomialdata->monomials[i];
4837  assert(monomial != NULL);
4838  for( j = 0; j < monomial->nfactors; ++j )
4839  {
4840  assert(monomial->childidxs[j] >= 0);
4841  assert(monomial->childidxs[j] < expr->nchildren);
4842  ++childusage[monomial->childidxs[j]];
4843  }
4844  }
4845 
4846  /* move linear monomials out of polynomial */
4847  for( i = 0; i < polynomialdata->nmonomials; ++i )
4848  {
4849  monomial = polynomialdata->monomials[i];
4850  assert(monomial != NULL);
4851  if( monomial->nfactors != 1 )
4852  continue;
4853  if( monomial->exponents[0] != 1.0 )
4854  continue;
4855  childidx = monomial->childidxs[0];
4856  if( SCIPexprGetOperator(expr->children[childidx]) != SCIP_EXPR_VARIDX )
4857  continue;
4858 
4859  /* we are at a linear monomial in a variable */
4860  assert(SCIPexprGetOpIndex(expr->children[childidx]) < nvars);
4861  if( childusage[childidx] == 1 && varsusage[SCIPexprGetOpIndex(expr->children[childidx])] == 1 )
4862  {
4863  /* if the child expression is not used in another monomial (which would due to merging be not linear)
4864  * and if the variable is not used somewhere else in the tree,
4865  * then move this monomial into linear part and free child
4866  */
4867  linidxs[*nlinvars] = SCIPexprGetOpIndex(expr->children[childidx]);
4868  lincoefs[*nlinvars] = monomial->coef;
4869  ++*nlinvars;
4870 
4871  SCIPexprFreeDeep(blkmem, &expr->children[childidx]);
4872  monomial->coef = 0.0;
4873  monomial->nfactors = 0;
4874  }
4875  }
4876 
4877  BMSfreeBlockMemoryArray(blkmem, &varsusage, nvars);
4878  BMSfreeBlockMemoryArray(blkmem, &childusage, expr->nchildren);
4879 
4880  if( *nlinvars > 0 )
4881  {
4882  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
4883  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, FALSE);
4885  }
4886 
4887  return SCIP_OKAY;
4888 }
4889 
4890 /** converts polynomial expressions back into simpler expressions, where possible */
4891 static
4893  BMS_BLKMEM* blkmem, /**< block memory data structure */
4894  SCIP_EXPR* expr /**< expression to convert back */
4895  )
4896 {
4897  int i;
4898 
4899  assert(blkmem != NULL);
4900  assert(expr != NULL);
4901 
4902  for( i = 0; i < expr->nchildren; ++i )
4903  {
4905  }
4906 
4907  if( expr->op != SCIP_EXPR_POLYNOMIAL )
4908  return SCIP_OKAY;
4909 
4910  SCIP_CALL( exprUnconvertPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren, (void**)expr->children) );
4911 
4912  return SCIP_OKAY;
4913 }
4914 
4915 static
4916 SCIP_DECL_HASHGETKEY( exprparseVarTableGetKey )
4917 { /*lint --e{715}*/
4918  return (void*)((char*)elem + sizeof(int));
4919 }
4920 
4921 /** parses a variable name from a string and creates corresponding expression
4922  *
4923  * Creates a new variable index if variable not seen before, updates varnames and vartable structures.
4924  */
4925 static
4927  BMS_BLKMEM* blkmem, /**< block memory data structure */
4928  const char** str, /**< pointer to the string to be parsed */
4929  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
4930  int* nvars, /**< running number of encountered variables so far */
4931  int** varnames, /**< pointer to buffer to store new variable names */
4932  int* varnameslength, /**< pointer to length of the varnames buffer array */
4933  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
4934  SCIP_Real coefficient, /**< coefficient to be used when creating the expression */
4935  const char* varnameendptr /**< if a <varname> should be parsed, set this to NULL. Then, str points to the '<'
4936  else, str should point to the first letter of the varname, and varnameendptr should
4937  point one char behind the last char of the variable name */
4938  )
4939 {
4940  int namelength;
4941  int varidx;
4942  char varname[SCIP_MAXSTRLEN];
4943  void* element;
4944 
4945  assert(blkmem != NULL);
4946  assert(str != NULL);
4947  assert(expr != NULL);
4948  assert(nvars != NULL);
4949  assert(varnames != NULL);
4950  assert(vartable != NULL);
4951 
4952  if( varnameendptr == NULL )
4953  {
4954  ++*str;
4955  varnameendptr = *str;
4956  while( varnameendptr[0] != '>' )
4957  ++varnameendptr;
4958  }
4959 
4960  namelength = varnameendptr - *str; /*lint !e712*/
4961  if( namelength >= SCIP_MAXSTRLEN )
4962  {
4963  SCIPerrorMessage("Variable name %.*s is too long for buffer in exprparseReadVariable.\n", namelength, str);
4964  return SCIP_READERROR;
4965  }
4966 
4967  memcpy(varname, *str, namelength * sizeof(char));
4968  varname[namelength] = '\0';
4969 
4970  element = SCIPhashtableRetrieve(vartable, varname);
4971  if( element != NULL )
4972  {
4973  /* variable is old friend */
4974  assert(strcmp((char*)element + sizeof(int), varname) == 0);
4975 
4976  varidx = *(int*)element;
4977  }
4978  else
4979  {
4980  /* variable is new */
4981  varidx = *nvars;
4982 
4983  (*varnameslength) -= (int)(1 + (strlen(varname) + 1) / sizeof(int) + 1);
4984  if( *varnameslength < 0 )
4985  {
4986  SCIPerrorMessage("Buffer in exprparseReadVariable is too short for varaible name %.*s.\n", namelength, str);
4987  return SCIP_READERROR;
4988  }
4989 
4990  /* store index of variable and variable name in varnames buffer */
4991  **varnames = varidx;
4992  (void) SCIPstrncpy((char*)(*varnames + 1), varname, (int)strlen(varname)+1);
4993 
4994  /* insert variable into hashtable */
4995  SCIP_CALL( SCIPhashtableInsert(vartable, (void*)*varnames) );
4996 
4997  ++*nvars;
4998  *varnames += 1 + (strlen(varname) + 1) / sizeof(int) + 1;
4999  }
5000 
5001  /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
5002  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_VARIDX, varidx) ); /*lint !e613*/
5003  if( coefficient != 1.0 )
5004  {
5005  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, expr, &coefficient, 0.0) );
5006  }
5007 
5008  /* Move pointer to char behind end of variable */
5009  *str = varnameendptr + 1;
5010 
5011  /* consprint sometimes prints a variable type identifier which we don't need */
5012  if( (*str)[0] == '[' && (*str)[2] == ']' &&
5013  ((*str)[1] == SCIP_VARTYPE_BINARY_CHAR ||
5014  (*str)[1] == SCIP_VARTYPE_INTEGER_CHAR ||
5015  (*str)[1] == SCIP_VARTYPE_IMPLINT_CHAR ||
5016  (*str)[1] == SCIP_VARTYPE_CONTINUOUS_CHAR ) )
5017  *str += 3;
5018 
5019  return SCIP_OKAY;
5020 }
5021 
5022 /** if str[0] points to an opening parenthesis, this function sets endptr to point to the matching closing bracket in str
5023  *
5024  * Searches for at most length characters.
5025  */
5026 static
5028  const char* str, /**< pointer to the string to be parsed */
5029  const char** endptr, /**< pointer to point to the closing parenthesis */
5030  int length /**< length of the string to be parsed */
5031  )
5032 {
5033  int nopenbrackets;
5034 
5035  assert(str[0] == '(');
5036 
5037  *endptr = str;
5038 
5039  /* find the end of this expression */
5040  nopenbrackets = 0;
5041  while( (*endptr - str ) < length && !(nopenbrackets == 1 && *endptr[0] == ')') )
5042  {
5043  if( *endptr[0] == '(')
5044  ++nopenbrackets;
5045  if( *endptr[0] == ')')
5046  --nopenbrackets;
5047  ++*endptr;
5048  }
5049 
5050  if( *endptr[0] != ')' )
5051  {
5052  SCIPerrorMessage("unable to find closing parenthesis in unbalanced expression %.*s\n", length, str);
5053  return SCIP_READERROR;
5054  }
5055 
5056  return SCIP_OKAY;
5057 }
5058 
5059 /** this function sets endptr to point to the next separating comma in str
5060  *
5061  * That is, for a given string like "x+f(x,y),z", endptr will point to the comma before "z"
5062  *
5063  * Searches for at most length characters.
5064  */
5065 static
5067  const char* str, /**< pointer to the string to be parsed */
5068  const char** endptr, /**< pointer to point to the comma */
5069  int length /**< length of the string to be parsed */
5070  )
5071 {
5072  int nopenbrackets;
5073 
5074  *endptr = str;
5075 
5076  /* find a comma without open brackets */
5077  nopenbrackets = 0;
5078  while( (*endptr - str ) < length && !(nopenbrackets == 0 && *endptr[0] == ',') )
5079  {
5080  if( *endptr[0] == '(')
5081  ++nopenbrackets;
5082  if( *endptr[0] == ')')
5083  --nopenbrackets;
5084  ++*endptr;
5085  }
5086 
5087  if( *endptr[0] != ',' )
5088  {
5089  SCIPerrorMessage("unable to find separating comma in unbalanced expression %.*s\n", length, str);
5090  return SCIP_READERROR;
5091  }
5092 
5093  return SCIP_OKAY;
5094 }
5095 
5096 /** parses an expression from a string */
5097 static
5099  BMS_BLKMEM* blkmem, /**< block memory data structure */
5100  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
5101  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
5102  const char* str, /**< pointer to the string to be parsed */
5103  int length, /**< length of the string to be parsed */
5104  const char* lastchar, /**< pointer to the last char of str that should be parsed */
5105  int* nvars, /**< running number of encountered variables so far */
5106  int** varnames, /**< pointer to buffer to store new variable names */
5107  int* varnameslength, /**< pointer to length of the varnames buffer array */
5108  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
5109  int recursiondepth /**< current recursion depth */
5110  )
5111 { /*lint --e{712,747}*/
5112  SCIP_EXPR* arg1;
5113  SCIP_EXPR* arg2;
5114  const char* subexpptr;
5115  const char* subexpendptr;
5116  const char* strstart;
5117  const char* endptr;
5118  char* nonconstendptr;
5119  SCIP_Real number;
5120  int subexplength;
5121  int nopenbrackets;
5122 
5123  assert(blkmem != NULL);
5124  assert(expr != NULL);
5125  assert(str != NULL);
5126  assert(lastchar >= str);
5127  assert(nvars != NULL);
5128  assert(varnames != NULL);
5129  assert(vartable != NULL);
5130 
5131  assert(recursiondepth < 100);
5132 
5133  strstart = str; /* might be needed for error message... */
5134 
5135  SCIPdebugMessage("exprParse (%i): parsing %.*s\n", recursiondepth, (int) (lastchar-str + 1), str);
5136 
5137  /* ignore whitespace */
5138  while( isspace((unsigned char)*str) )
5139  ++str;
5140 
5141  /* look for a sum or difference not contained in brackets */
5142  subexpptr = str;
5143  nopenbrackets = 0;
5144 
5145  /* find the end of this expression
5146  * a '+' right at the beginning indicates a coefficient, not treated here, or a summation
5147  */
5148  while( subexpptr != lastchar && !(nopenbrackets == 0 && (subexpptr[0] == '+' || subexpptr[0] == '-') && subexpptr != str) )
5149  {
5150  if( subexpptr[0] == '(')
5151  ++nopenbrackets;
5152  if( subexpptr[0] == ')')
5153  --nopenbrackets;
5154  ++subexpptr;
5155  }
5156 
5157  if( subexpptr != lastchar )
5158  {
5159  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str, (int) ((subexpptr - 1) - str + 1), subexpptr - 1, nvars,
5160  varnames, varnameslength, vartable, recursiondepth + 1) );
5161 
5162  if( subexpptr[0] == '+' )
5163  ++subexpptr;
5164  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, subexpptr , (int) (lastchar - (subexpptr ) + 1), lastchar, nvars,
5165  varnames, varnameslength, vartable, recursiondepth + 1) );
5166 
5167  /* make new expression from two arguments
5168  * we always use add, because we leave the operator between the found expressions in the second argument
5169  * this way, we do not have to worry about ''minus brackets'' in the case of more then two summands:
5170  * a - b - c = a + (-b -c)
5171  */
5172  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5173 
5174  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5175  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5176  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5177 
5178  return SCIP_OKAY;
5179  }
5180 
5181  /* check for a bracketed subexpression */
5182  if( str[0] == '(' )
5183  {
5184  nopenbrackets = 0;
5185 
5186  subexplength = -1; /* we do not want the closing bracket in the string */
5187  subexpptr = str + 1; /* leave out opening bracket */
5188 
5189  /* find the end of this expression */
5190  while( subexplength < length && !(nopenbrackets == 1 && str[0] == ')') )
5191  {
5192  if( str[0] == '(' )
5193  ++nopenbrackets;
5194  if( str[0] == ')' )
5195  --nopenbrackets;
5196  ++str;
5197  ++subexplength;
5198  }
5199  subexpendptr = str - 1; /* leave out closing bracket */
5200 
5201  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, subexpptr, subexplength, subexpendptr, nvars, varnames,
5202  varnameslength, vartable, recursiondepth + 1) );
5203  ++str;
5204  }
5205  else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+')
5206  && (isdigit((unsigned char)str[1]) || str[1] == ' ')) )
5207  {
5208  /* check if there is a lonely minus coming, indicating a -1.0 */
5209  if( str[0] == '-' && str[1] == ' ' )
5210  {
5211  number = -1.0;
5212  nonconstendptr = (char*) str + 1;
5213  }
5214  /* check if there is a number coming */
5215  else if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5216  {
5217  SCIPerrorMessage("error parsing number from <%s>\n", str);
5218  return SCIP_READERROR;
5219  }
5220  str = nonconstendptr;
5221 
5222  /* ignore whitespace */
5223  while( isspace((unsigned char)*str) && str != lastchar )
5224  ++str;
5225 
5226  if( str[0] != '*' && str[0] != '/' && str[0] != '+' && str[0] != '-' && str[0] != '^' )
5227  {
5228  if( str < lastchar )
5229  {
5230  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, str, (int)(lastchar - str) + 1, lastchar, nvars, varnames,
5231  varnameslength, vartable, recursiondepth + 1) );
5232  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, *expr, number) );
5233  }
5234  else
5235  {
5236  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5237  }
5238  str = lastchar + 1;
5239  }
5240  else
5241  {
5242  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5243  }
5244  }
5245  else if( str[0] == '<' )
5246  {
5247  /* check if expressions begins with a variable */
5248  SCIP_CALL( exprparseReadVariable(blkmem, &str, expr, nvars, varnames, varnameslength, vartable, 1.0, NULL) );
5249  }
5250  /* four character operators */
5251  else if( strncmp(str, "sqrt", 4) == 0 )
5252  {
5253  str += 4;
5254  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5255  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5256  varnameslength, vartable, recursiondepth + 1) );
5257  str = endptr + 1;
5258 
5259  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQRT, arg1) );
5260  }
5261  /* three character operators with 1 argument */
5262  else if(
5263  strncmp(str, "abs", 3) == 0 ||
5264  strncmp(str, "cos", 3) == 0 ||
5265  strncmp(str, "exp", 3) == 0 ||
5266  strncmp(str, "log", 3) == 0 ||
5267  strncmp(str, "sin", 3) == 0 ||
5268  strncmp(str, "sqr", 3) == 0 ||
5269  strncmp(str, "tan", 3) == 0 )
5270  {
5271  const char* opname = str;
5272 
5273  str += 3;
5274  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5275  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5276  varnameslength, vartable, recursiondepth + 1) );
5277  str = endptr + 1;
5278 
5279  if( strncmp(opname, "abs", 3) == 0 )
5280  {
5281  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_ABS, arg1) );
5282  }
5283  else if( strncmp(opname, "cos", 3) == 0 )
5284  {
5285  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_COS, arg1) );
5286  }
5287  else if( strncmp(opname, "exp", 3) == 0 )
5288  {
5289  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, arg1) );
5290  }
5291  else if( strncmp(opname, "log", 3) == 0 )
5292  {
5293  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5294  }
5295  else if( strncmp(opname, "sin", 3) == 0 )
5296  {
5297  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIN, arg1) );
5298  }
5299  else if( strncmp(opname, "sqr", 3) == 0 )
5300  {
5301  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQUARE, arg1) );
5302  }
5303  else
5304  {
5305  assert(strncmp(opname, "tan", 3) == 0);
5306  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_TAN, arg1) );
5307  }
5308  }
5309  /* three character operators with 2 arguments */
5310  else if(
5311  strncmp(str, "max", 3) == 0 ||
5312  strncmp(str, "min", 3) == 0 )
5313  {
5314  /* we have a string of the form "min(...,...)" or "max(...,...)"
5315  * first find the closing parenthesis, then the comma
5316  */
5317  const char* comma;
5318  SCIP_EXPROP op;
5319 
5320  op = (str[1] == 'a' ? SCIP_EXPR_MAX : SCIP_EXPR_MIN);
5321 
5322  str += 3;
5323  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5324 
5325  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5326 
5327  /* parse first argument [str+1..comma-1] */
5328  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5329  varnameslength, vartable, recursiondepth + 1) );
5330 
5331  /* parse second argument [comma+1..endptr] */
5332  ++comma;
5333  while( comma < endptr && *comma == ' ' )
5334  ++comma;
5335 
5336  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, comma, endptr - comma, endptr - 1, nvars, varnames,
5337  varnameslength, vartable, recursiondepth + 1) );
5338 
5339  SCIP_CALL( SCIPexprCreate(blkmem, expr, op, arg1, arg2) );
5340 
5341  str = endptr + 1;
5342  }
5343  else if( strncmp(str, "power", 5) == 0 )
5344  {
5345  /* we have a string of the form "power(...,integer)" (thus, intpower)
5346  * first find the closing parenthesis, then the comma
5347  */
5348  const char* comma;
5349  int exponent;
5350 
5351  str += 5;
5352  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5353 
5354  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5355 
5356  /* parse first argument [str+1..comma-1] */
5357  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5358  varnameslength, vartable, recursiondepth + 1) );
5359 
5360  ++comma;
5361  /* parse second argument [comma, endptr-1]: it needs to be an integer */
5362  while( comma < endptr && *comma == ' ' )
5363  ++comma;
5364  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5365  {
5366  SCIPerrorMessage("error parsing integer exponent from <%s>\n", comma);
5367  }
5368  if( !SCIPstrToIntValue(comma, &exponent, &nonconstendptr) )
5369  {
5370  SCIPerrorMessage("error parsing integer from <%s>\n", comma);
5371  return SCIP_READERROR;
5372  }
5373 
5374  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, exponent) );
5375 
5376  str = endptr + 1;
5377  }
5378  else if( strncmp(str, "realpower", 9) == 0 || strncmp(str, "signpower", 9) == 0 )
5379  {
5380  /* we have a string of the form "realpower(...,double)" or "signpower(...,double)"
5381  * first find the closing parenthesis, then the comma
5382  */
5383  const char* opname = str;
5384  const char* comma;
5385 
5386  str += 9;
5387  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5388 
5389  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5390 
5391  /* parse first argument [str+1..comma-1] */
5392  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5393  varnameslength, vartable, recursiondepth + 1) );
5394 
5395  ++comma;
5396  /* parse second argument [comma, endptr-1]: it needs to be an number */
5397  while( comma < endptr && *comma == ' ' )
5398  ++comma;
5399  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5400  {
5401  SCIPerrorMessage("error parsing number exponent from <%s>\n", comma);
5402  }
5403  if( !SCIPstrToRealValue(comma, &number, &nonconstendptr) )
5404  {
5405  SCIPerrorMessage("error parsing number from <%s>\n", comma);
5406  return SCIP_READERROR;
5407  }
5408 
5409  if( strncmp(opname, "realpower", 9) == 0 )
5410  {
5411  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, number) );
5412  }
5413  else
5414  {
5415  assert(strncmp(opname, "signpower", 9) == 0);
5416  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIGNPOWER, arg1, number) );
5417  }
5418 
5419  str = endptr + 1;
5420  }
5421  else if( isalpha(*str) || *str == '_' || *str == '#' )
5422  {
5423  /* check for a variable, that was not recognized earlier because somebody omitted the '<' and '>' we need for
5424  * SCIPparseVarName, making everyones life harder;
5425  * we allow only variable names starting with a character or underscore here
5426  */
5427  const char* varnamestartptr = str;
5428 
5429  /* allow only variable names containing characters, digits, hash marks, and underscores here */
5430  while( isalnum(str[0]) || str[0] == '_' || str[0] == '#' )
5431  ++str;
5432 
5433  SCIP_CALL( exprparseReadVariable(blkmem, &varnamestartptr, expr, nvars, varnames, varnameslength,
5434  vartable, 1.0, str) );
5435  }
5436  else
5437  {
5438  SCIPerrorMessage("parsing of invalid expression %.*s.\n", (int) (lastchar - str + 1), str);
5439  return SCIP_READERROR;
5440  }
5441 
5442  /* if we are one char behind lastchar, we are done */
5443  if( str == lastchar + 1)
5444  {
5445  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5446  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5447  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5448 
5449  return SCIP_OKAY;
5450  }
5451 
5452  /* check if we are still in bounds */
5453  if( str > lastchar + 1)
5454  {
5455  SCIPerrorMessage("error finding first expression in \"%.*s\" took us outside of given subexpression length\n", length, strstart);
5456  return SCIP_READERROR;
5457  }
5458 
5459  /* ignore whitespace */
5460  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5461  ++str;
5462 
5463  /* maybe now we're done? */
5464  if( str >= lastchar + 1)
5465  {
5466  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5467  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5468  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5469 
5470  return SCIP_OKAY;
5471  }
5472 
5473  if( str[0] == '^' )
5474  {
5475  /* a '^' behind the found expression indicates a power */
5476  SCIP_Real constant;
5477 
5478  arg1 = *expr;
5479  ++str;
5480  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5481  ++str;
5482 
5483  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5484  {
5485  /* there is a number coming */
5486  if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5487  {
5488  SCIPerrorMessage("error parsing number from <%s>\n", str);
5489  return SCIP_READERROR;
5490  }
5491 
5492  SCIP_CALL( SCIPexprCreate(blkmem, &arg2, SCIP_EXPR_CONST, number) );
5493  str = nonconstendptr;
5494 
5495  constant = SCIPexprGetOpReal(arg2);
5496  SCIPexprFreeDeep(blkmem, &arg2);
5497 
5498  /* expr^number is intpower or realpower */
5499  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5500  {
5501  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5502  }
5503  else
5504  {
5505  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5506  }
5507  }
5508  else if( str[0] == '(' )
5509  {
5510  /* we use exprParse to evaluate the exponent */
5511 
5512  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5513  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5514  varnameslength, vartable, recursiondepth + 1) );
5515 
5516  if( SCIPexprGetOperator(arg2) != SCIP_EXPR_CONST )
5517  {
5518  /* reformulate arg1^arg2 as exp(arg2 * log(arg1)) */
5519  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5520  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, *expr, arg2) );
5521  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, *expr) );
5522  }
5523  else
5524  {
5525  /* expr^number is intpower or realpower */
5526  constant = SCIPexprGetOpReal(arg2);
5527  SCIPexprFreeDeep(blkmem, &arg2);
5528  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5529  {
5530  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5531  }
5532  else
5533  {
5534  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5535  }
5536  }
5537  str = endptr + 1;
5538  }
5539  else
5540  {
5541  SCIPerrorMessage("unexpected string following ^ in %.*s\n", length, str);
5542  return SCIP_READERROR;
5543  }
5544 
5545  /* ignore whitespace */
5546  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5547  ++str;
5548  }
5549 
5550  /* check for a two argument operator that is not a multiplication */
5551  if( str <= lastchar && (str[0] == '+' || str[0] == '-' || str[0] == '/') )
5552  {
5553  char op;
5554 
5555  op = str[0];
5556  arg1 = *expr;
5557 
5558  /* step forward over the operator to go to the beginning of the second argument */
5559  ++str;
5560 
5561  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5562  varnameslength, vartable, recursiondepth + 1) );
5563  str = lastchar + 1;
5564 
5565  /* make new expression from two arguments */
5566  if( op == '+')
5567  {
5568  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5569  }
5570  else if( op == '-')
5571  {
5572  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, -1.0, arg2, 0.0) );
5573  }
5574  else if( op == '*' )
5575  {
5576  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5577  {
5578  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5579  }
5580  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5581  {
5582  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5583  }
5584  else
5585  {
5586  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5587  }
5588  }
5589  else
5590  {
5591  assert(op == '/');
5592 
5593  if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5594  {
5595  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, 1.0 / SCIPexprGetOpReal(arg2)) );
5596  SCIPexprFreeShallow(blkmem, &arg2);
5597  }
5598  else
5599  {
5600  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_DIV, arg1, arg2) );
5601  }
5602  }
5603  }
5604 
5605  /* ignore whitespace */
5606  while( isspace((unsigned char)*str) )
5607  ++str;
5608 
5609  /* we are either done or we have a multiplication? */
5610  if( str >= lastchar + 1 )
5611  {
5612  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5613  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5614  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5615 
5616  return SCIP_OKAY;
5617  }
5618 
5619  /* if there is a part of the string left to be parsed, we assume that this as a multiplication */
5620  arg1 = *expr;
5621 
5622  /* stepping over multiplication operator if needed */
5623  if( str[0] == '*' )
5624  {
5625  ++str;
5626  }
5627  else if( str[0] != '(' )
5628  {
5629  SCIPdebugMessage("No operator found, assuming a multiplication before %.*s\n", (int) (lastchar - str + 1), str);
5630  }
5631 
5632  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5633  varnameslength, vartable, recursiondepth + 1) );
5634 
5635  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5636  {
5637  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5638  SCIPexprFreeDeep(blkmem, &arg1);
5639  }
5640  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5641  {
5642  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5643  SCIPexprFreeDeep(blkmem, &arg2);
5644  }
5645  else
5646  {
5647  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5648  }
5649 
5650  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5651  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5652  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5653 
5654  return SCIP_OKAY;
5655 }
5656 
5657 /**@} */
5658 
5659 /**@name Expression methods */
5660 /**@{ */
5661 
5662 /* In debug mode, the following methods are implemented as function calls to ensure
5663  * type validity.
5664  * In optimized mode, the methods are implemented as defines to improve performance.
5665  * However, we want to have them in the library anyways, so we have to undef the defines.
5666  */
5667 
5668 #undef SCIPexprGetOperator
5669 #undef SCIPexprGetNChildren
5670 #undef SCIPexprGetChildren
5671 #undef SCIPexprGetOpIndex
5672 #undef SCIPexprGetOpReal
5673 #undef SCIPexprGetOpData
5674 #undef SCIPexprGetRealPowerExponent
5675 #undef SCIPexprGetIntPowerExponent
5676 #undef SCIPexprGetSignPowerExponent
5677 #undef SCIPexprGetLinearCoefs
5678 #undef SCIPexprGetLinearConstant
5679 #undef SCIPexprGetQuadElements
5680 #undef SCIPexprGetQuadConstant
5681 #undef SCIPexprGetQuadLinearCoefs
5682 #undef SCIPexprGetNQuadElements
5683 #undef SCIPexprGetMonomials
5684 #undef SCIPexprGetNMonomials
5685 #undef SCIPexprGetPolynomialConstant
5686 #undef SCIPexprGetMonomialCoef
5687 #undef SCIPexprGetMonomialNFactors
5688 #undef SCIPexprGetMonomialChildIndices
5689 #undef SCIPexprGetMonomialExponents
5690 #undef SCIPexprGetUserData
5691 #undef SCIPexprHasUserEstimator
5692 #undef SCIPexprGetUserEvalCapability
5693 
5694 /** gives operator of expression */
5696  SCIP_EXPR* expr /**< expression */
5697  )
5698 {
5699  assert(expr != NULL);
5700 
5701  return expr->op;
5702 }
5703 
5704 /** gives number of children of an expression */
5706  SCIP_EXPR* expr /**< expression */
5707  )
5708 {
5709  assert(expr != NULL);
5710 
5711  return expr->nchildren;
5712 }
5713 
5714 /** gives pointer to array with children of an expression */
5716  SCIP_EXPR* expr /**< expression */
5717  )
5718 {
5719  assert(expr != NULL);
5720 
5721  return expr->children;
5722 }
5723 
5724 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
5726  SCIP_EXPR* expr /**< expression */
5727  )
5728 {
5729  assert(expr != NULL);
5730  assert(expr->op == SCIP_EXPR_VARIDX || expr->op == SCIP_EXPR_PARAM);
5731 
5732  return expr->data.intval;
5733 }
5734 
5735 /** gives real belonging to a SCIP_EXPR_CONST operand */
5737  SCIP_EXPR* expr /**< expression */
5738  )
5739 {
5740  assert(expr != NULL);
5741  assert(expr->op == SCIP_EXPR_CONST);
5742 
5743  return expr->data.dbl;
5744 }
5745 
5746 /** gives void* belonging to a complex operand */
5748  SCIP_EXPR* expr /**< expression */
5749  )
5750 {
5751  assert(expr != NULL);
5752  assert(expr->op >= SCIP_EXPR_SUM); /* only complex operands store their data as void* */
5753 
5754  return expr->data.data;
5755 }
5756 
5757 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
5759  SCIP_EXPR* expr /**< expression */
5760  )
5761 {
5762  assert(expr != NULL);
5763  assert(expr->op == SCIP_EXPR_REALPOWER);
5764 
5765  return expr->data.dbl;
5766 }
5767 
5768 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
5770  SCIP_EXPR* expr /**< expression */
5771  )
5772 {
5773  assert(expr != NULL);
5774  assert(expr->op == SCIP_EXPR_INTPOWER);
5775 
5776  return expr->data.intval;
5777 }
5778 
5779 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
5781  SCIP_EXPR* expr /**< expression */
5782  )
5783 {
5784  assert(expr != NULL);
5785  assert(expr->op == SCIP_EXPR_SIGNPOWER);
5786 
5787  return expr->data.dbl;
5788 }
5789 
5790 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
5792  SCIP_EXPR* expr /**< expression */
5793  )
5794 {
5795  assert(expr != NULL);
5796  assert(expr->op == SCIP_EXPR_LINEAR);
5797  assert(expr->data.data != NULL);
5798 
5799  /* the coefficients are stored in the first nchildren elements of the array stored as expression data */
5800  return (SCIP_Real*)expr->data.data;
5801 }
5802 
5803 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
5805  SCIP_EXPR* expr /**< expression */
5806  )
5807 {
5808  assert(expr != NULL);
5809  assert(expr->op == SCIP_EXPR_LINEAR);
5810  assert(expr->data.data != NULL);
5811 
5812  /* the constant is stored in the nchildren's element of the array stored as expression data */
5813  return ((SCIP_Real*)expr->data.data)[expr->nchildren];
5814 }
5815 
5816 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5818  SCIP_EXPR* expr /**< quadratic expression */
5819  )
5820 {
5821  assert(expr != NULL);
5822  assert(expr->op == SCIP_EXPR_QUADRATIC);
5823  assert(expr->data.data != NULL);
5824 
5825  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->quadelems;
5826 }
5827 
5828 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
5830  SCIP_EXPR* expr /**< quadratic expression */
5831  )
5832 {
5833  assert(expr != NULL);
5834  assert(expr->op == SCIP_EXPR_QUADRATIC);
5835  assert(expr->data.data != NULL);
5836 
5837  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->constant;
5838 }
5839 
5840 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression
5841  * can be NULL if all coefficients are 0.0 */
5843  SCIP_EXPR* expr /**< quadratic expression */
5844  )
5845 {
5846  assert(expr != NULL);
5847  assert(expr->op == SCIP_EXPR_QUADRATIC);
5848  assert(expr->data.data != NULL);
5849 
5850  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->lincoefs;
5851 }
5852 
5853 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5855  SCIP_EXPR* expr /**< quadratic expression */
5856  )
5857 {
5858  assert(expr != NULL);
5859  assert(expr->op == SCIP_EXPR_QUADRATIC);
5860  assert(expr->data.data != NULL);
5861 
5862  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->nquadelems;
5863 }
5864 
5865 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5867  SCIP_EXPR* expr /**< expression */
5868  )
5869 {
5870  assert(expr != NULL);
5871  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5872  assert(expr->data.data != NULL);
5873 
5874  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->monomials;
5875 }
5876 
5877 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5879  SCIP_EXPR* expr /**< expression */
5880  )
5881 {
5882  assert(expr != NULL);
5883  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5884  assert(expr->data.data != NULL);
5885 
5886  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->nmonomials;
5887 }
5888 
5889 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
5891  SCIP_EXPR* expr /**< expression */
5892  )
5893 {
5894  assert(expr != NULL);
5895  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5896  assert(expr->data.data != NULL);
5897 
5898  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant;
5899 }
5900 
5901 /** gets coefficient of a monomial */
5903  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5904  )
5905 {
5906  assert(monomial != NULL);
5907 
5908  return monomial->coef;
5909 }
5910 
5911 /** gets number of factors of a monomial */
5913  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5914  )
5915 {
5916  assert(monomial != NULL);
5917 
5918  return monomial->nfactors;
5919 }
5920 
5921 /** gets indices of children corresponding to factors of a monomial */
5923  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5924  )
5925 {
5926  assert(monomial != NULL);
5927 
5928  return monomial->childidxs;
5929 }
5930 
5931 /** gets exponents in factors of a monomial */
5933  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5934  )
5935 {
5936  assert(monomial != NULL);
5937 
5938  return monomial->exponents;
5939 }
5940 
5941 /** gets user data of a user expression */
5943  SCIP_EXPR* expr
5944  )
5945 {
5946  assert(expr != NULL);
5947  assert(expr->data.data != NULL);
5948 
5949  return ((SCIP_EXPRDATA_USER*)expr->data.data)->userdata;
5950 }
5951 
5952 /** indicates whether a user expression has the estimator callback defined */
5954  SCIP_EXPR* expr
5955  )
5956 {
5957  assert(expr != NULL);
5958  assert(expr->data.data != NULL);
5959 
5960  return ((SCIP_EXPRDATA_USER*)expr->data.data)->estimate != NULL;
5961 }
5962 
5963 /** gives the evaluation capability of a user expression */
5965  SCIP_EXPR* expr
5966  )
5967 {
5968  assert(expr != NULL);
5969  assert(expr->data.data != NULL);
5970 
5971  return ((SCIP_EXPRDATA_USER*)expr->data.data)->evalcapability;
5972 }
5973 
5974 /** creates a simple expression */
5976  BMS_BLKMEM* blkmem, /**< block memory data structure */
5977  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
5978  SCIP_EXPROP op, /**< operand of expression */
5979  ... /**< arguments of operand */
5980  )
5981 {
5982  va_list ap;
5983  SCIP_EXPR** children;
5984  SCIP_EXPROPDATA opdata;
5985 
5986  assert(blkmem != NULL);
5987  assert(expr != NULL);
5988 
5989  switch( op )
5990  {
5991  case SCIP_EXPR_VARIDX:
5992  case SCIP_EXPR_PARAM:
5993  {
5994  va_start( ap, op ); /*lint !e838*/
5995  opdata.intval = va_arg( ap, int ); /*lint !e416 !e826*/
5996  va_end( ap ); /*lint !e826*/
5997 
5998  assert( opdata.intval >= 0 );
5999 
6000  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
6001  break;
6002  }
6003 
6004  case SCIP_EXPR_CONST:
6005  {
6006  va_start(ap, op ); /*lint !e838*/
6007  opdata.dbl = va_arg( ap, SCIP_Real ); /*lint !e416 !e826*/
6008  va_end( ap ); /*lint !e826*/
6009 
6010  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
6011  break;
6012  }
6013 
6014  /* operands with two children */
6015  case SCIP_EXPR_PLUS :
6016  case SCIP_EXPR_MINUS :
6017  case SCIP_EXPR_MUL :
6018  case SCIP_EXPR_DIV :
6019  case SCIP_EXPR_MIN :
6020  case SCIP_EXPR_MAX :
6021  {
6022  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 2) ); /*lint !e506*/
6023 
6024  va_start(ap, op ); /*lint !e838*/
6025  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6026  children[1] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6027  assert(children[0] != NULL);
6028  assert(children[1] != NULL);
6029  va_end( ap ); /*lint !e826*/
6030  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6031 
6032  SCIP_CALL( exprCreate( blkmem, expr, op, 2, children, opdata ) );
6033  break;
6034  }
6035 
6036  /* operands with one child */
6037  case SCIP_EXPR_SQUARE:
6038  case SCIP_EXPR_SQRT :
6039  case SCIP_EXPR_EXP :
6040  case SCIP_EXPR_LOG :
6041  case SCIP_EXPR_SIN :
6042  case SCIP_EXPR_COS :
6043  case SCIP_EXPR_TAN :
6044  /* case SCIP_EXPR_ERF : */
6045  /* case SCIP_EXPR_ERFI : */
6046  case SCIP_EXPR_ABS :
6047  case SCIP_EXPR_SIGN :
6048  {
6049  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6050 
6051  va_start(ap, op ); /*lint !e838*/
6052  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6053  assert(children[0] != NULL);
6054  va_end( ap ); /*lint !e826*/
6055  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6056 
6057  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6058  break;
6059  }
6060 
6061  case SCIP_EXPR_REALPOWER:
6062  case SCIP_EXPR_SIGNPOWER:
6063  {
6064  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6065 
6066  va_start(ap, op ); /*lint !e838*/
6067  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6068  assert(children[0] != NULL);
6069  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
6070  va_end( ap ); /*lint !e826*/
6071 
6072  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6073  break;
6074  }
6075 
6076  case SCIP_EXPR_INTPOWER:
6077  {
6078  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6079 
6080  va_start(ap, op ); /*lint !e838*/
6081  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6082  assert(children[0] != NULL);
6083  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
6084  va_end( ap ); /*lint !e826*/
6085 
6086  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6087  break;
6088  }
6089 
6090  /* complex operands */
6091  case SCIP_EXPR_SUM :
6092  case SCIP_EXPR_PRODUCT:
6093  {
6094  int nchildren;
6095  SCIP_EXPR** childrenarg;
6096 
6097  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6098 
6099  va_start(ap, op ); /*lint !e838*/
6100  /* first argument should be number of children */
6101  nchildren = va_arg( ap, int ); /*lint !e416 !e826*/
6102  assert(nchildren >= 0);
6103 
6104  /* for a sum or product of 0 terms we can finish here */
6105  if( nchildren == 0 )
6106  {
6107  SCIP_RETCODE retcode;
6108  retcode = exprCreate( blkmem, expr, op, 0, NULL, opdata);
6109  va_end( ap ); /*lint !e826*/
6110  SCIP_CALL( retcode );
6111  break;
6112  }
6113 
6114  /* next argument should be array of children expressions */
6115  childrenarg = va_arg( ap, SCIP_EXPR** ); /*lint !e416 !e826*/
6116  assert(childrenarg != NULL);
6117  va_end( ap ); /*lint !e826*/
6118 
6119  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &children, childrenarg, nchildren) );
6120 
6121  SCIP_CALL( exprCreate( blkmem, expr, op, nchildren, children, opdata) );
6122  break;
6123  }
6124 
6125  case SCIP_EXPR_LINEAR :
6126  case SCIP_EXPR_QUADRATIC:
6127  case SCIP_EXPR_POLYNOMIAL:
6128  case SCIP_EXPR_USER:
6129  {
6130  SCIPerrorMessage("cannot create complex expression linear, quadratic, polynomial, or user with SCIPexprCreate\n");
6131  return SCIP_INVALIDDATA;
6132  }
6133 
6134  case SCIP_EXPR_LAST:
6135  SCIPABORT();
6136  break;
6137  }
6138 
6139  return SCIP_OKAY;
6140 }
6141 
6142 /** copies an expression including its children */
6144  BMS_BLKMEM* blkmem, /**< block memory data structure */
6145  SCIP_EXPR** targetexpr, /**< buffer to store pointer to copied expression */
6146  SCIP_EXPR* sourceexpr /**< expression to copy */
6147  )
6148 {
6149  assert(blkmem != NULL);
6150  assert(targetexpr != NULL);
6151  assert(sourceexpr != NULL);
6152 
6153  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targetexpr, sourceexpr) );
6154 
6155  if( sourceexpr->nchildren )
6156  {
6157  int i;
6158 
6159  /* alloc memory for children expressions */
6160  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetexpr)->children, sourceexpr->nchildren) );
6161 
6162  /* copy children expressions */
6163  for( i = 0; i < sourceexpr->nchildren; ++i )
6164  {
6165  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targetexpr)->children[i], sourceexpr->children[i]) );
6166  }
6167  }
6168  else
6169  {
6170  assert((*targetexpr)->children == NULL); /* otherwise, sourceexpr->children was not NULL, which is wrong */
6171  }
6172 
6173  /* call operands data copy callback for complex operands
6174  * for simple operands BMSduplicate above should have done the job
6175  */
6176  if( exprOpTable[sourceexpr->op].copydata != NULL )
6177  {
6178  SCIP_CALL( exprOpTable[sourceexpr->op].copydata(blkmem, sourceexpr->nchildren, sourceexpr->data, &(*targetexpr)->data) );
6179  }
6180 
6181  return SCIP_OKAY;
6182 }
6183 
6184 /** frees an expression including its children */
6186  BMS_BLKMEM* blkmem, /**< block memory data structure */
6187  SCIP_EXPR** expr /**< pointer to expression to free */
6188  )
6189 {
6190  assert(blkmem != NULL);
6191  assert(expr != NULL);
6192  assert(*expr != NULL);
6193 
6194  /* call operands data free callback, if given */
6195  if( exprOpTable[(*expr)->op].freedata != NULL )
6196  {
6197  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6198  }
6199 
6200  if( (*expr)->nchildren )
6201  {
6202  int i;
6203 
6204  assert( (*expr)->children != NULL );
6205 
6206  for( i = 0; i < (*expr)->nchildren; ++i )
6207  {
6208  SCIPexprFreeDeep(blkmem, &(*expr)->children[i]);
6209  assert((*expr)->children[i] == NULL);
6210  }
6211 
6212  BMSfreeBlockMemoryArray(blkmem, &(*expr)->children, (*expr)->nchildren);
6213  }
6214  else
6215  {
6216  assert( (*expr)->children == NULL );
6217  }
6218 
6219  BMSfreeBlockMemory(blkmem, expr);
6220 }
6221 
6222 /** frees an expression but not its children */
6224  BMS_BLKMEM* blkmem, /**< block memory data structure */
6225  SCIP_EXPR** expr /**< pointer to expression to free */
6226  )
6227 {
6228  assert(blkmem != NULL);
6229  assert(expr != NULL);
6230  assert(*expr != NULL);
6231 
6232  /* call operands data free callback, if given */
6233  if( exprOpTable[(*expr)->op].freedata != NULL )
6234  {
6235  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6236  }
6237 
6238  BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->nchildren);
6239 
6240  BMSfreeBlockMemory(blkmem, expr);
6241 }
6242 
6243 /** creates an expression from the addition of two given expression, with coefficients, and a constant
6244  *
6245  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6246  * Favors creation and maintaining of SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6247  */
6249  BMS_BLKMEM* blkmem, /**< block memory data structure */
6250  SCIP_EXPR** expr, /**< pointer to store pointer to created expression */
6251  SCIP_Real coef1, /**< coefficient of first term */
6252  SCIP_EXPR* term1, /**< expression of first term, or NULL */
6253  SCIP_Real coef2, /**< coefficient of second term */
6254  SCIP_EXPR* term2, /**< expression of second term, or NULL */
6255  SCIP_Real constant /**< constant term to add */
6256  )
6257 {
6258  assert(blkmem != NULL);
6259  assert(expr != NULL);
6260 
6261  /* @todo could do something special with quadratic and polynomial expressions */
6262 
6263  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_CONST )
6264  {
6265  constant += coef1 * SCIPexprGetOpReal(term1);
6266  SCIPexprFreeDeep(blkmem, &term1);
6267  }
6268 
6269  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_CONST )
6270  {
6271  constant += coef2 * SCIPexprGetOpReal(term2);
6272  SCIPexprFreeDeep(blkmem, &term2);
6273  }
6274 
6275  if( term1 == NULL && term2 == NULL )
6276  {
6277  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, constant) );
6278  return SCIP_OKAY;
6279  }
6280 
6281  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && coef1 != 1.0 )
6282  {
6283  /* multiply coefficients and constant of linear expression term1 by coef1 */
6284  SCIP_Real* data;
6285  int i;
6286 
6287  data = (SCIP_Real*)term1->data.data;
6288  assert(data != NULL);
6289 
6290  /* loop one more index to multiply also constant of linear expression */
6291  for( i = 0; i <= term1->nchildren; ++i )
6292  data[i] *= coef1;
6293 
6294  coef1 = 1.0;
6295  }
6296 
6297  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR && coef2 != 1.0 )
6298  {
6299  /* multiply coefficients and constant of linear expression term2 by coef2 */
6300  SCIP_Real* data;
6301  int i;
6302 
6303  data = (SCIP_Real*)term2->data.data;
6304  assert(data != NULL);
6305 
6306  /* loop one more index to multiply also constant of linear expression */
6307  for( i = 0; i <= term2->nchildren; ++i )
6308  data[i] *= coef2;
6309 
6310  coef2 = 1.0;
6311  }
6312 
6313  if( term1 == NULL || term2 == NULL )
6314  {
6315  if( term1 == NULL )
6316  {
6317  term1 = term2;
6318  coef1 = coef2;
6319  }
6320  if( constant != 0.0 || coef1 != 1.0 )
6321  {
6322  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6323  {
6324  assert(coef1 == 1.0);
6325 
6326  /* add constant to existing linear expression */
6327  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 0, NULL, NULL, constant) );
6328  *expr = term1;
6329  }
6330  else
6331  {
6332  /* create new linear expression for coef1 * term1 + constant */
6333  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term1, &coef1, constant) );
6334  }
6335  }
6336  else
6337  {
6338  assert(constant == 0.0);
6339  assert(coef1 == 1.0);
6340  *expr = term1;
6341  }
6342 
6343  return SCIP_OKAY;
6344  }
6345 
6347  {
6348  /* add 2nd linear expression to first one */
6349  assert(coef1 == 1.0);
6350  assert(coef2 == 1.0);
6351 
6353  SCIPexprFreeShallow(blkmem, &term2);
6354 
6355  *expr = term1;
6356 
6357  return SCIP_OKAY;
6358  }
6359 
6360  if( SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
6361  {
6362  /* if only term2 is linear, then swap */
6363  SCIP_EXPR* tmp;
6364 
6365  tmp = term2;
6366  assert(coef2 == 1.0);
6367 
6368  term2 = term1;
6369  coef2 = coef1;
6370  term1 = tmp;
6371  coef1 = 1.0;
6372  }
6373 
6374  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6375  {
6376  /* add coef2*term2 as extra child to linear expression term1 */
6377  assert(coef1 == 1.0);
6378 
6379  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 1, &coef2, &term2, constant) );
6380  *expr = term1;
6381 
6382  return SCIP_OKAY;
6383  }
6384 
6385  /* both terms are not linear, then create new linear term for sum */
6386  {
6387  SCIP_Real coefs[2];
6388  SCIP_EXPR* children[2];
6389 
6390  coefs[0] = coef1;
6391  coefs[1] = coef2;
6392  children[0] = term1;
6393  children[1] = term2;
6394 
6395  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 2, children, coefs, constant) );
6396  }
6397 
6398  return SCIP_OKAY;
6399 }
6400 
6401 /** creates an expression from the multiplication of an expression with a constant
6402  *
6403  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6404  * Favors creation and maintaining SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6405  */
6407  BMS_BLKMEM* blkmem, /**< block memory data structure */
6408  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
6409  SCIP_EXPR* term, /**< term to multiply by factor */
6410  SCIP_Real factor /**< factor */
6411  )
6412 {
6413  assert(blkmem != NULL);
6414  assert(expr != NULL);
6415  assert(term != NULL);
6416 
6417  if( factor == 0.0 )
6418  {
6419  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, 0.0) );
6420 
6421  SCIPexprFreeDeep(blkmem, &term);
6422 
6423  return SCIP_OKAY;
6424  }
6425  if( factor == 1.0 )
6426  {
6427  *expr = term;
6428  return SCIP_OKAY;
6429  }
6430 
6431  switch( SCIPexprGetOperator(term) )
6432  {
6433  case SCIP_EXPR_CONST :
6434  {
6435  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, factor * SCIPexprGetOpReal(term)) );
6436  SCIPexprFreeDeep(blkmem, &term);
6437  break;
6438  }
6439 
6440  case SCIP_EXPR_LINEAR :
6441  {
6442  SCIP_Real* data;
6443  int i;
6444 
6445  data = (SCIP_Real*)term->data.data;
6446  assert(data != NULL);
6447 
6448  /* loop one more index to multiply also constant of linear expression */
6449  for( i = 0; i <= SCIPexprGetNChildren(term); ++i )
6450  data[i] *= factor;
6451 
6452  *expr = term;
6453  break;
6454  }
6455 
6456  case SCIP_EXPR_QUADRATIC :
6457  {
6459  int i;
6460 
6461  data = (SCIP_EXPRDATA_QUADRATIC*)term->data.data;
6462 
6463  data->constant *= factor;
6464 
6465  if( data->lincoefs != NULL )
6466  for( i = 0; i < term->nchildren; ++i )
6467  data->lincoefs[i] *= factor;
6468 
6469  for( i = 0; i < data->nquadelems; ++i )
6470  data->quadelems[i].coef *= factor;
6471 
6472  *expr = term;
6473  break;
6474  }
6475 
6476  case SCIP_EXPR_POLYNOMIAL :
6477  {
6479  int i;
6480 
6481  data = (SCIP_EXPRDATA_POLYNOMIAL*)term->data.data;
6482 
6483  data->constant *= factor;
6484 
6485  for( i = 0; i < data->nmonomials; ++i )
6486  data->monomials[i]->coef *= factor;
6487 
6488  *expr = term;
6489  break;
6490  }
6491 
6492  default:
6493  {
6494  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term, &factor, 0.0) );
6495  break;
6496  }
6497 
6498  } /*lint !e788 */
6499 
6500  return SCIP_OKAY;
6501 }
6502 
6503 /** creates a SCIP_EXPR_LINEAR expression that is (affine) linear in its children: constant + sum_i coef_i child_i */
6505  BMS_BLKMEM* blkmem, /**< block memory data structure */
6506  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6507  int nchildren, /**< number of children */
6508  SCIP_EXPR** children, /**< children of expression */
6509  SCIP_Real* coefs, /**< coefficients of children */
6510  SCIP_Real constant /**< constant part */
6511  )
6512 {
6513  SCIP_EXPROPDATA opdata;
6514  SCIP_EXPR** childrencopy;
6515  SCIP_Real* data;
6516 
6517  assert(nchildren >= 0);
6518  assert(children != NULL || nchildren == 0);
6519  assert(coefs != NULL || nchildren == 0);
6520 
6521  if( nchildren > 0 )
6522  {
6523  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6524  }
6525  else
6526  childrencopy = NULL;
6527 
6528  /* we store the coefficients and the constant in a single array and make this our operand data */
6529  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, nchildren + 1) );
6530  BMScopyMemoryArray(data, coefs, nchildren); /*lint !e644*/
6531  data[nchildren] = constant;
6532 
6533  opdata.data = (void*)data;
6534 
6535  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_LINEAR, nchildren, childrencopy, opdata) );
6536 
6537  return SCIP_OKAY;
6538 }
6539 
6540 /** adds new terms to a linear expression */
6542  BMS_BLKMEM* blkmem, /**< block memory */
6543  SCIP_EXPR* expr, /**< linear expression */
6544  int nchildren, /**< number of children to add */
6545  SCIP_Real* coefs, /**< coefficients of additional children */
6546  SCIP_EXPR** children, /**< additional children expressions */
6547  SCIP_Real constant /**< constant to add */
6548  )
6549 {
6550  SCIP_Real* data;
6551 
6552  assert(blkmem != NULL);
6553  assert(expr != NULL);
6554  assert(expr->op == SCIP_EXPR_LINEAR);
6555  assert(nchildren >= 0);
6556  assert(coefs != NULL || nchildren == 0);
6557  assert(children != NULL || nchildren == 0);
6558 
6559  data = (SCIP_Real*)expr->data.data;
6560  assert(data != NULL);
6561 
6562  /* handle simple case of adding a constant */
6563  if( nchildren == 0 )
6564  {
6565  data[expr->nchildren] += constant;
6566 
6567  return SCIP_OKAY;
6568  }
6569 
6570  /* add new children to expr's children array */
6571  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nchildren) );
6572  BMScopyMemoryArray(&expr->children[expr->nchildren], children, nchildren); /*lint !e866*/
6573 
6574  /* add constant and new coefs to expr's data array */
6575  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, expr->nchildren + 1, expr->nchildren + nchildren + 1) );
6576  data[expr->nchildren + nchildren] = data[expr->nchildren] + constant;
6577  BMScopyMemoryArray(&data[expr->nchildren], coefs, nchildren); /*lint !e866*/
6578  expr->data.data = (void*)data;
6579 
6580  expr->nchildren += nchildren;
6581 
6582  return SCIP_OKAY;
6583 }
6584 
6585 /** creates a SCIP_EXPR_QUADRATIC expression: constant + sum_i coef_i child_i + sum_i coef_i child1_i child2_i */
6587  BMS_BLKMEM* blkmem, /**< block memory data structure */
6588  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6589  int nchildren, /**< number of children */
6590  SCIP_EXPR** children, /**< children of expression */
6591  SCIP_Real constant, /**< constant */
6592  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
6593  int nquadelems, /**< number of quadratic elements */
6594  SCIP_QUADELEM* quadelems /**< quadratic elements specifying coefficients and child indices */
6595  )
6596 {
6597  SCIP_EXPROPDATA opdata;
6598  SCIP_EXPR** childrencopy;
6600 
6601  assert(nchildren >= 0);
6602  assert(children != NULL || nchildren == 0);
6603  assert(quadelems != NULL || nquadelems == 0);
6604 
6605  if( nchildren > 0 )
6606  {
6607  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6608  }
6609  else
6610  childrencopy = NULL;
6611 
6612  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
6613 
6614  opdata.data = (void*)data;
6615 
6616  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_QUADRATIC, nchildren, childrencopy, opdata) );
6617 
6618  return SCIP_OKAY;
6619 }
6620 
6621 /** ensures that quadratic elements of a quadratic expression are sorted */
6623  SCIP_EXPR* expr /**< quadratic expression */
6624  )
6625 {
6626  assert(expr != NULL);
6627  assert(expr->op == SCIP_EXPR_QUADRATIC);
6628  assert(expr->data.data != NULL);
6629 
6631 }
6632 
6633 /** creates a SCIP_EXPR_POLYNOMIAL expression from an array of monomials: constant + sum_i monomial_i */
6635  BMS_BLKMEM* blkmem, /**< block memory data structure */
6636  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6637  int nchildren, /**< number of children */
6638  SCIP_EXPR** children, /**< children of expression */
6639  int nmonomials, /**< number of monomials */
6640  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
6641  SCIP_Real constant, /**< constant part */
6642  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6643  )
6644 {
6645  SCIP_EXPROPDATA opdata;
6646  SCIP_EXPR** childrencopy;
6648 
6649  assert(nchildren >= 0);
6650  assert(children != NULL || nchildren == 0);
6651  assert(monomials != NULL || nmonomials == 0);
6652 
6653  if( nchildren > 0 )
6654  {
6655  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6656  }
6657  else
6658  childrencopy = NULL;
6659 
6660  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
6661  opdata.data = (void*)data;
6662 
6663  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_POLYNOMIAL, nchildren, childrencopy, opdata) );
6664 
6665  return SCIP_OKAY;
6666 }
6667 
6668 /** adds an array of monomials to a SCIP_EXPR_POLYNOMIAL expression */
6670  BMS_BLKMEM* blkmem, /**< block memory of expression */
6671  SCIP_EXPR* expr, /**< expression */
6672  int nmonomials, /**< number of monomials to add */
6673  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
6674  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6675  )
6676 {
6677  assert(blkmem != NULL);
6678  assert(expr != NULL);
6679  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6680  assert(monomials != NULL || nmonomials == 0);
6681 
6682  if( nmonomials == 0 )
6683  return SCIP_OKAY;
6684 
6685  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, nmonomials, monomials, copymonomials) );
6686 
6687  return SCIP_OKAY;
6688 }
6689 
6690 /** changes the constant in a SCIP_EXPR_POLYNOMIAL expression */
6692  SCIP_EXPR* expr, /**< expression */
6693  SCIP_Real constant /**< new value for constant */
6694  )
6695 {
6696  assert(expr != NULL);
6697  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6698  assert(expr->data.data != NULL);
6699 
6700  ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant = constant;
6701 }
6702 
6703 /** multiplies each summand of a polynomial by a given constant */
6705  BMS_BLKMEM* blkmem, /**< block memory */
6706  SCIP_EXPR* expr, /**< polynomial expression */
6707  SCIP_Real factor /**< constant factor */
6708  )
6709 {
6710  assert(expr != NULL);
6711  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6712  assert(expr->data.data != NULL);
6713 
6714  polynomialdataMultiplyByConstant(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor);
6715 }
6716 
6717 /** multiplies each summand of a polynomial by a given monomial */
6719  BMS_BLKMEM* blkmem, /**< block memory */
6720  SCIP_EXPR* expr, /**< polynomial expression */
6721  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
6722  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6723  )
6724 {
6725  assert(blkmem != NULL);
6726  assert(factor != NULL);
6727  assert(expr != NULL);
6728  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6729  assert(expr->data.data != NULL);
6730 
6731  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor, childmap) );
6732 
6733  return SCIP_OKAY;
6734 }
6735 
6736 /** multiplies this polynomial by a polynomial
6737  *
6738  * Factor needs to be different from expr.
6739  * Children of factor need to be children of expr already, w.r.t. an optional mapping of child indices.
6740  */
6742  BMS_BLKMEM* blkmem, /**< block memory */
6743  SCIP_EXPR* expr, /**< polynomial expression */
6744  SCIP_EXPR* factor, /**< polynomial factor */
6745  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6746  )
6747 {
6748  assert(blkmem != NULL);
6749  assert(expr != NULL);
6750  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6751  assert(expr->data.data != NULL);
6752  assert(factor != NULL);
6753  assert(factor->op == SCIP_EXPR_POLYNOMIAL);
6754  assert(factor->data.data != NULL);
6755  assert(expr != factor);
6756 
6757 #ifndef NDEBUG
6758  if( childmap == NULL )
6759  {
6760  int i;
6761  assert(factor->nchildren == expr->nchildren);
6762  for( i = 0; i < factor->nchildren; ++i )
6763  assert(SCIPexprAreEqual(expr->children[i], factor->children[i], 0.0));
6764  }
6765  else
6766  {
6767  int i;
6768  for( i = 0; i < factor->nchildren; ++i )
6769  {
6770  assert(childmap[i] >= 0);
6771  assert(childmap[i] < expr->nchildren);
6772  assert(SCIPexprAreEqual(expr->children[childmap[i]], factor->children[i], 0.0));
6773  }
6774  }
6775 #endif
6776 
6778 
6779  return SCIP_OKAY;
6780 }
6781 
6782 /** takes a power of the polynomial
6783  *
6784  * Exponent need to be an integer.
6785  * Polynomial needs to be a monomial, if exponent is negative.
6786  */
6788  BMS_BLKMEM* blkmem, /**< block memory */
6789  SCIP_EXPR* expr, /**< polynomial expression */
6790  int exponent /**< exponent of power operation */
6791  )
6792 {
6793  assert(blkmem != NULL);
6794  assert(expr != NULL);
6795  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6796  assert(expr->data.data != NULL);
6797 
6798  SCIP_CALL( polynomialdataPower(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, exponent) );
6799 
6800  return SCIP_OKAY;
6801 }
6802 
6803 /** merges monomials in a polynomial expression that differ only in coefficient into a single monomial
6804  *
6805  * Eliminates monomials with coefficient between -eps and eps.
6806  */
6808  BMS_BLKMEM* blkmem, /**< block memory */
6809  SCIP_EXPR* expr, /**< polynomial expression */
6810  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
6811  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
6812  )
6813 {
6814  assert(expr != NULL);
6815  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6816  assert(expr->data.data != NULL);
6817 
6818  polynomialdataMergeMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, eps, mergefactors);
6819 }
6820 
6821 /** checks if two monomials are equal */
6823  SCIP_EXPRDATA_MONOMIAL* monomial1, /**< first monomial */
6824  SCIP_EXPRDATA_MONOMIAL* monomial2, /**< second monomial */
6825  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6826  )
6827 {
6828  int i;
6829 
6830  assert(monomial1 != NULL);
6831  assert(monomial2 != NULL);
6832 
6833  if( monomial1->nfactors != monomial2->nfactors )
6834  return FALSE;
6835 
6836  if( !EPSEQ(monomial1->coef, monomial2->coef, eps) )
6837  return FALSE;
6838 
6839  SCIPexprSortMonomialFactors(monomial1);
6840  SCIPexprSortMonomialFactors(monomial2);
6841 
6842  for( i = 0; i < monomial1->nfactors; ++i )
6843  {
6844  if( monomial1->childidxs[i] != monomial2->childidxs[i] ||
6845  !EPSEQ(monomial1->exponents[i], monomial2->exponents[i], eps) )
6846  return FALSE;
6847  }
6848 
6849  return TRUE;
6850 }
6851 
6852 /** changes coefficient of monomial */
6854  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6855  SCIP_Real newcoef /**< new coefficient */
6856  )
6857 {
6858  assert(monomial != NULL);
6859 
6860  monomial->coef = newcoef;
6861 }
6862 
6863 /** adds factors to a monomial */
6865  BMS_BLKMEM* blkmem, /**< block memory */
6866  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6867  int nfactors, /**< number of factors to add */
6868  int* childidxs, /**< indices of children corresponding to factors */
6869  SCIP_Real* exponents /**< exponent in each factor */
6870  )
6871 {
6872  assert(monomial != NULL);
6873  assert(nfactors >= 0);
6874  assert(childidxs != NULL || nfactors == 0);
6875  assert(exponents != NULL || nfactors == 0);
6876 
6877  if( nfactors == 0 )
6878  return SCIP_OKAY;
6879 
6880  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + nfactors) );
6881  assert(monomial->nfactors + nfactors <= monomial->factorssize);
6882 
6883  BMScopyMemoryArray(&monomial->childidxs[monomial->nfactors], childidxs, nfactors); /*lint !e866*/
6884  BMScopyMemoryArray(&monomial->exponents[monomial->nfactors], exponents, nfactors); /*lint !e866*/
6885 
6886  monomial->nfactors += nfactors;
6887  monomial->sorted = (monomial->nfactors <= 1);
6888 
6889  return SCIP_OKAY;
6890 }
6891 
6892 /** multiplies a monomial with a monomial */
6894  BMS_BLKMEM* blkmem, /**< block memory */
6895  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6896  SCIP_EXPRDATA_MONOMIAL* factor, /**< factor monomial */
6897  int* childmap /**< map to apply to children in factor, or NULL for 1:1 */
6898  )
6899 {
6900  assert(monomial != NULL);
6901  assert(factor != NULL);
6902 
6903  if( factor->coef == 0.0 )
6904  {
6905  monomial->nfactors = 0;
6906  monomial->coef = 0.0;
6907  return SCIP_OKAY;
6908  }
6909 
6910  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, factor->nfactors, factor->childidxs, factor->exponents) );
6911 
6912  if( childmap != NULL )
6913  {
6914  int i;
6915  for( i = monomial->nfactors - factor->nfactors; i < monomial->nfactors; ++i )
6916  monomial->childidxs[i] = childmap[monomial->childidxs[i]];
6917  }
6918 
6919  monomial->coef *= factor->coef;
6920 
6921  return SCIP_OKAY;
6922 }
6923 
6924 /** replaces the monomial by a power of the monomial
6925  *
6926  * Allows only integers as exponent.
6927  */
6929  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6930  int exponent /**< integer exponent of power operation */
6931  )
6932 {
6933  int i;
6934 
6935  assert(monomial != NULL);
6936 
6937  if( exponent == 1 )
6938  return;
6939 
6940  if( exponent == 0 )
6941  {
6942  /* x^0 = 1, unless x = 0; 0^0 = 0 */
6943  if( monomial->coef != 0.0 )
6944  monomial->coef = 1.0;
6945  monomial->nfactors = 0;
6946  return;
6947  }
6948 
6949  monomial->coef = pow(monomial->coef, (SCIP_Real)exponent);
6950  for( i = 0; i < monomial->nfactors; ++i )
6951  monomial->exponents[i] *= exponent;
6952 }
6953 
6954 /** merges factors that correspond to the same child by adding exponents
6955  *
6956  * Eliminates factors with exponent between -eps and eps.
6957  */
6959  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6960  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6961  )
6962 {
6963  int i;
6964  int offset;
6965 
6966  assert(monomial != NULL);
6967  assert(eps >= 0.0);
6968 
6969  SCIPexprSortMonomialFactors(monomial);
6970 
6971  /* merge factors with same child index by adding up their exponents
6972  * delete factors with exponent 0.0 */
6973  offset = 0;
6974  i = 0;
6975  while( i + offset < monomial->nfactors )
6976  {
6977  if( offset > 0 )
6978  {
6979  assert(monomial->childidxs[i] == -1);
6980  assert(monomial->childidxs[i+offset] >= 0);
6981  monomial->childidxs[i] = monomial->childidxs[i+offset];
6982  monomial->exponents[i] = monomial->exponents[i+offset];
6983 #ifndef NDEBUG
6984  monomial->childidxs[i+offset] = -1;
6985 #endif
6986  }
6987 
6988  while( i+offset+1 < monomial->nfactors && monomial->childidxs[i] == monomial->childidxs[i+offset+1] )
6989  {
6990  monomial->exponents[i] += monomial->exponents[i+offset+1];
6991 #ifndef NDEBUG
6992  monomial->childidxs[i+offset+1] = -1;
6993 #endif
6994  ++offset;
6995  }
6996 
6997  if( EPSZ(monomial->exponents[i], eps) )
6998  {
6999 #ifndef NDEBUG
7000  monomial->childidxs[i] = -1;
7001 #endif
7002  ++offset;
7003  continue;
7004  }
7005  else if( EPSISINT(monomial->exponents[i], eps) )
7006  monomial->exponents[i] = EPSROUND(monomial->exponents[i], eps);
7007 
7008  ++i;
7009  }
7010 
7011 #ifndef NDEBUG
7012  for( ; i < monomial->nfactors; ++i )
7013  assert(monomial->childidxs[i] == -1);
7014 #endif
7015 
7016  monomial->nfactors -= offset;
7017 
7018  if( EPSEQ(monomial->coef, 1.0, eps) )
7019  monomial->coef = 1.0;
7020  else if( EPSEQ(monomial->coef, -1.0, eps) )
7021  monomial->coef = -1.0;
7022 }
7023 
7024 /** ensures that monomials of a polynomial are sorted */
7026  SCIP_EXPR* expr /**< polynomial expression */
7027  )
7028 {
7029  assert(expr != NULL);
7030  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
7031  assert(expr->data.data != NULL);
7032 
7034 }
7035 
7036 /** creates a monomial */
7038  BMS_BLKMEM* blkmem, /**< block memory */
7039  SCIP_EXPRDATA_MONOMIAL** monomial, /**< buffer where to store pointer to new monomial */
7040  SCIP_Real coef, /**< coefficient of monomial */
7041  int nfactors, /**< number of factors in monomial */
7042  int* childidxs, /**< indices of children corresponding to factors, or NULL if identity */
7043  SCIP_Real* exponents /**< exponent in each factor, or NULL if all 1.0 */
7044  )
7045 {
7046  assert(blkmem != NULL);
7047  assert(monomial != NULL);
7048 
7049  SCIP_ALLOC( BMSallocBlockMemory(blkmem, monomial) );
7050 
7051  (*monomial)->coef = coef;
7052  (*monomial)->nfactors = nfactors;
7053  (*monomial)->factorssize = nfactors;
7054  (*monomial)->sorted = (nfactors <= 1);
7055 
7056  if( nfactors > 0 )
7057  {
7058  if( childidxs != NULL )
7059  {
7060  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->childidxs, childidxs, nfactors) );
7061  }
7062  else
7063  {
7064  int i;
7065 
7066  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->childidxs, nfactors) );
7067  for( i = 0; i < nfactors; ++i )
7068  (*monomial)->childidxs[i] = i;
7069  }
7070 
7071  if( exponents != NULL )
7072  {
7073  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->exponents, exponents, nfactors) );
7074  }
7075  else
7076  {
7077  int i;
7078 
7079  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->exponents, nfactors) );
7080  for( i = 0; i < nfactors; ++i )
7081  (*monomial)->exponents[i] = 1.0;
7082  }
7083  }
7084  else
7085  {
7086  (*monomial)->childidxs = NULL;
7087  (*monomial)->exponents = NULL;
7088  }
7089 
7090  return SCIP_OKAY;
7091 }
7092 
7093 /** frees a monomial */
7095  BMS_BLKMEM* blkmem, /**< block memory */
7096  SCIP_EXPRDATA_MONOMIAL** monomial /**< pointer to monomial that should be freed */
7097  )
7098 {
7099  assert(blkmem != NULL);
7100  assert( monomial != NULL);
7101  assert(*monomial != NULL);
7102 
7103  if( (*monomial)->factorssize > 0 )
7104  {
7105  assert((*monomial)->childidxs != NULL);
7106  assert((*monomial)->exponents != NULL);
7107 
7108  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->childidxs, (*monomial)->factorssize);
7109  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->exponents, (*monomial)->factorssize);
7110  }
7111  assert((*monomial)->childidxs == NULL);
7112  assert((*monomial)->exponents == NULL);
7113 
7114  BMSfreeBlockMemory(blkmem, monomial);
7115 }
7116 
7117 /** ensures that factors in a monomial are sorted */
7119  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
7120  )
7121 {
7122  assert(monomial != NULL);
7123 
7124  if( monomial->sorted )
7125  return;
7126 
7127  if( monomial->nfactors > 0 )
7128  SCIPsortIntReal(monomial->childidxs, monomial->exponents, monomial->nfactors);
7129 
7130  monomial->sorted = TRUE;
7131 }
7132 
7133 /** finds a factor corresponding to a given child index in a monomial
7134  *
7135  * Note that if the factors have not been merged, the position of some factor corresponding to a given child is given.
7136  * Returns TRUE if a factor is found, FALSE if not.
7137  */
7139  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
7140  int childidx, /**< index of the child which factor to search for */
7141  int* pos /**< buffer to store position of factor */
7142  )
7143 {
7144  assert(monomial != NULL);
7145 
7146  if( monomial->nfactors == 0 )
7147  return FALSE;
7148 
7149  SCIPexprSortMonomialFactors(monomial);
7150 
7151  return SCIPsortedvecFindInt(monomial->childidxs, childidx, monomial->nfactors, pos);
7152 }
7153 
7154 /** creates a user expression */
7156  BMS_BLKMEM* blkmem, /**< block memory data structure */
7157  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
7158  int nchildren, /**< number of children */
7159  SCIP_EXPR** children, /**< children of expression */
7160  SCIP_USEREXPRDATA* data, /**< user data for expression, expression assumes ownership */
7161  SCIP_EXPRINTCAPABILITY evalcapability, /**< capability of evaluation functions (partially redundant, currently) */
7162  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
7163  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function, or NULL if not implemented */
7164  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
7165  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function, or NULL if not implemented */
7166  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
7167  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
7168  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
7169  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
7170  )
7171 {
7172  SCIP_EXPROPDATA opdata;
7173  SCIP_EXPRDATA_USER* userexprdata;
7174  SCIP_EXPR** childrencopy;
7175 
7176  assert(blkmem != NULL);
7177  assert(expr != NULL);
7178  assert(eval != NULL);
7179  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
7180  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
7181  assert(curv != NULL);
7182  assert(copydata != NULL || data == NULL);
7183  assert(freedata != NULL || data == NULL);
7184 
7185  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &userexprdata) );
7186 
7187  userexprdata->userdata = data;
7188  userexprdata->evalcapability = evalcapability;
7189  userexprdata->eval = eval;
7190  userexprdata->inteval = inteval;
7191  userexprdata->curv = curv;
7192  userexprdata->prop = prop;
7193  userexprdata->estimate = estimate;
7194  userexprdata->copydata = copydata;
7195  userexprdata->freedata = freedata;
7196  userexprdata->print = print;
7197 
7198  opdata.data = (void*) userexprdata;
7199 
7200  if( nchildren == 0 )
7201  {
7202  SCIP_CALL( exprCreate(blkmem, expr, SCIP_EXPR_USER, 0, NULL, opdata) );
7203  return SCIP_OKAY;
7204  }
7205  assert(children != NULL);
7206 
7207  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
7208 
7209  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_USER, nchildren, childrencopy, opdata) );
7210 
7211  return SCIP_OKAY;
7212 }
7213 
7214 /** indicates whether the expression contains a SCIP_EXPR_PARAM */
7216  SCIP_EXPR* expr /**< expression */
7217  )
7218 {
7219  int i;
7220 
7221  assert(expr != NULL);
7222 
7223  if( expr->op == SCIP_EXPR_PARAM )
7224  return TRUE;
7225 
7226  for( i = 0; i < expr->nchildren; ++i )
7227  if( SCIPexprHasParam(expr->children[i]) )
7228  return TRUE;
7229 
7230  return FALSE;
7231 }
7232 
7233 /** gets maximal degree of expression, or SCIP_EXPR_DEGREEINFINITY if not a polynomial */
7235  SCIP_EXPR* expr, /**< expression */
7236  int* maxdegree /**< buffer to store maximal degree */
7237  )
7238 {
7239  int child1;
7240  int child2;
7241 
7242  assert(expr != NULL);
7243  assert(maxdegree != NULL);
7244 
7245  switch( expr->op )
7246  {
7247  case SCIP_EXPR_VARIDX:
7248  *maxdegree = 1;
7249  break;
7250 
7251  case SCIP_EXPR_CONST:
7252  case SCIP_EXPR_PARAM:
7253  *maxdegree = 0;
7254  break;
7255 
7256  case SCIP_EXPR_PLUS:
7257  case SCIP_EXPR_MINUS:
7258  {
7259  assert(expr->children[0] != NULL);
7260  assert(expr->children[1] != NULL);
7261 
7262  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7263  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7264 
7265  *maxdegree = MAX(child1, child2);
7266  break;
7267  }
7268 
7269  case SCIP_EXPR_MUL:
7270  {
7271  assert(expr->children[0] != NULL);
7272  assert(expr->children[1] != NULL);
7273 
7274  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7275  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7276 
7277  *maxdegree = child1 + child2;
7278  break;
7279  }
7280 
7281  case SCIP_EXPR_DIV:
7282  {
7283  assert(expr->children[0] != NULL);
7284  assert(expr->children[1] != NULL);
7285 
7286  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7287  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7288 
7289  /* if not division by constant, then it is not a polynomial */
7290  *maxdegree = (child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : child1;
7291  break;
7292  }
7293 
7294  case SCIP_EXPR_SQUARE:
7295  {
7296  assert(expr->children[0] != NULL);
7297 
7298  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7299 
7300  *maxdegree = 2 * child1;
7301  break;
7302  }
7303 
7304  case SCIP_EXPR_SQRT:
7305  {
7306  assert(expr->children[0] != NULL);
7307 
7308  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7309 
7310  /* if not squareroot of constant, then no polynomial */
7311  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7312  break;
7313  }
7314 
7315  case SCIP_EXPR_REALPOWER:
7316  {
7317  assert(expr->children[0] != NULL);
7318 
7319  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7320 
7321  /* constant ^ constant has degree 0 */
7322  if( child1 == 0 )
7323  {
7324  *maxdegree = 0;
7325  break;
7326  }
7327 
7328  /* non-polynomial ^ constant is not a polynomial */
7329  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7330  {
7331  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7332  break;
7333  }
7334 
7335  /* so it is polynomial ^ constant
7336  * let's see whether the constant is integral */
7337 
7338  if( expr->data.dbl == 0.0 ) /* polynomial ^ 0 == 0 */
7339  *maxdegree = 0;
7340  else if( expr->data.dbl > 0.0 && (int)expr->data.dbl == expr->data.dbl ) /* natural exponent gives polynomial again */ /*lint !e777*/
7341  *maxdegree = child1 * (int)expr->data.dbl;
7342  else /* negative or nonintegral exponent does not give polynomial */
7343  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7344 
7345  break;
7346  }
7347 
7348  case SCIP_EXPR_INTPOWER:
7349  {
7350  assert(expr->children[0] != NULL);
7351 
7352  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7353 
7354  /* constant ^ integer or something ^ 0 has degree 0 */
7355  if( child1 == 0 || expr->data.intval == 0 )
7356  {
7357  *maxdegree = 0;
7358  break;
7359  }
7360 
7361  /* non-polynomial ^ integer or something ^ negative is not a polynomial */
7362  if( child1 >= SCIP_EXPR_DEGREEINFINITY || expr->data.intval < 0 )
7363  {
7364  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7365  break;
7366  }
7367 
7368  /* so it is polynomial ^ natural, which gives a polynomial again */
7369  *maxdegree = child1 * expr->data.intval;
7370 
7371  break;
7372  }
7373 
7374  case SCIP_EXPR_SIGNPOWER:
7375  {
7376  assert(expr->children[0] != NULL);
7377 
7378  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7379 
7380  /* if child is not constant, then it is no polynomial */
7381  *maxdegree = child1 != 0 ? SCIP_EXPR_DEGREEINFINITY : 0;
7382  break;
7383  }
7384 
7385  case SCIP_EXPR_EXP:
7386  case SCIP_EXPR_LOG:
7387  case SCIP_EXPR_SIN:
7388  case SCIP_EXPR_COS:
7389  case SCIP_EXPR_TAN:
7390  /* case SCIP_EXPR_ERF: */
7391  /* case SCIP_EXPR_ERFI: */
7392  case SCIP_EXPR_ABS:
7393  case SCIP_EXPR_SIGN:
7394  case SCIP_EXPR_USER:
7395  {
7396  assert(expr->children[0] != NULL);
7397 
7398  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7399 
7400  /* if argument is not a constant, then no polynomial, otherwise it is a constant */
7401  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7402  break;
7403  }
7404 
7405  case SCIP_EXPR_MIN:
7406  case SCIP_EXPR_MAX:
7407  {
7408  assert(expr->children[0] != NULL);
7409  assert(expr->children[1] != NULL);
7410 
7411  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7412  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7413 
7414  /* if any of the operands is not constant, then it is no polynomial */
7415  *maxdegree = (child1 != 0 || child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7416  break;
7417  }
7418 
7419  case SCIP_EXPR_SUM:
7420  case SCIP_EXPR_LINEAR:
7421  {
7422  int i;
7423 
7424  *maxdegree = 0;
7425  for( i = 0; i < expr->nchildren && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7426  {
7427  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7428  if( child1 > *maxdegree )
7429  *maxdegree = child1;
7430  }
7431 
7432  break;
7433  }
7434 
7435  case SCIP_EXPR_PRODUCT:
7436  {
7437  int i;
7438 
7439  *maxdegree = 0;
7440  for( i = 0; i < expr->nchildren; ++i )
7441  {
7442  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7443  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7444  {
7445  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7446  break;
7447  }
7448  *maxdegree += child1;
7449  }
7450 
7451  break;
7452  }
7453 
7454  case SCIP_EXPR_QUADRATIC:
7455  {
7456  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7457  int childidx;
7458  int quadidx;
7459 
7460  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7461 
7462  /* make sure quadratic elements are sorted */
7463  quadraticdataSort(quadraticdata);
7464 
7465  *maxdegree = 0;
7466  quadidx = 0;
7467  for( childidx = 0; childidx < expr->nchildren; ++childidx )
7468  {
7469  /* if no linear or no quadratic coefficient with current child on first position, then nothing to do */
7470  if( (quadraticdata->lincoefs == NULL || quadraticdata->lincoefs[childidx] == 0.0) &&
7471  (quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 > childidx) )
7472  continue;
7473 
7474  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[childidx], &child1) );
7475  if( child1 == SCIP_EXPR_DEGREEINFINITY )
7476  {
7477  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7478  break;
7479  }
7480 
7481  while( quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 == childidx )
7482  {
7483  if( quadraticdata->quadelems[quadidx].idx2 == childidx )
7484  {
7485  /* square term */
7486  if( 2*child1 > *maxdegree )
7487  *maxdegree = 2*child1;
7488  }
7489  else
7490  {
7491  /* bilinear term */
7492  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[quadraticdata->quadelems[quadidx].idx2], &child2) );
7493  if( child2 == SCIP_EXPR_DEGREEINFINITY )
7494  {
7495  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7496  break;
7497  }
7498  if( child1 + child2 > *maxdegree )
7499  *maxdegree = child1 + child2;
7500  }
7501  ++quadidx;
7502  }
7503  if( *maxdegree == SCIP_EXPR_DEGREEINFINITY )
7504  break;
7505  }
7506 
7507  break;
7508  }
7509 
7510  case SCIP_EXPR_POLYNOMIAL:
7511  {
7512  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7513  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7514  int monomialdegree;
7515  int i;
7516  int j;
7517 
7518  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7519 
7520  *maxdegree = 0;
7521  for( i = 0; i < polynomialdata->nmonomials && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7522  {
7523  monomialdata = polynomialdata->monomials[i];
7524  assert(monomialdata != NULL);
7525 
7526  /* compute degree of monomial = sum of degree of factors */
7527  monomialdegree = 0;
7528  for( j = 0; j < monomialdata->nfactors; ++j )
7529  {
7530  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[monomialdata->childidxs[j]], &child1) );
7531 
7532  /* if the exponent of the factor is not a natural number and the child is not constant (degree 0),
7533  * then we report that we are not really a polynomial */
7534  if( child1 != 0 && (monomialdata->exponents[j] < 0.0 || (int)monomialdata->exponents[j] != monomialdata->exponents[j]) )
7535  {
7536  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7537  break;
7538  }
7539 
7540  monomialdegree += child1 * (int)monomialdata->exponents[j];
7541  }
7542 
7543  if( monomialdegree > *maxdegree )
7544  *maxdegree = monomialdegree;
7545  }
7546 
7547  break;
7548  }
7549 
7550  case SCIP_EXPR_LAST:
7551  SCIPABORT();
7552  break;
7553  }
7554 
7555  return SCIP_OKAY;
7556 }
7557 
7558 /** counts usage of variables in expression */
7560  SCIP_EXPR* expr, /**< expression to update */
7561  int* varsusage /**< array with counters of variable usage */
7562  )
7563 {
7564  int i;
7565 
7566  assert(expr != NULL);
7567  assert(varsusage != NULL);
7568 
7569  if( expr->op == SCIP_EXPR_VARIDX )
7570  {
7571  ++varsusage[expr->data.intval];
7572  }
7573 
7574  for( i = 0; i < expr->nchildren; ++i )
7575  SCIPexprGetVarsUsage(expr->children[i], varsusage);
7576 }
7577 
7578 /** compares whether two expressions are the same
7579  *
7580  * Inconclusive, i.e., may give FALSE even if expressions are equivalent (x*y != y*x).
7581  */
7583  SCIP_EXPR* expr1, /**< first expression */
7584  SCIP_EXPR* expr2, /**< second expression */
7585  SCIP_Real eps /**< threshold under which numbers are assumed to be zero */
7586  )
7587 {
7588  assert(expr1 != NULL);
7589  assert(expr2 != NULL);
7590 
7591  if( expr1 == expr2 )
7592  return TRUE;
7593 
7594  if( expr1->op != expr2->op )
7595  return FALSE;
7596 
7597  switch( expr1->op )
7598  {
7599  case SCIP_EXPR_VARIDX:
7600  case SCIP_EXPR_PARAM:
7601  return expr1->data.intval == expr2->data.intval;
7602 
7603  case SCIP_EXPR_CONST:
7604  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps);
7605 
7606  /* operands with two children */
7607  case SCIP_EXPR_PLUS :
7608  case SCIP_EXPR_MINUS :
7609  case SCIP_EXPR_MUL :
7610  case SCIP_EXPR_DIV :
7611  case SCIP_EXPR_MIN :
7612  case SCIP_EXPR_MAX :
7613  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps) && SCIPexprAreEqual(expr1->children[1], expr2->children[1], eps);
7614 
7615  /* operands with one child */
7616  case SCIP_EXPR_SQUARE:
7617  case SCIP_EXPR_SQRT :
7618  case SCIP_EXPR_EXP :
7619  case SCIP_EXPR_LOG :
7620  case SCIP_EXPR_SIN :
7621  case SCIP_EXPR_COS :
7622  case SCIP_EXPR_TAN :
7623  /* case SCIP_EXPR_ERF : */
7624  /* case SCIP_EXPR_ERFI : */
7625  case SCIP_EXPR_ABS :
7626  case SCIP_EXPR_SIGN :
7627  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7628 
7629  case SCIP_EXPR_REALPOWER:
7630  case SCIP_EXPR_SIGNPOWER:
7631  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps) && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7632 
7633  case SCIP_EXPR_INTPOWER:
7634  return expr1->data.intval == expr2->data.intval && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7635 
7636  /* complex operands */
7637  case SCIP_EXPR_SUM :
7638  case SCIP_EXPR_PRODUCT:
7639  {
7640  int i;
7641 
7642  /* @todo sort children and have sorted flag in data? */
7643 
7644  if( expr1->nchildren != expr2->nchildren )
7645  return FALSE;
7646 
7647  for( i = 0; i < expr1->nchildren; ++i )
7648  {
7649  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7650  return FALSE;
7651  }
7652 
7653  return TRUE;
7654  }
7655 
7656  case SCIP_EXPR_LINEAR :
7657  {
7658  SCIP_Real* data1;
7659  SCIP_Real* data2;
7660  int i;
7661 
7662  /* @todo sort children and have sorted flag in data? */
7663 
7664  if( expr1->nchildren != expr2->nchildren )
7665  return FALSE;
7666 
7667  data1 = (SCIP_Real*)expr1->data.data;
7668  data2 = (SCIP_Real*)expr2->data.data;
7669 
7670  /* check if constant and coefficients are equal */
7671  for( i = 0; i < expr1->nchildren + 1; ++i )
7672  if( !EPSEQ(data1[i], data2[i], eps) )
7673  return FALSE;
7674 
7675  /* check if children are equal */
7676  for( i = 0; i < expr1->nchildren; ++i )
7677  {
7678  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7679  return FALSE;
7680  }
7681 
7682  return TRUE;
7683  }
7684 
7685  case SCIP_EXPR_QUADRATIC:
7686  {
7687  SCIP_EXPRDATA_QUADRATIC* data1;
7688  SCIP_EXPRDATA_QUADRATIC* data2;
7689  int i;
7690 
7691  if( expr1->nchildren != expr2->nchildren )
7692  return FALSE;
7693 
7694  data1 = (SCIP_EXPRDATA_QUADRATIC*)expr1->data.data;
7695  data2 = (SCIP_EXPRDATA_QUADRATIC*)expr2->data.data;
7696 
7697  if( data1->nquadelems != data2->nquadelems )
7698  return FALSE;
7699 
7700  if( !EPSEQ(data1->constant, data2->constant, eps) )
7701  return FALSE;
7702 
7703  /* check if linear part is equal */
7704  if( data1->lincoefs != NULL || data2->lincoefs != NULL )
7705  for( i = 0; i < expr1->nchildren; ++i )
7706  {
7707  if( data1->lincoefs == NULL )
7708  {
7709  if( !EPSZ(data2->lincoefs[i], eps) )
7710  return FALSE;
7711  }
7712  else if( data2->lincoefs == NULL )
7713  {
7714  if( !EPSZ(data1->lincoefs[i], eps) )
7715  return FALSE;
7716  }
7717  else if( !EPSEQ(data1->lincoefs[i], data2->lincoefs[i], eps) )
7718  return FALSE;
7719  }
7720 
7721  SCIPexprSortQuadElems(expr1);
7722  SCIPexprSortQuadElems(expr2);
7723 
7724  /* check if quadratic elements are equal */
7725  for( i = 0; i < data1->nquadelems; ++i )
7726  if( data1->quadelems[i].idx1 != data2->quadelems[i].idx1 ||
7727  data1->quadelems[i].idx2 != data2->quadelems[i].idx2 ||
7728  !EPSEQ(data1->quadelems[i].coef, data2->quadelems[i].coef, eps) )
7729  return FALSE;
7730 
7731  /* check if children are equal */
7732  for( i = 0; i < expr1->nchildren; ++i )
7733  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7734  return FALSE;
7735 
7736  return TRUE;
7737  }
7738 
7739  case SCIP_EXPR_POLYNOMIAL:
7740  {
7741  SCIP_EXPRDATA_POLYNOMIAL* data1;
7742  SCIP_EXPRDATA_POLYNOMIAL* data2;
7743  int i;
7744 
7745  if( expr1->nchildren != expr2->nchildren )
7746  return FALSE;
7747 
7748  data1 = (SCIP_EXPRDATA_POLYNOMIAL*)expr1->data.data;
7749  data2 = (SCIP_EXPRDATA_POLYNOMIAL*)expr2->data.data;
7750 
7751  if( data1->nmonomials != data2->nmonomials )
7752  return FALSE;
7753 
7754  if( !EPSEQ(data1->constant, data2->constant, eps) )
7755  return FALSE;
7756 
7757  /* make sure polynomials are sorted */
7758  SCIPexprSortMonomials(expr1);
7759  SCIPexprSortMonomials(expr2);
7760 
7761  /* check if monomials are equal */
7762  for( i = 0; i < data1->nmonomials; ++i )
7763  {
7764  if( !SCIPexprAreMonomialsEqual(data1->monomials[i], data2->monomials[i], eps) )
7765  return FALSE;
7766  }
7767 
7768  /* check if children are equal */
7769  for( i = 0; i < expr1->nchildren; ++i )
7770  {
7771  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7772  return FALSE;
7773  }
7774 
7775  return TRUE;
7776  }
7777 
7778  case SCIP_EXPR_USER:
7779  {
7780  /* @todo could implement this via another user callback */
7781  return FALSE;
7782  }
7783 
7784  case SCIP_EXPR_LAST:
7785  break;
7786  }
7787 
7788  SCIPerrorMessage("this should never happen\n");
7789  SCIPABORT();
7790  return FALSE; /*lint !e527*/
7791 }
7792 
7793 /** aims at simplifying an expression and splitting of a linear expression
7794  *
7795  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
7796  */
7798  BMS_BLKMEM* blkmem, /**< block memory data structure */
7799  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7800  SCIP_EXPR* expr, /**< expression */
7801  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
7802  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
7803  int nvars, /**< number of variables in expression */
7804  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
7805  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
7806  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
7807  )
7808 {
7809  assert(blkmem != NULL);
7810  assert(expr != NULL);
7811  assert(eps >= 0.0);
7812 
7813  SCIPdebugMessage("simplify expression: ");
7814  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7815  SCIPdebugPrintf("\n");
7816 
7818 
7819  SCIPdebugMessage("converted to polynomials: ");
7820  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7821  SCIPdebugPrintf("\n");
7822 
7823  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr, eps, maxexpansionexponent) );
7824 
7825  SCIPdebugMessage("polynomials flattened: ");
7826  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7827  SCIPdebugPrintf("\n");
7828 
7829  if( nlinvars != NULL )
7830  {
7831  /* separate linear part from root polynomial */
7832  SCIP_CALL( exprsimplifySeparateLinearFromPolynomial(blkmem, expr, eps, nvars, nlinvars, linidxs, lincoefs) );
7833 
7834  SCIPdebugMessage("separated linear part: ");
7835  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7836  SCIPdebugPrintf("\n");
7837  }
7838 
7840 
7841  SCIPdebugMessage("converted back from polynomials: ");
7842  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7843  SCIPdebugPrintf("\n");
7844 
7845  return SCIP_OKAY;
7846 }
7847 
7848 /** evaluates an expression w.r.t. given values for children expressions */
7850  SCIP_EXPR* expr, /**< expression */
7851  SCIP_Real* argvals, /**< values for children, can be NULL if the expression has no children */
7852  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression operand is not a variable */
7853  SCIP_Real* param, /**< values for parameters, can be NULL if the expression operand is not a parameter */
7854  SCIP_Real* val /**< buffer to store value */
7855  )
7856 {
7857  assert(expr != NULL);
7858  assert(argvals != NULL || expr->nchildren == 0);
7859 
7860  /* evaluate this expression */
7861  assert( exprOpTable[expr->op].eval != NULL );
7862  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, argvals, varvals, param, val) );
7863 
7864  return SCIP_OKAY;
7865 }
7866 
7867 /** evaluates an expression w.r.t. a point */
7869  SCIP_EXPR* expr, /**< expression */
7870  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression is constant */
7871  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7872  SCIP_Real* val /**< buffer to store value */
7873  )
7874 {
7875  int i;
7877  SCIP_Real* buf;
7878 
7879  /* if many children, get large enough memory to store argument values */
7881  {
7882  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7883  }
7884  else
7885  {
7886  buf = staticbuf;
7887  }
7888 
7889  /* evaluate children */
7890  for( i = 0; i < expr->nchildren; ++i )
7891  {
7892  SCIP_CALL( SCIPexprEval(expr->children[i], varvals, param, &buf[i]) ); /*lint !e644*/
7893  }
7894 
7895  /* evaluate this expression */
7896  assert( exprOpTable[expr->op].eval != NULL );
7897  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, buf, varvals, param, val) );
7898 
7899  /* free memory, if allocated before */
7900  if( staticbuf != buf )
7901  {
7902  BMSfreeMemoryArray(&buf);
7903  }
7904 
7905  return SCIP_OKAY;
7906 }
7907 
7908 /** evaluates an expression w.r.t. given interval values for children expressions */
7910  SCIP_EXPR* expr, /**< expression */
7911  SCIP_Real infinity, /**< value to use for infinity */
7912  SCIP_INTERVAL* argvals, /**< interval values for children, can be NULL if the expression has no children */
7913  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7914  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7915  SCIP_INTERVAL* val /**< buffer to store value */
7916  )
7917 {
7918  assert(expr != NULL);
7919  assert(argvals != NULL || expr->nchildren == 0);
7920 
7921  /* evaluate this expression */
7922  assert( exprOpTable[expr->op].inteval != NULL );
7923  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, argvals, varvals, param, val) );
7924 
7925  return SCIP_OKAY;
7926 }
7927 
7928 /** evaluates an expression w.r.t. an interval */
7930  SCIP_EXPR* expr, /**< expression */
7931  SCIP_Real infinity, /**< value to use for infinity */
7932  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7933  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7934  SCIP_INTERVAL* val /**< buffer to store value */
7935  )
7936 {
7937  int i;
7939  SCIP_INTERVAL* buf;
7940 
7941  /* if many children, get large enough memory to store argument values */
7943  {
7944  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7945  }
7946  else
7947  {
7948  buf = staticbuf;
7949  }
7950 
7951  /* evaluate children */
7952  for( i = 0; i < expr->nchildren; ++i )
7953  {
7954  SCIP_CALL( SCIPexprEvalInt(expr->children[i], infinity, varvals, param, &buf[i]) ); /*lint !e644*/
7955  }
7956 
7957  /* evaluate this expression */
7958  assert( exprOpTable[expr->op].inteval != NULL );
7959  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, buf, varvals, param, val) );
7960 
7961  /* free memory, if allocated before */
7962  if( staticbuf != buf )
7963  {
7964  BMSfreeMemoryArray(&buf);
7965  }
7966 
7967  return SCIP_OKAY;
7968 }
7969 
7970 /** evaluates a user expression w.r.t. given values for children expressions */
7972  SCIP_EXPR* expr, /**< expression */
7973  SCIP_Real* argvals, /**< values for children */
7974  SCIP_Real* val, /**< buffer to store function value */
7975  SCIP_Real* gradient, /**< buffer to store gradient values, or NULL if not requested */
7976  SCIP_Real* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7977  )
7978 {
7979  SCIP_EXPRDATA_USER* exprdata;
7980 
7981  assert(expr != NULL);
7982  assert(expr->op == SCIP_EXPR_USER);
7983  assert(argvals != NULL || expr->nchildren == 0);
7984 
7985  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7986  assert(exprdata->eval != NULL);
7987 
7988  SCIP_CALL( exprdata->eval(exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7989 
7990  return SCIP_OKAY;
7991 }
7992 
7993 /** evaluates a user expression w.r.t. an interval */
7995  SCIP_EXPR* expr, /**< expression */
7996  SCIP_Real infinity, /**< value to use for infinity */
7997  SCIP_INTERVAL* argvals, /**< values for children */
7998  SCIP_INTERVAL* val, /**< buffer to store value */
7999  SCIP_INTERVAL* gradient, /**< buffer to store gradient values, or NULL if not requested */
8000  SCIP_INTERVAL* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
8001  )
8002 {
8003  SCIP_EXPRDATA_USER* exprdata;
8004 
8005  assert(expr != NULL);
8006  assert(expr->op == SCIP_EXPR_USER);
8007  assert(argvals != NULL || expr->nchildren == 0);
8008 
8009  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8010 
8011  if( exprdata->inteval == NULL )
8012  {
8013  int i;
8014 
8015  for( i = 0; i < expr->nchildren; ++i )
8016  SCIPintervalSetEntire(infinity, &argvals[i]); /*lint !e613*/
8017  }
8018  else
8019  {
8020  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
8021  }
8022 
8023  return SCIP_OKAY;
8024 }
8025 
8026 /** internal curvature check method */
8027 static
8029  SCIP_EXPR* expr, /**< expression to check */
8030  SCIP_Real infinity, /**< value to use for infinity */
8031  SCIP_INTERVAL* varbounds, /**< domains of variables */
8032  SCIP_INTERVAL* childbounds, /**< child bounds buffer array */
8033  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
8034  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8035  SCIP_EXPRCURV* childcurv, /**< buffer array for curvature of children */
8036  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
8037  )
8038 {
8039  int i;
8040 
8041  assert(childbounds != NULL);
8042  assert(childcurv != NULL);
8043 
8044  /* check curvature and compute bounds of children
8045  * constant children can be considered as always linear */
8046  for( i = 0; i < expr->nchildren; ++i )
8047  {
8048  SCIP_CALL( SCIPexprCheckCurvature(expr->children[i], infinity, varbounds, param, &childcurv[i], &childbounds[i]) ); /*lint !e644*/
8049  if( childbounds[i].inf == childbounds[i].sup ) /*lint !e777*/
8050  childcurv[i] = SCIP_EXPRCURV_LINEAR;
8051  }
8052 
8053  /* get curvature and bounds of expr */
8054  assert(exprOpTable[expr->op].curv != NULL);
8055  assert(exprOpTable[expr->op].inteval != NULL);
8056 
8057  SCIP_CALL( exprOpTable[expr->op].curv(infinity, expr->data, expr->nchildren, childbounds, childcurv, curv) );
8058  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, childbounds, varbounds, param, bounds) );
8059 
8060  return SCIP_OKAY;
8061 }
8062 
8063 /** tries to determine the curvature type of an expression w.r.t. given variable domains */
8065  SCIP_EXPR* expr, /**< expression to check */
8066  SCIP_Real infinity, /**< value to use for infinity */
8067  SCIP_INTERVAL* varbounds, /**< domains of variables */
8068  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
8069  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8070  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
8071  )
8072 {
8074  SCIP_INTERVAL* childbounds = NULL;
8076  SCIP_EXPRCURV* childcurv = NULL;
8077  SCIP_RETCODE retcode = SCIP_OKAY;
8078 
8079  assert(expr != NULL);
8080  assert(curv != NULL);
8081  assert(bounds != NULL);
8082 
8083  /* if many children, get large enough memory to store argument values */
8085  {
8086  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, expr->nchildren) );
8087  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, expr->nchildren), TERMINATE );
8088  }
8089  else
8090  {
8091  childbounds = childboundsbuf;
8092  childcurv = childcurvbuf;
8093  }
8094 
8095  retcode = doCheckCurvature(expr, infinity, varbounds, childbounds, param, curv, childcurv, bounds);
8096 
8097 TERMINATE:
8098  /* free memory, if allocated before */
8099  if( childboundsbuf != childbounds )
8100  {
8101  BMSfreeMemoryArrayNull(&childcurv);
8102  BMSfreeMemoryArrayNull(&childbounds);
8103  }
8104 
8105  return retcode;
8106 }
8107 
8108 /** under-/overestimates a user expression w.r.t. to given values and bounds for children expressions */
8110  SCIP_EXPR* expr, /**< expression */
8111  SCIP_Real infinity, /**< value to use for infinity */
8112  SCIP_Real* argvals, /**< values for children */
8113  SCIP_INTERVAL* argbounds, /**< bounds for children */
8114  SCIP_Bool overestimate, /**< whether to overestimate the expression */
8115  SCIP_Real* coeffs, /**< buffer to store the linear coefficients for each child expression that gives a valid under-/overestimator */
8116  SCIP_Real* constant, /**< buffer to store the constant value of the linear under-/overestimator */
8117  SCIP_Bool* success /**< buffer to store whether an estimator was successfully computed */
8118  )
8119 {
8120  SCIP_EXPRDATA_USER* exprdata;
8121 
8122  assert(expr != NULL);
8123  assert(expr->op == SCIP_EXPR_USER);
8124  assert(argvals != NULL || expr->nchildren == 0);
8125  assert(argbounds != NULL || expr->nchildren == 0);
8126 
8127  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8128 
8129  if( exprdata->estimate != NULL )
8130  {
8131  SCIP_CALL( exprdata->estimate(infinity, exprdata->userdata, expr->nchildren, argvals, argbounds, overestimate, coeffs, constant, success ) );
8132  }
8133  else
8134  {
8135  *success = FALSE;
8136  }
8137 
8138  return SCIP_OKAY;
8139 }
8140 
8141 /** substitutes variables (SCIP_EXPR_VARIDX) by expressions
8142  *
8143  * Note that only the children of the given expr are checked!
8144  * A variable with index i is replaced by a copy of substexprs[i], if the latter is not NULL.
8145  * If substexprs[i] == NULL, then the variable expression i is not touched.
8146  */
8148  BMS_BLKMEM* blkmem, /**< block memory data structure */
8149  SCIP_EXPR* expr, /**< expression, which of the children may be replaced */
8150  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8151  )
8152 {
8153  int i;
8154 
8155  assert(blkmem != NULL);
8156  assert(expr != NULL);
8157  assert(substexprs != NULL);
8158 
8159  for( i = 0; i < expr->nchildren; ++i )
8160  {
8161  if( expr->children[i]->op == SCIP_EXPR_VARIDX )
8162  {
8163  int varidx;
8164  varidx = expr->children[i]->data.intval;
8165 
8166  assert(varidx >= 0);
8167  if( substexprs[varidx] != NULL )
8168  {
8169  /* replace child i by copy of substexprs[expr->children[i]->opdata.intval] */
8170  SCIPexprFreeDeep(blkmem, &expr->children[i]);
8171  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[i], substexprs[varidx]) );
8172  }
8173  }
8174  else
8175  {
8176  /* call recursively */
8177  SCIP_CALL( SCIPexprSubstituteVars(blkmem, expr->children[i], substexprs) );
8178  }
8179  }
8180 
8181  return SCIP_OKAY;
8182 }
8183 
8184 /** updates variable indices in expression tree */
8186  SCIP_EXPR* expr, /**< expression to update */
8187  int* newindices /**< new indices of variables */
8188  )
8189 {
8190  int i;
8191 
8192  assert(expr != NULL);
8193  assert(newindices != NULL);
8194 
8195  if( expr->op == SCIP_EXPR_VARIDX )
8196  {
8197  expr->data.intval = newindices[expr->data.intval];
8198  assert(expr->data.intval >= 0);
8199  }
8200 
8201  for( i = 0; i < expr->nchildren; ++i )
8202  SCIPexprReindexVars(expr->children[i], newindices);
8203 }
8204 
8205 /** updates parameter indices in expression tree */
8207  SCIP_EXPR* expr, /**< expression to update */
8208  int* newindices /**< new indices of variables */
8209  )
8210 {
8211  int i;
8212 
8213  assert(expr != NULL);
8214  assert(newindices != NULL);
8215 
8216  if( expr->op == SCIP_EXPR_PARAM )
8217  {
8218  expr->data.intval = newindices[expr->data.intval];
8219  assert(expr->data.intval >= 0);
8220  }
8221 
8222  for( i = 0; i < expr->nchildren; ++i )
8223  SCIPexprReindexParams(expr->children[i], newindices);
8224 }
8225 
8226 /** prints an expression */
8228  SCIP_EXPR* expr, /**< expression */
8229  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8230  FILE* file, /**< file for printing, or NULL for stdout */
8231  const char** varnames, /**< names of variables, or NULL for default names */
8232  const char** paramnames, /**< names of parameters, or NULL for default names */
8233  SCIP_Real* paramvals /**< values of parameters, or NULL for not printing */
8234  )
8235 {
8236  assert( expr != NULL );
8237 
8238  switch( expr->op )
8239  {
8240  /* @Note: 'expr->data.intval' is either between 0 and number of variables-1, if it uses the varnames array, or
8241  * between 0 and number of params in the expression tree, if it uses the paramnames array
8242  * because, here, we cannot get the values above we cannot assert them
8243  */
8244  case SCIP_EXPR_VARIDX:
8245  if( varnames != NULL )
8246  {
8247  assert(varnames[expr->data.intval] != NULL);
8248  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", varnames[expr->data.intval]);
8249  }
8250  else
8251  {
8252  SCIPmessageFPrintInfo(messagehdlr, file, "var%d", expr->data.intval);
8253  }
8254  break;
8255 
8256  case SCIP_EXPR_PARAM:
8257  if( paramnames != NULL )
8258  {
8259  assert(paramnames[expr->data.intval] != NULL);
8260  SCIPmessageFPrintInfo(messagehdlr, file, "%s", paramnames[expr->data.intval]);
8261  }
8262  else
8263  {
8264  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", expr->data.intval );
8265  }
8266  if( paramvals != NULL )
8267  {
8268  SCIPmessageFPrintInfo(messagehdlr, file, "[%g]", paramvals[expr->data.intval] );
8269  }
8270  break;
8271 
8272  case SCIP_EXPR_CONST:
8273  if (expr->data.dbl < 0.0 )
8274  SCIPmessageFPrintInfo(messagehdlr, file, "(%g)", expr->data.dbl );
8275  else
8276  SCIPmessageFPrintInfo(messagehdlr, file, "%g", expr->data.dbl );
8277  break;
8278 
8279  case SCIP_EXPR_PLUS:
8280  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8281  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8282  SCIPmessageFPrintInfo(messagehdlr, file, " + ");
8283  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8284  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8285  break;
8286 
8287  case SCIP_EXPR_MINUS:
8288  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8289  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8290  SCIPmessageFPrintInfo(messagehdlr, file, " - ");
8291  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8292  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8293  break;
8294 
8295  case SCIP_EXPR_MUL:
8296  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8297  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8298  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8299  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8300  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8301  break;
8302 
8303  case SCIP_EXPR_DIV:
8304  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8305  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8306  SCIPmessageFPrintInfo(messagehdlr, file, " / ");
8307  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8308  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8309  break;
8310 
8311  case SCIP_EXPR_REALPOWER:
8312  case SCIP_EXPR_SIGNPOWER:
8313  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8314  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8315  SCIPmessageFPrintInfo(messagehdlr, file, ", %g)", expr->data.dbl);
8316  break;
8317 
8318  case SCIP_EXPR_INTPOWER:
8319  SCIPmessageFPrintInfo(messagehdlr, file, "power(");
8320  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8321  SCIPmessageFPrintInfo(messagehdlr, file, ", %d)", expr->data.intval);
8322  break;
8323 
8324  case SCIP_EXPR_SQUARE:
8325  case SCIP_EXPR_SQRT:
8326  case SCIP_EXPR_EXP:
8327  case SCIP_EXPR_LOG:
8328  case SCIP_EXPR_SIN:
8329  case SCIP_EXPR_COS:
8330  case SCIP_EXPR_TAN:
8331  /* case SCIP_EXPR_ERF: */
8332  /* case SCIP_EXPR_ERFI: */
8333  case SCIP_EXPR_MIN:
8334  case SCIP_EXPR_MAX:
8335  case SCIP_EXPR_ABS:
8336  case SCIP_EXPR_SIGN:
8337  {
8338  int i;
8339 
8340  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8341 
8342  for( i = 0; i < expr->nchildren; ++i )
8343  {
8344  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8345  if( i + 1 < expr->nchildren )
8346  {
8347  SCIPmessageFPrintInfo(messagehdlr, file, ", ");
8348  }
8349  }
8350 
8351  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8352  break;
8353  }
8354 
8355  case SCIP_EXPR_SUM:
8356  case SCIP_EXPR_PRODUCT:
8357  {
8358  switch( expr->nchildren )
8359  {
8360  case 0:
8361  SCIPmessageFPrintInfo(messagehdlr, file, expr->op == SCIP_EXPR_SUM ? "0" : "1");
8362  break;
8363  case 1:
8364  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8365  break;
8366  default:
8367  {
8368  int i;
8369  char opstr[SCIP_MAXSTRLEN];
8370 
8371  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8372  for( i = 0; i < expr->nchildren; ++i )
8373  {
8374  if( i > 0 )
8375  {
8376  (void) SCIPsnprintf(opstr, SCIP_MAXSTRLEN, "%s", expr->op == SCIP_EXPR_SUM ? " + " : " * ");
8377  SCIPmessageFPrintInfo(messagehdlr, file, opstr);
8378  }
8379  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8380  }
8381  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8382  }
8383  }
8384  break;
8385  }
8386 
8387  case SCIP_EXPR_LINEAR:
8388  {
8389  SCIP_Real constant;
8390  int i;
8391 
8392  constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
8393 
8394  if( expr->nchildren == 0 )
8395  {
8396  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", constant);
8397  break;
8398  }
8399 
8400  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8401 
8402  if( constant != 0.0 )
8403  {
8404  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", constant);
8405  }
8406 
8407  for( i = 0; i < expr->nchildren; ++i )
8408  {
8409  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", ((SCIP_Real*)expr->data.data)[i]);
8410  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8411  }
8412 
8413  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8414  break;
8415  }
8416 
8417  case SCIP_EXPR_QUADRATIC:
8418  {
8419  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
8420  int i;
8421 
8422  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
8423  assert(quadraticdata != NULL);
8424 
8425  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8426 
8427  if( quadraticdata->constant != 0.0 )
8428  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->constant);
8429 
8430  if( quadraticdata->lincoefs != NULL )
8431  for( i = 0; i < expr->nchildren; ++i )
8432  {
8433  if( quadraticdata->lincoefs[i] == 0.0 )
8434  continue;
8435  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->lincoefs[i]);
8436  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8437  }
8438 
8439  for( i = 0; i < quadraticdata->nquadelems; ++i )
8440  {
8441  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->quadelems[i].coef);
8442  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
8443  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
8444  {
8445  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
8446  }
8447  else
8448  {
8449  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8450  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
8451  }
8452  }
8453 
8454  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8455  break;
8456  }
8457 
8458  case SCIP_EXPR_POLYNOMIAL:
8459  {
8460  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
8461  SCIP_EXPRDATA_MONOMIAL* monomialdata;
8462  int i;
8463  int j;
8464 
8465  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8466 
8467  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
8468  assert(polynomialdata != NULL);
8469 
8470  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
8471  {
8472  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", polynomialdata->constant);
8473  }
8474 
8475  for( i = 0; i < polynomialdata->nmonomials; ++i )
8476  {
8477  monomialdata = polynomialdata->monomials[i];
8478  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g", monomialdata->coef);
8479 
8480  for( j = 0; j < monomialdata->nfactors; ++j )
8481  {
8482  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8483 
8484  SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
8485  if( monomialdata->exponents[j] < 0.0 )
8486  {
8487  SCIPmessageFPrintInfo(messagehdlr, file, "^(%.15g)", monomialdata->exponents[j]);
8488  }
8489  else if( monomialdata->exponents[j] != 1.0 )
8490  {
8491  SCIPmessageFPrintInfo(messagehdlr, file, "^%.15g", monomialdata->exponents[j]);
8492  }
8493  }
8494  }
8495 
8496  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8497  break;
8498  }
8499 
8500  case SCIP_EXPR_USER:
8501  {
8502  SCIP_EXPRDATA_USER* exprdata;
8503  int i;
8504 
8505  exprdata = (SCIP_EXPRDATA_USER*)expr->data.data;
8506  assert(exprdata != NULL);
8507 
8508  if( exprdata->print != NULL )
8509  {
8510  exprdata->print(exprdata->userdata, messagehdlr, file);
8511  }
8512  else
8513  {
8514  SCIPmessageFPrintInfo(messagehdlr, file, "user");
8515  }
8516 
8517  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8518  for( i = 0; i < expr->nchildren; ++i )
8519  {
8520  if( i > 0 )
8521  {
8522  SCIPmessageFPrintInfo(messagehdlr, file, ",");
8523  }
8524  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8525  }
8526  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8527 
8528  break;
8529  }
8530 
8531  case SCIP_EXPR_LAST:
8532  {
8533  SCIPerrorMessage("invalid expression\n");
8534  SCIPABORT();
8535  }
8536  }
8537 }
8538 
8539 /** parses an expression from a string */
8541  BMS_BLKMEM* blkmem, /**< block memory data structure */
8542  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8543  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
8544  const char* str, /**< pointer to the string to be parsed */
8545  const char* lastchar, /**< pointer to the last char of str that should be parsed */
8546  int* nvars, /**< buffer to store number of variables */
8547  int* varnames, /**< buffer to store variable names, prefixed by index (as int) */
8548  int varnameslength /**< length of the varnames buffer array */
8549  )
8550 {
8551  SCIP_HASHTABLE* vartable;
8552  SCIP_RETCODE retcode;
8553 
8554  assert(blkmem != NULL);
8555  assert(expr != NULL);
8556  assert(str != NULL);
8557  assert(lastchar != NULL);
8558  assert(nvars != NULL);
8559  assert(varnames != NULL);
8560 
8561  *nvars = 0;
8562 
8563  /* create a hash table for variable names and corresponding expression index
8564  * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
8565  */
8566  SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString,
8567  SCIPhashKeyValString, NULL) );
8568 
8569  retcode = exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames,
8570  &varnameslength, vartable, 0);
8571 
8572  SCIPhashtableFree(&vartable);
8573 
8574  return retcode;
8575 }
8576 
8577 
8578 /**@} */
8579 
8580 /**@name Expression tree methods */
8581 /**@{ */
8582 
8583 /* In debug mode, the following methods are implemented as function calls to ensure
8584  * type validity.
8585  * In optimized mode, the methods are implemented as defines to improve performance.
8586  * However, we want to have them in the library anyways, so we have to undef the defines.
8587  */
8588 
8589 #undef SCIPexprtreeGetRoot
8590 #undef SCIPexprtreeGetNVars
8591 #undef SCIPexprtreeGetNParams
8592 #undef SCIPexprtreeGetParamVals
8593 #undef SCIPexprtreeSetParamVal
8594 #undef SCIPexprtreeGetInterpreterData
8595 #undef SCIPexprtreeSetInterpreterData
8596 #undef SCIPexprtreeFreeInterpreterData
8597 #undef SCIPexprtreeHasParam
8598 #undef SCIPexprtreeGetMaxDegree
8599 #undef SCIPexprtreeEval
8600 #undef SCIPexprtreeEvalInt
8601 #undef SCIPexprtreePrint
8602 
8603 /** returns root expression of an expression tree */
8605  SCIP_EXPRTREE* tree /**< expression tree */
8606  )
8607 {
8608  assert(tree != NULL);
8609 
8610  return tree->root;
8611 }
8612 
8613 /** returns number of variables in expression tree */
8615  SCIP_EXPRTREE* tree /**< expression tree */
8616  )
8617 {
8618  assert(tree != NULL);
8619 
8620  return tree->nvars;
8621 }
8622 
8623 /** returns number of parameters in expression tree */
8625  SCIP_EXPRTREE* tree /**< expression tree */
8626  )
8627 {
8628  assert(tree != NULL);
8629 
8630  return tree->nparams;
8631 }
8632 
8633 /** returns values of parameters or NULL if none */
8635  SCIP_EXPRTREE* tree /**< expression tree */
8636  )
8637 {
8638  assert(tree != NULL);
8639 
8640  return tree->params;
8641 }
8642 
8643 /** sets value of a single parameter in expression tree */
8645  SCIP_EXPRTREE* tree, /**< expression tree */
8646  int paramidx, /**< index of parameter */
8647  SCIP_Real paramval /**< new value of parameter */
8648  )
8649 {
8650  assert(tree != NULL);
8651  assert(paramidx >= 0);
8652  assert(paramidx < tree->nparams);
8653  assert(tree->params != NULL);
8654 
8655  tree->params[paramidx] = paramval;
8656 }
8657 
8658 /** gets data of expression tree interpreter, or NULL if not set */
8660  SCIP_EXPRTREE* tree /**< expression tree */
8661  )
8662 {
8663  assert(tree != NULL);
8664 
8665  return tree->interpreterdata;
8666 }
8667 
8668 /** sets data of expression tree interpreter */
8670  SCIP_EXPRTREE* tree, /**< expression tree */
8671  SCIP_EXPRINTDATA* interpreterdata /**< expression interpreter data */
8672  )
8673 {
8674  assert(tree != NULL);
8675  assert(interpreterdata != NULL);
8676  assert(tree->interpreterdata == NULL);
8677 
8678  tree->interpreterdata = interpreterdata;
8679 }
8680 
8681 /** frees data of expression tree interpreter, if any */
8683  SCIP_EXPRTREE* tree /**< expression tree */
8684  )
8685 {
8686  if( tree->interpreterdata != NULL )
8687  {
8689  assert(tree->interpreterdata == NULL);
8690  }
8691 
8692  return SCIP_OKAY;
8693 }
8694 
8695 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
8697  SCIP_EXPRTREE* tree /**< expression tree */
8698  )
8699 {
8700  assert(tree != NULL);
8701 
8702  return SCIPexprHasParam(tree->root);
8703 }
8704 
8705 /** Gives maximal degree of expression in expression tree.
8706  *
8707  * If constant expression, gives 0,
8708  * if linear expression, gives 1,
8709  * if polynomial expression, gives its maximal degree,
8710  * otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8711  */
8713  SCIP_EXPRTREE* tree, /**< expression tree */
8714  int* maxdegree /**< buffer to store maximal degree */
8715  )
8716 {
8717  assert(tree != NULL);
8718 
8719  SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8720 
8721  return SCIP_OKAY;
8722 }
8723 
8724 /** evaluates an expression tree w.r.t. a point */
8726  SCIP_EXPRTREE* tree, /**< expression tree */
8727  SCIP_Real* varvals, /**< values for variables */
8728  SCIP_Real* val /**< buffer to store expression tree value */
8729  )
8730 {
8731  assert(tree != NULL);
8732  assert(varvals != NULL || tree->nvars == 0);
8733  assert(val != NULL);
8734 
8735  SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8736 
8737  return SCIP_OKAY;
8738 }
8739 
8740 /** evaluates an expression tree w.r.t. an interval */
8742  SCIP_EXPRTREE* tree, /**< expression tree */
8743  SCIP_Real infinity, /**< value for infinity */
8744  SCIP_INTERVAL* varvals, /**< intervals for variables */
8745  SCIP_INTERVAL* val /**< buffer to store expression tree value */
8746  )
8747 {
8748  assert(tree != NULL);
8749  assert(varvals != NULL || tree->nvars == 0);
8750  assert(val != NULL);
8751 
8752  SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8753 
8754  return SCIP_OKAY;
8755 }
8756 
8757 /** prints an expression tree */
8759  SCIP_EXPRTREE* tree, /**< expression tree */
8760  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8761  FILE* file, /**< file for printing, or NULL for stdout */
8762  const char** varnames, /**< names of variables, or NULL for default names */
8763  const char** paramnames /**< names of parameters, or NULL for default names */
8764  )
8765 {
8766  assert(tree != NULL);
8767 
8768  SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8769 }
8770 
8771 
8772 /** creates an expression tree */
8774  BMS_BLKMEM* blkmem, /**< block memory data structure */
8775  SCIP_EXPRTREE** tree, /**< buffer to store address of created expression tree */
8776  SCIP_EXPR* root, /**< pointer to root expression, not copied deep !, can be NULL */
8777  int nvars, /**< number of variables in variable mapping */
8778  int nparams, /**< number of parameters in expression */
8779  SCIP_Real* params /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8780  )
8781 {
8782  assert(blkmem != NULL);
8783  assert(tree != NULL);
8784 
8785  SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8786 
8787  (*tree)->blkmem = blkmem;
8788  (*tree)->root = root;
8789  (*tree)->nvars = nvars;
8790  (*tree)->vars = NULL;
8791  (*tree)->nparams = nparams;
8792  (*tree)->interpreterdata = NULL;
8793 
8794  if( params != NULL )
8795  {
8796  assert(nparams > 0);
8797  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8798  }
8799  else if( nparams > 0 )
8800  {
8801  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8802  BMSclearMemoryArray((*tree)->params, nparams);
8803  }
8804  else
8805  {
8806  assert(nparams == 0);
8807  (*tree)->params = NULL;
8808  }
8809 
8810  return SCIP_OKAY;
8811 }
8812 
8813 /** copies an expression tree */
8815  BMS_BLKMEM* blkmem, /**< block memory that should be used in new expression tree */
8816  SCIP_EXPRTREE** targettree, /**< buffer to store address of copied expression tree */
8817  SCIP_EXPRTREE* sourcetree /**< expression tree to copy */
8818  )
8819 {
8820  assert(blkmem != NULL);
8821  assert(targettree != NULL);
8822  assert(sourcetree != NULL);
8823 
8824  /* copy expression tree "header" */
8825  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8826 
8827  /* we may have a new block memory; and we do not want to keep the others interpreter data */
8828  (*targettree)->blkmem = blkmem;
8829  (*targettree)->interpreterdata = NULL;
8830 
8831  /* copy variables, if any */
8832  if( sourcetree->vars != NULL )
8833  {
8834  assert(sourcetree->nvars > 0);
8835 
8836  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8837  }
8838 
8839  /* copy parameters, if any */
8840  if( sourcetree->params != NULL )
8841  {
8842  assert(sourcetree->nparams > 0);
8843 
8844  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8845  }
8846 
8847  /* copy expression */
8848  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8849 
8850  return SCIP_OKAY;
8851 }
8852 
8853 /** frees an expression tree */
8855  SCIP_EXPRTREE** tree /**< pointer to expression tree that is freed */
8856  )
8857 {
8858  assert( tree != NULL);
8859  assert(*tree != NULL);
8860 
8862 
8863  if( (*tree)->root != NULL )
8864  {
8865  SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8866  assert((*tree)->root == NULL);
8867  }
8868 
8869  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars, (*tree)->nvars );
8870  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8871 
8872  BMSfreeBlockMemory((*tree)->blkmem, tree);
8873 
8874  return SCIP_OKAY;
8875 }
8876 
8877 /** sets number and values of all parameters in expression tree */
8879  SCIP_EXPRTREE* tree, /**< expression tree */
8880  int nparams, /**< number of parameters */
8881  SCIP_Real* paramvals /**< values of parameters, can be NULL if nparams == 0 */
8882  )
8883 {
8884  assert(tree != NULL);
8885  assert(paramvals != NULL || nparams == 0);
8886 
8887  if( nparams == 0 )
8888  {
8889  BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8890  }
8891  else if( tree->params != NULL )
8892  {
8893  SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8894  BMScopyMemoryArray(tree->params, paramvals, nparams);
8895  }
8896  else
8897  {
8898  SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8899  }
8900 
8901  tree->nparams = nparams;
8902  assert(tree->params != NULL || tree->nparams == 0);
8903 
8904  return SCIP_OKAY;
8905 }
8906 
8907 
8908 /** gives the number of usages for each variable in the expression tree */
8910  SCIP_EXPRTREE* tree, /**< expression tree */
8911  int* varsusage /**< array where to store for each variable how often it is used in the tree */
8912  )
8913 {
8914  assert(tree != NULL);
8915  assert(varsusage != NULL);
8916 
8917  if( tree->nvars == 0 )
8918  return;
8919 
8920  BMSclearMemoryArray(varsusage, tree->nvars);
8921  SCIPexprGetVarsUsage(tree->root, varsusage);
8922 }
8923 
8924 /** aims at simplifying an expression and splitting of a linear expression
8925  *
8926  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
8927  */
8929  SCIP_EXPRTREE* tree, /**< expression tree */
8930  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8931  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
8932  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8933  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8934  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8935  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
8936  )
8937 {
8938 #ifndef NDEBUG
8939  SCIP_RANDNUMGEN* randnumgen;
8940  SCIP_Real* testx;
8941  SCIP_Real testval_before;
8942  SCIP_Real testval_after;
8943  int i;
8944 #endif
8945 
8946  assert(tree != NULL);
8947 
8948 #ifndef NDEBUG
8949  SCIP_CALL( SCIPrandomCreate(&randnumgen, tree->blkmem, 42) );
8950 
8951  SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) ); /*lint !e666*/
8952  for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8953  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
8954  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8955 
8956  SCIPrandomFree(&randnumgen, tree->blkmem);
8957 #endif
8958 
8959  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8960  SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8961 
8962 #ifndef NDEBUG
8963  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8964  if( nlinvars != NULL && testval_before == testval_before ) /*lint !e777*/
8965  for( i = 0; i < *nlinvars; ++i )
8966  testval_after += lincoefs[i] * testx[linidxs[i]];
8967  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
8968  BMSfreeMemoryArray(&testx);
8969 #endif
8970 
8971  /* removing something from the the tree may invalidate the interpreter data */
8972  if( nlinvars != NULL && *nlinvars > 0 )
8974 
8975  return SCIP_OKAY;
8976 }
8977 
8978 /** adds an expression to the root expression of the tree
8979  *
8980  * 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.
8981  * If no root existed yet, then the root is set to the given expression (or a copy of it).
8982  */
8984  SCIP_EXPRTREE* tree, /**< expression tree */
8985  SCIP_EXPR* expr, /**< expression to add to tree */
8986  SCIP_Bool copyexpr /**< whether expression should be copied */
8987  )
8988 {
8989  assert(tree != NULL);
8990 
8991  /* adding something to the tree may invalidate the interpreter data */
8993 
8994  if( copyexpr )
8995  {
8996  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &expr, expr) );
8997  }
8998 
8999  if( tree->root == NULL )
9000  {
9001  tree->root = expr;
9002  }
9003  else
9004  {
9005  SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
9006  }
9007 
9008  return SCIP_OKAY;
9009 }
9010 
9011 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
9013  SCIP_EXPRTREE* tree, /**< expression tree */
9014  SCIP_Real infinity, /**< value for infinity */
9015  SCIP_INTERVAL* varbounds, /**< domains of variables */
9016  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
9017  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression, or NULL if not needed */
9018  )
9019 {
9020  SCIP_INTERVAL exprbounds;
9021 
9022  assert(tree != NULL);
9023 
9024  if( tree->root == NULL )
9025  {
9026  *curv = SCIP_EXPRCURV_LINEAR;
9027 
9028  if( bounds != NULL )
9029  SCIPintervalSet(bounds, 0.0);
9030 
9031  return SCIP_OKAY;
9032  }
9033 
9034  SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
9035 
9036  if( bounds != NULL )
9037  *bounds = exprbounds;
9038 
9039  return SCIP_OKAY;
9040 }
9041 
9042 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
9043  *
9044  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL.
9045  * If substexprs[i] == NULL, then the variable expression i is not touched.
9046  */
9048  SCIP_EXPRTREE* tree, /**< expression tree */
9049  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
9050  )
9051 {
9052  assert(tree != NULL);
9053 
9054  if( tree->root == NULL )
9055  return SCIP_OKAY;
9056 
9057  if( tree->root->op == SCIP_EXPR_VARIDX )
9058  {
9059  int varidx;
9060 
9061  varidx = tree->root->data.intval;
9062  assert(varidx >= 0);
9063  if( substexprs[varidx] != NULL )
9064  {
9065  /* substitute root expression */
9066  SCIPexprFreeDeep(tree->blkmem, &tree->root);
9067  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
9068  }
9069  }
9070  else
9071  {
9072  /* check children (and grandchildren and so on...) of root expression */
9073  SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
9074  }
9075 
9076  /* substitution of variables should invalidate interpreter data */
9078 
9079  return SCIP_OKAY;
9080 }
9081 
9082 /**@} */
9083 
9084 /**@name Quadratic element methods */
9085 /**@{ */
9086 
9087 /** comparing two quadratic elements
9088  *
9089  * 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
9090  */
9091 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
9092 
9093 /** swaps two quadratic elements */
9094 #define QUADELEMS_SWAP(x,y) \
9095  { \
9096  SCIP_QUADELEM temp = x; \
9097  x = y; \
9098  y = temp; \
9099  }
9100 
9101 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
9102 static
9104  SCIP_QUADELEM* elems, /**< array to be sorted */
9105  int start, /**< starting index */
9106  int end /**< ending index */
9107  )
9108 {
9109  assert(start <= end);
9110 
9111  /* use quick sort for long lists */
9112  while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
9113  {
9114  SCIP_QUADELEM pivotkey;
9115  int lo;
9116  int hi;
9117  int mid;
9118 
9119  /* select pivot element */
9120  mid = (start+end)/2;
9121  pivotkey = elems[mid];
9122 
9123  /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
9124  lo = start;
9125  hi = end;
9126  for( ;; )
9127  {
9128  while( lo < end && QUADELEMS_ISBETTER(elems[lo], pivotkey) )
9129  lo++;
9130  while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
9131  hi--;
9132 
9133  if( lo >= hi )
9134  break;
9135 
9136  QUADELEMS_SWAP(elems[lo], elems[hi]);
9137 
9138  lo++;
9139  hi--;
9140  }
9141  assert(hi == lo-1 || hi == start);
9142 
9143  /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
9144  while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
9145  lo++;
9146 
9147  /* make sure that we have at least one element in the smaller partition */
9148  if( lo == start )
9149  {
9150  /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
9151  assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
9152  assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
9153  QUADELEMS_SWAP(elems[lo], elems[mid]);
9154  lo++;
9155  }
9156 
9157  /* sort the smaller partition by a recursive call, sort the larger part without recursion */
9158  if( hi - start <= end - lo )
9159  {
9160  /* sort [start,hi] with a recursive call */
9161  if( start < hi )
9162  quadelemsQuickSort(elems, start, hi);
9163 
9164  /* now focus on the larger part [lo,end] */
9165  start = lo;
9166  }
9167  else
9168  {
9169  /* sort [lo,end] with a recursive call */
9170  if( lo < end )
9171  quadelemsQuickSort(elems, lo, end);
9172 
9173  /* now focus on the larger part [start,hi] */
9174  end = hi;
9175  }
9176  }
9177 
9178  /* use shell sort on the remaining small list */
9179  if( end - start >= 1 )
9180  {
9181  static const int incs[3] = {1, 5, 19}; /* sequence of increments */
9182  int k;
9183 
9184  for( k = 2; k >= 0; --k )
9185  {
9186  int h;
9187  int i;
9188 
9189  for( h = incs[k], i = h + start; i <= end; ++i )
9190  {
9191  int j;
9192  SCIP_QUADELEM tempkey = elems[i];
9193 
9194  j = i;
9195  while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
9196  {
9197  elems[j] = elems[j-h];
9198  j -= h;
9199  }
9200 
9201  elems[j] = tempkey;
9202  }
9203  }
9204  }
9205 }
9206 
9207 /** sorts an array of quadratic elements
9208  *
9209  * The elements are sorted such that the first index is increasing and
9210  * such that among elements with the same first index, the second index is increasing.
9211  * For elements with same first and second index, the order is not defined.
9212  */
9214  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9215  int nquadelems /**< number of quadratic elements */
9216  )
9217 {
9218  if( nquadelems == 0 )
9219  return;
9220 
9221 #ifndef NDEBUG
9222  {
9223  int i;
9224  for( i = 0; i < nquadelems; ++i )
9225  assert(quadelems[i].idx1 <= quadelems[i].idx2);
9226  }
9227 #endif
9228 
9229  quadelemsQuickSort(quadelems, 0, nquadelems-1);
9230 }
9231 
9232 /** Finds an index pair in a sorted array of quadratic elements.
9233  *
9234  * If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
9235  * 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.
9236  * Assumes that idx1 <= idx2.
9237  */
9239  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9240  int idx1, /**< index of first variable in element to search for */
9241  int idx2, /**< index of second variable in element to search for */
9242  int nquadelems, /**< number of quadratic elements in array */
9243  int* pos /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
9244  )
9245 {
9246  int left;
9247  int right;
9248 
9249  assert(quadelems != NULL || nquadelems == 0);
9250  assert(idx1 <= idx2);
9251 
9252  if( nquadelems == 0 )
9253  {
9254  if( pos != NULL )
9255  *pos = 0;
9256  return FALSE;
9257  }
9258 
9259  left = 0;
9260  right = nquadelems - 1;
9261  while( left <= right )
9262  {
9263  int middle;
9264 
9265  middle = (left+right)/2;
9266  assert(0 <= middle && middle < nquadelems);
9267 
9268  if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) ) /*lint !e613*/
9269  right = middle - 1;
9270  else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) ) /*lint !e613*/
9271  left = middle + 1;
9272  else
9273  {
9274  if( pos != NULL )
9275  *pos = middle;
9276  return TRUE;
9277  }
9278  }
9279  assert(left == right+1);
9280 
9281  if( pos != NULL )
9282  *pos = left;
9283  return FALSE;
9284 }
9285 
9286 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
9287  *
9288  * Assumes that elements have been sorted before.
9289  */
9291  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9292  int nquadelems, /**< number of quadratic elements */
9293  int* nquadelemsnew /**< pointer to store new (reduced) number of quadratic elements */
9294  )
9295 {
9296  int i;
9297  int next;
9298 
9299  assert(quadelems != NULL);
9300  assert(nquadelemsnew != NULL);
9301  assert(nquadelems >= 0);
9302 
9303  i = 0;
9304  next = 0;
9305  while( next < nquadelems )
9306  {
9307  /* assert that array is sorted */
9308  assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
9309  (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
9310 
9311  /* skip elements with coefficient 0.0 */
9312  if( quadelems[next].coef == 0.0 )
9313  {
9314  ++next;
9315  continue;
9316  }
9317 
9318  /* if next element has same index as previous one, add it to the previous one */
9319  if( i >= 1 &&
9320  quadelems[i-1].idx1 == quadelems[next].idx1 &&
9321  quadelems[i-1].idx2 == quadelems[next].idx2 )
9322  {
9323  quadelems[i-1].coef += quadelems[next].coef;
9324  ++next;
9325  continue;
9326  }
9327 
9328  /* otherwise, move next element to current position */
9329  quadelems[i] = quadelems[next];
9330  ++i;
9331  ++next;
9332  }
9333  assert(next == nquadelems);
9334 
9335  /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
9336  *nquadelemsnew = i;
9337 }
9338 
9339 /**@} */
9340 
9341 /**@name Expression graph node private methods */
9342 /**@{ */
9343 
9344 /** adds a parent to an expression graph node */
9345 static
9347  BMS_BLKMEM* blkmem, /**< block memory */
9348  SCIP_EXPRGRAPHNODE* node, /**< expression graph node where to add a parent */
9349  SCIP_EXPRGRAPHNODE* parent /**< parent node */
9350  )
9351 {
9352  assert(blkmem != NULL);
9353  assert(node != NULL);
9354  assert(node->depth >= 0);
9355  assert(node->pos >= 0);
9356  assert(parent != NULL);
9357  assert(parent->depth >= 0);
9358  assert(parent->pos >= 0);
9359  assert(parent->depth > node->depth); /* a parent node need to have larger depth */
9360 
9361  ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
9362  assert(node->nparents < node->parentssize);
9363 
9364  node->parents[node->nparents] = parent;
9365  ++node->nparents;
9366 
9367  /* update sorted flag */
9368  node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (exprgraphnodecomp((void*)node->parents[node->nparents-2], (void*)parent) <= 0));
9369 
9370  return SCIP_OKAY;
9371 }
9372 
9373 /** ensures that array of parents in a node is sorted */
9374 static
9376  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
9377  )
9378 {
9379  assert(node != NULL);
9380 
9381  if( node->parentssorted )
9382  {
9383 #ifndef NDEBUG
9384  int i;
9385  for( i = 1; i < node->nparents; ++i )
9386  assert(exprgraphnodecomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
9387 #endif
9388  return;
9389  }
9390 
9391  SCIPsortPtr((void**)node->parents, exprgraphnodecomp, node->nparents);
9392 
9393  node->parentssorted = TRUE;
9394 }
9395 
9396 /** removes a parent from an expression graph node
9397  *
9398  * If the node is not used and has no other parents, then it is freed.
9399  */
9400 static
9402  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9403  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to remove a parent, *node will be set to NULL */
9404  SCIP_EXPRGRAPHNODE* parent /**< parent node to remove */
9405  )
9406 {
9407  SCIP_EXPRGRAPHNODE* node_;
9408  int pos;
9409  int i;
9410 
9411  assert(exprgraph != NULL);
9412  assert(node != NULL);
9413  assert(*node != NULL);
9414  assert((*node)->depth >= 0);
9415  assert((*node)->pos >= 0);
9416  assert((*node)->nparents > 0);
9417  assert(parent != NULL);
9418  assert(parent->depth >= 0);
9419  assert(parent->pos >= 0);
9420  assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
9421 
9422  /* find parent */
9423  exprgraphNodeSortParents(*node);
9424  (void) SCIPsortedvecFindPtr((void**)(*node)->parents, exprgraphnodecomp, (void*)parent, (*node)->nparents, &pos);
9425  assert(pos >= 0);
9426  assert(pos < (*node)->nparents);
9427  assert((*node)->parents[pos] == parent);
9428 
9429 #ifdef SCIP_DISABLED_CODE
9430  /* move last parent to pos, if pos is before last
9431  * update sorted flag */
9432  if( pos < (*node)->nparents-1 )
9433  {
9434  (*node)->parents[pos] = (*node)->parents[(*node)->nparents-1];
9435  (*node)->parentssorted = ((*node)->nparents <= 2);
9436  }
9437 #else
9438  /* move all parents behind pos one position up
9439  * this is faster than moving the last parent to position pos if there are many repeated calls to this function as the parents array remains sorted
9440  */
9441  for( i = pos+1; i < (*node)->nparents; ++i )
9442  (*node)->parents[i-1] = (*node)->parents[i];
9443 #endif
9444  --(*node)->nparents;
9445 
9446  /* keep pointer to *node in case it is still used */
9447  node_ = (*node)->nuses > 0 ? *node : NULL;
9448 
9449  /* capture and release node so it is freed if possible */
9450  SCIPexprgraphCaptureNode(*node);
9451  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
9452 
9453  /* restore pointer, if node still exists */
9454  *node = node_;
9455 
9456  return SCIP_OKAY;
9457 }
9458 
9459 /** checks if a node is parent of a node */
9460 static
9462  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9463  SCIP_EXPRGRAPHNODE* parent /**< parent to look for */
9464  )
9465 {
9466  int pos;
9467 
9468  assert(node != NULL);
9469  assert(parent != NULL);
9470 
9471  /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
9472  if( node->depth >= parent->depth || node->nparents == 0 )
9473  return FALSE;
9474  assert(node->parents != NULL);
9475 
9476  /* ensure parents array is sorted */
9478 
9479  return SCIPsortedvecFindPtr((void**)node->parents, exprgraphnodecomp, (void*)parent, node->nparents, &pos);
9480 }
9481 
9482 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
9483  *
9484  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
9485  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
9486  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
9487  *
9488  * It is assumed that node and all exprs are in the expression graph already.
9489  * It is assumed that all expressions that are added have lower depth than node.
9490  */
9491 static
9493  BMS_BLKMEM* blkmem, /**< block memory */
9494  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9495  int nexprs, /**< number of children to add */
9496  SCIP_EXPRGRAPHNODE** exprs, /**< children nodes to add */
9497  int* childmap /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
9498  )
9499 {
9500  int i;
9501  int j;
9502  int orignchildren;
9503  SCIP_Bool existsalready;
9504 
9505  assert(blkmem != NULL);
9506  assert(node != NULL);
9507  assert(node->depth > 0);
9508  assert(node->pos >= 0);
9509  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);
9510  assert(exprs != NULL || nexprs == 0);
9511 
9512  if( nexprs == 0 )
9513  return SCIP_OKAY;
9514 
9515  orignchildren = node->nchildren;
9516  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
9517 
9518  for( i = 0; i < nexprs; ++i )
9519  {
9520  assert(exprs[i]->depth >= 0); /*lint !e613*/
9521  assert(exprs[i]->pos >= 0); /*lint !e613*/
9522  assert(exprs[i]->depth < node->depth); /*lint !e613*/
9523 
9524  /* check if exprs[i] is a child already, if not SUM or PRODUCT */
9525  existsalready = FALSE;
9526  if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
9527  for( j = 0; j < orignchildren; ++j )
9528  /* during simplification of polynomials, their may be NULL's in children array */
9529  if( node->children[j] != NULL && node->children[j] == exprs[i] ) /*lint !e613*/
9530  {
9531  existsalready = TRUE;
9532  break;
9533  }
9534 
9535  if( !existsalready )
9536  {
9537  /* add exprs[i] to children array */
9538  node->children[node->nchildren] = exprs[i]; /*lint !e613*/
9539  SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) ); /*lint !e613*/
9540  if( childmap != NULL )
9541  childmap[i] = node->nchildren;
9542  ++node->nchildren;
9543  }
9544  else
9545  {
9546  if( childmap != NULL )
9547  childmap[i] = j; /*lint !e644*/
9548  if( node->op == SCIP_EXPR_LINEAR )
9549  {
9550  /* if linear expression, increase coefficient by 1.0 */
9551  ((SCIP_Real*)node->data.data)[j] += 1.0;
9552  }
9553  }
9554  }
9555 
9556  /* shrink children array to actually used size */
9557  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
9558 
9559  if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
9560  {
9561  /* if linear expression, then add 1.0 coefficients for new expressions */
9562  SCIP_Real* data;
9563 
9564  data = (SCIP_Real*)node->data.data;
9565  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
9566  data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
9567  for( i = orignchildren; i < node->nchildren; ++i )
9568  data[i] = 1.0;
9569  node->data.data = (void*)data;
9570  }
9571  else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
9572  {
9573  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
9575 
9576  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9577  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
9578  BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren); /*lint !e866*/
9579  }
9580 
9581  node->simplified = FALSE;
9582 
9583  return SCIP_OKAY;
9584 }
9585 
9586 /** replaces a child node by another node
9587  *
9588  * Assumes that both nodes represent the same expression.
9589  * If this node was the last parent of oldchild and oldchild is not in use, then it is freed.
9590  * newchild must have deeper depth than node.
9591  */
9592 static
9594  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9595  SCIP_EXPRGRAPHNODE* node, /**< pointer to expression graph node */
9596  SCIP_EXPRGRAPHNODE** oldchild, /**< child node that should be replaced, it may be freed */
9597  SCIP_EXPRGRAPHNODE* newchild /**< node that should take position of oldchild */
9598  )
9599 {
9600  int childpos = -1;
9601 
9602  assert(exprgraph != NULL);
9603  assert(node != NULL);
9604  assert(oldchild != NULL);
9605  assert(*oldchild != NULL);
9606  assert(newchild != NULL);
9607 
9608  if( *oldchild == newchild )
9609  return SCIP_OKAY;
9610 
9611  SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
9612 
9613  /* let's see if child is just next to the place where we looked in a previous call to this function */
9614  if( exprgraph->lastreplacechildpos >= 0 && exprgraph->lastreplacechildpos+1 < node->nchildren && node->children[exprgraph->lastreplacechildpos+1] == *oldchild )
9615  {
9616  childpos = exprgraph->lastreplacechildpos+1;
9617  }
9618  else for( childpos = 0; childpos < node->nchildren; ++childpos )
9619  {
9620  /* search for oldchild in children array */
9621  if( node->children[childpos] == *oldchild )
9622  break;
9623  }
9624  assert(childpos >= 0);
9625  assert(childpos < node->nchildren);
9626  assert(node->children[childpos] == *oldchild);
9627 
9628  /* add as parent to newchild */
9629  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
9630 
9631  /* remove as parent from oldchild */
9632  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
9633 
9634  /* set newchild as child i */
9635  node->children[childpos] = newchild;
9636 
9637  node->simplified = FALSE;
9638 
9639  /* remember to look next to childpos first next time */
9640  exprgraph->lastreplacechildpos = childpos;
9641 
9642  return SCIP_OKAY;
9643 }
9644 
9645 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
9646  *
9647  * A node is larger than another node, if their corresponding constants are related that way.
9648  */
9649 static
9650 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
9651 {
9652  assert(elem1 != NULL);
9653  assert(elem2 != NULL);
9654  assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
9655  assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
9656  assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9657  assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9658 
9659  if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9660  return 1;
9661  else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9662  return -1;
9663  else
9664  return 0;
9665 }
9666 
9667 /** sort array of nodes that holds constants */
9668 static
9670  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
9671  )
9672 {
9673  assert(exprgraph != NULL);
9674 
9675  if( exprgraph->constssorted )
9676  return;
9677 
9678  SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
9679 
9680  exprgraph->constssorted = TRUE;
9681 }
9682 
9683 /** finds position of expression graph node corresponding to a constant in constnodes array */
9684 static
9686  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9687  SCIP_EXPRGRAPHNODE* node, /**< node to search for */
9688  int* pos /**< buffer to store position of node, if found */
9689  )
9690 {
9691  int left;
9692  int right;
9693  int middle;
9694 
9695  assert(exprgraph != NULL);
9696  assert(node != NULL);
9697  assert(node->op == SCIP_EXPR_CONST);
9698  assert(node->depth == 0);
9699  assert(node->pos >= 0);
9700  assert(pos != NULL);
9701 
9702  exprgraphSortConstNodes(exprgraph);
9703  assert(exprgraph->constssorted);
9704 
9705  /* find a node with constant node->data.dbl using binary search */
9706  left = 0;
9707  right = exprgraph->nconsts-1;
9708  *pos = -1;
9709  while( left <= right )
9710  {
9711  middle = (left+right)/2;
9712  assert(0 <= middle && middle < exprgraph->nconsts);
9713 
9714  if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9715  right = middle - 1;
9716  else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9717  left = middle + 1;
9718  else
9719  {
9720  *pos = middle;
9721  break;
9722  }
9723  }
9724  assert(left == right+1 || *pos >= 0);
9725  if( left == right+1 )
9726  return FALSE;
9727 
9728  /* search left of *pos to find node */
9729  while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl ) /*lint !e777*/
9730  --*pos;
9731  /* search right of *pos to find node */
9732  while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl ) /*lint !e777*/
9733  ++*pos;
9734 
9735  return exprgraph->constnodes[*pos] == node;
9736 }
9737 
9738 /** creates an expression graph node */
9739 static
9741  BMS_BLKMEM* blkmem, /**< block memory */
9742  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
9743  SCIP_EXPROP op, /**< operator type of expression */
9744  SCIP_EXPROPDATA opdata /**< operator data of expression */
9745  )
9746 {
9747  assert(blkmem != NULL);
9748  assert(node != NULL);
9749 
9750  SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9751  BMSclearMemory(*node);
9752 
9753  (*node)->op = op;
9754  (*node)->data = opdata;
9755 
9756  /* mark graph position as not in graph yet */
9757  (*node)->depth = -1;
9758  (*node)->pos = -1;
9759 
9760  /* arrays of length 0 are trivially sorted */
9761  (*node)->parentssorted = TRUE;
9762 
9763  /* set bounds interval to entire */
9764  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9765  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9766 
9767  /* set initial value to invalid */
9768  (*node)->value = SCIP_INVALID;
9769 
9770  /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9771  if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9772  (*node)->curv = SCIP_EXPRCURV_LINEAR;
9773  else
9774  (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9775 
9776  /* per default, a node is enabled */
9777  (*node)->enabled = TRUE;
9778 
9779  return SCIP_OKAY;
9780 }
9781 
9782 /** prints the expression corresponding to a node (not recursively) */
9783 static
9785  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9786  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9787  FILE* file, /**< file to print to, or NULL for stdout */
9788  const char** varnames, /**< variable names, or NULL for generic names */
9789  SCIP_Bool printchildrenbounds /**< whether to print bounds of children */
9790  )
9791 {
9792  int i;
9793 
9794  assert(node != NULL);
9795 
9796  switch( node->op )
9797  {
9798  case SCIP_EXPR_VARIDX:
9799  if( varnames != NULL )
9800  {
9801  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9802  }
9803  else
9804  SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9805  break;
9806 
9807  case SCIP_EXPR_CONST:
9808  SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9809  break;
9810 
9811  case SCIP_EXPR_PARAM:
9812  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9813  break;
9814 
9815  case SCIP_EXPR_PLUS:
9816  if( printchildrenbounds )
9817  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9818  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9819  if( printchildrenbounds )
9820  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9821  break;
9822 
9823  case SCIP_EXPR_MINUS:
9824  if( printchildrenbounds )
9825  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9826  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9827  if( printchildrenbounds )
9828  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9829  break;
9830 
9831  case SCIP_EXPR_MUL:
9832  if( printchildrenbounds )
9833  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9834  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9835  if( printchildrenbounds )
9836  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9837  break;
9838 
9839  case SCIP_EXPR_DIV:
9840  if( printchildrenbounds )
9841  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9842  SCIPmessageFPrintInfo(messagehdlr, file, "/");
9843  if( printchildrenbounds )
9844  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9845  break;
9846 
9847  case SCIP_EXPR_SQUARE:
9848  if( printchildrenbounds )
9849  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9850  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9851  break;
9852 
9853  case SCIP_EXPR_REALPOWER:
9854  if( printchildrenbounds )
9855  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9856  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9857  break;
9858 
9859  case SCIP_EXPR_SIGNPOWER:
9860  if( printchildrenbounds )
9861  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9862  node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9863  else
9864  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9865  break;
9866 
9867  case SCIP_EXPR_INTPOWER:
9868  SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9869  if( printchildrenbounds )
9870  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9871  SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9872  break;
9873 
9874  case SCIP_EXPR_SQRT:
9875  case SCIP_EXPR_EXP:
9876  case SCIP_EXPR_LOG:
9877  case SCIP_EXPR_SIN:
9878  case SCIP_EXPR_COS:
9879  case SCIP_EXPR_TAN:
9880  /* SCIP_EXPR_ERF = 20, */ /**< gaussian error function (1 operand) */
9881  /* SCIP_EXPR_ERFI = 21, */ /**< imaginary part of gaussian error function (1 operand) */
9882  case SCIP_EXPR_MIN:
9883  case SCIP_EXPR_MAX:
9884  case SCIP_EXPR_ABS:
9885  case SCIP_EXPR_SIGN:
9886  SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9887  if( printchildrenbounds )
9888  {
9889  SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9890  if( node->nchildren == 2 )
9891  SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9892  SCIPmessageFPrintInfo(messagehdlr, file, ")");
9893  }
9894  break;
9895 
9896  case SCIP_EXPR_SUM:
9897  if( printchildrenbounds )
9898  for( i = 0; i < node->nchildren; ++i )
9899  {
9900  if( i > 0 )
9901  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9902  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9903  }
9904  else
9905  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9906  break;
9907 
9908  case SCIP_EXPR_PRODUCT:
9909  if( printchildrenbounds )
9910  for( i = 0; i < node->nchildren; ++i )
9911  {
9912  if( i > 0 )
9913  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9914  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9915  }
9916  else
9917  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9918  break;
9919 
9920  case SCIP_EXPR_LINEAR:
9921  {
9922  SCIP_Real constant;
9923 
9924  constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9925 
9926  if( constant != 0.0 || node->nchildren == 0 )
9927  SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9928 
9929  for( i = 0; i < node->nchildren; ++i )
9930  {
9931  if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9932  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9933  else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9934  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9935  else
9936  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9937  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9938  if( printchildrenbounds )
9939  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9940  }
9941 
9942  break;
9943  }
9944 
9945  case SCIP_EXPR_QUADRATIC:
9946  {
9947  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9948 
9949  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9950  assert(quadraticdata != NULL);
9951 
9952  if( quadraticdata->constant != 0.0 )
9953  SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9954 
9955  if( quadraticdata->lincoefs != NULL )
9956  for( i = 0; i < node->nchildren; ++i )
9957  {
9958  if( quadraticdata->lincoefs[i] == 0.0 )
9959  continue;
9960  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9961  if( printchildrenbounds )
9962  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9963  }
9964 
9965  for( i = 0; i < quadraticdata->nquadelems; ++i )
9966  {
9967  if( quadraticdata->quadelems[i].coef == 1.0 )
9968  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9969  else if( quadraticdata->quadelems[i].coef == -1.0 )
9970  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9971  else
9972  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9973  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9974  if( printchildrenbounds )
9975  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9976  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9977  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9978  else
9979  {
9980  SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9981  if( printchildrenbounds )
9982  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9983  }
9984  }
9985 
9986  break;
9987  }
9988 
9989  case SCIP_EXPR_POLYNOMIAL:
9990  {
9991  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9992  SCIP_EXPRDATA_MONOMIAL* monomialdata;
9993  int j;
9994 
9995  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9996  assert(polynomialdata != NULL);
9997 
9998  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
9999  {
10000  SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
10001  }
10002 
10003  for( i = 0; i < polynomialdata->nmonomials; ++i )
10004  {
10005  monomialdata = polynomialdata->monomials[i];
10006  if( monomialdata->coef == 1.0 )
10007  SCIPmessageFPrintInfo(messagehdlr, file, "+");
10008  else if( monomialdata->coef == -1.0 )
10009  SCIPmessageFPrintInfo(messagehdlr, file, "-");
10010  else
10011  SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
10012 
10013  for( j = 0; j < monomialdata->nfactors; ++j )
10014  {
10015  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
10016  if( printchildrenbounds )
10017  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
10018  if( monomialdata->exponents[j] < 0.0 )
10019  SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
10020  else if( monomialdata->exponents[j] != 1.0 )
10021  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
10022  }
10023  }
10024 
10025  break;
10026  }
10027 
10028  case SCIP_EXPR_LAST:
10029  SCIPABORT();
10030  break;
10031 
10032  default:
10033  SCIPmessageFPrintInfo(messagehdlr, file, "%s", SCIPexpropGetName(node->op));
10034  break;
10035  } /*lint !e788*/
10036 }
10037 
10038 /** prints a node of an expression graph */
10039 static
10041  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10042  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10043  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
10044  FILE* file, /**< file to print to, or NULL for stdout */
10045  const char** varnames /**< variable names, or NULL for generic names */
10046  )
10047 {
10048  SCIP_Real color;
10049  int i;
10050 
10051  assert(exprgraph != NULL);
10052  assert(node != NULL);
10053  assert(file != NULL);
10054 
10055  color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
10056  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
10057 
10058  exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
10059 
10060  SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
10062  SCIPmessageFPrintInfo(messagehdlr, file, "!");
10064  SCIPmessageFPrintInfo(messagehdlr, file, "*");
10066  SCIPmessageFPrintInfo(messagehdlr, file, "+");
10067 
10068  SCIPmessageFPrintInfo(messagehdlr, file, "\"");
10069 
10070  if( !node->enabled )
10071  SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
10072 
10073  SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
10074 
10075  /* add edges from node to children */
10076  for( i = 0; i < node->nchildren; ++i )
10077  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);
10078 }
10079 
10080 /** evaluate node of expression graph w.r.t. values stored in children */
10081 static
10083  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10084  SCIP_Real* varvals /**< values for variables */
10085  )
10086 {
10087  int i;
10089  SCIP_Real* buf;
10090 
10091  assert(node != NULL);
10092 
10093  /* if many children, get large enough memory to store argument values */
10095  {
10096  SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
10097  }
10098  else
10099  {
10100  buf = staticbuf;
10101  }
10102 
10103  /* get values of children */
10104  for( i = 0; i < node->nchildren; ++i )
10105  {
10106  assert(node->children[i]->value != SCIP_INVALID); /*lint !e777*/
10107  buf[i] = node->children[i]->value; /*lint !e644*/
10108  }
10109 
10110  /* evaluate this expression */
10111  assert(exprOpTable[node->op].eval != NULL);
10112  SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
10113  assert(node->value != SCIP_INVALID); /*lint !e777*/
10114 
10115  /* free memory, if allocated before */
10116  if( staticbuf != buf )
10117  {
10118  BMSfreeMemoryArray(&buf);
10119  }
10120 
10121  return SCIP_OKAY;
10122 }
10123 
10124 /** evaluates node including subtree */
10125 static
10127  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10128  SCIP_Real* varvals /**< values for variables */
10129  )
10130 {
10131  int i;
10132 
10133  assert(node != NULL);
10134 
10135  for( i = 0; i < node->nchildren; ++i )
10136  {
10137  SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
10138  }
10139 
10140  SCIP_CALL( exprgraphNodeEval(node, varvals) );
10141 
10142  return SCIP_OKAY;
10143 }
10144 
10145 /** updates bounds of a node if a children has changed its bounds */
10146 static
10148  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10149  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10150  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
10151  SCIP_Bool parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
10152  )
10153 {
10154  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
10155  SCIP_INTERVAL* childbounds;
10156  SCIP_INTERVAL newbounds;
10157  int i;
10158 
10159  assert(node != NULL);
10160  assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
10161  assert(node->pos >= 0); /* node should be in graph */
10162  assert(node->op != SCIP_EXPR_VARIDX);
10163  assert(node->op != SCIP_EXPR_PARAM);
10164 
10165  /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
10166  * if node is disabled, then also do nothing */
10167  if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
10168  return SCIP_OKAY;
10169 
10170  /* if many children, get large enough memory to store children bounds */
10172  {
10173  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
10174  }
10175  else
10176  {
10177  childbounds = childboundsstatic;
10178  }
10179 
10180  /* assemble bounds of children */
10181  for( i = 0; i < node->nchildren; ++i )
10182  {
10183  /* child should have valid and non-empty bounds */
10185  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10186 
10187  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
10188  }
10189 
10190  /* call interval evaluation function for this operand */
10191  assert( exprOpTable[node->op].inteval != NULL );
10192  SCIPintervalSet(&newbounds, 0.0);
10193  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
10194 
10195  /* free memory, if allocated before */
10196  if( childbounds != childboundsstatic )
10197  {
10198  BMSfreeMemoryArray(&childbounds);
10199  }
10200 
10201  /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
10202 
10203  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
10204  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
10205  *
10206  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
10207  *
10208  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
10209  */
10210  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
10211  ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
10212  {
10213  for( i = 0; i < node->nparents; ++i )
10215 
10216  node->bounds = newbounds;
10217  }
10218  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
10219  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
10220  {
10221  for( i = 0; i < node->nparents; ++i )
10223 
10224  node->bounds = newbounds;
10225  }
10226  else
10227  {
10228  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
10229  }
10230 
10231  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);
10232 
10233  /* node now has valid bounds */
10234  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
10235 
10236  return SCIP_OKAY;
10237 }
10238 
10239 /** propagate bounds of a node into children by reverting the nodes expression */
10240 static
10242  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10243  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
10244  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10245  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
10246  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
10247  )
10248 {
10249  SCIP_INTERVAL childbounds;
10250  int i;
10251 
10252  assert(exprgraph != NULL);
10253  assert(node != NULL);
10254  assert(node->depth >= 0); /* node should be in graph */
10255  assert(node->pos >= 0); /* node should be in graph */
10256  assert(minstrength >= 0.0);
10257  assert(cutoff != NULL);
10258  assert(!SCIPintervalIsEmpty(infinity, node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
10259  assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
10260 
10261  /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
10263  return;
10264 
10265  /* if node is not enabled, then do nothing */
10266  if( !node->enabled )
10267  return;
10268 
10269  /* tell children that they should propagate their bounds even if not tightened */
10271  minstrength = -1.0;
10272 
10273  /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
10275 
10276  /* 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);
10277  * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10278  * SCIPdebugPrintf("\n");
10279  */
10280 
10281  /* @todo add callback to exprOpTable for this */
10282 
10283  switch( node->op )
10284  {
10285  case SCIP_EXPR_VARIDX:
10286  case SCIP_EXPR_CONST:
10287  case SCIP_EXPR_PARAM:
10288  /* cannot propagate bound changes further */
10289  break;
10290 
10291  case SCIP_EXPR_PLUS:
10292  {
10293  assert(node->nchildren == 2);
10294  /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
10295 
10296  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10297  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10298 
10299  if( *cutoff )
10300  break;
10301 
10302  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10303  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10304 
10305  break;
10306  }
10307 
10308  case SCIP_EXPR_MINUS:
10309  {
10310  assert(node->nchildren == 2);
10311  /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
10312 
10313  SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10314  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10315 
10316  if( *cutoff )
10317  break;
10318 
10319  SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10320  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10321 
10322  break;
10323  }
10324 
10325  case SCIP_EXPR_MUL:
10326  {
10327  assert(node->nchildren == 2);
10328  /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
10329 
10330  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10331  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10332 
10333  if( *cutoff )
10334  break;
10335 
10336  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10337  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10338 
10339  break;
10340  }
10341 
10342  case SCIP_EXPR_DIV:
10343  {
10344  assert(node->nchildren == 2);
10345  /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
10346 
10347  SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10348  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10349 
10350  if( *cutoff )
10351  break;
10352 
10353  SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10354  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10355 
10356  break;
10357  }
10358 
10359  case SCIP_EXPR_SQUARE:
10360  {
10361  assert(node->nchildren == 1);
10362  /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
10363 
10364  if( node->bounds.sup < 0.0 )
10365  {
10366  *cutoff = TRUE;
10367  break;
10368  }
10369 
10370  SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
10371  if( node->children[0]->bounds.inf <= -childbounds.inf )
10372  SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
10373  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10374 
10375  break;
10376  }
10377 
10378  case SCIP_EXPR_SQRT:
10379  {
10380  assert(node->nchildren == 1);
10381  /* f = sqrt(c0) -> c0 = f^2 */
10382 
10383  SCIPintervalSquare(infinity, &childbounds, node->bounds);
10384  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10385 
10386  break;
10387  }
10388 
10389  case SCIP_EXPR_REALPOWER:
10390  {
10391  assert(node->nchildren == 1);
10392 
10393  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
10394 
10395  if( SCIPintervalIsEmpty(infinity, childbounds) )
10396  {
10397  *cutoff = TRUE;
10398  break;
10399  }
10400  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10401 
10402  break;
10403  }
10404 
10405  case SCIP_EXPR_SIGNPOWER:
10406  {
10407  assert(node->nchildren == 1);
10408 
10409  if( node->data.dbl != 0.0 )
10410  {
10411  SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
10412  }
10413  else
10414  {
10415  /* behaves like SCIP_EXPR_SIGN */
10416  SCIPintervalSetBounds(&childbounds,
10417  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10418  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10419  }
10420 
10421  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10422 
10423  break;
10424  }
10425 
10426  case SCIP_EXPR_INTPOWER:
10427  {
10428  assert(node->nchildren == 1);
10429 
10430  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
10431 
10432  if( SCIPintervalIsEmpty(infinity, childbounds) )
10433  {
10434  *cutoff = TRUE;
10435  break;
10436  }
10437  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10438 
10439  break;
10440  }
10441 
10442  case SCIP_EXPR_EXP:
10443  {
10444  assert(node->nchildren == 1);
10445  /* f = exp(c0) -> c0 = log(f) */
10446 
10447  if( node->bounds.sup < 0.0 )
10448  {
10449  *cutoff = TRUE;
10450  break;
10451  }
10452 
10453  SCIPintervalLog(infinity, &childbounds, node->bounds);
10454  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10455 
10456  break;
10457  }
10458 
10459  case SCIP_EXPR_LOG:
10460  {
10461  assert(node->nchildren == 1);
10462  /* f = log(c0) -> c0 = exp(f) */
10463 
10464  SCIPintervalExp(infinity, &childbounds, node->bounds);
10465  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10466 
10467  break;
10468  }
10469 
10470  case SCIP_EXPR_SIN:
10471  case SCIP_EXPR_COS:
10472  case SCIP_EXPR_TAN:
10473  /* case SCIP_EXPR_ERF: */
10474  /* case SCIP_EXPR_ERFI: */
10475  {
10476  assert(node->nchildren == 1);
10477 
10478  /* @todo implement */
10479 
10480  break;
10481  }
10482 
10483  case SCIP_EXPR_ABS:
10484  {
10485  assert(node->nchildren == 1);
10486 
10487  /* use identity if child bounds are non-negative */
10488  if( node->children[0]->bounds.inf >= 0 )
10489  {
10490  SCIPintervalSetBounds(&childbounds, node->bounds.inf, node->bounds.sup);
10491  }
10492  /* use -identity if child bounds are non-positive */
10493  else if( node->children[0]->bounds.sup <= 0 )
10494  {
10495  assert(node->bounds.inf <= node->bounds.sup);
10496  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, -node->bounds.inf);
10497  }
10498  /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
10499  else
10500  {
10501  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
10502  }
10503 
10504  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10505 
10506  break;
10507  }
10508 
10509  case SCIP_EXPR_SIGN:
10510  {
10511  assert(node->nchildren == 1);
10512  /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
10513 
10514  SCIPintervalSetBounds(&childbounds,
10515  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10516  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10517  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10518 
10519  break;
10520  }
10521 
10522  case SCIP_EXPR_MIN:
10523  {
10524  assert(node->nchildren == 2);
10525  /* f = min(c0,c1) -> f <= c0, f <= c1
10526  * if c1 > f -> c0 = f
10527  * if c0 > f -> c1 = f
10528  */
10529 
10530  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10531  node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10532  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10533 
10534  if( *cutoff )
10535  break;
10536 
10537  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10538  node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10539  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10540 
10541  break;
10542  }
10543 
10544  case SCIP_EXPR_MAX:
10545  {
10546  assert(node->nchildren == 2);
10547  /* f = max(c0, c1) -> f >= c0, f >= c1
10548  * if c1 < f -> c0 = f
10549  * if c0 < f -> c1 = f
10550  */
10551 
10552  SCIPintervalSetBounds(&childbounds,
10553  node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10554  node->bounds.sup);
10555  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10556 
10557  SCIPintervalSetBounds(&childbounds,
10558  node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10559  node->bounds.sup);
10560  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10561 
10562  break;
10563  }
10564 
10565  case SCIP_EXPR_SUM:
10566  {
10567  SCIP_ROUNDMODE prevroundmode;
10568 
10569  /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
10570 
10571  SCIP_Real minlinactivity;
10572  SCIP_Real maxlinactivity;
10573  int minlinactivityinf;
10574  int maxlinactivityinf;
10575 
10576  if( node->nchildren == 0 )
10577  break;
10578 
10579  if( SCIPintervalIsEntire(infinity, node->bounds) )
10580  break;
10581 
10582  minlinactivity = 0.0;
10583  maxlinactivity = 0.0;
10584  minlinactivityinf = 0;
10585  maxlinactivityinf = 0;
10586 
10587  prevroundmode = SCIPintervalGetRoundingMode();
10589 
10590  for( i = 0; i < node->nchildren; ++i )
10591  {
10592  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10593 
10594  /* minimal activity is only useful if node has a finite upper bound */
10595  if( node->bounds.sup < infinity )
10596  {
10597  if( node->children[i]->bounds.inf <= -infinity )
10598  {
10599  ++minlinactivityinf;
10600  }
10601  else
10602  {
10603  assert(node->children[i]->bounds.inf < infinity);
10604  minlinactivity += node->children[i]->bounds.inf;
10605  }
10606  }
10607 
10608  /* maximal activity is only useful if node has a finite lower bound
10609  * we compute negated maximal activity here so we can keep downward rounding
10610  */
10611  if( node->bounds.inf > -infinity )
10612  {
10613  if( node->children[i]->bounds.sup >= infinity )
10614  {
10615  ++maxlinactivityinf;
10616  }
10617  else
10618  {
10619  assert(node->children[i]->bounds.sup > -infinity);
10620  maxlinactivity -= node->children[i]->bounds.sup;
10621  }
10622  }
10623  }
10624  maxlinactivity = -maxlinactivity; /* correct sign */
10625 
10626  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10627  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10628  ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10629  )
10630  {
10631  SCIPintervalSetRoundingMode(prevroundmode);
10632  break;
10633  }
10634 
10635  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10636  {
10637  /* upper bounds of c_i is
10638  * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
10639  * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
10640  */
10641  SCIPintervalSetEntire(infinity, &childbounds);
10642  if( node->bounds.sup < infinity )
10643  {
10644  /* we are still in downward rounding mode, so negate and negate to get upward rounding */
10645  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10646  {
10647  assert(minlinactivityinf == 1);
10648  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
10649  }
10650  else if( minlinactivityinf == 0 )
10651  {
10652  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
10653  }
10654  }
10655 
10656  /* lower bounds of c_i is
10657  * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
10658  * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
10659  */
10660  if( node->bounds.inf > -infinity )
10661  {
10662  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10663  {
10664  assert(maxlinactivityinf == 1);
10665  childbounds.inf = node->bounds.inf - maxlinactivity;
10666  }
10667  else if( maxlinactivityinf == 0 )
10668  {
10669  childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
10670  }
10671  }
10672 
10673  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10674  }
10675 
10676  SCIPintervalSetRoundingMode(prevroundmode);
10677 
10678  break;
10679  }
10680 
10681  case SCIP_EXPR_PRODUCT:
10682  {
10683  int j;
10684  /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
10685 
10686  /* too expensive (runtime here is quadratic in number of children) */
10687  if( node->nchildren > 10 )
10688  break;
10689 
10690  /* useless */
10691  if( SCIPintervalIsEntire(infinity, node->bounds) )
10692  break;
10693 
10694  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10695  {
10696  /* compute prod_{j:j!=i} c_j */
10697  SCIPintervalSet(&childbounds, 1.0);
10698  for( j = 0; j < node->nchildren; ++j )
10699  {
10700  if( i == j )
10701  continue;
10702  SCIPintervalMul(infinity, &childbounds, childbounds, node->children[j]->bounds);
10703 
10704  /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
10705  if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
10706  break;
10707  }
10708 
10709  if( j == node->nchildren )
10710  {
10711  SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
10712  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10713  }
10714  }
10715 
10716  break;
10717  }
10718 
10719  case SCIP_EXPR_LINEAR:
10720  {
10721  SCIP_ROUNDMODE prevroundmode;
10722  SCIP_Real* coefs;
10723 
10724  /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10725 
10726  SCIP_Real minlinactivity;
10727  SCIP_Real maxlinactivity;
10728  int minlinactivityinf;
10729  int maxlinactivityinf;
10730 
10731  if( node->nchildren == 0 )
10732  break;
10733 
10734  if( SCIPintervalIsEntire(infinity, node->bounds) )
10735  break;
10736 
10737  coefs = (SCIP_Real*)node->data.data;
10738 
10739  minlinactivity = coefs[node->nchildren];
10740  maxlinactivity = -coefs[node->nchildren];
10741  minlinactivityinf = 0;
10742  maxlinactivityinf = 0;
10743 
10744  prevroundmode = SCIPintervalGetRoundingMode();
10746 
10747  for( i = 0; i < node->nchildren; ++i )
10748  {
10749  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10750 
10751  /* minimal activity is only useful if node has a finite upper bound */
10752  if( node->bounds.sup < infinity )
10753  {
10754  if( coefs[i] >= 0.0 )
10755  {
10756  if( node->children[i]->bounds.inf <= -infinity )
10757  {
10758  ++minlinactivityinf;
10759  }
10760  else
10761  {
10762  assert(node->children[i]->bounds.inf < infinity);
10763  minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10764  }
10765  }
10766  else
10767  {
10768  if( node->children[i]->bounds.sup >= infinity )
10769  {
10770  ++minlinactivityinf;
10771  }
10772  else
10773  {
10774  assert(node->children[i]->bounds.sup > -infinity);
10775  minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10776  }
10777  }
10778  }
10779 
10780  /* maximal activity is only useful if node has a finite lower bound
10781  * we compute negated maximal activity here so we can keep downward rounding
10782  */
10783  if( node->bounds.inf > -infinity )
10784  {
10785  if( coefs[i] >= 0.0 )
10786  {
10787  if( node->children[i]->bounds.sup >= infinity )
10788  {
10789  ++maxlinactivityinf;
10790  }
10791  else
10792  {
10793  assert(node->children[i]->bounds.sup > -infinity);
10794  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.sup;
10795  }
10796  }
10797  else
10798  {
10799  if( node->children[i]->bounds.inf <= -infinity )
10800  {
10801  ++maxlinactivityinf;
10802  }
10803  else
10804  {
10805  assert(node->children[i]->bounds.inf < infinity);
10806  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.inf;
10807  }
10808  }
10809  }
10810  }
10811  maxlinactivity = SCIPintervalNegateReal(maxlinactivity); /* correct sign */
10812 
10813  /* SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]; bounds = [%10g,%10g]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf, node->bounds.inf, node->bounds.sup); */
10814 
10815  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10816  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10817  (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10818  )
10819  {
10820  SCIPintervalSetRoundingMode(prevroundmode);
10821  break;
10822  }
10823 
10824  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10825  {
10826  SCIP_INTERVAL ac;
10827 
10828  if( coefs[i] == 0.0 )
10829  continue;
10830 
10831  /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10832  SCIPintervalSet(&ac, 0.0);
10833  if( coefs[i] >= 0.0 )
10834  {
10835  if( node->children[i]->bounds.inf > -infinity )
10836  ac.inf = coefs[i] * node->children[i]->bounds.inf;
10837  if( node->children[i]->bounds.sup < infinity )
10839  }
10840  else
10841  {
10842  if( node->children[i]->bounds.sup < infinity )
10843  ac.inf = coefs[i] * node->children[i]->bounds.sup;
10844  if( node->children[i]->bounds.inf > -infinity )
10845  ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10846  }
10847 
10848  SCIPintervalSetEntire(infinity, &childbounds);
10849  if( coefs[i] > 0.0 )
10850  {
10851  /* upper bounds of c_i is
10852  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10853  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10854  */
10855  if( node->bounds.sup < infinity )
10856  {
10857  /* we are still in downward rounding mode, so negate to get upward rounding */
10858  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10859  {
10860  assert(minlinactivityinf == 1);
10861  childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10862  }
10863  else if( minlinactivityinf == 0 )
10864  {
10865  childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10866  }
10867  }
10868 
10869  /* lower bounds of c_i is
10870  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10871  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10872  */
10873  if( node->bounds.inf > -infinity )
10874  {
10875  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10876  {
10877  assert(maxlinactivityinf == 1);
10878  childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10879  }
10880  else if( maxlinactivityinf == 0 )
10881  {
10882  childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10883  }
10884  }
10885  }
10886  else
10887  {
10888  /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10889  * thus, we do (b-a)/(-c) in downward rounding
10890  */
10891  /* lower bounds of c_i is
10892  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10893  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10894  */
10895  if( node->bounds.sup < infinity )
10896  {
10897  if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10898  {
10899  assert(minlinactivityinf == 1);
10900  childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10901  }
10902  else if( minlinactivityinf == 0 )
10903  {
10904  childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10905  }
10906  }
10907 
10908  /* upper bounds of c_i is
10909  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10910  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10911  */
10912  if( node->bounds.inf > -infinity )
10913  {
10914  /* we are still in downward rounding mode, so negate to get upward rounding */
10915  if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10916  {
10917  assert(maxlinactivityinf == 1);
10918  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10919  }
10920  else if( maxlinactivityinf == 0 )
10921  {
10922  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10923  }
10924  }
10925  }
10926 
10927  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10928  }
10929 
10930  SCIPintervalSetRoundingMode(prevroundmode);
10931 
10932  break;
10933  }
10934 
10935  case SCIP_EXPR_QUADRATIC:
10936  {
10937  SCIP_EXPRDATA_QUADRATIC* quaddata;
10938  SCIP_INTERVAL tmp;
10939  SCIP_INTERVAL a;
10940  SCIP_INTERVAL b;
10941  SCIP_INTERVAL c;
10942  SCIP_QUADELEM* quadelems;
10943  int nquadelems;
10944  SCIP_Real* lincoefs;
10945  int k;
10946 
10947  /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10948  * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10949  */
10950 
10951  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10952  quadelems = quaddata->quadelems;
10953  nquadelems = quaddata->nquadelems;
10954  lincoefs = quaddata->lincoefs;
10955 
10956  /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10957  if( nquadelems > 10 )
10958  break;
10959 
10960  if( SCIPintervalIsEntire(infinity, node->bounds) )
10961  break;
10962 
10963  if( node->nchildren == 2 && nquadelems > 0 )
10964  {
10965  /* if it's a bivariate quadratic expression with bilinear term, do something special */
10966  SCIP_Real ax; /* square coefficient of first child */
10967  SCIP_Real ay; /* square coefficient of second child */
10968  SCIP_Real axy; /* bilinear coefficient */
10969 
10970  ax = 0.0;
10971  ay = 0.0;
10972  axy = 0.0;
10973  for( i = 0; i < nquadelems; ++i )
10974  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10975  ax += quadelems[i].coef;
10976  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10977  ay += quadelems[i].coef;
10978  else
10979  axy += quadelems[i].coef;
10980 
10981  c = node->bounds;
10982  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10983 
10984  /* compute bounds for x */
10986  infinity, &childbounds, ax, ay, axy,
10987  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10988  c, node->children[0]->bounds, node->children[1]->bounds
10989  );
10990  if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10991  {
10992  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",
10993  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10994  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10995  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10996  );
10997  }
10998 
10999  if( SCIPintervalIsEmpty(infinity, childbounds) )
11000  *cutoff = TRUE;
11001  else
11002  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11003  if( *cutoff )
11004  break;
11005 
11006  /* compute bounds for y */
11008  infinity, &childbounds, ay, ax, axy,
11009  lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
11010  c, node->children[1]->bounds, node->children[0]->bounds
11011  );
11012 
11013  if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
11014  {
11015  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",
11016  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
11017  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
11018  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
11019  );
11020  }
11021 
11022  if( SCIPintervalIsEmpty(infinity, childbounds) )
11023  *cutoff = TRUE;
11024  else
11025  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
11026  if( *cutoff )
11027  break;
11028 
11029  break;
11030  }
11031 
11032  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11033  {
11034  SCIPintervalSet(&a, 0.0);
11035  SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
11036  c = node->bounds;
11037  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
11038 
11039  /* move linear terms not corresponding to i into c
11040  * @todo do this faster, see EXPR_LINEAR
11041  */
11042  if( lincoefs != NULL )
11043  for( k = 0; k < node->nchildren; ++k )
11044  if( i != k && lincoefs[k] != 0.0 )
11045  {
11046  SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
11047  SCIPintervalSub(infinity, &c, c, tmp);
11048  }
11049 
11050  for( k = 0; k < nquadelems; ++k )
11051  {
11052  if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
11053  {
11054  SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
11055  }
11056  else if( quadelems[k].idx1 == i )
11057  {
11058  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
11059  SCIPintervalAdd(infinity, &b, b, tmp);
11060  }
11061  else if( quadelems[k].idx2 == i )
11062  {
11063  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
11064  SCIPintervalAdd(infinity, &b, b, tmp);
11065  }
11066  else if( quadelems[k].idx1 == quadelems[k].idx2 )
11067  {
11068  SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
11069  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11070  SCIPintervalSub(infinity, &c, c, tmp);
11071  }
11072  else
11073  {
11074  SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
11075  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11076  SCIPintervalSub(infinity, &c, c, tmp);
11077  }
11078  }
11079 
11080  SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
11081  a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
11082  SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c, node->children[i]->bounds);
11083  if( SCIPintervalIsEmpty(infinity, childbounds) )
11084  *cutoff = TRUE;
11085  else
11086  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11087  }
11088 
11089  break;
11090  }
11091 
11092  case SCIP_EXPR_POLYNOMIAL:
11093  {
11094  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11095  SCIP_EXPRDATA_MONOMIAL** monomials;
11096  SCIP_EXPRDATA_MONOMIAL* monomial;
11097  int nmonomials;
11098  int j;
11099  int k;
11100  SCIP_Real n;
11101  int nexpisdoublen;
11102  int nexpishalfn;
11103  char abc_flag;
11104 
11105  SCIP_INTERVAL monomialcoef;
11106  SCIP_INTERVAL tmp;
11107  SCIP_INTERVAL a;
11108  SCIP_INTERVAL b;
11109  SCIP_INTERVAL c;
11110  SCIP_INTERVAL childpowbounds;
11111 
11112  /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
11113  * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
11114  *
11115  * we determine n by setting n to the first exponent of x that we see
11116  * then we count how often we see x^(2n) and x^(n/2)
11117  * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
11118  */
11119 
11120  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11121  monomials = polynomialdata->monomials;
11122  nmonomials = polynomialdata->nmonomials;
11123 
11124  if( SCIPintervalIsEntire(infinity, node->bounds) )
11125  break;
11126 
11127  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11128  {
11129  n = 0.0;
11130  nexpisdoublen = 0;
11131  nexpishalfn = 0;
11132  for( j = 0; j < nmonomials; ++j )
11133  {
11134  monomial = monomials[j];
11135  for( k = 0; k < monomial->nfactors; ++k )
11136  {
11137  if( monomial->childidxs[k] == i )
11138  {
11139  if( n == 0.0 )
11140  n = monomial->exponents[k];
11141  else if( n == 2*monomial->exponents[k] ) /*lint !e777*/
11142  ++nexpishalfn;
11143  else if( 2*n == monomial->exponents[k] ) /*lint !e777*/
11144  ++nexpisdoublen;
11145  }
11146  }
11147  }
11148 
11149  if( n == 0.0 )
11150  {
11151  /* child does not appear in polynomial -> cannot deduce bound */
11152  continue;
11153  }
11154 
11155  /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
11156  if( nexpishalfn > nexpisdoublen )
11157  n /= 2.0;
11158 
11159  SCIPintervalSet(&a, 0.0);
11160  SCIPintervalSet(&b, 0.0);
11161  SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
11162 
11163  for( j = 0; j < nmonomials; ++j )
11164  {
11165  monomial = monomials[j];
11166  SCIPintervalSet(&monomialcoef, monomial->coef);
11167  abc_flag = 'c';
11168  for( k = 0; k < monomial->nfactors; ++k )
11169  {
11170  if( monomial->childidxs[k] == i )
11171  {
11172  assert(abc_flag == 'c'); /* child should appear only once per monom */
11173  if( n > 0.0 )
11174  {
11175  if( monomial->exponents[k] > 2.0*n )
11176  {
11177  abc_flag = 'a';
11178  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11179  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11180  }
11181  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11182  {
11183  abc_flag = 'a';
11184  }
11185  else if( monomial->exponents[k] > n )
11186  {
11187  abc_flag = 'b';
11188  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11189  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11190  }
11191  else if( monomial->exponents[k] == n ) /*lint !e777*/
11192  {
11193  abc_flag = 'b';
11194  }
11195  else
11196  {
11197  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11198  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11199  }
11200  }
11201  else
11202  {
11203  assert(n < 0.0);
11204  if( monomial->exponents[k] < 2.0*n )
11205  {
11206  abc_flag = 'a';
11207  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11208  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11209  }
11210  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11211  {
11212  abc_flag = 'a';
11213  }
11214  else if( monomial->exponents[k] < n )
11215  {
11216  abc_flag = 'b';
11217  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11218  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11219  }
11220  else if( monomial->exponents[k] == n ) /*lint !e777*/
11221  {
11222  abc_flag = 'b';
11223  }
11224  else
11225  {
11226  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11227  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11228  }
11229  }
11230  }
11231  else
11232  {
11233  SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
11234  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11235  }
11236  }
11237 
11238  if( abc_flag == 'a' )
11239  {
11240  SCIPintervalAdd(infinity, &a, a, monomialcoef);
11241  /* if monomialcoef is such that a exceeds value for infinity, then stop */
11242  if( a.inf >= infinity || a.sup <= -infinity )
11243  break;
11244  }
11245  else if( abc_flag == 'b' )
11246  {
11247  SCIPintervalAdd(infinity, &b, b, monomialcoef);
11248  /* if monomialcoef is such that b exceeds value for infinity, then stop */
11249  if( b.inf >= infinity || b.sup <= -infinity )
11250  break;
11251  }
11252  else
11253  {
11254  SCIPintervalSub(infinity, &c, c, monomialcoef);
11255  /* if monomialcoef is such that c exceeds value for infinity, then stop */
11256  if( c.inf >= infinity || c.sup <= -infinity )
11257  break;
11258  }
11259  }
11260 
11261  /* if we run out of numbers (within -infinity,infinity) above, then stop */
11262  if( j < nmonomials )
11263  continue;
11264 
11265  /* now have equation a*child^(2n) + b*child^n = c
11266  * solve a*y^2 + b*y = c (for y in childbounds^n), then child^n = y
11267  */
11268  SCIPintervalPowerScalar(infinity, &childpowbounds, node->children[i]->bounds, n);
11269  SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g] for c%d^%g in [%10g,%10g]",
11270  a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup, i, n, childpowbounds.inf, childpowbounds.sup);
11271  SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c, childpowbounds);
11272  SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
11273 
11274  if( SCIPintervalIsEmpty(infinity, tmp) )
11275  {
11276  *cutoff = TRUE;
11277  break;
11278  }
11279 
11280  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
11281  SCIPdebugPrintf(" with c%d = [%10g, %10g] -> c%d = [%10g, %10g]\n", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup, i, childbounds.inf, childbounds.sup);
11282  if( SCIPintervalIsEmpty(infinity, childbounds) )
11283  {
11284  SCIPdebugMessage(" -> cutoff\n");
11285  *cutoff = TRUE;
11286  break;
11287  }
11288 
11289  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11290 
11291  /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
11292  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11293  SCIPdebugPrintf("\n"); */
11294  }
11295 
11296  break;
11297  }
11298 
11299  case SCIP_EXPR_USER:
11300  {
11301  SCIP_INTERVAL* childrenbounds;
11302  SCIP_EXPRDATA_USER* exprdata;
11303  int c;
11304 
11305  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11306 
11307  /* do nothing if callback not implemented */
11308  if( exprdata->prop == NULL )
11309  break;
11310 
11311  /* if only one child, do faster */
11312  if( node->nchildren == 1 )
11313  {
11314  childbounds = node->children[0]->bounds;
11315  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, 1, &childbounds, node->bounds, cutoff) );
11316 
11317  if( !*cutoff )
11318  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11319 
11320  break;
11321  }
11322 
11323  SCIP_ALLOC_ABORT( BMSallocBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren) );
11324  for( c = 0; c < node->nchildren; ++c )
11325  childrenbounds[c] = node->children[c]->bounds;
11326 
11327  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, node->nchildren, childrenbounds, node->bounds, cutoff) );
11328 
11329  for( c = 0; !*cutoff && c < node->nchildren; ++c )
11330  {
11331  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[c], childrenbounds[c], minstrength, infinity, cutoff);
11332  }
11333 
11334  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren);
11335 
11336  break;
11337  }
11338 
11339  case SCIP_EXPR_LAST:
11340  SCIPABORT();
11341  break;
11342  }
11343 }
11344 
11345 /** removes duplicate children in a polynomial expression node
11346  *
11347  * Leaves NULL's in children array.
11348  */
11349 static
11351  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11352  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11353  )
11354 {
11355  SCIP_Bool foundduplicates;
11356  int* childmap;
11357  int i;
11358  int j;
11359 
11360  assert(exprgraph != NULL);
11361  assert(node != NULL);
11362  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11363 
11364  if( node->nchildren == 0 )
11365  return SCIP_OKAY;
11366 
11367  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
11368 
11369  foundduplicates = FALSE;
11370  for( i = 0; i < node->nchildren; ++i )
11371  {
11372  if( node->children[i] == NULL )
11373  continue;
11374  childmap[i] = i; /*lint !e644*/
11375 
11376  for( j = i+1; j < node->nchildren; ++j )
11377  {
11378  if( node->children[j] == NULL )
11379  continue;
11380 
11381  if( node->children[i] == node->children[j] )
11382  {
11383  /* node should be parent of children[j] at least twice,
11384  * so we remove it once
11385  */
11386  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
11387  node->children[j] = NULL;
11388  assert(exprgraphNodeIsParent(node->children[i], node));
11389 
11390  childmap[j] = i;
11391  foundduplicates = TRUE;
11392  }
11393  }
11394  }
11395 
11396  /* apply childmap to monomials */
11397  if( foundduplicates )
11399 
11400  /* free childmap */
11401  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
11402 
11403  return SCIP_OKAY;
11404 }
11405 
11406 /** eliminates NULL's in children array and shrinks it to actual size */
11407 static
11409  BMS_BLKMEM* blkmem, /**< block memory */
11410  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11411  )
11412 {
11413  int* childmap;
11414  int lastnonnull;
11415  int i;
11416 
11417  assert(blkmem != NULL);
11418  assert(node != NULL);
11419  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11420 
11421  if( node->nchildren == 0 )
11422  return SCIP_OKAY;
11423 
11424  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
11425 
11426  /* close gaps in children array */
11427  lastnonnull = node->nchildren-1;
11428  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11429  --lastnonnull;
11430  for( i = 0; i <= lastnonnull; ++i )
11431  {
11432  if( node->children[i] != NULL )
11433  {
11434  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
11435  continue;
11436  }
11437  assert(node->children[lastnonnull] != NULL);
11438 
11439  /* move child at lastnonnull to position i */
11440  node->children[i] = node->children[lastnonnull];
11441  node->children[lastnonnull] = NULL;
11442  childmap[lastnonnull] = i;
11443 
11444  /* update lastnonnull */
11445  --lastnonnull;
11446  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11447  --lastnonnull;
11448  }
11449  assert(i > lastnonnull);
11450 
11451  /* apply childmap to monomials */
11452  if( lastnonnull < node->nchildren-1 )
11454 
11455  BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
11456 
11457  /* shrink children array */
11458  if( lastnonnull >= 0 )
11459  {
11460  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
11461  node->nchildren = lastnonnull+1;
11462  }
11463  else
11464  {
11465  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11466  node->nchildren = 0;
11467  }
11468 
11469  return SCIP_OKAY;
11470 }
11471 
11472 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
11473  *
11474  * Converts node into polynomial, if possible and not constant.
11475  */
11476 static
11478  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11479  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
11480  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
11481  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
11482  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
11483  SCIP_Bool* havechange /**< flag to set if the node has been changed */
11484  )
11485 {
11486  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11487  SCIP_EXPRDATA_MONOMIAL* monomial;
11488  BMS_BLKMEM* blkmem;
11489  SCIP_Bool removechild;
11490  SCIP_Bool* childinuse;
11491  int* childmap;
11492  int childmapsize;
11493  int i;
11494  int j;
11495  int orignchildren;
11496 
11497  assert(exprgraph != NULL);
11498  assert(node != NULL);
11499  assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
11500  assert(havechange != NULL);
11501 
11502  blkmem = exprgraph->blkmem;
11503  assert(blkmem != NULL);
11504 
11505  SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
11506 
11507  /* if all children are constants, then turn this node into constant */
11508  for( i = 0; i < node->nchildren; ++i )
11509  if( node->children[i]->op != SCIP_EXPR_CONST )
11510  break;
11511  if( node->nchildren > 0 && i == node->nchildren )
11512  {
11513  /* get value of node */
11515  assert(node->value != SCIP_INVALID); /*lint !e777*/
11516 
11517  SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
11518  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11519  SCIPdebugPrintf("\n");
11520 
11521  /* free expression data */
11522  if( exprOpTable[node->op].freedata != NULL )
11523  exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
11524 
11525  /* disconnect from children */
11526  for( i = 0; i < node->nchildren; ++i )
11527  {
11528  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11529  }
11530  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11531  node->nchildren = 0;
11532 
11533  /* turn into constant expression */
11534  node->op = SCIP_EXPR_CONST;
11535  node->data.dbl = node->value;
11536 
11537  *havechange = TRUE;
11538  node->simplified = TRUE;
11539 
11540  return SCIP_OKAY;
11541  }
11542 
11543  /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
11544  * @todo log(product) -> sum(log)
11545  * @todo product(exp) -> exp(sum)
11546  * @todo exp(x)^p -> exp(p*x)
11547  * @todo exp(const*log(x)) -> x^const
11548  */
11549 
11550  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
11551 
11552  if( node->op != SCIP_EXPR_POLYNOMIAL )
11553  {
11554  node->simplified = TRUE;
11555  return SCIP_OKAY;
11556  }
11557 
11558  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11559  assert(polynomialdata != NULL);
11560 
11561  orignchildren = node->nchildren;
11562 
11563  /* check if we have duplicate children and merge */
11565  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11566 
11567  SCIPdebugMessage("expand factors in expression node ");
11568  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11569  SCIPdebugPrintf("\n");
11570 
11571  childmap = NULL;
11572  childmapsize = 0;
11573 
11574  /* resolve children that are constants
11575  * we do this first, because it reduces the degree and number of factors in the monomials,
11576  * 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
11577  */
11578  for( i = 0; i < node->nchildren; ++i )
11579  {
11580  if( node->children[i] == NULL )
11581  continue;
11582 
11583  /* convert children to polynomial, if not constant or polynomial
11584  * if child was simplified in this round, it may have already been converted, and then nothing happens
11585  * but if child was already simplified, then it was not converted, and thus we try it here
11586  */
11587  if( node->children[i]->op != SCIP_EXPR_CONST )
11588  continue;
11589 
11590  SCIPdebugMessage("expand child %d in expression node ", i);
11591  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11592  SCIPdebugPrintf("\n\tchild = ");
11593  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11594  SCIPdebugPrintf("\n");
11595 
11596  removechild = TRUE; /* we intend to release children[i] */
11597 
11598  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11599 
11600  /* put constant of child i into every monomial where child i is used */
11601  for( j = 0; j < polynomialdata->nmonomials; ++j )
11602  {
11603  int factorpos;
11604 
11605  monomial = polynomialdata->monomials[j];
11606  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11607  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11608 
11609  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11610  {
11611  assert(factorpos >= 0);
11612  assert(factorpos < monomial->nfactors);
11613  /* assert that factors have been merged */
11614  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11615  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11616 
11617  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11618 
11619  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 ) /*lint !e835*/
11620  {
11621  /* if constant is negative and our exponent is not integer, then cannot do expansion */
11622  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
11623  removechild = FALSE;
11624  }
11625  else
11626  {
11627  monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
11628 
11629  /* move last factor to position factorpos */
11630  if( factorpos < monomial->nfactors-1 )
11631  {
11632  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
11633  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
11634  }
11635  --monomial->nfactors;
11636  monomial->sorted = FALSE;
11637  polynomialdata->sorted = FALSE;
11638 
11639  *havechange = TRUE;
11640  }
11641  }
11642  }
11643 
11644  /* forget about child i, if it is not used anymore */
11645  if( removechild )
11646  {
11647  /* remove node from list of parents of child i */
11648  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11649  node->children[i] = NULL;
11650  }
11651 
11652  /* simplify current polynomial again */
11653  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11654  }
11655 
11656  /* resolve children that are polynomials itself */
11657  for( i = 0; i < node->nchildren; ++i )
11658  {
11659  if( node->children[i] == NULL )
11660  continue;
11661 
11662  /* convert children to polynomial, if not constant or polynomial
11663  * if child was simplified in this round, it may have already been converted, and then nothing happens
11664  * but if child was already simplified, then it was not converted, and thus we try it here
11665  */
11666  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
11667 
11668  if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
11669  continue;
11670 
11671  SCIPdebugMessage("expand child %d in expression node %p = ", i, (void*)node);
11672  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11673  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n\tchild = ") );
11674  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11675  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
11676 
11677  removechild = TRUE; /* we intend to release children[i] */
11678 
11679  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11680 
11681  /* add children of child i to node */
11682  SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
11683 
11684  /* put polynomial of child i into every monomial where child i is used */
11685  j = 0;
11686  while( j < polynomialdata->nmonomials )
11687  {
11688  int factorpos;
11689  SCIP_Bool success;
11690 
11691  monomial = polynomialdata->monomials[j];
11692  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11693  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11694 
11695  /* make sure factors are merged, should only be potentially necessary if not sorted, see also #1848 */
11696  if( !monomial->sorted )
11697  SCIPexprMergeMonomialFactors(monomial, eps);
11698 
11699  if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11700  {
11701  ++j;
11702  continue;
11703  }
11704 
11705  assert(factorpos >= 0);
11706  assert(factorpos < monomial->nfactors);
11707  /* assert that factors have been merged */
11708  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11709  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11710 
11711  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11712 
11713  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
11714  (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
11715 
11716  if( !success )
11717  {
11718  removechild = FALSE;
11719  ++j;
11720  }
11721  else
11722  *havechange = TRUE;
11723 
11724  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
11725  * we thus repeat with index j, if a factor was successfully expanded
11726  */
11727  }
11728 
11729  /* forget about child i, if it is not used anymore */
11730  if( removechild )
11731  {
11732  /* remove node from list of parents of child i */
11733  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11734  node->children[i] = NULL;
11735  }
11736  }
11737 
11738  /* simplify current polynomial again */
11739  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11740 
11741  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
11742 
11743  /* check which children are still in use */
11744  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
11745  BMSclearMemoryArray(childinuse, node->nchildren); /*lint !e644*/
11746  for( i = 0; i < polynomialdata->nmonomials; ++i )
11747  {
11748  monomial = polynomialdata->monomials[i];
11749  assert(monomial != NULL);
11750 
11751  for( j = 0; j < monomial->nfactors; ++j )
11752  {
11753  assert(monomial->childidxs[j] >= 0);
11754  assert(monomial->childidxs[j] < node->nchildren);
11755  childinuse[monomial->childidxs[j]] = TRUE;
11756  }
11757  }
11758 
11759  /* free children that are not used in any monomial */
11760  for( i = 0; i < node->nchildren; ++i )
11761  if( node->children[i] != NULL && !childinuse[i] )
11762  {
11763  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11764  node->children[i] = NULL;
11765  }
11766 
11767  BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
11768 
11769  /* remove NULLs from children array */
11771 
11772  /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
11773  if( node->nchildren == 0 )
11774  {
11775  SCIP_Real val;
11776 
11777  /* if no children, then it should also have no monomials */
11778  assert(polynomialdata->nmonomials == 0);
11779 
11780  val = polynomialdata->constant;
11781  polynomialdataFree(blkmem, &polynomialdata);
11782 
11783  node->op = SCIP_EXPR_CONST;
11784  node->data.dbl = val;
11785  node->value = val;
11786  }
11787 
11788  /* if no factor in a monomial was replaced, the number of children should not have changed
11789  * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11790  */
11791  *havechange |= (node->nchildren < orignchildren); /*lint !e514*/
11792 
11793  node->simplified = TRUE;
11794 
11795  SCIPdebugMessage("-> %p = ", (void*)node);
11796  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11797  SCIPdebugPrintf("\n");
11798 
11799  return SCIP_OKAY;
11800 }
11801 
11802 /** creates an expression from a given node in an expression graph
11803  *
11804  * Assembles mapping of variables from graph to tree.
11805  */
11806 static
11808  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11809  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which expression should be created */
11810  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
11811  int* nexprvars, /**< current number of variables in expression */
11812  int* varidx /**< current mapping of variable indices from graph to expression */
11813  )
11814 {
11815  SCIP_EXPR** childexprs;
11816  int i;
11817 
11818  assert(exprgraph != NULL);
11819  assert(node != NULL);
11820  assert(expr != NULL);
11821  assert(nexprvars != NULL);
11822  assert(*nexprvars >= 0);
11823  assert(varidx != NULL);
11824 
11825  childexprs = NULL;
11826  if( node->nchildren > 0 )
11827  {
11828  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11829  for( i = 0; i < node->nchildren; ++i )
11830  {
11831  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) ); /*lint !e613*/
11832  }
11833  }
11834 
11835  switch( node->op )
11836  {
11837  case SCIP_EXPR_VARIDX:
11838  {
11839  /* check if the variable already has an index assigned in the expression tree
11840  * if not, create one and increase nexprvars
11841  */
11842  assert(node->data.intval >= 0);
11843  assert(node->data.intval < exprgraph->nvars);
11844  assert(varidx[node->data.intval] >= -1);
11845  assert(varidx[node->data.intval] < *nexprvars);
11846  if( varidx[node->data.intval] == -1 )
11847  {
11848  varidx[node->data.intval] = *nexprvars;
11849  ++*nexprvars;
11850  }
11851 
11852  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11853  break;
11854  }
11855 
11856  case SCIP_EXPR_CONST:
11857  {
11858  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11859  break;
11860  }
11861 
11862  case SCIP_EXPR_REALPOWER:
11863  case SCIP_EXPR_SIGNPOWER:
11864  {
11865  assert(node->nchildren == 1);
11866  assert(childexprs != NULL);
11867  /* coverity[var_deref_op] */
11868  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11869  break;
11870  }
11871 
11872  case SCIP_EXPR_INTPOWER:
11873  {
11874  assert(node->nchildren == 1);
11875  assert(childexprs != NULL);
11876  /* coverity[var_deref_op] */
11877  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11878  break;
11879  }
11880 
11881  case SCIP_EXPR_PLUS:
11882  case SCIP_EXPR_MINUS:
11883  case SCIP_EXPR_MUL:
11884  case SCIP_EXPR_DIV:
11885  case SCIP_EXPR_MIN:
11886  case SCIP_EXPR_MAX:
11887  {
11888  assert(node->nchildren == 2);
11889  assert(childexprs != NULL);
11890  /* coverity[var_deref_op] */
11891  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11892  break;
11893  }
11894 
11895  case SCIP_EXPR_SQUARE:
11896  case SCIP_EXPR_SQRT:
11897  case SCIP_EXPR_EXP:
11898  case SCIP_EXPR_LOG:
11899  case SCIP_EXPR_SIN:
11900  case SCIP_EXPR_COS:
11901  case SCIP_EXPR_TAN:
11902  /* case SCIP_EXPR_ERF: */
11903  /* case SCIP_EXPR_ERFI: */
11904  case SCIP_EXPR_ABS:
11905  case SCIP_EXPR_SIGN:
11906  {
11907  assert(node->nchildren == 1);
11908  assert(childexprs != NULL);
11909  /* coverity[var_deref_op] */
11910  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11911  break;
11912  }
11913 
11914  case SCIP_EXPR_SUM:
11915  case SCIP_EXPR_PRODUCT:
11916  {
11917  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11918  break;
11919  }
11920 
11921  case SCIP_EXPR_LINEAR:
11922  {
11923  assert(node->data.data != NULL);
11924 
11925  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11926  break;
11927  }
11928 
11929  case SCIP_EXPR_QUADRATIC:
11930  {
11931  SCIP_EXPRDATA_QUADRATIC* quaddata;
11932 
11933  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11934  assert(quaddata != NULL);
11935 
11936  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11937  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11938  break;
11939  }
11940 
11941  case SCIP_EXPR_POLYNOMIAL:
11942  {
11943  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11944 
11945  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11946  assert(polynomialdata != NULL);
11947 
11948  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11949  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11950 
11951  break;
11952  }
11953 
11954  case SCIP_EXPR_USER:
11955  {
11956  SCIP_EXPRDATA_USER* exprdata;
11957  SCIP_USEREXPRDATA* userdata;
11958 
11959  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11960  assert(exprdata != NULL);
11961 
11962  if( exprdata->copydata != NULL )
11963  {
11964  SCIP_CALL( exprdata->copydata(exprgraph->blkmem, node->nchildren, exprdata->userdata, &userdata) );
11965  }
11966  else
11967  userdata = exprdata->userdata;
11968 
11969  /* coverity[var_deref_op] */
11970  SCIP_CALL( SCIPexprCreateUser(exprgraph->blkmem, expr, node->nchildren, childexprs,
11971  userdata, exprdata->evalcapability, exprdata->eval, exprdata->inteval, exprdata->curv, exprdata->prop, exprdata->estimate, exprdata->copydata, exprdata->freedata, exprdata->print) );
11972 
11973  break;
11974  }
11975 
11976  case SCIP_EXPR_LAST:
11977  case SCIP_EXPR_PARAM:
11978  {
11979  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11980  return SCIP_ERROR;
11981  }
11982  }
11983 
11984  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11985 
11986  return SCIP_OKAY;
11987 }
11988 
11989 /** counts how often expression graph variables are used in a subtree of the expression graph
11990  *
11991  * @note The function does not clear the array first, but only increases already existing counts.
11992  */
11993 static
11995  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11996  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11997  )
11998 {
11999  int i;
12000 
12001  assert(node != NULL);
12002  assert(varsusage != NULL);
12003 
12004  if( node->op == SCIP_EXPR_VARIDX )
12005  {
12006  ++varsusage[node->data.intval];
12007  return;
12008  }
12009 
12010  for( i = 0; i < node->nchildren; ++i )
12011  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
12012 }
12013 
12014 /** checks whether a node can be put into a component when checking block separability of an expression
12015  *
12016  * If a variable used by node is already in another component, components are merged and component number is updated.
12017  */
12018 static
12020  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
12021  int* compnr, /**< component number to assign, may be reduced if variables overlap */
12022  int nchildcomps, /**< number of entries for which childcomps have been set already */
12023  int* childcomps, /**< component numbers of children */
12024  int nvars, /**< number of variables */
12025  int* varcomps /**< component numbers of variables */
12026  )
12027 {
12028  int varidx;
12029  int i;
12030 
12031  assert(node != NULL);
12032  assert(compnr != NULL);
12033  assert(*compnr >= 0);
12034  assert(childcomps != NULL);
12035  assert(varcomps != NULL);
12036 
12037  if( node->op != SCIP_EXPR_VARIDX )
12038  {
12039  for( i = 0; i < node->nchildren; ++i )
12040  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
12041  return;
12042  }
12043 
12044  varidx = node->data.intval;
12045  assert(varidx >= 0);
12046  assert(varidx < nvars);
12047 
12048  if( varcomps[varidx] == -1 )
12049  {
12050  /* first time we get to this variable, so set it's component to compnr and we are done */
12051  varcomps[varidx] = *compnr;
12052  return;
12053  }
12054 
12055  if( varcomps[varidx] == *compnr )
12056  {
12057  /* variable is already in current component, that's also good and we are done */
12058  return;
12059  }
12060 
12061  /* variable is already in another component, so have to merge component compnr into that component
12062  * do this by updating varcomps and childcomps */
12063  for( i = 0; i < nvars; ++i )
12064  if( varcomps[i] == *compnr )
12065  varcomps[i] = varcomps[varidx];
12066  for( i = 0; i < nchildcomps; ++i )
12067  if( childcomps[i] == *compnr )
12068  /* coverity[copy_paste_error] */
12069  childcomps[i] = varcomps[varidx];
12070  *compnr = varcomps[varidx];
12071 }
12072 
12073 /**@} */
12074 
12075 /**@name Expression graph private methods */
12076 /**@{ */
12077 
12078 /** assert that expression graph has at least a given depth */
12079 static
12081  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
12082  int mindepth /**< minimal depth that should be ensured */
12083  )
12084 {
12085  int olddepth;
12086 
12087  assert(exprgraph != NULL);
12088  assert(exprgraph->blkmem != NULL);
12089 
12090  if( mindepth <= exprgraph->depth )
12091  return SCIP_OKAY;
12092 
12093  olddepth = exprgraph->depth;
12094  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
12095  assert(exprgraph->depth >= mindepth);
12096 
12097  /* initialize new array entries to 0 and NULL, resp. */
12098  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12099  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12100  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12101 
12102  return SCIP_OKAY;
12103 }
12104 
12105 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
12106 static
12108  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12109  int varidx /**< variable index */
12110  )
12111 {
12112  SCIP_EXPRGRAPHNODE* varnode;
12113  void* var;
12114 
12115  assert(exprgraph != NULL);
12116  assert(varidx >= 0);
12117  assert(varidx < exprgraph->nvars);
12118 
12119  varnode = exprgraph->varnodes[varidx];
12120  assert(varnode->data.intval == varidx);
12121 
12122  var = exprgraph->vars[varidx];
12123 
12124  /* call varremove callback method, if set */
12125  if( exprgraph->exprgraphvarremove != NULL )
12126  {
12127  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
12128  }
12129 
12130  /* remove variable from hashmap */
12131  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
12132 
12133  /* move last variable to position varidx and give it the new index */
12134  if( varidx < exprgraph->nvars-1 )
12135  {
12136  /* call callback method, if set */
12137  if( exprgraph->exprgraphvarchgidx != NULL )
12138  {
12139  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
12140  }
12141 
12142  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
12143  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
12144  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
12145  exprgraph->varnodes[varidx]->data.intval = varidx;
12146  SCIP_CALL( SCIPhashmapSetImageInt(exprgraph->varidxs, exprgraph->vars[varidx], varidx) );
12147  }
12148  --exprgraph->nvars;
12149 
12150  return SCIP_OKAY;
12151 }
12152 
12153 /** moves a node in an expression graph to a different depth
12154  *
12155  * New depth must be larger than children depth.
12156  * Moves parent nodes to higher depth, if needed.
12157  * Variable nodes cannot be moved.
12158  */
12159 static
12161  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12162  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
12163  int newdepth /**< new depth to which to move node */
12164  )
12165 {
12166  int olddepth;
12167  int oldpos;
12168  int i;
12169 
12170  assert(exprgraph != NULL);
12171  assert(node != NULL);
12172  assert(node->depth >= 0); /* node should be in graph */
12173  assert(newdepth >= 0);
12174 
12175  /* if already on aimed depth, then don't need to move */
12176  if( node->depth == newdepth )
12177  return SCIP_OKAY;
12178 
12179  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
12180 
12181 #ifndef NDEBUG
12182  /* assert that children are at lower depth than new depth */
12183  for( i = 0; i < node->nchildren; ++i )
12184  assert(node->children[i]->depth < newdepth);
12185 #endif
12186 
12187  /* move parents to higher depth, if needed */
12188  for( i = 0; i < node->nparents; ++i )
12189  {
12190  if( node->parents[i]->depth <= newdepth )
12191  {
12192  /* move parent to depth+1 */
12193  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
12194  assert(node->parents[i]->depth > newdepth);
12195  }
12196  }
12197 
12198  /* ensure that graph is deep enough */
12199  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
12200  assert(exprgraph->depth > newdepth);
12201 
12202  olddepth = node->depth;
12203  oldpos = node->pos;
12204 
12205  /* add node to new depth */
12206  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
12207  node->depth = newdepth;
12208  node->pos = exprgraph->nnodes[newdepth];
12209  exprgraph->nodes[newdepth][node->pos] = node;
12210  ++exprgraph->nnodes[newdepth];
12211 
12212  /* 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) */
12213  for( i = 0; i < node->nchildren; ++i )
12214  node->children[i]->parentssorted = FALSE;
12215 
12216  /* move last node at previous depth to previous position, if it wasn't last */
12217  if( oldpos < exprgraph->nnodes[olddepth]-1 )
12218  {
12219  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
12220  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
12221 
12222  /* 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) */
12223  for( i = 0; i < exprgraph->nodes[olddepth][oldpos]->nchildren; ++i )
12224  exprgraph->nodes[olddepth][oldpos]->children[i]->parentssorted = FALSE;
12225  }
12226  --exprgraph->nnodes[olddepth];
12227 
12228  if( node->depth == 0 )
12229  {
12230  /* if at depth 0, then it need to be a node for either a constant or a variable */
12231  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
12232  if( node->op == SCIP_EXPR_CONST )
12233  {
12234  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
12235  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
12236  exprgraph->constnodes[exprgraph->nconsts] = node;
12237  ++exprgraph->nconsts;
12238  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
12239  }
12240  else
12241  {
12242  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
12243  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
12244  return SCIP_ERROR;
12245  }
12246 
12247  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
12248  node->curv = SCIP_EXPRCURV_LINEAR;
12249  }
12250 
12251  return SCIP_OKAY;
12252 }
12253 
12254 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
12255 static
12257  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12258  int nchildren, /**< number of children */
12259  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
12260  SCIP_EXPROP op, /**< operator */
12261  SCIP_EXPROPDATA opdata, /**< operator data */
12262  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
12263  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
12264  )
12265 {
12266  SCIP_EXPRGRAPHNODE** parentcands;
12267  int nparentcands;
12268  int parentcandssize;
12269  int i;
12270  int p;
12271 
12272  assert(exprgraph != NULL);
12273  assert(nchildren > 0);
12274  assert(children != NULL);
12275  assert(parent != NULL);
12276 
12277  *parent = NULL;
12278 
12279  /* create initial set of parent candidates as
12280  * all parents of first child that have the same operator type and the same number of children
12281  * additionally, some easy conditions for complex expression types:
12282  * if expression type is int/real/signpower, then compare also exponent,
12283  * if expression type is linear, then compare also constant part,
12284  * if expression type is quadratic, then compare also number of quadratic elements,
12285  * if expression type is polynomial, then compare also number of monmials and constant part
12286  */
12287  parentcandssize = children[0]->nparents;
12288  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
12289  nparentcands = 0;
12290  for( p = 0; p < children[0]->nparents; ++p )
12291  if( children[0]->parents[p]->op == op &&
12292  children[0]->parents[p]->nchildren == nchildren &&
12293  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
12294  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12295  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12296  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
12297  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
12298  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
12299  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
12300  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
12301  )
12302  {
12303  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
12304  }
12305 
12306  /* for all remaining children, remove parent candidates, that are not in their list of parents */
12307  for( i = 1; i < nchildren && nparentcands > 0; ++i )
12308  {
12309  p = 0;
12310  while( p < nparentcands )
12311  {
12312  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
12313  * otherwise keep candidate and check next one
12314  */
12315  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
12316  {
12317  parentcands[p] = parentcands[nparentcands-1];
12318  --nparentcands;
12319  }
12320  else
12321  ++p;
12322  }
12323  }
12324 
12325  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
12326 
12327  if( nparentcands == 0 )
12328  {
12329  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
12330  return SCIP_OKAY;
12331  }
12332 
12333  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
12334  * check if there is also one which corresponds to same expression and store that one in *parent
12335  */
12336  switch( op )
12337  {
12338  /* commutative operands with no data */
12339  case SCIP_EXPR_PLUS :
12340  case SCIP_EXPR_MUL :
12341  case SCIP_EXPR_MIN :
12342  case SCIP_EXPR_MAX :
12343  case SCIP_EXPR_SUM :
12344  case SCIP_EXPR_PRODUCT:
12345  case SCIP_EXPR_SQUARE :
12346  case SCIP_EXPR_SQRT :
12347  case SCIP_EXPR_EXP :
12348  case SCIP_EXPR_LOG :
12349  case SCIP_EXPR_SIN :
12350  case SCIP_EXPR_COS :
12351  case SCIP_EXPR_TAN :
12352  /* case SCIP_EXPR_ERF : */
12353  /* case SCIP_EXPR_ERFI : */
12354  case SCIP_EXPR_ABS :
12355  case SCIP_EXPR_SIGN :
12356  {
12357  /* sort childnodes, if needed for later */
12358  if( nchildren > 2 )
12359  SCIPsortPtr((void**)children, exprgraphnodecomp, nchildren);
12360  for( p = 0; p < nparentcands; ++p )
12361  {
12362  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12363  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12364 
12365  if( nchildren == 1 )
12366  {
12367  assert(parentcands[p]->children[0] == children[0]);
12368  /* same operand, same child, so same expression */
12369  *parent = parentcands[p];
12370  break;
12371  }
12372  else if( nchildren == 2 )
12373  {
12374  /* We know that every node in children is also a child of parentcands[p].
12375  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
12376  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
12377  */
12378  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
12379  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
12380  {
12381  *parent = parentcands[p];
12382  break;
12383  }
12384  }
12385  else
12386  {
12387  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
12388 
12389  /* sort children of parent candidate */
12390  SCIPsortPtr((void**)parentcands[p]->children, exprgraphnodecomp, nchildren);
12391 
12392  /* check if childnodes and parentcands[p]->children are the same */
12393  for( i = 0; i < nchildren; ++i )
12394  if( children[i] != parentcands[p]->children[i] )
12395  break;
12396  if( i == nchildren )
12397  {
12398  /* yeah, found an exact match */
12399  *parent = parentcands[p];
12400  break;
12401  }
12402  }
12403  }
12404 
12405  break;
12406  }
12407 
12408  /* non-commutative operands with two children */
12409  case SCIP_EXPR_MINUS :
12410  case SCIP_EXPR_DIV :
12411  {
12412  for( p = 0; p < nparentcands; ++p )
12413  {
12414  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12415  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
12416  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
12417  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
12418  {
12419  /* yeah, found one */
12420  *parent = parentcands[p];
12421  break;
12422  }
12423  }
12424 
12425  break;
12426  }
12427 
12428  /* operands with one child and data */
12429  case SCIP_EXPR_INTPOWER:
12430  {
12431  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12432  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12433  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12434  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
12435 
12436  /* yeah, have one with same exponent */
12437  *parent = parentcands[0];
12438 
12439  break;
12440  }
12441 
12442  case SCIP_EXPR_REALPOWER:
12443  case SCIP_EXPR_SIGNPOWER:
12444  {
12445  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12446  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12447  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12448  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
12449 
12450  /* yeah, have one with same exponent */
12451  *parent = parentcands[0];
12452 
12453  break;
12454  }
12455 
12456  /* commutative operands with n children and data */
12457  case SCIP_EXPR_LINEAR:
12458  {
12459  SCIP_Real* exprcoef;
12460  SCIP_Real* candcoef;
12461 
12462  exprcoef = (SCIP_Real*)opdata.data;
12463  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
12464  if( exprchildren != NULL )
12465  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, exprgraphnodecomp, nchildren);
12466  else
12467  SCIPsortPtrReal((void**)children, exprcoef, exprgraphnodecomp, nchildren);
12468  for( p = 0; p < nparentcands; ++p )
12469  {
12470  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12471  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12472 
12473  candcoef = (SCIP_Real*)parentcands[p]->data.data;
12474  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12475 
12476  /* sort children of parent candidate */
12477  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, exprgraphnodecomp, nchildren);
12478 
12479  /* check if children and coefficients in parent candidate and expression are the same */
12480  for( i = 0; i < nchildren; ++i )
12481  {
12482  if( children[i] != parentcands[p]->children[i] )
12483  break;
12484  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
12485  break;
12486  }
12487  if( i < nchildren )
12488  continue;
12489 
12490  /* yeah, found an exact match */
12491  *parent = parentcands[p];
12492  break;
12493  }
12494 
12495  break;
12496  }
12497 
12498  case SCIP_EXPR_QUADRATIC:
12499  {
12500  SCIP_EXPRDATA_QUADRATIC* exprdata;
12501  SCIP_Real* exprlincoef;
12502  SCIP_Real* candlincoef;
12503  SCIP_EXPRDATA_QUADRATIC* canddata;
12504  int* perm;
12505  int* invperm;
12506 
12507  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
12508  exprlincoef = exprdata->lincoefs;
12509 
12510  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
12511 
12512  /* sort expr->children and childnodes and store inverse permutation in invperm */
12513  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12514  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12515  for( i = 0; i < nchildren; ++i )
12516  invperm[i] = i; /*lint !e644*/
12517 
12518  if( exprlincoef != NULL )
12519  if( exprchildren != NULL )
12520  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12521  else
12522  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12523  else
12524  if( exprchildren != NULL )
12525  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12526  else
12527  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12528 
12529  /* compute permutation from its inverse */
12530  for( i = 0; i < nchildren; ++i )
12531  perm[invperm[i]] = i; /*lint !e644*/
12532 
12533  /* apply permuation to exprdata->quadelems and sort again */
12534  for( i = 0; i < exprdata->nquadelems; ++i )
12535  {
12536  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
12537  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
12538  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
12539  {
12540  int tmp;
12541  tmp = exprdata->quadelems[i].idx1;
12542  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
12543  exprdata->quadelems[i].idx2 = tmp;
12544  }
12545  }
12546  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
12547  exprdata->sorted = TRUE;
12548 
12549  for( p = 0; p < nparentcands; ++p )
12550  {
12551  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12552  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12553 
12554  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
12555  candlincoef = canddata->lincoefs;
12556  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
12557  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12558 
12559  /* sort parentcands[p]->children and store inverse permutation in invperm */
12560  for( i = 0; i < nchildren; ++i )
12561  invperm[i] = i;
12562 
12563  if( candlincoef != NULL )
12564  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, exprgraphnodecomp, parentcands[p]->nchildren);
12565  else
12566  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12567 
12568  /* compute permutation from its inverse */
12569  for( i = 0; i < nchildren; ++i )
12570  perm[invperm[i]] = i;
12571 
12572  /* apply permutation to canddata->quadelems */
12573  for( i = 0; i < canddata->nquadelems; ++i )
12574  {
12575  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
12576  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
12577  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
12578  {
12579  int tmp;
12580  tmp = canddata->quadelems[i].idx1;
12581  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
12582  canddata->quadelems[i].idx2 = tmp;
12583  }
12584  }
12585  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
12586  canddata->sorted = TRUE;
12587 
12588  /* check if children and linear coefficients in parent candidate and expression are the same */
12589  for( i = 0; i < nchildren; ++i )
12590  {
12591  if( children[i] != parentcands[p]->children[i] )
12592  break;
12593  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
12594  break;
12595  }
12596  if( i < nchildren )
12597  continue;
12598 
12599  assert(exprdata->nquadelems == canddata->nquadelems);
12600  for( i = 0; i < exprdata->nquadelems; ++i )
12601  {
12602  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
12603  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
12604  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
12605  break;
12606  }
12607  if( i == exprdata->nquadelems )
12608  {
12609  /* yeah, parentcands[p] is same quadratic expression as expr */
12610  *parent = parentcands[p];
12611  break;
12612  }
12613  }
12614 
12615  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12616  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12617 
12618  break;
12619  }
12620 
12621  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
12622  case SCIP_EXPR_POLYNOMIAL:
12623  {
12624  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
12625  SCIP_EXPRDATA_POLYNOMIAL* canddata;
12626  int* perm;
12627  int* invperm;
12628 
12629  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
12630 
12631  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
12632 
12633  /* sort exprchildren and childnodes and store inverse permutation in invperm */
12634  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12635  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12636  for( i = 0; i < nchildren; ++i )
12637  invperm[i] = i; /*lint !e644*/
12638 
12639  if( exprchildren != NULL )
12640  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12641  else
12642  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12643 
12644  /* compute permutation from its inverse */
12645  for( i = 0; i < nchildren; ++i )
12646  perm[invperm[i]] = i; /*lint !e644*/
12647 
12648  /* apply permutation to exprdata and sort again */
12649  polynomialdataApplyChildmap(exprdata, perm);
12650  polynomialdataSortMonomials(exprdata);
12651 
12652  for( p = 0; p < nparentcands; ++p )
12653  {
12654  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12655  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12656 
12657  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
12658  assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
12659  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12660 
12661  /* sort parentcands[p]->children and store inverse permutation in invperm */
12662  for( i = 0; i < nchildren; ++i )
12663  invperm[i] = i;
12664 
12665  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12666 
12667  /* compute permutation from its inverse */
12668  for( i = 0; i < nchildren; ++i )
12669  perm[invperm[i]] = i;
12670 
12671  /* apply permutation to canddata and sort again */
12672  polynomialdataApplyChildmap(canddata, perm);
12673  polynomialdataSortMonomials(canddata);
12674 
12675  /* check if children are equal */
12676  for( i = 0; i < nchildren; ++i )
12677  if( children[i] != parentcands[p]->children[i] )
12678  break;
12679  if( i < nchildren )
12680  continue;
12681 
12682  /* check if monomials are equal */
12683  for( i = 0; i < exprdata->nmonomials; ++i )
12684  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
12685  break;
12686  if( i == exprdata->nmonomials )
12687  {
12688  /* yeah, parentcands[p] is same polynomial expression as expr */
12689  *parent = parentcands[p];
12690  break;
12691  }
12692  }
12693 
12694  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12695  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12696 
12697  break;
12698  }
12699 
12700  case SCIP_EXPR_USER:
12701  {
12702  /* @todo need comparison function on user data to decide whether a parent candidate fits */
12703  break;
12704  }
12705 
12706  case SCIP_EXPR_VARIDX:
12707  case SCIP_EXPR_PARAM:
12708  case SCIP_EXPR_CONST:
12709  case SCIP_EXPR_LAST:
12710  SCIPerrorMessage("expression operand %d unexpected here\n", op);
12711  return SCIP_ERROR;
12712  }
12713 
12714  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
12715 
12716  return SCIP_OKAY;
12717 }
12718 
12719 /** adds an expression into an expression graph
12720  *
12721  * Enables corresponding nodes.
12722  */
12723 static
12725  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12726  SCIP_EXPR* expr, /**< expression to add */
12727  void** vars, /**< variables corresponding to VARIDX expressions */
12728  SCIP_Real* params, /**< parameter values */
12729  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
12730  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12731  )
12732 {
12733  SCIP_EXPRGRAPHNODE** childnodes;
12734  SCIP_Bool childisnew;
12735  SCIP_Bool nochildisnew;
12736  SCIP_EXPROPDATA opdata;
12737  int i;
12738 
12739  assert(exprgraph != NULL);
12740  assert(expr != NULL);
12741  assert(exprnode != NULL);
12742  assert(exprnodeisnew != NULL);
12743 
12744  if( expr->op == SCIP_EXPR_VARIDX )
12745  {
12746  /* find node corresponding to variable and add if not existing yet */
12747  assert(expr->nchildren == 0);
12748 
12749  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12750  assert(*exprnode != NULL);
12751  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12752  assert((*exprnode)->data.intval >= 0);
12753  assert((*exprnode)->data.intval < exprgraph->nvars);
12754  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12755 
12756  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12757 
12758  return SCIP_OKAY;
12759  }
12760 
12761  if( expr->op == SCIP_EXPR_CONST )
12762  {
12763  /* find node corresponding to constant and add if not existing yet */
12764  assert(expr->nchildren == 0);
12765 
12766  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12767  assert(*exprnode != NULL);
12768  assert((*exprnode)->op == SCIP_EXPR_CONST);
12769  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
12770 
12771  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12772 
12773  return SCIP_OKAY;
12774  }
12775 
12776  if( expr->op == SCIP_EXPR_PARAM )
12777  {
12778  /* find node corresponding to constant corresponding to parameter and add if not existing yet */
12779  assert(expr->nchildren == 0);
12780  assert(params != NULL);
12781 
12782  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, params[expr->data.intval], exprnode) );
12783  assert(*exprnode != NULL);
12784  assert((*exprnode)->op == SCIP_EXPR_CONST);
12785  assert((*exprnode)->data.dbl == params[expr->data.intval]); /*lint !e777*/
12786 
12787  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12788 
12789  return SCIP_OKAY;
12790  }
12791 
12792  /* expression should be variable or constant or have children */
12793  assert(expr->nchildren > 0);
12794 
12795  /* add children expressions into expression graph
12796  * check if we can find a common parent
12797  */
12798  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12799  nochildisnew = TRUE;
12800  for( i = 0; i < expr->nchildren; ++i )
12801  {
12802  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, params, &childnodes[i], &childisnew) ); /*lint !e644*/
12803  assert(childnodes[i] != NULL);
12804  nochildisnew &= !childisnew; /*lint !e514*/
12805  }
12806 
12807  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12808  if( nochildisnew )
12809  {
12810  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12811 
12812  if( *exprnode != NULL )
12813  {
12814  /* node already existing, make sure it is enabled */
12815  (*exprnode)->enabled = TRUE;
12816  *exprnodeisnew = FALSE;
12817 
12818  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12819  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12820  * SCIPdebugPrintf("\n");
12821  */
12822 
12823  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12824  return SCIP_OKAY;
12825  }
12826  }
12827 
12828  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12829 
12830  /* copy expression data */
12831  if( exprOpTable[expr->op].copydata != NULL )
12832  {
12833  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12834  }
12835  else
12836  {
12837  opdata = expr->data;
12838  }
12839 
12840  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12841  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12842  *exprnodeisnew = TRUE;
12843 
12844  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12845 
12846  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12847  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12848  * SCIPdebugPrintf("\n");
12849  */
12850 
12851  return SCIP_OKAY;
12852 }
12853 
12854 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12855 static
12857  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12858  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12859  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12860  )
12861 {
12862  SCIP_EXPRGRAPHNODE* node;
12863  int i;
12864  int p;
12865 
12866  assert(exprgraph != NULL);
12867  assert(clearreverseprop != NULL);
12868  assert(boundchanged != NULL);
12869 
12870  *boundchanged = FALSE;
12871  for( i = 0; i < exprgraph->nvars; ++i )
12872  {
12873  node = exprgraph->varnodes[i];
12874 
12875  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12876  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12877  {
12879  continue;
12880  }
12881 
12882  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12883  {
12884  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12885  SCIP_Real tmp;
12886 
12887  tmp = exprgraph->varbounds[i].inf;
12888  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12889  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12890  }
12891 
12892  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12893  +exprgraph->varbounds[i].sup > node->bounds.sup )
12894  {
12895  for( p = 0; p < node->nparents; ++p )
12897 
12898  node->bounds = exprgraph->varbounds[i];
12899  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12900 
12901  *boundchanged = TRUE;
12902 
12903  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12904  *clearreverseprop = TRUE;
12905  }
12906  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12907  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12908  {
12909  for( p = 0; p < node->nparents; ++p )
12911 
12912  node->bounds = exprgraph->varbounds[i];
12913  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12914 
12915  *boundchanged = TRUE;
12916  }
12917  else
12918  {
12919  node->bounds = exprgraph->varbounds[i];
12920  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12921  }
12922 
12924  }
12925 }
12926 
12927 /**@} */
12928 
12929 /**@name Expression graph node methods */
12930 /**@{ */
12931 
12932 /* In debug mode, the following methods are implemented as function calls to ensure
12933  * type validity.
12934  * In optimized mode, the methods are implemented as defines to improve performance.
12935  * However, we want to have them in the library anyways, so we have to undef the defines.
12936  */
12937 
12938 #undef SCIPexprgraphCaptureNode
12939 #undef SCIPexprgraphIsNodeEnabled
12940 #undef SCIPexprgraphGetNodeNChildren
12941 #undef SCIPexprgraphGetNodeChildren
12942 #undef SCIPexprgraphGetNodeNParents
12943 #undef SCIPexprgraphGetNodeParents
12944 #undef SCIPexprgraphGetNodeDepth
12945 #undef SCIPexprgraphGetNodePosition
12946 #undef SCIPexprgraphGetNodeOperator
12947 #undef SCIPexprgraphGetNodeOperatorIndex
12948 #undef SCIPexprgraphGetNodeOperatorReal
12949 #undef SCIPexprgraphGetNodeVar
12950 #undef SCIPexprgraphGetNodeRealPowerExponent
12951 #undef SCIPexprgraphGetNodeIntPowerExponent
12952 #undef SCIPexprgraphGetNodeSignPowerExponent
12953 #undef SCIPexprgraphGetNodeLinearCoefs
12954 #undef SCIPexprgraphGetNodeLinearConstant
12955 #undef SCIPexprgraphGetNodeQuadraticConstant
12956 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12957 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12958 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12959 #undef SCIPexprgraphGetNodePolynomialMonomials
12960 #undef SCIPexprgraphGetNodePolynomialNMonomials
12961 #undef SCIPexprgraphGetNodePolynomialConstant
12962 #undef SCIPexprgraphGetNodeUserData
12963 #undef SCIPexprgraphHasNodeUserEstimator
12964 #undef SCIPexprgraphGetNodeBounds
12965 #undef SCIPexprgraphGetNodeVal
12966 #undef SCIPexprgraphGetNodeCurvature
12967 
12968 /** captures node, i.e., increases number of uses */
12970  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12971  )
12972 {
12973  assert(node->nuses >= 0);
12974 
12975  SCIPdebugMessage("capture node %p\n", (void*)node);
12976 
12977  ++node->nuses;
12978 }
12979 
12980 /** returns whether a node is currently enabled */
12982  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12983  )
12984 {
12985  assert(node != NULL);
12986 
12987  return node->enabled;
12988 }
12989 
12990 /** gets number of children of a node in an expression graph */
12992  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12993  )
12994 {
12995  assert(node != NULL);
12996 
12997  return node->nchildren;
12998 }
12999 
13000 /** gets children of a node in an expression graph */
13002  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13003  )
13004 {
13005  assert(node != NULL);
13006 
13007  return node->children;
13008 }
13009 
13010 /** gets number of parents of a node in an expression graph */
13012  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13013  )
13014 {
13015  assert(node != NULL);
13016 
13017  return node->nparents;
13018 }
13019 
13020 /** gets parents of a node in an expression graph */
13022  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13023  )
13024 {
13025  assert(node != NULL);
13026 
13027  return node->parents;
13028 }
13029 
13030 /** gets depth of node in expression graph */
13032  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13033  )
13034 {
13035  assert(node != NULL);
13036 
13037  return node->depth;
13038 }
13039 
13040 /** gets position of node in expression graph at its depth level */
13042  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13043  )
13044 {
13045  assert(node != NULL);
13046 
13047  return node->pos;
13048 }
13049 
13050 /** gets operator of a node in an expression graph */
13052  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13053  )
13054 {
13055  assert(node != NULL);
13056 
13057  return node->op;
13058 }
13059 
13060 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
13062  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13063  )
13064 {
13065  assert(node != NULL);
13066  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
13067 
13068  return node->data.intval;
13069 }
13070 
13071 /** gives real belonging to a SCIP_EXPR_CONST operand */
13073  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13074  )
13075 {
13076  assert(node != NULL);
13077  assert(node->op == SCIP_EXPR_CONST);
13078 
13079  return node->data.dbl;
13080 }
13081 
13082 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
13084  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13085  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13086  )
13087 {
13088  assert(exprgraph != NULL);
13089  assert(node != NULL);
13090  assert(node->op == SCIP_EXPR_VARIDX);
13091  assert(node->data.intval >= 0);
13092  assert(node->data.intval < exprgraph->nvars);
13093 
13094  return exprgraph->vars[node->data.intval];
13095 }
13096 
13097 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
13099  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13100  )
13101 {
13102  assert(node != NULL);
13103  assert(node->op == SCIP_EXPR_REALPOWER);
13104 
13105  return node->data.dbl;
13106 }
13107 
13108 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
13110  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13111  )
13112 {
13113  assert(node != NULL);
13114  assert(node->op == SCIP_EXPR_INTPOWER);
13115 
13116  return node->data.intval;
13117 }
13118 
13119 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
13121  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13122  )
13123 {
13124  assert(node != NULL);
13125  assert(node->op == SCIP_EXPR_SIGNPOWER);
13126 
13127  return node->data.dbl;
13128 }
13129 
13130 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
13132  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13133  )
13134 {
13135  assert(node != NULL);
13136  assert(node->op == SCIP_EXPR_LINEAR);
13137 
13138  return (SCIP_Real*)node->data.data;
13139 }
13140 
13141 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
13143  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13144  )
13145 {
13146  assert(node != NULL);
13147  assert(node->op == SCIP_EXPR_LINEAR);
13148  assert(node->data.data != NULL);
13149 
13150  return ((SCIP_Real*)node->data.data)[node->nchildren];
13151 }
13152 
13153 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
13155  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13156  )
13157 {
13158  assert(node != NULL);
13159  assert(node->op == SCIP_EXPR_QUADRATIC);
13160  assert(node->data.data != NULL);
13161 
13162  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
13163 }
13164 
13165 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
13167  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13168  )
13169 {
13170  assert(node != NULL);
13171  assert(node->op == SCIP_EXPR_QUADRATIC);
13172  assert(node->data.data != NULL);
13173 
13174  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
13175 }
13176 
13177 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13179  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13180  )
13181 {
13182  assert(node != NULL);
13183  assert(node->op == SCIP_EXPR_QUADRATIC);
13184  assert(node->data.data != NULL);
13185 
13186  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
13187 }
13188 
13189 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13191  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13192  )
13193 {
13194  assert(node != NULL);
13195  assert(node->op == SCIP_EXPR_QUADRATIC);
13196  assert(node->data.data != NULL);
13197 
13198  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
13199 }
13200 
13201 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13203  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13204  )
13205 {
13206  assert(node != NULL);
13207  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13208  assert(node->data.data != NULL);
13209 
13210  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
13211 }
13212 
13213 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13215  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13216  )
13217 {
13218  assert(node != NULL);
13219  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13220  assert(node->data.data != NULL);
13221 
13222  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
13223 }
13224 
13225 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
13227  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13228  )
13229 {
13230  assert(node != NULL);
13231  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13232  assert(node->data.data != NULL);
13233 
13234  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
13235 }
13236 
13237 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
13238  *
13239  * Assumes that curvature of children and bounds of children and node itself are valid.
13240  */
13242  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13243  int monomialidx, /**< index of monomial */
13244  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
13245  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
13246  )
13247 {
13248  SCIP_EXPRDATA_MONOMIAL* monomial;
13249  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13250  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13251  SCIP_INTERVAL* childbounds = NULL;
13252  SCIP_EXPRCURV* childcurv = NULL;
13253  SCIP_EXPRGRAPHNODE* child;
13254  SCIP_RETCODE retcode = SCIP_OKAY;
13255  int i;
13256 
13257  assert(node != NULL);
13258  assert(node->depth >= 0); /* node should be in graph */
13259  assert(node->pos >= 0); /* node should be in graph */
13260  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13261  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
13262  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13263  assert(node->data.data != NULL);
13264  assert(monomialidx >= 0);
13265  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
13266  assert(curv != NULL);
13267 
13268  if( SCIPintervalIsEmpty(infinity, node->bounds) )
13269  {
13270  *curv = SCIP_EXPRCURV_LINEAR;
13271  return SCIP_OKAY;
13272  }
13273 
13274  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
13275  assert(monomial != NULL);
13276 
13277  /* if many children, get large enough memory to store children bounds */
13278  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13279  {
13280  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13281  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, monomial->nfactors), TERMINATE );
13282  }
13283  else
13284  {
13285  childbounds = childboundsstatic;
13286  childcurv = childcurvstatic;
13287  }
13288 
13289  /* assemble bounds and curvature of children */
13290  for( i = 0; i < monomial->nfactors; ++i )
13291  {
13292  child = node->children[monomial->childidxs[i]];
13293  assert(child != NULL);
13294 
13295  /* child should have valid and non-empty bounds */
13296  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13297  assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13298  /* nodes at depth 0 are always linear */
13299  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13300 
13301  childbounds[i] = child->bounds; /*lint !e644*/
13302  childcurv[i] = child->curv; /*lint !e644*/
13303  }
13304 
13305  /* check curvature */
13306  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13307  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13308 
13309  /* free memory, if allocated before */
13310 TERMINATE:
13311  if( childbounds != childboundsstatic )
13312  {
13313  BMSfreeMemoryArrayNull(&childbounds);
13314  BMSfreeMemoryArrayNull(&childcurv);
13315  }
13316 
13317  return retcode;
13318 }
13319 
13320 /** gives the user data belonging to a SCIP_EXPR_USER expression */
13322  SCIP_EXPRGRAPHNODE* node
13323  )
13324 {
13325  assert(node != NULL);
13326  assert(node->op == SCIP_EXPR_USER);
13327  assert(node->data.data != NULL);
13328 
13329  return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13330 }
13331 
13332 /** indicates whether a user expression has the estimator callback defined */
13334  SCIP_EXPRGRAPHNODE* node
13335  )
13336 {
13337  assert(node != NULL);
13338  assert(node->op == SCIP_EXPR_USER);
13339  assert(node->data.data != NULL);
13340 
13341  return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13342 }
13343 
13344 /** gets bounds of a node in an expression graph */
13346  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13347  )
13348 {
13349  assert(node != NULL);
13350 
13351  return node->bounds;
13352 }
13353 
13354 /** gets value of expression associated to node from last evaluation call */
13356  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13357  )
13358 {
13359  assert(node != NULL);
13360 
13361  return node->value;
13362 }
13363 
13364 /** gets curvature of expression associated to node from last curvature check call */
13366  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13367  )
13368 {
13369  assert(node != NULL);
13370 
13371  return node->curv;
13372 }
13373 
13374 /** creates an expression graph node */
13376  BMS_BLKMEM* blkmem, /**< block memory */
13377  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13378  SCIP_EXPROP op, /**< operator type of expression */
13379  ...
13380  )
13381 {
13382  va_list ap;
13383  SCIP_EXPROPDATA opdata;
13384 
13385  assert(blkmem != NULL);
13386  assert(node != NULL);
13387 
13388  *node = NULL;
13389 
13390  switch( op )
13391  {
13392  case SCIP_EXPR_VARIDX :
13393  case SCIP_EXPR_PARAM :
13394  case SCIP_EXPR_CONST :
13395  case SCIP_EXPR_LINEAR :
13396  case SCIP_EXPR_QUADRATIC :
13397  case SCIP_EXPR_POLYNOMIAL:
13398  case SCIP_EXPR_USER :
13399  {
13400  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
13401  SCIPABORT();
13402  return SCIP_ERROR; /*lint !e527*/
13403  }
13404 
13405  /* operands without data */
13406  case SCIP_EXPR_PLUS :
13407  case SCIP_EXPR_MINUS :
13408  case SCIP_EXPR_MUL :
13409  case SCIP_EXPR_DIV :
13410  case SCIP_EXPR_MIN :
13411  case SCIP_EXPR_MAX :
13412  case SCIP_EXPR_SQUARE :
13413  case SCIP_EXPR_SQRT :
13414  case SCIP_EXPR_EXP :
13415  case SCIP_EXPR_LOG :
13416  case SCIP_EXPR_SIN :
13417  case SCIP_EXPR_COS :
13418  case SCIP_EXPR_TAN :
13419  /* case SCIP_EXPR_ERF : */
13420  /* case SCIP_EXPR_ERFI: */
13421  case SCIP_EXPR_ABS :
13422  case SCIP_EXPR_SIGN :
13423  case SCIP_EXPR_SUM :
13424  case SCIP_EXPR_PRODUCT:
13425  opdata.data = NULL;
13426  break;
13427 
13428  case SCIP_EXPR_REALPOWER:
13429  case SCIP_EXPR_SIGNPOWER:
13430  {
13431  va_start(ap, op ); /*lint !e838*/
13432  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
13433  va_end( ap ); /*lint !e826*/
13434 
13435  break;
13436  }
13437 
13438  case SCIP_EXPR_INTPOWER:
13439  {
13440  va_start(ap, op ); /*lint !e838*/
13441  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
13442  va_end( ap ); /*lint !e826*/
13443 
13444  break;
13445  }
13446 
13447  case SCIP_EXPR_LAST:
13448  SCIPABORT();
13449  return SCIP_INVALIDDATA; /*lint !e527*/
13450  }
13451 
13452  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13453 
13454  return SCIP_OKAY;
13455 }
13456 
13457 /** creates an expression graph node for a linear expression */
13459  BMS_BLKMEM* blkmem, /**< block memory */
13460  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13461  int ncoefs, /**< number of coefficients */
13462  SCIP_Real* coefs, /**< coefficients of linear expression */
13463  SCIP_Real constant /**< constant of linear expression */
13464  )
13465 {
13466  SCIP_EXPROPDATA opdata;
13467  SCIP_Real* data;
13468 
13469  assert(blkmem != NULL);
13470  assert(node != NULL);
13471 
13472  /* we store the coefficients and the constant in a single array and make this our operand data */
13473  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13474  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
13475  data[ncoefs] = constant;
13476 
13477  opdata.data = data;
13478  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13479 
13480  return SCIP_OKAY;
13481 }
13482 
13483 /** creates an expression graph node for a quadratic expression */
13485  BMS_BLKMEM* blkmem, /**< block memory */
13486  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13487  int nchildren, /**< number of children */
13488  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
13489  int nquadelems, /**< number of quadratic elements */
13490  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
13491  SCIP_Real constant /**< constant */
13492  )
13493 {
13494  SCIP_EXPROPDATA opdata;
13496 
13497  assert(blkmem != NULL);
13498  assert(node != NULL);
13499  assert(quadelems != NULL || nquadelems == 0);
13500 
13501  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13502 
13503  opdata.data = data;
13504  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13505 
13506  return SCIP_OKAY;
13507 }
13508 
13509 /** creates an expression graph node for a polynomial expression */
13511  BMS_BLKMEM* blkmem, /**< block memory */
13512  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13513  int nmonomials, /**< number of monomials */
13514  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13515  SCIP_Real constant, /**< constant of polynomial */
13516  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13517  )
13518 {
13519  SCIP_EXPROPDATA opdata;
13521 
13522  assert(blkmem != NULL);
13523  assert(node != NULL);
13524  assert(monomials != NULL || nmonomials == 0);
13525 
13526  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13527 
13528  opdata.data = data;
13529  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13530 
13531  return SCIP_OKAY;
13532 }
13533 
13534 /** adds monomials to an expression graph node that is a polynomial expression */
13536  BMS_BLKMEM* blkmem, /**< block memory */
13537  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
13538  int nmonomials, /**< number of monomials */
13539  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13540  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13541  )
13542 {
13543  assert(blkmem != NULL);
13544  assert(node != NULL);
13546  assert(monomials != NULL || nmonomials == 0);
13547 
13548  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13549 
13550  return SCIP_OKAY;
13551 }
13552 
13553 /** creates an expression graph node for a user expression */
13555  BMS_BLKMEM* blkmem, /**< block memory */
13556  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13557  SCIP_USEREXPRDATA* data, /**< user data for expression, node assumes ownership */
13558  SCIP_EXPRINTCAPABILITY evalcapability, /**< evaluation capability */
13559  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
13560  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function */
13561  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
13562  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function */
13563  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13564  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13565  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
13566  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
13567  )
13568 {
13569  SCIP_EXPROPDATA opdata;
13570  SCIP_EXPRDATA_USER* exprdata;
13571 
13572  assert(blkmem != NULL);
13573  assert(node != NULL);
13574  assert(eval != NULL);
13575  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
13576  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13577  assert(copydata != NULL || data == NULL);
13578  assert(freedata != NULL || data == NULL);
13579 
13580  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13581 
13582  exprdata->userdata = data;
13583  exprdata->evalcapability = evalcapability;
13584  exprdata->eval = eval;
13585  exprdata->estimate = estimate;
13586  exprdata->inteval = inteval;
13587  exprdata->curv = curv;
13588  exprdata->prop = prop;
13589  exprdata->copydata = copydata;
13590  exprdata->freedata = freedata;
13591  exprdata->print = print;
13592 
13593  opdata.data = (void*) exprdata;
13594 
13595  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13596 
13597  return SCIP_OKAY;
13598 }
13599 
13600 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13601  *
13602  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13603  * If the node is a linear expression, it may be freed.
13604  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13605  * It is assumed that the user had captured the node.
13606  * It is assumed that the expression graph has been simplified before.
13607  */
13609  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13610  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
13611  int linvarssize, /**< length of linvars and lincoefs arrays */
13612  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
13613  void** linvars, /**< buffer to store variables of linear part */
13614  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
13615  SCIP_Real* constant /**< buffer to store constant part */
13616  )
13617 {
13618  int orignvars;
13619  int* varsusage;
13620  SCIP_EXPRGRAPHNODE* orignode;
13621  SCIP_Bool havechange;
13622  int i;
13623 
13624  assert(exprgraph != NULL);
13625  assert(node != NULL);
13626  assert(*node != NULL);
13627  assert((*node)->nuses > 0);
13628  assert(nlinvars != NULL);
13629  assert(linvars != NULL || linvarssize == 0);
13630  assert(lincoefs != NULL || linvarssize == 0);
13631  assert(constant != NULL);
13632 
13633  *constant = 0.0;
13634  *nlinvars = 0;
13635 
13636  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13637 
13638  /* do some obvious and easy cases */
13639  switch( (*node)->op )
13640  {
13641  case SCIP_EXPR_VARIDX:
13642  {
13643  if( linvarssize >= 1 )
13644  {
13645  *nlinvars = 1;
13646  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
13647  lincoefs[0] = 1.0; /*lint !e613*/
13648 
13649  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13650  }
13651  return SCIP_OKAY;
13652  }
13653 
13654  case SCIP_EXPR_CONST:
13655  {
13656  *constant = (*node)->data.dbl;
13657  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13658 
13659  return SCIP_OKAY;
13660  }
13661 
13662  case SCIP_EXPR_REALPOWER:
13663  case SCIP_EXPR_SIGNPOWER:
13664  {
13665  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13666  {
13667  *nlinvars = 1;
13668  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13669  lincoefs[0] = 1.0; /*lint !e613*/
13670 
13671  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13672  }
13673  return SCIP_OKAY;
13674  }
13675 
13676  case SCIP_EXPR_INTPOWER:
13677  {
13678  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13679  {
13680  *nlinvars = 1;
13681  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13682  lincoefs[0] = 1.0; /*lint !e613*/
13683 
13684  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13685  }
13686  return SCIP_OKAY;
13687  }
13688 
13689  case SCIP_EXPR_PLUS:
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_MINUS:
13734  {
13735  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13736  {
13737  *constant = (*node)->children[0]->data.dbl;
13738  *nlinvars = 1;
13739  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13740  lincoefs[0] = -1.0; /*lint !e613*/
13741 
13742  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13743 
13744  return SCIP_OKAY;
13745  }
13746  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13747  {
13748  *constant = -(*node)->children[1]->data.dbl;
13749  *nlinvars = 1;
13750  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13751  lincoefs[0] = 1.0; /*lint !e613*/
13752 
13753  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13754 
13755  return SCIP_OKAY;
13756  }
13757  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13758  {
13759  *nlinvars = 2;
13760  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13761  lincoefs[0] = 1.0; /*lint !e613*/
13762  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13763  lincoefs[1] = -1.0; /*lint !e613*/
13764 
13765  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13766 
13767  return SCIP_OKAY;
13768  }
13769  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13770  {
13771  /* handle this one later */
13772  break;
13773  }
13774  return SCIP_OKAY;
13775  }
13776 
13777  case SCIP_EXPR_MUL:
13778  {
13779  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13780  {
13781  *nlinvars = 1;
13782  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13783  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
13784 
13785  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13786  }
13787  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13788  {
13789  *nlinvars = 1;
13790  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13791  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
13792 
13793  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13794  }
13795  return SCIP_OKAY;
13796  }
13797 
13798  case SCIP_EXPR_DIV:
13799  {
13800  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13801  return SCIP_OKAY;
13802 
13803  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13804  {
13805  *nlinvars = 1;
13806  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13807  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
13808 
13809  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13810  }
13811  return SCIP_OKAY;
13812  }
13813 
13814  case SCIP_EXPR_SQUARE:
13815  case SCIP_EXPR_SQRT:
13816  case SCIP_EXPR_EXP:
13817  case SCIP_EXPR_LOG:
13818  case SCIP_EXPR_SIN:
13819  case SCIP_EXPR_COS:
13820  case SCIP_EXPR_TAN:
13821  /* case SCIP_EXPR_ERF: */
13822  /* case SCIP_EXPR_ERFI: */
13823  case SCIP_EXPR_ABS:
13824  case SCIP_EXPR_SIGN:
13825  case SCIP_EXPR_MIN:
13826  case SCIP_EXPR_MAX:
13827  return SCIP_OKAY;
13828 
13829  case SCIP_EXPR_PRODUCT:
13830  case SCIP_EXPR_USER:
13831  return SCIP_OKAY;
13832 
13833  case SCIP_EXPR_SUM:
13834  case SCIP_EXPR_LINEAR:
13835  case SCIP_EXPR_QUADRATIC:
13836  case SCIP_EXPR_POLYNOMIAL:
13837  default:
13838  {
13839  /* check if there is a child that is a variable */
13840  for( i = 0; i < (*node)->nchildren; ++i )
13841  {
13842  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13843  break;
13844  }
13845 
13846  if( i == (*node)->nchildren )
13847  return SCIP_OKAY;
13848 
13849  break;
13850  }
13851  } /*lint !e788*/
13852 
13853  /* count how often variables are used in this expression */
13854  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13855  orignvars = exprgraph->nvars;
13856  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13857  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
13858 
13859  exprgraphNodeGetVarsUsage(*node, varsusage);
13860 
13861  /* duplicate node if it has parents or more than one user */
13862  orignode = NULL;
13863  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13864  {
13865  SCIP_EXPROPDATA data;
13866 
13867  orignode = *node;
13868 
13869  if( exprOpTable[orignode->op].copydata != NULL )
13870  {
13871  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13872  }
13873  else
13874  data = orignode->data;
13875 
13876  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13877  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13878  SCIPexprgraphCaptureNode(*node);
13879  }
13880 
13881  havechange = FALSE;
13882  /* split up constant and linear part */
13883  switch( (*node)->op )
13884  {
13885  case SCIP_EXPR_PLUS:
13886  case SCIP_EXPR_MINUS:
13887  {
13888  SCIP_EXPRGRAPHNODE* varchild;
13889  SCIP_EXPRGRAPHNODE* otherchild;
13890  int varidx;
13891 
13892  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13893  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13894  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13895  assert(linvarssize >= 1);
13896 
13897  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13898  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13899  varidx = varchild->data.intval;
13900  /* if variable is used in other child (which should be nonlinear), we don't take it */
13901  if( varsusage[varidx] > 1 )
13902  break;
13903 
13904  /* add to linear variables */
13905  *nlinvars = 1;
13906  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13907  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13908  lincoefs[0] = -1.0; /*lint !e613*/
13909  else
13910  lincoefs[0] = 1.0; /*lint !e613*/
13911 
13912  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13913  {
13914  /* replace *node by otherchild */
13915  SCIPexprgraphCaptureNode(otherchild);
13916  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13917  *node = otherchild;
13918  }
13919  else
13920  {
13921  SCIP_Real* lindata;
13922 
13923  /* turn *node into linear expression -1.0 * otherchild */
13924 
13925  /* reduce to one child */
13926  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13927  (*node)->children[0] = otherchild;
13928  (*node)->nchildren = 1;
13929  (*node)->op = SCIP_EXPR_LINEAR;
13930 
13931  /* setup linear data -1.0 * child0 + 0.0 */
13932  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13933  lindata[0] = -1.0;
13934  lindata[1] = 0.0;
13935  (*node)->data.data = (void*)lindata;
13936 
13937  /* remove *node as parent of varchild */
13938  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13939  }
13940 
13941  havechange = TRUE;
13942 
13943  break;
13944  }
13945 
13946  case SCIP_EXPR_SUM:
13947  {
13948  int nchildren;
13949 
13950  i = 0;
13951  nchildren = (*node)->nchildren;
13952  while( i < nchildren )
13953  {
13954  /* sort out constants */
13955  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13956  {
13957  *constant += (*node)->children[i]->data.dbl;
13958  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13959 
13960  if( i < nchildren-1 )
13961  {
13962  (*node)->children[i] = (*node)->children[nchildren-1];
13963  (*node)->children[nchildren-1] = NULL;
13964  }
13965  --nchildren;
13966 
13967  continue;
13968  }
13969 
13970  /* keep every child that is not a constant or variable */
13971  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13972  {
13973  ++i;
13974  continue;
13975  }
13976 
13977  /* skip variables that are used in other parts of the expression */
13978  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13979  {
13980  ++i;
13981  continue;
13982  }
13983 
13984  /* move variable into linear part, if still space */
13985  if( *nlinvars < linvarssize )
13986  {
13987  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13988  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13989  ++*nlinvars;
13990 
13991  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13992  if( i < nchildren-1 )
13993  {
13994  (*node)->children[i] = (*node)->children[nchildren-1];
13995  (*node)->children[nchildren-1] = NULL;
13996  }
13997  --nchildren;
13998 
13999  continue;
14000  }
14001  }
14002  assert(i == nchildren);
14003 
14004  if( nchildren == 0 )
14005  {
14006  /* all children were removed */
14007  havechange = TRUE;
14008  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14009  (*node)->nchildren = 0;
14010  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14011  break;
14012  }
14013 
14014  if( nchildren < (*node)->nchildren )
14015  {
14016  /* some children were removed */
14017  havechange = TRUE;
14018  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14019  (*node)->nchildren = nchildren;
14020  }
14021 
14022  if( havechange && (*node)->nchildren == 1 )
14023  {
14024  /* replace node by its child */
14025  SCIP_EXPRGRAPHNODE* child;
14026 
14027  child = (*node)->children[0];
14028  SCIPexprgraphCaptureNode(child);
14029  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14030  *node = child;
14031 
14032  break;
14033  }
14034 
14035  break;
14036  }
14037 
14038  case SCIP_EXPR_LINEAR:
14039  {
14040  int nchildren;
14041  SCIP_Real* coefs;
14042 
14043  coefs = (SCIP_Real*)(*node)->data.data;
14044  assert(coefs != NULL);
14045 
14046  /* remove constant, if nonzero */
14047  if( coefs[(*node)->nchildren] != 0.0 )
14048  {
14049  *constant = coefs[(*node)->nchildren];
14050  coefs[(*node)->nchildren] = 0.0;
14051  havechange = TRUE;
14052  }
14053 
14054  i = 0;
14055  nchildren = (*node)->nchildren;
14056  while( i < nchildren )
14057  {
14058  /* sort out constants */
14059  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
14060  {
14061  *constant += coefs[i] * (*node)->children[i]->data.dbl;
14062  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14063 
14064  if( i < nchildren-1 )
14065  {
14066  (*node)->children[i] = (*node)->children[nchildren-1];
14067  (*node)->children[nchildren-1] = NULL;
14068  coefs[i] = coefs[nchildren-1];
14069  coefs[nchildren-1] = 0.0;
14070  }
14071  --nchildren;
14072 
14073  continue;
14074  }
14075 
14076  /* keep everything that is not a constant or variable */
14077  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14078  {
14079  ++i;
14080  continue;
14081  }
14082 
14083  /* skip variables that are used in other parts of the expression */
14084  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14085  {
14086  ++i;
14087  continue;
14088  }
14089 
14090  /* move variable into linear part, if still space */
14091  if( *nlinvars < linvarssize )
14092  {
14093  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14094  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
14095  ++*nlinvars;
14096 
14097  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14098  if( i < nchildren-1 )
14099  {
14100  (*node)->children[i] = (*node)->children[nchildren-1];
14101  (*node)->children[nchildren-1] = NULL;
14102  coefs[i] = coefs[nchildren-1];
14103  coefs[nchildren-1] = 0.0;
14104  }
14105  --nchildren;
14106 
14107  continue;
14108  }
14109  }
14110  assert(i == nchildren);
14111 
14112  if( nchildren == 0 )
14113  {
14114  /* all children were removed */
14115  havechange = TRUE;
14116  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14117  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
14118  (*node)->data.data = NULL;
14119  (*node)->nchildren = 0;
14120  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
14121  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14122  break;
14123  }
14124 
14125  if( nchildren < (*node)->nchildren )
14126  {
14127  /* some children were removed */
14128  havechange = TRUE;
14129  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14130  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
14131  coefs[nchildren] = 0.0;
14132  (*node)->data.data = (void*)coefs;
14133  (*node)->nchildren = nchildren;
14134  }
14135 
14136  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
14137  {
14138  /* replace node by its child */
14139  SCIP_EXPRGRAPHNODE* child;
14140 
14141  child = (*node)->children[0];
14142  SCIPexprgraphCaptureNode(child);
14143  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14144  *node = child;
14145 
14146  break;
14147  }
14148 
14149  break;
14150  }
14151 
14152  case SCIP_EXPR_QUADRATIC:
14153  {
14154  SCIP_EXPRDATA_QUADRATIC* quaddata;
14155  SCIP_Bool* childused;
14156  int* childmap;
14157  int nchildren;
14158 
14159  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
14160  assert(quaddata != NULL);
14161 
14162  /* remove constant, if nonzero */
14163  if( quaddata->constant != 0.0 )
14164  {
14165  *constant = quaddata->constant;
14166  quaddata->constant = 0.0;
14167  havechange = TRUE;
14168  }
14169 
14170  /* if there is no linear part or no space left for linear variables, then stop */
14171  if( quaddata->lincoefs == NULL || linvarssize == 0 )
14172  break;
14173 
14174  /* check which childs are used in quadratic terms */
14175  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14176  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14177 
14178  for( i = 0; i < quaddata->nquadelems; ++i )
14179  {
14180  childused[quaddata->quadelems[i].idx1] = TRUE;
14181  childused[quaddata->quadelems[i].idx2] = TRUE;
14182  }
14183 
14184  /* alloc space for mapping of children indices */
14185  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
14186 
14187  nchildren = (*node)->nchildren;
14188  for( i = 0; i < nchildren; ++i )
14189  {
14190  childmap[i] = i; /*lint !e644*/
14191  if( *nlinvars >= linvarssize )
14192  continue;
14193  /* skip child if not variable or also used in quadratic part or other parts of expression */
14194  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14195  continue;
14196  if( childused[i] )
14197  continue;
14198  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14199  continue;
14200 
14201  /* put variable into linear part */
14202  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14203  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
14204  quaddata->lincoefs[i] = 0.0;
14205  ++*nlinvars;
14206 
14207  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14208 
14209  /* move last child to position i */
14210  if( i < nchildren-1 )
14211  {
14212  (*node)->children[i] = (*node)->children[nchildren-1];
14213  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
14214  childused[i] = childused[nchildren-1];
14215  childmap[nchildren-1] = i;
14216  }
14217  --nchildren;
14218  childmap[i] = -1;
14219 
14220  havechange = TRUE;
14221  --i; /* look at i again */
14222  }
14223 
14224  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
14225 
14226  if( nchildren < (*node)->nchildren )
14227  {
14228  /* apply childmap to quadratic term */
14229  for( i = 0; i < quaddata->nquadelems; ++i )
14230  {
14231  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
14232  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
14233  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
14234  {
14235  int tmp;
14236  tmp = quaddata->quadelems[i].idx1;
14237  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
14238  quaddata->quadelems[i].idx2 = tmp;
14239  }
14240  }
14241  quaddata->sorted = FALSE;
14242  }
14243  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
14244 
14245  if( nchildren == 0 )
14246  {
14247  /* all children were removed (so it was actually a linear expression) */
14248  havechange = TRUE;
14249  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14250  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
14251  (*node)->data.data = NULL;
14252  (*node)->nchildren = 0;
14253  (*node)->op = SCIP_EXPR_SUM;
14254  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14255  break;
14256  }
14257 
14258  if( nchildren < (*node)->nchildren )
14259  {
14260  /* reduce number of children */
14261  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14262  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
14263  (*node)->nchildren = nchildren;
14264  }
14265 
14266  break;
14267  }
14268 
14269  case SCIP_EXPR_POLYNOMIAL:
14270  {
14271  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
14272  SCIP_EXPRDATA_MONOMIAL* monomial;
14273  SCIP_Bool* childused;
14274  int childidx;
14275  int j;
14276 
14277  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
14278  assert(polynomialdata != NULL);
14279 
14280  /* make sure linear monomials are merged */
14281  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14282 
14283  /* remove constant, if nonzero */
14284  if( polynomialdata->constant != 0.0 )
14285  {
14286  *constant = polynomialdata->constant;
14287  polynomialdata->constant = 0.0;
14288  havechange = TRUE;
14289  }
14290 
14291  /* if there is no space for linear variables, then stop */
14292  if( linvarssize == 0 )
14293  break;
14294 
14295  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14296  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14297  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14298  for( i = 0; i < polynomialdata->nmonomials; ++i )
14299  {
14300  monomial = polynomialdata->monomials[i];
14301  assert(monomial != NULL);
14302  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14303  continue;
14304  for( j = 0; j < monomial->nfactors; ++j )
14305  {
14306  assert(monomial->childidxs[j] >= 0);
14307  assert(monomial->childidxs[j] < (*node)->nchildren);
14308  childused[monomial->childidxs[j]] = TRUE;
14309  }
14310  }
14311 
14312  /* move linear monomials out of polynomial */
14313  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14314  {
14315  monomial = polynomialdata->monomials[i];
14316  assert(monomial != NULL);
14317 
14318  /* sort out constants */
14319  if( monomial->nfactors == 0 )
14320  {
14321  if( monomial->coef != 0.0 )
14322  {
14323  *constant += monomial->coef;
14324  havechange = TRUE;
14325  }
14326  continue;
14327  }
14328 
14329  if( monomial->nfactors != 1 )
14330  continue;
14331  if( monomial->exponents[0] != 1.0 )
14332  continue;
14333  childidx = monomial->childidxs[0];
14334  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14335  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14336  continue;
14337  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14338  continue;
14339 
14340  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14341 
14342  /* put variable into linear part */
14343  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
14344  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
14345  ++*nlinvars;
14346 
14347  monomial->coef = 0.0;
14348  monomial->nfactors = 0;
14349  polynomialdata->sorted = FALSE;
14350 
14351  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14352  (*node)->children[childidx] = NULL;
14353 
14354  havechange = TRUE;
14355  }
14356 
14357  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14358 
14359  if( *nlinvars > 0 )
14360  {
14361  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14362  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14364  }
14365 
14366  if( (*node)->nchildren == 0 )
14367  {
14368  assert(polynomialdata->nmonomials == 0);
14369  assert(polynomialdata->constant == 0.0);
14370  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14371  havechange = TRUE;
14372  break;
14373  }
14374 
14375  break;
14376  }
14377 
14378  default: ;
14379  } /*lint !e788*/
14380 
14381  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14382 
14383  if( orignode != NULL )
14384  {
14385  /* if node was duplicated, we need to forget about original or duplicate */
14386  if( !havechange )
14387  {
14388  /* if nothing has changed, then forget about duplicate */
14389  assert(*constant == 0.0);
14390  assert(*nlinvars == 0);
14391  assert(*node != NULL);
14392  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14393  *node = orignode;
14394  }
14395  else
14396  {
14397  /* if something changed, then release original node */
14398  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14399  }
14400  }
14401  else if( havechange && *node != NULL )
14402  {
14403  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14404  (*node)->value = SCIP_INVALID;
14405  (*node)->simplified = FALSE;
14406  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14407  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14408  exprgraph->needvarboundprop = TRUE;
14409  }
14410 
14411  return SCIP_OKAY;
14412 }
14413 
14414 /** moves parents from a one node to another node
14415  *
14416  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14417  * srcnode may be freed, if not captured.
14418  * It is assumed that targetnode represents the same expression as srcnode.
14419  */
14421  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14422  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
14423  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
14424  )
14425 {
14426  assert(exprgraph != NULL);
14427  assert(srcnode != NULL);
14428  assert(*srcnode != NULL);
14429  assert(targetnode != NULL);
14430 
14431  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14432  {
14433  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14434  {
14435  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14436  }
14437  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14438  }
14439  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14440 
14441  return SCIP_OKAY;
14442 }
14443 
14444 /** releases node, i.e., decreases number of uses
14445  *
14446  * node is freed if no parents and no other uses.
14447  * Children are recursively released if they have no other parents.
14448  * Nodes that are removed are also freed.
14449  * If node correspond to a variable, then the variable is removed from the expression graph;
14450  * similarly for constants.
14451  */
14453  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14454  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
14455  )
14456 {
14457  int i;
14458 
14459  assert(exprgraph != NULL);
14460  assert(node != NULL);
14461  assert(*node != NULL);
14462  assert((*node)->depth >= 0); /* node should be in graph */
14463  assert((*node)->pos >= 0); /* node should be in graph */
14464  assert((*node)->depth < exprgraph->depth);
14465  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14466  assert((*node)->nuses >= 1);
14467  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14468 
14469  SCIPdebugMessage("release node %p\n", (void*)*node);
14470 
14471  --(*node)->nuses;
14472 
14473  /* do nothing if node still has parents or is still in use */
14474  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14475  {
14476  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);
14477  *node = NULL;
14478  return SCIP_OKAY;
14479  }
14480 
14481  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14482 
14483  /* notify children about removal of its parent
14484  * they are also freed, if possible */
14485  for( i = 0; i < (*node)->nchildren; ++i )
14486  {
14487  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14488  (*node)->children[i] = NULL;
14489  }
14490 
14491  if( (*node)->op == SCIP_EXPR_VARIDX )
14492  {
14493  assert((*node)->depth == 0);
14494  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14495  }
14496  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14497  {
14498  int constidx;
14499 
14500  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14501  assert(constidx >= 0);
14502  assert(constidx < exprgraph->nconsts);
14503  assert(exprgraph->constnodes[constidx] == *node);
14504 
14505  /* move last constant to position constidx */
14506  if( constidx < exprgraph->nconsts-1 )
14507  {
14508  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14509  exprgraph->constssorted = (exprgraph->nconsts <= 2);
14510  }
14511  --exprgraph->nconsts;
14512  }
14513  else
14514  {
14515  /* only variables and constants are allowed at depth 0 */
14516  assert((*node)->depth > 0);
14517  }
14518 
14519  /* remove node from nodes array in expression graph */
14520  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14521  {
14522  /* move last node at depth of *node to position of *node */
14523  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14524  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14525 
14526  /* moving the node may change the order in the parents array of each child */
14527  for( i = 0; i < exprgraph->nodes[(*node)->depth][(*node)->pos]->nchildren; ++i )
14528  exprgraph->nodes[(*node)->depth][(*node)->pos]->children[i]->parentssorted = FALSE;
14529  }
14530  --exprgraph->nnodes[(*node)->depth];
14531 
14532  /* node is now not in graph anymore */
14533  (*node)->depth = -1;
14534  (*node)->pos = -1;
14535 
14536  /* free node */
14537  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14538 
14539  *node = NULL;
14540 
14541  return SCIP_OKAY;
14542 }
14543 
14544 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14545 /** frees a node of an expression graph */
14547  BMS_BLKMEM* blkmem, /**< block memory */
14548  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
14549  )
14550 {
14551  assert(blkmem != NULL);
14552  assert( node != NULL);
14553  assert(*node != NULL);
14554  assert((*node)->depth == -1); /* node should not be in graph anymore */
14555  assert((*node)->pos == -1); /* node should not be in graph anymore */
14556  assert((*node)->nuses == 0); /* node should not be in use */
14557 
14558  /* free operator data, if needed */
14559  if( exprOpTable[(*node)->op].freedata != NULL )
14560  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14561 
14562  /* free arrays of children and parent nodes */
14563  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14564  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
14565 
14566  /* free node struct */
14567  BMSfreeBlockMemory(blkmem, node);
14568 }
14569 
14570 /** enables a node and recursively all its children in an expression graph */
14572  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14573  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14574  )
14575 {
14576  int i;
14577 
14578  assert(exprgraph != NULL);
14579  assert(node != NULL);
14580  assert(node->depth >= 0);
14581  assert(node->pos >= 0);
14582 
14583  if( node->enabled )
14584  return;
14585 
14586  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14587 
14588  node->enabled = TRUE;
14589  for( i = 0; i < node->nchildren; ++i )
14590  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14591 
14592  /* make sure bounds are updated in next bound propagation round */
14593  SCIPintervalSetEntire(SCIP_REAL_MAX, &node->bounds);
14594  exprgraph->needvarboundprop = TRUE;
14595 }
14596 
14597 /** disables a node and recursively all children which have no enabled parents in an expression graph */
14599  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14600  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14601  )
14602 {
14603  int i;
14604 
14605  assert(exprgraph != NULL);
14606  assert(node != NULL);
14607  assert(node->depth >= 0);
14608  assert(node->pos >= 0);
14609 
14610  if( !node->enabled )
14611  return;
14612 
14613  /* workaround: don't disable nodes if there could be more users than the one who is disabling the node
14614  * otherwise, if there are several nonlinear constraints using the same expression graph node as root node,
14615  * we might get enabled constraints with disabled node
14616  */
14617  if( node->nuses > 1 )
14618  return;
14619 
14620  /* if all parents of node are disabled, then also node can be disabled */
14621  node->enabled = FALSE;
14622  for( i = 0; i < node->nparents; ++i )
14623  if( node->parents[i]->enabled )
14624  {
14625  node->enabled = TRUE;
14626  return;
14627  }
14628 
14629  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14630 
14631  for( i = 0; i < node->nchildren; ++i )
14632  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14633 }
14634 
14635 /** returns whether the node has siblings in the expression graph */
14637  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14638  )
14639 {
14640  int p;
14641 
14642  assert(node != NULL);
14643 
14644  for( p = 0; p < node->nparents; ++p )
14645  if( node->parents[p]->nchildren > 1 )
14646  return TRUE;
14647 
14648  return FALSE;
14649 }
14650 
14651 /** returns whether all children of an expression graph node are variable nodes
14652  *
14653  * Returns TRUE for nodes without children.
14654  */
14656  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14657  )
14658 {
14659  int i;
14660 
14661  assert(node != NULL);
14662 
14663  for( i = 0; i < node->nchildren; ++i )
14664  if( node->children[i]->op != SCIP_EXPR_VARIDX )
14665  return FALSE;
14666 
14667  return TRUE;
14668 }
14669 
14670 /** returns whether the node has an ancestor which has a nonlinear expression operand */
14672  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14673  )
14674 {
14675  int p;
14676 
14677  for( p = 0; p < node->nparents; ++p )
14678  {
14679  assert(node->parents[p]->depth > node->depth);
14680  switch( node->parents[p]->op )
14681  {
14682  case SCIP_EXPR_PLUS:
14683  case SCIP_EXPR_MINUS:
14684  case SCIP_EXPR_SUM:
14685  case SCIP_EXPR_LINEAR:
14687  return TRUE;
14688  break;
14689 
14690 #ifndef NDEBUG
14691  case SCIP_EXPR_VARIDX:
14692  case SCIP_EXPR_CONST:
14693  case SCIP_EXPR_PARAM:
14694  assert(0); /* these expressions cannot have children */
14695  break;
14696 #endif
14697 
14698  default:
14699  /* parent has nonlinear expression operand */
14700  return TRUE;
14701  }/*lint !e788*/
14702  }
14703 
14704  return FALSE;
14705 }
14706 
14707 /** prints an expression graph node */
14709  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14710  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14711  FILE* file /**< file to print to, or NULL for stdout */
14712  )
14713 {
14714  assert(node != NULL);
14715 
14716  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14717 }
14718 
14719 /** tightens the bounds in a node of the graph
14720  *
14721  * Preparation for reverse propagation.
14722  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14723  */
14725  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14726  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
14727  SCIP_INTERVAL nodebounds, /**< new bounds for node */
14728  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) */
14729  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14730  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14731  )
14732 {
14733  assert(exprgraph != NULL);
14734  assert(node != NULL);
14735  assert(node->depth >= 0);
14736  assert(node->pos >= 0);
14737  assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14738  assert(cutoff != NULL);
14739 
14740  *cutoff = FALSE;
14741 
14742  /* if node is disabled, then ignore new bounds */
14743  if( !node->enabled )
14744  {
14745  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14746  return;
14747  }
14748 
14749  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14750  (void*)node, node->depth, node->pos,
14751  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14752 
14753  /* bounds in node should be valid */
14754  assert(!(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
14755 
14756  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14757  {
14758  *cutoff = TRUE;
14759  SCIPdebugPrintf(" -> cutoff\n");
14760  return;
14761  }
14762 
14763  /* if minstrength is negative, always mark that node has recently tightened bounds,
14764  * if bounds are considerably improved or tightening leads to an empty interval,
14765  * mark that node has recently tightened bounds
14766  * if bounds are only slightly improved, set the status to tightened by parent,
14767  * so next propagateVarBound round will reset the bounds
14768  */
14769  if( minstrength < 0.0 )
14770  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE;
14771  else if(
14772  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14773  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14774  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT;
14775  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14776  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT;
14777 
14778  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14779  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14780 }
14781 
14782 /** ensures that bounds and curvature information in a node is uptodate
14783  *
14784  * Assumes that bounds and curvature in children are uptodate.
14785  */
14787  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14788  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14789  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14790  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14791  )
14792 {
14793  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14794  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14795  SCIP_INTERVAL* childbounds = NULL;
14796  SCIP_EXPRCURV* childcurv = NULL;
14797  SCIP_RETCODE retcode = SCIP_OKAY;
14798  int i;
14799 
14800  assert(node != NULL);
14801  assert(node->depth >= 0); /* node should be in graph */
14802  assert(node->pos >= 0); /* node should be in graph */
14803  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14804 
14805  if( node->depth == 0 )
14806  {
14807  /* we cannot update bound tightenings in variable nodes here */
14808  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14809  return SCIP_OKAY;
14810  }
14811 
14812  assert(node->op != SCIP_EXPR_VARIDX);
14813  assert(node->op != SCIP_EXPR_PARAM);
14814 
14815  /* if many children, get large enough memory to store children bounds */
14817  {
14818  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14819  SCIP_ALLOC_TERMINATE(retcode, BMSallocMemoryArray(&childcurv, node->nchildren), TERMINATE);
14820  }
14821  else
14822  {
14823  childbounds = childboundsstatic;
14824  childcurv = childcurvstatic;
14825  }
14826 
14827  /* assemble bounds and curvature of children */
14828  for( i = 0; i < node->nchildren; ++i )
14829  {
14830  /* child should have valid and non-empty bounds */
14832  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14833  /* nodes at depth 0 are always linear */
14834  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14835 
14836  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
14837  childcurv[i] = node->children[i]->curv; /*lint !e644*/
14838  }
14839 
14840  /* if we do not have valid bounds, then update
14841  * code below is copied from exprgraphNodeUpdateBounds */
14843  {
14844  SCIP_INTERVAL newbounds;
14845 
14846  /* calling interval evaluation function for this operand */
14847  assert( exprOpTable[node->op].inteval != NULL );
14848  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds), TERMINATE );
14849 
14850  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14851  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14852  *
14853  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14854  *
14855  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14856  */
14857  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14859  {
14860  for( i = 0; i < node->nparents; ++i )
14862 
14863  node->bounds = newbounds;
14864  }
14865  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14866  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14867  {
14868  for( i = 0; i < node->nparents; ++i )
14870 
14871  node->bounds = newbounds;
14872  }
14873  else
14874  {
14875  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14876  }
14877 
14878  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);
14879 
14880  /* node now has valid bounds */
14881  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
14882  }
14883 
14884  /* update curvature */
14885  if( SCIPintervalIsEmpty(infinity, node->bounds) )
14886  {
14887  node->curv = SCIP_EXPRCURV_LINEAR;
14888 
14889  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14890  }
14891  else
14892  {
14893  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv), TERMINATE );
14894 
14895  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14896  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14897  * SCIPdebugPrintf("\n");
14898  */
14899  }
14900 TERMINATE:
14901  /* free memory, if allocated before */
14902  if( childbounds != childboundsstatic )
14903  {
14904  BMSfreeMemoryArrayNull(&childbounds);
14905  BMSfreeMemoryArrayNull(&childcurv);
14906  }
14907 
14908  return retcode;
14909 }
14910 
14911 /**@} */
14912 
14913 /**@name Expression graph methods */
14914 /**@{ */
14915 
14916 /* In debug mode, the following methods are implemented as function calls to ensure
14917  * type validity.
14918  * In optimized mode, the methods are implemented as defines to improve performance.
14919  * However, we want to have them in the library anyways, so we have to undef the defines.
14920  */
14921 
14922 #undef SCIPexprgraphGetDepth
14923 #undef SCIPexprgraphGetNNodes
14924 #undef SCIPexprgraphGetNodes
14925 #undef SCIPexprgraphGetNVars
14926 #undef SCIPexprgraphGetVars
14927 #undef SCIPexprgraphGetVarNodes
14928 #undef SCIPexprgraphSetVarNodeValue
14929 #undef SCIPexprgraphSetVarsBounds
14930 #undef SCIPexprgraphSetVarBounds
14931 #undef SCIPexprgraphSetVarNodeBounds
14932 #undef SCIPexprgraphSetVarNodeLb
14933 #undef SCIPexprgraphSetVarNodeUb
14934 #undef SCIPexprgraphGetVarsBounds
14935 
14936 /** get current maximal depth of expression graph */
14938  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14939  )
14940 {
14941  assert(exprgraph != NULL);
14942 
14943  return exprgraph->depth;
14944 }
14945 
14946 /** gets array with number of nodes at each depth of expression graph */
14948  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14949  )
14950 {
14951  assert(exprgraph != NULL);
14952 
14953  return exprgraph->nnodes;
14954 }
14955 
14956 /** gets nodes of expression graph, one array per depth */
14958  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14959  )
14960 {
14961  assert(exprgraph != NULL);
14962 
14963  return exprgraph->nodes;
14964 }
14965 
14966 /** gets number of variables in expression graph */
14968  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14969  )
14970 {
14971  assert(exprgraph != NULL);
14972 
14973  return exprgraph->nvars;
14974 }
14975 
14976 /** gets array of variables in expression graph */
14978  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14979  )
14980 {
14981  assert(exprgraph != NULL);
14982 
14983  return exprgraph->vars;
14984 }
14985 
14986 /** gets array of expression graph nodes corresponding to variables */
14988  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14989  )
14990 {
14991  assert(exprgraph != NULL);
14992 
14993  return exprgraph->varnodes;
14994 }
14995 
14996 /** sets value for a single variable given as expression graph node */
14998  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14999  SCIP_Real value /**< new value for variable */
15000  )
15001 {
15002  assert(varnode != NULL);
15003  assert(varnode->op == SCIP_EXPR_VARIDX);
15004 
15005  varnode->value = value;
15006 }
15007 
15008 /** sets bounds for variables */
15010  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15011  SCIP_INTERVAL* varbounds /**< new bounds for variables */
15012  )
15013 {
15014  assert(exprgraph != NULL);
15015  assert(varbounds != NULL || exprgraph->nvars == 0);
15016 
15017  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
15018 }
15019 
15020 /** sets bounds for a single variable */
15022  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15023  void* var, /**< variable */
15024  SCIP_INTERVAL varbounds /**< new bounds of variable */
15025  )
15026 {
15027  int pos;
15028 
15029  assert(exprgraph != NULL);
15030  assert(var != NULL);
15031  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15032 
15033  pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15034  assert(pos < exprgraph->nvars);
15035  assert(exprgraph->vars[pos] == var);
15036 
15037  exprgraph->varbounds[pos] = varbounds;
15038 }
15039 
15040 /** sets bounds for a single variable given as expression graph node */
15042  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15043  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15044  SCIP_INTERVAL varbounds /**< new bounds of variable */
15045  )
15046 {
15047  int pos;
15048 
15049  assert(exprgraph != NULL);
15050  assert(varnode != NULL);
15051 
15052  pos = varnode->data.intval;
15053  assert(pos >= 0);
15054  assert(pos < exprgraph->nvars);
15055  assert(exprgraph->varnodes[pos] == varnode);
15056 
15057  exprgraph->varbounds[pos] = varbounds;
15058 }
15059 
15060 /** sets lower bound for a single variable given as expression graph node */
15062  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15063  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15064  SCIP_Real lb /**< new lower bound for variable */
15065  )
15066 {
15067  int pos;
15068 
15069  assert(exprgraph != NULL);
15070  assert(varnode != NULL);
15071 
15072  pos = varnode->data.intval;
15073  assert(pos >= 0);
15074  assert(pos < exprgraph->nvars);
15075  assert(exprgraph->varnodes[pos] == varnode);
15076 
15077  exprgraph->varbounds[pos].inf = lb;
15078 }
15079 
15080 /** sets upper bound for a single variable given as expression graph node */
15082  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15083  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15084  SCIP_Real ub /**< new upper bound for variable */
15085  )
15086 {
15087  int pos;
15088 
15089  assert(exprgraph != NULL);
15090  assert(varnode != NULL);
15091 
15092  pos = varnode->data.intval;
15093  assert(pos >= 0);
15094  assert(pos < exprgraph->nvars);
15095  assert(exprgraph->varnodes[pos] == varnode);
15096 
15097  exprgraph->varbounds[pos].sup = ub;
15098 }
15099 
15100 /** gets bounds that are stored for all variables */
15102  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
15103  )
15104 {
15105  return exprgraph->varbounds;
15106 }
15107 
15108 /** creates an empty expression graph */
15110  BMS_BLKMEM* blkmem, /**< block memory */
15111  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
15112  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
15113  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
15114  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /**< callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
15115  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /**< callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
15116  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /**< callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
15117  void* userdata /**< user data to pass to callback functions */
15118  )
15119 {
15120  assert(blkmem != NULL);
15121  assert(exprgraph != NULL);
15122 
15123  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
15124  BMSclearMemory(*exprgraph);
15125  (*exprgraph)->blkmem = blkmem;
15126 
15127  /* create nodes's arrays */
15128  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
15129  assert((*exprgraph)->depth >= 1);
15130 
15131  /* create var's arrays and hashmap */
15132  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
15133  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, (*exprgraph)->varssize) );
15134 
15135  /* empty array of constants is sorted */
15136  (*exprgraph)->constssorted = TRUE;
15137 
15138  /* store callback functions and user data */
15139  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
15140  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
15141  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
15142  (*exprgraph)->userdata = userdata;
15143 
15144  return SCIP_OKAY;
15145 }
15146 
15147 /** frees an expression graph */
15149  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
15150  )
15151 {
15152  BMS_BLKMEM* blkmem;
15153  int d;
15154 
15155  assert( exprgraph != NULL);
15156  assert(*exprgraph != NULL);
15157  assert((*exprgraph)->nvars == 0);
15158  assert((*exprgraph)->nconsts == 0);
15159 
15160  blkmem = (*exprgraph)->blkmem;
15161  assert(blkmem != NULL);
15162 
15163  /* free nodes arrays */
15164  for( d = 0; d < (*exprgraph)->depth; ++d )
15165  {
15166  assert((*exprgraph)->nnodes[d] == 0);
15167  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
15168  }
15169  assert((*exprgraph)->nodes != NULL);
15170  assert((*exprgraph)->nnodes != NULL);
15171  assert((*exprgraph)->nodessize != NULL);
15172  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
15173  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
15174  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
15175 
15176  /* free variables arrays and hashmap */
15177  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
15178  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
15179  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
15180  SCIPhashmapFree(&(*exprgraph)->varidxs);
15181 
15182  /* free constants array */
15183  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
15184 
15185  /* free graph struct */
15186  BMSfreeBlockMemory(blkmem, exprgraph);
15187 
15188  return SCIP_OKAY;
15189 }
15190 
15191 /** adds an expression graph node to an expression graph
15192  *
15193  * Expression graph assumes ownership of node.
15194  * Children are notified about new parent.
15195  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
15196  */
15198  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15199  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
15200  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
15201  int nchildren, /**< number of children */
15202  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
15203  )
15204 {
15205  SCIP_Bool childvalsvalid;
15206  int depth;
15207  int i;
15208 
15209  assert(exprgraph != NULL);
15210  assert(node != NULL);
15211  assert(node->pos < 0); /* node should have no position in graph yet */
15212  assert(node->depth < 0); /* node should have no position in graph yet */
15213  assert(node->nchildren == 0); /* node should not have stored children yet */
15214  assert(node->children == NULL); /* node should not have stored children yet */
15215  assert(node->nparents == 0); /* node should not have parents stored yet */
15216  assert(children != NULL || nchildren == 0);
15217 
15218  /* choose depth as maximal depth of children + 1, and at least mindepth */
15219  depth = MAX(0, mindepth);
15220  for( i = 0; i < nchildren; ++i )
15221  {
15222  if( children[i]->depth >= depth ) /*lint !e613*/
15223  depth = children[i]->depth + 1; /*lint !e613*/
15224  }
15225 
15226  /* ensure that expression graph is deep enough */
15227  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
15228  assert(exprgraph->depth > depth);
15229 
15230  /* ensure enough space for nodes at depth depth */
15231  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
15232 
15233  /* add node to graph */
15234  node->depth = depth;
15235  node->pos = exprgraph->nnodes[depth];
15236  exprgraph->nodes[depth][node->pos] = node;
15237  ++exprgraph->nnodes[depth];
15238 
15239  /* add as parent to children
15240  * and check if children has valid values */
15241  childvalsvalid = TRUE;
15242  for( i = 0; i < nchildren; ++i )
15243  {
15244  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
15245  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
15246  }
15247  /* store children */
15248  if( nchildren > 0 )
15249  {
15250  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
15251  node->nchildren = nchildren;
15252  }
15253 
15254  if( node->op == SCIP_EXPR_CONST )
15255  {
15256  /* set bounds to constant value of node */
15258  SCIPintervalSet(&node->bounds, node->data.dbl);
15259  }
15260  else
15261  {
15262  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
15265  exprgraph->needvarboundprop = TRUE;
15266  }
15267 
15268  /* if not a variable, set value of node according to values of children (if all have valid values) */
15269  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
15270  {
15271  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15272  }
15273 
15274  return SCIP_OKAY;
15275 }
15276 
15277 /** adds variables to an expression graph, if not existing yet
15278  *
15279  * Also already existing nodes are enabled.
15280  */
15282  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15283  int nvars, /**< number of variables to add */
15284  void** vars, /**< variables to add */
15285  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
15286  )
15287 {
15288  SCIP_EXPRGRAPHNODE* node;
15289  SCIP_EXPROPDATA opdata;
15290  int i;
15291 
15292  assert(exprgraph != NULL);
15293  assert(exprgraph->depth >= 1);
15294  assert(vars != NULL || nvars == 0);
15295 
15296  /* 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 */
15297  if( exprgraph->nvars == 0 )
15298  {
15299  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15300  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15301  }
15302 
15303  for( i = 0; i < nvars; ++i )
15304  {
15305  /* skip variables that exist already */
15306  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15307  {
15308  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
15309  assert(node != NULL);
15310 
15311  /* enable node */
15312  node->enabled = TRUE;
15313 
15314  if( varnodes != NULL )
15315  varnodes[i] = node;
15316 
15317  continue;
15318  }
15319 
15320  /* create new variable expression */
15321  opdata.intval = exprgraph->nvars;
15322  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15323 
15324  /* add expression node to expression graph at depth 0 */
15325  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15326 
15327  /* add variable node to vars arrays and hashmap */
15328  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15329  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
15330  exprgraph->varnodes[exprgraph->nvars] = node;
15331  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15332  SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[i], exprgraph->nvars) ); /*lint !e613*/
15333  ++exprgraph->nvars;
15334 
15335  if( varnodes != NULL )
15336  varnodes[i] = node;
15337 
15338  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15339 
15340  /* call callback method, if set */
15341  if( exprgraph->exprgraphvaradded != NULL )
15342  {
15343  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
15344  }
15345  }
15346 
15347  return SCIP_OKAY;
15348 }
15349 
15350 /** adds a constant to an expression graph, if not existing yet
15351  *
15352  * Also already existing nodes are enabled.
15353  */
15355  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15356  SCIP_Real constant, /**< constant to add */
15357  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
15358  )
15359 {
15360  SCIP_EXPROPDATA opdata;
15361 
15362  assert(exprgraph != NULL);
15363  assert(constnode != NULL);
15364 
15365  /* check if there is already an expression for this constant */
15366  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15367  {
15368  assert(*constnode != NULL);
15369  assert((*constnode)->op == SCIP_EXPR_CONST);
15370  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15371  (*constnode)->enabled = TRUE;
15372  return SCIP_OKAY;
15373  }
15374 
15375  /* create new node for constant */
15376  opdata.dbl = constant;
15377  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15378 
15379  /* add node to expression graph at depth 0 */
15380  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15381  assert((*constnode)->depth == 0);
15382  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
15383 
15384  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15385  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15386  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15387  ++exprgraph->nconsts;
15388  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15389 
15390  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15391 
15392  return SCIP_OKAY;
15393 }
15394 
15395 /** adds sum of expression trees into expression graph
15396  *
15397  * node will also be captured.
15398  *
15399  * @note Parameters will be converted into constants
15400  */
15402  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15403  int nexprtrees, /**< number of expression trees to add */
15404  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
15405  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
15406  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
15407  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) */
15408  )
15409 {
15410  SCIP_Bool allone;
15411 
15412  assert(exprgraph != NULL);
15413  assert(nexprtrees > 0);
15414  assert(exprtrees != NULL);
15415  assert(rootnode != NULL);
15416  assert(rootnodeisnew != NULL);
15417 
15418  *rootnode = NULL;
15419 
15420  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15421  {
15422  assert(exprtrees[0] != NULL);
15423  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15424 
15425  /* coverity[var_deref_model] */
15426  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, exprtrees[0]->params, rootnode, rootnodeisnew) );
15427  }
15428  else
15429  {
15430  SCIP_EXPROP op;
15431  SCIP_EXPRGRAPHNODE** rootnodes;
15432  SCIP_Bool rootnodeisnew_;
15433  int i;
15434 
15435  *rootnodeisnew = TRUE;
15436  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15437 
15438  allone = TRUE;
15439  for( i = 0; i < nexprtrees; ++i )
15440  {
15441  assert(exprtrees[i] != NULL);
15442  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15443 
15444  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, exprtrees[i]->params, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
15445  assert(rootnodes[i] != NULL);
15446  *rootnodeisnew &= rootnodeisnew_;
15447 
15448  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
15449  }
15450 
15451  /* decide which operand we want to use for the root node */
15452  if( coefs == NULL || allone )
15453  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15454  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15455  op = SCIP_EXPR_MINUS;
15456  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15457  {
15458  SCIP_EXPRGRAPHNODE* tmp;
15459 
15460  tmp = rootnodes[0];
15461  rootnodes[0] = rootnodes[1];
15462  rootnodes[1] = tmp;
15463  op = SCIP_EXPR_MINUS;
15464  }
15465  else
15466  op = SCIP_EXPR_LINEAR;
15467 
15468  if( op != SCIP_EXPR_LINEAR )
15469  {
15470  SCIP_EXPROPDATA data;
15471  data.data = NULL;
15472 
15473  if( !*rootnodeisnew )
15474  {
15475  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15476  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15477  }
15478 
15479  if( *rootnode == NULL )
15480  {
15481  /* create new node for sum of rootnodes and add to exprgraph */
15482  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15483  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15484  *rootnodeisnew = TRUE;
15485  }
15486  else
15487  {
15488  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15489  *rootnodeisnew = FALSE;
15490  }
15491  }
15492  else
15493  {
15494  SCIP_EXPROPDATA data;
15495  SCIP_Real* lindata;
15496 
15497  assert(op == SCIP_EXPR_LINEAR);
15498 
15499  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15500  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15501  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
15502  lindata[nexprtrees] = 0.0;
15503  data.data = lindata;
15504 
15505  if( !*rootnodeisnew )
15506  {
15507  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15508  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15509  }
15510 
15511  if( *rootnode == NULL )
15512  {
15513  /* create new node for linear combination of rootnodes and add to exprgraph */
15514  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15515  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15516  *rootnodeisnew = TRUE;
15517  }
15518  else
15519  {
15520  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15521  *rootnodeisnew = FALSE;
15522  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15523  }
15524  }
15525 
15526  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15527  }
15528  assert(*rootnode != NULL);
15529 
15530  SCIPexprgraphCaptureNode(*rootnode);
15531 
15532  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15533  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15534 
15535  return SCIP_OKAY;
15536 }
15537 
15538 /** replaces variable in expression graph by a linear sum of variables
15539  *
15540  * Variables will be added if not in the graph yet.
15541  */
15543  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15544  void* var, /**< variable to replace */
15545  int ncoefs, /**< number of coefficients in linear term */
15546  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
15547  void** vars, /**< variables in linear term */
15548  SCIP_Real constant /**< constant offset */
15549  )
15550 {
15551  SCIP_EXPRGRAPHNODE* varnode;
15552  SCIP_Real* lindata;
15553  int varidx;
15554  int i;
15555 
15556  assert(exprgraph != NULL);
15557  assert(var != NULL);
15558  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15559  assert(coefs != NULL || ncoefs == 0);
15560  assert(vars != NULL || ncoefs == 0);
15561 
15562  varidx = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15563  assert(varidx < exprgraph->nvars);
15564  assert(exprgraph->vars[varidx] == var);
15565  varnode = exprgraph->varnodes[varidx];
15566  assert(varnode != NULL);
15567  assert(varnode->data.intval == varidx);
15568 
15569  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
15570  {
15571  /* variable is replaced by constant or variable */
15572  SCIP_EXPRGRAPHNODE* node;
15573 
15574  /* check if there is already a node for this constant or variable */
15575  node = NULL;
15576  if( ncoefs == 0 )
15577  {
15578  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15579  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
15580  }
15581  else
15582  {
15583  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
15584  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
15585  }
15586 
15587  if( node != NULL )
15588  {
15589  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15590 
15591  /* tell parents of varnode to replace child varnode by node, this may free varnode */
15592  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15593 
15594  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15595  if( varnode != NULL )
15596  {
15597  assert(varnode->nuses > 0);
15598  assert(varnode->nparents == 0);
15599 
15600  /* remove variable (but don't free it's node) from graph */
15601  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15602 
15603  /* move varnode up to depth 1 */
15604  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15605 
15606  /* turn into EXPR_SUM expression */
15607  varnode->op = SCIP_EXPR_SUM;
15608  varnode->data.data = NULL;
15609  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
15610  varnode->children[0] = node;
15611  varnode->nchildren = 1;
15612  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15613 
15614  varnode->value = node->value;
15615  varnode->bounds = node->bounds;
15616  varnode->boundstatus = (node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID) ? SCIP_EXPRBOUNDSTATUS_VALID : SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
15617  }
15618  }
15619  else if( ncoefs == 0 )
15620  {
15621  /* turn node into EXPR_CONST node */
15622 
15623  /* remove variable (but don't free it's node) from graph */
15624  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15625 
15626  /* convert into EXPR_CONST node */
15627  varnode->op = SCIP_EXPR_CONST;
15628  varnode->data.dbl = constant;
15629 
15630  varnode->value = constant;
15631  SCIPintervalSet(&varnode->bounds, constant);
15633 
15634  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15635  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15636  exprgraph->constnodes[exprgraph->nconsts] = varnode;
15637  ++exprgraph->nconsts;
15638  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15639  }
15640  else
15641  {
15642  /* turn node into EXPR_VARIDX node for new variable */
15643 
15644  /* remove variable (but don't free it's node) from graph */
15645  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15646 
15647  varnode->data.intval = exprgraph->nvars;
15648 
15649  /* add variable node to vars arrays and hashmap */
15650  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15651  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
15652  exprgraph->varnodes[exprgraph->nvars] = varnode;
15653  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15654  SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[0], exprgraph->nvars) ); /*lint !e613*/
15655  ++exprgraph->nvars;
15656 
15657  /* call callback method, if set */
15658  if( exprgraph->exprgraphvaradded != NULL )
15659  {
15660  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
15661  }
15662  }
15663 
15664  /* mark varnode and its parents as not simplified */
15665  if( varnode != NULL )
15666  {
15667  varnode->simplified = FALSE;
15668  for( i = 0; i < varnode->nparents; ++i )
15669  varnode->parents[i]->simplified = FALSE;
15670  }
15671 
15672  return SCIP_OKAY;
15673  }
15674 
15675  /* turn varnode into EXPR_LINEAR */
15676 
15677  /* remove variable (but don't free it's node) from graph */
15678  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15679 
15680  /* move varnode up to depth 1 */
15681  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15682 
15683  /* convert into EXPR_LINEAR node */
15684  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15685  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
15686  lindata[ncoefs] = constant;
15687  varnode->data.data = (void*)lindata;
15688  varnode->op = SCIP_EXPR_LINEAR;
15689 
15690  /* add nodes corresponding to vars to expression graph, if not existing yet */
15691  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15692  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15693  varnode->nchildren = ncoefs;
15694 
15695  /* notify vars about new parent varnode */
15696  for( i = 0; i < ncoefs; ++i )
15697  {
15698  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15699  }
15700 
15701  /* set value and bounds to invalid, curvature can remain (still linear) */
15702  varnode->value = SCIP_INVALID;
15704 
15705  /* mark varnode and its parents as not simplified */
15706  varnode->simplified = FALSE;
15707  for( i = 0; i < varnode->nparents; ++i )
15708  varnode->parents[i]->simplified = FALSE;
15709 
15710  return SCIP_OKAY;
15711 }
15712 
15713 /** finds expression graph node corresponding to a variable */
15715  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15716  void* var, /**< variable to search for */
15717  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15718  )
15719 {
15720  int pos;
15721 
15722  assert(exprgraph != NULL);
15723  assert(var != NULL);
15724  assert(varnode != NULL);
15725 
15726  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15727  {
15728  *varnode = NULL;
15729  return FALSE;
15730  }
15731 
15732  pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15733  assert(pos < exprgraph->nvars);
15734 
15735  *varnode = exprgraph->varnodes[pos];
15736  assert(*varnode != NULL);
15737  assert((*varnode)->op == SCIP_EXPR_VARIDX);
15738 
15739  return TRUE;
15740 }
15741 
15742 /** finds expression graph node corresponding to a constant */
15744  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15745  SCIP_Real constant, /**< constant to search for */
15746  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15747  )
15748 {
15749  int left;
15750  int right;
15751  int middle;
15752 
15753  assert(exprgraph != NULL);
15754  assert(constnode != NULL);
15755  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
15756 
15757  exprgraphSortConstNodes(exprgraph);
15758  assert(exprgraph->constssorted);
15759 
15760  /* find node using binary search */
15761  left = 0;
15762  right = exprgraph->nconsts-1;
15763  *constnode = NULL;
15764 
15765  while( left <= right )
15766  {
15767  middle = (left+right)/2;
15768  assert(0 <= middle && middle < exprgraph->nconsts);
15769 
15770  if( constant < exprgraph->constnodes[middle]->data.dbl )
15771  right = middle - 1;
15772  else if( constant > exprgraph->constnodes[middle]->data.dbl )
15773  left = middle + 1;
15774  else
15775  {
15776  *constnode = exprgraph->constnodes[middle];
15777  break;
15778  }
15779  }
15780  if( left == right+1 )
15781  return FALSE;
15782 
15783  assert(*constnode != NULL);
15784  assert((*constnode)->op == SCIP_EXPR_CONST);
15785  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15786 
15787  return TRUE;
15788 }
15789 
15790 /** prints an expression graph in dot format */
15792  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15793  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15794  FILE* file, /**< file to print to, or NULL for stdout */
15795  const char** varnames /**< variable names, or NULL for generic names */
15796  )
15797 {
15798  int d;
15799  int i;
15800 
15801  assert(exprgraph != NULL);
15802 
15803  if( file == NULL )
15804  file = stdout;
15805 
15806  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15807  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15808 
15809  for( d = 0; d < exprgraph->depth; ++d )
15810  {
15811  if( exprgraph->nnodes[d] == 0 )
15812  continue;
15813 
15814  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15815  {
15816  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15817  }
15818  }
15819 
15820  /* tell dot that all nodes of depth 0 have the same rank */
15821  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15822  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15823  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15824  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15825 
15826  /* tell dot that all nodes without parent have the same rank */
15827  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15828  for( d = 0; d < exprgraph->depth; ++d )
15829  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15830  if( exprgraph->nodes[d][i]->nparents == 0 )
15831  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15832  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15833 
15834  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15835 
15836  return SCIP_OKAY;
15837 }
15838 
15839 /** evaluates nodes of expression graph for given values of variables */
15841  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15842  SCIP_Real* varvals /**< values for variables */
15843  )
15844 {
15845  int d;
15846  int i;
15847 
15848  assert(exprgraph != NULL);
15849  assert(varvals != NULL || exprgraph->nvars == 0);
15850 
15851  for( d = 0; d < exprgraph->depth; ++d )
15852  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15853  {
15854  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15855  }
15856 
15857  return SCIP_OKAY;
15858 }
15859 
15860 /** propagates bound changes in variables forward through the expression graph */
15862  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15863  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15864  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
15865  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15866  )
15867 {
15868  SCIP_EXPRGRAPHNODE* node;
15869  SCIP_Bool boundchanged;
15870  int d;
15871  int i;
15872 
15873  assert(exprgraph != NULL);
15874  assert(domainerror != NULL);
15875 
15876  *domainerror = FALSE;
15877 
15878  /* update bounds in varnodes of expression graph */
15879  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15880 
15881  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15882  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15883  {
15884  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15885  return SCIP_OKAY;
15886  }
15887 
15888  /* propagate bound changes, interrupt if we get to a node with empty bounds */
15889  for( d = 1; d < exprgraph->depth; ++d )
15890  {
15891  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15892  {
15893  node = exprgraph->nodes[d][i];
15894  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15895  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15896  {
15897  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15898  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15899  *domainerror = TRUE;
15900  return SCIP_OKAY;
15901  }
15902  }
15903  }
15904 
15905  exprgraph->needvarboundprop = FALSE;
15906 
15907  return SCIP_OKAY;
15908 }
15909 
15910 /** propagates bound changes in nodes backward through the graph
15911  *
15912  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15913  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15914  */
15916  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15917  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15918  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15919  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15920  )
15921 {
15922  SCIP_EXPRGRAPHNODE* node;
15923  int d;
15924  int i;
15925 
15926  assert(exprgraph != NULL);
15927  assert(cutoff != NULL);
15928 
15929  *cutoff = FALSE;
15930 
15931  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15932  {
15933  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15934  {
15935  node = exprgraph->nodes[d][i];
15936  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15937  }
15938  }
15939  if( *cutoff )
15940  return;
15941 }
15942 
15943 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15944  *
15945  * Implies update of bounds in expression graph.
15946  */
15948  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15949  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15950  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15951  )
15952 {
15953  SCIP_EXPRGRAPHNODE* node;
15954  SCIP_Bool boundchanged;
15955  int d;
15956  int i;
15957 
15958  assert(exprgraph != NULL);
15959 
15960  /* update bounds in varnodes of expression graph */
15961  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15962 
15963 #ifndef NDEBUG
15964  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15965  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15966 #endif
15967 
15968  for( d = 1; d < exprgraph->depth; ++d )
15969  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15970  {
15971  node = exprgraph->nodes[d][i];
15972  assert(node != NULL);
15973 
15974  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15975 
15976  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15977  {
15978  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15979  return SCIP_OKAY;
15980  }
15981  }
15982 
15983  return SCIP_OKAY;
15984 }
15985 
15986 /** aims at simplifying an expression graph
15987  *
15988  * 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)).
15989  */
15991  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15992  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15993  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15994  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15995  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15996  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15997  )
15998 {
15999  SCIP_EXPRGRAPHNODE* node;
16000  SCIP_Bool havechangenode;
16001  SCIP_Bool allsimplified;
16002  int d;
16003  int i;
16004  int j;
16005 
16006 #ifndef NDEBUG
16007  SCIP_Real* testx;
16008  SCIP_HASHMAP* testvalidx;
16009  SCIP_Real* testvals;
16010  SCIP_RANDNUMGEN* randnumgen;
16011  int testvalssize;
16012  int ntestvals;
16013 #endif
16014 
16015  assert(exprgraph != NULL);
16016  assert(eps >= 0.0);
16017  assert(havechange != NULL);
16018  assert(domainerror != NULL);
16019 
16020 #ifndef NDEBUG
16021  SCIP_CALL( SCIPrandomCreate(&randnumgen, exprgraph->blkmem, 862) ); /* see also #1848 */
16022  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
16023  testvals = NULL;
16024  ntestvals = 0;
16025  testvalssize = 0;
16026 
16027  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
16028  for( i = 0; i < exprgraph->nvars; ++i )
16029  testx[i] = SCIPrandomGetReal(randnumgen,
16030  exprgraph->varbounds[i].inf < -100.0 ? MIN(-100.0, exprgraph->varbounds[i].sup) : exprgraph->varbounds[i].inf,
16031  exprgraph->varbounds[i].sup > 100.0 ? MAX( 100.0, exprgraph->varbounds[i].inf) : exprgraph->varbounds[i].sup); /*lint !e644*/
16032  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
16033  for( d = 1; d < exprgraph->depth; ++d )
16034  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16035  {
16036  node = exprgraph->nodes[d][i];
16037  assert(node != NULL);
16038 
16039  /* 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 */
16040  if( node->nuses > 0 )
16041  {
16042  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
16043  SCIP_CALL( SCIPhashmapInsertInt(testvalidx, (void*)node, ntestvals) );
16044  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
16045  ++ntestvals;
16046  }
16047  }
16048 
16049  SCIPrandomFree(&randnumgen, exprgraph->blkmem);
16050 #endif
16051 
16052 #ifdef SCIP_OUTPUT
16053  {
16054  FILE* file;
16055  file = fopen("exprgraph_beforesimplify.dot", "w");
16056  if( file != NULL )
16057  {
16058  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16059  fclose(file);
16060  }
16061  }
16062 #endif
16063 
16064  *havechange = FALSE; /* we have not changed any node yet */
16065  *domainerror = FALSE; /* no domain errors encountered so far */
16066  allsimplified = TRUE; /* all nodes we looked at are simplified */
16067 
16068  /* call node simplifier from bottom up
16069  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
16070  */
16071  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
16072  {
16073  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16074  {
16075  node = exprgraph->nodes[d][i];
16076  assert(node != NULL);
16077 
16078  havechangenode = FALSE; /* node did not change yet */
16079 
16080  if( node->op != SCIP_EXPR_CONST )
16081  {
16082  /* skip nodes that are already simplified */
16083  if( node->simplified )
16084  continue;
16085 
16086  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
16087 
16088  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
16089  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
16090  assert(node->simplified == TRUE);
16091  *havechange |= havechangenode;
16092  }
16093 
16094  /* if node was or has been converted into constant, may move to depth 0 */
16095  if( node->op == SCIP_EXPR_CONST )
16096  {
16097  SCIP_EXPRGRAPHNODE* constnode;
16098 
16099  if( !SCIPisFinite(node->value) ) /*lint !e777*/
16100  {
16101  SCIPdebugMessage("Expression graph simplify turned node into NaN or inf.\n");
16102  *domainerror = TRUE;
16103  break;
16104  }
16105 
16106  /* check if there is already a node for this constant */
16107  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
16108  {
16109  assert(constnode->op == SCIP_EXPR_CONST);
16110  assert(constnode->data.dbl == node->value); /*lint !e777*/
16111 
16112  if( node->nparents > 0 )
16113  {
16114  /* move parents of this node to constnode, node may be freed if not in use */
16115  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
16116  /* node should have no parents anymore, so it should have been freed if not in use */
16117  assert(node == NULL || node->nuses > 0);
16118  havechangenode = TRUE;
16119 
16120  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
16121  if( node == NULL )
16122  {
16123  --i;
16124  continue;
16125  }
16126  }
16127  assert(node != NULL);
16128  assert(node->nuses > 0);
16129 
16130  if( constnode->nuses == 0 )
16131  {
16132  /* move node to depth 0, adding it to constnodes */
16133  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16134 
16135  /* move parents of constnode to node, so constnode is freed */
16136  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
16137  assert(constnode == NULL);
16138  havechangenode = TRUE;
16139 
16140  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16141  --i;
16142  continue;
16143  }
16144  }
16145  else
16146  {
16147  /* move to depth 0, adding it to constnodes */
16148  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16149 
16150  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16151  --i;
16152  }
16153  }
16154 
16155  /* if there was a change, mark parents as not simplified */
16156  if( havechangenode )
16157  for( j = 0; j < node->nparents; ++j )
16158  node->parents[j]->simplified = FALSE;
16159  }
16160  } /*lint !e850*/
16161 
16162  /* if we did nothing, clean up and escape from here */
16163  if( allsimplified || *domainerror )
16164  goto EXPRGRAPHSIMPLIFY_CLEANUP;
16165 
16166  /* @todo find duplicate subexpressions in expression graph */
16167 
16168  /* unconvert polynomials into simpler expressions, where possible */
16169  for( d = 1; d < exprgraph->depth; ++d )
16170  {
16171  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16172  {
16173  node = exprgraph->nodes[d][i];
16174  assert(node != NULL);
16175 
16176  if( node->op != SCIP_EXPR_POLYNOMIAL )
16177  continue;
16178 
16179  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
16180 
16181  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
16182  {
16183  /* node is identity w.r.t only child
16184  * replace node as child of parents by child of node
16185  */
16186 
16187  for( j = 0; node != NULL && j < node->nparents; ++j )
16188  {
16189  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
16190  }
16191  /* node should have no parents anymore, so it should have been freed if not in use */
16192  assert(node == NULL || node->nuses > 0);
16193 
16194  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
16195  if( node == NULL )
16196  --i;
16197  }
16198  }
16199  } /*lint !e850*/
16200 
16201 #ifdef SCIP_OUTPUT
16202  {
16203  FILE* file;
16204  file = fopen("exprgraph_aftersimplify.dot", "w");
16205  if( file != NULL )
16206  {
16207  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16208  fclose(file);
16209  }
16210  }
16211 #endif
16212 
16213 #ifndef NDEBUG
16214  for( d = 1; d < exprgraph->depth; ++d )
16215  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16216  {
16217  int idx;
16218  SCIP_Real testval_before;
16219  SCIP_Real testval_after;
16220 
16221  node = exprgraph->nodes[d][i];
16222  assert(node != NULL);
16223 
16224  SCIP_CALL( exprgraphNodeEval(node, NULL) );
16225 
16226  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
16227  if( node->nuses > 0 )
16228  {
16229  assert(SCIPhashmapExists(testvalidx, (void*)node));
16230 
16231  idx = SCIPhashmapGetImageInt(testvalidx, (void*)node);
16232  assert(idx < ntestvals);
16233  assert(testvals != NULL);
16234 
16235  testval_before = testvals[idx]; /*lint !e613*/
16236  testval_after = SCIPexprgraphGetNodeVal(node);
16237 
16238  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), 10*eps)); /*lint !e777*/
16239  }
16240  }
16241 #endif
16242 
16243  EXPRGRAPHSIMPLIFY_CLEANUP:
16244 #ifndef NDEBUG
16245  BMSfreeMemoryArray(&testx);
16246  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
16247  SCIPhashmapFree(&testvalidx);
16248 #endif
16249 
16250  return SCIP_OKAY;
16251 }
16252 
16253 /** creates an expression tree from a given node in an expression graph */
16255  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16256  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
16257  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
16258  )
16259 {
16260  SCIP_EXPR* root;
16261  int nexprvars;
16262  int* varidx;
16263  int i;
16264 
16265  assert(exprgraph != NULL);
16266  assert(rootnode != NULL);
16267  assert(rootnode->depth >= 0);
16268  assert(rootnode->pos >= 0);
16269  assert(exprtree != NULL);
16270 
16271  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16272  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16273 
16274  /* initially, no variable appears in the expression tree */
16275  for( i = 0; i < exprgraph->nvars; ++i )
16276  varidx[i] = -1; /*lint !e644*/
16277  nexprvars = 0;
16278 
16279  /* create expression from the subgraph that has rootnode as root */
16280  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
16281 
16282  /* create expression tree for this expression */
16283  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
16284 
16285  /* copy variables into expression tree */
16286  if( nexprvars > 0 )
16287  {
16288  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
16289  for( i = 0; i < exprgraph->nvars; ++i )
16290  {
16291  assert(varidx[i] >= -1);
16292  assert(varidx[i] < nexprvars);
16293  if( varidx[i] >= 0 )
16294  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
16295  }
16296  }
16297 
16298  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16299 
16300  return SCIP_OKAY;
16301 }
16302 
16303 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16304  *
16305  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16306  */
16308  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16309  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16310  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16311  int* nexprtrees, /**< buffer to store number of expression trees */
16312  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16313  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16314  )
16315 {
16316  int ncomponents;
16317  int* childcomp;
16318  int* varcomp;
16319  int compnr;
16320  SCIP_Bool haveoverlap;
16321  int i;
16322  int j;
16323  int k;
16324 
16325  SCIP_EXPR** exprs;
16326  int nexprs;
16327  int* childmap;
16328  int* childmapinv;
16329  int* varidx;
16330  int nexprvars;
16331 
16332  assert(exprgraph != NULL);
16333  assert(node != NULL);
16334  assert(node->depth >= 0);
16335  assert(node->pos >= 0);
16336  assert(exprtreessize > 0);
16337  assert(nexprtrees != NULL);
16338  assert(exprtrees != NULL);
16339  assert(exprtreecoefs != NULL);
16340 
16341  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16342  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16343  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16344  ( node->op != SCIP_EXPR_PLUS &&
16345  node->op != SCIP_EXPR_MINUS &&
16346  node->op != SCIP_EXPR_SUM &&
16347  node->op != SCIP_EXPR_LINEAR &&
16348  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16349  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16350  {
16351  *nexprtrees = 1;
16352  exprtreecoefs[0] = 1.0;
16353  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16354 
16355  return SCIP_OKAY;
16356  }
16357 
16358  /* find components in node->children <-> variables graph */
16359  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16360  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16361  for( i = 0; i < exprgraph->nvars; ++i )
16362  varcomp[i] = -1; /*lint !e644*/
16363 
16364  haveoverlap = FALSE;
16365  for( i = 0; i < node->nchildren; ++i )
16366  {
16367  compnr = i;
16368  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
16369  assert(compnr >= 0);
16370  assert(compnr < node->nchildren);
16371  childcomp[i] = compnr;
16372 
16373  /* remember if component number was changed by CheckComponent */
16374  if( compnr != i )
16375  haveoverlap = TRUE;
16376  }
16377 
16378  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16379 
16380  if( node->op == SCIP_EXPR_QUADRATIC )
16381  {
16382  /* merge components for products of children from different components */
16384 
16385  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16386  assert(data != NULL);
16387 
16388  for( i = 0; i < data->nquadelems; ++i )
16389  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16390  {
16391  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16392  compnr = childcomp[data->quadelems[i].idx2];
16393  for( j = 0; j < node->nchildren; ++j )
16394  if( childcomp[j] == compnr )
16395  childcomp[j] = childcomp[data->quadelems[i].idx1];
16396  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16397  haveoverlap = TRUE;
16398  }
16399  }
16400  else if( node->op == SCIP_EXPR_POLYNOMIAL )
16401  {
16402  /* merge components for monomials of children from different components */
16404 
16405  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16406  assert(data != NULL);
16407 
16408  for( i = 0; i < data->nmonomials; ++i )
16409  for( j = 1; j < data->monomials[i]->nfactors; ++j )
16410  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16411  {
16412  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16413  compnr = childcomp[data->monomials[i]->childidxs[j]];
16414  for( k = 0; k < node->nchildren; ++k )
16415  if( childcomp[k] == compnr )
16416  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16417  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16418  haveoverlap = TRUE;
16419  }
16420  }
16421 
16422  if( haveoverlap )
16423  {
16424  /* some component numbers are unused, thus relabel and count final number of components */
16425  int* compmap;
16426 
16427  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16428  for( i = 0; i < node->nchildren; ++i )
16429  compmap[i] = -1; /*lint !e644*/
16430 
16431  ncomponents = 0;
16432  for( i = 0; i < node->nchildren; ++i )
16433  {
16434  if( compmap[childcomp[i]] == -1 )
16435  compmap[childcomp[i]] = ncomponents++;
16436  childcomp[i] = compmap[childcomp[i]];
16437  }
16438 
16439  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16440  }
16441  else
16442  {
16443  ncomponents = node->nchildren;
16444  }
16445 
16446  if( ncomponents == 1 )
16447  {
16448  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16449  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16450 
16451  *nexprtrees = 1;
16452  exprtreecoefs[0] = 1.0;
16453  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16454 
16455  return SCIP_OKAY;
16456  }
16457 
16458  if( ncomponents > exprtreessize )
16459  {
16460  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16461  for( i = 0; i < node->nchildren; ++i )
16462  if( childcomp[i] >= exprtreessize )
16463  childcomp[i] = exprtreessize-1;
16464  ncomponents = exprtreessize;
16465  }
16466 
16467  assert(ncomponents >= 2);
16468 
16469  /* setup expression trees for each component */
16470  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16471  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16472  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16473  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16474  for( i = 0; i < ncomponents; ++i )
16475  {
16476  /* initially, no variable appears in the expression tree */
16477  for( j = 0; j < exprgraph->nvars; ++j )
16478  varidx[j] = -1; /*lint !e644*/
16479  nexprvars = 0;
16480 
16481  /* collect expressions from children belonging to component i */
16482  nexprs = 0;
16483  for( j = 0; j < node->nchildren; ++j )
16484  {
16485  assert(childcomp[j] >= 0);
16486  assert(childcomp[j] < ncomponents);
16487  if( childcomp[j] != i )
16488  continue;
16489 
16490  /* create expression from the subgraph that has child j as root */
16491  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
16492  childmap[j] = nexprs; /*lint !e644*/
16493  childmapinv[nexprs] = j; /*lint !e644*/
16494  ++nexprs;
16495  }
16496 
16497  /* setup expression tree for component i */
16498  switch( node->op )
16499  {
16500  case SCIP_EXPR_PLUS:
16501  {
16502  assert(ncomponents == 2);
16503  assert(nexprs == 1);
16504 
16505  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16506  exprtreecoefs[i] = 1.0;
16507 
16508  break;
16509  }
16510 
16511  case SCIP_EXPR_MINUS:
16512  {
16513  assert(ncomponents == 2);
16514  assert(nexprs == 1);
16515 
16516  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16517  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16518  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16519  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16520 
16521  break;
16522  }
16523 
16524  case SCIP_EXPR_SUM:
16525  {
16526  if( nexprs == 1 )
16527  {
16528  /* component corresponds to exactly one child of node */
16529  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16530  }
16531  else
16532  {
16533  /* component corresponds to a sum of children of node */
16534  SCIP_EXPR* sumexpr;
16535 
16536  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16537  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16538  }
16539  exprtreecoefs[i] = 1.0;
16540 
16541  break;
16542  }
16543 
16544  case SCIP_EXPR_LINEAR:
16545  {
16546  SCIP_Real* nodecoefs;
16547  SCIP_EXPR* sumexpr;
16548 
16549  nodecoefs = (SCIP_Real*)node->data.data;
16550 
16551  /* if there is a constant, then we put it into the expression of the first component */
16552  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16553  {
16554  /* component corresponds to exactly one child of node */
16555  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16556  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16557  }
16558  else if( nexprs == 1 )
16559  {
16560  /* component corresponds to a sum of one child and a constant */
16561  assert(i == 0);
16562  assert(nodecoefs[node->nchildren] != 0.0);
16563  assert(nodecoefs[childmapinv[0]] != 0.0);
16564  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16565  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16566  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16567  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16568  }
16569  else
16570  {
16571  /* component corresponds to a linear combination of children of node */
16572 
16573  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16574  {
16575  /* if two expressions with equal sign, then create PLUS expression */
16576  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16577  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16578  }
16579  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16580  {
16581  /* if two expressions with opposite sign, then create MINUS expression */
16582  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16583  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16584  }
16585  else
16586  {
16587  /* assemble coefficents and create SUM or LINEAR expression */
16588  SCIP_Real* coefs;
16589  SCIP_Bool allcoefsequal;
16590 
16591  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16592  allcoefsequal = TRUE;
16593  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
16594  for( j = 0; j < nexprs; ++j )
16595  {
16596  coefs[j] = nodecoefs[childmapinv[j]];
16597  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
16598  }
16599 
16600  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16601  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16602  {
16603  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16604  exprtreecoefs[i] = coefs[0];
16605  }
16606  else
16607  {
16608  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16609  exprtreecoefs[i] = 1.0;
16610  }
16611 
16612  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16613  }
16614 
16615  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16616  }
16617 
16618  break;
16619  }
16620 
16621  case SCIP_EXPR_QUADRATIC:
16622  {
16623  SCIP_EXPR* quadexpr;
16625  SCIP_Real* lincoefs;
16626  SCIP_QUADELEM* quadelems;
16627  int nquadelems;
16628 
16629  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16630 
16631  exprtreecoefs[i] = 1.0;
16632 
16633  /* assemble coefficients corresponding to component i */
16634  if( nodedata->lincoefs != NULL )
16635  {
16636  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16637  for( j = 0; j < nexprs; ++j )
16638  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
16639  }
16640  else
16641  lincoefs = NULL;
16642 
16643  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16644  nquadelems = 0;
16645  for( j = 0; j < nodedata->nquadelems; ++j )
16646  {
16647  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16648  if( childcomp[nodedata->quadelems[j].idx1] != i )
16649  continue;
16650  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
16651  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16652  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16653  ++nquadelems;
16654  }
16655 
16656  /* put constant into first component */
16657  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16658  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16659 
16660  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16661  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16662 
16663  break;
16664  }
16665 
16666  case SCIP_EXPR_POLYNOMIAL:
16667  {
16668  SCIP_EXPR* polyexpr;
16670  SCIP_EXPRDATA_MONOMIAL** monomials;
16671  SCIP_Real constant;
16672  int nmonomials;
16673 
16674  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16675 
16676  constant = nodedata->constant;
16677  exprtreecoefs[i] = 1.0;
16678 
16679  /* collect monomials belonging to component i */
16680  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16681  nmonomials = 0;
16682  for( j = 0; j < nodedata->nmonomials; ++j )
16683  {
16684  if( nodedata->monomials[j]->nfactors == 0 )
16685  {
16686  constant += nodedata->monomials[j]->coef;
16687  continue;
16688  }
16689  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16690  continue;
16691 
16692  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16693  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
16694  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16695  {
16696  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16697  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16698  }
16699  ++nmonomials;
16700  }
16701 
16702  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16703  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16704 
16705  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16706 
16707  break;
16708  }
16709 
16710  default:
16711  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16712  return SCIP_ERROR;
16713  } /*lint !e788*/
16714 
16715  /* copy variables into expression tree */
16716  if( nexprvars > 0 )
16717  {
16718  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16719  for( j = 0; j < exprgraph->nvars; ++j )
16720  {
16721  assert(varidx[j] >= -1);
16722  assert(varidx[j] < nexprvars);
16723  if( varidx[j] >= 0 )
16724  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16725  }
16726  }
16727  }
16728 
16729  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16730  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16731  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16732  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16733  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16734 
16735  *nexprtrees = ncomponents;
16736 
16737  return SCIP_OKAY;
16738 }
16739 
16740 /** returns how often expression graph variables are used in a subtree of the expression graph */
16742  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16743  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
16744  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16745  )
16746 {
16747  assert(exprgraph != NULL);
16748  assert(node != NULL);
16749  assert(varsusage != NULL);
16750 
16751  BMSclearMemoryArray(varsusage, exprgraph->nvars);
16752 
16753  exprgraphNodeGetVarsUsage(node, varsusage);
16754 }
16755 
16756 /** gives the number of summands which the expression of an expression graph node consists of */
16758  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
16759  )
16760 {
16761  switch( node->op )
16762  {
16763  case SCIP_EXPR_PLUS:
16764  case SCIP_EXPR_MINUS:
16765  return 2;
16766 
16767  case SCIP_EXPR_SUM:
16768  case SCIP_EXPR_LINEAR:
16769  return node->nchildren;
16770 
16771  case SCIP_EXPR_QUADRATIC:
16772  {
16774 
16775  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16776  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16777  }
16778 
16779  case SCIP_EXPR_POLYNOMIAL:
16780  {
16782 
16783  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16784  return nodedata->nmonomials;
16785  }
16786 
16787  default:
16788  return 1;
16789  } /*lint !e788*/
16790 }
16791 
16792 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
16794  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16795  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16796  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16797  int* nexprtrees, /**< buffer to store number of expression trees */
16798  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16799  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16800  )
16801 {
16802  int* varidx;
16803  int nexprvars;
16804  int i;
16805 
16806  assert(exprgraph != NULL);
16807  assert(node != NULL);
16808  assert(node->depth >= 0);
16809  assert(node->pos >= 0);
16810  assert(exprtreessize > 0);
16811  assert(nexprtrees != NULL);
16812  assert(exprtrees != NULL);
16813  assert(exprtreecoefs != NULL);
16814 
16815  /* if node is not separable, fallback to SCIPexprgraphGetTree */
16816  if( node->op != SCIP_EXPR_PLUS &&
16817  node->op != SCIP_EXPR_MINUS &&
16818  node->op != SCIP_EXPR_SUM &&
16819  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16820  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16821  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16822  {
16823  *nexprtrees = 1;
16824  exprtreecoefs[0] = 1.0;
16825  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16826 
16827  return SCIP_OKAY;
16828  }
16829 
16830  switch( node->op )
16831  {
16832  case SCIP_EXPR_PLUS:
16833  {
16834  assert(exprtreessize >= 2);
16835 
16836  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16837  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16838 
16839  exprtreecoefs[0] = 1.0;
16840  exprtreecoefs[1] = 1.0;
16841 
16842  *nexprtrees = 2;
16843  break;
16844  }
16845 
16846  case SCIP_EXPR_MINUS:
16847  {
16848  assert(exprtreessize >= 2);
16849 
16850  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16851  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16852 
16853  exprtreecoefs[0] = 1.0;
16854  exprtreecoefs[1] = -1.0;
16855 
16856  *nexprtrees = 2;
16857  break;
16858  }
16859 
16860  case SCIP_EXPR_SUM:
16861  {
16862  assert(exprtreessize >= node->nchildren);
16863 
16864  for( i = 0; i < node->nchildren; ++i )
16865  {
16866  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16867  exprtreecoefs[i] = 1.0;
16868  }
16869 
16870  *nexprtrees = node->nchildren;
16871  break;
16872  }
16873 
16874  case SCIP_EXPR_LINEAR:
16875  {
16876  SCIP_Real* nodecoefs;
16877 
16878  assert(exprtreessize >= node->nchildren);
16879  assert(node->nchildren > 0);
16880 
16881  nodecoefs = (SCIP_Real*)node->data.data;
16882  assert(nodecoefs != NULL);
16883 
16884  for( i = 0; i < node->nchildren; ++i )
16885  {
16886  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16887  exprtreecoefs[i] = nodecoefs[i];
16888  }
16889 
16890  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16891  if( nodecoefs[node->nchildren] != 0.0 )
16892  {
16893  SCIP_EXPR* constexpr_;
16894 
16895  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16896  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16897  }
16898 
16899  *nexprtrees = node->nchildren;
16900  break;
16901  }
16902 
16903  case SCIP_EXPR_QUADRATIC:
16904  {
16906  SCIP_Real* lincoefs;
16907  SCIP_QUADELEM* quadelems;
16908  int nquadelems;
16909  SCIP_EXPR* expr;
16910  int j;
16911 
16912  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16913  lincoefs = nodedata->lincoefs;
16914  quadelems = nodedata->quadelems;
16915  nquadelems = nodedata->nquadelems;
16916 
16917  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16918  assert(node->nchildren > 0);
16919 
16920  *nexprtrees = 0;
16921  if( lincoefs != NULL )
16922  {
16923  for( i = 0; i < node->nchildren; ++i )
16924  {
16925  if( lincoefs[i] == 0.0 )
16926  continue;
16927  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16928  exprtreecoefs[*nexprtrees] = lincoefs[i];
16929  ++*nexprtrees;
16930  }
16931  }
16932 
16933  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16934  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16935 
16936  for( i = 0; i < nquadelems; ++i )
16937  {
16938  /* initially, no variable appears in the expression tree */
16939  for( j = 0; j < exprgraph->nvars; ++j )
16940  varidx[j] = -1; /*lint !e644*/
16941  nexprvars = 0;
16942 
16943  /* create expression from the subgraph at quadelems[i].idx1 */
16944  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16945 
16946  if( quadelems[i].idx1 == quadelems[i].idx2 )
16947  {
16948  /* create expression for square of expr */
16949  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16950  }
16951  else
16952  {
16953  SCIP_EXPR* expr2;
16954 
16955  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16956  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16957  /* create expression for product */
16958  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16959  }
16960 
16961  /* create expression tree for expr */
16962  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16963 
16964  /* copy variables into expression tree */
16965  if( nexprvars > 0 )
16966  {
16967  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16968  for( j = 0; j < exprgraph->nvars; ++j )
16969  {
16970  assert(varidx[j] >= -1);
16971  assert(varidx[j] < nexprvars);
16972  if( varidx[j] >= 0 )
16973  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16974  }
16975  }
16976 
16977  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16978 
16979  ++*nexprtrees;
16980  }
16981 
16982  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16983  if( nodedata->constant != 0.0 )
16984  {
16985  SCIP_EXPR* constexpr_;
16986 
16987  assert(*nexprtrees > 0);
16988  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16989  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16990  }
16991 
16992  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16993 
16994  break;
16995  }
16996 
16997  case SCIP_EXPR_POLYNOMIAL:
16998  {
17000  SCIP_EXPRDATA_MONOMIAL** monomials;
17001  SCIP_Real constant;
17002  int nmonomials;
17003  SCIP_EXPR* expr;
17004  int* childidxs;
17005  int j;
17006 
17007  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
17008  monomials = nodedata->monomials;
17009  nmonomials = nodedata->nmonomials;
17010  constant = nodedata->constant;
17011 
17012  assert(exprtreessize >= nmonomials);
17013  assert(node->nchildren > 0);
17014 
17015  *nexprtrees = 0;
17016 
17017  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
17018  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
17019 
17020  for( i = 0; i < nmonomials; ++i )
17021  {
17022  /* initially, no variable appears in the expression tree */
17023  for( j = 0; j < exprgraph->nvars; ++j )
17024  varidx[j] = -1;
17025  nexprvars = 0;
17026 
17027  if( monomials[i]->nfactors == 1 )
17028  {
17029  /* create expression from the subgraph at only factor */
17030  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17031 
17032  /* put exponent in, if not 1.0 */
17033  if( monomials[i]->exponents[0] == 1.0 )
17034  ;
17035  else if( monomials[i]->exponents[0] == 2.0 )
17036  {
17037  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
17038  }
17039  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
17040  {
17041  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
17042  }
17043  else
17044  {
17045  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
17046  }
17047  }
17048  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
17049  {
17050  SCIP_EXPR* expr2;
17051 
17052  /* create expressions for both factors */
17053  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17054  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
17055 
17056  /* create expression for product of factors */
17057  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
17058  }
17059  else
17060  {
17061  SCIP_EXPRDATA_MONOMIAL* monomial;
17062  SCIP_EXPR** exprs;
17063  int f;
17064 
17065  /* create expression for each factor, assemble varidx and nexprvars
17066  * create child indices (= identity) */
17067  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
17068  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
17069  for( f = 0; f < monomials[i]->nfactors; ++f )
17070  {
17071  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
17072  childidxs[f] = f; /*lint !e644*/
17073  }
17074 
17075  /* create monomial and polynomial expression for this monomial
17076  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
17077  */
17078  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
17079  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
17080  constant = 0.0;
17081 
17082  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
17083  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
17084  }
17085 
17086  /* create expression tree for expr */
17087  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
17088 
17089  /* copy variables into expression tree */
17090  if( nexprvars > 0 )
17091  {
17092  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
17093  for( j = 0; j < exprgraph->nvars; ++j )
17094  {
17095  assert(varidx[j] >= -1);
17096  assert(varidx[j] < nexprvars);
17097  if( varidx[j] >= 0 )
17098  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
17099  }
17100  }
17101 
17102  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
17103 
17104  ++*nexprtrees;
17105  }
17106 
17107  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
17108  if( constant != 0.0 )
17109  {
17110  SCIP_EXPR* constexpr_;
17111 
17112  assert(*nexprtrees > 0);
17113  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
17114  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
17115  }
17116 
17117  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
17118 
17119  break;
17120  }
17121 
17122  default:
17123  SCIPerrorMessage("unexpected operator type %d\n", node->op);
17124  return SCIP_ERROR;
17125  } /*lint !e788*/
17126 
17127  return SCIP_OKAY;
17128 }
17129 
17130 /**@} */
void SCIPintervalSignPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_EXPRBOUNDSTATUS_CHILDRELAXED
Definition: type_expr.h:213
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13355
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15861
void SCIPexprFreeDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6185
void SCIPexprtreeGetVarsUsage(SCIP_EXPRTREE *tree, int *varsusage)
Definition: expr.c:8909
void SCIPquadelemSort(SCIP_QUADELEM *quadelems, int nquadelems)
Definition: expr.c:9213
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15542
void SCIPexprSortMonomials(SCIP_EXPR *expr)
Definition: expr.c:7025
void SCIPintervalSubScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define exprcurvSin
Definition: expr.c:2079
#define QUADELEMS_SWAP(x, y)
Definition: expr.c:9094
void SCIPintervalMax(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:459
SCIP_EXPROPDATA data
Definition: struct_expr.h:51
static void exprgraphSortConstNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:9669
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14997
static SCIP_RETCODE exprgraphNodeAddParent(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9346
SCIP_RETCODE SCIPexprSubstituteVars(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR **substexprs)
Definition: expr.c:8147
static SCIP_RETCODE exprsimplifyConvertToPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4267
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:15197
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2486
void SCIPintervalSign(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define QUADELEMS_ISBETTER(a, b)
Definition: expr.c:9091
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:4291
SCIP_RETCODE SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16793
SCIP_RETCODE SCIPexprtreeEvalInt(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_INTERVAL *val)
Definition: expr.c:8741
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:15281
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:140
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:8758
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5922
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:14786
static SCIP_RETCODE polynomialdataMultiplyByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:956
static SCIP_RETCODE exprUnconvertPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren, void **children)
Definition: expr.c:3763
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:8028
static SCIP_RETCODE exprgraphNodeAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nexprs, SCIP_EXPRGRAPHNODE **exprs, int *childmap)
Definition: expr.c:9492
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12991
static SCIP_RETCODE exprgraphNodeCreateExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPR **expr, int *nexprvars, int *varidx)
Definition: expr.c:11807
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5695
SCIP_EXPORT SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
#define infinity
Definition: gastrans.c:71
struct SCIP_UserExprData SCIP_USEREXPRDATA
Definition: type_expr.h:221
void SCIPexprPrint(SCIP_EXPR *expr, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, const char **paramnames, SCIP_Real *paramvals)
Definition: expr.c:8227
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14967
static SCIP_RETCODE exprgraphEnsureDepth(SCIP_EXPRGRAPH *exprgraph, int mindepth)
Definition: expr.c:12080
#define SCIP_MAXSTRLEN
Definition: def.h:273
static void polynomialdataSortMonomials(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata)
Definition: expr.c:801
static SCIP_RETCODE exprgraphNodeSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange)
Definition: expr.c:11477
#define SCIP_VARTYPE_INTEGER_CHAR
Definition: def.h:135
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
SCIP_Real * exponents
Definition: struct_expr.h:95
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2547
#define SCIP_DECL_USEREXPREVAL(x)
Definition: type_expr.h:248
#define SCIP_DECL_USEREXPRPRINT(x)
Definition: type_expr.h:310
int SCIPexprgraphGetDepth(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14937
static SCIP_RETCODE polynomialdataMultiplyByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *factordata, int *childmap)
Definition: expr.c:1000
int lastreplacechildpos
Definition: struct_expr.h:183
static SCIP_RETCODE exprparseFindSeparatingComma(const char *str, const char **endptr, int length)
Definition: expr.c:5066
static SCIP_RETCODE exprgraphNodeRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11408
const char * SCIPexpropGetName(SCIP_EXPROP op)
Definition: expr.c:3265
void SCIPexprChgPolynomialConstant(SCIP_EXPR *expr, SCIP_Real constant)
Definition: expr.c:6691
SCIP_RETCODE SCIPexprgraphAddConst(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15354
SCIP_RETCODE SCIPexprtreeGetMaxDegree(SCIP_EXPRTREE *tree, int *maxdegree)
Definition: expr.c:8712
SCIP_Real * SCIPexprtreeGetParamVals(SCIP_EXPRTREE *tree)
Definition: expr.c:8634
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:15041
SCIP_RETCODE SCIPexprCreateMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial, SCIP_Real coef, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:7037
static SCIP_DECL_SORTPTRCOMP(exprgraphnodecomp)
Definition: expr.c:127
void SCIPexprgraphCaptureNode(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12969
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:13484
static SCIP_DECL_EXPRFREEDATA(exprFreeDataLinear)
Definition: expr.c:2542
SCIP_Real SCIPexprGetRealPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5758
SCIP_EXPROP op
Definition: struct_expr.h:48
int SCIPexprGetOpIndex(SCIP_EXPR *expr)
Definition: expr.c:5725
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3131
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:7797
SCIP_RETCODE SCIPexprPolynomialPower(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int exponent)
Definition: expr.c:6787
void SCIPexprChgMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real newcoef)
Definition: expr.c:6853
SCIP_Bool SCIPexprHasParam(SCIP_EXPR *expr)
Definition: expr.c:7215
SCIPInterval cos(const SCIPInterval &x)
SCIP_Real SCIPexprGetPolynomialConstant(SCIP_EXPR *expr)
Definition: expr.c:5890
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:15915
#define FALSE
Definition: def.h:73
void SCIPintervalMul(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define EPSEQ(x, y, eps)
Definition: def.h:188
#define EPSISINT(x, eps)
Definition: def.h:200
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT
Definition: type_expr.h:214
SCIP_Bool SCIPexprAreEqual(SCIP_EXPR *expr1, SCIP_EXPR *expr2, SCIP_Real eps)
Definition: expr.c:7582
void SCIPexprMonomialPower(SCIP_EXPRDATA_MONOMIAL *monomial, int exponent)
Definition: expr.c:6928
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14987
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:9967
static void exprgraphNodeCheckSeparabilityComponent(SCIP_EXPRGRAPHNODE *node, int *compnr, int nchildcomps, int *childcomps, int nvars, int *varcomps)
Definition: expr.c:12019
static SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11350
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13120
#define TRUE
Definition: def.h:72
#define SCIPdebug(x)
Definition: pub_message.h:84
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static int calcGrowSize(int num)
Definition: expr.c:107
static SCIP_RETCODE exprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op, int nchildren, SCIP_EXPR **children, SCIP_EXPROPDATA opdata)
Definition: expr.c:3294
SCIP_RETCODE SCIPexprtreeCopy(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **targettree, SCIP_EXPRTREE *sourcetree)
Definition: expr.c:8814
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13011
void SCIPexprGetVarsUsage(SCIP_EXPR *expr, int *varsusage)
Definition: expr.c:7559
void SCIPintervalMin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_INTERVAL SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13345
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15840
void SCIPexprReindexVars(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8185
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
#define SCIP_DECL_USEREXPRINTEVAL(x)
Definition: type_expr.h:261
void SCIPintervalPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int * SCIPexprgraphGetNNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14947
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:115
SCIP_RETCODE SCIPexprEvalInt(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7929
#define EPSGE(x, y, eps)
Definition: def.h:192
SCIP_EXPORT void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPexprSortMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:7118
static void polynomialdataApplyChildmap(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int *childmap)
Definition: expr.c:1160
#define SCIPdebugMessage
Definition: pub_message.h:87
static SCIP_DECL_EXPRCURV(exprcurvDefault)
Definition: expr.c:1420
SCIP_EXPRDATA_MONOMIAL ** monomials
Definition: struct_expr.h:80
static struct exprOpTableElement exprOpTable[]
Definition: expr.c:3218
#define SIGN(x)
Definition: expr.c:47
#define BMSduplicateBlockMemory(mem, ptr, source)
Definition: memory.h:451
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15401
SCIP_RETCODE SCIPexprMultiplyMonomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6893
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8773
SCIP_Bool SCIPquadelemSortedFind(SCIP_QUADELEM *quadelems, int idx1, int idx2, int nquadelems, int *pos)
Definition: expr.c:9238
unsigned int SCIP_EXPRINTCAPABILITY
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8644
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:2122
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:15148
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13214
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:10040
real eps
#define SCIP_EXPRESSION_MAXCHILDEST
Definition: expr.c:41
static void exprgraphUpdateVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Bool *clearreverseprop, SCIP_Bool *boundchanged)
Definition: expr.c:12856
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:14420
SCIP_EXPRCURV SCIPexprcurvMonomial(int nfactors, SCIP_Real *exponents, int *factoridxs, SCIP_EXPRCURV *factorcurv, SCIP_INTERVAL *factorbounds)
Definition: expr.c:362
SCIP_EXPRDATA_MONOMIAL ** SCIPexprGetMonomials(SCIP_EXPR *expr)
Definition: expr.c:5866
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:2235
static SCIP_DECL_EXPREVAL(exprevalVar)
Definition: expr.c:1429
SCIP_EXPORT void SCIPsortPtrPtrRealInt(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
public methods for expressions, expression trees, expression graphs, and related stuff ...
SCIP_EXPRCURV SCIPexprcurvMultiply(SCIP_Real factor, SCIP_EXPRCURV curvature)
Definition: expr.c:241
int SCIPexprGetMonomialNFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5912
int SCIPexprGetIntPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5769
void SCIPintervalSin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3220
#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:9012
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13051
static SCIP_RETCODE exprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op, SCIP_EXPROPDATA opdata)
Definition: expr.c:9740
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13202
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:15109
#define SCIP_ALLOC_ABORT(x)
Definition: def.h:354
#define SCIP_DECL_EXPRGRAPHVARADDED(x)
Definition: type_expr.h:183
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3362
SCIP_HASHMAP * varidxs
Definition: struct_expr.h:169
int SCIPexprgraphGetNodeOperatorIndex(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13061
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:4926
SCIP_Real coef
Definition: type_expr.h:104
SCIP_Real inf
Definition: intervalarith.h:39
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:10898
const char * SCIPexprcurvGetName(SCIP_EXPRCURV curv)
Definition: expr.c:475
static const NodeData nodedata[]
Definition: gastrans.c:74
SCIP_Real SCIPexprgraphGetNodeLinearConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13142
#define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize)
Definition: expr.c:88
SCIP_Real * params
Definition: struct_expr.h:62
#define BMSduplicateBlockMemoryArray(mem, ptr, source, num)
Definition: memory.h:453
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13226
SCIP_RETCODE SCIPexprAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:6669
SCIP_Bool SCIPexprgraphHasNodeNonlinearAncestor(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14671
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13365
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:6586
SCIP_Bool SCIPexprgraphFindConstNode(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15743
int SCIPstrncpy(char *t, const char *s, int size)
Definition: misc.c:10633
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:7868
void SCIPexprgraphSetVarsBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_INTERVAL *varbounds)
Definition: expr.c:15009
union SCIP_ExprOpData SCIP_EXPROPDATA
Definition: type_expr.h:92
static SCIP_Bool isUbBetter(SCIP_Real minstrength, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:170
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:139
SCIP_RETCODE SCIPexprgraphCheckCurvature(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop)
Definition: expr.c:15947
SCIP_RETCODE SCIPexprGetMaxDegree(SCIP_EXPR *expr, int *maxdegree)
Definition: expr.c:7234
static void polynomialdataMultiplyByConstant(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_Real factor)
Definition: expr.c:926
#define SCIPerrorMessage
Definition: pub_message.h:55
enum SCIP_ExprOp SCIP_EXPROP
Definition: type_expr.h:91
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:10691
interval arithmetics for provable bounds
#define SCIPdebugPrintf
Definition: pub_message.h:90
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:13554
SCIP_Real * SCIPexprGetQuadLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5842
SCIP_EXPRGRAPHNODE *** SCIPexprgraphGetNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14957
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16757
SCIP_INTERVAL bounds
Definition: struct_expr.h:137
static SCIP_RETCODE exprsimplifyRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4345
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:6143
static const char * curvnames[4]
Definition: expr.c:195
SCIPInterval sqrt(const SCIPInterval &x)
SCIP_Bool SCIPexprgraphHasNodeUserEstimator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13333
static SCIP_DECL_EXPRCOPYDATA(exprCopyDataLinear)
Definition: expr.c:2524
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:5098
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:491
SCIPInterval sign(const SCIPInterval &x)
SCIP_EXPRCURV SCIPexprcurvPower(SCIP_INTERVAL basebounds, SCIP_EXPRCURV basecurv, SCIP_Real exponent)
Definition: expr.c:254
void print(const Container &container, const std::string &prefix="", const std::string &suffix="", std::ostream &os=std::cout, bool negate=false, int prec=6)
SCIP_Real SCIPexprGetQuadConstant(SCIP_EXPR *expr)
Definition: expr.c:5829
static SCIP_RETCODE exprgraphNodeReplaceChild(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE **oldchild, SCIP_EXPRGRAPHNODE *newchild)
Definition: expr.c:9593
void SCIPmessagePrintWarning(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:418
SCIP_EXPRGRAPHNODE *** nodes
Definition: struct_expr.h:162
SCIP_EXPORT SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
#define EXPROPEMPTY
Definition: expr.c:3214
internal miscellaneous methods
#define NULL
Definition: lpi_spx1.cpp:155
void SCIPrandomFree(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem)
Definition: misc.c:9929
static SCIP_Bool exprgraphNodeIsParent(SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9461
static void polynomialdataFree(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata)
Definition: expr.c:713
#define REALABS(x)
Definition: def.h:187
void SCIPexprMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:6807
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:8614
SCIP_Bool SCIPexprAreMonomialsEqual(SCIP_EXPRDATA_MONOMIAL *monomial1, SCIP_EXPRDATA_MONOMIAL *monomial2, SCIP_Real eps)
Definition: expr.c:6822
SCIP_EXPORT void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_EXPRGRAPHNODE ** varnodes
Definition: struct_expr.h:167
SCIP_RETCODE SCIPexprgraphCreateNodeLinear(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int ncoefs, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:13458
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16307
#define SCIP_CALL(x)
Definition: def.h:364
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12981
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:15101
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:6634
SCIP_RETCODE SCIPexprCheckCurvature(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_Real *param, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:8064
SCIP_VAR * h
Definition: circlepacking.c:59
SCIP_RETCODE SCIPexprEvalUser(SCIP_EXPR *expr, SCIP_Real *argvals, SCIP_Real *val, SCIP_Real *gradient, SCIP_Real *hessian)
Definition: expr.c:7971
SCIP_Real sup
Definition: intervalarith.h:40
void SCIPmessagePrintInfo(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:585
SCIP_RETCODE SCIPexprEvalShallow(SCIP_EXPR *expr, SCIP_Real *argvals, SCIP_Real *varvals, SCIP_Real *param, SCIP_Real *val)
Definition: expr.c:7849
void SCIPexprMultiplyPolynomialByConstant(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real factor)
Definition: expr.c:6704
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:14724
static SCIP_RETCODE exprsimplifyUnconvertPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4892
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:8109
static SCIP_RETCODE exprgraphNodeUpdateBounds(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool parenttightenisinvalid)
Definition: expr.c:10147
#define SCIP_DECL_USEREXPRCURV(x)
Definition: type_expr.h:272
void SCIPexprFreeMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial)
Definition: expr.c:7094
SCIP_EXPORT void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPexprMulConstant(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPR *term, SCIP_Real factor)
Definition: expr.c:6406
SCIP_EXPR * SCIPexprtreeGetRoot(SCIP_EXPRTREE *tree)
Definition: expr.c:8604
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:7155
SCIP_Bool SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14636
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:13241
#define SCIP_DECL_USEREXPRESTIMATE(x)
Definition: type_expr.h:236
#define SCIP_DECL_USEREXPRPROP(x)
Definition: type_expr.h:284
SCIP_Real SCIPexprgraphGetNodeOperatorReal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13072
#define SCIP_EXPRBOUNDSTATUS_VALID
Definition: type_expr.h:211
SCIP_RETCODE SCIPexprAdd(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_Real coef1, SCIP_EXPR *term1, SCIP_Real coef2, SCIP_EXPR *term2, SCIP_Real constant)
Definition: expr.c:6248
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13154
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:456
SCIP_RETCODE SCIPexprMultiplyPolynomialByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR *factor, int *childmap)
Definition: expr.c:6741
void SCIPexprMergeMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real eps)
Definition: expr.c:6958
void SCIPintervalCos(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_EXPRINTCAPABILITY SCIPexprGetUserEvalCapability(SCIP_EXPR *expr)
Definition: expr.c:5964
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:834
SCIP_EXPORT void SCIPsortPtrRealInt(void **ptrarray, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:5715
SCIP_Real SCIPexprGetSignPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5780
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2285
SCIP_EXPRGRAPHNODE ** children
Definition: struct_expr.h:128
#define SCIP_Bool
Definition: def.h:70
void ** vars
Definition: struct_expr.h:60
SCIP_Bool needvarboundprop
Definition: struct_expr.h:181
static SCIP_RETCODE exprgraphNodeEval(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:10082
SCIP_USEREXPRDATA * userdata
Definition: struct_expr.h:103
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14655
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds)
SCIPInterval sin(const SCIPInterval &x)
#define BMSallocBlockMemoryArray(mem, ptr, num)
Definition: memory.h:445
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3013
void SCIPexprSortQuadElems(SCIP_EXPR *expr)
Definition: expr.c:6622
static SCIP_RETCODE monomialdataEnsureFactorsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomialdata, int minsize)
Definition: expr.c:604
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:15061
SCIP_EXPORT SCIP_RETCODE SCIPexprintFreeData(SCIP_EXPRINTDATA **interpreterdata)
static SCIP_RETCODE exprsimplifyFlattenPolynomials(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR *expr, SCIP_Real eps, int maxexpansionexponent)
Definition: expr.c:4462
static SCIP_RETCODE exprgraphNodeRemoveParent(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9401
BMS_BLKMEM * blkmem
Definition: struct_expr.h:57
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8659
SCIP_RETCODE SCIPexprtreeFreeInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8682
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:458
void SCIPquadelemSqueeze(SCIP_QUADELEM *quadelems, int nquadelems, int *nquadelemsnew)
Definition: expr.c:9290
SCIP_Bool SCIPexprHasUserEstimator(SCIP_EXPR *expr)
Definition: expr.c:5953
#define MAX(x, y)
Definition: tclique_def.h:83
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:5705
SCIP_EXPORT void SCIPsortIntReal(int *intarray, SCIP_Real *realarray, int len)
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:16741
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:15081
static SCIP_Bool exprgraphFindConstNodePos(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *pos)
Definition: expr.c:9685
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:13608
SCIP_RETCODE SCIPexprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op,...)
Definition: expr.c:5975
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:8854
SCIP_Bool SCIPexprFindMonomialFactor(SCIP_EXPRDATA_MONOMIAL *monomial, int childidx, int *pos)
Definition: expr.c:7138
static SCIP_DECL_EXPRINTEVAL(exprevalIntDefault)
Definition: expr.c:1411
#define EPSLE(x, y, eps)
Definition: def.h:190
void SCIPexprgraphFreeNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14546
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:10241
#define SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED
Definition: type_expr.h:212
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14598
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:126
SCIPInterval log(const SCIPInterval &x)
SCIP_USEREXPRDATA * SCIPexprGetUserData(SCIP_EXPR *expr)
Definition: expr.c:5942
SCIP_RETCODE SCIPexprtreeAddExpr(SCIP_EXPRTREE *tree, SCIP_EXPR *expr, SCIP_Bool copyexpr)
Definition: expr.c:8983
#define SCIP_EXPR_DEGREEINFINITY
Definition: type_expr.h:116
SCIP_EXPROPDATA data
Definition: struct_expr.h:120
SCIP_EXPRGRAPHNODE ** parents
Definition: struct_expr.h:133
static long * number
void SCIPintervalAbs(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define BMSclearMemory(ptr)
Definition: memory.h:121
SCIP_Real SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5902
static SCIP_RETCODE polynomialdataCopy(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *sourcepolynomialdata)
Definition: expr.c:676
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:1189
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13083
void * SCIPexprGetOpData(SCIP_EXPR *expr)
Definition: expr.c:5747
SCIP_EXPROP op
Definition: struct_expr.h:119
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13166
#define SCIP_REAL_MAX
Definition: def.h:164
static SCIP_RETCODE exprConvertToPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren)
Definition: expr.c:3325
SCIP_RETCODE SCIPexprEvalIntUser(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *val, SCIP_INTERVAL *gradient, SCIP_INTERVAL *hessian)
Definition: expr.c:7994
int SCIPexprgraphGetNodeIntPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13109
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13021
SCIP_QUADELEM * quadelems
Definition: struct_expr.h:71
static void exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:9375
#define EPSLT(x, y, eps)
Definition: def.h:189
#define SCIP_DECL_EXPRGRAPHVARREMOVE(x)
Definition: type_expr.h:193
static SCIP_RETCODE exprgraphAddExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPR *expr, void **vars, SCIP_Real *params, SCIP_EXPRGRAPHNODE **exprnode, SCIP_Bool *exprnodeisnew)
Definition: expr.c:12724
static SCIP_RETCODE polynomialdataAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:759
#define EPSGT(x, y, eps)
Definition: def.h:191
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:95
SCIP_VAR ** b
Definition: circlepacking.c:56
int SCIPexpropGetNChildren(SCIP_EXPROP op)
Definition: expr.c:3275
static void quadraticdataSort(SCIP_EXPRDATA_QUADRATIC *quadraticdata)
Definition: expr.c:529
#define SCIP_VARTYPE_IMPLINT_CHAR
Definition: def.h:136
SCIP_EXPRINTDATA * interpreterdata
Definition: struct_expr.h:63
#define exprcurvCos
Definition: expr.c:2107
SCIP_Bool SCIPexprgraphFindVarNode(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_EXPRGRAPHNODE **varnode)
Definition: expr.c:15714
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8206
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13131
#define SCIP_EXPRINTCAPABILITY_FUNCVALUE
SCIP_Real * SCIPexprGetLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5791
SCIP_Bool SCIPexprtreeHasParam(SCIP_EXPRTREE *tree)
Definition: expr.c:8696
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Real SCIPexprGetOpReal(SCIP_EXPR *expr)
Definition: expr.c:5736
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13041
static SCIP_Bool isLbBetter(SCIP_Real minstrength, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:150
SCIP_RETCODE SCIPexprgraphNodePolynomialAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:13535
SCIP_Bool parentssorted
Definition: struct_expr.h:134
#define SCIP_VARTYPE_CONTINUOUS_CHAR
Definition: def.h:137
SCIP_EXPRGRAPHNODE ** constnodes
Definition: struct_expr.h:173
void SCIPexprFreeShallow(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6223
SCIP_QUADELEM * SCIPexprGetQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5817
SCIP_RETCODE SCIPexprgraphCreateNodePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:13510
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:13321
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:4791
SCIP_RETCODE SCIPexprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op,...)
Definition: expr.c:13375
SCIP_RETCODE SCIPexprEvalIntShallow(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7909
SCIP_RETCODE SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14452
int SCIPexprGetNMonomials(SCIP_EXPR *expr)
Definition: expr.c:5878
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE
Definition: type_expr.h:216
SCIP_VAR * a
Definition: circlepacking.c:57
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10590
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:609
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3047
SCIP_RETCODE SCIPexprtreeSimplify(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:8928
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:16254
#define SCIP_DECL_USEREXPRCOPYDATA(x)
Definition: type_expr.h:293
#define SCIP_Real
Definition: def.h:163
#define EPSROUND(x, eps)
Definition: def.h:198
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:629
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_CALL_TERMINATE(retcode, x, TERM)
Definition: def.h:385
SCIP_RETCODE SCIPrandomCreate(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem, unsigned int initialseed)
Definition: misc.c:9913
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13001
#define SCIP_INVALID
Definition: def.h:183
SCIP_RETCODE SCIPexprAddMonomialFactors(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:6864
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5932
void SCIPexprgraphPrintNode(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: expr.c:14708
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:9047
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:8540
#define SCIPisFinite(x)
Definition: pub_misc.h:1861
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:10126
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:134
int SCIPexprtreeGetNParams(SCIP_EXPRTREE *tree)
Definition: expr.c:8624
SCIP_RETCODE SCIPexprgraphSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange, SCIP_Bool *domainerror)
Definition: expr.c:15990
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
static SCIP_RETCODE exprsimplifyRemovePolynomialUnusedChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4411
#define exprcurvTan
Definition: expr.c:2125
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:12160
static SCIP_RETCODE exprparseFindClosingParenthesis(const char *str, const char **endptr, int length)
Definition: expr.c:5027
SCIP_RETCODE SCIPexprAddToLinear(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nchildren, SCIP_Real *coefs, SCIP_EXPR **children, SCIP_Real constant)
Definition: expr.c:6541
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:4148
#define nnodes
Definition: gastrans.c:65
SCIP_EXPORT void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:443
SCIP_RETCODE SCIPexprMultiplyPolynomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6718
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13098
#define EPSFLOOR(x, eps)
Definition: def.h:196
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:122
static SCIP_DECL_HASHGETKEY(exprparseVarTableGetKey)
Definition: expr.c:4916
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:429
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13190
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:10660
#define SCIP_ALLOC_TERMINATE(retcode, x, TERM)
Definition: def.h:395
static SCIP_RETCODE polynomialdataPower(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int exponent)
Definition: expr.c:1090
#define SCIP_CALL_ABORT(x)
Definition: def.h:343
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14977
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT
Definition: type_expr.h:215
SCIP_RETCODE SCIPexprCreateLinear(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:6504
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_ALLOC(x)
Definition: def.h:375
#define SCIPABORT()
Definition: def.h:336
SCIP_Real SCIPexprGetLinearConstant(SCIP_EXPR *expr)
Definition: expr.c:5804
void SCIPexprtreeSetInterpreterData(SCIP_EXPRTREE *tree, SCIP_EXPRINTDATA *interpreterdata)
Definition: expr.c:8669
SCIP_EXPRCURV SCIPexprcurvAdd(SCIP_EXPRCURV curv1, SCIP_EXPRCURV curv2)
Definition: expr.c:206
struct SCIP_ExprIntData SCIP_EXPRINTDATA
static void quadelemsQuickSort(SCIP_QUADELEM *elems, int start, int end)
Definition: expr.c:9103
static SCIP_RETCODE polynomialdataEnsureMonomialsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int minsize)
Definition: expr.c:742
SCIP_RETCODE SCIPexprtreeSetParams(SCIP_EXPRTREE *tree, int nparams, SCIP_Real *paramvals)
Definition: expr.c:8878
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
int SCIPexprGetNQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5854
static void exprgraphPrintNodeExpression(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, SCIP_Bool printchildrenbounds)
Definition: expr.c:9784
#define SCIP_DECL_USEREXPRFREEDATA(x)
Definition: type_expr.h:301
static SCIP_RETCODE exprgraphFindParentByOperator(SCIP_EXPRGRAPH *exprgraph, int nchildren, SCIP_EXPRGRAPHNODE **children, SCIP_EXPROP op, SCIP_EXPROPDATA opdata, SCIP_EXPR **exprchildren, SCIP_EXPRGRAPHNODE **parent)
Definition: expr.c:12256
static void exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:11994
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15791
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3378
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:449
void SCIPintervalSetRoundingModeDownwards(void)
#define EPSZ(x, eps)
Definition: def.h:193
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:13031
#define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize)
Definition: expr.c:53
SCIP_EXPRCURV SCIPexprcurvNegate(SCIP_EXPRCURV curvature)
Definition: expr.c:215
SCIP_RETCODE SCIPexprtreeEval(SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
Definition: expr.c:8725
SCIP_EXPRINTCAPABILITY evalcapability
Definition: struct_expr.h:104
void SCIPexprgraphSetVarBounds(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_INTERVAL varbounds)
Definition: expr.c:15021
static SCIP_RETCODE exprgraphRemoveVar(SCIP_EXPRGRAPH *exprgraph, int varidx)
Definition: expr.c:12107
SCIP_EXPORT void SCIPsortPtrPtrInt(void **ptrarray1, void **ptrarray2, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_DECL_EXPRGRAPHVARCHGIDX(x)
Definition: type_expr.h:205
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
void SCIPexprgraphEnableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14571
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3296
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13178