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  /* coverity[var_deref_op] */
3976  quaddata->lincoefs[polynomialdata->monomials[i]->childidxs[0]] += polynomialdata->monomials[i]->coef;
3977  }
3978  else
3979  {
3980  /* monomial should be a square term */
3981  assert(polynomialdata->monomials[i]->exponents[0] == 2.0);
3982  assert(quadelemidx < quaddata->nquadelems);
3983  quaddata->quadelems[quadelemidx].idx1 = polynomialdata->monomials[i]->childidxs[0];
3984  quaddata->quadelems[quadelemidx].idx2 = polynomialdata->monomials[i]->childidxs[0];
3985  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3986  ++quadelemidx;
3987  }
3988  }
3989  else
3990  {
3991  /* monomial should be a bilinear term */
3992  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3993  assert(polynomialdata->monomials[i]->exponents[1] == 1.0);
3994  assert(quadelemidx < quaddata->nquadelems);
3995  quaddata->quadelems[quadelemidx].idx1 = MIN(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3996  quaddata->quadelems[quadelemidx].idx2 = MAX(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3997  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3998  ++quadelemidx;
3999  }
4000  }
4001  assert(quadelemidx == quaddata->nquadelems);
4002 
4003  polynomialdataFree(blkmem, &polynomialdata);
4004 
4005  *op = SCIP_EXPR_QUADRATIC;
4006  data->data = (void*)quaddata;
4007 
4008  return SCIP_OKAY;
4009  }
4010 
4011  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 1 && polynomialdata->monomials[0]->coef == 1.0 )
4012  {
4013  /* polynomial is product of children */
4014  monomial = polynomialdata->monomials[0];
4015  assert(monomial->nfactors == nchildren);
4016 
4017  if( monomial->nfactors == 1 )
4018  {
4019  /* polynomial is x^k for some k */
4020  assert(monomial->exponents[0] != 1.0); /* should have been handled before */
4021  assert(monomial->childidxs[0] == 0);
4022 
4023  if( monomial->exponents[0] == 2.0 )
4024  {
4025  /* polynomial is x^2, so turn into SCIP_EXPR_SQUARE */
4026 
4027  polynomialdataFree(blkmem, &polynomialdata);
4028  data->data = NULL;
4029 
4030  *op = SCIP_EXPR_SQUARE;
4031 
4032  return SCIP_OKAY;
4033  }
4034 
4035  if( EPSISINT(monomial->exponents[0], 0.0) ) /*lint !e835*/
4036  {
4037  /* k is an integer, so turn into SCIP_EXPR_INTPOWER */
4038  int exponent;
4039 
4040  exponent = (int)EPSROUND(monomial->exponents[0], 0.0); /*lint !e835*/
4041 
4042  polynomialdataFree(blkmem, &polynomialdata);
4043 
4044  *op = SCIP_EXPR_INTPOWER;
4045  data->intval = exponent;
4046 
4047  return SCIP_OKAY;
4048  }
4049 
4050  if( monomial->exponents[0] == 0.5 )
4051  {
4052  /* polynomial is sqrt(x), so turn into SCIP_EXPR_SQRT */
4053 
4054  polynomialdataFree(blkmem, &polynomialdata);
4055  data->data = NULL;
4056 
4057  *op = SCIP_EXPR_SQRT;
4058 
4059  return SCIP_OKAY;
4060  }
4061 
4062  {
4063  /* polynomial is x^a with a some real number, so turn into SCIP_EXPR_REALPOWER */
4064  SCIP_Real exponent;
4065 
4066  exponent = monomial->exponents[0];
4067 
4068  polynomialdataFree(blkmem, &polynomialdata);
4069 
4070  *op = SCIP_EXPR_REALPOWER;
4071  data->dbl = exponent;
4072 
4073  return SCIP_OKAY;
4074  }
4075  }
4076 
4077  if( maxdegree == 2 && monomial->nfactors == 2 )
4078  {
4079  /* polynomial is product of two children, so turn into SCIP_EXPR_MUL */
4080  assert(monomial->exponents[0] == 1.0);
4081  assert(monomial->exponents[1] == 1.0);
4082 
4083  polynomialdataFree(blkmem, &polynomialdata);
4084  data->data = NULL;
4085 
4086  *op = SCIP_EXPR_MUL;
4087 
4088  return SCIP_OKAY;
4089  }
4090 
4091  if( maxdegree == monomial->nfactors )
4092  {
4093  /* polynomial is a product of n children, so turn into SCIP_EXPR_PRODUCT */
4094 
4095  polynomialdataFree(blkmem, &polynomialdata);
4096  data->data = NULL;
4097 
4098  *op = SCIP_EXPR_PRODUCT;
4099 
4100  return SCIP_OKAY;
4101  }
4102 
4103  if( monomial->nfactors == 2 && monomial->exponents[0] == 1.0 && monomial->exponents[1] == -1.0 )
4104  {
4105  /* polynomial is x/y, so turn into SCIP_EXPR_DIV */
4106  assert(monomial->childidxs[0] == 0);
4107  assert(monomial->childidxs[1] == 1);
4108 
4109  polynomialdataFree(blkmem, &polynomialdata);
4110  data->data = NULL;
4111 
4112  *op = SCIP_EXPR_DIV;
4113 
4114  return SCIP_OKAY;
4115  }
4116 
4117  if( monomial->nfactors == 2 && monomial->exponents[0] == -1.0 && monomial->exponents[1] == 1.0 )
4118  {
4119  /* polynomial is y/x, so turn into SCIP_EXPR_DIV */
4120  void* tmp;
4121 
4122  assert(monomial->childidxs[0] == 0);
4123  assert(monomial->childidxs[1] == 1);
4124 
4125  polynomialdataFree(blkmem, &polynomialdata);
4126  data->data = NULL;
4127 
4128  /* swap children */
4129  tmp = children[1]; /*lint !e613*/
4130  children[1] = children[0]; /*lint !e613*/
4131  children[0] = tmp; /*lint !e613*/
4132 
4133  *op = SCIP_EXPR_DIV;
4134 
4135  return SCIP_OKAY;
4136  }
4137  }
4138 
4139  return SCIP_OKAY;
4140 }
4141 
4142 /** adds copies of expressions to the array of children of a sum, product, linear, quadratic, or polynomial expression
4143  *
4144  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
4145  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
4146  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
4147  */
4148 static
4150  BMS_BLKMEM* blkmem, /**< block memory */
4151  SCIP_EXPR* expr, /**< quadratic or polynomial expression */
4152  int nexprs, /**< number of expressions to add */
4153  SCIP_EXPR** exprs, /**< expressions to add */
4154  SCIP_Bool comparechildren, /**< whether to compare expressions with already existing children (no effect for sum and product) */
4155  SCIP_Real eps, /**< which epsilon to use when comparing expressions */
4156  int* childmap /**< array where to store mapping of indices from exprs to children array in expr, or NULL if not of interest */
4157  )
4158 {
4159  int i;
4160 
4161  assert(blkmem != NULL);
4162  assert(expr != NULL);
4163  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);
4164  assert(exprs != NULL || nexprs == 0);
4165 
4166  if( nexprs == 0 )
4167  return SCIP_OKAY;
4168 
4169  switch( expr->op )
4170  {
4171  case SCIP_EXPR_SUM:
4172  case SCIP_EXPR_PRODUCT:
4173  {
4174  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4175  for( i = 0; i < nexprs; ++i )
4176  {
4177  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren + i], exprs[i]) ); /*lint !e613*/
4178  if( childmap != NULL )
4179  childmap[i] = expr->nchildren + i;
4180  }
4181  expr->nchildren += nexprs;
4182 
4183  break;
4184  }
4185 
4186  case SCIP_EXPR_LINEAR:
4187  case SCIP_EXPR_QUADRATIC:
4188  case SCIP_EXPR_POLYNOMIAL:
4189  {
4190  int j;
4191  int orignchildren;
4192  SCIP_Bool existsalready;
4193 
4194  orignchildren = expr->nchildren;
4195  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4196 
4197  for( i = 0; i < nexprs; ++i )
4198  {
4199  existsalready = FALSE;
4200  if( comparechildren )
4201  for( j = 0; j < orignchildren; ++j )
4202  /* during simplification of polynomials, their may be NULL's in children array */
4203  if( expr->children[j] != NULL && SCIPexprAreEqual(expr->children[j], exprs[i], eps) ) /*lint !e613*/
4204  {
4205  existsalready = TRUE;
4206  break;
4207  }
4208 
4209  if( !existsalready )
4210  {
4211  /* add copy of exprs[j] to children array */
4212  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren], exprs[i]) ); /*lint !e613*/
4213  if( childmap != NULL )
4214  childmap[i] = expr->nchildren;
4215  ++expr->nchildren;
4216  }
4217  else
4218  {
4219  if( childmap != NULL )
4220  childmap[i] = j; /*lint !e644*/
4221  if( expr->op == SCIP_EXPR_LINEAR )
4222  {
4223  /* if linear expression, increase coefficient by 1.0 */
4224  ((SCIP_Real*)expr->data.data)[j] += 1.0;
4225  }
4226  }
4227  }
4228 
4229  /* shrink children array to actually used size */
4230  assert(comparechildren || expr->nchildren == orignchildren + nexprs);
4231  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, orignchildren + nexprs, expr->nchildren) );
4232 
4233  if( expr->op == SCIP_EXPR_LINEAR && expr->nchildren > orignchildren )
4234  {
4235  /* if linear expression, then add 1.0 coefficients for new expressions */
4236  SCIP_Real* data;
4237 
4238  data = (SCIP_Real*)expr->data.data;
4239  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, expr->nchildren + 1) );
4240  data[expr->nchildren] = data[orignchildren]; /* move constant from old end to new end */
4241  for( i = orignchildren; i < expr->nchildren; ++i )
4242  data[i] = 1.0;
4243  expr->data.data = (void*)data;
4244  }
4245  else if( expr->op == SCIP_EXPR_QUADRATIC && expr->nchildren > orignchildren )
4246  {
4247  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
4249 
4250  data = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
4251  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, expr->nchildren) );
4252  BMSclearMemoryArray(&data->lincoefs[orignchildren], expr->nchildren - orignchildren); /*lint !e866*/
4253  }
4254 
4255  break;
4256  }
4257 
4258  default:
4259  SCIPerrorMessage("exprsimplifyAddChildren cannot be called for operand %d\n", expr->op);
4260  return SCIP_INVALIDDATA;
4261  } /*lint !e788*/
4262 
4263  return SCIP_OKAY;
4264 }
4265 
4266 /** converts expressions into polynomials, where possible and obvious */
4267 static
4269  BMS_BLKMEM* blkmem, /**< block memory data structure */
4270  SCIP_EXPR* expr /**< expression to convert */
4271  )
4272 {
4273  int i;
4274 
4275  assert(expr != NULL);
4276 
4277  for( i = 0; i < expr->nchildren; ++i )
4278  {
4280  }
4281 
4282  SCIP_CALL( exprConvertToPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren) );
4283 
4284  return SCIP_OKAY;
4285 }
4286 
4287 /** removes duplicate children in a polynomial expression
4288  *
4289  * Leaves NULL's in children array.
4290  */
4291 static
4293  BMS_BLKMEM* blkmem, /**< block memory data structure */
4294  SCIP_EXPR* expr, /**< expression */
4295  SCIP_Real eps /**< threshold for zero */
4296  )
4297 {
4298  SCIP_Bool foundduplicates;
4299  int* childmap;
4300  int i;
4301  int j;
4302 
4303  assert(blkmem != NULL);
4304  assert(expr != NULL);
4305  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4306 
4307  if( expr->nchildren == 0 )
4308  return SCIP_OKAY;
4309 
4310  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4311 
4312  foundduplicates = FALSE;
4313  for( i = 0; i < expr->nchildren; ++i )
4314  {
4315  if( expr->children[i] == NULL )
4316  continue;
4317  childmap[i] = i; /*lint !e644*/
4318 
4319  for( j = i+1; j < expr->nchildren; ++j )
4320  {
4321  if( expr->children[j] == NULL )
4322  continue;
4323 
4324  if( SCIPexprAreEqual(expr->children[i], expr->children[j], eps) )
4325  {
4326  /* forget about expr j and remember that is to be replaced by i */
4327  SCIPexprFreeDeep(blkmem, &expr->children[j]);
4328  childmap[j] = i;
4329  foundduplicates = TRUE;
4330  }
4331  }
4332  }
4333 
4334  /* apply childmap to monomials */
4335  if( foundduplicates )
4337 
4338  /* free childmap */
4339  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4340 
4341  return SCIP_OKAY;
4342 }
4343 
4344 /** eliminates NULL's in children array and shrinks it to actual size */
4345 static
4347  BMS_BLKMEM* blkmem, /**< block memory data structure */
4348  SCIP_EXPR* expr /**< expression */
4349  )
4350 {
4351  int* childmap;
4352  int lastnonnull;
4353  int i;
4354 
4355  assert(blkmem != NULL);
4356  assert(expr != NULL);
4357  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4358 
4359  if( expr->nchildren == 0 )
4360  return SCIP_OKAY;
4361 
4362  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4363 
4364  /* close gaps in children array */
4365  lastnonnull = expr->nchildren-1;
4366  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4367  --lastnonnull;
4368  for( i = 0; i <= lastnonnull; ++i )
4369  {
4370  if( expr->children[i] != NULL )
4371  {
4372  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
4373  continue;
4374  }
4375  assert(expr->children[lastnonnull] != NULL);
4376 
4377  /* move child at lastnonnull to position i */
4378  expr->children[i] = expr->children[lastnonnull];
4379  expr->children[lastnonnull] = NULL;
4380  childmap[lastnonnull] = i;
4381 
4382  /* update lastnonnull */
4383  --lastnonnull;
4384  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4385  --lastnonnull;
4386  }
4387  assert(i > lastnonnull);
4388 
4389  /* apply childmap to monomials */
4390  if( lastnonnull < expr->nchildren-1 )
4392 
4393  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4394 
4395  /* shrink children array */
4396  if( lastnonnull >= 0 )
4397  {
4398  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, lastnonnull+1) );
4399  expr->nchildren = lastnonnull+1;
4400  }
4401  else
4402  {
4403  BMSfreeBlockMemoryArray(blkmem, &expr->children, expr->nchildren);
4404  expr->nchildren = 0;
4405  }
4406 
4407  return SCIP_OKAY;
4408 }
4409 
4410 /** checks which children are still in use and frees those which are not */
4411 static
4413  BMS_BLKMEM* blkmem, /**< block memory data structure */
4414  SCIP_EXPR* expr /**< polynomial expression */
4415  )
4416 {
4417  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4418  SCIP_EXPRDATA_MONOMIAL* monomial;
4419  SCIP_Bool* childinuse;
4420  int i;
4421  int j;
4422 
4423  assert(blkmem != NULL);
4424  assert(expr != NULL);
4425 
4426  if( expr->nchildren == 0 )
4427  return SCIP_OKAY;
4428 
4429  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4430  assert(polynomialdata != NULL);
4431 
4432  /* check which children are still in use */
4433  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, expr->nchildren) );
4434  BMSclearMemoryArray(childinuse, expr->nchildren); /*lint !e644*/
4435  for( i = 0; i < polynomialdata->nmonomials; ++i )
4436  {
4437  monomial = polynomialdata->monomials[i];
4438  assert(monomial != NULL);
4439 
4440  for( j = 0; j < monomial->nfactors; ++j )
4441  {
4442  assert(monomial->childidxs[j] >= 0);
4443  assert(monomial->childidxs[j] < expr->nchildren);
4444  childinuse[monomial->childidxs[j]] = TRUE;
4445  }
4446  }
4447 
4448  /* free children that are not used in any monomial */
4449  for( i = 0; i < expr->nchildren; ++i )
4450  if( expr->children[i] != NULL && !childinuse[i] )
4451  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4452 
4453  BMSfreeBlockMemoryArray(blkmem, &childinuse, expr->nchildren);
4454 
4455  return SCIP_OKAY;
4456 }
4457 
4458 /** flattens polynomials in polynomials, check for constants in non-polynomials expressions
4459  *
4460  * exprsimplifyConvertToPolynomials should have been called before to eliminate simple polynomial operands.
4461  */
4462 static
4464  BMS_BLKMEM* blkmem, /**< block memory data structure */
4465  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4466  SCIP_EXPR* expr, /**< expression */
4467  SCIP_Real eps, /**< threshold, under which values are treat as 0 */
4468  int maxexpansionexponent/**< maximal exponent for which we still expand non-monomial polynomials */
4469  )
4470 {
4471  int i;
4472 
4473  assert(expr != NULL);
4474 
4475  for( i = 0; i < expr->nchildren; ++i )
4476  {
4477  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr->children[i], eps, maxexpansionexponent) );
4478  }
4479 
4480  switch( SCIPexprGetOperator(expr) )
4481  {
4482  case SCIP_EXPR_VARIDX:
4483  case SCIP_EXPR_CONST:
4484  case SCIP_EXPR_PARAM:
4485  case SCIP_EXPR_PLUS:
4486  case SCIP_EXPR_MINUS:
4487  case SCIP_EXPR_MUL:
4488  case SCIP_EXPR_DIV:
4489  case SCIP_EXPR_SQUARE:
4490  case SCIP_EXPR_SQRT:
4491  case SCIP_EXPR_INTPOWER:
4492  case SCIP_EXPR_REALPOWER:
4493  case SCIP_EXPR_SIGNPOWER:
4494  break;
4495 
4496  case SCIP_EXPR_EXP:
4497  case SCIP_EXPR_LOG:
4498  case SCIP_EXPR_SIN:
4499  case SCIP_EXPR_COS:
4500  case SCIP_EXPR_TAN:
4501  /* case SCIP_EXPR_ERF: */
4502  /* case SCIP_EXPR_ERFI: */
4503  case SCIP_EXPR_ABS:
4504  case SCIP_EXPR_SIGN:
4505  {
4506  /* check if argument is a constant */
4507  if( (expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) ||
4508  expr->children[0]->op == SCIP_EXPR_CONST )
4509  {
4510  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4511  SCIP_Real exprval;
4512 
4513  /* since child0 has no children and it's polynomial was flattened, it should have no monomials */
4514  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4515 
4516  /* evaluate expression in constant polynomial */
4517  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4518 
4519  /* create polynomial */
4520  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4521 
4522  expr->op = SCIP_EXPR_POLYNOMIAL;
4523  expr->data.data = (void*)polynomialdata;
4524 
4525  /* forget child */
4526  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4527  BMSfreeBlockMemoryArray(blkmem, &expr->children, 1);
4528  expr->nchildren = 0;
4529  }
4530 
4531  break;
4532  }
4533 
4534  case SCIP_EXPR_MIN:
4535  case SCIP_EXPR_MAX:
4536  {
4537  /* check if both arguments are constants */
4538  if( ((expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) || expr->children[0]->op == SCIP_EXPR_CONST) &&
4539  ((expr->children[1]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[1]) == 0) || expr->children[1]->op == SCIP_EXPR_CONST) )
4540  {
4541  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4542  SCIP_Real exprval;
4543 
4544  /* since children have no children and it's polynomial was flattened, it should have no monomials */
4545  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4546  assert(expr->children[1]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[1]) == 0);
4547 
4548  /* evaluate expression in constants */
4549  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4550 
4551  /* create polynomial */
4552  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4553 
4554  expr->op = SCIP_EXPR_POLYNOMIAL;
4555  expr->data.data = (void*)polynomialdata;
4556 
4557  /* forget children */
4558  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4559  SCIPexprFreeDeep(blkmem, &expr->children[1]);
4560  BMSfreeBlockMemoryArray(blkmem, &expr->children, 2);
4561  expr->nchildren = 0;
4562  }
4563 
4564  break;
4565  }
4566 
4567  case SCIP_EXPR_SUM:
4568  case SCIP_EXPR_PRODUCT:
4569  case SCIP_EXPR_LINEAR:
4570  case SCIP_EXPR_QUADRATIC:
4571  case SCIP_EXPR_USER:
4572  break;
4573 
4574  case SCIP_EXPR_POLYNOMIAL:
4575  {
4576  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4577  SCIP_EXPRDATA_MONOMIAL* monomial;
4578  SCIP_Bool removechild;
4579  int* childmap;
4580  int childmapsize;
4581  int j;
4582 
4583  /* simplify current polynomial */
4585  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4586 
4587  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4588  assert(polynomialdata != NULL);
4589 
4590  SCIPdebugMessage("expand factors in expression ");
4591  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4592  SCIPdebugPrintf("\n");
4593 
4594  childmap = NULL;
4595  childmapsize = 0;
4596 
4597  /* resolve children that are constants
4598  * we do this first, because it reduces the degree and number of factors in the monomials,
4599  * 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
4600  */
4601  for( i = 0; i < expr->nchildren; ++i )
4602  {
4603  if( expr->children[i] == NULL )
4604  continue;
4605 
4606  if( SCIPexprGetOperator(expr->children[i]) != SCIP_EXPR_CONST )
4607  continue;
4608 
4609  removechild = TRUE; /* we intend to delete children[i] */
4610 
4611  if( childmapsize < expr->children[i]->nchildren )
4612  {
4613  int newsize;
4614 
4615  newsize = calcGrowSize(expr->children[i]->nchildren);
4616  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4617  childmapsize = newsize;
4618  }
4619 
4620  /* put constant of child i into every monomial where child i is used */
4621  for( j = 0; j < polynomialdata->nmonomials; ++j )
4622  {
4623  int factorpos;
4624  SCIP_Bool success;
4625 
4626  monomial = polynomialdata->monomials[j];
4627  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4628  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4629 
4630  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4631  {
4632  assert(factorpos >= 0);
4633  assert(factorpos < monomial->nfactors);
4634  /* assert that factors have been merged */
4635  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4636  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4637 
4638  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4639  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4640  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4641 
4642  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && SCIPexprGetOpReal(expr->children[i]) < 0.0 ) /*lint !e835*/
4643  {
4644  /* if constant is negative and our exponent is not integer, then cannot do expansion */
4645  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n",
4646  SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4647  success = FALSE;
4648  }
4649  else
4650  {
4651  monomial->coef *= pow(SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4652 
4653  /* move last factor to position factorpos */
4654  if( factorpos < monomial->nfactors-1 )
4655  {
4656  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
4657  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
4658  }
4659  --monomial->nfactors;
4660  monomial->sorted = FALSE;
4661  polynomialdata->sorted = FALSE;
4662 
4663  success = TRUE;
4664  }
4665 
4666  if( !success )
4667  removechild = FALSE;
4668  }
4669  }
4670 
4671  /* forget about child i, if it is not used anymore */
4672  if( removechild )
4673  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4674 
4675  /* simplify current polynomial again */
4676  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4677  }
4678 
4679  /* try to resolve children that are polynomials itself */
4680  for( i = 0; i < expr->nchildren; ++i )
4681  {
4682  if( expr->children[i] == NULL )
4683  continue;
4684 
4686  continue;
4687 
4688  removechild = TRUE; /* we intend to delete children[i] */
4689 
4690  if( childmapsize < expr->children[i]->nchildren )
4691  {
4692  int newsize;
4693 
4694  newsize = calcGrowSize(expr->children[i]->nchildren);
4695  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4696  childmapsize = newsize;
4697  }
4698 
4699  /* add children of child i */
4700  SCIP_CALL( exprsimplifyAddChildren(blkmem, expr, expr->children[i]->nchildren, expr->children[i]->children, TRUE, eps, childmap) );
4701 
4702  /* put polynomial of child i into every monomial where child i is used */
4703  j = 0;
4704  while( j < polynomialdata->nmonomials )
4705  {
4706  int factorpos;
4707  SCIP_Bool success;
4708 
4709  monomial = polynomialdata->monomials[j];
4710  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4711  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4712 
4713  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4714  {
4715  assert(factorpos >= 0);
4716  assert(factorpos < monomial->nfactors);
4717  /* assert that factors have been merged */
4718  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4719  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4720 
4721  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4722  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4723  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4724 
4725  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
4726  (SCIP_EXPRDATA_POLYNOMIAL*)expr->children[i]->data.data, childmap, maxexpansionexponent, &success) );
4727 
4728  if( !success )
4729  {
4730  removechild = FALSE;
4731  ++j;
4732  }
4733  }
4734  else
4735  ++j;
4736 
4737  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
4738  * we thus repeat with index j, if a factor was successfully expanded
4739  */
4740  }
4741 
4742  /* forget about child i, if it is not used anymore */
4743  if( removechild )
4744  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4745 
4746  /* simplify current polynomial again */
4747  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4748  }
4749 
4750  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
4751 
4752  /* free children that are not in use anymore */
4754 
4755  /* remove NULLs from children array */
4757 
4758  /* if no children left, then it's a constant polynomial -> change into EXPR_CONST */
4759  if( expr->nchildren == 0 )
4760  {
4761  SCIP_Real val;
4762 
4763  /* if no children, then it should also have no monomials */
4764  assert(polynomialdata->nmonomials == 0);
4765 
4766  val = polynomialdata->constant;
4767  polynomialdataFree(blkmem, &polynomialdata);
4768 
4769  expr->op = SCIP_EXPR_CONST;
4770  expr->data.dbl = val;
4771  }
4772 
4773  SCIPdebugMessage("-> ");
4774  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4775  SCIPdebugPrintf("\n");
4776 
4777  break;
4778  }
4779 
4780  case SCIP_EXPR_LAST:
4781  break;
4782  } /*lint !e788*/
4783 
4784  return SCIP_OKAY;
4785 }
4786 
4787 /** separates linear monomials from an expression, if it is a polynomial expression
4788  *
4789  * Separates only those linear terms whose variable is not used otherwise in the expression.
4790  */
4791 static
4793  BMS_BLKMEM* blkmem, /**< block memory data structure */
4794  SCIP_EXPR* expr, /**< expression */
4795  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
4796  int nvars, /**< number of variables in expression */
4797  int* nlinvars, /**< buffer to store number of linear variables in linear part */
4798  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part */
4799  SCIP_Real* lincoefs /**< array to store coefficients of linear part */
4800  )
4801 {
4802  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4803  SCIP_EXPRDATA_MONOMIAL* monomial;
4804  int* varsusage;
4805  int* childusage;
4806  int childidx;
4807  int i;
4808  int j;
4809 
4810  assert(blkmem != NULL);
4811  assert(expr != NULL);
4812  assert(nlinvars != NULL);
4813  assert(linidxs != NULL);
4814  assert(lincoefs != NULL);
4815 
4816  *nlinvars = 0;
4817 
4819  return SCIP_OKAY;
4820 
4821  if( SCIPexprGetNChildren(expr) == 0 )
4822  return SCIP_OKAY;
4823 
4824  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4825  assert(polynomialdata != NULL);
4826 
4827  /* get variable usage */
4828  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &varsusage, nvars) );
4829  BMSclearMemoryArray(varsusage, nvars); /*lint !e644*/
4830  SCIPexprGetVarsUsage(expr, varsusage);
4831 
4832  /* get child usage: how often each child is used in the polynomial */
4833  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childusage, expr->nchildren) );
4834  BMSclearMemoryArray(childusage, expr->nchildren); /*lint !e644*/
4835  for( i = 0; i < polynomialdata->nmonomials; ++i )
4836  {
4837  monomial = polynomialdata->monomials[i];
4838  assert(monomial != NULL);
4839  for( j = 0; j < monomial->nfactors; ++j )
4840  {
4841  assert(monomial->childidxs[j] >= 0);
4842  assert(monomial->childidxs[j] < expr->nchildren);
4843  ++childusage[monomial->childidxs[j]];
4844  }
4845  }
4846 
4847  /* move linear monomials out of polynomial */
4848  for( i = 0; i < polynomialdata->nmonomials; ++i )
4849  {
4850  monomial = polynomialdata->monomials[i];
4851  assert(monomial != NULL);
4852  if( monomial->nfactors != 1 )
4853  continue;
4854  if( monomial->exponents[0] != 1.0 )
4855  continue;
4856  childidx = monomial->childidxs[0];
4857  if( SCIPexprGetOperator(expr->children[childidx]) != SCIP_EXPR_VARIDX )
4858  continue;
4859 
4860  /* we are at a linear monomial in a variable */
4861  assert(SCIPexprGetOpIndex(expr->children[childidx]) < nvars);
4862  if( childusage[childidx] == 1 && varsusage[SCIPexprGetOpIndex(expr->children[childidx])] == 1 )
4863  {
4864  /* if the child expression is not used in another monomial (which would due to merging be not linear)
4865  * and if the variable is not used somewhere else in the tree,
4866  * then move this monomial into linear part and free child
4867  */
4868  linidxs[*nlinvars] = SCIPexprGetOpIndex(expr->children[childidx]);
4869  lincoefs[*nlinvars] = monomial->coef;
4870  ++*nlinvars;
4871 
4872  SCIPexprFreeDeep(blkmem, &expr->children[childidx]);
4873  monomial->coef = 0.0;
4874  monomial->nfactors = 0;
4875  }
4876  }
4877 
4878  BMSfreeBlockMemoryArray(blkmem, &varsusage, nvars);
4879  BMSfreeBlockMemoryArray(blkmem, &childusage, expr->nchildren);
4880 
4881  if( *nlinvars > 0 )
4882  {
4883  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
4884  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, FALSE);
4886  }
4887 
4888  return SCIP_OKAY;
4889 }
4890 
4891 /** converts polynomial expressions back into simpler expressions, where possible */
4892 static
4894  BMS_BLKMEM* blkmem, /**< block memory data structure */
4895  SCIP_EXPR* expr /**< expression to convert back */
4896  )
4897 {
4898  int i;
4899 
4900  assert(blkmem != NULL);
4901  assert(expr != NULL);
4902 
4903  for( i = 0; i < expr->nchildren; ++i )
4904  {
4906  }
4907 
4908  if( expr->op != SCIP_EXPR_POLYNOMIAL )
4909  return SCIP_OKAY;
4910 
4911  SCIP_CALL( exprUnconvertPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren, (void**)expr->children) );
4912 
4913  return SCIP_OKAY;
4914 }
4915 
4916 static
4917 SCIP_DECL_HASHGETKEY( exprparseVarTableGetKey )
4918 { /*lint --e{715}*/
4919  return (void*)((char*)elem + sizeof(int));
4920 }
4921 
4922 /** parses a variable name from a string and creates corresponding expression
4923  *
4924  * Creates a new variable index if variable not seen before, updates varnames and vartable structures.
4925  */
4926 static
4928  BMS_BLKMEM* blkmem, /**< block memory data structure */
4929  const char** str, /**< pointer to the string to be parsed */
4930  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
4931  int* nvars, /**< running number of encountered variables so far */
4932  int** varnames, /**< pointer to buffer to store new variable names */
4933  int* varnameslength, /**< pointer to length of the varnames buffer array */
4934  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
4935  SCIP_Real coefficient, /**< coefficient to be used when creating the expression */
4936  const char* varnameendptr /**< if a <varname> should be parsed, set this to NULL. Then, str points to the '<'
4937  else, str should point to the first letter of the varname, and varnameendptr should
4938  point one char behind the last char of the variable name */
4939  )
4940 {
4941  int namelength;
4942  int varidx;
4943  char varname[SCIP_MAXSTRLEN];
4944  void* element;
4945 
4946  assert(blkmem != NULL);
4947  assert(str != NULL);
4948  assert(expr != NULL);
4949  assert(nvars != NULL);
4950  assert(varnames != NULL);
4951  assert(vartable != NULL);
4952 
4953  if( varnameendptr == NULL )
4954  {
4955  ++*str;
4956  varnameendptr = *str;
4957  while( varnameendptr[0] != '>' )
4958  ++varnameendptr;
4959  }
4960 
4961  namelength = varnameendptr - *str; /*lint !e712*/
4962  if( namelength >= SCIP_MAXSTRLEN )
4963  {
4964  SCIPerrorMessage("Variable name %.*s is too long for buffer in exprparseReadVariable.\n", namelength, str);
4965  return SCIP_READERROR;
4966  }
4967 
4968  memcpy(varname, *str, namelength * sizeof(char));
4969  varname[namelength] = '\0';
4970 
4971  element = SCIPhashtableRetrieve(vartable, varname);
4972  if( element != NULL )
4973  {
4974  /* variable is old friend */
4975  assert(strcmp((char*)element + sizeof(int), varname) == 0);
4976 
4977  varidx = *(int*)element;
4978  }
4979  else
4980  {
4981  /* variable is new */
4982  varidx = *nvars;
4983 
4984  (*varnameslength) -= (int)(1 + (strlen(varname) + 1) / sizeof(int) + 1);
4985  if( *varnameslength < 0 )
4986  {
4987  SCIPerrorMessage("Buffer in exprparseReadVariable is too short for varaible name %.*s.\n", namelength, str);
4988  return SCIP_READERROR;
4989  }
4990 
4991  /* store index of variable and variable name in varnames buffer */
4992  **varnames = varidx;
4993  (void) SCIPstrncpy((char*)(*varnames + 1), varname, (int)strlen(varname)+1);
4994 
4995  /* insert variable into hashtable */
4996  SCIP_CALL( SCIPhashtableInsert(vartable, (void*)*varnames) );
4997 
4998  ++*nvars;
4999  *varnames += 1 + (strlen(varname) + 1) / sizeof(int) + 1;
5000  }
5001 
5002  /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
5003  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_VARIDX, varidx) ); /*lint !e613*/
5004  if( coefficient != 1.0 )
5005  {
5006  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, expr, &coefficient, 0.0) );
5007  }
5008 
5009  /* Move pointer to char behind end of variable */
5010  *str = varnameendptr + 1;
5011 
5012  /* consprint sometimes prints a variable type identifier which we don't need */
5013  if( (*str)[0] == '[' && (*str)[2] == ']' &&
5014  ((*str)[1] == SCIP_VARTYPE_BINARY_CHAR ||
5015  (*str)[1] == SCIP_VARTYPE_INTEGER_CHAR ||
5016  (*str)[1] == SCIP_VARTYPE_IMPLINT_CHAR ||
5017  (*str)[1] == SCIP_VARTYPE_CONTINUOUS_CHAR ) )
5018  *str += 3;
5019 
5020  return SCIP_OKAY;
5021 }
5022 
5023 /** if str[0] points to an opening parenthesis, this function sets endptr to point to the matching closing bracket in str
5024  *
5025  * Searches for at most length characters.
5026  */
5027 static
5029  const char* str, /**< pointer to the string to be parsed */
5030  const char** endptr, /**< pointer to point to the closing parenthesis */
5031  int length /**< length of the string to be parsed */
5032  )
5033 {
5034  int nopenbrackets;
5035 
5036  assert(str[0] == '(');
5037 
5038  *endptr = str;
5039 
5040  /* find the end of this expression */
5041  nopenbrackets = 0;
5042  while( (*endptr - str ) < length && !(nopenbrackets == 1 && *endptr[0] == ')') )
5043  {
5044  if( *endptr[0] == '(')
5045  ++nopenbrackets;
5046  if( *endptr[0] == ')')
5047  --nopenbrackets;
5048  ++*endptr;
5049  }
5050 
5051  if( *endptr[0] != ')' )
5052  {
5053  SCIPerrorMessage("unable to find closing parenthesis in unbalanced expression %.*s\n", length, str);
5054  return SCIP_READERROR;
5055  }
5056 
5057  return SCIP_OKAY;
5058 }
5059 
5060 /** this function sets endptr to point to the next separating comma in str
5061  *
5062  * That is, for a given string like "x+f(x,y),z", endptr will point to the comma before "z"
5063  *
5064  * Searches for at most length characters.
5065  */
5066 static
5068  const char* str, /**< pointer to the string to be parsed */
5069  const char** endptr, /**< pointer to point to the comma */
5070  int length /**< length of the string to be parsed */
5071  )
5072 {
5073  int nopenbrackets;
5074 
5075  *endptr = str;
5076 
5077  /* find a comma without open brackets */
5078  nopenbrackets = 0;
5079  while( (*endptr - str ) < length && !(nopenbrackets == 0 && *endptr[0] == ',') )
5080  {
5081  if( *endptr[0] == '(')
5082  ++nopenbrackets;
5083  if( *endptr[0] == ')')
5084  --nopenbrackets;
5085  ++*endptr;
5086  }
5087 
5088  if( *endptr[0] != ',' )
5089  {
5090  SCIPerrorMessage("unable to find separating comma in unbalanced expression %.*s\n", length, str);
5091  return SCIP_READERROR;
5092  }
5093 
5094  return SCIP_OKAY;
5095 }
5096 
5097 /** parses an expression from a string */
5098 static
5100  BMS_BLKMEM* blkmem, /**< block memory data structure */
5101  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
5102  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
5103  const char* str, /**< pointer to the string to be parsed */
5104  int length, /**< length of the string to be parsed */
5105  const char* lastchar, /**< pointer to the last char of str that should be parsed */
5106  int* nvars, /**< running number of encountered variables so far */
5107  int** varnames, /**< pointer to buffer to store new variable names */
5108  int* varnameslength, /**< pointer to length of the varnames buffer array */
5109  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
5110  int recursiondepth /**< current recursion depth */
5111  )
5112 { /*lint --e{712,747}*/
5113  SCIP_EXPR* arg1;
5114  SCIP_EXPR* arg2;
5115  const char* subexpptr;
5116  const char* subexpendptr;
5117  const char* strstart;
5118  const char* endptr;
5119  char* nonconstendptr;
5120  SCIP_Real number;
5121  int subexplength;
5122  int nopenbrackets;
5123 
5124  assert(blkmem != NULL);
5125  assert(expr != NULL);
5126  assert(str != NULL);
5127  assert(lastchar >= str);
5128  assert(nvars != NULL);
5129  assert(varnames != NULL);
5130  assert(vartable != NULL);
5131 
5132  assert(recursiondepth < 100);
5133 
5134  strstart = str; /* might be needed for error message... */
5135 
5136  SCIPdebugMessage("exprParse (%i): parsing %.*s\n", recursiondepth, (int) (lastchar-str + 1), str);
5137 
5138  /* ignore whitespace */
5139  while( isspace((unsigned char)*str) )
5140  ++str;
5141 
5142  /* look for a sum or difference not contained in brackets */
5143  subexpptr = str;
5144  nopenbrackets = 0;
5145 
5146  /* find the end of this expression
5147  * a '+' right at the beginning indicates a coefficient, not treated here, or a summation
5148  * a '+' or '-' that follows an 'e' or 'E' indicates that we are in the middle of a number, so it doesn't separate terms
5149  */
5150  while( subexpptr != lastchar && !(nopenbrackets == 0 && (subexpptr[0] == '+' || subexpptr[0] == '-') && subexpptr != str && subexpptr[-1] != 'e' && subexpptr[-1] != 'E') )
5151  {
5152  if( subexpptr[0] == '(')
5153  ++nopenbrackets;
5154  if( subexpptr[0] == ')')
5155  --nopenbrackets;
5156  ++subexpptr;
5157  }
5158 
5159  if( subexpptr != lastchar )
5160  {
5161  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str, (int) ((subexpptr - 1) - str + 1), subexpptr - 1, nvars,
5162  varnames, varnameslength, vartable, recursiondepth + 1) );
5163 
5164  if( subexpptr[0] == '+' )
5165  ++subexpptr;
5166  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, subexpptr , (int) (lastchar - (subexpptr ) + 1), lastchar, nvars,
5167  varnames, varnameslength, vartable, recursiondepth + 1) );
5168 
5169  /* make new expression from two arguments
5170  * we always use add, because we leave the operator between the found expressions in the second argument
5171  * this way, we do not have to worry about ''minus brackets'' in the case of more then two summands:
5172  * a - b - c = a + (-b -c)
5173  */
5174  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5175 
5176  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5177  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5178  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5179 
5180  return SCIP_OKAY;
5181  }
5182 
5183  /* check for a bracketed subexpression */
5184  if( str[0] == '(' )
5185  {
5186  nopenbrackets = 0;
5187 
5188  subexplength = -1; /* we do not want the closing bracket in the string */
5189  subexpptr = str + 1; /* leave out opening bracket */
5190 
5191  /* find the end of this expression */
5192  while( subexplength < length && !(nopenbrackets == 1 && str[0] == ')') )
5193  {
5194  if( str[0] == '(' )
5195  ++nopenbrackets;
5196  if( str[0] == ')' )
5197  --nopenbrackets;
5198  ++str;
5199  ++subexplength;
5200  }
5201  subexpendptr = str - 1; /* leave out closing bracket */
5202 
5203  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, subexpptr, subexplength, subexpendptr, nvars, varnames,
5204  varnameslength, vartable, recursiondepth + 1) );
5205  ++str;
5206  }
5207  else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+')
5208  && (isdigit((unsigned char)str[1]) || str[1] == ' ')) )
5209  {
5210  /* check if there is a lonely minus coming, indicating a -1.0 */
5211  if( str[0] == '-' && str[1] == ' ' )
5212  {
5213  number = -1.0;
5214  nonconstendptr = (char*) str + 1;
5215  }
5216  /* check if there is a number coming */
5217  else if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5218  {
5219  SCIPerrorMessage("error parsing number from <%s>\n", str);
5220  return SCIP_READERROR;
5221  }
5222  str = nonconstendptr;
5223 
5224  /* ignore whitespace */
5225  while( isspace((unsigned char)*str) && str != lastchar )
5226  ++str;
5227 
5228  if( str[0] != '*' && str[0] != '/' && str[0] != '+' && str[0] != '-' && str[0] != '^' )
5229  {
5230  if( str < lastchar )
5231  {
5232  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, str, (int)(lastchar - str) + 1, lastchar, nvars, varnames,
5233  varnameslength, vartable, recursiondepth + 1) );
5234  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, *expr, number) );
5235  }
5236  else
5237  {
5238  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5239  }
5240  str = lastchar + 1;
5241  }
5242  else
5243  {
5244  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5245  }
5246  }
5247  else if( str[0] == '<' )
5248  {
5249  /* check if expressions begins with a variable */
5250  SCIP_CALL( exprparseReadVariable(blkmem, &str, expr, nvars, varnames, varnameslength, vartable, 1.0, NULL) );
5251  }
5252  /* four character operators */
5253  else if( strncmp(str, "sqrt", 4) == 0 )
5254  {
5255  str += 4;
5256  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5257  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5258  varnameslength, vartable, recursiondepth + 1) );
5259  str = endptr + 1;
5260 
5261  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQRT, arg1) );
5262  }
5263  /* three character operators with 1 argument */
5264  else if(
5265  strncmp(str, "abs", 3) == 0 ||
5266  strncmp(str, "cos", 3) == 0 ||
5267  strncmp(str, "exp", 3) == 0 ||
5268  strncmp(str, "log", 3) == 0 ||
5269  strncmp(str, "sin", 3) == 0 ||
5270  strncmp(str, "sqr", 3) == 0 ||
5271  strncmp(str, "tan", 3) == 0 )
5272  {
5273  const char* opname = str;
5274 
5275  str += 3;
5276  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5277  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5278  varnameslength, vartable, recursiondepth + 1) );
5279  str = endptr + 1;
5280 
5281  if( strncmp(opname, "abs", 3) == 0 )
5282  {
5283  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_ABS, arg1) );
5284  }
5285  else if( strncmp(opname, "cos", 3) == 0 )
5286  {
5287  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_COS, arg1) );
5288  }
5289  else if( strncmp(opname, "exp", 3) == 0 )
5290  {
5291  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, arg1) );
5292  }
5293  else if( strncmp(opname, "log", 3) == 0 )
5294  {
5295  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5296  }
5297  else if( strncmp(opname, "sin", 3) == 0 )
5298  {
5299  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIN, arg1) );
5300  }
5301  else if( strncmp(opname, "sqr", 3) == 0 )
5302  {
5303  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQUARE, arg1) );
5304  }
5305  else
5306  {
5307  assert(strncmp(opname, "tan", 3) == 0);
5308  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_TAN, arg1) );
5309  }
5310  }
5311  /* three character operators with 2 arguments */
5312  else if(
5313  strncmp(str, "max", 3) == 0 ||
5314  strncmp(str, "min", 3) == 0 )
5315  {
5316  /* we have a string of the form "min(...,...)" or "max(...,...)"
5317  * first find the closing parenthesis, then the comma
5318  */
5319  const char* comma;
5320  SCIP_EXPROP op;
5321 
5322  op = (str[1] == 'a' ? SCIP_EXPR_MAX : SCIP_EXPR_MIN);
5323 
5324  str += 3;
5325  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5326 
5327  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5328 
5329  /* parse first argument [str+1..comma-1] */
5330  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5331  varnameslength, vartable, recursiondepth + 1) );
5332 
5333  /* parse second argument [comma+1..endptr] */
5334  ++comma;
5335  while( comma < endptr && *comma == ' ' )
5336  ++comma;
5337 
5338  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, comma, endptr - comma, endptr - 1, nvars, varnames,
5339  varnameslength, vartable, recursiondepth + 1) );
5340 
5341  SCIP_CALL( SCIPexprCreate(blkmem, expr, op, arg1, arg2) );
5342 
5343  str = endptr + 1;
5344  }
5345  else if( strncmp(str, "power", 5) == 0 )
5346  {
5347  /* we have a string of the form "power(...,integer)" (thus, intpower)
5348  * first find the closing parenthesis, then the comma
5349  */
5350  const char* comma;
5351  int exponent;
5352 
5353  str += 5;
5354  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5355 
5356  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5357 
5358  /* parse first argument [str+1..comma-1] */
5359  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5360  varnameslength, vartable, recursiondepth + 1) );
5361 
5362  ++comma;
5363  /* parse second argument [comma, endptr-1]: it needs to be an integer */
5364  while( comma < endptr && *comma == ' ' )
5365  ++comma;
5366  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5367  {
5368  SCIPerrorMessage("error parsing integer exponent from <%s>\n", comma);
5369  }
5370  if( !SCIPstrToIntValue(comma, &exponent, &nonconstendptr) )
5371  {
5372  SCIPerrorMessage("error parsing integer from <%s>\n", comma);
5373  return SCIP_READERROR;
5374  }
5375 
5376  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, exponent) );
5377 
5378  str = endptr + 1;
5379  }
5380  else if( strncmp(str, "realpower", 9) == 0 || strncmp(str, "signpower", 9) == 0 )
5381  {
5382  /* we have a string of the form "realpower(...,double)" or "signpower(...,double)"
5383  * first find the closing parenthesis, then the comma
5384  */
5385  const char* opname = str;
5386  const char* comma;
5387 
5388  str += 9;
5389  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5390 
5391  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5392 
5393  /* parse first argument [str+1..comma-1] */
5394  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames,
5395  varnameslength, vartable, recursiondepth + 1) );
5396 
5397  ++comma;
5398  /* parse second argument [comma, endptr-1]: it needs to be an number */
5399  while( comma < endptr && *comma == ' ' )
5400  ++comma;
5401  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5402  {
5403  SCIPerrorMessage("error parsing number exponent from <%s>\n", comma);
5404  }
5405  if( !SCIPstrToRealValue(comma, &number, &nonconstendptr) )
5406  {
5407  SCIPerrorMessage("error parsing number from <%s>\n", comma);
5408  return SCIP_READERROR;
5409  }
5410 
5411  if( strncmp(opname, "realpower", 9) == 0 )
5412  {
5413  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, number) );
5414  }
5415  else
5416  {
5417  assert(strncmp(opname, "signpower", 9) == 0);
5418  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIGNPOWER, arg1, number) );
5419  }
5420 
5421  str = endptr + 1;
5422  }
5423  else if( isalpha(*str) || *str == '_' || *str == '#' )
5424  {
5425  /* check for a variable, that was not recognized earlier because somebody omitted the '<' and '>' we need for
5426  * SCIPparseVarName, making everyones life harder;
5427  * we allow only variable names starting with a character or underscore here
5428  */
5429  const char* varnamestartptr = str;
5430 
5431  /* allow only variable names containing characters, digits, hash marks, and underscores here */
5432  while( isalnum(str[0]) || str[0] == '_' || str[0] == '#' )
5433  ++str;
5434 
5435  SCIP_CALL( exprparseReadVariable(blkmem, &varnamestartptr, expr, nvars, varnames, varnameslength,
5436  vartable, 1.0, str) );
5437  }
5438  else
5439  {
5440  SCIPerrorMessage("parsing of invalid expression %.*s.\n", (int) (lastchar - str + 1), str);
5441  return SCIP_READERROR;
5442  }
5443 
5444  /* if we are one char behind lastchar, we are done */
5445  if( str == lastchar + 1)
5446  {
5447  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5448  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5449  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5450 
5451  return SCIP_OKAY;
5452  }
5453 
5454  /* check if we are still in bounds */
5455  if( str > lastchar + 1)
5456  {
5457  SCIPerrorMessage("error finding first expression in \"%.*s\" took us outside of given subexpression length\n", length, strstart);
5458  return SCIP_READERROR;
5459  }
5460 
5461  /* ignore whitespace */
5462  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5463  ++str;
5464 
5465  /* maybe now we're done? */
5466  if( str >= lastchar + 1)
5467  {
5468  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5469  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5470  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5471 
5472  return SCIP_OKAY;
5473  }
5474 
5475  if( str[0] == '^' )
5476  {
5477  /* a '^' behind the found expression indicates a power */
5478  SCIP_Real constant;
5479 
5480  arg1 = *expr;
5481  ++str;
5482  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5483  ++str;
5484 
5485  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5486  {
5487  /* there is a number coming */
5488  if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5489  {
5490  SCIPerrorMessage("error parsing number from <%s>\n", str);
5491  return SCIP_READERROR;
5492  }
5493 
5494  SCIP_CALL( SCIPexprCreate(blkmem, &arg2, SCIP_EXPR_CONST, number) );
5495  str = nonconstendptr;
5496 
5497  constant = SCIPexprGetOpReal(arg2);
5498  SCIPexprFreeDeep(blkmem, &arg2);
5499 
5500  /* expr^number is intpower or realpower */
5501  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5502  {
5503  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5504  }
5505  else
5506  {
5507  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5508  }
5509  }
5510  else if( str[0] == '(' )
5511  {
5512  /* we use exprParse to evaluate the exponent */
5513 
5514  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5515  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str + 1, endptr - str - 1, endptr -1, nvars, varnames,
5516  varnameslength, vartable, recursiondepth + 1) );
5517 
5518  if( SCIPexprGetOperator(arg2) != SCIP_EXPR_CONST )
5519  {
5520  /* reformulate arg1^arg2 as exp(arg2 * log(arg1)) */
5521  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5522  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, *expr, arg2) );
5523  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, *expr) );
5524  }
5525  else
5526  {
5527  /* expr^number is intpower or realpower */
5528  constant = SCIPexprGetOpReal(arg2);
5529  SCIPexprFreeDeep(blkmem, &arg2);
5530  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5531  {
5532  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5533  }
5534  else
5535  {
5536  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5537  }
5538  }
5539  str = endptr + 1;
5540  }
5541  else
5542  {
5543  SCIPerrorMessage("unexpected string following ^ in %.*s\n", length, str);
5544  return SCIP_READERROR;
5545  }
5546 
5547  /* ignore whitespace */
5548  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5549  ++str;
5550  }
5551 
5552  /* check for a two argument operator that is not a multiplication */
5553  if( str <= lastchar && (str[0] == '+' || str[0] == '-' || str[0] == '/') )
5554  {
5555  char op;
5556 
5557  op = str[0];
5558  arg1 = *expr;
5559 
5560  /* step forward over the operator to go to the beginning of the second argument */
5561  ++str;
5562 
5563  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5564  varnameslength, vartable, recursiondepth + 1) );
5565  str = lastchar + 1;
5566 
5567  /* make new expression from two arguments */
5568  if( op == '+')
5569  {
5570  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5571  }
5572  else if( op == '-')
5573  {
5574  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, -1.0, arg2, 0.0) );
5575  }
5576  else if( op == '*' )
5577  {
5578  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5579  {
5580  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5581  }
5582  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5583  {
5584  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5585  }
5586  else
5587  {
5588  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5589  }
5590  }
5591  else
5592  {
5593  assert(op == '/');
5594 
5595  if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5596  {
5597  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, 1.0 / SCIPexprGetOpReal(arg2)) );
5598  SCIPexprFreeShallow(blkmem, &arg2);
5599  }
5600  else
5601  {
5602  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_DIV, arg1, arg2) );
5603  }
5604  }
5605  }
5606 
5607  /* ignore whitespace */
5608  while( isspace((unsigned char)*str) )
5609  ++str;
5610 
5611  /* we are either done or we have a multiplication? */
5612  if( str >= lastchar + 1 )
5613  {
5614  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5615  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5616  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5617 
5618  return SCIP_OKAY;
5619  }
5620 
5621  /* if there is a part of the string left to be parsed, we assume that this as a multiplication */
5622  arg1 = *expr;
5623 
5624  /* stepping over multiplication operator if needed */
5625  if( str[0] == '*' )
5626  {
5627  ++str;
5628  }
5629  else if( str[0] != '(' )
5630  {
5631  SCIPdebugMessage("No operator found, assuming a multiplication before %.*s\n", (int) (lastchar - str + 1), str);
5632  }
5633 
5634  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames,
5635  varnameslength, vartable, recursiondepth + 1) );
5636 
5637  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5638  {
5639  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5640  SCIPexprFreeDeep(blkmem, &arg1);
5641  }
5642  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5643  {
5644  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5645  SCIPexprFreeDeep(blkmem, &arg2);
5646  }
5647  else
5648  {
5649  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5650  }
5651 
5652  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5653  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5654  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5655 
5656  return SCIP_OKAY;
5657 }
5658 
5659 /**@} */
5660 
5661 /**@name Expression methods */
5662 /**@{ */
5663 
5664 /* In debug mode, the following methods are implemented as function calls to ensure
5665  * type validity.
5666  * In optimized mode, the methods are implemented as defines to improve performance.
5667  * However, we want to have them in the library anyways, so we have to undef the defines.
5668  */
5669 
5670 #undef SCIPexprGetOperator
5671 #undef SCIPexprGetNChildren
5672 #undef SCIPexprGetChildren
5673 #undef SCIPexprGetOpIndex
5674 #undef SCIPexprGetOpReal
5675 #undef SCIPexprGetOpData
5676 #undef SCIPexprGetRealPowerExponent
5677 #undef SCIPexprGetIntPowerExponent
5678 #undef SCIPexprGetSignPowerExponent
5679 #undef SCIPexprGetLinearCoefs
5680 #undef SCIPexprGetLinearConstant
5681 #undef SCIPexprGetQuadElements
5682 #undef SCIPexprGetQuadConstant
5683 #undef SCIPexprGetQuadLinearCoefs
5684 #undef SCIPexprGetNQuadElements
5685 #undef SCIPexprGetMonomials
5686 #undef SCIPexprGetNMonomials
5687 #undef SCIPexprGetPolynomialConstant
5688 #undef SCIPexprGetMonomialCoef
5689 #undef SCIPexprGetMonomialNFactors
5690 #undef SCIPexprGetMonomialChildIndices
5691 #undef SCIPexprGetMonomialExponents
5692 #undef SCIPexprGetUserData
5693 #undef SCIPexprHasUserEstimator
5694 #undef SCIPexprGetUserEvalCapability
5695 
5696 /** gives operator of expression */
5698  SCIP_EXPR* expr /**< expression */
5699  )
5700 {
5701  assert(expr != NULL);
5702 
5703  return expr->op;
5704 }
5705 
5706 /** gives number of children of an expression */
5708  SCIP_EXPR* expr /**< expression */
5709  )
5710 {
5711  assert(expr != NULL);
5712 
5713  return expr->nchildren;
5714 }
5715 
5716 /** gives pointer to array with children of an expression */
5718  SCIP_EXPR* expr /**< expression */
5719  )
5720 {
5721  assert(expr != NULL);
5722 
5723  return expr->children;
5724 }
5725 
5726 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
5728  SCIP_EXPR* expr /**< expression */
5729  )
5730 {
5731  assert(expr != NULL);
5732  assert(expr->op == SCIP_EXPR_VARIDX || expr->op == SCIP_EXPR_PARAM);
5733 
5734  return expr->data.intval;
5735 }
5736 
5737 /** gives real belonging to a SCIP_EXPR_CONST operand */
5739  SCIP_EXPR* expr /**< expression */
5740  )
5741 {
5742  assert(expr != NULL);
5743  assert(expr->op == SCIP_EXPR_CONST);
5744 
5745  return expr->data.dbl;
5746 }
5747 
5748 /** gives void* belonging to a complex operand */
5750  SCIP_EXPR* expr /**< expression */
5751  )
5752 {
5753  assert(expr != NULL);
5754  assert(expr->op >= SCIP_EXPR_SUM); /* only complex operands store their data as void* */
5755 
5756  return expr->data.data;
5757 }
5758 
5759 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
5761  SCIP_EXPR* expr /**< expression */
5762  )
5763 {
5764  assert(expr != NULL);
5765  assert(expr->op == SCIP_EXPR_REALPOWER);
5766 
5767  return expr->data.dbl;
5768 }
5769 
5770 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
5772  SCIP_EXPR* expr /**< expression */
5773  )
5774 {
5775  assert(expr != NULL);
5776  assert(expr->op == SCIP_EXPR_INTPOWER);
5777 
5778  return expr->data.intval;
5779 }
5780 
5781 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
5783  SCIP_EXPR* expr /**< expression */
5784  )
5785 {
5786  assert(expr != NULL);
5787  assert(expr->op == SCIP_EXPR_SIGNPOWER);
5788 
5789  return expr->data.dbl;
5790 }
5791 
5792 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
5794  SCIP_EXPR* expr /**< expression */
5795  )
5796 {
5797  assert(expr != NULL);
5798  assert(expr->op == SCIP_EXPR_LINEAR);
5799  assert(expr->data.data != NULL);
5800 
5801  /* the coefficients are stored in the first nchildren elements of the array stored as expression data */
5802  return (SCIP_Real*)expr->data.data;
5803 }
5804 
5805 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
5807  SCIP_EXPR* expr /**< expression */
5808  )
5809 {
5810  assert(expr != NULL);
5811  assert(expr->op == SCIP_EXPR_LINEAR);
5812  assert(expr->data.data != NULL);
5813 
5814  /* the constant is stored in the nchildren's element of the array stored as expression data */
5815  return ((SCIP_Real*)expr->data.data)[expr->nchildren];
5816 }
5817 
5818 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5820  SCIP_EXPR* expr /**< quadratic expression */
5821  )
5822 {
5823  assert(expr != NULL);
5824  assert(expr->op == SCIP_EXPR_QUADRATIC);
5825  assert(expr->data.data != NULL);
5826 
5827  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->quadelems;
5828 }
5829 
5830 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
5832  SCIP_EXPR* expr /**< quadratic expression */
5833  )
5834 {
5835  assert(expr != NULL);
5836  assert(expr->op == SCIP_EXPR_QUADRATIC);
5837  assert(expr->data.data != NULL);
5838 
5839  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->constant;
5840 }
5841 
5842 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression
5843  * can be NULL if all coefficients are 0.0 */
5845  SCIP_EXPR* expr /**< quadratic expression */
5846  )
5847 {
5848  assert(expr != NULL);
5849  assert(expr->op == SCIP_EXPR_QUADRATIC);
5850  assert(expr->data.data != NULL);
5851 
5852  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->lincoefs;
5853 }
5854 
5855 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5857  SCIP_EXPR* expr /**< quadratic expression */
5858  )
5859 {
5860  assert(expr != NULL);
5861  assert(expr->op == SCIP_EXPR_QUADRATIC);
5862  assert(expr->data.data != NULL);
5863 
5864  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->nquadelems;
5865 }
5866 
5867 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5869  SCIP_EXPR* expr /**< expression */
5870  )
5871 {
5872  assert(expr != NULL);
5873  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5874  assert(expr->data.data != NULL);
5875 
5876  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->monomials;
5877 }
5878 
5879 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5881  SCIP_EXPR* expr /**< expression */
5882  )
5883 {
5884  assert(expr != NULL);
5885  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5886  assert(expr->data.data != NULL);
5887 
5888  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->nmonomials;
5889 }
5890 
5891 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
5893  SCIP_EXPR* expr /**< expression */
5894  )
5895 {
5896  assert(expr != NULL);
5897  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5898  assert(expr->data.data != NULL);
5899 
5900  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant;
5901 }
5902 
5903 /** gets coefficient of a monomial */
5905  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5906  )
5907 {
5908  assert(monomial != NULL);
5909 
5910  return monomial->coef;
5911 }
5912 
5913 /** gets number of factors of a monomial */
5915  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5916  )
5917 {
5918  assert(monomial != NULL);
5919 
5920  return monomial->nfactors;
5921 }
5922 
5923 /** gets indices of children corresponding to factors of a monomial */
5925  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5926  )
5927 {
5928  assert(monomial != NULL);
5929 
5930  return monomial->childidxs;
5931 }
5932 
5933 /** gets exponents in factors of a monomial */
5935  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5936  )
5937 {
5938  assert(monomial != NULL);
5939 
5940  return monomial->exponents;
5941 }
5942 
5943 /** gets user data of a user expression */
5945  SCIP_EXPR* expr
5946  )
5947 {
5948  assert(expr != NULL);
5949  assert(expr->data.data != NULL);
5950 
5951  return ((SCIP_EXPRDATA_USER*)expr->data.data)->userdata;
5952 }
5953 
5954 /** indicates whether a user expression has the estimator callback defined */
5956  SCIP_EXPR* expr
5957  )
5958 {
5959  assert(expr != NULL);
5960  assert(expr->data.data != NULL);
5961 
5962  return ((SCIP_EXPRDATA_USER*)expr->data.data)->estimate != NULL;
5963 }
5964 
5965 /** gives the evaluation capability of a user expression */
5967  SCIP_EXPR* expr
5968  )
5969 {
5970  assert(expr != NULL);
5971  assert(expr->data.data != NULL);
5972 
5973  return ((SCIP_EXPRDATA_USER*)expr->data.data)->evalcapability;
5974 }
5975 
5976 /** creates a simple expression */
5978  BMS_BLKMEM* blkmem, /**< block memory data structure */
5979  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
5980  SCIP_EXPROP op, /**< operand of expression */
5981  ... /**< arguments of operand */
5982  )
5983 {
5984  va_list ap;
5985  SCIP_EXPR** children;
5986  SCIP_EXPROPDATA opdata;
5987 
5988  assert(blkmem != NULL);
5989  assert(expr != NULL);
5990 
5991  switch( op )
5992  {
5993  case SCIP_EXPR_VARIDX:
5994  case SCIP_EXPR_PARAM:
5995  {
5996  va_start( ap, op ); /*lint !e838*/
5997  opdata.intval = va_arg( ap, int ); /*lint !e416 !e826*/
5998  va_end( ap ); /*lint !e826*/
5999 
6000  assert( opdata.intval >= 0 );
6001 
6002  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
6003  break;
6004  }
6005 
6006  case SCIP_EXPR_CONST:
6007  {
6008  va_start(ap, op ); /*lint !e838*/
6009  opdata.dbl = va_arg( ap, SCIP_Real ); /*lint !e416 !e826*/
6010  va_end( ap ); /*lint !e826*/
6011 
6012  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
6013  break;
6014  }
6015 
6016  /* operands with two children */
6017  case SCIP_EXPR_PLUS :
6018  case SCIP_EXPR_MINUS :
6019  case SCIP_EXPR_MUL :
6020  case SCIP_EXPR_DIV :
6021  case SCIP_EXPR_MIN :
6022  case SCIP_EXPR_MAX :
6023  {
6024  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 2) ); /*lint !e506*/
6025 
6026  va_start(ap, op ); /*lint !e838*/
6027  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6028  children[1] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6029  assert(children[0] != NULL);
6030  assert(children[1] != NULL);
6031  va_end( ap ); /*lint !e826*/
6032  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6033 
6034  SCIP_CALL( exprCreate( blkmem, expr, op, 2, children, opdata ) );
6035  break;
6036  }
6037 
6038  /* operands with one child */
6039  case SCIP_EXPR_SQUARE:
6040  case SCIP_EXPR_SQRT :
6041  case SCIP_EXPR_EXP :
6042  case SCIP_EXPR_LOG :
6043  case SCIP_EXPR_SIN :
6044  case SCIP_EXPR_COS :
6045  case SCIP_EXPR_TAN :
6046  /* case SCIP_EXPR_ERF : */
6047  /* case SCIP_EXPR_ERFI : */
6048  case SCIP_EXPR_ABS :
6049  case SCIP_EXPR_SIGN :
6050  {
6051  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6052 
6053  va_start(ap, op ); /*lint !e838*/
6054  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6055  assert(children[0] != NULL);
6056  va_end( ap ); /*lint !e826*/
6057  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6058 
6059  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6060  break;
6061  }
6062 
6063  case SCIP_EXPR_REALPOWER:
6064  case SCIP_EXPR_SIGNPOWER:
6065  {
6066  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6067 
6068  va_start(ap, op ); /*lint !e838*/
6069  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6070  assert(children[0] != NULL);
6071  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
6072  va_end( ap ); /*lint !e826*/
6073 
6074  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6075  break;
6076  }
6077 
6078  case SCIP_EXPR_INTPOWER:
6079  {
6080  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6081 
6082  va_start(ap, op ); /*lint !e838*/
6083  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6084  assert(children[0] != NULL);
6085  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
6086  va_end( ap ); /*lint !e826*/
6087 
6088  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6089  break;
6090  }
6091 
6092  /* complex operands */
6093  case SCIP_EXPR_SUM :
6094  case SCIP_EXPR_PRODUCT:
6095  {
6096  int nchildren;
6097  SCIP_EXPR** childrenarg;
6098 
6099  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6100 
6101  va_start(ap, op ); /*lint !e838*/
6102  /* first argument should be number of children */
6103  nchildren = va_arg( ap, int ); /*lint !e416 !e826*/
6104  assert(nchildren >= 0);
6105 
6106  /* for a sum or product of 0 terms we can finish here */
6107  if( nchildren == 0 )
6108  {
6109  SCIP_RETCODE retcode;
6110  retcode = exprCreate( blkmem, expr, op, 0, NULL, opdata);
6111  va_end( ap ); /*lint !e826*/
6112  SCIP_CALL( retcode );
6113  break;
6114  }
6115 
6116  /* next argument should be array of children expressions */
6117  childrenarg = va_arg( ap, SCIP_EXPR** ); /*lint !e416 !e826*/
6118  assert(childrenarg != NULL);
6119  va_end( ap ); /*lint !e826*/
6120 
6121  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &children, childrenarg, nchildren) );
6122 
6123  SCIP_CALL( exprCreate( blkmem, expr, op, nchildren, children, opdata) );
6124  break;
6125  }
6126 
6127  case SCIP_EXPR_LINEAR :
6128  case SCIP_EXPR_QUADRATIC:
6129  case SCIP_EXPR_POLYNOMIAL:
6130  case SCIP_EXPR_USER:
6131  {
6132  SCIPerrorMessage("cannot create complex expression linear, quadratic, polynomial, or user with SCIPexprCreate\n");
6133  return SCIP_INVALIDDATA;
6134  }
6135 
6136  case SCIP_EXPR_LAST:
6137  SCIPABORT();
6138  break;
6139  }
6140 
6141  return SCIP_OKAY;
6142 }
6143 
6144 /** copies an expression including its children */
6146  BMS_BLKMEM* blkmem, /**< block memory data structure */
6147  SCIP_EXPR** targetexpr, /**< buffer to store pointer to copied expression */
6148  SCIP_EXPR* sourceexpr /**< expression to copy */
6149  )
6150 {
6151  assert(blkmem != NULL);
6152  assert(targetexpr != NULL);
6153  assert(sourceexpr != NULL);
6154 
6155  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targetexpr, sourceexpr) );
6156 
6157  if( sourceexpr->nchildren )
6158  {
6159  int i;
6160 
6161  /* alloc memory for children expressions */
6162  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetexpr)->children, sourceexpr->nchildren) );
6163 
6164  /* copy children expressions */
6165  for( i = 0; i < sourceexpr->nchildren; ++i )
6166  {
6167  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targetexpr)->children[i], sourceexpr->children[i]) );
6168  }
6169  }
6170  else
6171  {
6172  assert((*targetexpr)->children == NULL); /* otherwise, sourceexpr->children was not NULL, which is wrong */
6173  }
6174 
6175  /* call operands data copy callback for complex operands
6176  * for simple operands BMSduplicate above should have done the job
6177  */
6178  if( exprOpTable[sourceexpr->op].copydata != NULL )
6179  {
6180  SCIP_CALL( exprOpTable[sourceexpr->op].copydata(blkmem, sourceexpr->nchildren, sourceexpr->data, &(*targetexpr)->data) );
6181  }
6182 
6183  return SCIP_OKAY;
6184 }
6185 
6186 /** frees an expression including its children */
6188  BMS_BLKMEM* blkmem, /**< block memory data structure */
6189  SCIP_EXPR** expr /**< pointer to expression to free */
6190  )
6191 {
6192  assert(blkmem != NULL);
6193  assert(expr != NULL);
6194  assert(*expr != NULL);
6195 
6196  /* call operands data free callback, if given */
6197  if( exprOpTable[(*expr)->op].freedata != NULL )
6198  {
6199  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6200  }
6201 
6202  if( (*expr)->nchildren )
6203  {
6204  int i;
6205 
6206  assert( (*expr)->children != NULL );
6207 
6208  for( i = 0; i < (*expr)->nchildren; ++i )
6209  {
6210  SCIPexprFreeDeep(blkmem, &(*expr)->children[i]);
6211  assert((*expr)->children[i] == NULL);
6212  }
6213 
6214  BMSfreeBlockMemoryArray(blkmem, &(*expr)->children, (*expr)->nchildren);
6215  }
6216  else
6217  {
6218  assert( (*expr)->children == NULL );
6219  }
6220 
6221  BMSfreeBlockMemory(blkmem, expr);
6222 }
6223 
6224 /** frees an expression but not its children */
6226  BMS_BLKMEM* blkmem, /**< block memory data structure */
6227  SCIP_EXPR** expr /**< pointer to expression to free */
6228  )
6229 {
6230  assert(blkmem != NULL);
6231  assert(expr != NULL);
6232  assert(*expr != NULL);
6233 
6234  /* call operands data free callback, if given */
6235  if( exprOpTable[(*expr)->op].freedata != NULL )
6236  {
6237  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6238  }
6239 
6240  BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->nchildren);
6241 
6242  BMSfreeBlockMemory(blkmem, expr);
6243 }
6244 
6245 /** creates an expression from the addition of two given expression, with coefficients, and a constant
6246  *
6247  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6248  * Favors creation and maintaining of SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6249  */
6251  BMS_BLKMEM* blkmem, /**< block memory data structure */
6252  SCIP_EXPR** expr, /**< pointer to store pointer to created expression */
6253  SCIP_Real coef1, /**< coefficient of first term */
6254  SCIP_EXPR* term1, /**< expression of first term, or NULL */
6255  SCIP_Real coef2, /**< coefficient of second term */
6256  SCIP_EXPR* term2, /**< expression of second term, or NULL */
6257  SCIP_Real constant /**< constant term to add */
6258  )
6259 {
6260  assert(blkmem != NULL);
6261  assert(expr != NULL);
6262 
6263  /* @todo could do something special with quadratic and polynomial expressions */
6264 
6265  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_CONST )
6266  {
6267  constant += coef1 * SCIPexprGetOpReal(term1);
6268  SCIPexprFreeDeep(blkmem, &term1);
6269  }
6270 
6271  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_CONST )
6272  {
6273  constant += coef2 * SCIPexprGetOpReal(term2);
6274  SCIPexprFreeDeep(blkmem, &term2);
6275  }
6276 
6277  if( term1 == NULL && term2 == NULL )
6278  {
6279  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, constant) );
6280  return SCIP_OKAY;
6281  }
6282 
6283  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && coef1 != 1.0 )
6284  {
6285  /* multiply coefficients and constant of linear expression term1 by coef1 */
6286  SCIP_Real* data;
6287  int i;
6288 
6289  data = (SCIP_Real*)term1->data.data;
6290  assert(data != NULL);
6291 
6292  /* loop one more index to multiply also constant of linear expression */
6293  for( i = 0; i <= term1->nchildren; ++i )
6294  data[i] *= coef1;
6295 
6296  coef1 = 1.0;
6297  }
6298 
6299  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR && coef2 != 1.0 )
6300  {
6301  /* multiply coefficients and constant of linear expression term2 by coef2 */
6302  SCIP_Real* data;
6303  int i;
6304 
6305  data = (SCIP_Real*)term2->data.data;
6306  assert(data != NULL);
6307 
6308  /* loop one more index to multiply also constant of linear expression */
6309  for( i = 0; i <= term2->nchildren; ++i )
6310  data[i] *= coef2;
6311 
6312  coef2 = 1.0;
6313  }
6314 
6315  if( term1 == NULL || term2 == NULL )
6316  {
6317  if( term1 == NULL )
6318  {
6319  term1 = term2;
6320  coef1 = coef2;
6321  }
6322  if( constant != 0.0 || coef1 != 1.0 )
6323  {
6324  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6325  {
6326  assert(coef1 == 1.0);
6327 
6328  /* add constant to existing linear expression */
6329  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 0, NULL, NULL, constant) );
6330  *expr = term1;
6331  }
6332  else
6333  {
6334  /* create new linear expression for coef1 * term1 + constant */
6335  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term1, &coef1, constant) );
6336  }
6337  }
6338  else
6339  {
6340  assert(constant == 0.0);
6341  assert(coef1 == 1.0);
6342  *expr = term1;
6343  }
6344 
6345  return SCIP_OKAY;
6346  }
6347 
6349  {
6350  /* add 2nd linear expression to first one */
6351  assert(coef1 == 1.0);
6352  assert(coef2 == 1.0);
6353 
6355  SCIPexprFreeShallow(blkmem, &term2);
6356 
6357  *expr = term1;
6358 
6359  return SCIP_OKAY;
6360  }
6361 
6362  if( SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
6363  {
6364  /* if only term2 is linear, then swap */
6365  SCIP_EXPR* tmp;
6366 
6367  tmp = term2;
6368  assert(coef2 == 1.0);
6369 
6370  term2 = term1;
6371  coef2 = coef1;
6372  term1 = tmp;
6373  coef1 = 1.0;
6374  }
6375 
6376  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6377  {
6378  /* add coef2*term2 as extra child to linear expression term1 */
6379  assert(coef1 == 1.0);
6380 
6381  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 1, &coef2, &term2, constant) );
6382  *expr = term1;
6383 
6384  return SCIP_OKAY;
6385  }
6386 
6387  /* both terms are not linear, then create new linear term for sum */
6388  {
6389  SCIP_Real coefs[2];
6390  SCIP_EXPR* children[2];
6391 
6392  coefs[0] = coef1;
6393  coefs[1] = coef2;
6394  children[0] = term1;
6395  children[1] = term2;
6396 
6397  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 2, children, coefs, constant) );
6398  }
6399 
6400  return SCIP_OKAY;
6401 }
6402 
6403 /** creates an expression from the multiplication of an expression with a constant
6404  *
6405  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6406  * Favors creation and maintaining SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6407  */
6409  BMS_BLKMEM* blkmem, /**< block memory data structure */
6410  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
6411  SCIP_EXPR* term, /**< term to multiply by factor */
6412  SCIP_Real factor /**< factor */
6413  )
6414 {
6415  assert(blkmem != NULL);
6416  assert(expr != NULL);
6417  assert(term != NULL);
6418 
6419  if( factor == 0.0 )
6420  {
6421  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, 0.0) );
6422 
6423  SCIPexprFreeDeep(blkmem, &term);
6424 
6425  return SCIP_OKAY;
6426  }
6427  if( factor == 1.0 )
6428  {
6429  *expr = term;
6430  return SCIP_OKAY;
6431  }
6432 
6433  switch( SCIPexprGetOperator(term) )
6434  {
6435  case SCIP_EXPR_CONST :
6436  {
6437  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, factor * SCIPexprGetOpReal(term)) );
6438  SCIPexprFreeDeep(blkmem, &term);
6439  break;
6440  }
6441 
6442  case SCIP_EXPR_LINEAR :
6443  {
6444  SCIP_Real* data;
6445  int i;
6446 
6447  data = (SCIP_Real*)term->data.data;
6448  assert(data != NULL);
6449 
6450  /* loop one more index to multiply also constant of linear expression */
6451  for( i = 0; i <= SCIPexprGetNChildren(term); ++i )
6452  data[i] *= factor;
6453 
6454  *expr = term;
6455  break;
6456  }
6457 
6458  case SCIP_EXPR_QUADRATIC :
6459  {
6461  int i;
6462 
6463  data = (SCIP_EXPRDATA_QUADRATIC*)term->data.data;
6464 
6465  data->constant *= factor;
6466 
6467  if( data->lincoefs != NULL )
6468  for( i = 0; i < term->nchildren; ++i )
6469  data->lincoefs[i] *= factor;
6470 
6471  for( i = 0; i < data->nquadelems; ++i )
6472  data->quadelems[i].coef *= factor;
6473 
6474  *expr = term;
6475  break;
6476  }
6477 
6478  case SCIP_EXPR_POLYNOMIAL :
6479  {
6481  int i;
6482 
6483  data = (SCIP_EXPRDATA_POLYNOMIAL*)term->data.data;
6484 
6485  data->constant *= factor;
6486 
6487  for( i = 0; i < data->nmonomials; ++i )
6488  data->monomials[i]->coef *= factor;
6489 
6490  *expr = term;
6491  break;
6492  }
6493 
6494  default:
6495  {
6496  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term, &factor, 0.0) );
6497  break;
6498  }
6499 
6500  } /*lint !e788 */
6501 
6502  return SCIP_OKAY;
6503 }
6504 
6505 /** creates a SCIP_EXPR_LINEAR expression that is (affine) linear in its children: constant + sum_i coef_i child_i */
6507  BMS_BLKMEM* blkmem, /**< block memory data structure */
6508  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6509  int nchildren, /**< number of children */
6510  SCIP_EXPR** children, /**< children of expression */
6511  SCIP_Real* coefs, /**< coefficients of children */
6512  SCIP_Real constant /**< constant part */
6513  )
6514 {
6515  SCIP_EXPROPDATA opdata;
6516  SCIP_EXPR** childrencopy;
6517  SCIP_Real* data;
6518 
6519  assert(nchildren >= 0);
6520  assert(children != NULL || nchildren == 0);
6521  assert(coefs != NULL || nchildren == 0);
6522 
6523  if( nchildren > 0 )
6524  {
6525  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6526  }
6527  else
6528  childrencopy = NULL;
6529 
6530  /* we store the coefficients and the constant in a single array and make this our operand data */
6531  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, nchildren + 1) );
6532  BMScopyMemoryArray(data, coefs, nchildren); /*lint !e644*/
6533  data[nchildren] = constant;
6534 
6535  opdata.data = (void*)data;
6536 
6537  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_LINEAR, nchildren, childrencopy, opdata) );
6538 
6539  return SCIP_OKAY;
6540 }
6541 
6542 /** adds new terms to a linear expression */
6544  BMS_BLKMEM* blkmem, /**< block memory */
6545  SCIP_EXPR* expr, /**< linear expression */
6546  int nchildren, /**< number of children to add */
6547  SCIP_Real* coefs, /**< coefficients of additional children */
6548  SCIP_EXPR** children, /**< additional children expressions */
6549  SCIP_Real constant /**< constant to add */
6550  )
6551 {
6552  SCIP_Real* data;
6553 
6554  assert(blkmem != NULL);
6555  assert(expr != NULL);
6556  assert(expr->op == SCIP_EXPR_LINEAR);
6557  assert(nchildren >= 0);
6558  assert(coefs != NULL || nchildren == 0);
6559  assert(children != NULL || nchildren == 0);
6560 
6561  data = (SCIP_Real*)expr->data.data;
6562  assert(data != NULL);
6563 
6564  /* handle simple case of adding a constant */
6565  if( nchildren == 0 )
6566  {
6567  data[expr->nchildren] += constant;
6568 
6569  return SCIP_OKAY;
6570  }
6571 
6572  /* add new children to expr's children array */
6573  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nchildren) );
6574  BMScopyMemoryArray(&expr->children[expr->nchildren], children, nchildren); /*lint !e866*/
6575 
6576  /* add constant and new coefs to expr's data array */
6577  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, expr->nchildren + 1, expr->nchildren + nchildren + 1) );
6578  data[expr->nchildren + nchildren] = data[expr->nchildren] + constant;
6579  BMScopyMemoryArray(&data[expr->nchildren], coefs, nchildren); /*lint !e866*/
6580  expr->data.data = (void*)data;
6581 
6582  expr->nchildren += nchildren;
6583 
6584  return SCIP_OKAY;
6585 }
6586 
6587 /** creates a SCIP_EXPR_QUADRATIC expression: constant + sum_i coef_i child_i + sum_i coef_i child1_i child2_i */
6589  BMS_BLKMEM* blkmem, /**< block memory data structure */
6590  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6591  int nchildren, /**< number of children */
6592  SCIP_EXPR** children, /**< children of expression */
6593  SCIP_Real constant, /**< constant */
6594  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
6595  int nquadelems, /**< number of quadratic elements */
6596  SCIP_QUADELEM* quadelems /**< quadratic elements specifying coefficients and child indices */
6597  )
6598 {
6599  SCIP_EXPROPDATA opdata;
6600  SCIP_EXPR** childrencopy;
6602 
6603  assert(nchildren >= 0);
6604  assert(children != NULL || nchildren == 0);
6605  assert(quadelems != NULL || nquadelems == 0);
6606 
6607  if( nchildren > 0 )
6608  {
6609  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6610  }
6611  else
6612  childrencopy = NULL;
6613 
6614  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
6615 
6616  opdata.data = (void*)data;
6617 
6618  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_QUADRATIC, nchildren, childrencopy, opdata) );
6619 
6620  return SCIP_OKAY;
6621 }
6622 
6623 /** ensures that quadratic elements of a quadratic expression are sorted */
6625  SCIP_EXPR* expr /**< quadratic expression */
6626  )
6627 {
6628  assert(expr != NULL);
6629  assert(expr->op == SCIP_EXPR_QUADRATIC);
6630  assert(expr->data.data != NULL);
6631 
6633 }
6634 
6635 /** creates a SCIP_EXPR_POLYNOMIAL expression from an array of monomials: constant + sum_i monomial_i */
6637  BMS_BLKMEM* blkmem, /**< block memory data structure */
6638  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6639  int nchildren, /**< number of children */
6640  SCIP_EXPR** children, /**< children of expression */
6641  int nmonomials, /**< number of monomials */
6642  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
6643  SCIP_Real constant, /**< constant part */
6644  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6645  )
6646 {
6647  SCIP_EXPROPDATA opdata;
6648  SCIP_EXPR** childrencopy;
6650 
6651  assert(nchildren >= 0);
6652  assert(children != NULL || nchildren == 0);
6653  assert(monomials != NULL || nmonomials == 0);
6654 
6655  if( nchildren > 0 )
6656  {
6657  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6658  }
6659  else
6660  childrencopy = NULL;
6661 
6662  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
6663  opdata.data = (void*)data;
6664 
6665  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_POLYNOMIAL, nchildren, childrencopy, opdata) );
6666 
6667  return SCIP_OKAY;
6668 }
6669 
6670 /** adds an array of monomials to a SCIP_EXPR_POLYNOMIAL expression */
6672  BMS_BLKMEM* blkmem, /**< block memory of expression */
6673  SCIP_EXPR* expr, /**< expression */
6674  int nmonomials, /**< number of monomials to add */
6675  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
6676  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6677  )
6678 {
6679  assert(blkmem != NULL);
6680  assert(expr != NULL);
6681  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6682  assert(monomials != NULL || nmonomials == 0);
6683 
6684  if( nmonomials == 0 )
6685  return SCIP_OKAY;
6686 
6687  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, nmonomials, monomials, copymonomials) );
6688 
6689  return SCIP_OKAY;
6690 }
6691 
6692 /** changes the constant in a SCIP_EXPR_POLYNOMIAL expression */
6694  SCIP_EXPR* expr, /**< expression */
6695  SCIP_Real constant /**< new value for constant */
6696  )
6697 {
6698  assert(expr != NULL);
6699  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6700  assert(expr->data.data != NULL);
6701 
6702  ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant = constant;
6703 }
6704 
6705 /** multiplies each summand of a polynomial by a given constant */
6707  BMS_BLKMEM* blkmem, /**< block memory */
6708  SCIP_EXPR* expr, /**< polynomial expression */
6709  SCIP_Real factor /**< constant factor */
6710  )
6711 {
6712  assert(expr != NULL);
6713  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6714  assert(expr->data.data != NULL);
6715 
6716  polynomialdataMultiplyByConstant(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor);
6717 }
6718 
6719 /** multiplies each summand of a polynomial by a given monomial */
6721  BMS_BLKMEM* blkmem, /**< block memory */
6722  SCIP_EXPR* expr, /**< polynomial expression */
6723  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
6724  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6725  )
6726 {
6727  assert(blkmem != NULL);
6728  assert(factor != NULL);
6729  assert(expr != NULL);
6730  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6731  assert(expr->data.data != NULL);
6732 
6733  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor, childmap) );
6734 
6735  return SCIP_OKAY;
6736 }
6737 
6738 /** multiplies this polynomial by a polynomial
6739  *
6740  * Factor needs to be different from expr.
6741  * Children of factor need to be children of expr already, w.r.t. an optional mapping of child indices.
6742  */
6744  BMS_BLKMEM* blkmem, /**< block memory */
6745  SCIP_EXPR* expr, /**< polynomial expression */
6746  SCIP_EXPR* factor, /**< polynomial factor */
6747  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6748  )
6749 {
6750  assert(blkmem != NULL);
6751  assert(expr != NULL);
6752  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6753  assert(expr->data.data != NULL);
6754  assert(factor != NULL);
6755  assert(factor->op == SCIP_EXPR_POLYNOMIAL);
6756  assert(factor->data.data != NULL);
6757  assert(expr != factor);
6758 
6759 #ifndef NDEBUG
6760  if( childmap == NULL )
6761  {
6762  int i;
6763  assert(factor->nchildren == expr->nchildren);
6764  for( i = 0; i < factor->nchildren; ++i )
6765  assert(SCIPexprAreEqual(expr->children[i], factor->children[i], 0.0));
6766  }
6767  else
6768  {
6769  int i;
6770  for( i = 0; i < factor->nchildren; ++i )
6771  {
6772  assert(childmap[i] >= 0);
6773  assert(childmap[i] < expr->nchildren);
6774  assert(SCIPexprAreEqual(expr->children[childmap[i]], factor->children[i], 0.0));
6775  }
6776  }
6777 #endif
6778 
6780 
6781  return SCIP_OKAY;
6782 }
6783 
6784 /** takes a power of the polynomial
6785  *
6786  * Exponent need to be an integer.
6787  * Polynomial needs to be a monomial, if exponent is negative.
6788  */
6790  BMS_BLKMEM* blkmem, /**< block memory */
6791  SCIP_EXPR* expr, /**< polynomial expression */
6792  int exponent /**< exponent of power operation */
6793  )
6794 {
6795  assert(blkmem != NULL);
6796  assert(expr != NULL);
6797  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6798  assert(expr->data.data != NULL);
6799 
6800  SCIP_CALL( polynomialdataPower(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, exponent) );
6801 
6802  return SCIP_OKAY;
6803 }
6804 
6805 /** merges monomials in a polynomial expression that differ only in coefficient into a single monomial
6806  *
6807  * Eliminates monomials with coefficient between -eps and eps.
6808  */
6810  BMS_BLKMEM* blkmem, /**< block memory */
6811  SCIP_EXPR* expr, /**< polynomial expression */
6812  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
6813  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
6814  )
6815 {
6816  assert(expr != NULL);
6817  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6818  assert(expr->data.data != NULL);
6819 
6820  polynomialdataMergeMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, eps, mergefactors);
6821 }
6822 
6823 /** checks if two monomials are equal */
6825  SCIP_EXPRDATA_MONOMIAL* monomial1, /**< first monomial */
6826  SCIP_EXPRDATA_MONOMIAL* monomial2, /**< second monomial */
6827  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6828  )
6829 {
6830  int i;
6831 
6832  assert(monomial1 != NULL);
6833  assert(monomial2 != NULL);
6834 
6835  if( monomial1->nfactors != monomial2->nfactors )
6836  return FALSE;
6837 
6838  if( !EPSEQ(monomial1->coef, monomial2->coef, eps) )
6839  return FALSE;
6840 
6841  SCIPexprSortMonomialFactors(monomial1);
6842  SCIPexprSortMonomialFactors(monomial2);
6843 
6844  for( i = 0; i < monomial1->nfactors; ++i )
6845  {
6846  if( monomial1->childidxs[i] != monomial2->childidxs[i] ||
6847  !EPSEQ(monomial1->exponents[i], monomial2->exponents[i], eps) )
6848  return FALSE;
6849  }
6850 
6851  return TRUE;
6852 }
6853 
6854 /** changes coefficient of monomial */
6856  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6857  SCIP_Real newcoef /**< new coefficient */
6858  )
6859 {
6860  assert(monomial != NULL);
6861 
6862  monomial->coef = newcoef;
6863 }
6864 
6865 /** adds factors to a monomial */
6867  BMS_BLKMEM* blkmem, /**< block memory */
6868  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6869  int nfactors, /**< number of factors to add */
6870  int* childidxs, /**< indices of children corresponding to factors */
6871  SCIP_Real* exponents /**< exponent in each factor */
6872  )
6873 {
6874  assert(monomial != NULL);
6875  assert(nfactors >= 0);
6876  assert(childidxs != NULL || nfactors == 0);
6877  assert(exponents != NULL || nfactors == 0);
6878 
6879  if( nfactors == 0 )
6880  return SCIP_OKAY;
6881 
6882  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + nfactors) );
6883  assert(monomial->nfactors + nfactors <= monomial->factorssize);
6884 
6885  BMScopyMemoryArray(&monomial->childidxs[monomial->nfactors], childidxs, nfactors); /*lint !e866*/
6886  BMScopyMemoryArray(&monomial->exponents[monomial->nfactors], exponents, nfactors); /*lint !e866*/
6887 
6888  monomial->nfactors += nfactors;
6889  monomial->sorted = (monomial->nfactors <= 1);
6890 
6891  return SCIP_OKAY;
6892 }
6893 
6894 /** multiplies a monomial with a monomial */
6896  BMS_BLKMEM* blkmem, /**< block memory */
6897  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6898  SCIP_EXPRDATA_MONOMIAL* factor, /**< factor monomial */
6899  int* childmap /**< map to apply to children in factor, or NULL for 1:1 */
6900  )
6901 {
6902  assert(monomial != NULL);
6903  assert(factor != NULL);
6904 
6905  if( factor->coef == 0.0 )
6906  {
6907  monomial->nfactors = 0;
6908  monomial->coef = 0.0;
6909  return SCIP_OKAY;
6910  }
6911 
6912  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, factor->nfactors, factor->childidxs, factor->exponents) );
6913 
6914  if( childmap != NULL )
6915  {
6916  int i;
6917  for( i = monomial->nfactors - factor->nfactors; i < monomial->nfactors; ++i )
6918  monomial->childidxs[i] = childmap[monomial->childidxs[i]];
6919  }
6920 
6921  monomial->coef *= factor->coef;
6922 
6923  return SCIP_OKAY;
6924 }
6925 
6926 /** replaces the monomial by a power of the monomial
6927  *
6928  * Allows only integers as exponent.
6929  */
6931  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6932  int exponent /**< integer exponent of power operation */
6933  )
6934 {
6935  int i;
6936 
6937  assert(monomial != NULL);
6938 
6939  if( exponent == 1 )
6940  return;
6941 
6942  if( exponent == 0 )
6943  {
6944  /* x^0 = 1, unless x = 0; 0^0 = 0 */
6945  if( monomial->coef != 0.0 )
6946  monomial->coef = 1.0;
6947  monomial->nfactors = 0;
6948  return;
6949  }
6950 
6951  monomial->coef = pow(monomial->coef, (SCIP_Real)exponent);
6952  for( i = 0; i < monomial->nfactors; ++i )
6953  monomial->exponents[i] *= exponent;
6954 }
6955 
6956 /** merges factors that correspond to the same child by adding exponents
6957  *
6958  * Eliminates factors with exponent between -eps and eps.
6959  */
6961  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6962  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6963  )
6964 {
6965  int i;
6966  int offset;
6967 
6968  assert(monomial != NULL);
6969  assert(eps >= 0.0);
6970 
6971  SCIPexprSortMonomialFactors(monomial);
6972 
6973  /* merge factors with same child index by adding up their exponents
6974  * delete factors with exponent 0.0 */
6975  offset = 0;
6976  i = 0;
6977  while( i + offset < monomial->nfactors )
6978  {
6979  if( offset > 0 )
6980  {
6981  assert(monomial->childidxs[i] == -1);
6982  assert(monomial->childidxs[i+offset] >= 0);
6983  monomial->childidxs[i] = monomial->childidxs[i+offset];
6984  monomial->exponents[i] = monomial->exponents[i+offset];
6985 #ifndef NDEBUG
6986  monomial->childidxs[i+offset] = -1;
6987 #endif
6988  }
6989 
6990  while( i+offset+1 < monomial->nfactors && monomial->childidxs[i] == monomial->childidxs[i+offset+1] )
6991  {
6992  monomial->exponents[i] += monomial->exponents[i+offset+1];
6993 #ifndef NDEBUG
6994  monomial->childidxs[i+offset+1] = -1;
6995 #endif
6996  ++offset;
6997  }
6998 
6999  if( EPSZ(monomial->exponents[i], eps) )
7000  {
7001 #ifndef NDEBUG
7002  monomial->childidxs[i] = -1;
7003 #endif
7004  ++offset;
7005  continue;
7006  }
7007  else if( EPSISINT(monomial->exponents[i], eps) )
7008  monomial->exponents[i] = EPSROUND(monomial->exponents[i], eps);
7009 
7010  ++i;
7011  }
7012 
7013 #ifndef NDEBUG
7014  for( ; i < monomial->nfactors; ++i )
7015  assert(monomial->childidxs[i] == -1);
7016 #endif
7017 
7018  monomial->nfactors -= offset;
7019 
7020  if( EPSEQ(monomial->coef, 1.0, eps) )
7021  monomial->coef = 1.0;
7022  else if( EPSEQ(monomial->coef, -1.0, eps) )
7023  monomial->coef = -1.0;
7024 }
7025 
7026 /** ensures that monomials of a polynomial are sorted */
7028  SCIP_EXPR* expr /**< polynomial expression */
7029  )
7030 {
7031  assert(expr != NULL);
7032  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
7033  assert(expr->data.data != NULL);
7034 
7036 }
7037 
7038 /** creates a monomial */
7040  BMS_BLKMEM* blkmem, /**< block memory */
7041  SCIP_EXPRDATA_MONOMIAL** monomial, /**< buffer where to store pointer to new monomial */
7042  SCIP_Real coef, /**< coefficient of monomial */
7043  int nfactors, /**< number of factors in monomial */
7044  int* childidxs, /**< indices of children corresponding to factors, or NULL if identity */
7045  SCIP_Real* exponents /**< exponent in each factor, or NULL if all 1.0 */
7046  )
7047 {
7048  assert(blkmem != NULL);
7049  assert(monomial != NULL);
7050 
7051  SCIP_ALLOC( BMSallocBlockMemory(blkmem, monomial) );
7052 
7053  (*monomial)->coef = coef;
7054  (*monomial)->nfactors = nfactors;
7055  (*monomial)->factorssize = nfactors;
7056  (*monomial)->sorted = (nfactors <= 1);
7057 
7058  if( nfactors > 0 )
7059  {
7060  if( childidxs != NULL )
7061  {
7062  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->childidxs, childidxs, nfactors) );
7063  }
7064  else
7065  {
7066  int i;
7067 
7068  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->childidxs, nfactors) );
7069  for( i = 0; i < nfactors; ++i )
7070  (*monomial)->childidxs[i] = i;
7071  }
7072 
7073  if( exponents != NULL )
7074  {
7075  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->exponents, exponents, nfactors) );
7076  }
7077  else
7078  {
7079  int i;
7080 
7081  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->exponents, nfactors) );
7082  for( i = 0; i < nfactors; ++i )
7083  (*monomial)->exponents[i] = 1.0;
7084  }
7085  }
7086  else
7087  {
7088  (*monomial)->childidxs = NULL;
7089  (*monomial)->exponents = NULL;
7090  }
7091 
7092  return SCIP_OKAY;
7093 }
7094 
7095 /** frees a monomial */
7097  BMS_BLKMEM* blkmem, /**< block memory */
7098  SCIP_EXPRDATA_MONOMIAL** monomial /**< pointer to monomial that should be freed */
7099  )
7100 {
7101  assert(blkmem != NULL);
7102  assert( monomial != NULL);
7103  assert(*monomial != NULL);
7104 
7105  if( (*monomial)->factorssize > 0 )
7106  {
7107  assert((*monomial)->childidxs != NULL);
7108  assert((*monomial)->exponents != NULL);
7109 
7110  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->childidxs, (*monomial)->factorssize);
7111  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->exponents, (*monomial)->factorssize);
7112  }
7113  assert((*monomial)->childidxs == NULL);
7114  assert((*monomial)->exponents == NULL);
7115 
7116  BMSfreeBlockMemory(blkmem, monomial);
7117 }
7118 
7119 /** ensures that factors in a monomial are sorted */
7121  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
7122  )
7123 {
7124  assert(monomial != NULL);
7125 
7126  if( monomial->sorted )
7127  return;
7128 
7129  if( monomial->nfactors > 0 )
7130  SCIPsortIntReal(monomial->childidxs, monomial->exponents, monomial->nfactors);
7131 
7132  monomial->sorted = TRUE;
7133 }
7134 
7135 /** finds a factor corresponding to a given child index in a monomial
7136  *
7137  * Note that if the factors have not been merged, the position of some factor corresponding to a given child is given.
7138  * Returns TRUE if a factor is found, FALSE if not.
7139  */
7141  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
7142  int childidx, /**< index of the child which factor to search for */
7143  int* pos /**< buffer to store position of factor */
7144  )
7145 {
7146  assert(monomial != NULL);
7147 
7148  if( monomial->nfactors == 0 )
7149  return FALSE;
7150 
7151  SCIPexprSortMonomialFactors(monomial);
7152 
7153  return SCIPsortedvecFindInt(monomial->childidxs, childidx, monomial->nfactors, pos);
7154 }
7155 
7156 /** creates a user expression */
7158  BMS_BLKMEM* blkmem, /**< block memory data structure */
7159  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
7160  int nchildren, /**< number of children */
7161  SCIP_EXPR** children, /**< children of expression */
7162  SCIP_USEREXPRDATA* data, /**< user data for expression, expression assumes ownership */
7163  SCIP_EXPRINTCAPABILITY evalcapability, /**< capability of evaluation functions (partially redundant, currently) */
7164  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
7165  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function, or NULL if not implemented */
7166  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
7167  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function, or NULL if not implemented */
7168  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
7169  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
7170  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
7171  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
7172  )
7173 {
7174  SCIP_EXPROPDATA opdata;
7175  SCIP_EXPRDATA_USER* userexprdata;
7176  SCIP_EXPR** childrencopy;
7177 
7178  assert(blkmem != NULL);
7179  assert(expr != NULL);
7180  assert(eval != NULL);
7181  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
7182  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
7183  assert(curv != NULL);
7184  assert(copydata != NULL || data == NULL);
7185  assert(freedata != NULL || data == NULL);
7186 
7187  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &userexprdata) );
7188 
7189  userexprdata->userdata = data;
7190  userexprdata->evalcapability = evalcapability;
7191  userexprdata->eval = eval;
7192  userexprdata->inteval = inteval;
7193  userexprdata->curv = curv;
7194  userexprdata->prop = prop;
7195  userexprdata->estimate = estimate;
7196  userexprdata->copydata = copydata;
7197  userexprdata->freedata = freedata;
7198  userexprdata->print = print;
7199 
7200  opdata.data = (void*) userexprdata;
7201 
7202  if( nchildren == 0 )
7203  {
7204  SCIP_CALL( exprCreate(blkmem, expr, SCIP_EXPR_USER, 0, NULL, opdata) );
7205  return SCIP_OKAY;
7206  }
7207  assert(children != NULL);
7208 
7209  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
7210 
7211  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_USER, nchildren, childrencopy, opdata) );
7212 
7213  return SCIP_OKAY;
7214 }
7215 
7216 /** indicates whether the expression contains a SCIP_EXPR_PARAM */
7218  SCIP_EXPR* expr /**< expression */
7219  )
7220 {
7221  int i;
7222 
7223  assert(expr != NULL);
7224 
7225  if( expr->op == SCIP_EXPR_PARAM )
7226  return TRUE;
7227 
7228  for( i = 0; i < expr->nchildren; ++i )
7229  if( SCIPexprHasParam(expr->children[i]) )
7230  return TRUE;
7231 
7232  return FALSE;
7233 }
7234 
7235 /** gets maximal degree of expression, or SCIP_EXPR_DEGREEINFINITY if not a polynomial */
7237  SCIP_EXPR* expr, /**< expression */
7238  int* maxdegree /**< buffer to store maximal degree */
7239  )
7240 {
7241  int child1;
7242  int child2;
7243 
7244  assert(expr != NULL);
7245  assert(maxdegree != NULL);
7246 
7247  switch( expr->op )
7248  {
7249  case SCIP_EXPR_VARIDX:
7250  *maxdegree = 1;
7251  break;
7252 
7253  case SCIP_EXPR_CONST:
7254  case SCIP_EXPR_PARAM:
7255  *maxdegree = 0;
7256  break;
7257 
7258  case SCIP_EXPR_PLUS:
7259  case SCIP_EXPR_MINUS:
7260  {
7261  assert(expr->children[0] != NULL);
7262  assert(expr->children[1] != NULL);
7263 
7264  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7265  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7266 
7267  *maxdegree = MAX(child1, child2);
7268  break;
7269  }
7270 
7271  case SCIP_EXPR_MUL:
7272  {
7273  assert(expr->children[0] != NULL);
7274  assert(expr->children[1] != NULL);
7275 
7276  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7277  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7278 
7279  *maxdegree = child1 + child2;
7280  break;
7281  }
7282 
7283  case SCIP_EXPR_DIV:
7284  {
7285  assert(expr->children[0] != NULL);
7286  assert(expr->children[1] != NULL);
7287 
7288  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7289  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7290 
7291  /* if not division by constant, then it is not a polynomial */
7292  *maxdegree = (child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : child1;
7293  break;
7294  }
7295 
7296  case SCIP_EXPR_SQUARE:
7297  {
7298  assert(expr->children[0] != NULL);
7299 
7300  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7301 
7302  *maxdegree = 2 * child1;
7303  break;
7304  }
7305 
7306  case SCIP_EXPR_SQRT:
7307  {
7308  assert(expr->children[0] != NULL);
7309 
7310  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7311 
7312  /* if not squareroot of constant, then no polynomial */
7313  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7314  break;
7315  }
7316 
7317  case SCIP_EXPR_REALPOWER:
7318  {
7319  assert(expr->children[0] != NULL);
7320 
7321  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7322 
7323  /* constant ^ constant has degree 0 */
7324  if( child1 == 0 )
7325  {
7326  *maxdegree = 0;
7327  break;
7328  }
7329 
7330  /* non-polynomial ^ constant is not a polynomial */
7331  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7332  {
7333  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7334  break;
7335  }
7336 
7337  /* so it is polynomial ^ constant
7338  * let's see whether the constant is integral */
7339 
7340  if( expr->data.dbl == 0.0 ) /* polynomial ^ 0 == 0 */
7341  *maxdegree = 0;
7342  else if( expr->data.dbl > 0.0 && (int)expr->data.dbl == expr->data.dbl ) /* natural exponent gives polynomial again */ /*lint !e777*/
7343  *maxdegree = child1 * (int)expr->data.dbl;
7344  else /* negative or nonintegral exponent does not give polynomial */
7345  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7346 
7347  break;
7348  }
7349 
7350  case SCIP_EXPR_INTPOWER:
7351  {
7352  assert(expr->children[0] != NULL);
7353 
7354  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7355 
7356  /* constant ^ integer or something ^ 0 has degree 0 */
7357  if( child1 == 0 || expr->data.intval == 0 )
7358  {
7359  *maxdegree = 0;
7360  break;
7361  }
7362 
7363  /* non-polynomial ^ integer or something ^ negative is not a polynomial */
7364  if( child1 >= SCIP_EXPR_DEGREEINFINITY || expr->data.intval < 0 )
7365  {
7366  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7367  break;
7368  }
7369 
7370  /* so it is polynomial ^ natural, which gives a polynomial again */
7371  *maxdegree = child1 * expr->data.intval;
7372 
7373  break;
7374  }
7375 
7376  case SCIP_EXPR_SIGNPOWER:
7377  {
7378  assert(expr->children[0] != NULL);
7379 
7380  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7381 
7382  /* if child is not constant, then it is no polynomial */
7383  *maxdegree = child1 != 0 ? SCIP_EXPR_DEGREEINFINITY : 0;
7384  break;
7385  }
7386 
7387  case SCIP_EXPR_EXP:
7388  case SCIP_EXPR_LOG:
7389  case SCIP_EXPR_SIN:
7390  case SCIP_EXPR_COS:
7391  case SCIP_EXPR_TAN:
7392  /* case SCIP_EXPR_ERF: */
7393  /* case SCIP_EXPR_ERFI: */
7394  case SCIP_EXPR_ABS:
7395  case SCIP_EXPR_SIGN:
7396  case SCIP_EXPR_USER:
7397  {
7398  assert(expr->children[0] != NULL);
7399 
7400  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7401 
7402  /* if argument is not a constant, then no polynomial, otherwise it is a constant */
7403  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7404  break;
7405  }
7406 
7407  case SCIP_EXPR_MIN:
7408  case SCIP_EXPR_MAX:
7409  {
7410  assert(expr->children[0] != NULL);
7411  assert(expr->children[1] != NULL);
7412 
7413  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7414  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7415 
7416  /* if any of the operands is not constant, then it is no polynomial */
7417  *maxdegree = (child1 != 0 || child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7418  break;
7419  }
7420 
7421  case SCIP_EXPR_SUM:
7422  case SCIP_EXPR_LINEAR:
7423  {
7424  int i;
7425 
7426  *maxdegree = 0;
7427  for( i = 0; i < expr->nchildren && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7428  {
7429  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7430  if( child1 > *maxdegree )
7431  *maxdegree = child1;
7432  }
7433 
7434  break;
7435  }
7436 
7437  case SCIP_EXPR_PRODUCT:
7438  {
7439  int i;
7440 
7441  *maxdegree = 0;
7442  for( i = 0; i < expr->nchildren; ++i )
7443  {
7444  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7445  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7446  {
7447  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7448  break;
7449  }
7450  *maxdegree += child1;
7451  }
7452 
7453  break;
7454  }
7455 
7456  case SCIP_EXPR_QUADRATIC:
7457  {
7458  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7459  int childidx;
7460  int quadidx;
7461 
7462  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7463 
7464  /* make sure quadratic elements are sorted */
7465  quadraticdataSort(quadraticdata);
7466 
7467  *maxdegree = 0;
7468  quadidx = 0;
7469  for( childidx = 0; childidx < expr->nchildren; ++childidx )
7470  {
7471  /* if no linear or no quadratic coefficient with current child on first position, then nothing to do */
7472  if( (quadraticdata->lincoefs == NULL || quadraticdata->lincoefs[childidx] == 0.0) &&
7473  (quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 > childidx) )
7474  continue;
7475 
7476  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[childidx], &child1) );
7477  if( child1 == SCIP_EXPR_DEGREEINFINITY )
7478  {
7479  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7480  break;
7481  }
7482 
7483  while( quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 == childidx )
7484  {
7485  if( quadraticdata->quadelems[quadidx].idx2 == childidx )
7486  {
7487  /* square term */
7488  if( 2*child1 > *maxdegree )
7489  *maxdegree = 2*child1;
7490  }
7491  else
7492  {
7493  /* bilinear term */
7494  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[quadraticdata->quadelems[quadidx].idx2], &child2) );
7495  if( child2 == SCIP_EXPR_DEGREEINFINITY )
7496  {
7497  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7498  break;
7499  }
7500  if( child1 + child2 > *maxdegree )
7501  *maxdegree = child1 + child2;
7502  }
7503  ++quadidx;
7504  }
7505  if( *maxdegree == SCIP_EXPR_DEGREEINFINITY )
7506  break;
7507  }
7508 
7509  break;
7510  }
7511 
7512  case SCIP_EXPR_POLYNOMIAL:
7513  {
7514  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7515  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7516  int monomialdegree;
7517  int i;
7518  int j;
7519 
7520  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7521 
7522  *maxdegree = 0;
7523  for( i = 0; i < polynomialdata->nmonomials && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7524  {
7525  monomialdata = polynomialdata->monomials[i];
7526  assert(monomialdata != NULL);
7527 
7528  /* compute degree of monomial = sum of degree of factors */
7529  monomialdegree = 0;
7530  for( j = 0; j < monomialdata->nfactors; ++j )
7531  {
7532  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[monomialdata->childidxs[j]], &child1) );
7533 
7534  /* if the exponent of the factor is not a natural number and the child is not constant (degree 0),
7535  * then we report that we are not really a polynomial */
7536  if( child1 != 0 && (monomialdata->exponents[j] < 0.0 || (int)monomialdata->exponents[j] != monomialdata->exponents[j]) )
7537  {
7538  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7539  break;
7540  }
7541 
7542  monomialdegree += child1 * (int)monomialdata->exponents[j];
7543  }
7544 
7545  if( monomialdegree > *maxdegree )
7546  *maxdegree = monomialdegree;
7547  }
7548 
7549  break;
7550  }
7551 
7552  case SCIP_EXPR_LAST:
7553  SCIPABORT();
7554  break;
7555  }
7556 
7557  return SCIP_OKAY;
7558 }
7559 
7560 /** counts usage of variables in expression */
7562  SCIP_EXPR* expr, /**< expression to update */
7563  int* varsusage /**< array with counters of variable usage */
7564  )
7565 {
7566  int i;
7567 
7568  assert(expr != NULL);
7569  assert(varsusage != NULL);
7570 
7571  if( expr->op == SCIP_EXPR_VARIDX )
7572  {
7573  ++varsusage[expr->data.intval];
7574  }
7575 
7576  for( i = 0; i < expr->nchildren; ++i )
7577  SCIPexprGetVarsUsage(expr->children[i], varsusage);
7578 }
7579 
7580 /** compares whether two expressions are the same
7581  *
7582  * Inconclusive, i.e., may give FALSE even if expressions are equivalent (x*y != y*x).
7583  */
7585  SCIP_EXPR* expr1, /**< first expression */
7586  SCIP_EXPR* expr2, /**< second expression */
7587  SCIP_Real eps /**< threshold under which numbers are assumed to be zero */
7588  )
7589 {
7590  assert(expr1 != NULL);
7591  assert(expr2 != NULL);
7592 
7593  if( expr1 == expr2 )
7594  return TRUE;
7595 
7596  if( expr1->op != expr2->op )
7597  return FALSE;
7598 
7599  switch( expr1->op )
7600  {
7601  case SCIP_EXPR_VARIDX:
7602  case SCIP_EXPR_PARAM:
7603  return expr1->data.intval == expr2->data.intval;
7604 
7605  case SCIP_EXPR_CONST:
7606  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps);
7607 
7608  /* operands with two children */
7609  case SCIP_EXPR_PLUS :
7610  case SCIP_EXPR_MINUS :
7611  case SCIP_EXPR_MUL :
7612  case SCIP_EXPR_DIV :
7613  case SCIP_EXPR_MIN :
7614  case SCIP_EXPR_MAX :
7615  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps) && SCIPexprAreEqual(expr1->children[1], expr2->children[1], eps);
7616 
7617  /* operands with one child */
7618  case SCIP_EXPR_SQUARE:
7619  case SCIP_EXPR_SQRT :
7620  case SCIP_EXPR_EXP :
7621  case SCIP_EXPR_LOG :
7622  case SCIP_EXPR_SIN :
7623  case SCIP_EXPR_COS :
7624  case SCIP_EXPR_TAN :
7625  /* case SCIP_EXPR_ERF : */
7626  /* case SCIP_EXPR_ERFI : */
7627  case SCIP_EXPR_ABS :
7628  case SCIP_EXPR_SIGN :
7629  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7630 
7631  case SCIP_EXPR_REALPOWER:
7632  case SCIP_EXPR_SIGNPOWER:
7633  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps) && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7634 
7635  case SCIP_EXPR_INTPOWER:
7636  return expr1->data.intval == expr2->data.intval && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7637 
7638  /* complex operands */
7639  case SCIP_EXPR_SUM :
7640  case SCIP_EXPR_PRODUCT:
7641  {
7642  int i;
7643 
7644  /* @todo sort children and have sorted flag in data? */
7645 
7646  if( expr1->nchildren != expr2->nchildren )
7647  return FALSE;
7648 
7649  for( i = 0; i < expr1->nchildren; ++i )
7650  {
7651  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7652  return FALSE;
7653  }
7654 
7655  return TRUE;
7656  }
7657 
7658  case SCIP_EXPR_LINEAR :
7659  {
7660  SCIP_Real* data1;
7661  SCIP_Real* data2;
7662  int i;
7663 
7664  /* @todo sort children and have sorted flag in data? */
7665 
7666  if( expr1->nchildren != expr2->nchildren )
7667  return FALSE;
7668 
7669  data1 = (SCIP_Real*)expr1->data.data;
7670  data2 = (SCIP_Real*)expr2->data.data;
7671 
7672  /* check if constant and coefficients are equal */
7673  for( i = 0; i < expr1->nchildren + 1; ++i )
7674  if( !EPSEQ(data1[i], data2[i], eps) )
7675  return FALSE;
7676 
7677  /* check if children are equal */
7678  for( i = 0; i < expr1->nchildren; ++i )
7679  {
7680  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7681  return FALSE;
7682  }
7683 
7684  return TRUE;
7685  }
7686 
7687  case SCIP_EXPR_QUADRATIC:
7688  {
7689  SCIP_EXPRDATA_QUADRATIC* data1;
7690  SCIP_EXPRDATA_QUADRATIC* data2;
7691  int i;
7692 
7693  if( expr1->nchildren != expr2->nchildren )
7694  return FALSE;
7695 
7696  data1 = (SCIP_EXPRDATA_QUADRATIC*)expr1->data.data;
7697  data2 = (SCIP_EXPRDATA_QUADRATIC*)expr2->data.data;
7698 
7699  if( data1->nquadelems != data2->nquadelems )
7700  return FALSE;
7701 
7702  if( !EPSEQ(data1->constant, data2->constant, eps) )
7703  return FALSE;
7704 
7705  /* check if linear part is equal */
7706  if( data1->lincoefs != NULL || data2->lincoefs != NULL )
7707  for( i = 0; i < expr1->nchildren; ++i )
7708  {
7709  if( data1->lincoefs == NULL )
7710  {
7711  if( !EPSZ(data2->lincoefs[i], eps) )
7712  return FALSE;
7713  }
7714  else if( data2->lincoefs == NULL )
7715  {
7716  if( !EPSZ(data1->lincoefs[i], eps) )
7717  return FALSE;
7718  }
7719  else if( !EPSEQ(data1->lincoefs[i], data2->lincoefs[i], eps) )
7720  return FALSE;
7721  }
7722 
7723  SCIPexprSortQuadElems(expr1);
7724  SCIPexprSortQuadElems(expr2);
7725 
7726  /* check if quadratic elements are equal */
7727  for( i = 0; i < data1->nquadelems; ++i )
7728  if( data1->quadelems[i].idx1 != data2->quadelems[i].idx1 ||
7729  data1->quadelems[i].idx2 != data2->quadelems[i].idx2 ||
7730  !EPSEQ(data1->quadelems[i].coef, data2->quadelems[i].coef, eps) )
7731  return FALSE;
7732 
7733  /* check if children are equal */
7734  for( i = 0; i < expr1->nchildren; ++i )
7735  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7736  return FALSE;
7737 
7738  return TRUE;
7739  }
7740 
7741  case SCIP_EXPR_POLYNOMIAL:
7742  {
7743  SCIP_EXPRDATA_POLYNOMIAL* data1;
7744  SCIP_EXPRDATA_POLYNOMIAL* data2;
7745  int i;
7746 
7747  if( expr1->nchildren != expr2->nchildren )
7748  return FALSE;
7749 
7750  data1 = (SCIP_EXPRDATA_POLYNOMIAL*)expr1->data.data;
7751  data2 = (SCIP_EXPRDATA_POLYNOMIAL*)expr2->data.data;
7752 
7753  if( data1->nmonomials != data2->nmonomials )
7754  return FALSE;
7755 
7756  if( !EPSEQ(data1->constant, data2->constant, eps) )
7757  return FALSE;
7758 
7759  /* make sure polynomials are sorted */
7760  SCIPexprSortMonomials(expr1);
7761  SCIPexprSortMonomials(expr2);
7762 
7763  /* check if monomials are equal */
7764  for( i = 0; i < data1->nmonomials; ++i )
7765  {
7766  if( !SCIPexprAreMonomialsEqual(data1->monomials[i], data2->monomials[i], eps) )
7767  return FALSE;
7768  }
7769 
7770  /* check if children are equal */
7771  for( i = 0; i < expr1->nchildren; ++i )
7772  {
7773  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7774  return FALSE;
7775  }
7776 
7777  return TRUE;
7778  }
7779 
7780  case SCIP_EXPR_USER:
7781  {
7782  /* @todo could implement this via another user callback */
7783  return FALSE;
7784  }
7785 
7786  case SCIP_EXPR_LAST:
7787  break;
7788  }
7789 
7790  SCIPerrorMessage("this should never happen\n");
7791  SCIPABORT();
7792  return FALSE; /*lint !e527*/
7793 }
7794 
7795 /** aims at simplifying an expression and splitting of a linear expression
7796  *
7797  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
7798  */
7800  BMS_BLKMEM* blkmem, /**< block memory data structure */
7801  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7802  SCIP_EXPR* expr, /**< expression */
7803  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
7804  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
7805  int nvars, /**< number of variables in expression */
7806  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
7807  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
7808  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
7809  )
7810 {
7811  assert(blkmem != NULL);
7812  assert(expr != NULL);
7813  assert(eps >= 0.0);
7814 
7815  SCIPdebugMessage("simplify expression: ");
7816  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7817  SCIPdebugPrintf("\n");
7818 
7820 
7821  SCIPdebugMessage("converted to polynomials: ");
7822  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7823  SCIPdebugPrintf("\n");
7824 
7825  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr, eps, maxexpansionexponent) );
7826 
7827  SCIPdebugMessage("polynomials flattened: ");
7828  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7829  SCIPdebugPrintf("\n");
7830 
7831  if( nlinvars != NULL )
7832  {
7833  /* separate linear part from root polynomial */
7834  SCIP_CALL( exprsimplifySeparateLinearFromPolynomial(blkmem, expr, eps, nvars, nlinvars, linidxs, lincoefs) );
7835 
7836  SCIPdebugMessage("separated linear part: ");
7837  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7838  SCIPdebugPrintf("\n");
7839  }
7840 
7842 
7843  SCIPdebugMessage("converted back from polynomials: ");
7844  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7845  SCIPdebugPrintf("\n");
7846 
7847  return SCIP_OKAY;
7848 }
7849 
7850 /** evaluates an expression w.r.t. given values for children expressions */
7852  SCIP_EXPR* expr, /**< expression */
7853  SCIP_Real* argvals, /**< values for children, can be NULL if the expression has no children */
7854  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression operand is not a variable */
7855  SCIP_Real* param, /**< values for parameters, can be NULL if the expression operand is not a parameter */
7856  SCIP_Real* val /**< buffer to store value */
7857  )
7858 {
7859  assert(expr != NULL);
7860  assert(argvals != NULL || expr->nchildren == 0);
7861 
7862  /* evaluate this expression */
7863  assert( exprOpTable[expr->op].eval != NULL );
7864  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, argvals, varvals, param, val) );
7865 
7866  return SCIP_OKAY;
7867 }
7868 
7869 /** evaluates an expression w.r.t. a point */
7871  SCIP_EXPR* expr, /**< expression */
7872  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression is constant */
7873  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7874  SCIP_Real* val /**< buffer to store value */
7875  )
7876 {
7877  int i;
7879  SCIP_Real* buf;
7880 
7881  /* if many children, get large enough memory to store argument values */
7883  {
7884  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7885  }
7886  else
7887  {
7888  buf = staticbuf;
7889  }
7890 
7891  /* evaluate children */
7892  for( i = 0; i < expr->nchildren; ++i )
7893  {
7894  SCIP_CALL( SCIPexprEval(expr->children[i], varvals, param, &buf[i]) ); /*lint !e644*/
7895  }
7896 
7897  /* evaluate this expression */
7898  assert( exprOpTable[expr->op].eval != NULL );
7899  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, buf, varvals, param, val) );
7900 
7901  /* free memory, if allocated before */
7902  if( staticbuf != buf )
7903  {
7904  BMSfreeMemoryArray(&buf);
7905  }
7906 
7907  return SCIP_OKAY;
7908 }
7909 
7910 /** evaluates an expression w.r.t. given interval values for children expressions */
7912  SCIP_EXPR* expr, /**< expression */
7913  SCIP_Real infinity, /**< value to use for infinity */
7914  SCIP_INTERVAL* argvals, /**< interval values for children, can be NULL if the expression has no children */
7915  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7916  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7917  SCIP_INTERVAL* val /**< buffer to store value */
7918  )
7919 {
7920  assert(expr != NULL);
7921  assert(argvals != NULL || expr->nchildren == 0);
7922 
7923  /* evaluate this expression */
7924  assert( exprOpTable[expr->op].inteval != NULL );
7925  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, argvals, varvals, param, val) );
7926 
7927  return SCIP_OKAY;
7928 }
7929 
7930 /** evaluates an expression w.r.t. an interval */
7932  SCIP_EXPR* expr, /**< expression */
7933  SCIP_Real infinity, /**< value to use for infinity */
7934  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7935  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7936  SCIP_INTERVAL* val /**< buffer to store value */
7937  )
7938 {
7939  int i;
7941  SCIP_INTERVAL* buf;
7942 
7943  /* if many children, get large enough memory to store argument values */
7945  {
7946  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7947  }
7948  else
7949  {
7950  buf = staticbuf;
7951  }
7952 
7953  /* evaluate children */
7954  for( i = 0; i < expr->nchildren; ++i )
7955  {
7956  SCIP_CALL( SCIPexprEvalInt(expr->children[i], infinity, varvals, param, &buf[i]) ); /*lint !e644*/
7957  }
7958 
7959  /* evaluate this expression */
7960  assert( exprOpTable[expr->op].inteval != NULL );
7961  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, buf, varvals, param, val) );
7962 
7963  /* free memory, if allocated before */
7964  if( staticbuf != buf )
7965  {
7966  BMSfreeMemoryArray(&buf);
7967  }
7968 
7969  return SCIP_OKAY;
7970 }
7971 
7972 /** evaluates a user expression w.r.t. given values for children expressions */
7974  SCIP_EXPR* expr, /**< expression */
7975  SCIP_Real* argvals, /**< values for children */
7976  SCIP_Real* val, /**< buffer to store function value */
7977  SCIP_Real* gradient, /**< buffer to store gradient values, or NULL if not requested */
7978  SCIP_Real* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7979  )
7980 {
7981  SCIP_EXPRDATA_USER* exprdata;
7982 
7983  assert(expr != NULL);
7984  assert(expr->op == SCIP_EXPR_USER);
7985  assert(argvals != NULL || expr->nchildren == 0);
7986 
7987  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7988  assert(exprdata->eval != NULL);
7989 
7990  SCIP_CALL( exprdata->eval(exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7991 
7992  return SCIP_OKAY;
7993 }
7994 
7995 /** evaluates a user expression w.r.t. an interval */
7997  SCIP_EXPR* expr, /**< expression */
7998  SCIP_Real infinity, /**< value to use for infinity */
7999  SCIP_INTERVAL* argvals, /**< values for children */
8000  SCIP_INTERVAL* val, /**< buffer to store value */
8001  SCIP_INTERVAL* gradient, /**< buffer to store gradient values, or NULL if not requested */
8002  SCIP_INTERVAL* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
8003  )
8004 {
8005  SCIP_EXPRDATA_USER* exprdata;
8006 
8007  assert(expr != NULL);
8008  assert(expr->op == SCIP_EXPR_USER);
8009  assert(argvals != NULL || expr->nchildren == 0);
8010 
8011  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8012 
8013  if( exprdata->inteval == NULL )
8014  {
8015  int i;
8016 
8017  for( i = 0; i < expr->nchildren; ++i )
8018  SCIPintervalSetEntire(infinity, &argvals[i]); /*lint !e613*/
8019  }
8020  else
8021  {
8022  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
8023  }
8024 
8025  return SCIP_OKAY;
8026 }
8027 
8028 /** internal curvature check method */
8029 static
8031  SCIP_EXPR* expr, /**< expression to check */
8032  SCIP_Real infinity, /**< value to use for infinity */
8033  SCIP_INTERVAL* varbounds, /**< domains of variables */
8034  SCIP_INTERVAL* childbounds, /**< child bounds buffer array */
8035  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
8036  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8037  SCIP_EXPRCURV* childcurv, /**< buffer array for curvature of children */
8038  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
8039  )
8040 {
8041  int i;
8042 
8043  assert(childbounds != NULL);
8044  assert(childcurv != NULL);
8045 
8046  /* check curvature and compute bounds of children
8047  * constant children can be considered as always linear */
8048  for( i = 0; i < expr->nchildren; ++i )
8049  {
8050  SCIP_CALL( SCIPexprCheckCurvature(expr->children[i], infinity, varbounds, param, &childcurv[i], &childbounds[i]) ); /*lint !e644*/
8051  if( childbounds[i].inf == childbounds[i].sup ) /*lint !e777*/
8052  childcurv[i] = SCIP_EXPRCURV_LINEAR;
8053  }
8054 
8055  /* get curvature and bounds of expr */
8056  assert(exprOpTable[expr->op].curv != NULL);
8057  assert(exprOpTable[expr->op].inteval != NULL);
8058 
8059  SCIP_CALL( exprOpTable[expr->op].curv(infinity, expr->data, expr->nchildren, childbounds, childcurv, curv) );
8060  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, childbounds, varbounds, param, bounds) );
8061 
8062  return SCIP_OKAY;
8063 }
8064 
8065 /** tries to determine the curvature type of an expression w.r.t. given variable domains */
8067  SCIP_EXPR* expr, /**< expression to check */
8068  SCIP_Real infinity, /**< value to use for infinity */
8069  SCIP_INTERVAL* varbounds, /**< domains of variables */
8070  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
8071  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8072  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
8073  )
8074 {
8076  SCIP_INTERVAL* childbounds = NULL;
8078  SCIP_EXPRCURV* childcurv = NULL;
8079  SCIP_RETCODE retcode = SCIP_OKAY;
8080 
8081  assert(expr != NULL);
8082  assert(curv != NULL);
8083  assert(bounds != NULL);
8084 
8085  /* if many children, get large enough memory to store argument values */
8087  {
8088  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, expr->nchildren) );
8089  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, expr->nchildren), TERMINATE );
8090  }
8091  else
8092  {
8093  childbounds = childboundsbuf;
8094  childcurv = childcurvbuf;
8095  }
8096 
8097  retcode = doCheckCurvature(expr, infinity, varbounds, childbounds, param, curv, childcurv, bounds);
8098 
8099 TERMINATE:
8100  /* free memory, if allocated before */
8101  if( childboundsbuf != childbounds )
8102  {
8103  BMSfreeMemoryArrayNull(&childcurv);
8104  BMSfreeMemoryArrayNull(&childbounds);
8105  }
8106 
8107  return retcode;
8108 }
8109 
8110 /** under-/overestimates a user expression w.r.t. to given values and bounds for children expressions */
8112  SCIP_EXPR* expr, /**< expression */
8113  SCIP_Real infinity, /**< value to use for infinity */
8114  SCIP_Real* argvals, /**< values for children */
8115  SCIP_INTERVAL* argbounds, /**< bounds for children */
8116  SCIP_Bool overestimate, /**< whether to overestimate the expression */
8117  SCIP_Real* coeffs, /**< buffer to store the linear coefficients for each child expression that gives a valid under-/overestimator */
8118  SCIP_Real* constant, /**< buffer to store the constant value of the linear under-/overestimator */
8119  SCIP_Bool* success /**< buffer to store whether an estimator was successfully computed */
8120  )
8121 {
8122  SCIP_EXPRDATA_USER* exprdata;
8123 
8124  assert(expr != NULL);
8125  assert(expr->op == SCIP_EXPR_USER);
8126  assert(argvals != NULL || expr->nchildren == 0);
8127  assert(argbounds != NULL || expr->nchildren == 0);
8128 
8129  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8130 
8131  if( exprdata->estimate != NULL )
8132  {
8133  SCIP_CALL( exprdata->estimate(infinity, exprdata->userdata, expr->nchildren, argvals, argbounds, overestimate, coeffs, constant, success ) );
8134  }
8135  else
8136  {
8137  *success = FALSE;
8138  }
8139 
8140  return SCIP_OKAY;
8141 }
8142 
8143 /** substitutes variables (SCIP_EXPR_VARIDX) by expressions
8144  *
8145  * Note that only the children of the given expr are checked!
8146  * A variable with index i is replaced by a copy of substexprs[i], if the latter is not NULL.
8147  * If substexprs[i] == NULL, then the variable expression i is not touched.
8148  */
8150  BMS_BLKMEM* blkmem, /**< block memory data structure */
8151  SCIP_EXPR* expr, /**< expression, which of the children may be replaced */
8152  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8153  )
8154 {
8155  int i;
8156 
8157  assert(blkmem != NULL);
8158  assert(expr != NULL);
8159  assert(substexprs != NULL);
8160 
8161  for( i = 0; i < expr->nchildren; ++i )
8162  {
8163  if( expr->children[i]->op == SCIP_EXPR_VARIDX )
8164  {
8165  int varidx;
8166  varidx = expr->children[i]->data.intval;
8167 
8168  assert(varidx >= 0);
8169  if( substexprs[varidx] != NULL )
8170  {
8171  /* replace child i by copy of substexprs[expr->children[i]->opdata.intval] */
8172  SCIPexprFreeDeep(blkmem, &expr->children[i]);
8173  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[i], substexprs[varidx]) );
8174  }
8175  }
8176  else
8177  {
8178  /* call recursively */
8179  SCIP_CALL( SCIPexprSubstituteVars(blkmem, expr->children[i], substexprs) );
8180  }
8181  }
8182 
8183  return SCIP_OKAY;
8184 }
8185 
8186 /** updates variable indices in expression tree */
8188  SCIP_EXPR* expr, /**< expression to update */
8189  int* newindices /**< new indices of variables */
8190  )
8191 {
8192  int i;
8193 
8194  assert(expr != NULL);
8195  assert(newindices != NULL);
8196 
8197  if( expr->op == SCIP_EXPR_VARIDX )
8198  {
8199  expr->data.intval = newindices[expr->data.intval];
8200  assert(expr->data.intval >= 0);
8201  }
8202 
8203  for( i = 0; i < expr->nchildren; ++i )
8204  SCIPexprReindexVars(expr->children[i], newindices);
8205 }
8206 
8207 /** updates parameter indices in expression tree */
8209  SCIP_EXPR* expr, /**< expression to update */
8210  int* newindices /**< new indices of variables */
8211  )
8212 {
8213  int i;
8214 
8215  assert(expr != NULL);
8216  assert(newindices != NULL);
8217 
8218  if( expr->op == SCIP_EXPR_PARAM )
8219  {
8220  expr->data.intval = newindices[expr->data.intval];
8221  assert(expr->data.intval >= 0);
8222  }
8223 
8224  for( i = 0; i < expr->nchildren; ++i )
8225  SCIPexprReindexParams(expr->children[i], newindices);
8226 }
8227 
8228 /** prints an expression */
8230  SCIP_EXPR* expr, /**< expression */
8231  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8232  FILE* file, /**< file for printing, or NULL for stdout */
8233  const char** varnames, /**< names of variables, or NULL for default names */
8234  const char** paramnames, /**< names of parameters, or NULL for default names */
8235  SCIP_Real* paramvals /**< values of parameters, or NULL for not printing */
8236  )
8237 {
8238  assert( expr != NULL );
8239 
8240  switch( expr->op )
8241  {
8242  /* @Note: 'expr->data.intval' is either between 0 and number of variables-1, if it uses the varnames array, or
8243  * between 0 and number of params in the expression tree, if it uses the paramnames array
8244  * because, here, we cannot get the values above we cannot assert them
8245  */
8246  case SCIP_EXPR_VARIDX:
8247  if( varnames != NULL )
8248  {
8249  assert(varnames[expr->data.intval] != NULL);
8250  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", varnames[expr->data.intval]);
8251  }
8252  else
8253  {
8254  SCIPmessageFPrintInfo(messagehdlr, file, "var%d", expr->data.intval);
8255  }
8256  break;
8257 
8258  case SCIP_EXPR_PARAM:
8259  if( paramnames != NULL )
8260  {
8261  assert(paramnames[expr->data.intval] != NULL);
8262  SCIPmessageFPrintInfo(messagehdlr, file, "%s", paramnames[expr->data.intval]);
8263  }
8264  else
8265  {
8266  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", expr->data.intval );
8267  }
8268  if( paramvals != NULL )
8269  {
8270  SCIPmessageFPrintInfo(messagehdlr, file, "[%g]", paramvals[expr->data.intval] );
8271  }
8272  break;
8273 
8274  case SCIP_EXPR_CONST:
8275  if (expr->data.dbl < 0.0 )
8276  SCIPmessageFPrintInfo(messagehdlr, file, "(%g)", expr->data.dbl );
8277  else
8278  SCIPmessageFPrintInfo(messagehdlr, file, "%g", expr->data.dbl );
8279  break;
8280 
8281  case SCIP_EXPR_PLUS:
8282  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8283  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8284  SCIPmessageFPrintInfo(messagehdlr, file, " + ");
8285  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8286  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8287  break;
8288 
8289  case SCIP_EXPR_MINUS:
8290  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8291  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8292  SCIPmessageFPrintInfo(messagehdlr, file, " - ");
8293  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8294  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8295  break;
8296 
8297  case SCIP_EXPR_MUL:
8298  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8299  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8300  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8301  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8302  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8303  break;
8304 
8305  case SCIP_EXPR_DIV:
8306  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8307  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8308  SCIPmessageFPrintInfo(messagehdlr, file, " / ");
8309  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8310  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8311  break;
8312 
8313  case SCIP_EXPR_REALPOWER:
8314  case SCIP_EXPR_SIGNPOWER:
8315  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8316  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8317  SCIPmessageFPrintInfo(messagehdlr, file, ", %g)", expr->data.dbl);
8318  break;
8319 
8320  case SCIP_EXPR_INTPOWER:
8321  SCIPmessageFPrintInfo(messagehdlr, file, "power(");
8322  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8323  SCIPmessageFPrintInfo(messagehdlr, file, ", %d)", expr->data.intval);
8324  break;
8325 
8326  case SCIP_EXPR_SQUARE:
8327  case SCIP_EXPR_SQRT:
8328  case SCIP_EXPR_EXP:
8329  case SCIP_EXPR_LOG:
8330  case SCIP_EXPR_SIN:
8331  case SCIP_EXPR_COS:
8332  case SCIP_EXPR_TAN:
8333  /* case SCIP_EXPR_ERF: */
8334  /* case SCIP_EXPR_ERFI: */
8335  case SCIP_EXPR_MIN:
8336  case SCIP_EXPR_MAX:
8337  case SCIP_EXPR_ABS:
8338  case SCIP_EXPR_SIGN:
8339  {
8340  int i;
8341 
8342  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8343 
8344  for( i = 0; i < expr->nchildren; ++i )
8345  {
8346  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8347  if( i + 1 < expr->nchildren )
8348  {
8349  SCIPmessageFPrintInfo(messagehdlr, file, ", ");
8350  }
8351  }
8352 
8353  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8354  break;
8355  }
8356 
8357  case SCIP_EXPR_SUM:
8358  case SCIP_EXPR_PRODUCT:
8359  {
8360  switch( expr->nchildren )
8361  {
8362  case 0:
8363  SCIPmessageFPrintInfo(messagehdlr, file, expr->op == SCIP_EXPR_SUM ? "0" : "1");
8364  break;
8365  case 1:
8366  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8367  break;
8368  default:
8369  {
8370  int i;
8371  char opstr[SCIP_MAXSTRLEN];
8372 
8373  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8374  for( i = 0; i < expr->nchildren; ++i )
8375  {
8376  if( i > 0 )
8377  {
8378  (void) SCIPsnprintf(opstr, SCIP_MAXSTRLEN, "%s", expr->op == SCIP_EXPR_SUM ? " + " : " * ");
8379  SCIPmessageFPrintInfo(messagehdlr, file, opstr);
8380  }
8381  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8382  }
8383  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8384  }
8385  }
8386  break;
8387  }
8388 
8389  case SCIP_EXPR_LINEAR:
8390  {
8391  SCIP_Real constant;
8392  int i;
8393 
8394  constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
8395 
8396  if( expr->nchildren == 0 )
8397  {
8398  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", constant);
8399  break;
8400  }
8401 
8402  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8403 
8404  if( constant != 0.0 )
8405  {
8406  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", constant);
8407  }
8408 
8409  for( i = 0; i < expr->nchildren; ++i )
8410  {
8411  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", ((SCIP_Real*)expr->data.data)[i]);
8412  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8413  }
8414 
8415  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8416  break;
8417  }
8418 
8419  case SCIP_EXPR_QUADRATIC:
8420  {
8421  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
8422  int i;
8423 
8424  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
8425  assert(quadraticdata != NULL);
8426 
8427  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8428 
8429  if( quadraticdata->constant != 0.0 )
8430  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->constant);
8431 
8432  if( quadraticdata->lincoefs != NULL )
8433  for( i = 0; i < expr->nchildren; ++i )
8434  {
8435  if( quadraticdata->lincoefs[i] == 0.0 )
8436  continue;
8437  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->lincoefs[i]);
8438  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8439  }
8440 
8441  for( i = 0; i < quadraticdata->nquadelems; ++i )
8442  {
8443  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->quadelems[i].coef);
8444  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
8445  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
8446  {
8447  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
8448  }
8449  else
8450  {
8451  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8452  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
8453  }
8454  }
8455 
8456  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8457  break;
8458  }
8459 
8460  case SCIP_EXPR_POLYNOMIAL:
8461  {
8462  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
8463  SCIP_EXPRDATA_MONOMIAL* monomialdata;
8464  int i;
8465  int j;
8466 
8467  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8468 
8469  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
8470  assert(polynomialdata != NULL);
8471 
8472  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
8473  {
8474  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", polynomialdata->constant);
8475  }
8476 
8477  for( i = 0; i < polynomialdata->nmonomials; ++i )
8478  {
8479  monomialdata = polynomialdata->monomials[i];
8480  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g", monomialdata->coef);
8481 
8482  for( j = 0; j < monomialdata->nfactors; ++j )
8483  {
8484  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8485 
8486  SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
8487  if( monomialdata->exponents[j] < 0.0 )
8488  {
8489  SCIPmessageFPrintInfo(messagehdlr, file, "^(%.15g)", monomialdata->exponents[j]);
8490  }
8491  else if( monomialdata->exponents[j] != 1.0 )
8492  {
8493  SCIPmessageFPrintInfo(messagehdlr, file, "^%.15g", monomialdata->exponents[j]);
8494  }
8495  }
8496  }
8497 
8498  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8499  break;
8500  }
8501 
8502  case SCIP_EXPR_USER:
8503  {
8504  SCIP_EXPRDATA_USER* exprdata;
8505  int i;
8506 
8507  exprdata = (SCIP_EXPRDATA_USER*)expr->data.data;
8508  assert(exprdata != NULL);
8509 
8510  if( exprdata->print != NULL )
8511  {
8512  exprdata->print(exprdata->userdata, messagehdlr, file);
8513  }
8514  else
8515  {
8516  SCIPmessageFPrintInfo(messagehdlr, file, "user");
8517  }
8518 
8519  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8520  for( i = 0; i < expr->nchildren; ++i )
8521  {
8522  if( i > 0 )
8523  {
8524  SCIPmessageFPrintInfo(messagehdlr, file, ",");
8525  }
8526  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8527  }
8528  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8529 
8530  break;
8531  }
8532 
8533  case SCIP_EXPR_LAST:
8534  {
8535  SCIPerrorMessage("invalid expression\n");
8536  SCIPABORT();
8537  }
8538  }
8539 }
8540 
8541 /** parses an expression from a string */
8543  BMS_BLKMEM* blkmem, /**< block memory data structure */
8544  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8545  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
8546  const char* str, /**< pointer to the string to be parsed */
8547  const char* lastchar, /**< pointer to the last char of str that should be parsed */
8548  int* nvars, /**< buffer to store number of variables */
8549  int* varnames, /**< buffer to store variable names, prefixed by index (as int) */
8550  int varnameslength /**< length of the varnames buffer array */
8551  )
8552 {
8553  SCIP_HASHTABLE* vartable;
8554  SCIP_RETCODE retcode;
8555 
8556  assert(blkmem != NULL);
8557  assert(expr != NULL);
8558  assert(str != NULL);
8559  assert(lastchar != NULL);
8560  assert(nvars != NULL);
8561  assert(varnames != NULL);
8562 
8563  *nvars = 0;
8564 
8565  /* create a hash table for variable names and corresponding expression index
8566  * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
8567  */
8568  SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString,
8569  SCIPhashKeyValString, NULL) );
8570 
8571  retcode = exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames,
8572  &varnameslength, vartable, 0);
8573 
8574  SCIPhashtableFree(&vartable);
8575 
8576  return retcode;
8577 }
8578 
8579 
8580 /**@} */
8581 
8582 /**@name Expression tree methods */
8583 /**@{ */
8584 
8585 /* In debug mode, the following methods are implemented as function calls to ensure
8586  * type validity.
8587  * In optimized mode, the methods are implemented as defines to improve performance.
8588  * However, we want to have them in the library anyways, so we have to undef the defines.
8589  */
8590 
8591 #undef SCIPexprtreeGetRoot
8592 #undef SCIPexprtreeGetNVars
8593 #undef SCIPexprtreeGetNParams
8594 #undef SCIPexprtreeGetParamVals
8595 #undef SCIPexprtreeSetParamVal
8596 #undef SCIPexprtreeGetInterpreterData
8597 #undef SCIPexprtreeSetInterpreterData
8598 #undef SCIPexprtreeFreeInterpreterData
8599 #undef SCIPexprtreeHasParam
8600 #undef SCIPexprtreeGetMaxDegree
8601 #undef SCIPexprtreeEval
8602 #undef SCIPexprtreeEvalInt
8603 #undef SCIPexprtreePrint
8604 
8605 /** returns root expression of an expression tree */
8607  SCIP_EXPRTREE* tree /**< expression tree */
8608  )
8609 {
8610  assert(tree != NULL);
8611 
8612  return tree->root;
8613 }
8614 
8615 /** returns number of variables in expression tree */
8617  SCIP_EXPRTREE* tree /**< expression tree */
8618  )
8619 {
8620  assert(tree != NULL);
8621 
8622  return tree->nvars;
8623 }
8624 
8625 /** returns number of parameters in expression tree */
8627  SCIP_EXPRTREE* tree /**< expression tree */
8628  )
8629 {
8630  assert(tree != NULL);
8631 
8632  return tree->nparams;
8633 }
8634 
8635 /** returns values of parameters or NULL if none */
8637  SCIP_EXPRTREE* tree /**< expression tree */
8638  )
8639 {
8640  assert(tree != NULL);
8641 
8642  return tree->params;
8643 }
8644 
8645 /** sets value of a single parameter in expression tree */
8647  SCIP_EXPRTREE* tree, /**< expression tree */
8648  int paramidx, /**< index of parameter */
8649  SCIP_Real paramval /**< new value of parameter */
8650  )
8651 {
8652  assert(tree != NULL);
8653  assert(paramidx >= 0);
8654  assert(paramidx < tree->nparams);
8655  assert(tree->params != NULL);
8656 
8657  tree->params[paramidx] = paramval;
8658 }
8659 
8660 /** gets data of expression tree interpreter, or NULL if not set */
8662  SCIP_EXPRTREE* tree /**< expression tree */
8663  )
8664 {
8665  assert(tree != NULL);
8666 
8667  return tree->interpreterdata;
8668 }
8669 
8670 /** sets data of expression tree interpreter */
8672  SCIP_EXPRTREE* tree, /**< expression tree */
8673  SCIP_EXPRINTDATA* interpreterdata /**< expression interpreter data */
8674  )
8675 {
8676  assert(tree != NULL);
8677  assert(interpreterdata != NULL);
8678  assert(tree->interpreterdata == NULL);
8679 
8680  tree->interpreterdata = interpreterdata;
8681 }
8682 
8683 /** frees data of expression tree interpreter, if any */
8685  SCIP_EXPRTREE* tree /**< expression tree */
8686  )
8687 {
8688  if( tree->interpreterdata != NULL )
8689  {
8691  assert(tree->interpreterdata == NULL);
8692  }
8693 
8694  return SCIP_OKAY;
8695 }
8696 
8697 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
8699  SCIP_EXPRTREE* tree /**< expression tree */
8700  )
8701 {
8702  assert(tree != NULL);
8703 
8704  return SCIPexprHasParam(tree->root);
8705 }
8706 
8707 /** Gives maximal degree of expression in expression tree.
8708  *
8709  * If constant expression, gives 0,
8710  * if linear expression, gives 1,
8711  * if polynomial expression, gives its maximal degree,
8712  * otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8713  */
8715  SCIP_EXPRTREE* tree, /**< expression tree */
8716  int* maxdegree /**< buffer to store maximal degree */
8717  )
8718 {
8719  assert(tree != NULL);
8720 
8721  SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8722 
8723  return SCIP_OKAY;
8724 }
8725 
8726 /** evaluates an expression tree w.r.t. a point */
8728  SCIP_EXPRTREE* tree, /**< expression tree */
8729  SCIP_Real* varvals, /**< values for variables */
8730  SCIP_Real* val /**< buffer to store expression tree value */
8731  )
8732 {
8733  assert(tree != NULL);
8734  assert(varvals != NULL || tree->nvars == 0);
8735  assert(val != NULL);
8736 
8737  SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8738 
8739  return SCIP_OKAY;
8740 }
8741 
8742 /** evaluates an expression tree w.r.t. an interval */
8744  SCIP_EXPRTREE* tree, /**< expression tree */
8745  SCIP_Real infinity, /**< value for infinity */
8746  SCIP_INTERVAL* varvals, /**< intervals for variables */
8747  SCIP_INTERVAL* val /**< buffer to store expression tree value */
8748  )
8749 {
8750  assert(tree != NULL);
8751  assert(varvals != NULL || tree->nvars == 0);
8752  assert(val != NULL);
8753 
8754  SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8755 
8756  return SCIP_OKAY;
8757 }
8758 
8759 /** prints an expression tree */
8761  SCIP_EXPRTREE* tree, /**< expression tree */
8762  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8763  FILE* file, /**< file for printing, or NULL for stdout */
8764  const char** varnames, /**< names of variables, or NULL for default names */
8765  const char** paramnames /**< names of parameters, or NULL for default names */
8766  )
8767 {
8768  assert(tree != NULL);
8769 
8770  SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8771 }
8772 
8773 
8774 /** creates an expression tree */
8776  BMS_BLKMEM* blkmem, /**< block memory data structure */
8777  SCIP_EXPRTREE** tree, /**< buffer to store address of created expression tree */
8778  SCIP_EXPR* root, /**< pointer to root expression, not copied deep !, can be NULL */
8779  int nvars, /**< number of variables in variable mapping */
8780  int nparams, /**< number of parameters in expression */
8781  SCIP_Real* params /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8782  )
8783 {
8784  assert(blkmem != NULL);
8785  assert(tree != NULL);
8786 
8787  SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8788 
8789  (*tree)->blkmem = blkmem;
8790  (*tree)->root = root;
8791  (*tree)->nvars = nvars;
8792  (*tree)->vars = NULL;
8793  (*tree)->nparams = nparams;
8794  (*tree)->interpreterdata = NULL;
8795 
8796  if( params != NULL )
8797  {
8798  assert(nparams > 0);
8799  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8800  }
8801  else if( nparams > 0 )
8802  {
8803  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8804  BMSclearMemoryArray((*tree)->params, nparams);
8805  }
8806  else
8807  {
8808  assert(nparams == 0);
8809  (*tree)->params = NULL;
8810  }
8811 
8812  return SCIP_OKAY;
8813 }
8814 
8815 /** copies an expression tree */
8817  BMS_BLKMEM* blkmem, /**< block memory that should be used in new expression tree */
8818  SCIP_EXPRTREE** targettree, /**< buffer to store address of copied expression tree */
8819  SCIP_EXPRTREE* sourcetree /**< expression tree to copy */
8820  )
8821 {
8822  assert(blkmem != NULL);
8823  assert(targettree != NULL);
8824  assert(sourcetree != NULL);
8825 
8826  /* copy expression tree "header" */
8827  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8828 
8829  /* we may have a new block memory; and we do not want to keep the others interpreter data */
8830  (*targettree)->blkmem = blkmem;
8831  (*targettree)->interpreterdata = NULL;
8832 
8833  /* copy variables, if any */
8834  if( sourcetree->vars != NULL )
8835  {
8836  assert(sourcetree->nvars > 0);
8837 
8838  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8839  }
8840 
8841  /* copy parameters, if any */
8842  if( sourcetree->params != NULL )
8843  {
8844  assert(sourcetree->nparams > 0);
8845 
8846  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8847  }
8848 
8849  /* copy expression */
8850  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8851 
8852  return SCIP_OKAY;
8853 }
8854 
8855 /** frees an expression tree */
8857  SCIP_EXPRTREE** tree /**< pointer to expression tree that is freed */
8858  )
8859 {
8860  assert( tree != NULL);
8861  assert(*tree != NULL);
8862 
8864 
8865  if( (*tree)->root != NULL )
8866  {
8867  SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8868  assert((*tree)->root == NULL);
8869  }
8870 
8871  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars, (*tree)->nvars );
8872  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8873 
8874  BMSfreeBlockMemory((*tree)->blkmem, tree);
8875 
8876  return SCIP_OKAY;
8877 }
8878 
8879 /** sets number and values of all parameters in expression tree */
8881  SCIP_EXPRTREE* tree, /**< expression tree */
8882  int nparams, /**< number of parameters */
8883  SCIP_Real* paramvals /**< values of parameters, can be NULL if nparams == 0 */
8884  )
8885 {
8886  assert(tree != NULL);
8887  assert(paramvals != NULL || nparams == 0);
8888 
8889  if( nparams == 0 )
8890  {
8891  BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8892  }
8893  else if( tree->params != NULL )
8894  {
8895  SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8896  BMScopyMemoryArray(tree->params, paramvals, nparams);
8897  }
8898  else
8899  {
8900  SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8901  }
8902 
8903  tree->nparams = nparams;
8904  assert(tree->params != NULL || tree->nparams == 0);
8905 
8906  return SCIP_OKAY;
8907 }
8908 
8909 
8910 /** gives the number of usages for each variable in the expression tree */
8912  SCIP_EXPRTREE* tree, /**< expression tree */
8913  int* varsusage /**< array where to store for each variable how often it is used in the tree */
8914  )
8915 {
8916  assert(tree != NULL);
8917  assert(varsusage != NULL);
8918 
8919  if( tree->nvars == 0 )
8920  return;
8921 
8922  BMSclearMemoryArray(varsusage, tree->nvars);
8923  SCIPexprGetVarsUsage(tree->root, varsusage);
8924 }
8925 
8926 /** aims at simplifying an expression and splitting of a linear expression
8927  *
8928  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
8929  */
8931  SCIP_EXPRTREE* tree, /**< expression tree */
8932  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8933  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
8934  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8935  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8936  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8937  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
8938  )
8939 {
8940 #ifndef NDEBUG
8941  SCIP_RANDNUMGEN* randnumgen;
8942  SCIP_Real* testx;
8943  SCIP_Real testval_before;
8944  SCIP_Real testval_after;
8945  int i;
8946 #endif
8947 
8948  assert(tree != NULL);
8949 
8950 #ifndef NDEBUG
8951  SCIP_CALL( SCIPrandomCreate(&randnumgen, tree->blkmem, 42) );
8952 
8953  SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) ); /*lint !e666*/
8954  for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8955  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
8956  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8957 
8958  SCIPrandomFree(&randnumgen, tree->blkmem);
8959 #endif
8960 
8961  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8962  SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8963 
8964 #ifndef NDEBUG
8965  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8966  if( nlinvars != NULL && testval_before == testval_before ) /*lint !e777*/
8967  for( i = 0; i < *nlinvars; ++i )
8968  testval_after += lincoefs[i] * testx[linidxs[i]];
8969  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
8970  BMSfreeMemoryArray(&testx);
8971 #endif
8972 
8973  /* removing something from the the tree may invalidate the interpreter data */
8974  if( nlinvars != NULL && *nlinvars > 0 )
8976 
8977  return SCIP_OKAY;
8978 }
8979 
8980 /** adds an expression to the root expression of the tree
8981  *
8982  * 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.
8983  * If no root existed yet, then the root is set to the given expression (or a copy of it).
8984  */
8986  SCIP_EXPRTREE* tree, /**< expression tree */
8987  SCIP_EXPR* expr, /**< expression to add to tree */
8988  SCIP_Bool copyexpr /**< whether expression should be copied */
8989  )
8990 {
8991  assert(tree != NULL);
8992 
8993  /* adding something to the tree may invalidate the interpreter data */
8995 
8996  if( copyexpr )
8997  {
8998  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &expr, expr) );
8999  }
9000 
9001  if( tree->root == NULL )
9002  {
9003  tree->root = expr;
9004  }
9005  else
9006  {
9007  SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
9008  }
9009 
9010  return SCIP_OKAY;
9011 }
9012 
9013 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
9015  SCIP_EXPRTREE* tree, /**< expression tree */
9016  SCIP_Real infinity, /**< value for infinity */
9017  SCIP_INTERVAL* varbounds, /**< domains of variables */
9018  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
9019  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression, or NULL if not needed */
9020  )
9021 {
9022  SCIP_INTERVAL exprbounds;
9023 
9024  assert(tree != NULL);
9025 
9026  if( tree->root == NULL )
9027  {
9028  *curv = SCIP_EXPRCURV_LINEAR;
9029 
9030  if( bounds != NULL )
9031  SCIPintervalSet(bounds, 0.0);
9032 
9033  return SCIP_OKAY;
9034  }
9035 
9036  SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
9037 
9038  if( bounds != NULL )
9039  *bounds = exprbounds;
9040 
9041  return SCIP_OKAY;
9042 }
9043 
9044 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
9045  *
9046  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL.
9047  * If substexprs[i] == NULL, then the variable expression i is not touched.
9048  */
9050  SCIP_EXPRTREE* tree, /**< expression tree */
9051  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
9052  )
9053 {
9054  assert(tree != NULL);
9055 
9056  if( tree->root == NULL )
9057  return SCIP_OKAY;
9058 
9059  if( tree->root->op == SCIP_EXPR_VARIDX )
9060  {
9061  int varidx;
9062 
9063  varidx = tree->root->data.intval;
9064  assert(varidx >= 0);
9065  if( substexprs[varidx] != NULL )
9066  {
9067  /* substitute root expression */
9068  SCIPexprFreeDeep(tree->blkmem, &tree->root);
9069  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
9070  }
9071  }
9072  else
9073  {
9074  /* check children (and grandchildren and so on...) of root expression */
9075  SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
9076  }
9077 
9078  /* substitution of variables should invalidate interpreter data */
9080 
9081  return SCIP_OKAY;
9082 }
9083 
9084 /**@} */
9085 
9086 /**@name Quadratic element methods */
9087 /**@{ */
9088 
9089 /** comparing two quadratic elements
9090  *
9091  * 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
9092  */
9093 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
9094 
9095 /** swaps two quadratic elements */
9096 #define QUADELEMS_SWAP(x,y) \
9097  { \
9098  SCIP_QUADELEM temp = x; \
9099  x = y; \
9100  y = temp; \
9101  }
9102 
9103 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
9104 static
9106  SCIP_QUADELEM* elems, /**< array to be sorted */
9107  int start, /**< starting index */
9108  int end /**< ending index */
9109  )
9110 {
9111  assert(start <= end);
9112 
9113  /* use quick sort for long lists */
9114  while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
9115  {
9116  SCIP_QUADELEM pivotkey;
9117  int lo;
9118  int hi;
9119  int mid;
9120 
9121  /* select pivot element */
9122  mid = (start+end)/2;
9123  pivotkey = elems[mid];
9124 
9125  /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
9126  lo = start;
9127  hi = end;
9128  for( ;; )
9129  {
9130  while( lo < end && QUADELEMS_ISBETTER(elems[lo], pivotkey) )
9131  lo++;
9132  while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
9133  hi--;
9134 
9135  if( lo >= hi )
9136  break;
9137 
9138  QUADELEMS_SWAP(elems[lo], elems[hi]);
9139 
9140  lo++;
9141  hi--;
9142  }
9143  assert(hi == lo-1 || hi == start);
9144 
9145  /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
9146  while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
9147  lo++;
9148 
9149  /* make sure that we have at least one element in the smaller partition */
9150  if( lo == start )
9151  {
9152  /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
9153  assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
9154  assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
9155  QUADELEMS_SWAP(elems[lo], elems[mid]);
9156  lo++;
9157  }
9158 
9159  /* sort the smaller partition by a recursive call, sort the larger part without recursion */
9160  if( hi - start <= end - lo )
9161  {
9162  /* sort [start,hi] with a recursive call */
9163  if( start < hi )
9164  quadelemsQuickSort(elems, start, hi);
9165 
9166  /* now focus on the larger part [lo,end] */
9167  start = lo;
9168  }
9169  else
9170  {
9171  /* sort [lo,end] with a recursive call */
9172  if( lo < end )
9173  quadelemsQuickSort(elems, lo, end);
9174 
9175  /* now focus on the larger part [start,hi] */
9176  end = hi;
9177  }
9178  }
9179 
9180  /* use shell sort on the remaining small list */
9181  if( end - start >= 1 )
9182  {
9183  static const int incs[3] = {1, 5, 19}; /* sequence of increments */
9184  int k;
9185 
9186  for( k = 2; k >= 0; --k )
9187  {
9188  int h;
9189  int i;
9190 
9191  for( h = incs[k], i = h + start; i <= end; ++i )
9192  {
9193  int j;
9194  SCIP_QUADELEM tempkey = elems[i];
9195 
9196  j = i;
9197  while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
9198  {
9199  elems[j] = elems[j-h];
9200  j -= h;
9201  }
9202 
9203  elems[j] = tempkey;
9204  }
9205  }
9206  }
9207 }
9208 
9209 /** sorts an array of quadratic elements
9210  *
9211  * The elements are sorted such that the first index is increasing and
9212  * such that among elements with the same first index, the second index is increasing.
9213  * For elements with same first and second index, the order is not defined.
9214  */
9216  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9217  int nquadelems /**< number of quadratic elements */
9218  )
9219 {
9220  if( nquadelems == 0 )
9221  return;
9222 
9223 #ifndef NDEBUG
9224  {
9225  int i;
9226  for( i = 0; i < nquadelems; ++i )
9227  assert(quadelems[i].idx1 <= quadelems[i].idx2);
9228  }
9229 #endif
9230 
9231  quadelemsQuickSort(quadelems, 0, nquadelems-1);
9232 }
9233 
9234 /** Finds an index pair in a sorted array of quadratic elements.
9235  *
9236  * If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
9237  * 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.
9238  * Assumes that idx1 <= idx2.
9239  */
9241  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9242  int idx1, /**< index of first variable in element to search for */
9243  int idx2, /**< index of second variable in element to search for */
9244  int nquadelems, /**< number of quadratic elements in array */
9245  int* pos /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
9246  )
9247 {
9248  int left;
9249  int right;
9250 
9251  assert(quadelems != NULL || nquadelems == 0);
9252  assert(idx1 <= idx2);
9253 
9254  if( nquadelems == 0 )
9255  {
9256  if( pos != NULL )
9257  *pos = 0;
9258  return FALSE;
9259  }
9260 
9261  left = 0;
9262  right = nquadelems - 1;
9263  while( left <= right )
9264  {
9265  int middle;
9266 
9267  middle = (left+right)/2;
9268  assert(0 <= middle && middle < nquadelems);
9269 
9270  if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) ) /*lint !e613*/
9271  right = middle - 1;
9272  else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) ) /*lint !e613*/
9273  left = middle + 1;
9274  else
9275  {
9276  if( pos != NULL )
9277  *pos = middle;
9278  return TRUE;
9279  }
9280  }
9281  assert(left == right+1);
9282 
9283  if( pos != NULL )
9284  *pos = left;
9285  return FALSE;
9286 }
9287 
9288 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
9289  *
9290  * Assumes that elements have been sorted before.
9291  */
9293  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9294  int nquadelems, /**< number of quadratic elements */
9295  int* nquadelemsnew /**< pointer to store new (reduced) number of quadratic elements */
9296  )
9297 {
9298  int i;
9299  int next;
9300 
9301  assert(quadelems != NULL);
9302  assert(nquadelemsnew != NULL);
9303  assert(nquadelems >= 0);
9304 
9305  i = 0;
9306  next = 0;
9307  while( next < nquadelems )
9308  {
9309  /* assert that array is sorted */
9310  assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
9311  (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
9312 
9313  /* skip elements with coefficient 0.0 */
9314  if( quadelems[next].coef == 0.0 )
9315  {
9316  ++next;
9317  continue;
9318  }
9319 
9320  /* if next element has same index as previous one, add it to the previous one */
9321  if( i >= 1 &&
9322  quadelems[i-1].idx1 == quadelems[next].idx1 &&
9323  quadelems[i-1].idx2 == quadelems[next].idx2 )
9324  {
9325  quadelems[i-1].coef += quadelems[next].coef;
9326  ++next;
9327  continue;
9328  }
9329 
9330  /* otherwise, move next element to current position */
9331  quadelems[i] = quadelems[next];
9332  ++i;
9333  ++next;
9334  }
9335  assert(next == nquadelems);
9336 
9337  /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
9338  *nquadelemsnew = i;
9339 }
9340 
9341 /**@} */
9342 
9343 /**@name Expression graph node private methods */
9344 /**@{ */
9345 
9346 /** adds a parent to an expression graph node */
9347 static
9349  BMS_BLKMEM* blkmem, /**< block memory */
9350  SCIP_EXPRGRAPHNODE* node, /**< expression graph node where to add a parent */
9351  SCIP_EXPRGRAPHNODE* parent /**< parent node */
9352  )
9353 {
9354  assert(blkmem != NULL);
9355  assert(node != NULL);
9356  assert(node->depth >= 0);
9357  assert(node->pos >= 0);
9358  assert(parent != NULL);
9359  assert(parent->depth >= 0);
9360  assert(parent->pos >= 0);
9361  assert(parent->depth > node->depth); /* a parent node need to have larger depth */
9362 
9363  ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
9364  assert(node->nparents < node->parentssize);
9365 
9366  node->parents[node->nparents] = parent;
9367  ++node->nparents;
9368 
9369  /* update sorted flag */
9370  node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (exprgraphnodecomp((void*)node->parents[node->nparents-2], (void*)parent) <= 0));
9371 
9372  return SCIP_OKAY;
9373 }
9374 
9375 /** ensures that array of parents in a node is sorted */
9376 static
9378  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
9379  )
9380 {
9381  assert(node != NULL);
9382 
9383  if( node->parentssorted )
9384  {
9385 #ifndef NDEBUG
9386  int i;
9387  for( i = 1; i < node->nparents; ++i )
9388  assert(exprgraphnodecomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
9389 #endif
9390  return;
9391  }
9392 
9393  SCIPsortPtr((void**)node->parents, exprgraphnodecomp, node->nparents);
9394 
9395  node->parentssorted = TRUE;
9396 }
9397 
9398 /** removes a parent from an expression graph node
9399  *
9400  * If the node is not used and has no other parents, then it is freed.
9401  */
9402 static
9404  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9405  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to remove a parent, *node will be set to NULL */
9406  SCIP_EXPRGRAPHNODE* parent /**< parent node to remove */
9407  )
9408 {
9409  SCIP_EXPRGRAPHNODE* node_;
9410  int pos;
9411  int i;
9412 
9413  assert(exprgraph != NULL);
9414  assert(node != NULL);
9415  assert(*node != NULL);
9416  assert((*node)->depth >= 0);
9417  assert((*node)->pos >= 0);
9418  assert((*node)->nparents > 0);
9419  assert(parent != NULL);
9420  assert(parent->depth >= 0);
9421  assert(parent->pos >= 0);
9422  assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
9423 
9424  /* find parent */
9425  exprgraphNodeSortParents(*node);
9426  (void) SCIPsortedvecFindPtr((void**)(*node)->parents, exprgraphnodecomp, (void*)parent, (*node)->nparents, &pos);
9427  assert(pos >= 0);
9428  assert(pos < (*node)->nparents);
9429  assert((*node)->parents[pos] == parent);
9430 
9431 #ifdef SCIP_DISABLED_CODE
9432  /* move last parent to pos, if pos is before last
9433  * update sorted flag */
9434  if( pos < (*node)->nparents-1 )
9435  {
9436  (*node)->parents[pos] = (*node)->parents[(*node)->nparents-1];
9437  (*node)->parentssorted = ((*node)->nparents <= 2);
9438  }
9439 #else
9440  /* move all parents behind pos one position up
9441  * 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
9442  */
9443  for( i = pos+1; i < (*node)->nparents; ++i )
9444  (*node)->parents[i-1] = (*node)->parents[i];
9445 #endif
9446  --(*node)->nparents;
9447 
9448  /* keep pointer to *node in case it is still used */
9449  node_ = (*node)->nuses > 0 ? *node : NULL;
9450 
9451  /* capture and release node so it is freed if possible */
9452  SCIPexprgraphCaptureNode(*node);
9453  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
9454 
9455  /* restore pointer, if node still exists */
9456  *node = node_;
9457 
9458  return SCIP_OKAY;
9459 }
9460 
9461 /** checks if a node is parent of a node */
9462 static
9464  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9465  SCIP_EXPRGRAPHNODE* parent /**< parent to look for */
9466  )
9467 {
9468  int pos;
9469 
9470  assert(node != NULL);
9471  assert(parent != NULL);
9472 
9473  /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
9474  if( node->depth >= parent->depth || node->nparents == 0 )
9475  return FALSE;
9476  assert(node->parents != NULL);
9477 
9478  /* ensure parents array is sorted */
9480 
9481  return SCIPsortedvecFindPtr((void**)node->parents, exprgraphnodecomp, (void*)parent, node->nparents, &pos);
9482 }
9483 
9484 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
9485  *
9486  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
9487  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
9488  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
9489  *
9490  * It is assumed that node and all exprs are in the expression graph already.
9491  * It is assumed that all expressions that are added have lower depth than node.
9492  */
9493 static
9495  BMS_BLKMEM* blkmem, /**< block memory */
9496  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9497  int nexprs, /**< number of children to add */
9498  SCIP_EXPRGRAPHNODE** exprs, /**< children nodes to add */
9499  int* childmap /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
9500  )
9501 {
9502  int i;
9503  int j;
9504  int orignchildren;
9505  SCIP_Bool existsalready;
9506 
9507  assert(blkmem != NULL);
9508  assert(node != NULL);
9509  assert(node->depth > 0);
9510  assert(node->pos >= 0);
9511  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);
9512  assert(exprs != NULL || nexprs == 0);
9513 
9514  if( nexprs == 0 )
9515  return SCIP_OKAY;
9516 
9517  orignchildren = node->nchildren;
9518  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
9519 
9520  for( i = 0; i < nexprs; ++i )
9521  {
9522  assert(exprs[i]->depth >= 0); /*lint !e613*/
9523  assert(exprs[i]->pos >= 0); /*lint !e613*/
9524  assert(exprs[i]->depth < node->depth); /*lint !e613*/
9525 
9526  /* check if exprs[i] is a child already, if not SUM or PRODUCT */
9527  existsalready = FALSE;
9528  if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
9529  for( j = 0; j < orignchildren; ++j )
9530  /* during simplification of polynomials, their may be NULL's in children array */
9531  if( node->children[j] != NULL && node->children[j] == exprs[i] ) /*lint !e613*/
9532  {
9533  existsalready = TRUE;
9534  break;
9535  }
9536 
9537  if( !existsalready )
9538  {
9539  /* add exprs[i] to children array */
9540  node->children[node->nchildren] = exprs[i]; /*lint !e613*/
9541  SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) ); /*lint !e613*/
9542  if( childmap != NULL )
9543  childmap[i] = node->nchildren;
9544  ++node->nchildren;
9545  }
9546  else
9547  {
9548  if( childmap != NULL )
9549  childmap[i] = j; /*lint !e644*/
9550  if( node->op == SCIP_EXPR_LINEAR )
9551  {
9552  /* if linear expression, increase coefficient by 1.0 */
9553  ((SCIP_Real*)node->data.data)[j] += 1.0;
9554  }
9555  }
9556  }
9557 
9558  /* shrink children array to actually used size */
9559  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
9560 
9561  if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
9562  {
9563  /* if linear expression, then add 1.0 coefficients for new expressions */
9564  SCIP_Real* data;
9565 
9566  data = (SCIP_Real*)node->data.data;
9567  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
9568  data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
9569  for( i = orignchildren; i < node->nchildren; ++i )
9570  data[i] = 1.0;
9571  node->data.data = (void*)data;
9572  }
9573  else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
9574  {
9575  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
9577 
9578  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9579  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
9580  BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren); /*lint !e866*/
9581  }
9582 
9583  node->simplified = FALSE;
9584 
9585  return SCIP_OKAY;
9586 }
9587 
9588 /** replaces a child node by another node
9589  *
9590  * Assumes that both nodes represent the same expression.
9591  * If this node was the last parent of oldchild and oldchild is not in use, then it is freed.
9592  * newchild must have deeper depth than node.
9593  */
9594 static
9596  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9597  SCIP_EXPRGRAPHNODE* node, /**< pointer to expression graph node */
9598  SCIP_EXPRGRAPHNODE** oldchild, /**< child node that should be replaced, it may be freed */
9599  SCIP_EXPRGRAPHNODE* newchild /**< node that should take position of oldchild */
9600  )
9601 {
9602  int childpos = -1;
9603 
9604  assert(exprgraph != NULL);
9605  assert(node != NULL);
9606  assert(oldchild != NULL);
9607  assert(*oldchild != NULL);
9608  assert(newchild != NULL);
9609 
9610  if( *oldchild == newchild )
9611  return SCIP_OKAY;
9612 
9613  SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
9614 
9615  /* let's see if child is just next to the place where we looked in a previous call to this function */
9616  if( exprgraph->lastreplacechildpos >= 0 && exprgraph->lastreplacechildpos+1 < node->nchildren && node->children[exprgraph->lastreplacechildpos+1] == *oldchild )
9617  {
9618  childpos = exprgraph->lastreplacechildpos+1;
9619  }
9620  else for( childpos = 0; childpos < node->nchildren; ++childpos )
9621  {
9622  /* search for oldchild in children array */
9623  if( node->children[childpos] == *oldchild )
9624  break;
9625  }
9626  assert(childpos >= 0);
9627  assert(childpos < node->nchildren);
9628  assert(node->children[childpos] == *oldchild);
9629 
9630  /* add as parent to newchild */
9631  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
9632 
9633  /* remove as parent from oldchild */
9634  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
9635 
9636  /* set newchild as child i */
9637  node->children[childpos] = newchild;
9638 
9639  node->simplified = FALSE;
9640 
9641  /* remember to look next to childpos first next time */
9642  exprgraph->lastreplacechildpos = childpos;
9643 
9644  return SCIP_OKAY;
9645 }
9646 
9647 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
9648  *
9649  * A node is larger than another node, if their corresponding constants are related that way.
9650  */
9651 static
9652 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
9653 {
9654  assert(elem1 != NULL);
9655  assert(elem2 != NULL);
9656  assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
9657  assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
9658  assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9659  assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9660 
9661  if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9662  return 1;
9663  else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9664  return -1;
9665  else
9666  return 0;
9667 }
9668 
9669 /** sort array of nodes that holds constants */
9670 static
9672  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
9673  )
9674 {
9675  assert(exprgraph != NULL);
9676 
9677  if( exprgraph->constssorted )
9678  return;
9679 
9680  SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
9681 
9682  exprgraph->constssorted = TRUE;
9683 }
9684 
9685 /** finds position of expression graph node corresponding to a constant in constnodes array */
9686 static
9688  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9689  SCIP_EXPRGRAPHNODE* node, /**< node to search for */
9690  int* pos /**< buffer to store position of node, if found */
9691  )
9692 {
9693  int left;
9694  int right;
9695  int middle;
9696 
9697  assert(exprgraph != NULL);
9698  assert(node != NULL);
9699  assert(node->op == SCIP_EXPR_CONST);
9700  assert(node->depth == 0);
9701  assert(node->pos >= 0);
9702  assert(pos != NULL);
9703 
9704  exprgraphSortConstNodes(exprgraph);
9705  assert(exprgraph->constssorted);
9706 
9707  /* find a node with constant node->data.dbl using binary search */
9708  left = 0;
9709  right = exprgraph->nconsts-1;
9710  *pos = -1;
9711  while( left <= right )
9712  {
9713  middle = (left+right)/2;
9714  assert(0 <= middle && middle < exprgraph->nconsts);
9715 
9716  if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9717  right = middle - 1;
9718  else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9719  left = middle + 1;
9720  else
9721  {
9722  *pos = middle;
9723  break;
9724  }
9725  }
9726  assert(left == right+1 || *pos >= 0);
9727  if( left == right+1 )
9728  return FALSE;
9729 
9730  /* search left of *pos to find node */
9731  while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl ) /*lint !e777*/
9732  --*pos;
9733  /* search right of *pos to find node */
9734  while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl ) /*lint !e777*/
9735  ++*pos;
9736 
9737  return exprgraph->constnodes[*pos] == node;
9738 }
9739 
9740 /** creates an expression graph node */
9741 static
9743  BMS_BLKMEM* blkmem, /**< block memory */
9744  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
9745  SCIP_EXPROP op, /**< operator type of expression */
9746  SCIP_EXPROPDATA opdata /**< operator data of expression */
9747  )
9748 {
9749  assert(blkmem != NULL);
9750  assert(node != NULL);
9751 
9752  SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9753  BMSclearMemory(*node);
9754 
9755  (*node)->op = op;
9756  (*node)->data = opdata;
9757 
9758  /* mark graph position as not in graph yet */
9759  (*node)->depth = -1;
9760  (*node)->pos = -1;
9761 
9762  /* arrays of length 0 are trivially sorted */
9763  (*node)->parentssorted = TRUE;
9764 
9765  /* set bounds interval to entire */
9766  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9767  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9768 
9769  /* set initial value to invalid */
9770  (*node)->value = SCIP_INVALID;
9771 
9772  /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9773  if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9774  (*node)->curv = SCIP_EXPRCURV_LINEAR;
9775  else
9776  (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9777 
9778  /* per default, a node is enabled */
9779  (*node)->enabled = TRUE;
9780 
9781  return SCIP_OKAY;
9782 }
9783 
9784 /** prints the expression corresponding to a node (not recursively) */
9785 static
9787  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9788  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9789  FILE* file, /**< file to print to, or NULL for stdout */
9790  const char** varnames, /**< variable names, or NULL for generic names */
9791  SCIP_Bool printchildrenbounds /**< whether to print bounds of children */
9792  )
9793 {
9794  int i;
9795 
9796  assert(node != NULL);
9797 
9798  switch( node->op )
9799  {
9800  case SCIP_EXPR_VARIDX:
9801  if( varnames != NULL )
9802  {
9803  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9804  }
9805  else
9806  SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9807  break;
9808 
9809  case SCIP_EXPR_CONST:
9810  SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9811  break;
9812 
9813  case SCIP_EXPR_PARAM:
9814  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9815  break;
9816 
9817  case SCIP_EXPR_PLUS:
9818  if( printchildrenbounds )
9819  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9820  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9821  if( printchildrenbounds )
9822  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9823  break;
9824 
9825  case SCIP_EXPR_MINUS:
9826  if( printchildrenbounds )
9827  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9828  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9829  if( printchildrenbounds )
9830  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9831  break;
9832 
9833  case SCIP_EXPR_MUL:
9834  if( printchildrenbounds )
9835  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9836  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9837  if( printchildrenbounds )
9838  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9839  break;
9840 
9841  case SCIP_EXPR_DIV:
9842  if( printchildrenbounds )
9843  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9844  SCIPmessageFPrintInfo(messagehdlr, file, "/");
9845  if( printchildrenbounds )
9846  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9847  break;
9848 
9849  case SCIP_EXPR_SQUARE:
9850  if( printchildrenbounds )
9851  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9852  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9853  break;
9854 
9855  case SCIP_EXPR_REALPOWER:
9856  if( printchildrenbounds )
9857  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9858  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9859  break;
9860 
9861  case SCIP_EXPR_SIGNPOWER:
9862  if( printchildrenbounds )
9863  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9864  node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9865  else
9866  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9867  break;
9868 
9869  case SCIP_EXPR_INTPOWER:
9870  SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9871  if( printchildrenbounds )
9872  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9873  SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9874  break;
9875 
9876  case SCIP_EXPR_SQRT:
9877  case SCIP_EXPR_EXP:
9878  case SCIP_EXPR_LOG:
9879  case SCIP_EXPR_SIN:
9880  case SCIP_EXPR_COS:
9881  case SCIP_EXPR_TAN:
9882  /* SCIP_EXPR_ERF = 20, */ /**< gaussian error function (1 operand) */
9883  /* SCIP_EXPR_ERFI = 21, */ /**< imaginary part of gaussian error function (1 operand) */
9884  case SCIP_EXPR_MIN:
9885  case SCIP_EXPR_MAX:
9886  case SCIP_EXPR_ABS:
9887  case SCIP_EXPR_SIGN:
9888  SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9889  if( printchildrenbounds )
9890  {
9891  SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9892  if( node->nchildren == 2 )
9893  SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9894  SCIPmessageFPrintInfo(messagehdlr, file, ")");
9895  }
9896  break;
9897 
9898  case SCIP_EXPR_SUM:
9899  if( printchildrenbounds )
9900  for( i = 0; i < node->nchildren; ++i )
9901  {
9902  if( i > 0 )
9903  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9904  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9905  }
9906  else
9907  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9908  break;
9909 
9910  case SCIP_EXPR_PRODUCT:
9911  if( printchildrenbounds )
9912  for( i = 0; i < node->nchildren; ++i )
9913  {
9914  if( i > 0 )
9915  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9916  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9917  }
9918  else
9919  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9920  break;
9921 
9922  case SCIP_EXPR_LINEAR:
9923  {
9924  SCIP_Real constant;
9925 
9926  constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9927 
9928  if( constant != 0.0 || node->nchildren == 0 )
9929  SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9930 
9931  for( i = 0; i < node->nchildren; ++i )
9932  {
9933  if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9934  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9935  else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9936  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9937  else
9938  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9939  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9940  if( printchildrenbounds )
9941  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9942  }
9943 
9944  break;
9945  }
9946 
9947  case SCIP_EXPR_QUADRATIC:
9948  {
9949  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9950 
9951  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9952  assert(quadraticdata != NULL);
9953 
9954  if( quadraticdata->constant != 0.0 )
9955  SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9956 
9957  if( quadraticdata->lincoefs != NULL )
9958  for( i = 0; i < node->nchildren; ++i )
9959  {
9960  if( quadraticdata->lincoefs[i] == 0.0 )
9961  continue;
9962  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9963  if( printchildrenbounds )
9964  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9965  }
9966 
9967  for( i = 0; i < quadraticdata->nquadelems; ++i )
9968  {
9969  if( quadraticdata->quadelems[i].coef == 1.0 )
9970  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9971  else if( quadraticdata->quadelems[i].coef == -1.0 )
9972  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9973  else
9974  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9975  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9976  if( printchildrenbounds )
9977  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9978  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9979  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9980  else
9981  {
9982  SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9983  if( printchildrenbounds )
9984  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9985  }
9986  }
9987 
9988  break;
9989  }
9990 
9991  case SCIP_EXPR_POLYNOMIAL:
9992  {
9993  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9994  SCIP_EXPRDATA_MONOMIAL* monomialdata;
9995  int j;
9996 
9997  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9998  assert(polynomialdata != NULL);
9999 
10000  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
10001  {
10002  SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
10003  }
10004 
10005  for( i = 0; i < polynomialdata->nmonomials; ++i )
10006  {
10007  monomialdata = polynomialdata->monomials[i];
10008  if( monomialdata->coef == 1.0 )
10009  SCIPmessageFPrintInfo(messagehdlr, file, "+");
10010  else if( monomialdata->coef == -1.0 )
10011  SCIPmessageFPrintInfo(messagehdlr, file, "-");
10012  else
10013  SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
10014 
10015  for( j = 0; j < monomialdata->nfactors; ++j )
10016  {
10017  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
10018  if( printchildrenbounds )
10019  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
10020  if( monomialdata->exponents[j] < 0.0 )
10021  SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
10022  else if( monomialdata->exponents[j] != 1.0 )
10023  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
10024  }
10025  }
10026 
10027  break;
10028  }
10029 
10030  case SCIP_EXPR_LAST:
10031  SCIPABORT();
10032  break;
10033 
10034  default:
10035  SCIPmessageFPrintInfo(messagehdlr, file, "%s", SCIPexpropGetName(node->op));
10036  break;
10037  } /*lint !e788*/
10038 }
10039 
10040 /** prints a node of an expression graph */
10041 static
10043  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10044  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10045  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
10046  FILE* file, /**< file to print to, or NULL for stdout */
10047  const char** varnames /**< variable names, or NULL for generic names */
10048  )
10049 {
10050  SCIP_Real color;
10051  int i;
10052 
10053  assert(exprgraph != NULL);
10054  assert(node != NULL);
10055  assert(file != NULL);
10056 
10057  color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
10058  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
10059 
10060  exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
10061 
10062  SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
10064  SCIPmessageFPrintInfo(messagehdlr, file, "!");
10066  SCIPmessageFPrintInfo(messagehdlr, file, "*");
10068  SCIPmessageFPrintInfo(messagehdlr, file, "+");
10069 
10070  SCIPmessageFPrintInfo(messagehdlr, file, "\"");
10071 
10072  if( !node->enabled )
10073  SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
10074 
10075  SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
10076 
10077  /* add edges from node to children */
10078  for( i = 0; i < node->nchildren; ++i )
10079  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);
10080 }
10081 
10082 /** evaluate node of expression graph w.r.t. values stored in children */
10083 static
10085  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10086  SCIP_Real* varvals /**< values for variables */
10087  )
10088 {
10089  int i;
10091  SCIP_Real* buf;
10092 
10093  assert(node != NULL);
10094 
10095  /* if many children, get large enough memory to store argument values */
10097  {
10098  SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
10099  }
10100  else
10101  {
10102  buf = staticbuf;
10103  }
10104 
10105  /* get values of children */
10106  for( i = 0; i < node->nchildren; ++i )
10107  {
10108  assert(node->children[i]->value != SCIP_INVALID); /*lint !e777*/
10109  buf[i] = node->children[i]->value; /*lint !e644*/
10110  }
10111 
10112  /* evaluate this expression */
10113  assert(exprOpTable[node->op].eval != NULL);
10114  SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
10115  assert(node->value != SCIP_INVALID); /*lint !e777*/
10116 
10117  /* free memory, if allocated before */
10118  if( staticbuf != buf )
10119  {
10120  BMSfreeMemoryArray(&buf);
10121  }
10122 
10123  return SCIP_OKAY;
10124 }
10125 
10126 /** evaluates node including subtree */
10127 static
10129  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10130  SCIP_Real* varvals /**< values for variables */
10131  )
10132 {
10133  int i;
10134 
10135  assert(node != NULL);
10136 
10137  for( i = 0; i < node->nchildren; ++i )
10138  {
10139  SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
10140  }
10141 
10142  SCIP_CALL( exprgraphNodeEval(node, varvals) );
10143 
10144  return SCIP_OKAY;
10145 }
10146 
10147 /** updates bounds of a node if a children has changed its bounds */
10148 static
10150  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10151  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10152  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
10153  SCIP_Bool parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
10154  )
10155 {
10156  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
10157  SCIP_INTERVAL* childbounds;
10158  SCIP_INTERVAL newbounds;
10159  int i;
10160 
10161  assert(node != NULL);
10162  assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
10163  assert(node->pos >= 0); /* node should be in graph */
10164  assert(node->op != SCIP_EXPR_VARIDX);
10165  assert(node->op != SCIP_EXPR_PARAM);
10166 
10167  /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
10168  * if node is disabled, then also do nothing */
10169  if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
10170  return SCIP_OKAY;
10171 
10172  /* if many children, get large enough memory to store children bounds */
10174  {
10175  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
10176  }
10177  else
10178  {
10179  childbounds = childboundsstatic;
10180  }
10181 
10182  /* assemble bounds of children */
10183  for( i = 0; i < node->nchildren; ++i )
10184  {
10185  /* child should have valid and non-empty bounds */
10187  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10188 
10189  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
10190  }
10191 
10192  /* call interval evaluation function for this operand */
10193  assert( exprOpTable[node->op].inteval != NULL );
10194  SCIPintervalSet(&newbounds, 0.0);
10195  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
10196 
10197  /* free memory, if allocated before */
10198  if( childbounds != childboundsstatic )
10199  {
10200  BMSfreeMemoryArray(&childbounds);
10201  }
10202 
10203  /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
10204 
10205  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
10206  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
10207  *
10208  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
10209  *
10210  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
10211  */
10212  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
10213  ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
10214  {
10215  for( i = 0; i < node->nparents; ++i )
10217 
10218  node->bounds = newbounds;
10219  }
10220  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
10221  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
10222  {
10223  for( i = 0; i < node->nparents; ++i )
10225 
10226  node->bounds = newbounds;
10227  }
10228  else
10229  {
10230  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
10231  }
10232 
10233  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);
10234 
10235  /* node now has valid bounds */
10236  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
10237 
10238  return SCIP_OKAY;
10239 }
10240 
10241 /** propagate bounds of a node into children by reverting the nodes expression */
10242 static
10244  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10245  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
10246  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10247  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
10248  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
10249  )
10250 {
10251  SCIP_INTERVAL childbounds;
10252  int i;
10253 
10254  assert(exprgraph != NULL);
10255  assert(node != NULL);
10256  assert(node->depth >= 0); /* node should be in graph */
10257  assert(node->pos >= 0); /* node should be in graph */
10258  assert(minstrength >= 0.0);
10259  assert(cutoff != NULL);
10260  assert(!SCIPintervalIsEmpty(infinity, node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
10261  assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
10262 
10263  /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
10265  return;
10266 
10267  /* if node is not enabled, then do nothing */
10268  if( !node->enabled )
10269  return;
10270 
10271  /* tell children that they should propagate their bounds even if not tightened */
10273  minstrength = -1.0;
10274 
10275  /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
10277 
10278  /* 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);
10279  * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10280  * SCIPdebugPrintf("\n");
10281  */
10282 
10283  /* @todo add callback to exprOpTable for this */
10284 
10285  switch( node->op )
10286  {
10287  case SCIP_EXPR_VARIDX:
10288  case SCIP_EXPR_CONST:
10289  case SCIP_EXPR_PARAM:
10290  /* cannot propagate bound changes further */
10291  break;
10292 
10293  case SCIP_EXPR_PLUS:
10294  {
10295  assert(node->nchildren == 2);
10296  /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
10297 
10298  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10299  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10300 
10301  if( *cutoff )
10302  break;
10303 
10304  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10305  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10306 
10307  break;
10308  }
10309 
10310  case SCIP_EXPR_MINUS:
10311  {
10312  assert(node->nchildren == 2);
10313  /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
10314 
10315  SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10316  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10317 
10318  if( *cutoff )
10319  break;
10320 
10321  SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10322  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10323 
10324  break;
10325  }
10326 
10327  case SCIP_EXPR_MUL:
10328  {
10329  assert(node->nchildren == 2);
10330  /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
10331 
10332  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10333  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10334 
10335  if( *cutoff )
10336  break;
10337 
10338  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10339  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10340 
10341  break;
10342  }
10343 
10344  case SCIP_EXPR_DIV:
10345  {
10346  assert(node->nchildren == 2);
10347  /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
10348 
10349  SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10350  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10351 
10352  if( *cutoff )
10353  break;
10354 
10355  SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10356  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10357 
10358  break;
10359  }
10360 
10361  case SCIP_EXPR_SQUARE:
10362  {
10363  assert(node->nchildren == 1);
10364  /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
10365 
10366  if( node->bounds.sup < 0.0 )
10367  {
10368  *cutoff = TRUE;
10369  break;
10370  }
10371 
10372  SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
10373  if( node->children[0]->bounds.inf <= -childbounds.inf )
10374  SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
10375  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10376 
10377  break;
10378  }
10379 
10380  case SCIP_EXPR_SQRT:
10381  {
10382  assert(node->nchildren == 1);
10383  /* f = sqrt(c0) -> c0 = f^2 */
10384 
10385  SCIPintervalSquare(infinity, &childbounds, node->bounds);
10386  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10387 
10388  break;
10389  }
10390 
10391  case SCIP_EXPR_REALPOWER:
10392  {
10393  assert(node->nchildren == 1);
10394 
10395  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
10396 
10397  if( SCIPintervalIsEmpty(infinity, childbounds) )
10398  {
10399  *cutoff = TRUE;
10400  break;
10401  }
10402  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10403 
10404  break;
10405  }
10406 
10407  case SCIP_EXPR_SIGNPOWER:
10408  {
10409  assert(node->nchildren == 1);
10410 
10411  if( node->data.dbl != 0.0 )
10412  {
10413  SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
10414  }
10415  else
10416  {
10417  /* behaves like SCIP_EXPR_SIGN */
10418  SCIPintervalSetBounds(&childbounds,
10419  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10420  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10421  }
10422 
10423  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10424 
10425  break;
10426  }
10427 
10428  case SCIP_EXPR_INTPOWER:
10429  {
10430  assert(node->nchildren == 1);
10431 
10432  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
10433 
10434  if( SCIPintervalIsEmpty(infinity, childbounds) )
10435  {
10436  *cutoff = TRUE;
10437  break;
10438  }
10439  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10440 
10441  break;
10442  }
10443 
10444  case SCIP_EXPR_EXP:
10445  {
10446  assert(node->nchildren == 1);
10447  /* f = exp(c0) -> c0 = log(f) */
10448 
10449  if( node->bounds.sup < 0.0 )
10450  {
10451  *cutoff = TRUE;
10452  break;
10453  }
10454 
10455  SCIPintervalLog(infinity, &childbounds, node->bounds);
10456  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10457 
10458  break;
10459  }
10460 
10461  case SCIP_EXPR_LOG:
10462  {
10463  assert(node->nchildren == 1);
10464  /* f = log(c0) -> c0 = exp(f) */
10465 
10466  SCIPintervalExp(infinity, &childbounds, node->bounds);
10467  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10468 
10469  break;
10470  }
10471 
10472  case SCIP_EXPR_SIN:
10473  case SCIP_EXPR_COS:
10474  case SCIP_EXPR_TAN:
10475  /* case SCIP_EXPR_ERF: */
10476  /* case SCIP_EXPR_ERFI: */
10477  {
10478  assert(node->nchildren == 1);
10479 
10480  /* @todo implement */
10481 
10482  break;
10483  }
10484 
10485  case SCIP_EXPR_ABS:
10486  {
10487  assert(node->nchildren == 1);
10488 
10489  /* use identity if child bounds are non-negative */
10490  if( node->children[0]->bounds.inf >= 0 )
10491  {
10492  SCIPintervalSetBounds(&childbounds, node->bounds.inf, node->bounds.sup);
10493  }
10494  /* use -identity if child bounds are non-positive */
10495  else if( node->children[0]->bounds.sup <= 0 )
10496  {
10497  assert(node->bounds.inf <= node->bounds.sup);
10498  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, -node->bounds.inf);
10499  }
10500  /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
10501  else
10502  {
10503  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
10504  }
10505 
10506  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10507 
10508  break;
10509  }
10510 
10511  case SCIP_EXPR_SIGN:
10512  {
10513  assert(node->nchildren == 1);
10514  /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
10515 
10516  SCIPintervalSetBounds(&childbounds,
10517  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10518  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10519  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10520 
10521  break;
10522  }
10523 
10524  case SCIP_EXPR_MIN:
10525  {
10526  assert(node->nchildren == 2);
10527  /* f = min(c0,c1) -> f <= c0, f <= c1
10528  * if c1 > f -> c0 = f
10529  * if c0 > f -> c1 = f
10530  */
10531 
10532  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10533  node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10534  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10535 
10536  if( *cutoff )
10537  break;
10538 
10539  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10540  node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10541  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10542 
10543  break;
10544  }
10545 
10546  case SCIP_EXPR_MAX:
10547  {
10548  assert(node->nchildren == 2);
10549  /* f = max(c0, c1) -> f >= c0, f >= c1
10550  * if c1 < f -> c0 = f
10551  * if c0 < f -> c1 = f
10552  */
10553 
10554  SCIPintervalSetBounds(&childbounds,
10555  node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10556  node->bounds.sup);
10557  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10558 
10559  SCIPintervalSetBounds(&childbounds,
10560  node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10561  node->bounds.sup);
10562  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10563 
10564  break;
10565  }
10566 
10567  case SCIP_EXPR_SUM:
10568  {
10569  SCIP_ROUNDMODE prevroundmode;
10570 
10571  /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
10572 
10573  SCIP_Real minlinactivity;
10574  SCIP_Real maxlinactivity;
10575  int minlinactivityinf;
10576  int maxlinactivityinf;
10577 
10578  if( node->nchildren == 0 )
10579  break;
10580 
10581  if( SCIPintervalIsEntire(infinity, node->bounds) )
10582  break;
10583 
10584  minlinactivity = 0.0;
10585  maxlinactivity = 0.0;
10586  minlinactivityinf = 0;
10587  maxlinactivityinf = 0;
10588 
10589  prevroundmode = SCIPintervalGetRoundingMode();
10591 
10592  for( i = 0; i < node->nchildren; ++i )
10593  {
10594  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10595 
10596  /* minimal activity is only useful if node has a finite upper bound */
10597  if( node->bounds.sup < infinity )
10598  {
10599  if( node->children[i]->bounds.inf <= -infinity )
10600  {
10601  ++minlinactivityinf;
10602  }
10603  else
10604  {
10605  assert(node->children[i]->bounds.inf < infinity);
10606  minlinactivity += node->children[i]->bounds.inf;
10607  }
10608  }
10609 
10610  /* maximal activity is only useful if node has a finite lower bound
10611  * we compute negated maximal activity here so we can keep downward rounding
10612  */
10613  if( node->bounds.inf > -infinity )
10614  {
10615  if( node->children[i]->bounds.sup >= infinity )
10616  {
10617  ++maxlinactivityinf;
10618  }
10619  else
10620  {
10621  assert(node->children[i]->bounds.sup > -infinity);
10622  maxlinactivity -= node->children[i]->bounds.sup;
10623  }
10624  }
10625  }
10626  maxlinactivity = -maxlinactivity; /* correct sign */
10627 
10628  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10629  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10630  ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10631  )
10632  {
10633  SCIPintervalSetRoundingMode(prevroundmode);
10634  break;
10635  }
10636 
10637  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10638  {
10639  /* upper bounds of c_i is
10640  * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
10641  * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
10642  */
10643  SCIPintervalSetEntire(infinity, &childbounds);
10644  if( node->bounds.sup < infinity )
10645  {
10646  /* we are still in downward rounding mode, so negate and negate to get upward rounding */
10647  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10648  {
10649  assert(minlinactivityinf == 1);
10650  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
10651  }
10652  else if( minlinactivityinf == 0 )
10653  {
10654  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
10655  }
10656  }
10657 
10658  /* lower bounds of c_i is
10659  * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
10660  * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
10661  */
10662  if( node->bounds.inf > -infinity )
10663  {
10664  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10665  {
10666  assert(maxlinactivityinf == 1);
10667  childbounds.inf = node->bounds.inf - maxlinactivity;
10668  }
10669  else if( maxlinactivityinf == 0 )
10670  {
10671  childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
10672  }
10673  }
10674 
10675  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10676  }
10677 
10678  SCIPintervalSetRoundingMode(prevroundmode);
10679 
10680  break;
10681  }
10682 
10683  case SCIP_EXPR_PRODUCT:
10684  {
10685  int j;
10686  /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
10687 
10688  /* too expensive (runtime here is quadratic in number of children) */
10689  if( node->nchildren > 10 )
10690  break;
10691 
10692  /* useless */
10693  if( SCIPintervalIsEntire(infinity, node->bounds) )
10694  break;
10695 
10696  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10697  {
10698  /* compute prod_{j:j!=i} c_j */
10699  SCIPintervalSet(&childbounds, 1.0);
10700  for( j = 0; j < node->nchildren; ++j )
10701  {
10702  if( i == j )
10703  continue;
10704  SCIPintervalMul(infinity, &childbounds, childbounds, node->children[j]->bounds);
10705 
10706  /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
10707  if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
10708  break;
10709  }
10710 
10711  if( j == node->nchildren )
10712  {
10713  SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
10714  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10715  }
10716  }
10717 
10718  break;
10719  }
10720 
10721  case SCIP_EXPR_LINEAR:
10722  {
10723  SCIP_ROUNDMODE prevroundmode;
10724  SCIP_Real* coefs;
10725 
10726  /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10727 
10728  SCIP_Real minlinactivity;
10729  SCIP_Real maxlinactivity;
10730  int minlinactivityinf;
10731  int maxlinactivityinf;
10732 
10733  if( node->nchildren == 0 )
10734  break;
10735 
10736  if( SCIPintervalIsEntire(infinity, node->bounds) )
10737  break;
10738 
10739  coefs = (SCIP_Real*)node->data.data;
10740 
10741  minlinactivity = coefs[node->nchildren];
10742  maxlinactivity = -coefs[node->nchildren];
10743  minlinactivityinf = 0;
10744  maxlinactivityinf = 0;
10745 
10746  prevroundmode = SCIPintervalGetRoundingMode();
10748 
10749  for( i = 0; i < node->nchildren; ++i )
10750  {
10751  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10752 
10753  /* minimal activity is only useful if node has a finite upper bound */
10754  if( node->bounds.sup < infinity )
10755  {
10756  if( coefs[i] >= 0.0 )
10757  {
10758  if( node->children[i]->bounds.inf <= -infinity )
10759  {
10760  ++minlinactivityinf;
10761  }
10762  else
10763  {
10764  assert(node->children[i]->bounds.inf < infinity);
10765  minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10766  }
10767  }
10768  else
10769  {
10770  if( node->children[i]->bounds.sup >= infinity )
10771  {
10772  ++minlinactivityinf;
10773  }
10774  else
10775  {
10776  assert(node->children[i]->bounds.sup > -infinity);
10777  minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10778  }
10779  }
10780  }
10781 
10782  /* maximal activity is only useful if node has a finite lower bound
10783  * we compute negated maximal activity here so we can keep downward rounding
10784  */
10785  if( node->bounds.inf > -infinity )
10786  {
10787  if( coefs[i] >= 0.0 )
10788  {
10789  if( node->children[i]->bounds.sup >= infinity )
10790  {
10791  ++maxlinactivityinf;
10792  }
10793  else
10794  {
10795  assert(node->children[i]->bounds.sup > -infinity);
10796  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.sup;
10797  }
10798  }
10799  else
10800  {
10801  if( node->children[i]->bounds.inf <= -infinity )
10802  {
10803  ++maxlinactivityinf;
10804  }
10805  else
10806  {
10807  assert(node->children[i]->bounds.inf < infinity);
10808  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.inf;
10809  }
10810  }
10811  }
10812  }
10813  maxlinactivity = SCIPintervalNegateReal(maxlinactivity); /* correct sign */
10814 
10815  /* SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]; bounds = [%10g,%10g]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf, node->bounds.inf, node->bounds.sup); */
10816 
10817  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10818  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10819  (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10820  )
10821  {
10822  SCIPintervalSetRoundingMode(prevroundmode);
10823  break;
10824  }
10825 
10826  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10827  {
10828  SCIP_INTERVAL ac;
10829 
10830  if( coefs[i] == 0.0 )
10831  continue;
10832 
10833  /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10834  SCIPintervalSet(&ac, 0.0);
10835  if( coefs[i] >= 0.0 )
10836  {
10837  if( node->children[i]->bounds.inf > -infinity )
10838  ac.inf = coefs[i] * node->children[i]->bounds.inf;
10839  if( node->children[i]->bounds.sup < infinity )
10841  }
10842  else
10843  {
10844  if( node->children[i]->bounds.sup < infinity )
10845  ac.inf = coefs[i] * node->children[i]->bounds.sup;
10846  if( node->children[i]->bounds.inf > -infinity )
10847  ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10848  }
10849 
10850  SCIPintervalSetEntire(infinity, &childbounds);
10851  if( coefs[i] > 0.0 )
10852  {
10853  /* upper bounds of c_i is
10854  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10855  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10856  */
10857  if( node->bounds.sup < infinity )
10858  {
10859  /* we are still in downward rounding mode, so negate to get upward rounding */
10860  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10861  {
10862  assert(minlinactivityinf == 1);
10863  childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10864  }
10865  else if( minlinactivityinf == 0 )
10866  {
10867  childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10868  }
10869  }
10870 
10871  /* lower bounds of c_i is
10872  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10873  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10874  */
10875  if( node->bounds.inf > -infinity )
10876  {
10877  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10878  {
10879  assert(maxlinactivityinf == 1);
10880  childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10881  }
10882  else if( maxlinactivityinf == 0 )
10883  {
10884  childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10885  }
10886  }
10887  }
10888  else
10889  {
10890  /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10891  * thus, we do (b-a)/(-c) in downward rounding
10892  */
10893  /* lower bounds of c_i is
10894  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10895  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10896  */
10897  if( node->bounds.sup < infinity )
10898  {
10899  if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10900  {
10901  assert(minlinactivityinf == 1);
10902  childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10903  }
10904  else if( minlinactivityinf == 0 )
10905  {
10906  childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10907  }
10908  }
10909 
10910  /* upper bounds of c_i is
10911  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10912  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10913  */
10914  if( node->bounds.inf > -infinity )
10915  {
10916  /* we are still in downward rounding mode, so negate to get upward rounding */
10917  if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10918  {
10919  assert(maxlinactivityinf == 1);
10920  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10921  }
10922  else if( maxlinactivityinf == 0 )
10923  {
10924  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10925  }
10926  }
10927  }
10928 
10929  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10930  }
10931 
10932  SCIPintervalSetRoundingMode(prevroundmode);
10933 
10934  break;
10935  }
10936 
10937  case SCIP_EXPR_QUADRATIC:
10938  {
10939  SCIP_EXPRDATA_QUADRATIC* quaddata;
10940  SCIP_INTERVAL tmp;
10941  SCIP_INTERVAL a;
10942  SCIP_INTERVAL b;
10943  SCIP_INTERVAL c;
10944  SCIP_QUADELEM* quadelems;
10945  int nquadelems;
10946  SCIP_Real* lincoefs;
10947  int k;
10948 
10949  /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10950  * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10951  */
10952 
10953  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10954  quadelems = quaddata->quadelems;
10955  nquadelems = quaddata->nquadelems;
10956  lincoefs = quaddata->lincoefs;
10957 
10958  /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10959  if( nquadelems > 10 )
10960  break;
10961 
10962  if( SCIPintervalIsEntire(infinity, node->bounds) )
10963  break;
10964 
10965  if( node->nchildren == 2 && nquadelems > 0 )
10966  {
10967  /* if it's a bivariate quadratic expression with bilinear term, do something special */
10968  SCIP_Real ax; /* square coefficient of first child */
10969  SCIP_Real ay; /* square coefficient of second child */
10970  SCIP_Real axy; /* bilinear coefficient */
10971 
10972  ax = 0.0;
10973  ay = 0.0;
10974  axy = 0.0;
10975  for( i = 0; i < nquadelems; ++i )
10976  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10977  ax += quadelems[i].coef;
10978  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10979  ay += quadelems[i].coef;
10980  else
10981  axy += quadelems[i].coef;
10982 
10983  c = node->bounds;
10984  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10985 
10986  /* compute bounds for x */
10988  infinity, &childbounds, ax, ay, axy,
10989  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10990  c, node->children[0]->bounds, node->children[1]->bounds
10991  );
10992  if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10993  {
10994  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",
10995  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10996  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10997  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10998  );
10999  }
11000 
11001  if( SCIPintervalIsEmpty(infinity, childbounds) )
11002  *cutoff = TRUE;
11003  else
11004  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11005  if( *cutoff )
11006  break;
11007 
11008  /* compute bounds for y */
11010  infinity, &childbounds, ay, ax, axy,
11011  lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
11012  c, node->children[1]->bounds, node->children[0]->bounds
11013  );
11014 
11015  if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
11016  {
11017  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",
11018  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
11019  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
11020  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
11021  );
11022  }
11023 
11024  if( SCIPintervalIsEmpty(infinity, childbounds) )
11025  *cutoff = TRUE;
11026  else
11027  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
11028  if( *cutoff )
11029  break;
11030 
11031  break;
11032  }
11033 
11034  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11035  {
11036  SCIPintervalSet(&a, 0.0);
11037  SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
11038  c = node->bounds;
11039  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
11040 
11041  /* move linear terms not corresponding to i into c
11042  * @todo do this faster, see EXPR_LINEAR
11043  */
11044  if( lincoefs != NULL )
11045  for( k = 0; k < node->nchildren; ++k )
11046  if( i != k && lincoefs[k] != 0.0 )
11047  {
11048  SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
11049  SCIPintervalSub(infinity, &c, c, tmp);
11050  }
11051 
11052  for( k = 0; k < nquadelems; ++k )
11053  {
11054  if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
11055  {
11056  SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
11057  }
11058  else if( quadelems[k].idx1 == i )
11059  {
11060  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
11061  SCIPintervalAdd(infinity, &b, b, tmp);
11062  }
11063  else if( quadelems[k].idx2 == i )
11064  {
11065  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
11066  SCIPintervalAdd(infinity, &b, b, tmp);
11067  }
11068  else if( quadelems[k].idx1 == quadelems[k].idx2 )
11069  {
11070  SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
11071  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11072  SCIPintervalSub(infinity, &c, c, tmp);
11073  }
11074  else
11075  {
11076  SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
11077  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11078  SCIPintervalSub(infinity, &c, c, tmp);
11079  }
11080  }
11081 
11082  SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
11083  a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
11084  SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c, node->children[i]->bounds);
11085  if( SCIPintervalIsEmpty(infinity, childbounds) )
11086  *cutoff = TRUE;
11087  else
11088  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11089  }
11090 
11091  break;
11092  }
11093 
11094  case SCIP_EXPR_POLYNOMIAL:
11095  {
11096  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11097  SCIP_EXPRDATA_MONOMIAL** monomials;
11098  SCIP_EXPRDATA_MONOMIAL* monomial;
11099  int nmonomials;
11100  int j;
11101  int k;
11102  SCIP_Real n;
11103  int nexpisdoublen;
11104  int nexpishalfn;
11105  char abc_flag;
11106 
11107  SCIP_INTERVAL monomialcoef;
11108  SCIP_INTERVAL tmp;
11109  SCIP_INTERVAL a;
11110  SCIP_INTERVAL b;
11111  SCIP_INTERVAL c;
11112  SCIP_INTERVAL childpowbounds;
11113 
11114  /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
11115  * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
11116  *
11117  * we determine n by setting n to the first exponent of x that we see
11118  * then we count how often we see x^(2n) and x^(n/2)
11119  * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
11120  */
11121 
11122  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11123  monomials = polynomialdata->monomials;
11124  nmonomials = polynomialdata->nmonomials;
11125 
11126  if( SCIPintervalIsEntire(infinity, node->bounds) )
11127  break;
11128 
11129  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11130  {
11131  n = 0.0;
11132  nexpisdoublen = 0;
11133  nexpishalfn = 0;
11134  for( j = 0; j < nmonomials; ++j )
11135  {
11136  monomial = monomials[j];
11137  for( k = 0; k < monomial->nfactors; ++k )
11138  {
11139  if( monomial->childidxs[k] == i )
11140  {
11141  if( n == 0.0 )
11142  n = monomial->exponents[k];
11143  else if( n == 2*monomial->exponents[k] ) /*lint !e777*/
11144  ++nexpishalfn;
11145  else if( 2*n == monomial->exponents[k] ) /*lint !e777*/
11146  ++nexpisdoublen;
11147  }
11148  }
11149  }
11150 
11151  if( n == 0.0 )
11152  {
11153  /* child does not appear in polynomial -> cannot deduce bound */
11154  continue;
11155  }
11156 
11157  /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
11158  if( nexpishalfn > nexpisdoublen )
11159  n /= 2.0;
11160 
11161  SCIPintervalSet(&a, 0.0);
11162  SCIPintervalSet(&b, 0.0);
11163  SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
11164 
11165  for( j = 0; j < nmonomials; ++j )
11166  {
11167  monomial = monomials[j];
11168  SCIPintervalSet(&monomialcoef, monomial->coef);
11169  abc_flag = 'c';
11170  for( k = 0; k < monomial->nfactors; ++k )
11171  {
11172  if( monomial->childidxs[k] == i )
11173  {
11174  assert(abc_flag == 'c'); /* child should appear only once per monom */
11175  if( n > 0.0 )
11176  {
11177  if( monomial->exponents[k] > 2.0*n )
11178  {
11179  abc_flag = 'a';
11180  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11181  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11182  }
11183  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11184  {
11185  abc_flag = 'a';
11186  }
11187  else if( monomial->exponents[k] > n )
11188  {
11189  abc_flag = 'b';
11190  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11191  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11192  }
11193  else if( monomial->exponents[k] == n ) /*lint !e777*/
11194  {
11195  abc_flag = 'b';
11196  }
11197  else
11198  {
11199  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11200  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11201  }
11202  }
11203  else
11204  {
11205  assert(n < 0.0);
11206  if( monomial->exponents[k] < 2.0*n )
11207  {
11208  abc_flag = 'a';
11209  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11210  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11211  }
11212  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11213  {
11214  abc_flag = 'a';
11215  }
11216  else if( monomial->exponents[k] < n )
11217  {
11218  abc_flag = 'b';
11219  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11220  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11221  }
11222  else if( monomial->exponents[k] == n ) /*lint !e777*/
11223  {
11224  abc_flag = 'b';
11225  }
11226  else
11227  {
11228  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11229  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11230  }
11231  }
11232  }
11233  else
11234  {
11235  SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
11236  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11237  }
11238  }
11239 
11240  if( abc_flag == 'a' )
11241  {
11242  SCIPintervalAdd(infinity, &a, a, monomialcoef);
11243  /* if monomialcoef is such that a exceeds value for infinity, then stop */
11244  if( a.inf >= infinity || a.sup <= -infinity )
11245  break;
11246  }
11247  else if( abc_flag == 'b' )
11248  {
11249  SCIPintervalAdd(infinity, &b, b, monomialcoef);
11250  /* if monomialcoef is such that b exceeds value for infinity, then stop */
11251  if( b.inf >= infinity || b.sup <= -infinity )
11252  break;
11253  }
11254  else
11255  {
11256  SCIPintervalSub(infinity, &c, c, monomialcoef);
11257  /* if monomialcoef is such that c exceeds value for infinity, then stop */
11258  if( c.inf >= infinity || c.sup <= -infinity )
11259  break;
11260  }
11261  }
11262 
11263  /* if we run out of numbers (within -infinity,infinity) above, then stop */
11264  if( j < nmonomials )
11265  continue;
11266 
11267  /* now have equation a*child^(2n) + b*child^n = c
11268  * solve a*y^2 + b*y = c (for y in childbounds^n), then child^n = y
11269  */
11270  SCIPintervalPowerScalar(infinity, &childpowbounds, node->children[i]->bounds, n);
11271  SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g] for c%d^%g in [%10g,%10g]",
11272  a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup, i, n, childpowbounds.inf, childpowbounds.sup);
11273  SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c, childpowbounds);
11274  SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
11275 
11276  if( SCIPintervalIsEmpty(infinity, tmp) )
11277  {
11278  *cutoff = TRUE;
11279  break;
11280  }
11281 
11282  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
11283  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);
11284  if( SCIPintervalIsEmpty(infinity, childbounds) )
11285  {
11286  SCIPdebugMessage(" -> cutoff\n");
11287  *cutoff = TRUE;
11288  break;
11289  }
11290 
11291  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11292 
11293  /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
11294  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11295  SCIPdebugPrintf("\n"); */
11296  }
11297 
11298  break;
11299  }
11300 
11301  case SCIP_EXPR_USER:
11302  {
11303  SCIP_INTERVAL* childrenbounds;
11304  SCIP_EXPRDATA_USER* exprdata;
11305  int c;
11306 
11307  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11308 
11309  /* do nothing if callback not implemented */
11310  if( exprdata->prop == NULL )
11311  break;
11312 
11313  /* if only one child, do faster */
11314  if( node->nchildren == 1 )
11315  {
11316  childbounds = node->children[0]->bounds;
11317  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, 1, &childbounds, node->bounds, cutoff) );
11318 
11319  if( !*cutoff )
11320  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11321 
11322  break;
11323  }
11324 
11325  SCIP_ALLOC_ABORT( BMSallocBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren) );
11326  for( c = 0; c < node->nchildren; ++c )
11327  childrenbounds[c] = node->children[c]->bounds;
11328 
11329  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, node->nchildren, childrenbounds, node->bounds, cutoff) );
11330 
11331  for( c = 0; !*cutoff && c < node->nchildren; ++c )
11332  {
11333  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[c], childrenbounds[c], minstrength, infinity, cutoff);
11334  }
11335 
11336  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren);
11337 
11338  break;
11339  }
11340 
11341  case SCIP_EXPR_LAST:
11342  SCIPABORT();
11343  break;
11344  }
11345 }
11346 
11347 /** removes duplicate children in a polynomial expression node
11348  *
11349  * Leaves NULL's in children array.
11350  */
11351 static
11353  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11354  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11355  )
11356 {
11357  SCIP_Bool foundduplicates;
11358  int* childmap;
11359  int i;
11360  int j;
11361 
11362  assert(exprgraph != NULL);
11363  assert(node != NULL);
11364  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11365 
11366  if( node->nchildren == 0 )
11367  return SCIP_OKAY;
11368 
11369  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
11370 
11371  foundduplicates = FALSE;
11372  for( i = 0; i < node->nchildren; ++i )
11373  {
11374  if( node->children[i] == NULL )
11375  continue;
11376  childmap[i] = i; /*lint !e644*/
11377 
11378  for( j = i+1; j < node->nchildren; ++j )
11379  {
11380  if( node->children[j] == NULL )
11381  continue;
11382 
11383  if( node->children[i] == node->children[j] )
11384  {
11385  /* node should be parent of children[j] at least twice,
11386  * so we remove it once
11387  */
11388  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
11389  node->children[j] = NULL;
11390  assert(exprgraphNodeIsParent(node->children[i], node));
11391 
11392  childmap[j] = i;
11393  foundduplicates = TRUE;
11394  }
11395  }
11396  }
11397 
11398  /* apply childmap to monomials */
11399  if( foundduplicates )
11401 
11402  /* free childmap */
11403  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
11404 
11405  return SCIP_OKAY;
11406 }
11407 
11408 /** eliminates NULL's in children array and shrinks it to actual size */
11409 static
11411  BMS_BLKMEM* blkmem, /**< block memory */
11412  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11413  )
11414 {
11415  int* childmap;
11416  int lastnonnull;
11417  int i;
11418 
11419  assert(blkmem != NULL);
11420  assert(node != NULL);
11421  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11422 
11423  if( node->nchildren == 0 )
11424  return SCIP_OKAY;
11425 
11426  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
11427 
11428  /* close gaps in children array */
11429  lastnonnull = node->nchildren-1;
11430  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11431  --lastnonnull;
11432  for( i = 0; i <= lastnonnull; ++i )
11433  {
11434  if( node->children[i] != NULL )
11435  {
11436  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
11437  continue;
11438  }
11439  assert(node->children[lastnonnull] != NULL);
11440 
11441  /* move child at lastnonnull to position i */
11442  node->children[i] = node->children[lastnonnull];
11443  node->children[lastnonnull] = NULL;
11444  childmap[lastnonnull] = i;
11445 
11446  /* update lastnonnull */
11447  --lastnonnull;
11448  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11449  --lastnonnull;
11450  }
11451  assert(i > lastnonnull);
11452 
11453  /* apply childmap to monomials */
11454  if( lastnonnull < node->nchildren-1 )
11456 
11457  BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
11458 
11459  /* shrink children array */
11460  if( lastnonnull >= 0 )
11461  {
11462  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
11463  node->nchildren = lastnonnull+1;
11464  }
11465  else
11466  {
11467  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11468  node->nchildren = 0;
11469  }
11470 
11471  return SCIP_OKAY;
11472 }
11473 
11474 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
11475  *
11476  * Converts node into polynomial, if possible and not constant.
11477  */
11478 static
11480  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11481  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
11482  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
11483  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
11484  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
11485  SCIP_Bool* havechange /**< flag to set if the node has been changed */
11486  )
11487 {
11488  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11489  SCIP_EXPRDATA_MONOMIAL* monomial;
11490  BMS_BLKMEM* blkmem;
11491  SCIP_Bool removechild;
11492  SCIP_Bool* childinuse;
11493  int* childmap;
11494  int childmapsize;
11495  int i;
11496  int j;
11497  int orignchildren;
11498 
11499  assert(exprgraph != NULL);
11500  assert(node != NULL);
11501  assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
11502  assert(havechange != NULL);
11503 
11504  blkmem = exprgraph->blkmem;
11505  assert(blkmem != NULL);
11506 
11507  SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
11508 
11509  /* if all children are constants, then turn this node into constant */
11510  for( i = 0; i < node->nchildren; ++i )
11511  if( node->children[i]->op != SCIP_EXPR_CONST )
11512  break;
11513  if( node->nchildren > 0 && i == node->nchildren )
11514  {
11515  /* get value of node */
11517  assert(node->value != SCIP_INVALID); /*lint !e777*/
11518 
11519  SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
11520  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11521  SCIPdebugPrintf("\n");
11522 
11523  /* free expression data */
11524  if( exprOpTable[node->op].freedata != NULL )
11525  exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
11526 
11527  /* disconnect from children */
11528  for( i = 0; i < node->nchildren; ++i )
11529  {
11530  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11531  }
11532  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11533  node->nchildren = 0;
11534 
11535  /* turn into constant expression */
11536  node->op = SCIP_EXPR_CONST;
11537  node->data.dbl = node->value;
11538 
11539  *havechange = TRUE;
11540  node->simplified = TRUE;
11541 
11542  return SCIP_OKAY;
11543  }
11544 
11545  /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
11546  * @todo log(product) -> sum(log)
11547  * @todo product(exp) -> exp(sum)
11548  * @todo exp(x)^p -> exp(p*x)
11549  * @todo exp(const*log(x)) -> x^const
11550  */
11551 
11552  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
11553 
11554  if( node->op != SCIP_EXPR_POLYNOMIAL )
11555  {
11556  node->simplified = TRUE;
11557  return SCIP_OKAY;
11558  }
11559 
11560  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11561  assert(polynomialdata != NULL);
11562 
11563  orignchildren = node->nchildren;
11564 
11565  /* check if we have duplicate children and merge */
11567  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11568 
11569  SCIPdebugMessage("expand factors in expression node ");
11570  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11571  SCIPdebugPrintf("\n");
11572 
11573  childmap = NULL;
11574  childmapsize = 0;
11575 
11576  /* resolve children that are constants
11577  * we do this first, because it reduces the degree and number of factors in the monomials,
11578  * 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
11579  */
11580  for( i = 0; i < node->nchildren; ++i )
11581  {
11582  if( node->children[i] == NULL )
11583  continue;
11584 
11585  /* convert children to polynomial, if not constant or polynomial
11586  * if child was simplified in this round, it may have already been converted, and then nothing happens
11587  * but if child was already simplified, then it was not converted, and thus we try it here
11588  */
11589  if( node->children[i]->op != SCIP_EXPR_CONST )
11590  continue;
11591 
11592  SCIPdebugMessage("expand child %d in expression node ", i);
11593  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11594  SCIPdebugPrintf("\n\tchild = ");
11595  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11596  SCIPdebugPrintf("\n");
11597 
11598  removechild = TRUE; /* we intend to release children[i] */
11599 
11600  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11601 
11602  /* put constant of child i into every monomial where child i is used */
11603  for( j = 0; j < polynomialdata->nmonomials; ++j )
11604  {
11605  int factorpos;
11606 
11607  monomial = polynomialdata->monomials[j];
11608  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11609  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11610 
11611  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11612  {
11613  assert(factorpos >= 0);
11614  assert(factorpos < monomial->nfactors);
11615  /* assert that factors have been merged */
11616  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11617  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11618 
11619  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11620 
11621  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 ) /*lint !e835*/
11622  {
11623  /* if constant is negative and our exponent is not integer, then cannot do expansion */
11624  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
11625  removechild = FALSE;
11626  }
11627  else
11628  {
11629  monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
11630 
11631  /* move last factor to position factorpos */
11632  if( factorpos < monomial->nfactors-1 )
11633  {
11634  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
11635  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
11636  }
11637  --monomial->nfactors;
11638  monomial->sorted = FALSE;
11639  polynomialdata->sorted = FALSE;
11640 
11641  *havechange = TRUE;
11642  }
11643  }
11644  }
11645 
11646  /* forget about child i, if it is not used anymore */
11647  if( removechild )
11648  {
11649  /* remove node from list of parents of child i */
11650  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11651  node->children[i] = NULL;
11652  }
11653 
11654  /* simplify current polynomial again */
11655  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11656  }
11657 
11658  /* resolve children that are polynomials itself */
11659  for( i = 0; i < node->nchildren; ++i )
11660  {
11661  if( node->children[i] == NULL )
11662  continue;
11663 
11664  /* convert children to polynomial, if not constant or polynomial
11665  * if child was simplified in this round, it may have already been converted, and then nothing happens
11666  * but if child was already simplified, then it was not converted, and thus we try it here
11667  */
11668  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
11669 
11670  if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
11671  continue;
11672 
11673  SCIPdebugMessage("expand child %d in expression node %p = ", i, (void*)node);
11674  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11675  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n\tchild = ") );
11676  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11677  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
11678 
11679  removechild = TRUE; /* we intend to release children[i] */
11680 
11681  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11682 
11683  /* add children of child i to node */
11684  SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
11685 
11686  /* put polynomial of child i into every monomial where child i is used */
11687  j = 0;
11688  while( j < polynomialdata->nmonomials )
11689  {
11690  int factorpos;
11691  SCIP_Bool success;
11692 
11693  monomial = polynomialdata->monomials[j];
11694  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11695  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11696 
11697  /* make sure factors are merged, should only be potentially necessary if not sorted, see also #1848 */
11698  if( !monomial->sorted )
11699  SCIPexprMergeMonomialFactors(monomial, eps);
11700 
11701  if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11702  {
11703  ++j;
11704  continue;
11705  }
11706 
11707  assert(factorpos >= 0);
11708  assert(factorpos < monomial->nfactors);
11709  /* assert that factors have been merged */
11710  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11711  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11712 
11713  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11714 
11715  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
11716  (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
11717 
11718  if( !success )
11719  {
11720  removechild = FALSE;
11721  ++j;
11722  }
11723  else
11724  *havechange = TRUE;
11725 
11726  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
11727  * we thus repeat with index j, if a factor was successfully expanded
11728  */
11729  }
11730 
11731  /* forget about child i, if it is not used anymore */
11732  if( removechild )
11733  {
11734  /* remove node from list of parents of child i */
11735  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11736  node->children[i] = NULL;
11737  }
11738  }
11739 
11740  /* simplify current polynomial again */
11741  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11742 
11743  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
11744 
11745  /* check which children are still in use */
11746  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
11747  BMSclearMemoryArray(childinuse, node->nchildren); /*lint !e644*/
11748  for( i = 0; i < polynomialdata->nmonomials; ++i )
11749  {
11750  monomial = polynomialdata->monomials[i];
11751  assert(monomial != NULL);
11752 
11753  for( j = 0; j < monomial->nfactors; ++j )
11754  {
11755  assert(monomial->childidxs[j] >= 0);
11756  assert(monomial->childidxs[j] < node->nchildren);
11757  childinuse[monomial->childidxs[j]] = TRUE;
11758  }
11759  }
11760 
11761  /* free children that are not used in any monomial */
11762  for( i = 0; i < node->nchildren; ++i )
11763  if( node->children[i] != NULL && !childinuse[i] )
11764  {
11765  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11766  node->children[i] = NULL;
11767  }
11768 
11769  BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
11770 
11771  /* remove NULLs from children array */
11773 
11774  /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
11775  if( node->nchildren == 0 )
11776  {
11777  SCIP_Real val;
11778 
11779  /* if no children, then it should also have no monomials */
11780  assert(polynomialdata->nmonomials == 0);
11781 
11782  val = polynomialdata->constant;
11783  polynomialdataFree(blkmem, &polynomialdata);
11784 
11785  node->op = SCIP_EXPR_CONST;
11786  node->data.dbl = val;
11787  node->value = val;
11788  }
11789 
11790  /* if no factor in a monomial was replaced, the number of children should not have changed
11791  * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11792  */
11793  *havechange |= (node->nchildren < orignchildren); /*lint !e514*/
11794 
11795  node->simplified = TRUE;
11796 
11797  SCIPdebugMessage("-> %p = ", (void*)node);
11798  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11799  SCIPdebugPrintf("\n");
11800 
11801  return SCIP_OKAY;
11802 }
11803 
11804 /** creates an expression from a given node in an expression graph
11805  *
11806  * Assembles mapping of variables from graph to tree.
11807  */
11808 static
11810  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11811  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which expression should be created */
11812  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
11813  int* nexprvars, /**< current number of variables in expression */
11814  int* varidx /**< current mapping of variable indices from graph to expression */
11815  )
11816 {
11817  SCIP_EXPR** childexprs;
11818  int i;
11819 
11820  assert(exprgraph != NULL);
11821  assert(node != NULL);
11822  assert(expr != NULL);
11823  assert(nexprvars != NULL);
11824  assert(*nexprvars >= 0);
11825  assert(varidx != NULL);
11826 
11827  childexprs = NULL;
11828  if( node->nchildren > 0 )
11829  {
11830  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11831  for( i = 0; i < node->nchildren; ++i )
11832  {
11833  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) ); /*lint !e613*/
11834  }
11835  }
11836 
11837  switch( node->op )
11838  {
11839  case SCIP_EXPR_VARIDX:
11840  {
11841  /* check if the variable already has an index assigned in the expression tree
11842  * if not, create one and increase nexprvars
11843  */
11844  assert(node->data.intval >= 0);
11845  assert(node->data.intval < exprgraph->nvars);
11846  assert(varidx[node->data.intval] >= -1);
11847  assert(varidx[node->data.intval] < *nexprvars);
11848  if( varidx[node->data.intval] == -1 )
11849  {
11850  varidx[node->data.intval] = *nexprvars;
11851  ++*nexprvars;
11852  }
11853 
11854  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11855  break;
11856  }
11857 
11858  case SCIP_EXPR_CONST:
11859  {
11860  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11861  break;
11862  }
11863 
11864  case SCIP_EXPR_REALPOWER:
11865  case SCIP_EXPR_SIGNPOWER:
11866  {
11867  assert(node->nchildren == 1);
11868  assert(childexprs != NULL);
11869  /* coverity[var_deref_op] */
11870  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11871  break;
11872  }
11873 
11874  case SCIP_EXPR_INTPOWER:
11875  {
11876  assert(node->nchildren == 1);
11877  assert(childexprs != NULL);
11878  /* coverity[var_deref_op] */
11879  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11880  break;
11881  }
11882 
11883  case SCIP_EXPR_PLUS:
11884  case SCIP_EXPR_MINUS:
11885  case SCIP_EXPR_MUL:
11886  case SCIP_EXPR_DIV:
11887  case SCIP_EXPR_MIN:
11888  case SCIP_EXPR_MAX:
11889  {
11890  assert(node->nchildren == 2);
11891  assert(childexprs != NULL);
11892  /* coverity[var_deref_op] */
11893  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11894  break;
11895  }
11896 
11897  case SCIP_EXPR_SQUARE:
11898  case SCIP_EXPR_SQRT:
11899  case SCIP_EXPR_EXP:
11900  case SCIP_EXPR_LOG:
11901  case SCIP_EXPR_SIN:
11902  case SCIP_EXPR_COS:
11903  case SCIP_EXPR_TAN:
11904  /* case SCIP_EXPR_ERF: */
11905  /* case SCIP_EXPR_ERFI: */
11906  case SCIP_EXPR_ABS:
11907  case SCIP_EXPR_SIGN:
11908  {
11909  assert(node->nchildren == 1);
11910  assert(childexprs != NULL);
11911  /* coverity[var_deref_op] */
11912  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11913  break;
11914  }
11915 
11916  case SCIP_EXPR_SUM:
11917  case SCIP_EXPR_PRODUCT:
11918  {
11919  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11920  break;
11921  }
11922 
11923  case SCIP_EXPR_LINEAR:
11924  {
11925  assert(node->data.data != NULL);
11926 
11927  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11928  break;
11929  }
11930 
11931  case SCIP_EXPR_QUADRATIC:
11932  {
11933  SCIP_EXPRDATA_QUADRATIC* quaddata;
11934 
11935  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11936  assert(quaddata != NULL);
11937 
11938  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11939  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11940  break;
11941  }
11942 
11943  case SCIP_EXPR_POLYNOMIAL:
11944  {
11945  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11946 
11947  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11948  assert(polynomialdata != NULL);
11949 
11950  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11951  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11952 
11953  break;
11954  }
11955 
11956  case SCIP_EXPR_USER:
11957  {
11958  SCIP_EXPRDATA_USER* exprdata;
11959  SCIP_USEREXPRDATA* userdata;
11960 
11961  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11962  assert(exprdata != NULL);
11963 
11964  if( exprdata->copydata != NULL )
11965  {
11966  SCIP_CALL( exprdata->copydata(exprgraph->blkmem, node->nchildren, exprdata->userdata, &userdata) );
11967  }
11968  else
11969  userdata = exprdata->userdata;
11970 
11971  /* coverity[var_deref_op] */
11972  /* coverity[var_deref_model] */
11973  SCIP_CALL( SCIPexprCreateUser(exprgraph->blkmem, expr, node->nchildren, childexprs,
11974  userdata, exprdata->evalcapability, exprdata->eval, exprdata->inteval, exprdata->curv, exprdata->prop, exprdata->estimate, exprdata->copydata, exprdata->freedata, exprdata->print) );
11975 
11976  break;
11977  }
11978 
11979  case SCIP_EXPR_LAST:
11980  case SCIP_EXPR_PARAM:
11981  {
11982  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11983  return SCIP_ERROR;
11984  }
11985  }
11986 
11987  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11988 
11989  return SCIP_OKAY;
11990 }
11991 
11992 /** counts how often expression graph variables are used in a subtree of the expression graph
11993  *
11994  * @note The function does not clear the array first, but only increases already existing counts.
11995  */
11996 static
11998  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11999  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
12000  )
12001 {
12002  int i;
12003 
12004  assert(node != NULL);
12005  assert(varsusage != NULL);
12006 
12007  if( node->op == SCIP_EXPR_VARIDX )
12008  {
12009  ++varsusage[node->data.intval];
12010  return;
12011  }
12012 
12013  for( i = 0; i < node->nchildren; ++i )
12014  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
12015 }
12016 
12017 /** checks whether a node can be put into a component when checking block separability of an expression
12018  *
12019  * If a variable used by node is already in another component, components are merged and component number is updated.
12020  */
12021 static
12023  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
12024  int* compnr, /**< component number to assign, may be reduced if variables overlap */
12025  int nchildcomps, /**< number of entries for which childcomps have been set already */
12026  int* childcomps, /**< component numbers of children */
12027  int nvars, /**< number of variables */
12028  int* varcomps /**< component numbers of variables */
12029  )
12030 {
12031  int varidx;
12032  int i;
12033 
12034  assert(node != NULL);
12035  assert(compnr != NULL);
12036  assert(*compnr >= 0);
12037  assert(childcomps != NULL);
12038  assert(varcomps != NULL);
12039 
12040  if( node->op != SCIP_EXPR_VARIDX )
12041  {
12042  for( i = 0; i < node->nchildren; ++i )
12043  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
12044  return;
12045  }
12046 
12047  varidx = node->data.intval;
12048  assert(varidx >= 0);
12049  assert(varidx < nvars);
12050 
12051  if( varcomps[varidx] == -1 )
12052  {
12053  /* first time we get to this variable, so set it's component to compnr and we are done */
12054  varcomps[varidx] = *compnr;
12055  return;
12056  }
12057 
12058  if( varcomps[varidx] == *compnr )
12059  {
12060  /* variable is already in current component, that's also good and we are done */
12061  return;
12062  }
12063 
12064  /* variable is already in another component, so have to merge component compnr into that component
12065  * do this by updating varcomps and childcomps */
12066  for( i = 0; i < nvars; ++i )
12067  if( varcomps[i] == *compnr )
12068  varcomps[i] = varcomps[varidx];
12069  for( i = 0; i < nchildcomps; ++i )
12070  if( childcomps[i] == *compnr )
12071  /* coverity[copy_paste_error] */
12072  childcomps[i] = varcomps[varidx];
12073  *compnr = varcomps[varidx];
12074 }
12075 
12076 /**@} */
12077 
12078 /**@name Expression graph private methods */
12079 /**@{ */
12080 
12081 /** assert that expression graph has at least a given depth */
12082 static
12084  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
12085  int mindepth /**< minimal depth that should be ensured */
12086  )
12087 {
12088  int olddepth;
12089 
12090  assert(exprgraph != NULL);
12091  assert(exprgraph->blkmem != NULL);
12092 
12093  if( mindepth <= exprgraph->depth )
12094  return SCIP_OKAY;
12095 
12096  olddepth = exprgraph->depth;
12097  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
12098  assert(exprgraph->depth >= mindepth);
12099 
12100  /* initialize new array entries to 0 and NULL, resp. */
12101  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12102  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12103  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12104 
12105  return SCIP_OKAY;
12106 }
12107 
12108 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
12109 static
12111  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12112  int varidx /**< variable index */
12113  )
12114 {
12115  SCIP_EXPRGRAPHNODE* varnode;
12116  void* var;
12117 
12118  assert(exprgraph != NULL);
12119  assert(varidx >= 0);
12120  assert(varidx < exprgraph->nvars);
12121 
12122  varnode = exprgraph->varnodes[varidx];
12123  assert(varnode->data.intval == varidx);
12124 
12125  var = exprgraph->vars[varidx];
12126 
12127  /* call varremove callback method, if set */
12128  if( exprgraph->exprgraphvarremove != NULL )
12129  {
12130  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
12131  }
12132 
12133  /* remove variable from hashmap */
12134  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
12135 
12136  /* move last variable to position varidx and give it the new index */
12137  if( varidx < exprgraph->nvars-1 )
12138  {
12139  /* call callback method, if set */
12140  if( exprgraph->exprgraphvarchgidx != NULL )
12141  {
12142  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
12143  }
12144 
12145  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
12146  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
12147  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
12148  exprgraph->varnodes[varidx]->data.intval = varidx;
12149  SCIP_CALL( SCIPhashmapSetImageInt(exprgraph->varidxs, exprgraph->vars[varidx], varidx) );
12150  }
12151  --exprgraph->nvars;
12152 
12153  return SCIP_OKAY;
12154 }
12155 
12156 /** moves a node in an expression graph to a different depth
12157  *
12158  * New depth must be larger than children depth.
12159  * Moves parent nodes to higher depth, if needed.
12160  * Variable nodes cannot be moved.
12161  */
12162 static
12164  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12165  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
12166  int newdepth /**< new depth to which to move node */
12167  )
12168 {
12169  int olddepth;
12170  int oldpos;
12171  int i;
12172 
12173  assert(exprgraph != NULL);
12174  assert(node != NULL);
12175  assert(node->depth >= 0); /* node should be in graph */
12176  assert(newdepth >= 0);
12177 
12178  /* if already on aimed depth, then don't need to move */
12179  if( node->depth == newdepth )
12180  return SCIP_OKAY;
12181 
12182  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
12183 
12184 #ifndef NDEBUG
12185  /* assert that children are at lower depth than new depth */
12186  for( i = 0; i < node->nchildren; ++i )
12187  assert(node->children[i]->depth < newdepth);
12188 #endif
12189 
12190  /* move parents to higher depth, if needed */
12191  for( i = 0; i < node->nparents; ++i )
12192  {
12193  if( node->parents[i]->depth <= newdepth )
12194  {
12195  /* move parent to depth+1 */
12196  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
12197  assert(node->parents[i]->depth > newdepth);
12198  }
12199  }
12200 
12201  /* ensure that graph is deep enough */
12202  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
12203  assert(exprgraph->depth > newdepth);
12204 
12205  olddepth = node->depth;
12206  oldpos = node->pos;
12207 
12208  /* add node to new depth */
12209  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
12210  node->depth = newdepth;
12211  node->pos = exprgraph->nnodes[newdepth];
12212  exprgraph->nodes[newdepth][node->pos] = node;
12213  ++exprgraph->nnodes[newdepth];
12214 
12215  /* 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) */
12216  for( i = 0; i < node->nchildren; ++i )
12217  node->children[i]->parentssorted = FALSE;
12218 
12219  /* move last node at previous depth to previous position, if it wasn't last */
12220  if( oldpos < exprgraph->nnodes[olddepth]-1 )
12221  {
12222  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
12223  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
12224 
12225  /* 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) */
12226  for( i = 0; i < exprgraph->nodes[olddepth][oldpos]->nchildren; ++i )
12227  exprgraph->nodes[olddepth][oldpos]->children[i]->parentssorted = FALSE;
12228  }
12229  --exprgraph->nnodes[olddepth];
12230 
12231  if( node->depth == 0 )
12232  {
12233  /* if at depth 0, then it need to be a node for either a constant or a variable */
12234  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
12235  if( node->op == SCIP_EXPR_CONST )
12236  {
12237  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
12238  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
12239  exprgraph->constnodes[exprgraph->nconsts] = node;
12240  ++exprgraph->nconsts;
12241  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
12242  }
12243  else
12244  {
12245  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
12246  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
12247  return SCIP_ERROR;
12248  }
12249 
12250  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
12251  node->curv = SCIP_EXPRCURV_LINEAR;
12252  }
12253 
12254  return SCIP_OKAY;
12255 }
12256 
12257 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
12258 static
12260  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12261  int nchildren, /**< number of children */
12262  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
12263  SCIP_EXPROP op, /**< operator */
12264  SCIP_EXPROPDATA opdata, /**< operator data */
12265  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
12266  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
12267  )
12268 {
12269  SCIP_EXPRGRAPHNODE** parentcands;
12270  int nparentcands;
12271  int parentcandssize;
12272  int i;
12273  int p;
12274 
12275  assert(exprgraph != NULL);
12276  assert(nchildren > 0);
12277  assert(children != NULL);
12278  assert(parent != NULL);
12279 
12280  *parent = NULL;
12281 
12282  /* create initial set of parent candidates as
12283  * all parents of first child that have the same operator type and the same number of children
12284  * additionally, some easy conditions for complex expression types:
12285  * if expression type is int/real/signpower, then compare also exponent,
12286  * if expression type is linear, then compare also constant part,
12287  * if expression type is quadratic, then compare also number of quadratic elements,
12288  * if expression type is polynomial, then compare also number of monmials and constant part
12289  */
12290  parentcandssize = children[0]->nparents;
12291  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
12292  nparentcands = 0;
12293  for( p = 0; p < children[0]->nparents; ++p )
12294  if( children[0]->parents[p]->op == op &&
12295  children[0]->parents[p]->nchildren == nchildren &&
12296  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
12297  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12298  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12299  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
12300  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
12301  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
12302  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
12303  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
12304  )
12305  {
12306  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
12307  }
12308 
12309  /* for all remaining children, remove parent candidates, that are not in their list of parents */
12310  for( i = 1; i < nchildren && nparentcands > 0; ++i )
12311  {
12312  p = 0;
12313  while( p < nparentcands )
12314  {
12315  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
12316  * otherwise keep candidate and check next one
12317  */
12318  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
12319  {
12320  parentcands[p] = parentcands[nparentcands-1];
12321  --nparentcands;
12322  }
12323  else
12324  ++p;
12325  }
12326  }
12327 
12328  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
12329 
12330  if( nparentcands == 0 )
12331  {
12332  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
12333  return SCIP_OKAY;
12334  }
12335 
12336  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
12337  * check if there is also one which corresponds to same expression and store that one in *parent
12338  */
12339  switch( op )
12340  {
12341  /* commutative operands with no data */
12342  case SCIP_EXPR_PLUS :
12343  case SCIP_EXPR_MUL :
12344  case SCIP_EXPR_MIN :
12345  case SCIP_EXPR_MAX :
12346  case SCIP_EXPR_SUM :
12347  case SCIP_EXPR_PRODUCT:
12348  case SCIP_EXPR_SQUARE :
12349  case SCIP_EXPR_SQRT :
12350  case SCIP_EXPR_EXP :
12351  case SCIP_EXPR_LOG :
12352  case SCIP_EXPR_SIN :
12353  case SCIP_EXPR_COS :
12354  case SCIP_EXPR_TAN :
12355  /* case SCIP_EXPR_ERF : */
12356  /* case SCIP_EXPR_ERFI : */
12357  case SCIP_EXPR_ABS :
12358  case SCIP_EXPR_SIGN :
12359  {
12360  /* sort childnodes, if needed for later */
12361  if( nchildren > 2 )
12362  SCIPsortPtr((void**)children, exprgraphnodecomp, nchildren);
12363  for( p = 0; p < nparentcands; ++p )
12364  {
12365  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12366  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12367 
12368  if( nchildren == 1 )
12369  {
12370  assert(parentcands[p]->children[0] == children[0]);
12371  /* same operand, same child, so same expression */
12372  *parent = parentcands[p];
12373  break;
12374  }
12375  else if( nchildren == 2 )
12376  {
12377  /* We know that every node in children is also a child of parentcands[p].
12378  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
12379  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
12380  */
12381  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
12382  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
12383  {
12384  *parent = parentcands[p];
12385  break;
12386  }
12387  }
12388  else
12389  {
12390  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
12391 
12392  /* sort children of parent candidate */
12393  SCIPsortPtr((void**)parentcands[p]->children, exprgraphnodecomp, nchildren);
12394 
12395  /* check if childnodes and parentcands[p]->children are the same */
12396  for( i = 0; i < nchildren; ++i )
12397  if( children[i] != parentcands[p]->children[i] )
12398  break;
12399  if( i == nchildren )
12400  {
12401  /* yeah, found an exact match */
12402  *parent = parentcands[p];
12403  break;
12404  }
12405  }
12406  }
12407 
12408  break;
12409  }
12410 
12411  /* non-commutative operands with two children */
12412  case SCIP_EXPR_MINUS :
12413  case SCIP_EXPR_DIV :
12414  {
12415  for( p = 0; p < nparentcands; ++p )
12416  {
12417  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12418  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
12419  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
12420  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
12421  {
12422  /* yeah, found one */
12423  *parent = parentcands[p];
12424  break;
12425  }
12426  }
12427 
12428  break;
12429  }
12430 
12431  /* operands with one child and data */
12432  case SCIP_EXPR_INTPOWER:
12433  {
12434  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12435  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12436  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12437  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
12438 
12439  /* yeah, have one with same exponent */
12440  *parent = parentcands[0];
12441 
12442  break;
12443  }
12444 
12445  case SCIP_EXPR_REALPOWER:
12446  case SCIP_EXPR_SIGNPOWER:
12447  {
12448  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12449  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12450  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12451  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
12452 
12453  /* yeah, have one with same exponent */
12454  *parent = parentcands[0];
12455 
12456  break;
12457  }
12458 
12459  /* commutative operands with n children and data */
12460  case SCIP_EXPR_LINEAR:
12461  {
12462  SCIP_Real* exprcoef;
12463  SCIP_Real* candcoef;
12464 
12465  exprcoef = (SCIP_Real*)opdata.data;
12466  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
12467  if( exprchildren != NULL )
12468  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, exprgraphnodecomp, nchildren);
12469  else
12470  SCIPsortPtrReal((void**)children, exprcoef, exprgraphnodecomp, nchildren);
12471  for( p = 0; p < nparentcands; ++p )
12472  {
12473  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12474  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12475 
12476  candcoef = (SCIP_Real*)parentcands[p]->data.data;
12477  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12478 
12479  /* sort children of parent candidate */
12480  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, exprgraphnodecomp, nchildren);
12481 
12482  /* check if children and coefficients in parent candidate and expression are the same */
12483  for( i = 0; i < nchildren; ++i )
12484  {
12485  if( children[i] != parentcands[p]->children[i] )
12486  break;
12487  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
12488  break;
12489  }
12490  if( i < nchildren )
12491  continue;
12492 
12493  /* yeah, found an exact match */
12494  *parent = parentcands[p];
12495  break;
12496  }
12497 
12498  break;
12499  }
12500 
12501  case SCIP_EXPR_QUADRATIC:
12502  {
12503  SCIP_EXPRDATA_QUADRATIC* exprdata;
12504  SCIP_Real* exprlincoef;
12505  SCIP_Real* candlincoef;
12506  SCIP_EXPRDATA_QUADRATIC* canddata;
12507  int* perm;
12508  int* invperm;
12509 
12510  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
12511  exprlincoef = exprdata->lincoefs;
12512 
12513  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
12514 
12515  /* sort expr->children and childnodes and store inverse permutation in invperm */
12516  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12517  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12518  for( i = 0; i < nchildren; ++i )
12519  invperm[i] = i; /*lint !e644*/
12520 
12521  if( exprlincoef != NULL )
12522  if( exprchildren != NULL )
12523  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12524  else
12525  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12526  else
12527  if( exprchildren != NULL )
12528  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12529  else
12530  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12531 
12532  /* compute permutation from its inverse */
12533  for( i = 0; i < nchildren; ++i )
12534  perm[invperm[i]] = i; /*lint !e644*/
12535 
12536  /* apply permuation to exprdata->quadelems and sort again */
12537  for( i = 0; i < exprdata->nquadelems; ++i )
12538  {
12539  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
12540  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
12541  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
12542  {
12543  int tmp;
12544  tmp = exprdata->quadelems[i].idx1;
12545  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
12546  exprdata->quadelems[i].idx2 = tmp;
12547  }
12548  }
12549  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
12550  exprdata->sorted = TRUE;
12551 
12552  for( p = 0; p < nparentcands; ++p )
12553  {
12554  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12555  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12556 
12557  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
12558  candlincoef = canddata->lincoefs;
12559  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
12560  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12561 
12562  /* sort parentcands[p]->children and store inverse permutation in invperm */
12563  for( i = 0; i < nchildren; ++i )
12564  invperm[i] = i;
12565 
12566  if( candlincoef != NULL )
12567  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, exprgraphnodecomp, parentcands[p]->nchildren);
12568  else
12569  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12570 
12571  /* compute permutation from its inverse */
12572  for( i = 0; i < nchildren; ++i )
12573  perm[invperm[i]] = i;
12574 
12575  /* apply permutation to canddata->quadelems */
12576  for( i = 0; i < canddata->nquadelems; ++i )
12577  {
12578  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
12579  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
12580  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
12581  {
12582  int tmp;
12583  tmp = canddata->quadelems[i].idx1;
12584  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
12585  canddata->quadelems[i].idx2 = tmp;
12586  }
12587  }
12588  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
12589  canddata->sorted = TRUE;
12590 
12591  /* check if children and linear coefficients in parent candidate and expression are the same */
12592  for( i = 0; i < nchildren; ++i )
12593  {
12594  if( children[i] != parentcands[p]->children[i] )
12595  break;
12596  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
12597  break;
12598  }
12599  if( i < nchildren )
12600  continue;
12601 
12602  assert(exprdata->nquadelems == canddata->nquadelems);
12603  for( i = 0; i < exprdata->nquadelems; ++i )
12604  {
12605  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
12606  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
12607  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
12608  break;
12609  }
12610  if( i == exprdata->nquadelems )
12611  {
12612  /* yeah, parentcands[p] is same quadratic expression as expr */
12613  *parent = parentcands[p];
12614  break;
12615  }
12616  }
12617 
12618  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12619  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12620 
12621  break;
12622  }
12623 
12624  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
12625  case SCIP_EXPR_POLYNOMIAL:
12626  {
12627  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
12628  SCIP_EXPRDATA_POLYNOMIAL* canddata;
12629  int* perm;
12630  int* invperm;
12631 
12632  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
12633 
12634  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
12635 
12636  /* sort exprchildren and childnodes and store inverse permutation in invperm */
12637  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12638  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12639  for( i = 0; i < nchildren; ++i )
12640  invperm[i] = i; /*lint !e644*/
12641 
12642  if( exprchildren != NULL )
12643  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12644  else
12645  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12646 
12647  /* compute permutation from its inverse */
12648  for( i = 0; i < nchildren; ++i )
12649  perm[invperm[i]] = i; /*lint !e644*/
12650 
12651  /* apply permutation to exprdata and sort again */
12652  polynomialdataApplyChildmap(exprdata, perm);
12653  polynomialdataSortMonomials(exprdata);
12654 
12655  for( p = 0; p < nparentcands; ++p )
12656  {
12657  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12658  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12659 
12660  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
12661  assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
12662  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12663 
12664  /* sort parentcands[p]->children and store inverse permutation in invperm */
12665  for( i = 0; i < nchildren; ++i )
12666  invperm[i] = i;
12667 
12668  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12669 
12670  /* compute permutation from its inverse */
12671  for( i = 0; i < nchildren; ++i )
12672  perm[invperm[i]] = i;
12673 
12674  /* apply permutation to canddata and sort again */
12675  polynomialdataApplyChildmap(canddata, perm);
12676  polynomialdataSortMonomials(canddata);
12677 
12678  /* check if children are equal */
12679  for( i = 0; i < nchildren; ++i )
12680  if( children[i] != parentcands[p]->children[i] )
12681  break;
12682  if( i < nchildren )
12683  continue;
12684 
12685  /* check if monomials are equal */
12686  for( i = 0; i < exprdata->nmonomials; ++i )
12687  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
12688  break;
12689  if( i == exprdata->nmonomials )
12690  {
12691  /* yeah, parentcands[p] is same polynomial expression as expr */
12692  *parent = parentcands[p];
12693  break;
12694  }
12695  }
12696 
12697  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12698  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12699 
12700  break;
12701  }
12702 
12703  case SCIP_EXPR_USER:
12704  {
12705  /* @todo need comparison function on user data to decide whether a parent candidate fits */
12706  break;
12707  }
12708 
12709  case SCIP_EXPR_VARIDX:
12710  case SCIP_EXPR_PARAM:
12711  case SCIP_EXPR_CONST:
12712  case SCIP_EXPR_LAST:
12713  SCIPerrorMessage("expression operand %d unexpected here\n", op);
12714  return SCIP_ERROR;
12715  }
12716 
12717  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
12718 
12719  return SCIP_OKAY;
12720 }
12721 
12722 /** adds an expression into an expression graph
12723  *
12724  * Enables corresponding nodes.
12725  */
12726 static
12728  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12729  SCIP_EXPR* expr, /**< expression to add */
12730  void** vars, /**< variables corresponding to VARIDX expressions */
12731  SCIP_Real* params, /**< parameter values */
12732  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
12733  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12734  )
12735 {
12736  SCIP_EXPRGRAPHNODE** childnodes;
12737  SCIP_Bool childisnew;
12738  SCIP_Bool nochildisnew;
12739  SCIP_EXPROPDATA opdata;
12740  int i;
12741 
12742  assert(exprgraph != NULL);
12743  assert(expr != NULL);
12744  assert(exprnode != NULL);
12745  assert(exprnodeisnew != NULL);
12746 
12747  if( expr->op == SCIP_EXPR_VARIDX )
12748  {
12749  /* find node corresponding to variable and add if not existing yet */
12750  assert(expr->nchildren == 0);
12751 
12752  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12753  assert(*exprnode != NULL);
12754  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12755  assert((*exprnode)->data.intval >= 0);
12756  assert((*exprnode)->data.intval < exprgraph->nvars);
12757  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12758 
12759  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12760 
12761  return SCIP_OKAY;
12762  }
12763 
12764  if( expr->op == SCIP_EXPR_CONST )
12765  {
12766  /* find node corresponding to constant and add if not existing yet */
12767  assert(expr->nchildren == 0);
12768 
12769  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12770  assert(*exprnode != NULL);
12771  assert((*exprnode)->op == SCIP_EXPR_CONST);
12772  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
12773 
12774  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12775 
12776  return SCIP_OKAY;
12777  }
12778 
12779  if( expr->op == SCIP_EXPR_PARAM )
12780  {
12781  /* find node corresponding to constant corresponding to parameter and add if not existing yet */
12782  assert(expr->nchildren == 0);
12783  assert(params != NULL);
12784 
12785  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, params[expr->data.intval], exprnode) );
12786  assert(*exprnode != NULL);
12787  assert((*exprnode)->op == SCIP_EXPR_CONST);
12788  assert((*exprnode)->data.dbl == params[expr->data.intval]); /*lint !e777*/
12789 
12790  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12791 
12792  return SCIP_OKAY;
12793  }
12794 
12795  /* expression should be variable or constant or have children */
12796  assert(expr->nchildren > 0);
12797 
12798  /* add children expressions into expression graph
12799  * check if we can find a common parent
12800  */
12801  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12802  nochildisnew = TRUE;
12803  for( i = 0; i < expr->nchildren; ++i )
12804  {
12805  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, params, &childnodes[i], &childisnew) ); /*lint !e644*/
12806  assert(childnodes[i] != NULL);
12807  nochildisnew &= !childisnew; /*lint !e514*/
12808  }
12809 
12810  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12811  if( nochildisnew )
12812  {
12813  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12814 
12815  if( *exprnode != NULL )
12816  {
12817  /* node already existing, make sure it is enabled */
12818  (*exprnode)->enabled = TRUE;
12819  *exprnodeisnew = FALSE;
12820 
12821  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12822  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12823  * SCIPdebugPrintf("\n");
12824  */
12825 
12826  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12827  return SCIP_OKAY;
12828  }
12829  }
12830 
12831  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12832 
12833  /* copy expression data */
12834  if( exprOpTable[expr->op].copydata != NULL )
12835  {
12836  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12837  }
12838  else
12839  {
12840  opdata = expr->data;
12841  }
12842 
12843  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12844  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12845  *exprnodeisnew = TRUE;
12846 
12847  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12848 
12849  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12850  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12851  * SCIPdebugPrintf("\n");
12852  */
12853 
12854  return SCIP_OKAY;
12855 }
12856 
12857 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12858 static
12860  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12861  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12862  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12863  )
12864 {
12865  SCIP_EXPRGRAPHNODE* node;
12866  int i;
12867  int p;
12868 
12869  assert(exprgraph != NULL);
12870  assert(clearreverseprop != NULL);
12871  assert(boundchanged != NULL);
12872 
12873  *boundchanged = FALSE;
12874  for( i = 0; i < exprgraph->nvars; ++i )
12875  {
12876  node = exprgraph->varnodes[i];
12877 
12878  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12879  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12880  {
12882  continue;
12883  }
12884 
12885  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12886  {
12887  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12888  SCIP_Real tmp;
12889 
12890  tmp = exprgraph->varbounds[i].inf;
12891  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12892  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12893  }
12894 
12895  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12896  +exprgraph->varbounds[i].sup > node->bounds.sup )
12897  {
12898  for( p = 0; p < node->nparents; ++p )
12900 
12901  node->bounds = exprgraph->varbounds[i];
12902  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12903 
12904  *boundchanged = TRUE;
12905 
12906  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12907  *clearreverseprop = TRUE;
12908  }
12909  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12910  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12911  {
12912  for( p = 0; p < node->nparents; ++p )
12914 
12915  node->bounds = exprgraph->varbounds[i];
12916  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12917 
12918  *boundchanged = TRUE;
12919  }
12920  else
12921  {
12922  node->bounds = exprgraph->varbounds[i];
12923  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12924  }
12925 
12927  }
12928 }
12929 
12930 /**@} */
12931 
12932 /**@name Expression graph node methods */
12933 /**@{ */
12934 
12935 /* In debug mode, the following methods are implemented as function calls to ensure
12936  * type validity.
12937  * In optimized mode, the methods are implemented as defines to improve performance.
12938  * However, we want to have them in the library anyways, so we have to undef the defines.
12939  */
12940 
12941 #undef SCIPexprgraphCaptureNode
12942 #undef SCIPexprgraphIsNodeEnabled
12943 #undef SCIPexprgraphGetNodeNChildren
12944 #undef SCIPexprgraphGetNodeChildren
12945 #undef SCIPexprgraphGetNodeNParents
12946 #undef SCIPexprgraphGetNodeParents
12947 #undef SCIPexprgraphGetNodeDepth
12948 #undef SCIPexprgraphGetNodePosition
12949 #undef SCIPexprgraphGetNodeOperator
12950 #undef SCIPexprgraphGetNodeOperatorIndex
12951 #undef SCIPexprgraphGetNodeOperatorReal
12952 #undef SCIPexprgraphGetNodeVar
12953 #undef SCIPexprgraphGetNodeRealPowerExponent
12954 #undef SCIPexprgraphGetNodeIntPowerExponent
12955 #undef SCIPexprgraphGetNodeSignPowerExponent
12956 #undef SCIPexprgraphGetNodeLinearCoefs
12957 #undef SCIPexprgraphGetNodeLinearConstant
12958 #undef SCIPexprgraphGetNodeQuadraticConstant
12959 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12960 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12961 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12962 #undef SCIPexprgraphGetNodePolynomialMonomials
12963 #undef SCIPexprgraphGetNodePolynomialNMonomials
12964 #undef SCIPexprgraphGetNodePolynomialConstant
12965 #undef SCIPexprgraphGetNodeUserData
12966 #undef SCIPexprgraphHasNodeUserEstimator
12967 #undef SCIPexprgraphGetNodeBounds
12968 #undef SCIPexprgraphGetNodeVal
12969 #undef SCIPexprgraphGetNodeCurvature
12970 
12971 /** captures node, i.e., increases number of uses */
12973  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12974  )
12975 {
12976  assert(node->nuses >= 0);
12977 
12978  SCIPdebugMessage("capture node %p\n", (void*)node);
12979 
12980  ++node->nuses;
12981 }
12982 
12983 /** returns whether a node is currently enabled */
12985  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12986  )
12987 {
12988  assert(node != NULL);
12989 
12990  return node->enabled;
12991 }
12992 
12993 /** gets number of children of a node in an expression graph */
12995  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12996  )
12997 {
12998  assert(node != NULL);
12999 
13000  return node->nchildren;
13001 }
13002 
13003 /** gets children of a node in an expression graph */
13005  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13006  )
13007 {
13008  assert(node != NULL);
13009 
13010  return node->children;
13011 }
13012 
13013 /** gets number of parents of a node in an expression graph */
13015  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13016  )
13017 {
13018  assert(node != NULL);
13019 
13020  return node->nparents;
13021 }
13022 
13023 /** gets parents of a node in an expression graph */
13025  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13026  )
13027 {
13028  assert(node != NULL);
13029 
13030  return node->parents;
13031 }
13032 
13033 /** gets depth of node in expression graph */
13035  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13036  )
13037 {
13038  assert(node != NULL);
13039 
13040  return node->depth;
13041 }
13042 
13043 /** gets position of node in expression graph at its depth level */
13045  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13046  )
13047 {
13048  assert(node != NULL);
13049 
13050  return node->pos;
13051 }
13052 
13053 /** gets operator of a node in an expression graph */
13055  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13056  )
13057 {
13058  assert(node != NULL);
13059 
13060  return node->op;
13061 }
13062 
13063 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
13065  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13066  )
13067 {
13068  assert(node != NULL);
13069  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
13070 
13071  return node->data.intval;
13072 }
13073 
13074 /** gives real belonging to a SCIP_EXPR_CONST operand */
13076  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13077  )
13078 {
13079  assert(node != NULL);
13080  assert(node->op == SCIP_EXPR_CONST);
13081 
13082  return node->data.dbl;
13083 }
13084 
13085 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
13087  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13088  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13089  )
13090 {
13091  assert(exprgraph != NULL);
13092  assert(node != NULL);
13093  assert(node->op == SCIP_EXPR_VARIDX);
13094  assert(node->data.intval >= 0);
13095  assert(node->data.intval < exprgraph->nvars);
13096 
13097  return exprgraph->vars[node->data.intval];
13098 }
13099 
13100 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
13102  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13103  )
13104 {
13105  assert(node != NULL);
13106  assert(node->op == SCIP_EXPR_REALPOWER);
13107 
13108  return node->data.dbl;
13109 }
13110 
13111 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
13113  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13114  )
13115 {
13116  assert(node != NULL);
13117  assert(node->op == SCIP_EXPR_INTPOWER);
13118 
13119  return node->data.intval;
13120 }
13121 
13122 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
13124  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13125  )
13126 {
13127  assert(node != NULL);
13128  assert(node->op == SCIP_EXPR_SIGNPOWER);
13129 
13130  return node->data.dbl;
13131 }
13132 
13133 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
13135  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13136  )
13137 {
13138  assert(node != NULL);
13139  assert(node->op == SCIP_EXPR_LINEAR);
13140 
13141  return (SCIP_Real*)node->data.data;
13142 }
13143 
13144 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
13146  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13147  )
13148 {
13149  assert(node != NULL);
13150  assert(node->op == SCIP_EXPR_LINEAR);
13151  assert(node->data.data != NULL);
13152 
13153  return ((SCIP_Real*)node->data.data)[node->nchildren];
13154 }
13155 
13156 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
13158  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13159  )
13160 {
13161  assert(node != NULL);
13162  assert(node->op == SCIP_EXPR_QUADRATIC);
13163  assert(node->data.data != NULL);
13164 
13165  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
13166 }
13167 
13168 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
13170  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13171  )
13172 {
13173  assert(node != NULL);
13174  assert(node->op == SCIP_EXPR_QUADRATIC);
13175  assert(node->data.data != NULL);
13176 
13177  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
13178 }
13179 
13180 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13182  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13183  )
13184 {
13185  assert(node != NULL);
13186  assert(node->op == SCIP_EXPR_QUADRATIC);
13187  assert(node->data.data != NULL);
13188 
13189  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
13190 }
13191 
13192 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13194  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13195  )
13196 {
13197  assert(node != NULL);
13198  assert(node->op == SCIP_EXPR_QUADRATIC);
13199  assert(node->data.data != NULL);
13200 
13201  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
13202 }
13203 
13204 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13206  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13207  )
13208 {
13209  assert(node != NULL);
13210  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13211  assert(node->data.data != NULL);
13212 
13213  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
13214 }
13215 
13216 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13218  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13219  )
13220 {
13221  assert(node != NULL);
13222  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13223  assert(node->data.data != NULL);
13224 
13225  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
13226 }
13227 
13228 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
13230  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13231  )
13232 {
13233  assert(node != NULL);
13234  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13235  assert(node->data.data != NULL);
13236 
13237  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
13238 }
13239 
13240 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
13241  *
13242  * Assumes that curvature of children and bounds of children and node itself are valid.
13243  */
13245  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13246  int monomialidx, /**< index of monomial */
13247  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
13248  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
13249  )
13250 {
13251  SCIP_EXPRDATA_MONOMIAL* monomial;
13252  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13253  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13254  SCIP_INTERVAL* childbounds = NULL;
13255  SCIP_EXPRCURV* childcurv = NULL;
13256  SCIP_EXPRGRAPHNODE* child;
13257  SCIP_RETCODE retcode = SCIP_OKAY;
13258  int i;
13259 
13260  assert(node != NULL);
13261  assert(node->depth >= 0); /* node should be in graph */
13262  assert(node->pos >= 0); /* node should be in graph */
13263  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13264  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
13265  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13266  assert(node->data.data != NULL);
13267  assert(monomialidx >= 0);
13268  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
13269  assert(curv != NULL);
13270 
13271  if( SCIPintervalIsEmpty(infinity, node->bounds) )
13272  {
13273  *curv = SCIP_EXPRCURV_LINEAR;
13274  return SCIP_OKAY;
13275  }
13276 
13277  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
13278  assert(monomial != NULL);
13279 
13280  /* if many children, get large enough memory to store children bounds */
13281  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13282  {
13283  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13284  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, monomial->nfactors), TERMINATE );
13285  }
13286  else
13287  {
13288  childbounds = childboundsstatic;
13289  childcurv = childcurvstatic;
13290  }
13291 
13292  /* assemble bounds and curvature of children */
13293  for( i = 0; i < monomial->nfactors; ++i )
13294  {
13295  child = node->children[monomial->childidxs[i]];
13296  assert(child != NULL);
13297 
13298  /* child should have valid and non-empty bounds */
13299  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13300  assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13301  /* nodes at depth 0 are always linear */
13302  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13303 
13304  childbounds[i] = child->bounds; /*lint !e644*/
13305  childcurv[i] = child->curv; /*lint !e644*/
13306  }
13307 
13308  /* check curvature */
13309  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13310  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13311 
13312  /* free memory, if allocated before */
13313 TERMINATE:
13314  if( childbounds != childboundsstatic )
13315  {
13316  BMSfreeMemoryArrayNull(&childbounds);
13317  BMSfreeMemoryArrayNull(&childcurv);
13318  }
13319 
13320  return retcode;
13321 }
13322 
13323 /** gives the user data belonging to a SCIP_EXPR_USER expression */
13325  SCIP_EXPRGRAPHNODE* node
13326  )
13327 {
13328  assert(node != NULL);
13329  assert(node->op == SCIP_EXPR_USER);
13330  assert(node->data.data != NULL);
13331 
13332  return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13333 }
13334 
13335 /** indicates whether a user expression has the estimator callback defined */
13337  SCIP_EXPRGRAPHNODE* node
13338  )
13339 {
13340  assert(node != NULL);
13341  assert(node->op == SCIP_EXPR_USER);
13342  assert(node->data.data != NULL);
13343 
13344  return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13345 }
13346 
13347 /** gets bounds of a node in an expression graph */
13349  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13350  )
13351 {
13352  assert(node != NULL);
13353 
13354  return node->bounds;
13355 }
13356 
13357 /** gets value of expression associated to node from last evaluation call */
13359  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13360  )
13361 {
13362  assert(node != NULL);
13363 
13364  return node->value;
13365 }
13366 
13367 /** gets curvature of expression associated to node from last curvature check call */
13369  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13370  )
13371 {
13372  assert(node != NULL);
13373 
13374  return node->curv;
13375 }
13376 
13377 /** creates an expression graph node */
13379  BMS_BLKMEM* blkmem, /**< block memory */
13380  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13381  SCIP_EXPROP op, /**< operator type of expression */
13382  ...
13383  )
13384 {
13385  va_list ap;
13386  SCIP_EXPROPDATA opdata;
13387 
13388  assert(blkmem != NULL);
13389  assert(node != NULL);
13390 
13391  *node = NULL;
13392 
13393  switch( op )
13394  {
13395  case SCIP_EXPR_VARIDX :
13396  case SCIP_EXPR_PARAM :
13397  case SCIP_EXPR_CONST :
13398  case SCIP_EXPR_LINEAR :
13399  case SCIP_EXPR_QUADRATIC :
13400  case SCIP_EXPR_POLYNOMIAL:
13401  case SCIP_EXPR_USER :
13402  {
13403  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
13404  SCIPABORT();
13405  return SCIP_ERROR; /*lint !e527*/
13406  }
13407 
13408  /* operands without data */
13409  case SCIP_EXPR_PLUS :
13410  case SCIP_EXPR_MINUS :
13411  case SCIP_EXPR_MUL :
13412  case SCIP_EXPR_DIV :
13413  case SCIP_EXPR_MIN :
13414  case SCIP_EXPR_MAX :
13415  case SCIP_EXPR_SQUARE :
13416  case SCIP_EXPR_SQRT :
13417  case SCIP_EXPR_EXP :
13418  case SCIP_EXPR_LOG :
13419  case SCIP_EXPR_SIN :
13420  case SCIP_EXPR_COS :
13421  case SCIP_EXPR_TAN :
13422  /* case SCIP_EXPR_ERF : */
13423  /* case SCIP_EXPR_ERFI: */
13424  case SCIP_EXPR_ABS :
13425  case SCIP_EXPR_SIGN :
13426  case SCIP_EXPR_SUM :
13427  case SCIP_EXPR_PRODUCT:
13428  opdata.data = NULL;
13429  break;
13430 
13431  case SCIP_EXPR_REALPOWER:
13432  case SCIP_EXPR_SIGNPOWER:
13433  {
13434  va_start(ap, op ); /*lint !e838*/
13435  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
13436  va_end( ap ); /*lint !e826*/
13437 
13438  break;
13439  }
13440 
13441  case SCIP_EXPR_INTPOWER:
13442  {
13443  va_start(ap, op ); /*lint !e838*/
13444  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
13445  va_end( ap ); /*lint !e826*/
13446 
13447  break;
13448  }
13449 
13450  case SCIP_EXPR_LAST:
13451  SCIPABORT();
13452  return SCIP_INVALIDDATA; /*lint !e527*/
13453  }
13454 
13455  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13456 
13457  return SCIP_OKAY;
13458 }
13459 
13460 /** creates an expression graph node for a linear expression */
13462  BMS_BLKMEM* blkmem, /**< block memory */
13463  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13464  int ncoefs, /**< number of coefficients */
13465  SCIP_Real* coefs, /**< coefficients of linear expression */
13466  SCIP_Real constant /**< constant of linear expression */
13467  )
13468 {
13469  SCIP_EXPROPDATA opdata;
13470  SCIP_Real* data;
13471 
13472  assert(blkmem != NULL);
13473  assert(node != NULL);
13474 
13475  /* we store the coefficients and the constant in a single array and make this our operand data */
13476  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13477  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
13478  data[ncoefs] = constant;
13479 
13480  opdata.data = data;
13481  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13482 
13483  return SCIP_OKAY;
13484 }
13485 
13486 /** creates an expression graph node for a quadratic expression */
13488  BMS_BLKMEM* blkmem, /**< block memory */
13489  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13490  int nchildren, /**< number of children */
13491  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
13492  int nquadelems, /**< number of quadratic elements */
13493  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
13494  SCIP_Real constant /**< constant */
13495  )
13496 {
13497  SCIP_EXPROPDATA opdata;
13499 
13500  assert(blkmem != NULL);
13501  assert(node != NULL);
13502  assert(quadelems != NULL || nquadelems == 0);
13503 
13504  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13505 
13506  opdata.data = data;
13507  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13508 
13509  return SCIP_OKAY;
13510 }
13511 
13512 /** creates an expression graph node for a polynomial expression */
13514  BMS_BLKMEM* blkmem, /**< block memory */
13515  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13516  int nmonomials, /**< number of monomials */
13517  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13518  SCIP_Real constant, /**< constant of polynomial */
13519  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13520  )
13521 {
13522  SCIP_EXPROPDATA opdata;
13524 
13525  assert(blkmem != NULL);
13526  assert(node != NULL);
13527  assert(monomials != NULL || nmonomials == 0);
13528 
13529  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13530 
13531  opdata.data = data;
13532  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13533 
13534  return SCIP_OKAY;
13535 }
13536 
13537 /** adds monomials to an expression graph node that is a polynomial expression */
13539  BMS_BLKMEM* blkmem, /**< block memory */
13540  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
13541  int nmonomials, /**< number of monomials */
13542  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13543  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13544  )
13545 {
13546  assert(blkmem != NULL);
13547  assert(node != NULL);
13549  assert(monomials != NULL || nmonomials == 0);
13550 
13551  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13552 
13553  return SCIP_OKAY;
13554 }
13555 
13556 /** creates an expression graph node for a user expression */
13558  BMS_BLKMEM* blkmem, /**< block memory */
13559  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13560  SCIP_USEREXPRDATA* data, /**< user data for expression, node assumes ownership */
13561  SCIP_EXPRINTCAPABILITY evalcapability, /**< evaluation capability */
13562  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
13563  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function */
13564  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
13565  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function */
13566  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13567  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13568  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
13569  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
13570  )
13571 {
13572  SCIP_EXPROPDATA opdata;
13573  SCIP_EXPRDATA_USER* exprdata;
13574 
13575  assert(blkmem != NULL);
13576  assert(node != NULL);
13577  assert(eval != NULL);
13578  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
13579  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13580  assert(copydata != NULL || data == NULL);
13581  assert(freedata != NULL || data == NULL);
13582 
13583  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13584 
13585  exprdata->userdata = data;
13586  exprdata->evalcapability = evalcapability;
13587  exprdata->eval = eval;
13588  exprdata->estimate = estimate;
13589  exprdata->inteval = inteval;
13590  exprdata->curv = curv;
13591  exprdata->prop = prop;
13592  exprdata->copydata = copydata;
13593  exprdata->freedata = freedata;
13594  exprdata->print = print;
13595 
13596  opdata.data = (void*) exprdata;
13597 
13598  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13599 
13600  return SCIP_OKAY;
13601 }
13602 
13603 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13604  *
13605  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13606  * If the node is a linear expression, it may be freed.
13607  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13608  * It is assumed that the user had captured the node.
13609  * It is assumed that the expression graph has been simplified before.
13610  */
13612  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13613  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
13614  int linvarssize, /**< length of linvars and lincoefs arrays */
13615  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
13616  void** linvars, /**< buffer to store variables of linear part */
13617  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
13618  SCIP_Real* constant /**< buffer to store constant part */
13619  )
13620 {
13621  int orignvars;
13622  int* varsusage;
13623  SCIP_EXPRGRAPHNODE* orignode;
13624  SCIP_Bool havechange;
13625  int i;
13626 
13627  assert(exprgraph != NULL);
13628  assert(node != NULL);
13629  assert(*node != NULL);
13630  assert((*node)->nuses > 0);
13631  assert(nlinvars != NULL);
13632  assert(linvars != NULL || linvarssize == 0);
13633  assert(lincoefs != NULL || linvarssize == 0);
13634  assert(constant != NULL);
13635 
13636  *constant = 0.0;
13637  *nlinvars = 0;
13638 
13639  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13640 
13641  /* do some obvious and easy cases */
13642  switch( (*node)->op )
13643  {
13644  case SCIP_EXPR_VARIDX:
13645  {
13646  if( linvarssize >= 1 )
13647  {
13648  *nlinvars = 1;
13649  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
13650  lincoefs[0] = 1.0; /*lint !e613*/
13651 
13652  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13653  }
13654  return SCIP_OKAY;
13655  }
13656 
13657  case SCIP_EXPR_CONST:
13658  {
13659  *constant = (*node)->data.dbl;
13660  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13661 
13662  return SCIP_OKAY;
13663  }
13664 
13665  case SCIP_EXPR_REALPOWER:
13666  case SCIP_EXPR_SIGNPOWER:
13667  {
13668  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13669  {
13670  *nlinvars = 1;
13671  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13672  lincoefs[0] = 1.0; /*lint !e613*/
13673 
13674  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13675  }
13676  return SCIP_OKAY;
13677  }
13678 
13679  case SCIP_EXPR_INTPOWER:
13680  {
13681  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13682  {
13683  *nlinvars = 1;
13684  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13685  lincoefs[0] = 1.0; /*lint !e613*/
13686 
13687  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13688  }
13689  return SCIP_OKAY;
13690  }
13691 
13692  case SCIP_EXPR_PLUS:
13693  {
13694  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13695  {
13696  *constant = (*node)->children[0]->data.dbl;
13697  *nlinvars = 1;
13698  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13699  lincoefs[0] = 1.0; /*lint !e613*/
13700 
13701  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13702 
13703  return SCIP_OKAY;
13704  }
13705  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13706  {
13707  *constant = (*node)->children[1]->data.dbl;
13708  *nlinvars = 1;
13709  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13710  lincoefs[0] = 1.0; /*lint !e613*/
13711 
13712  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13713 
13714  return SCIP_OKAY;
13715  }
13716  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13717  {
13718  *nlinvars = 2;
13719  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13720  lincoefs[0] = 1.0; /*lint !e613*/
13721  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13722  lincoefs[1] = 1.0; /*lint !e613*/
13723 
13724  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13725 
13726  return SCIP_OKAY;
13727  }
13728  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13729  {
13730  /* handle this one later */
13731  break;
13732  }
13733  return SCIP_OKAY;
13734  }
13735 
13736  case SCIP_EXPR_MINUS:
13737  {
13738  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13739  {
13740  *constant = (*node)->children[0]->data.dbl;
13741  *nlinvars = 1;
13742  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13743  lincoefs[0] = -1.0; /*lint !e613*/
13744 
13745  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13746 
13747  return SCIP_OKAY;
13748  }
13749  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13750  {
13751  *constant = -(*node)->children[1]->data.dbl;
13752  *nlinvars = 1;
13753  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13754  lincoefs[0] = 1.0; /*lint !e613*/
13755 
13756  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13757 
13758  return SCIP_OKAY;
13759  }
13760  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13761  {
13762  *nlinvars = 2;
13763  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13764  lincoefs[0] = 1.0; /*lint !e613*/
13765  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13766  lincoefs[1] = -1.0; /*lint !e613*/
13767 
13768  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13769 
13770  return SCIP_OKAY;
13771  }
13772  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13773  {
13774  /* handle this one later */
13775  break;
13776  }
13777  return SCIP_OKAY;
13778  }
13779 
13780  case SCIP_EXPR_MUL:
13781  {
13782  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13783  {
13784  *nlinvars = 1;
13785  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13786  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
13787 
13788  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13789  }
13790  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13791  {
13792  *nlinvars = 1;
13793  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13794  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
13795 
13796  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13797  }
13798  return SCIP_OKAY;
13799  }
13800 
13801  case SCIP_EXPR_DIV:
13802  {
13803  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13804  return SCIP_OKAY;
13805 
13806  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13807  {
13808  *nlinvars = 1;
13809  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13810  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
13811 
13812  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13813  }
13814  return SCIP_OKAY;
13815  }
13816 
13817  case SCIP_EXPR_SQUARE:
13818  case SCIP_EXPR_SQRT:
13819  case SCIP_EXPR_EXP:
13820  case SCIP_EXPR_LOG:
13821  case SCIP_EXPR_SIN:
13822  case SCIP_EXPR_COS:
13823  case SCIP_EXPR_TAN:
13824  /* case SCIP_EXPR_ERF: */
13825  /* case SCIP_EXPR_ERFI: */
13826  case SCIP_EXPR_ABS:
13827  case SCIP_EXPR_SIGN:
13828  case SCIP_EXPR_MIN:
13829  case SCIP_EXPR_MAX:
13830  return SCIP_OKAY;
13831 
13832  case SCIP_EXPR_PRODUCT:
13833  case SCIP_EXPR_USER:
13834  return SCIP_OKAY;
13835 
13836  case SCIP_EXPR_SUM:
13837  case SCIP_EXPR_LINEAR:
13838  case SCIP_EXPR_QUADRATIC:
13839  case SCIP_EXPR_POLYNOMIAL:
13840  default:
13841  {
13842  /* check if there is a child that is a variable */
13843  for( i = 0; i < (*node)->nchildren; ++i )
13844  {
13845  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13846  break;
13847  }
13848 
13849  if( i == (*node)->nchildren )
13850  return SCIP_OKAY;
13851 
13852  break;
13853  }
13854  } /*lint !e788*/
13855 
13856  /* count how often variables are used in this expression */
13857  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13858  orignvars = exprgraph->nvars;
13859  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13860  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
13861 
13862  exprgraphNodeGetVarsUsage(*node, varsusage);
13863 
13864  /* duplicate node if it has parents or more than one user */
13865  orignode = NULL;
13866  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13867  {
13868  SCIP_EXPROPDATA data;
13869 
13870  orignode = *node;
13871 
13872  if( exprOpTable[orignode->op].copydata != NULL )
13873  {
13874  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13875  }
13876  else
13877  data = orignode->data;
13878 
13879  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13880  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13881  SCIPexprgraphCaptureNode(*node);
13882  }
13883 
13884  havechange = FALSE;
13885  /* split up constant and linear part */
13886  switch( (*node)->op )
13887  {
13888  case SCIP_EXPR_PLUS:
13889  case SCIP_EXPR_MINUS:
13890  {
13891  SCIP_EXPRGRAPHNODE* varchild;
13892  SCIP_EXPRGRAPHNODE* otherchild;
13893  int varidx;
13894 
13895  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13896  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13897  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13898  assert(linvarssize >= 1);
13899 
13900  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13901  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13902  varidx = varchild->data.intval;
13903  /* if variable is used in other child (which should be nonlinear), we don't take it */
13904  if( varsusage[varidx] > 1 )
13905  break;
13906 
13907  /* add to linear variables */
13908  *nlinvars = 1;
13909  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13910  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13911  lincoefs[0] = -1.0; /*lint !e613*/
13912  else
13913  lincoefs[0] = 1.0; /*lint !e613*/
13914 
13915  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13916  {
13917  /* replace *node by otherchild */
13918  SCIPexprgraphCaptureNode(otherchild);
13919  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13920  *node = otherchild;
13921  }
13922  else
13923  {
13924  SCIP_Real* lindata;
13925 
13926  /* turn *node into linear expression -1.0 * otherchild */
13927 
13928  /* reduce to one child */
13929  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13930  (*node)->children[0] = otherchild;
13931  (*node)->nchildren = 1;
13932  (*node)->op = SCIP_EXPR_LINEAR;
13933 
13934  /* setup linear data -1.0 * child0 + 0.0 */
13935  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13936  lindata[0] = -1.0;
13937  lindata[1] = 0.0;
13938  (*node)->data.data = (void*)lindata;
13939 
13940  /* remove *node as parent of varchild */
13941  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13942  }
13943 
13944  havechange = TRUE;
13945 
13946  break;
13947  }
13948 
13949  case SCIP_EXPR_SUM:
13950  {
13951  int nchildren;
13952 
13953  i = 0;
13954  nchildren = (*node)->nchildren;
13955  while( i < nchildren )
13956  {
13957  /* sort out constants */
13958  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13959  {
13960  *constant += (*node)->children[i]->data.dbl;
13961  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13962 
13963  if( i < nchildren-1 )
13964  {
13965  (*node)->children[i] = (*node)->children[nchildren-1];
13966  (*node)->children[nchildren-1] = NULL;
13967  }
13968  --nchildren;
13969 
13970  continue;
13971  }
13972 
13973  /* keep every child that is not a constant or variable */
13974  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13975  {
13976  ++i;
13977  continue;
13978  }
13979 
13980  /* skip variables that are used in other parts of the expression */
13981  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13982  {
13983  ++i;
13984  continue;
13985  }
13986 
13987  /* move variable into linear part, if still space */
13988  if( *nlinvars < linvarssize )
13989  {
13990  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13991  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13992  ++*nlinvars;
13993 
13994  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13995  if( i < nchildren-1 )
13996  {
13997  (*node)->children[i] = (*node)->children[nchildren-1];
13998  (*node)->children[nchildren-1] = NULL;
13999  }
14000  --nchildren;
14001 
14002  continue;
14003  }
14004  }
14005  assert(i == nchildren);
14006 
14007  if( nchildren == 0 )
14008  {
14009  /* all children were removed */
14010  havechange = TRUE;
14011  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14012  (*node)->nchildren = 0;
14013  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14014  break;
14015  }
14016 
14017  if( nchildren < (*node)->nchildren )
14018  {
14019  /* some children were removed */
14020  havechange = TRUE;
14021  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14022  (*node)->nchildren = nchildren;
14023  }
14024 
14025  if( havechange && (*node)->nchildren == 1 )
14026  {
14027  /* replace node by its child */
14028  SCIP_EXPRGRAPHNODE* child;
14029 
14030  child = (*node)->children[0];
14031  SCIPexprgraphCaptureNode(child);
14032  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14033  *node = child;
14034 
14035  break;
14036  }
14037 
14038  break;
14039  }
14040 
14041  case SCIP_EXPR_LINEAR:
14042  {
14043  int nchildren;
14044  SCIP_Real* coefs;
14045 
14046  coefs = (SCIP_Real*)(*node)->data.data;
14047  assert(coefs != NULL);
14048 
14049  /* remove constant, if nonzero */
14050  if( coefs[(*node)->nchildren] != 0.0 )
14051  {
14052  *constant = coefs[(*node)->nchildren];
14053  coefs[(*node)->nchildren] = 0.0;
14054  havechange = TRUE;
14055  }
14056 
14057  i = 0;
14058  nchildren = (*node)->nchildren;
14059  while( i < nchildren )
14060  {
14061  /* sort out constants */
14062  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
14063  {
14064  *constant += coefs[i] * (*node)->children[i]->data.dbl;
14065  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14066 
14067  if( i < nchildren-1 )
14068  {
14069  (*node)->children[i] = (*node)->children[nchildren-1];
14070  (*node)->children[nchildren-1] = NULL;
14071  coefs[i] = coefs[nchildren-1];
14072  coefs[nchildren-1] = 0.0;
14073  }
14074  --nchildren;
14075 
14076  continue;
14077  }
14078 
14079  /* keep everything that is not a constant or variable */
14080  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14081  {
14082  ++i;
14083  continue;
14084  }
14085 
14086  /* skip variables that are used in other parts of the expression */
14087  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14088  {
14089  ++i;
14090  continue;
14091  }
14092 
14093  /* move variable into linear part, if still space */
14094  if( *nlinvars < linvarssize )
14095  {
14096  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14097  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
14098  ++*nlinvars;
14099 
14100  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14101  if( i < nchildren-1 )
14102  {
14103  (*node)->children[i] = (*node)->children[nchildren-1];
14104  (*node)->children[nchildren-1] = NULL;
14105  coefs[i] = coefs[nchildren-1];
14106  coefs[nchildren-1] = 0.0;
14107  }
14108  --nchildren;
14109 
14110  continue;
14111  }
14112  }
14113  assert(i == nchildren);
14114 
14115  if( nchildren == 0 )
14116  {
14117  /* all children were removed */
14118  havechange = TRUE;
14119  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14120  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
14121  (*node)->data.data = NULL;
14122  (*node)->nchildren = 0;
14123  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
14124  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14125  break;
14126  }
14127 
14128  if( nchildren < (*node)->nchildren )
14129  {
14130  /* some children were removed */
14131  havechange = TRUE;
14132  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14133  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
14134  coefs[nchildren] = 0.0;
14135  (*node)->data.data = (void*)coefs;
14136  (*node)->nchildren = nchildren;
14137  }
14138 
14139  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
14140  {
14141  /* replace node by its child */
14142  SCIP_EXPRGRAPHNODE* child;
14143 
14144  child = (*node)->children[0];
14145  SCIPexprgraphCaptureNode(child);
14146  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14147  *node = child;
14148 
14149  break;
14150  }
14151 
14152  break;
14153  }
14154 
14155  case SCIP_EXPR_QUADRATIC:
14156  {
14157  SCIP_EXPRDATA_QUADRATIC* quaddata;
14158  SCIP_Bool* childused;
14159  int* childmap;
14160  int nchildren;
14161 
14162  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
14163  assert(quaddata != NULL);
14164 
14165  /* remove constant, if nonzero */
14166  if( quaddata->constant != 0.0 )
14167  {
14168  *constant = quaddata->constant;
14169  quaddata->constant = 0.0;
14170  havechange = TRUE;
14171  }
14172 
14173  /* if there is no linear part or no space left for linear variables, then stop */
14174  if( quaddata->lincoefs == NULL || linvarssize == 0 )
14175  break;
14176 
14177  /* check which childs are used in quadratic terms */
14178  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14179  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14180 
14181  for( i = 0; i < quaddata->nquadelems; ++i )
14182  {
14183  childused[quaddata->quadelems[i].idx1] = TRUE;
14184  childused[quaddata->quadelems[i].idx2] = TRUE;
14185  }
14186 
14187  /* alloc space for mapping of children indices */
14188  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
14189 
14190  nchildren = (*node)->nchildren;
14191  for( i = 0; i < nchildren; ++i )
14192  {
14193  childmap[i] = i; /*lint !e644*/
14194  if( *nlinvars >= linvarssize )
14195  continue;
14196  /* skip child if not variable or also used in quadratic part or other parts of expression */
14197  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14198  continue;
14199  if( childused[i] )
14200  continue;
14201  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14202  continue;
14203 
14204  /* put variable into linear part */
14205  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14206  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
14207  quaddata->lincoefs[i] = 0.0;
14208  ++*nlinvars;
14209 
14210  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14211 
14212  /* move last child to position i */
14213  if( i < nchildren-1 )
14214  {
14215  (*node)->children[i] = (*node)->children[nchildren-1];
14216  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
14217  childused[i] = childused[nchildren-1];
14218  childmap[nchildren-1] = i;
14219  }
14220  --nchildren;
14221  childmap[i] = -1;
14222 
14223  havechange = TRUE;
14224  --i; /* look at i again */
14225  }
14226 
14227  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
14228 
14229  if( nchildren < (*node)->nchildren )
14230  {
14231  /* apply childmap to quadratic term */
14232  for( i = 0; i < quaddata->nquadelems; ++i )
14233  {
14234  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
14235  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
14236  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
14237  {
14238  int tmp;
14239  tmp = quaddata->quadelems[i].idx1;
14240  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
14241  quaddata->quadelems[i].idx2 = tmp;
14242  }
14243  }
14244  quaddata->sorted = FALSE;
14245  }
14246  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
14247 
14248  if( nchildren == 0 )
14249  {
14250  /* all children were removed (so it was actually a linear expression) */
14251  havechange = TRUE;
14252  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14253  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
14254  (*node)->data.data = NULL;
14255  (*node)->nchildren = 0;
14256  (*node)->op = SCIP_EXPR_SUM;
14257  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14258  break;
14259  }
14260 
14261  if( nchildren < (*node)->nchildren )
14262  {
14263  /* reduce number of children */
14264  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14265  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
14266  (*node)->nchildren = nchildren;
14267  }
14268 
14269  break;
14270  }
14271 
14272  case SCIP_EXPR_POLYNOMIAL:
14273  {
14274  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
14275  SCIP_EXPRDATA_MONOMIAL* monomial;
14276  SCIP_Bool* childused;
14277  int childidx;
14278  int j;
14279 
14280  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
14281  assert(polynomialdata != NULL);
14282 
14283  /* make sure linear monomials are merged */
14284  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14285 
14286  /* remove constant, if nonzero */
14287  if( polynomialdata->constant != 0.0 )
14288  {
14289  *constant = polynomialdata->constant;
14290  polynomialdata->constant = 0.0;
14291  havechange = TRUE;
14292  }
14293 
14294  /* if there is no space for linear variables, then stop */
14295  if( linvarssize == 0 )
14296  break;
14297 
14298  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14299  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14300  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14301  for( i = 0; i < polynomialdata->nmonomials; ++i )
14302  {
14303  monomial = polynomialdata->monomials[i];
14304  assert(monomial != NULL);
14305  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14306  continue;
14307  for( j = 0; j < monomial->nfactors; ++j )
14308  {
14309  assert(monomial->childidxs[j] >= 0);
14310  assert(monomial->childidxs[j] < (*node)->nchildren);
14311  childused[monomial->childidxs[j]] = TRUE;
14312  }
14313  }
14314 
14315  /* move linear monomials out of polynomial */
14316  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14317  {
14318  monomial = polynomialdata->monomials[i];
14319  assert(monomial != NULL);
14320 
14321  /* sort out constants */
14322  if( monomial->nfactors == 0 )
14323  {
14324  if( monomial->coef != 0.0 )
14325  {
14326  *constant += monomial->coef;
14327  havechange = TRUE;
14328  }
14329  continue;
14330  }
14331 
14332  if( monomial->nfactors != 1 )
14333  continue;
14334  if( monomial->exponents[0] != 1.0 )
14335  continue;
14336  childidx = monomial->childidxs[0];
14337  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14338  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14339  continue;
14340  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14341  continue;
14342 
14343  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14344 
14345  /* put variable into linear part */
14346  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
14347  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
14348  ++*nlinvars;
14349 
14350  monomial->coef = 0.0;
14351  monomial->nfactors = 0;
14352  polynomialdata->sorted = FALSE;
14353 
14354  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14355  (*node)->children[childidx] = NULL;
14356 
14357  havechange = TRUE;
14358  }
14359 
14360  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14361 
14362  if( *nlinvars > 0 )
14363  {
14364  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14365  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14367  }
14368 
14369  if( (*node)->nchildren == 0 )
14370  {
14371  assert(polynomialdata->nmonomials == 0);
14372  assert(polynomialdata->constant == 0.0);
14373  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14374  havechange = TRUE;
14375  break;
14376  }
14377 
14378  break;
14379  }
14380 
14381  default: ;
14382  } /*lint !e788*/
14383 
14384  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14385 
14386  if( orignode != NULL )
14387  {
14388  /* if node was duplicated, we need to forget about original or duplicate */
14389  if( !havechange )
14390  {
14391  /* if nothing has changed, then forget about duplicate */
14392  assert(*constant == 0.0);
14393  assert(*nlinvars == 0);
14394  assert(*node != NULL);
14395  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14396  *node = orignode;
14397  }
14398  else
14399  {
14400  /* if something changed, then release original node */
14401  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14402  }
14403  }
14404  else if( havechange && *node != NULL )
14405  {
14406  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14407  (*node)->value = SCIP_INVALID;
14408  (*node)->simplified = FALSE;
14409  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14410  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14411  exprgraph->needvarboundprop = TRUE;
14412  }
14413 
14414  return SCIP_OKAY;
14415 }
14416 
14417 /** moves parents from a one node to another node
14418  *
14419  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14420  * srcnode may be freed, if not captured.
14421  * It is assumed that targetnode represents the same expression as srcnode.
14422  */
14424  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14425  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
14426  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
14427  )
14428 {
14429  assert(exprgraph != NULL);
14430  assert(srcnode != NULL);
14431  assert(*srcnode != NULL);
14432  assert(targetnode != NULL);
14433 
14434  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14435  {
14436  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14437  {
14438  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14439  }
14440  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14441  }
14442  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14443 
14444  return SCIP_OKAY;
14445 }
14446 
14447 /** releases node, i.e., decreases number of uses
14448  *
14449  * node is freed if no parents and no other uses.
14450  * Children are recursively released if they have no other parents.
14451  * Nodes that are removed are also freed.
14452  * If node correspond to a variable, then the variable is removed from the expression graph;
14453  * similarly for constants.
14454  */
14456  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14457  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
14458  )
14459 {
14460  int i;
14461 
14462  assert(exprgraph != NULL);
14463  assert(node != NULL);
14464  assert(*node != NULL);
14465  assert((*node)->depth >= 0); /* node should be in graph */
14466  assert((*node)->pos >= 0); /* node should be in graph */
14467  assert((*node)->depth < exprgraph->depth);
14468  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14469  assert((*node)->nuses >= 1);
14470  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14471 
14472  SCIPdebugMessage("release node %p\n", (void*)*node);
14473 
14474  --(*node)->nuses;
14475 
14476  /* do nothing if node still has parents or is still in use */
14477  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14478  {
14479  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);
14480  *node = NULL;
14481  return SCIP_OKAY;
14482  }
14483 
14484  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14485 
14486  /* notify children about removal of its parent
14487  * they are also freed, if possible */
14488  for( i = 0; i < (*node)->nchildren; ++i )
14489  {
14490  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14491  (*node)->children[i] = NULL;
14492  }
14493 
14494  if( (*node)->op == SCIP_EXPR_VARIDX )
14495  {
14496  assert((*node)->depth == 0);
14497  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14498  }
14499  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14500  {
14501  int constidx;
14502 
14503  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14504  assert(constidx >= 0);
14505  assert(constidx < exprgraph->nconsts);
14506  assert(exprgraph->constnodes[constidx] == *node);
14507 
14508  /* move last constant to position constidx */
14509  if( constidx < exprgraph->nconsts-1 )
14510  {
14511  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14512  exprgraph->constssorted = (exprgraph->nconsts <= 2);
14513  }
14514  --exprgraph->nconsts;
14515  }
14516  else
14517  {
14518  /* only variables and constants are allowed at depth 0 */
14519  assert((*node)->depth > 0);
14520  }
14521 
14522  /* remove node from nodes array in expression graph */
14523  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14524  {
14525  /* move last node at depth of *node to position of *node */
14526  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14527  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14528 
14529  /* moving the node may change the order in the parents array of each child */
14530  for( i = 0; i < exprgraph->nodes[(*node)->depth][(*node)->pos]->nchildren; ++i )
14531  exprgraph->nodes[(*node)->depth][(*node)->pos]->children[i]->parentssorted = FALSE;
14532  }
14533  --exprgraph->nnodes[(*node)->depth];
14534 
14535  /* node is now not in graph anymore */
14536  (*node)->depth = -1;
14537  (*node)->pos = -1;
14538 
14539  /* free node */
14540  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14541 
14542  *node = NULL;
14543 
14544  return SCIP_OKAY;
14545 }
14546 
14547 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14548 /** frees a node of an expression graph */
14550  BMS_BLKMEM* blkmem, /**< block memory */
14551  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
14552  )
14553 {
14554  assert(blkmem != NULL);
14555  assert( node != NULL);
14556  assert(*node != NULL);
14557  assert((*node)->depth == -1); /* node should not be in graph anymore */
14558  assert((*node)->pos == -1); /* node should not be in graph anymore */
14559  assert((*node)->nuses == 0); /* node should not be in use */
14560 
14561  /* free operator data, if needed */
14562  if( exprOpTable[(*node)->op].freedata != NULL )
14563  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14564 
14565  /* free arrays of children and parent nodes */
14566  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14567  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
14568 
14569  /* free node struct */
14570  BMSfreeBlockMemory(blkmem, node);
14571 }
14572 
14573 /** enables a node and recursively all its children in an expression graph */
14575  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14576  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14577  )
14578 {
14579  int i;
14580 
14581  assert(exprgraph != NULL);
14582  assert(node != NULL);
14583  assert(node->depth >= 0);
14584  assert(node->pos >= 0);
14585 
14586  if( node->enabled )
14587  return;
14588 
14589  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14590 
14591  node->enabled = TRUE;
14592  for( i = 0; i < node->nchildren; ++i )
14593  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14594 
14595  /* make sure bounds are updated in next bound propagation round */
14596  SCIPintervalSetEntire(SCIP_REAL_MAX, &node->bounds);
14597  exprgraph->needvarboundprop = TRUE;
14598 }
14599 
14600 /** disables a node and recursively all children which have no enabled parents in an expression graph */
14602  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14603  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14604  )
14605 {
14606  int i;
14607 
14608  assert(exprgraph != NULL);
14609  assert(node != NULL);
14610  assert(node->depth >= 0);
14611  assert(node->pos >= 0);
14612 
14613  if( !node->enabled )
14614  return;
14615 
14616  /* workaround: don't disable nodes if there could be more users than the one who is disabling the node
14617  * otherwise, if there are several nonlinear constraints using the same expression graph node as root node,
14618  * we might get enabled constraints with disabled node
14619  */
14620  if( node->nuses > 1 )
14621  return;
14622 
14623  /* if all parents of node are disabled, then also node can be disabled */
14624  node->enabled = FALSE;
14625  for( i = 0; i < node->nparents; ++i )
14626  if( node->parents[i]->enabled )
14627  {
14628  node->enabled = TRUE;
14629  return;
14630  }
14631 
14632  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14633 
14634  for( i = 0; i < node->nchildren; ++i )
14635  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14636 }
14637 
14638 /** returns whether the node has siblings in the expression graph */
14640  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14641  )
14642 {
14643  int p;
14644 
14645  assert(node != NULL);
14646 
14647  for( p = 0; p < node->nparents; ++p )
14648  if( node->parents[p]->nchildren > 1 )
14649  return TRUE;
14650 
14651  return FALSE;
14652 }
14653 
14654 /** returns whether all children of an expression graph node are variable nodes
14655  *
14656  * Returns TRUE for nodes without children.
14657  */
14659  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14660  )
14661 {
14662  int i;
14663 
14664  assert(node != NULL);
14665 
14666  for( i = 0; i < node->nchildren; ++i )
14667  if( node->children[i]->op != SCIP_EXPR_VARIDX )
14668  return FALSE;
14669 
14670  return TRUE;
14671 }
14672 
14673 /** returns whether the node has an ancestor which has a nonlinear expression operand */
14675  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14676  )
14677 {
14678  int p;
14679 
14680  for( p = 0; p < node->nparents; ++p )
14681  {
14682  assert(node->parents[p]->depth > node->depth);
14683  switch( node->parents[p]->op )
14684  {
14685  case SCIP_EXPR_PLUS:
14686  case SCIP_EXPR_MINUS:
14687  case SCIP_EXPR_SUM:
14688  case SCIP_EXPR_LINEAR:
14690  return TRUE;
14691  break;
14692 
14693 #ifndef NDEBUG
14694  case SCIP_EXPR_VARIDX:
14695  case SCIP_EXPR_CONST:
14696  case SCIP_EXPR_PARAM:
14697  assert(0); /* these expressions cannot have children */
14698  break;
14699 #endif
14700 
14701  default:
14702  /* parent has nonlinear expression operand */
14703  return TRUE;
14704  }/*lint !e788*/
14705  }
14706 
14707  return FALSE;
14708 }
14709 
14710 /** prints an expression graph node */
14712  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14713  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14714  FILE* file /**< file to print to, or NULL for stdout */
14715  )
14716 {
14717  assert(node != NULL);
14718 
14719  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14720 }
14721 
14722 /** tightens the bounds in a node of the graph
14723  *
14724  * Preparation for reverse propagation.
14725  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14726  */
14728  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14729  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
14730  SCIP_INTERVAL nodebounds, /**< new bounds for node */
14731  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) */
14732  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14733  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14734  )
14735 {
14736  assert(exprgraph != NULL);
14737  assert(node != NULL);
14738  assert(node->depth >= 0);
14739  assert(node->pos >= 0);
14740  assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14741  assert(cutoff != NULL);
14742 
14743  *cutoff = FALSE;
14744 
14745  /* if node is disabled, then ignore new bounds */
14746  if( !node->enabled )
14747  {
14748  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14749  return;
14750  }
14751 
14752  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14753  (void*)node, node->depth, node->pos,
14754  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14755 
14756  /* bounds in node should be valid */
14757  assert(!(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
14758 
14759  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14760  {
14761  *cutoff = TRUE;
14762  SCIPdebugPrintf(" -> cutoff\n");
14763  return;
14764  }
14765 
14766  /* if minstrength is negative, always mark that node has recently tightened bounds,
14767  * if bounds are considerably improved or tightening leads to an empty interval,
14768  * mark that node has recently tightened bounds
14769  * if bounds are only slightly improved, set the status to tightened by parent,
14770  * so next propagateVarBound round will reset the bounds
14771  */
14772  if( minstrength < 0.0 )
14773  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE;
14774  else if(
14775  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14776  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14777  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT;
14778  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14779  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT;
14780 
14781  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14782  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14783 }
14784 
14785 /** ensures that bounds and curvature information in a node is uptodate
14786  *
14787  * Assumes that bounds and curvature in children are uptodate.
14788  */
14790  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14791  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14792  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14793  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14794  )
14795 {
14796  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14797  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14798  SCIP_INTERVAL* childbounds = NULL;
14799  SCIP_EXPRCURV* childcurv = NULL;
14800  SCIP_RETCODE retcode = SCIP_OKAY;
14801  int i;
14802 
14803  assert(node != NULL);
14804  assert(node->depth >= 0); /* node should be in graph */
14805  assert(node->pos >= 0); /* node should be in graph */
14806  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14807 
14808  if( node->depth == 0 )
14809  {
14810  /* we cannot update bound tightenings in variable nodes here */
14811  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14812  return SCIP_OKAY;
14813  }
14814 
14815  assert(node->op != SCIP_EXPR_VARIDX);
14816  assert(node->op != SCIP_EXPR_PARAM);
14817 
14818  /* if many children, get large enough memory to store children bounds */
14820  {
14821  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14822  SCIP_ALLOC_TERMINATE(retcode, BMSallocMemoryArray(&childcurv, node->nchildren), TERMINATE);
14823  }
14824  else
14825  {
14826  childbounds = childboundsstatic;
14827  childcurv = childcurvstatic;
14828  }
14829 
14830  /* assemble bounds and curvature of children */
14831  for( i = 0; i < node->nchildren; ++i )
14832  {
14833  /* child should have valid and non-empty bounds */
14835  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14836  /* nodes at depth 0 are always linear */
14837  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14838 
14839  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
14840  childcurv[i] = node->children[i]->curv; /*lint !e644*/
14841  }
14842 
14843  /* if we do not have valid bounds, then update
14844  * code below is copied from exprgraphNodeUpdateBounds */
14846  {
14847  SCIP_INTERVAL newbounds;
14848 
14849  /* calling interval evaluation function for this operand */
14850  assert( exprOpTable[node->op].inteval != NULL );
14851  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds), TERMINATE );
14852 
14853  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14854  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14855  *
14856  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14857  *
14858  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14859  */
14860  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14862  {
14863  for( i = 0; i < node->nparents; ++i )
14865 
14866  node->bounds = newbounds;
14867  }
14868  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14869  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14870  {
14871  for( i = 0; i < node->nparents; ++i )
14873 
14874  node->bounds = newbounds;
14875  }
14876  else
14877  {
14878  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14879  }
14880 
14881  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);
14882 
14883  /* node now has valid bounds */
14884  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
14885  }
14886 
14887  /* update curvature */
14888  if( SCIPintervalIsEmpty(infinity, node->bounds) )
14889  {
14890  node->curv = SCIP_EXPRCURV_LINEAR;
14891 
14892  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14893  }
14894  else
14895  {
14896  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv), TERMINATE );
14897 
14898  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14899  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14900  * SCIPdebugPrintf("\n");
14901  */
14902  }
14903 TERMINATE:
14904  /* free memory, if allocated before */
14905  if( childbounds != childboundsstatic )
14906  {
14907  BMSfreeMemoryArrayNull(&childbounds);
14908  BMSfreeMemoryArrayNull(&childcurv);
14909  }
14910 
14911  return retcode;
14912 }
14913 
14914 /**@} */
14915 
14916 /**@name Expression graph methods */
14917 /**@{ */
14918 
14919 /* In debug mode, the following methods are implemented as function calls to ensure
14920  * type validity.
14921  * In optimized mode, the methods are implemented as defines to improve performance.
14922  * However, we want to have them in the library anyways, so we have to undef the defines.
14923  */
14924 
14925 #undef SCIPexprgraphGetDepth
14926 #undef SCIPexprgraphGetNNodes
14927 #undef SCIPexprgraphGetNodes
14928 #undef SCIPexprgraphGetNVars
14929 #undef SCIPexprgraphGetVars
14930 #undef SCIPexprgraphGetVarNodes
14931 #undef SCIPexprgraphSetVarNodeValue
14932 #undef SCIPexprgraphSetVarsBounds
14933 #undef SCIPexprgraphSetVarBounds
14934 #undef SCIPexprgraphSetVarNodeBounds
14935 #undef SCIPexprgraphSetVarNodeLb
14936 #undef SCIPexprgraphSetVarNodeUb
14937 #undef SCIPexprgraphGetVarsBounds
14938 
14939 /** get current maximal depth of expression graph */
14941  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14942  )
14943 {
14944  assert(exprgraph != NULL);
14945 
14946  return exprgraph->depth;
14947 }
14948 
14949 /** gets array with number of nodes at each depth of expression graph */
14951  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14952  )
14953 {
14954  assert(exprgraph != NULL);
14955 
14956  return exprgraph->nnodes;
14957 }
14958 
14959 /** gets nodes of expression graph, one array per depth */
14961  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14962  )
14963 {
14964  assert(exprgraph != NULL);
14965 
14966  return exprgraph->nodes;
14967 }
14968 
14969 /** gets number of variables in expression graph */
14971  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14972  )
14973 {
14974  assert(exprgraph != NULL);
14975 
14976  return exprgraph->nvars;
14977 }
14978 
14979 /** gets array of variables in expression graph */
14981  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14982  )
14983 {
14984  assert(exprgraph != NULL);
14985 
14986  return exprgraph->vars;
14987 }
14988 
14989 /** gets array of expression graph nodes corresponding to variables */
14991  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14992  )
14993 {
14994  assert(exprgraph != NULL);
14995 
14996  return exprgraph->varnodes;
14997 }
14998 
14999 /** sets value for a single variable given as expression graph node */
15001  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15002  SCIP_Real value /**< new value for variable */
15003  )
15004 {
15005  assert(varnode != NULL);
15006  assert(varnode->op == SCIP_EXPR_VARIDX);
15007 
15008  varnode->value = value;
15009 }
15010 
15011 /** sets bounds for variables */
15013  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15014  SCIP_INTERVAL* varbounds /**< new bounds for variables */
15015  )
15016 {
15017  assert(exprgraph != NULL);
15018  assert(varbounds != NULL || exprgraph->nvars == 0);
15019 
15020  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
15021 }
15022 
15023 /** sets bounds for a single variable */
15025  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15026  void* var, /**< variable */
15027  SCIP_INTERVAL varbounds /**< new bounds of variable */
15028  )
15029 {
15030  int pos;
15031 
15032  assert(exprgraph != NULL);
15033  assert(var != NULL);
15034  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15035 
15036  pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15037  assert(pos < exprgraph->nvars);
15038  assert(exprgraph->vars[pos] == var);
15039 
15040  exprgraph->varbounds[pos] = varbounds;
15041 }
15042 
15043 /** sets bounds for a single variable given as expression graph node */
15045  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15046  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15047  SCIP_INTERVAL varbounds /**< new bounds of variable */
15048  )
15049 {
15050  int pos;
15051 
15052  assert(exprgraph != NULL);
15053  assert(varnode != NULL);
15054 
15055  pos = varnode->data.intval;
15056  assert(pos >= 0);
15057  assert(pos < exprgraph->nvars);
15058  assert(exprgraph->varnodes[pos] == varnode);
15059 
15060  exprgraph->varbounds[pos] = varbounds;
15061 }
15062 
15063 /** sets lower bound for a single variable given as expression graph node */
15065  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15066  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15067  SCIP_Real lb /**< new lower bound for variable */
15068  )
15069 {
15070  int pos;
15071 
15072  assert(exprgraph != NULL);
15073  assert(varnode != NULL);
15074 
15075  pos = varnode->data.intval;
15076  assert(pos >= 0);
15077  assert(pos < exprgraph->nvars);
15078  assert(exprgraph->varnodes[pos] == varnode);
15079 
15080  exprgraph->varbounds[pos].inf = lb;
15081 }
15082 
15083 /** sets upper bound for a single variable given as expression graph node */
15085  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15086  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15087  SCIP_Real ub /**< new upper bound for variable */
15088  )
15089 {
15090  int pos;
15091 
15092  assert(exprgraph != NULL);
15093  assert(varnode != NULL);
15094 
15095  pos = varnode->data.intval;
15096  assert(pos >= 0);
15097  assert(pos < exprgraph->nvars);
15098  assert(exprgraph->varnodes[pos] == varnode);
15099 
15100  exprgraph->varbounds[pos].sup = ub;
15101 }
15102 
15103 /** gets bounds that are stored for all variables */
15105  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
15106  )
15107 {
15108  return exprgraph->varbounds;
15109 }
15110 
15111 /** creates an empty expression graph */
15113  BMS_BLKMEM* blkmem, /**< block memory */
15114  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
15115  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
15116  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
15117  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /**< callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
15118  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /**< callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
15119  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /**< callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
15120  void* userdata /**< user data to pass to callback functions */
15121  )
15122 {
15123  assert(blkmem != NULL);
15124  assert(exprgraph != NULL);
15125 
15126  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
15127  BMSclearMemory(*exprgraph);
15128  (*exprgraph)->blkmem = blkmem;
15129 
15130  /* create nodes's arrays */
15131  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
15132  assert((*exprgraph)->depth >= 1);
15133 
15134  /* create var's arrays and hashmap */
15135  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
15136  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, (*exprgraph)->varssize) );
15137 
15138  /* empty array of constants is sorted */
15139  (*exprgraph)->constssorted = TRUE;
15140 
15141  /* store callback functions and user data */
15142  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
15143  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
15144  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
15145  (*exprgraph)->userdata = userdata;
15146 
15147  return SCIP_OKAY;
15148 }
15149 
15150 /** frees an expression graph */
15152  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
15153  )
15154 {
15155  BMS_BLKMEM* blkmem;
15156  int d;
15157 
15158  assert( exprgraph != NULL);
15159  assert(*exprgraph != NULL);
15160  assert((*exprgraph)->nvars == 0);
15161  assert((*exprgraph)->nconsts == 0);
15162 
15163  blkmem = (*exprgraph)->blkmem;
15164  assert(blkmem != NULL);
15165 
15166  /* free nodes arrays */
15167  for( d = 0; d < (*exprgraph)->depth; ++d )
15168  {
15169  assert((*exprgraph)->nnodes[d] == 0);
15170  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
15171  }
15172  assert((*exprgraph)->nodes != NULL);
15173  assert((*exprgraph)->nnodes != NULL);
15174  assert((*exprgraph)->nodessize != NULL);
15175  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
15176  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
15177  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
15178 
15179  /* free variables arrays and hashmap */
15180  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
15181  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
15182  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
15183  SCIPhashmapFree(&(*exprgraph)->varidxs);
15184 
15185  /* free constants array */
15186  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
15187 
15188  /* free graph struct */
15189  BMSfreeBlockMemory(blkmem, exprgraph);
15190 
15191  return SCIP_OKAY;
15192 }
15193 
15194 /** adds an expression graph node to an expression graph
15195  *
15196  * Expression graph assumes ownership of node.
15197  * Children are notified about new parent.
15198  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
15199  */
15201  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15202  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
15203  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
15204  int nchildren, /**< number of children */
15205  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
15206  )
15207 {
15208  SCIP_Bool childvalsvalid;
15209  int depth;
15210  int i;
15211 
15212  assert(exprgraph != NULL);
15213  assert(node != NULL);
15214  assert(node->pos < 0); /* node should have no position in graph yet */
15215  assert(node->depth < 0); /* node should have no position in graph yet */
15216  assert(node->nchildren == 0); /* node should not have stored children yet */
15217  assert(node->children == NULL); /* node should not have stored children yet */
15218  assert(node->nparents == 0); /* node should not have parents stored yet */
15219  assert(children != NULL || nchildren == 0);
15220 
15221  /* choose depth as maximal depth of children + 1, and at least mindepth */
15222  depth = MAX(0, mindepth);
15223  for( i = 0; i < nchildren; ++i )
15224  {
15225  if( children[i]->depth >= depth ) /*lint !e613*/
15226  depth = children[i]->depth + 1; /*lint !e613*/
15227  }
15228 
15229  /* ensure that expression graph is deep enough */
15230  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
15231  assert(exprgraph->depth > depth);
15232 
15233  /* ensure enough space for nodes at depth depth */
15234  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
15235 
15236  /* add node to graph */
15237  node->depth = depth;
15238  node->pos = exprgraph->nnodes[depth];
15239  exprgraph->nodes[depth][node->pos] = node;
15240  ++exprgraph->nnodes[depth];
15241 
15242  /* add as parent to children
15243  * and check if children has valid values */
15244  childvalsvalid = TRUE;
15245  for( i = 0; i < nchildren; ++i )
15246  {
15247  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
15248  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
15249  }
15250  /* store children */
15251  if( nchildren > 0 )
15252  {
15253  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
15254  node->nchildren = nchildren;
15255  }
15256 
15257  if( node->op == SCIP_EXPR_CONST )
15258  {
15259  /* set bounds to constant value of node */
15261  SCIPintervalSet(&node->bounds, node->data.dbl);
15262  }
15263  else
15264  {
15265  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
15268  exprgraph->needvarboundprop = TRUE;
15269  }
15270 
15271  /* if not a variable, set value of node according to values of children (if all have valid values) */
15272  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
15273  {
15274  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15275  }
15276 
15277  return SCIP_OKAY;
15278 }
15279 
15280 /** adds variables to an expression graph, if not existing yet
15281  *
15282  * Also already existing nodes are enabled.
15283  */
15285  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15286  int nvars, /**< number of variables to add */
15287  void** vars, /**< variables to add */
15288  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
15289  )
15290 {
15291  SCIP_EXPRGRAPHNODE* node;
15292  SCIP_EXPROPDATA opdata;
15293  int i;
15294 
15295  assert(exprgraph != NULL);
15296  assert(exprgraph->depth >= 1);
15297  assert(vars != NULL || nvars == 0);
15298 
15299  /* 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 */
15300  if( exprgraph->nvars == 0 )
15301  {
15302  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15303  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15304  }
15305 
15306  for( i = 0; i < nvars; ++i )
15307  {
15308  /* skip variables that exist already */
15309  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15310  {
15311  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
15312  assert(node != NULL);
15313 
15314  /* enable node */
15315  node->enabled = TRUE;
15316 
15317  if( varnodes != NULL )
15318  varnodes[i] = node;
15319 
15320  continue;
15321  }
15322 
15323  /* create new variable expression */
15324  opdata.intval = exprgraph->nvars;
15325  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15326 
15327  /* add expression node to expression graph at depth 0 */
15328  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15329 
15330  /* add variable node to vars arrays and hashmap */
15331  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15332  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
15333  exprgraph->varnodes[exprgraph->nvars] = node;
15334  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15335  SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[i], exprgraph->nvars) ); /*lint !e613*/
15336  ++exprgraph->nvars;
15337 
15338  if( varnodes != NULL )
15339  varnodes[i] = node;
15340 
15341  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15342 
15343  /* call callback method, if set */
15344  if( exprgraph->exprgraphvaradded != NULL )
15345  {
15346  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
15347  }
15348  }
15349 
15350  return SCIP_OKAY;
15351 }
15352 
15353 /** adds a constant to an expression graph, if not existing yet
15354  *
15355  * Also already existing nodes are enabled.
15356  */
15358  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15359  SCIP_Real constant, /**< constant to add */
15360  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
15361  )
15362 {
15363  SCIP_EXPROPDATA opdata;
15364 
15365  assert(exprgraph != NULL);
15366  assert(constnode != NULL);
15367 
15368  /* check if there is already an expression for this constant */
15369  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15370  {
15371  assert(*constnode != NULL);
15372  assert((*constnode)->op == SCIP_EXPR_CONST);
15373  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15374  (*constnode)->enabled = TRUE;
15375  return SCIP_OKAY;
15376  }
15377 
15378  /* create new node for constant */
15379  opdata.dbl = constant;
15380  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15381 
15382  /* add node to expression graph at depth 0 */
15383  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15384  assert((*constnode)->depth == 0);
15385  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
15386 
15387  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15388  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15389  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15390  ++exprgraph->nconsts;
15391  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15392 
15393  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15394 
15395  return SCIP_OKAY;
15396 }
15397 
15398 /** adds sum of expression trees into expression graph
15399  *
15400  * node will also be captured.
15401  *
15402  * @note Parameters will be converted into constants
15403  */
15405  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15406  int nexprtrees, /**< number of expression trees to add */
15407  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
15408  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
15409  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
15410  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) */
15411  )
15412 {
15413  SCIP_Bool allone;
15414 
15415  assert(exprgraph != NULL);
15416  assert(nexprtrees > 0);
15417  assert(exprtrees != NULL);
15418  assert(rootnode != NULL);
15419  assert(rootnodeisnew != NULL);
15420 
15421  *rootnode = NULL;
15422 
15423  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15424  {
15425  assert(exprtrees[0] != NULL);
15426  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15427 
15428  /* coverity[var_deref_model] */
15429  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, exprtrees[0]->params, rootnode, rootnodeisnew) );
15430  }
15431  else
15432  {
15433  SCIP_EXPROP op;
15434  SCIP_EXPRGRAPHNODE** rootnodes;
15435  SCIP_Bool rootnodeisnew_;
15436  int i;
15437 
15438  *rootnodeisnew = TRUE;
15439  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15440 
15441  allone = TRUE;
15442  for( i = 0; i < nexprtrees; ++i )
15443  {
15444  assert(exprtrees[i] != NULL);
15445  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15446 
15447  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, exprtrees[i]->params, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
15448  assert(rootnodes[i] != NULL);
15449  *rootnodeisnew &= rootnodeisnew_;
15450 
15451  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
15452  }
15453 
15454  /* decide which operand we want to use for the root node */
15455  if( coefs == NULL || allone )
15456  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15457  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15458  op = SCIP_EXPR_MINUS;
15459  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15460  {
15461  SCIP_EXPRGRAPHNODE* tmp;
15462 
15463  tmp = rootnodes[0];
15464  rootnodes[0] = rootnodes[1];
15465  rootnodes[1] = tmp;
15466  op = SCIP_EXPR_MINUS;
15467  }
15468  else
15469  op = SCIP_EXPR_LINEAR;
15470 
15471  if( op != SCIP_EXPR_LINEAR )
15472  {
15473  SCIP_EXPROPDATA data;
15474  data.data = NULL;
15475 
15476  if( !*rootnodeisnew )
15477  {
15478  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15479  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15480  }
15481 
15482  if( *rootnode == NULL )
15483  {
15484  /* create new node for sum of rootnodes and add to exprgraph */
15485  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15486  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15487  *rootnodeisnew = TRUE;
15488  }
15489  else
15490  {
15491  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15492  *rootnodeisnew = FALSE;
15493  }
15494  }
15495  else
15496  {
15497  SCIP_EXPROPDATA data;
15498  SCIP_Real* lindata;
15499 
15500  assert(op == SCIP_EXPR_LINEAR);
15501 
15502  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15503  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15504  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
15505  lindata[nexprtrees] = 0.0;
15506  data.data = lindata;
15507 
15508  if( !*rootnodeisnew )
15509  {
15510  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15511  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15512  }
15513 
15514  if( *rootnode == NULL )
15515  {
15516  /* create new node for linear combination of rootnodes and add to exprgraph */
15517  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15518  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15519  *rootnodeisnew = TRUE;
15520  }
15521  else
15522  {
15523  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15524  *rootnodeisnew = FALSE;
15525  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15526  }
15527  }
15528 
15529  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15530  }
15531  assert(*rootnode != NULL);
15532 
15533  SCIPexprgraphCaptureNode(*rootnode);
15534 
15535  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15536  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15537 
15538  return SCIP_OKAY;
15539 }
15540 
15541 /** replaces variable in expression graph by a linear sum of variables
15542  *
15543  * Variables will be added if not in the graph yet.
15544  */
15546  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15547  void* var, /**< variable to replace */
15548  int ncoefs, /**< number of coefficients in linear term */
15549  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
15550  void** vars, /**< variables in linear term */
15551  SCIP_Real constant /**< constant offset */
15552  )
15553 {
15554  SCIP_EXPRGRAPHNODE* varnode;
15555  SCIP_Real* lindata;
15556  int varidx;
15557  int i;
15558 
15559  assert(exprgraph != NULL);
15560  assert(var != NULL);
15561  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15562  assert(coefs != NULL || ncoefs == 0);
15563  assert(vars != NULL || ncoefs == 0);
15564 
15565  varidx = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15566  assert(varidx < exprgraph->nvars);
15567  assert(exprgraph->vars[varidx] == var);
15568  varnode = exprgraph->varnodes[varidx];
15569  assert(varnode != NULL);
15570  assert(varnode->data.intval == varidx);
15571 
15572  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
15573  {
15574  /* variable is replaced by constant or variable */
15575  SCIP_EXPRGRAPHNODE* node;
15576 
15577  /* check if there is already a node for this constant or variable */
15578  node = NULL;
15579  if( ncoefs == 0 )
15580  {
15581  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15582  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
15583  }
15584  else
15585  {
15586  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
15587  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
15588  }
15589 
15590  if( node != NULL )
15591  {
15592  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15593 
15594  /* tell parents of varnode to replace child varnode by node, this may free varnode */
15595  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15596 
15597  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15598  if( varnode != NULL )
15599  {
15600  assert(varnode->nuses > 0);
15601  assert(varnode->nparents == 0);
15602 
15603  /* remove variable (but don't free it's node) from graph */
15604  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15605 
15606  /* move varnode up to depth 1 */
15607  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15608 
15609  /* turn into EXPR_SUM expression */
15610  varnode->op = SCIP_EXPR_SUM;
15611  varnode->data.data = NULL;
15612  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
15613  varnode->children[0] = node;
15614  varnode->nchildren = 1;
15615  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15616 
15617  varnode->value = node->value;
15618  varnode->bounds = node->bounds;
15619  varnode->boundstatus = (node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID) ? SCIP_EXPRBOUNDSTATUS_VALID : SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
15620  }
15621  }
15622  else if( ncoefs == 0 )
15623  {
15624  /* turn node into EXPR_CONST node */
15625 
15626  /* remove variable (but don't free it's node) from graph */
15627  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15628 
15629  /* convert into EXPR_CONST node */
15630  varnode->op = SCIP_EXPR_CONST;
15631  varnode->data.dbl = constant;
15632 
15633  varnode->value = constant;
15634  SCIPintervalSet(&varnode->bounds, constant);
15636 
15637  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15638  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15639  exprgraph->constnodes[exprgraph->nconsts] = varnode;
15640  ++exprgraph->nconsts;
15641  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15642  }
15643  else
15644  {
15645  /* turn node into EXPR_VARIDX node for new variable */
15646 
15647  /* remove variable (but don't free it's node) from graph */
15648  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15649 
15650  varnode->data.intval = exprgraph->nvars;
15651 
15652  /* add variable node to vars arrays and hashmap */
15653  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15654  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
15655  exprgraph->varnodes[exprgraph->nvars] = varnode;
15656  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15657  SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[0], exprgraph->nvars) ); /*lint !e613*/
15658  ++exprgraph->nvars;
15659 
15660  /* call callback method, if set */
15661  if( exprgraph->exprgraphvaradded != NULL )
15662  {
15663  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
15664  }
15665  }
15666 
15667  /* mark varnode and its parents as not simplified */
15668  if( varnode != NULL )
15669  {
15670  varnode->simplified = FALSE;
15671  for( i = 0; i < varnode->nparents; ++i )
15672  varnode->parents[i]->simplified = FALSE;
15673  }
15674 
15675  return SCIP_OKAY;
15676  }
15677 
15678  /* turn varnode into EXPR_LINEAR */
15679 
15680  /* remove variable (but don't free it's node) from graph */
15681  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15682 
15683  /* move varnode up to depth 1 */
15684  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15685 
15686  /* convert into EXPR_LINEAR node */
15687  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15688  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
15689  lindata[ncoefs] = constant;
15690  varnode->data.data = (void*)lindata;
15691  varnode->op = SCIP_EXPR_LINEAR;
15692 
15693  /* add nodes corresponding to vars to expression graph, if not existing yet */
15694  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15695  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15696  varnode->nchildren = ncoefs;
15697 
15698  /* notify vars about new parent varnode */
15699  for( i = 0; i < ncoefs; ++i )
15700  {
15701  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15702  }
15703 
15704  /* set value and bounds to invalid, curvature can remain (still linear) */
15705  varnode->value = SCIP_INVALID;
15707 
15708  /* mark varnode and its parents as not simplified */
15709  varnode->simplified = FALSE;
15710  for( i = 0; i < varnode->nparents; ++i )
15711  varnode->parents[i]->simplified = FALSE;
15712 
15713  return SCIP_OKAY;
15714 }
15715 
15716 /** finds expression graph node corresponding to a variable */
15718  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15719  void* var, /**< variable to search for */
15720  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15721  )
15722 {
15723  int pos;
15724 
15725  assert(exprgraph != NULL);
15726  assert(var != NULL);
15727  assert(varnode != NULL);
15728 
15729  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15730  {
15731  *varnode = NULL;
15732  return FALSE;
15733  }
15734 
15735  pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15736  assert(pos < exprgraph->nvars);
15737 
15738  *varnode = exprgraph->varnodes[pos];
15739  assert(*varnode != NULL);
15740  assert((*varnode)->op == SCIP_EXPR_VARIDX);
15741 
15742  return TRUE;
15743 }
15744 
15745 /** finds expression graph node corresponding to a constant */
15747  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15748  SCIP_Real constant, /**< constant to search for */
15749  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15750  )
15751 {
15752  int left;
15753  int right;
15754  int middle;
15755 
15756  assert(exprgraph != NULL);
15757  assert(constnode != NULL);
15758  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
15759 
15760  exprgraphSortConstNodes(exprgraph);
15761  assert(exprgraph->constssorted);
15762 
15763  /* find node using binary search */
15764  left = 0;
15765  right = exprgraph->nconsts-1;
15766  *constnode = NULL;
15767 
15768  while( left <= right )
15769  {
15770  middle = (left+right)/2;
15771  assert(0 <= middle && middle < exprgraph->nconsts);
15772 
15773  if( constant < exprgraph->constnodes[middle]->data.dbl )
15774  right = middle - 1;
15775  else if( constant > exprgraph->constnodes[middle]->data.dbl )
15776  left = middle + 1;
15777  else
15778  {
15779  *constnode = exprgraph->constnodes[middle];
15780  break;
15781  }
15782  }
15783  if( left == right+1 )
15784  return FALSE;
15785 
15786  assert(*constnode != NULL);
15787  assert((*constnode)->op == SCIP_EXPR_CONST);
15788  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15789 
15790  return TRUE;
15791 }
15792 
15793 /** prints an expression graph in dot format */
15795  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15796  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15797  FILE* file, /**< file to print to, or NULL for stdout */
15798  const char** varnames /**< variable names, or NULL for generic names */
15799  )
15800 {
15801  int d;
15802  int i;
15803 
15804  assert(exprgraph != NULL);
15805 
15806  if( file == NULL )
15807  file = stdout;
15808 
15809  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15810  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15811 
15812  for( d = 0; d < exprgraph->depth; ++d )
15813  {
15814  if( exprgraph->nnodes[d] == 0 )
15815  continue;
15816 
15817  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15818  {
15819  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15820  }
15821  }
15822 
15823  /* tell dot that all nodes of depth 0 have the same rank */
15824  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15825  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15826  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15827  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15828 
15829  /* tell dot that all nodes without parent have the same rank */
15830  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15831  for( d = 0; d < exprgraph->depth; ++d )
15832  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15833  if( exprgraph->nodes[d][i]->nparents == 0 )
15834  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15835  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15836 
15837  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15838 
15839  return SCIP_OKAY;
15840 }
15841 
15842 /** evaluates nodes of expression graph for given values of variables */
15844  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15845  SCIP_Real* varvals /**< values for variables */
15846  )
15847 {
15848  int d;
15849  int i;
15850 
15851  assert(exprgraph != NULL);
15852  assert(varvals != NULL || exprgraph->nvars == 0);
15853 
15854  for( d = 0; d < exprgraph->depth; ++d )
15855  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15856  {
15857  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15858  }
15859 
15860  return SCIP_OKAY;
15861 }
15862 
15863 /** propagates bound changes in variables forward through the expression graph */
15865  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15866  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15867  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
15868  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15869  )
15870 {
15871  SCIP_EXPRGRAPHNODE* node;
15872  SCIP_Bool boundchanged;
15873  int d;
15874  int i;
15875 
15876  assert(exprgraph != NULL);
15877  assert(domainerror != NULL);
15878 
15879  *domainerror = FALSE;
15880 
15881  /* update bounds in varnodes of expression graph */
15882  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15883 
15884  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15885  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15886  {
15887  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15888  return SCIP_OKAY;
15889  }
15890 
15891  /* propagate bound changes, interrupt if we get to a node with empty bounds */
15892  for( d = 1; d < exprgraph->depth; ++d )
15893  {
15894  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15895  {
15896  node = exprgraph->nodes[d][i];
15897  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15898  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15899  {
15900  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15901  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15902  *domainerror = TRUE;
15903  return SCIP_OKAY;
15904  }
15905  }
15906  }
15907 
15908  exprgraph->needvarboundprop = FALSE;
15909 
15910  return SCIP_OKAY;
15911 }
15912 
15913 /** propagates bound changes in nodes backward through the graph
15914  *
15915  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15916  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15917  */
15919  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15920  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15921  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15922  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15923  )
15924 {
15925  SCIP_EXPRGRAPHNODE* node;
15926  int d;
15927  int i;
15928 
15929  assert(exprgraph != NULL);
15930  assert(cutoff != NULL);
15931 
15932  *cutoff = FALSE;
15933 
15934  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15935  {
15936  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15937  {
15938  node = exprgraph->nodes[d][i];
15939  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15940  }
15941  }
15942  if( *cutoff )
15943  return;
15944 }
15945 
15946 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15947  *
15948  * Implies update of bounds in expression graph.
15949  */
15951  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15952  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15953  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15954  )
15955 {
15956  SCIP_EXPRGRAPHNODE* node;
15957  SCIP_Bool boundchanged;
15958  int d;
15959  int i;
15960 
15961  assert(exprgraph != NULL);
15962 
15963  /* update bounds in varnodes of expression graph */
15964  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15965 
15966 #ifndef NDEBUG
15967  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15968  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15969 #endif
15970 
15971  for( d = 1; d < exprgraph->depth; ++d )
15972  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15973  {
15974  node = exprgraph->nodes[d][i];
15975  assert(node != NULL);
15976 
15977  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15978 
15979  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15980  {
15981  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15982  return SCIP_OKAY;
15983  }
15984  }
15985 
15986  return SCIP_OKAY;
15987 }
15988 
15989 /** aims at simplifying an expression graph
15990  *
15991  * 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)).
15992  */
15994  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15995  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15996  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15997  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15998  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15999  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
16000  )
16001 {
16002  SCIP_EXPRGRAPHNODE* node;
16003  SCIP_Bool havechangenode;
16004  SCIP_Bool allsimplified;
16005  int d;
16006  int i;
16007  int j;
16008 
16009 #ifndef NDEBUG
16010  SCIP_Real* testx;
16011  SCIP_HASHMAP* testvalidx;
16012  SCIP_Real* testvals;
16013  SCIP_RANDNUMGEN* randnumgen;
16014  int testvalssize;
16015  int ntestvals;
16016 #endif
16017 
16018  assert(exprgraph != NULL);
16019  assert(eps >= 0.0);
16020  assert(havechange != NULL);
16021  assert(domainerror != NULL);
16022 
16023 #ifndef NDEBUG
16024  SCIP_CALL( SCIPrandomCreate(&randnumgen, exprgraph->blkmem, 862) ); /* see also #1848 */
16025  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
16026  testvals = NULL;
16027  ntestvals = 0;
16028  testvalssize = 0;
16029 
16030  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
16031  for( i = 0; i < exprgraph->nvars; ++i )
16032  testx[i] = SCIPrandomGetReal(randnumgen,
16033  exprgraph->varbounds[i].inf < -100.0 ? MIN(-100.0, exprgraph->varbounds[i].sup) : exprgraph->varbounds[i].inf,
16034  exprgraph->varbounds[i].sup > 100.0 ? MAX( 100.0, exprgraph->varbounds[i].inf) : exprgraph->varbounds[i].sup); /*lint !e644*/
16035  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
16036  for( d = 1; d < exprgraph->depth; ++d )
16037  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16038  {
16039  node = exprgraph->nodes[d][i];
16040  assert(node != NULL);
16041 
16042  /* 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 */
16043  if( node->nuses > 0 )
16044  {
16045  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
16046  SCIP_CALL( SCIPhashmapInsertInt(testvalidx, (void*)node, ntestvals) );
16047  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
16048  ++ntestvals;
16049  }
16050  }
16051 
16052  SCIPrandomFree(&randnumgen, exprgraph->blkmem);
16053 #endif
16054 
16055 #ifdef SCIP_OUTPUT
16056  {
16057  FILE* file;
16058  file = fopen("exprgraph_beforesimplify.dot", "w");
16059  if( file != NULL )
16060  {
16061  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16062  fclose(file);
16063  }
16064  }
16065 #endif
16066 
16067  *havechange = FALSE; /* we have not changed any node yet */
16068  *domainerror = FALSE; /* no domain errors encountered so far */
16069  allsimplified = TRUE; /* all nodes we looked at are simplified */
16070 
16071  /* call node simplifier from bottom up
16072  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
16073  */
16074  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
16075  {
16076  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16077  {
16078  node = exprgraph->nodes[d][i];
16079  assert(node != NULL);
16080 
16081  havechangenode = FALSE; /* node did not change yet */
16082 
16083  if( node->op != SCIP_EXPR_CONST )
16084  {
16085  /* skip nodes that are already simplified */
16086  if( node->simplified )
16087  continue;
16088 
16089  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
16090 
16091  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
16092  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
16093  assert(node->simplified == TRUE);
16094  *havechange |= havechangenode;
16095  }
16096 
16097  /* if node was or has been converted into constant, may move to depth 0 */
16098  if( node->op == SCIP_EXPR_CONST )
16099  {
16100  SCIP_EXPRGRAPHNODE* constnode;
16101 
16102  if( !SCIPisFinite(node->value) ) /*lint !e777*/
16103  {
16104  SCIPdebugMessage("Expression graph simplify turned node into NaN or inf.\n");
16105  *domainerror = TRUE;
16106  break;
16107  }
16108 
16109  /* check if there is already a node for this constant */
16110  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
16111  {
16112  assert(constnode->op == SCIP_EXPR_CONST);
16113  assert(constnode->data.dbl == node->value); /*lint !e777*/
16114 
16115  if( node->nparents > 0 )
16116  {
16117  /* move parents of this node to constnode, node may be freed if not in use */
16118  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
16119  /* node should have no parents anymore, so it should have been freed if not in use */
16120  assert(node == NULL || node->nuses > 0);
16121  havechangenode = TRUE;
16122 
16123  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
16124  if( node == NULL )
16125  {
16126  --i;
16127  continue;
16128  }
16129  }
16130  assert(node != NULL);
16131  assert(node->nuses > 0);
16132 
16133  if( constnode->nuses == 0 )
16134  {
16135  /* move node to depth 0, adding it to constnodes */
16136  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16137 
16138  /* move parents of constnode to node, so constnode is freed */
16139  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
16140  assert(constnode == NULL);
16141  havechangenode = TRUE;
16142 
16143  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16144  --i;
16145  continue;
16146  }
16147  }
16148  else
16149  {
16150  /* move to depth 0, adding it to constnodes */
16151  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16152 
16153  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16154  --i;
16155  }
16156  }
16157 
16158  /* if there was a change, mark parents as not simplified */
16159  if( havechangenode )
16160  for( j = 0; j < node->nparents; ++j )
16161  node->parents[j]->simplified = FALSE;
16162  }
16163  } /*lint !e850*/
16164 
16165  /* if we did nothing, clean up and escape from here */
16166  if( allsimplified || *domainerror )
16167  goto EXPRGRAPHSIMPLIFY_CLEANUP;
16168 
16169  /* @todo find duplicate subexpressions in expression graph */
16170 
16171  /* unconvert polynomials into simpler expressions, where possible */
16172  for( d = 1; d < exprgraph->depth; ++d )
16173  {
16174  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16175  {
16176  node = exprgraph->nodes[d][i];
16177  assert(node != NULL);
16178 
16179  if( node->op != SCIP_EXPR_POLYNOMIAL )
16180  continue;
16181 
16182  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
16183 
16184  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
16185  {
16186  /* node is identity w.r.t only child
16187  * replace node as child of parents by child of node
16188  */
16189 
16190  for( j = 0; node != NULL && j < node->nparents; ++j )
16191  {
16192  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
16193  }
16194  /* node should have no parents anymore, so it should have been freed if not in use */
16195  assert(node == NULL || node->nuses > 0);
16196 
16197  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
16198  if( node == NULL )
16199  --i;
16200  }
16201  }
16202  } /*lint !e850*/
16203 
16204 #ifdef SCIP_OUTPUT
16205  {
16206  FILE* file;
16207  file = fopen("exprgraph_aftersimplify.dot", "w");
16208  if( file != NULL )
16209  {
16210  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16211  fclose(file);
16212  }
16213  }
16214 #endif
16215 
16216 #ifndef NDEBUG
16217  for( d = 1; d < exprgraph->depth; ++d )
16218  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16219  {
16220  int idx;
16221  SCIP_Real testval_before;
16222  SCIP_Real testval_after;
16223 
16224  node = exprgraph->nodes[d][i];
16225  assert(node != NULL);
16226 
16227  SCIP_CALL( exprgraphNodeEval(node, NULL) );
16228 
16229  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
16230  if( node->nuses > 0 )
16231  {
16232  assert(SCIPhashmapExists(testvalidx, (void*)node));
16233 
16234  idx = SCIPhashmapGetImageInt(testvalidx, (void*)node);
16235  assert(idx < ntestvals);
16236  assert(testvals != NULL);
16237 
16238  testval_before = testvals[idx]; /*lint !e613*/
16239  testval_after = SCIPexprgraphGetNodeVal(node);
16240 
16241  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), 10*eps)); /*lint !e777*/
16242  }
16243  }
16244 #endif
16245 
16246  EXPRGRAPHSIMPLIFY_CLEANUP:
16247 #ifndef NDEBUG
16248  BMSfreeMemoryArray(&testx);
16249  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
16250  SCIPhashmapFree(&testvalidx);
16251 #endif
16252 
16253  return SCIP_OKAY;
16254 }
16255 
16256 /** creates an expression tree from a given node in an expression graph */
16258  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16259  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
16260  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
16261  )
16262 {
16263  SCIP_EXPR* root;
16264  int nexprvars;
16265  int* varidx;
16266  int i;
16267 
16268  assert(exprgraph != NULL);
16269  assert(rootnode != NULL);
16270  assert(rootnode->depth >= 0);
16271  assert(rootnode->pos >= 0);
16272  assert(exprtree != NULL);
16273 
16274  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16275  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16276 
16277  /* initially, no variable appears in the expression tree */
16278  for( i = 0; i < exprgraph->nvars; ++i )
16279  varidx[i] = -1; /*lint !e644*/
16280  nexprvars = 0;
16281 
16282  /* create expression from the subgraph that has rootnode as root */
16283  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
16284 
16285  /* create expression tree for this expression */
16286  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
16287 
16288  /* copy variables into expression tree */
16289  if( nexprvars > 0 )
16290  {
16291  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
16292  for( i = 0; i < exprgraph->nvars; ++i )
16293  {
16294  assert(varidx[i] >= -1);
16295  assert(varidx[i] < nexprvars);
16296  if( varidx[i] >= 0 )
16297  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
16298  }
16299  }
16300 
16301  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16302 
16303  return SCIP_OKAY;
16304 }
16305 
16306 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16307  *
16308  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16309  */
16311  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16312  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16313  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16314  int* nexprtrees, /**< buffer to store number of expression trees */
16315  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16316  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16317  )
16318 {
16319  int ncomponents;
16320  int* childcomp;
16321  int* varcomp;
16322  int compnr;
16323  SCIP_Bool haveoverlap;
16324  int i;
16325  int j;
16326  int k;
16327 
16328  SCIP_EXPR** exprs;
16329  int nexprs;
16330  int* childmap;
16331  int* childmapinv;
16332  int* varidx;
16333  int nexprvars;
16334 
16335  assert(exprgraph != NULL);
16336  assert(node != NULL);
16337  assert(node->depth >= 0);
16338  assert(node->pos >= 0);
16339  assert(exprtreessize > 0);
16340  assert(nexprtrees != NULL);
16341  assert(exprtrees != NULL);
16342  assert(exprtreecoefs != NULL);
16343 
16344  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16345  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16346  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16347  ( node->op != SCIP_EXPR_PLUS &&
16348  node->op != SCIP_EXPR_MINUS &&
16349  node->op != SCIP_EXPR_SUM &&
16350  node->op != SCIP_EXPR_LINEAR &&
16351  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16352  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16353  {
16354  *nexprtrees = 1;
16355  exprtreecoefs[0] = 1.0;
16356  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16357 
16358  return SCIP_OKAY;
16359  }
16360 
16361  /* find components in node->children <-> variables graph */
16362  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16363  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16364  for( i = 0; i < exprgraph->nvars; ++i )
16365  varcomp[i] = -1; /*lint !e644*/
16366 
16367  haveoverlap = FALSE;
16368  for( i = 0; i < node->nchildren; ++i )
16369  {
16370  compnr = i;
16371  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
16372  assert(compnr >= 0);
16373  assert(compnr < node->nchildren);
16374  childcomp[i] = compnr;
16375 
16376  /* remember if component number was changed by CheckComponent */
16377  if( compnr != i )
16378  haveoverlap = TRUE;
16379  }
16380 
16381  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16382 
16383  if( node->op == SCIP_EXPR_QUADRATIC )
16384  {
16385  /* merge components for products of children from different components */
16387 
16388  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16389  assert(data != NULL);
16390 
16391  for( i = 0; i < data->nquadelems; ++i )
16392  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16393  {
16394  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16395  compnr = childcomp[data->quadelems[i].idx2];
16396  for( j = 0; j < node->nchildren; ++j )
16397  if( childcomp[j] == compnr )
16398  childcomp[j] = childcomp[data->quadelems[i].idx1];
16399  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16400  haveoverlap = TRUE;
16401  }
16402  }
16403  else if( node->op == SCIP_EXPR_POLYNOMIAL )
16404  {
16405  /* merge components for monomials of children from different components */
16407 
16408  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16409  assert(data != NULL);
16410 
16411  for( i = 0; i < data->nmonomials; ++i )
16412  for( j = 1; j < data->monomials[i]->nfactors; ++j )
16413  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16414  {
16415  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16416  compnr = childcomp[data->monomials[i]->childidxs[j]];
16417  for( k = 0; k < node->nchildren; ++k )
16418  if( childcomp[k] == compnr )
16419  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16420  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16421  haveoverlap = TRUE;
16422  }
16423  }
16424 
16425  if( haveoverlap )
16426  {
16427  /* some component numbers are unused, thus relabel and count final number of components */
16428  int* compmap;
16429 
16430  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16431  for( i = 0; i < node->nchildren; ++i )
16432  compmap[i] = -1; /*lint !e644*/
16433 
16434  ncomponents = 0;
16435  for( i = 0; i < node->nchildren; ++i )
16436  {
16437  if( compmap[childcomp[i]] == -1 )
16438  compmap[childcomp[i]] = ncomponents++;
16439  childcomp[i] = compmap[childcomp[i]];
16440  }
16441 
16442  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16443  }
16444  else
16445  {
16446  ncomponents = node->nchildren;
16447  }
16448 
16449  if( ncomponents == 1 )
16450  {
16451  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16452  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16453 
16454  *nexprtrees = 1;
16455  exprtreecoefs[0] = 1.0;
16456  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16457 
16458  return SCIP_OKAY;
16459  }
16460 
16461  if( ncomponents > exprtreessize )
16462  {
16463  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16464  for( i = 0; i < node->nchildren; ++i )
16465  if( childcomp[i] >= exprtreessize )
16466  childcomp[i] = exprtreessize-1;
16467  ncomponents = exprtreessize;
16468  }
16469 
16470  assert(ncomponents >= 2);
16471 
16472  /* setup expression trees for each component */
16473  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16474  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16475  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16476  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16477  for( i = 0; i < ncomponents; ++i )
16478  {
16479  /* initially, no variable appears in the expression tree */
16480  for( j = 0; j < exprgraph->nvars; ++j )
16481  varidx[j] = -1; /*lint !e644*/
16482  nexprvars = 0;
16483 
16484  /* collect expressions from children belonging to component i */
16485  nexprs = 0;
16486  for( j = 0; j < node->nchildren; ++j )
16487  {
16488  assert(childcomp[j] >= 0);
16489  assert(childcomp[j] < ncomponents);
16490  if( childcomp[j] != i )
16491  continue;
16492 
16493  /* create expression from the subgraph that has child j as root */
16494  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
16495  childmap[j] = nexprs; /*lint !e644*/
16496  childmapinv[nexprs] = j; /*lint !e644*/
16497  ++nexprs;
16498  }
16499 
16500  /* setup expression tree for component i */
16501  switch( node->op )
16502  {
16503  case SCIP_EXPR_PLUS:
16504  {
16505  assert(ncomponents == 2);
16506  assert(nexprs == 1);
16507 
16508  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16509  exprtreecoefs[i] = 1.0;
16510 
16511  break;
16512  }
16513 
16514  case SCIP_EXPR_MINUS:
16515  {
16516  assert(ncomponents == 2);
16517  assert(nexprs == 1);
16518 
16519  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16520  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16521  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16522  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16523 
16524  break;
16525  }
16526 
16527  case SCIP_EXPR_SUM:
16528  {
16529  if( nexprs == 1 )
16530  {
16531  /* component corresponds to exactly one child of node */
16532  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16533  }
16534  else
16535  {
16536  /* component corresponds to a sum of children of node */
16537  SCIP_EXPR* sumexpr;
16538 
16539  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16540  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16541  }
16542  exprtreecoefs[i] = 1.0;
16543 
16544  break;
16545  }
16546 
16547  case SCIP_EXPR_LINEAR:
16548  {
16549  SCIP_Real* nodecoefs;
16550  SCIP_EXPR* sumexpr;
16551 
16552  nodecoefs = (SCIP_Real*)node->data.data;
16553 
16554  /* if there is a constant, then we put it into the expression of the first component */
16555  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16556  {
16557  /* component corresponds to exactly one child of node */
16558  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16559  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16560  }
16561  else if( nexprs == 1 )
16562  {
16563  /* component corresponds to a sum of one child and a constant */
16564  assert(i == 0);
16565  assert(nodecoefs[node->nchildren] != 0.0);
16566  assert(nodecoefs[childmapinv[0]] != 0.0);
16567  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16568  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16569  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16570  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16571  }
16572  else
16573  {
16574  /* component corresponds to a linear combination of children of node */
16575 
16576  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16577  {
16578  /* if two expressions with equal sign, then create PLUS expression */
16579  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16580  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16581  }
16582  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16583  {
16584  /* if two expressions with opposite sign, then create MINUS expression */
16585  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16586  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16587  }
16588  else
16589  {
16590  /* assemble coefficents and create SUM or LINEAR expression */
16591  SCIP_Real* coefs;
16592  SCIP_Bool allcoefsequal;
16593 
16594  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16595  allcoefsequal = TRUE;
16596  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
16597  for( j = 0; j < nexprs; ++j )
16598  {
16599  coefs[j] = nodecoefs[childmapinv[j]];
16600  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
16601  }
16602 
16603  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16604  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16605  {
16606  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16607  exprtreecoefs[i] = coefs[0];
16608  }
16609  else
16610  {
16611  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16612  exprtreecoefs[i] = 1.0;
16613  }
16614 
16615  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16616  }
16617 
16618  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16619  }
16620 
16621  break;
16622  }
16623 
16624  case SCIP_EXPR_QUADRATIC:
16625  {
16626  SCIP_EXPR* quadexpr;
16628  SCIP_Real* lincoefs;
16629  SCIP_QUADELEM* quadelems;
16630  int nquadelems;
16631 
16632  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16633 
16634  exprtreecoefs[i] = 1.0;
16635 
16636  /* assemble coefficients corresponding to component i */
16637  if( nodedata->lincoefs != NULL )
16638  {
16639  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16640  for( j = 0; j < nexprs; ++j )
16641  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
16642  }
16643  else
16644  lincoefs = NULL;
16645 
16646  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16647  nquadelems = 0;
16648  for( j = 0; j < nodedata->nquadelems; ++j )
16649  {
16650  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16651  if( childcomp[nodedata->quadelems[j].idx1] != i )
16652  continue;
16653  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
16654  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16655  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16656  ++nquadelems;
16657  }
16658 
16659  /* put constant into first component */
16660  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16661  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16662 
16663  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16664  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16665 
16666  break;
16667  }
16668 
16669  case SCIP_EXPR_POLYNOMIAL:
16670  {
16671  SCIP_EXPR* polyexpr;
16673  SCIP_EXPRDATA_MONOMIAL** monomials;
16674  SCIP_Real constant;
16675  int nmonomials;
16676 
16677  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16678 
16679  constant = nodedata->constant;
16680  exprtreecoefs[i] = 1.0;
16681 
16682  /* collect monomials belonging to component i */
16683  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16684  nmonomials = 0;
16685  for( j = 0; j < nodedata->nmonomials; ++j )
16686  {
16687  if( nodedata->monomials[j]->nfactors == 0 )
16688  {
16689  constant += nodedata->monomials[j]->coef;
16690  continue;
16691  }
16692  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16693  continue;
16694 
16695  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16696  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
16697  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16698  {
16699  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16700  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16701  }
16702  ++nmonomials;
16703  }
16704 
16705  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16706  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16707 
16708  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16709 
16710  break;
16711  }
16712 
16713  default:
16714  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16715  return SCIP_ERROR;
16716  } /*lint !e788*/
16717 
16718  /* copy variables into expression tree */
16719  if( nexprvars > 0 )
16720  {
16721  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16722  for( j = 0; j < exprgraph->nvars; ++j )
16723  {
16724  assert(varidx[j] >= -1);
16725  assert(varidx[j] < nexprvars);
16726  if( varidx[j] >= 0 )
16727  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16728  }
16729  }
16730  }
16731 
16732  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16733  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16734  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16735  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16736  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16737 
16738  *nexprtrees = ncomponents;
16739 
16740  return SCIP_OKAY;
16741 }
16742 
16743 /** returns how often expression graph variables are used in a subtree of the expression graph */
16745  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16746  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
16747  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16748  )
16749 {
16750  assert(exprgraph != NULL);
16751  assert(node != NULL);
16752  assert(varsusage != NULL);
16753 
16754  BMSclearMemoryArray(varsusage, exprgraph->nvars);
16755 
16756  exprgraphNodeGetVarsUsage(node, varsusage);
16757 }
16758 
16759 /** gives the number of summands which the expression of an expression graph node consists of */
16761  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
16762  )
16763 {
16764  switch( node->op )
16765  {
16766  case SCIP_EXPR_PLUS:
16767  case SCIP_EXPR_MINUS:
16768  return 2;
16769 
16770  case SCIP_EXPR_SUM:
16771  case SCIP_EXPR_LINEAR:
16772  return node->nchildren;
16773 
16774  case SCIP_EXPR_QUADRATIC:
16775  {
16777 
16778  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16779  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16780  }
16781 
16782  case SCIP_EXPR_POLYNOMIAL:
16783  {
16785 
16786  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16787  return nodedata->nmonomials;
16788  }
16789 
16790  default:
16791  return 1;
16792  } /*lint !e788*/
16793 }
16794 
16795 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
16797  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16798  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16799  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16800  int* nexprtrees, /**< buffer to store number of expression trees */
16801  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16802  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16803  )
16804 {
16805  int* varidx;
16806  int nexprvars;
16807  int i;
16808 
16809  assert(exprgraph != NULL);
16810  assert(node != NULL);
16811  assert(node->depth >= 0);
16812  assert(node->pos >= 0);
16813  assert(exprtreessize > 0);
16814  assert(nexprtrees != NULL);
16815  assert(exprtrees != NULL);
16816  assert(exprtreecoefs != NULL);
16817 
16818  /* if node is not separable, fallback to SCIPexprgraphGetTree */
16819  if( node->op != SCIP_EXPR_PLUS &&
16820  node->op != SCIP_EXPR_MINUS &&
16821  node->op != SCIP_EXPR_SUM &&
16822  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16823  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16824  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16825  {
16826  *nexprtrees = 1;
16827  exprtreecoefs[0] = 1.0;
16828  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16829 
16830  return SCIP_OKAY;
16831  }
16832 
16833  switch( node->op )
16834  {
16835  case SCIP_EXPR_PLUS:
16836  {
16837  assert(exprtreessize >= 2);
16838 
16839  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16840  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16841 
16842  exprtreecoefs[0] = 1.0;
16843  exprtreecoefs[1] = 1.0;
16844 
16845  *nexprtrees = 2;
16846  break;
16847  }
16848 
16849  case SCIP_EXPR_MINUS:
16850  {
16851  assert(exprtreessize >= 2);
16852 
16853  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16854  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16855 
16856  exprtreecoefs[0] = 1.0;
16857  exprtreecoefs[1] = -1.0;
16858 
16859  *nexprtrees = 2;
16860  break;
16861  }
16862 
16863  case SCIP_EXPR_SUM:
16864  {
16865  assert(exprtreessize >= node->nchildren);
16866 
16867  for( i = 0; i < node->nchildren; ++i )
16868  {
16869  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16870  exprtreecoefs[i] = 1.0;
16871  }
16872 
16873  *nexprtrees = node->nchildren;
16874  break;
16875  }
16876 
16877  case SCIP_EXPR_LINEAR:
16878  {
16879  SCIP_Real* nodecoefs;
16880 
16881  assert(exprtreessize >= node->nchildren);
16882  assert(node->nchildren > 0);
16883 
16884  nodecoefs = (SCIP_Real*)node->data.data;
16885  assert(nodecoefs != NULL);
16886 
16887  for( i = 0; i < node->nchildren; ++i )
16888  {
16889  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16890  exprtreecoefs[i] = nodecoefs[i];
16891  }
16892 
16893  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16894  if( nodecoefs[node->nchildren] != 0.0 )
16895  {
16896  SCIP_EXPR* constexpr_;
16897 
16898  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16899  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16900  }
16901 
16902  *nexprtrees = node->nchildren;
16903  break;
16904  }
16905 
16906  case SCIP_EXPR_QUADRATIC:
16907  {
16909  SCIP_Real* lincoefs;
16910  SCIP_QUADELEM* quadelems;
16911  int nquadelems;
16912  SCIP_EXPR* expr;
16913  int j;
16914 
16915  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16916  lincoefs = nodedata->lincoefs;
16917  quadelems = nodedata->quadelems;
16918  nquadelems = nodedata->nquadelems;
16919 
16920  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16921  assert(node->nchildren > 0);
16922 
16923  *nexprtrees = 0;
16924  if( lincoefs != NULL )
16925  {
16926  for( i = 0; i < node->nchildren; ++i )
16927  {
16928  if( lincoefs[i] == 0.0 )
16929  continue;
16930  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16931  exprtreecoefs[*nexprtrees] = lincoefs[i];
16932  ++*nexprtrees;
16933  }
16934  }
16935 
16936  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16937  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16938 
16939  for( i = 0; i < nquadelems; ++i )
16940  {
16941  /* initially, no variable appears in the expression tree */
16942  for( j = 0; j < exprgraph->nvars; ++j )
16943  varidx[j] = -1; /*lint !e644*/
16944  nexprvars = 0;
16945 
16946  /* create expression from the subgraph at quadelems[i].idx1 */
16947  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16948 
16949  if( quadelems[i].idx1 == quadelems[i].idx2 )
16950  {
16951  /* create expression for square of expr */
16952  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16953  }
16954  else
16955  {
16956  SCIP_EXPR* expr2;
16957 
16958  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16959  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16960  /* create expression for product */
16961  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16962  }
16963 
16964  /* create expression tree for expr */
16965  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16966 
16967  /* copy variables into expression tree */
16968  if( nexprvars > 0 )
16969  {
16970  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16971  for( j = 0; j < exprgraph->nvars; ++j )
16972  {
16973  assert(varidx[j] >= -1);
16974  assert(varidx[j] < nexprvars);
16975  if( varidx[j] >= 0 )
16976  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16977  }
16978  }
16979 
16980  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16981 
16982  ++*nexprtrees;
16983  }
16984 
16985  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16986  if( nodedata->constant != 0.0 )
16987  {
16988  SCIP_EXPR* constexpr_;
16989 
16990  assert(*nexprtrees > 0);
16991  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16992  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16993  }
16994 
16995  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16996 
16997  break;
16998  }
16999 
17000  case SCIP_EXPR_POLYNOMIAL:
17001  {
17003  SCIP_EXPRDATA_MONOMIAL** monomials;
17004  SCIP_Real constant;
17005  int nmonomials;
17006  SCIP_EXPR* expr;
17007  int* childidxs;
17008  int j;
17009 
17010  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
17011  monomials = nodedata->monomials;
17012  nmonomials = nodedata->nmonomials;
17013  constant = nodedata->constant;
17014 
17015  assert(exprtreessize >= nmonomials);
17016  assert(node->nchildren > 0);
17017 
17018  *nexprtrees = 0;
17019 
17020  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
17021  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
17022 
17023  for( i = 0; i < nmonomials; ++i )
17024  {
17025  /* initially, no variable appears in the expression tree */
17026  for( j = 0; j < exprgraph->nvars; ++j )
17027  varidx[j] = -1;
17028  nexprvars = 0;
17029 
17030  if( monomials[i]->nfactors == 1 )
17031  {
17032  /* create expression from the subgraph at only factor */
17033  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17034 
17035  /* put exponent in, if not 1.0 */
17036  if( monomials[i]->exponents[0] == 1.0 )
17037  ;
17038  else if( monomials[i]->exponents[0] == 2.0 )
17039  {
17040  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
17041  }
17042  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
17043  {
17044  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
17045  }
17046  else
17047  {
17048  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
17049  }
17050  }
17051  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
17052  {
17053  SCIP_EXPR* expr2;
17054 
17055  /* create expressions for both factors */
17056  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17057  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
17058 
17059  /* create expression for product of factors */
17060  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
17061  }
17062  else
17063  {
17064  SCIP_EXPRDATA_MONOMIAL* monomial;
17065  SCIP_EXPR** exprs;
17066  int f;
17067 
17068  /* create expression for each factor, assemble varidx and nexprvars
17069  * create child indices (= identity) */
17070  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
17071  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
17072  for( f = 0; f < monomials[i]->nfactors; ++f )
17073  {
17074  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
17075  childidxs[f] = f; /*lint !e644*/
17076  }
17077 
17078  /* create monomial and polynomial expression for this monomial
17079  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
17080  */
17081  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
17082  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
17083  constant = 0.0;
17084 
17085  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
17086  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
17087  }
17088 
17089  /* create expression tree for expr */
17090  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
17091 
17092  /* copy variables into expression tree */
17093  if( nexprvars > 0 )
17094  {
17095  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
17096  for( j = 0; j < exprgraph->nvars; ++j )
17097  {
17098  assert(varidx[j] >= -1);
17099  assert(varidx[j] < nexprvars);
17100  if( varidx[j] >= 0 )
17101  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
17102  }
17103  }
17104 
17105  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
17106 
17107  ++*nexprtrees;
17108  }
17109 
17110  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
17111  if( constant != 0.0 )
17112  {
17113  SCIP_EXPR* constexpr_;
17114 
17115  assert(*nexprtrees > 0);
17116  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
17117  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
17118  }
17119 
17120  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
17121 
17122  break;
17123  }
17124 
17125  default:
17126  SCIPerrorMessage("unexpected operator type %d\n", node->op);
17127  return SCIP_ERROR;
17128  } /*lint !e788*/
17129 
17130  return SCIP_OKAY;
17131 }
17132 
17133 /**@} */
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:13358
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15864
void SCIPexprFreeDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6187
void SCIPexprtreeGetVarsUsage(SCIP_EXPRTREE *tree, int *varsusage)
Definition: expr.c:8911
void SCIPquadelemSort(SCIP_QUADELEM *quadelems, int nquadelems)
Definition: expr.c:9215
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15545
void SCIPexprSortMonomials(SCIP_EXPR *expr)
Definition: expr.c:7027
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:9096
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:9671
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:15000
static SCIP_RETCODE exprgraphNodeAddParent(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9348
SCIP_RETCODE SCIPexprSubstituteVars(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR **substexprs)
Definition: expr.c:8149
static SCIP_RETCODE exprsimplifyConvertToPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4268
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:15200
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2487
void SCIPintervalSign(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define QUADELEMS_ISBETTER(a, b)
Definition: expr.c:9093
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:4292
SCIP_RETCODE SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16796
SCIP_RETCODE SCIPexprtreeEvalInt(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_INTERVAL *val)
Definition: expr.c:8743
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:15284
#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:8760
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5924
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:14789
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:8030
static SCIP_RETCODE exprgraphNodeAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nexprs, SCIP_EXPRGRAPHNODE **exprs, int *childmap)
Definition: expr.c:9494
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12994
static SCIP_RETCODE exprgraphNodeCreateExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPR **expr, int *nexprvars, int *varidx)
Definition: expr.c:11809
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5697
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:8229
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14970
static SCIP_RETCODE exprgraphEnsureDepth(SCIP_EXPRGRAPH *exprgraph, int mindepth)
Definition: expr.c:12083
#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:11479
#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:2548
#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:14940
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:5067
static SCIP_RETCODE exprgraphNodeRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11410
const char * SCIPexpropGetName(SCIP_EXPROP op)
Definition: expr.c:3265
void SCIPexprChgPolynomialConstant(SCIP_EXPR *expr, SCIP_Real constant)
Definition: expr.c:6693
SCIP_RETCODE SCIPexprgraphAddConst(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15357
SCIP_RETCODE SCIPexprtreeGetMaxDegree(SCIP_EXPRTREE *tree, int *maxdegree)
Definition: expr.c:8714
SCIP_Real * SCIPexprtreeGetParamVals(SCIP_EXPRTREE *tree)
Definition: expr.c:8636
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:15044
SCIP_RETCODE SCIPexprCreateMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial, SCIP_Real coef, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:7039
static SCIP_DECL_SORTPTRCOMP(exprgraphnodecomp)
Definition: expr.c:127
void SCIPexprgraphCaptureNode(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12972
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:13487
static SCIP_DECL_EXPRFREEDATA(exprFreeDataLinear)
Definition: expr.c:2542
SCIP_Real SCIPexprGetRealPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5760
SCIP_EXPROP op
Definition: struct_expr.h:48
int SCIPexprGetOpIndex(SCIP_EXPR *expr)
Definition: expr.c:5727
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3132
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:7799
SCIP_RETCODE SCIPexprPolynomialPower(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int exponent)
Definition: expr.c:6789
void SCIPexprChgMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real newcoef)
Definition: expr.c:6855
SCIP_Bool SCIPexprHasParam(SCIP_EXPR *expr)
Definition: expr.c:7217
SCIPInterval cos(const SCIPInterval &x)
SCIP_Real SCIPexprGetPolynomialConstant(SCIP_EXPR *expr)
Definition: expr.c:5892
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:15918
#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:7584
void SCIPexprMonomialPower(SCIP_EXPRDATA_MONOMIAL *monomial, int exponent)
Definition: expr.c:6930
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14990
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:9981
static void exprgraphNodeCheckSeparabilityComponent(SCIP_EXPRGRAPHNODE *node, int *compnr, int nchildcomps, int *childcomps, int nvars, int *varcomps)
Definition: expr.c:12022
static SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11352
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13123
#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:8816
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13014
void SCIPexprGetVarsUsage(SCIP_EXPR *expr, int *varsusage)
Definition: expr.c:7561
void SCIPintervalMin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_INTERVAL SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13348
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15843
void SCIPexprReindexVars(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8187
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:14950
#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:7931
#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:7120
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:15404
SCIP_RETCODE SCIPexprMultiplyMonomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6895
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8775
SCIP_Bool SCIPquadelemSortedFind(SCIP_QUADELEM *quadelems, int idx1, int idx2, int nquadelems, int *pos)
Definition: expr.c:9240
unsigned int SCIP_EXPRINTCAPABILITY
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8646
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:15151
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13217
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:10042
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:12859
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:14423
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:5868
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:2236
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:5914
int SCIPexprGetIntPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5771
void SCIPintervalSin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3221
#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:9014
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13054
static SCIP_RETCODE exprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op, SCIP_EXPROPDATA opdata)
Definition: expr.c:9742
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13205
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:15112
#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:3363
SCIP_HASHMAP * varidxs
Definition: struct_expr.h:169
int SCIPexprgraphGetNodeOperatorIndex(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13064
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:4927
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:10912
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:13145
#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:13229
SCIP_RETCODE SCIPexprAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:6671
SCIP_Bool SCIPexprgraphHasNodeNonlinearAncestor(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14674
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13368
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:6588
SCIP_Bool SCIPexprgraphFindConstNode(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15746
int SCIPstrncpy(char *t, const char *s, int size)
Definition: misc.c:10647
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:7870
void SCIPexprgraphSetVarsBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_INTERVAL *varbounds)
Definition: expr.c:15012
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:15950
SCIP_RETCODE SCIPexprGetMaxDegree(SCIP_EXPR *expr, int *maxdegree)
Definition: expr.c:7236
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:10705
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:13557
SCIP_Real * SCIPexprGetQuadLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5844
SCIP_EXPRGRAPHNODE *** SCIPexprgraphGetNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14960
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16760
SCIP_INTERVAL bounds
Definition: struct_expr.h:137
static SCIP_RETCODE exprsimplifyRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4346
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:6145
static const char * curvnames[4]
Definition: expr.c:195
SCIPInterval sqrt(const SCIPInterval &x)
SCIP_Bool SCIPexprgraphHasNodeUserEstimator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13336
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:5099
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:5831
static SCIP_RETCODE exprgraphNodeReplaceChild(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE **oldchild, SCIP_EXPRGRAPHNODE *newchild)
Definition: expr.c:9595
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:9943
static SCIP_Bool exprgraphNodeIsParent(SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9463
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:6809
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:8616
SCIP_Bool SCIPexprAreMonomialsEqual(SCIP_EXPRDATA_MONOMIAL *monomial1, SCIP_EXPRDATA_MONOMIAL *monomial2, SCIP_Real eps)
Definition: expr.c:6824
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:13461
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16310
#define SCIP_CALL(x)
Definition: def.h:364
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12984
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:15104
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:6636
SCIP_RETCODE SCIPexprCheckCurvature(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_Real *param, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:8066
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:7973
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:7851
void SCIPexprMultiplyPolynomialByConstant(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real factor)
Definition: expr.c:6706
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:14727
static SCIP_RETCODE exprsimplifyUnconvertPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4893
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:8111
static SCIP_RETCODE exprgraphNodeUpdateBounds(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool parenttightenisinvalid)
Definition: expr.c:10149
#define SCIP_DECL_USEREXPRCURV(x)
Definition: type_expr.h:272
void SCIPexprFreeMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial)
Definition: expr.c:7096
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:6408
SCIP_EXPR * SCIPexprtreeGetRoot(SCIP_EXPRTREE *tree)
Definition: expr.c:8606
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:7157
SCIP_Bool SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14639
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:13244
#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:13075
#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:6250
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13157
#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:6743
void SCIPexprMergeMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real eps)
Definition: expr.c:6960
void SCIPintervalCos(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_EXPRINTCAPABILITY SCIPexprGetUserEvalCapability(SCIP_EXPR *expr)
Definition: expr.c:5966
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:5717
SCIP_Real SCIPexprGetSignPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5782
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2286
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:10084
SCIP_USEREXPRDATA * userdata
Definition: struct_expr.h:103
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14658
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:3014
void SCIPexprSortQuadElems(SCIP_EXPR *expr)
Definition: expr.c:6624
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:15064
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:4463
static SCIP_RETCODE exprgraphNodeRemoveParent(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9403
BMS_BLKMEM * blkmem
Definition: struct_expr.h:57
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8661
SCIP_RETCODE SCIPexprtreeFreeInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8684
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:9292
SCIP_Bool SCIPexprHasUserEstimator(SCIP_EXPR *expr)
Definition: expr.c:5955
#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:5707
SCIP_EXPORT void SCIPsortIntReal(int *intarray, SCIP_Real *realarray, int len)
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:16744
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:15084
static SCIP_Bool exprgraphFindConstNodePos(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *pos)
Definition: expr.c:9687
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:13611
SCIP_RETCODE SCIPexprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op,...)
Definition: expr.c:5977
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:8856
SCIP_Bool SCIPexprFindMonomialFactor(SCIP_EXPRDATA_MONOMIAL *monomial, int childidx, int *pos)
Definition: expr.c:7140
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:14549
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:10243
#define SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED
Definition: type_expr.h:212
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14601
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:126
SCIPInterval log(const SCIPInterval &x)
SCIP_USEREXPRDATA * SCIPexprGetUserData(SCIP_EXPR *expr)
Definition: expr.c:5944
SCIP_RETCODE SCIPexprtreeAddExpr(SCIP_EXPRTREE *tree, SCIP_EXPR *expr, SCIP_Bool copyexpr)
Definition: expr.c:8985
#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:5904
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:13086
void * SCIPexprGetOpData(SCIP_EXPR *expr)
Definition: expr.c:5749
SCIP_EXPROP op
Definition: struct_expr.h:119
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13169
#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:7996
int SCIPexprgraphGetNodeIntPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13112
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13024
SCIP_QUADELEM * quadelems
Definition: struct_expr.h:71
static void exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:9377
#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:12727
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:15717
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8208
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13134
#define SCIP_EXPRINTCAPABILITY_FUNCVALUE
SCIP_Real * SCIPexprGetLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5793
SCIP_Bool SCIPexprtreeHasParam(SCIP_EXPRTREE *tree)
Definition: expr.c:8698
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Real SCIPexprGetOpReal(SCIP_EXPR *expr)
Definition: expr.c:5738
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13044
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:13538
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:6225
SCIP_QUADELEM * SCIPexprGetQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5819
SCIP_RETCODE SCIPexprgraphCreateNodePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:13513
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:13324
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:4792
SCIP_RETCODE SCIPexprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op,...)
Definition: expr.c:13378
SCIP_RETCODE SCIPexprEvalIntShallow(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7911
SCIP_RETCODE SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14455
int SCIPexprGetNMonomials(SCIP_EXPR *expr)
Definition: expr.c:5880
#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:10604
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:609
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3048
SCIP_RETCODE SCIPexprtreeSimplify(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:8930
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:16257
#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:9927
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13004
#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:6866
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5934
void SCIPexprgraphPrintNode(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: expr.c:14711
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:9049
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:8542
#define SCIPisFinite(x)
Definition: pub_misc.h:1861
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:10128
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:134
int SCIPexprtreeGetNParams(SCIP_EXPRTREE *tree)
Definition: expr.c:8626
SCIP_RETCODE SCIPexprgraphSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange, SCIP_Bool *domainerror)
Definition: expr.c:15993
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
static SCIP_RETCODE exprsimplifyRemovePolynomialUnusedChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4412
#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:12163
static SCIP_RETCODE exprparseFindClosingParenthesis(const char *str, const char **endptr, int length)
Definition: expr.c:5028
SCIP_RETCODE SCIPexprAddToLinear(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nchildren, SCIP_Real *coefs, SCIP_EXPR **children, SCIP_Real constant)
Definition: expr.c:6543
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:4149
#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:6720
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13101
#define EPSFLOOR(x, eps)
Definition: def.h:196
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:122
static SCIP_DECL_HASHGETKEY(exprparseVarTableGetKey)
Definition: expr.c:4917
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:429
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13193
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:10674
#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:14980
#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:6506
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:5806
void SCIPexprtreeSetInterpreterData(SCIP_EXPRTREE *tree, SCIP_EXPRINTDATA *interpreterdata)
Definition: expr.c:8671
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:9105
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:8880
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
int SCIPexprGetNQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5856
static void exprgraphPrintNodeExpression(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, SCIP_Bool printchildrenbounds)
Definition: expr.c:9786
#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:12259
static void exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:11997
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15794
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3379
#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:13034
#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:8727
SCIP_EXPRINTCAPABILITY evalcapability
Definition: struct_expr.h:104
void SCIPexprgraphSetVarBounds(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_INTERVAL varbounds)
Definition: expr.c:15024
static SCIP_RETCODE exprgraphRemoveVar(SCIP_EXPRGRAPH *exprgraph, int varidx)
Definition: expr.c:12110
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:14574
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3297
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13181