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-2021 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 
8372  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8373  for( i = 0; i < expr->nchildren; ++i )
8374  {
8375  if( i > 0 )
8376  {
8377  SCIPmessageFPrintInfo(messagehdlr, file, "%s", expr->op == SCIP_EXPR_SUM ? " + " : " * ");
8378  }
8379  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8380  }
8381  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8382  }
8383  }
8384  break;
8385  }
8386 
8387  case SCIP_EXPR_LINEAR:
8388  {
8389  SCIP_Real constant;
8390  int i;
8391 
8392  constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
8393 
8394  if( expr->nchildren == 0 )
8395  {
8396  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", constant);
8397  break;
8398  }
8399 
8400  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8401 
8402  if( constant != 0.0 )
8403  {
8404  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", constant);
8405  }
8406 
8407  for( i = 0; i < expr->nchildren; ++i )
8408  {
8409  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", ((SCIP_Real*)expr->data.data)[i]);
8410  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8411  }
8412 
8413  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8414  break;
8415  }
8416 
8417  case SCIP_EXPR_QUADRATIC:
8418  {
8419  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
8420  int i;
8421 
8422  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
8423  assert(quadraticdata != NULL);
8424 
8425  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8426 
8427  if( quadraticdata->constant != 0.0 )
8428  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->constant);
8429 
8430  if( quadraticdata->lincoefs != NULL )
8431  for( i = 0; i < expr->nchildren; ++i )
8432  {
8433  if( quadraticdata->lincoefs[i] == 0.0 )
8434  continue;
8435  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->lincoefs[i]);
8436  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8437  }
8438 
8439  for( i = 0; i < quadraticdata->nquadelems; ++i )
8440  {
8441  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g ", quadraticdata->quadelems[i].coef);
8442  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
8443  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
8444  {
8445  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
8446  }
8447  else
8448  {
8449  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8450  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
8451  }
8452  }
8453 
8454  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8455  break;
8456  }
8457 
8458  case SCIP_EXPR_POLYNOMIAL:
8459  {
8460  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
8461  SCIP_EXPRDATA_MONOMIAL* monomialdata;
8462  int i;
8463  int j;
8464 
8465  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8466 
8467  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
8468  assert(polynomialdata != NULL);
8469 
8470  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
8471  {
8472  SCIPmessageFPrintInfo(messagehdlr, file, "%.15g", polynomialdata->constant);
8473  }
8474 
8475  for( i = 0; i < polynomialdata->nmonomials; ++i )
8476  {
8477  monomialdata = polynomialdata->monomials[i];
8478  SCIPmessageFPrintInfo(messagehdlr, file, " %+.15g", monomialdata->coef);
8479 
8480  for( j = 0; j < monomialdata->nfactors; ++j )
8481  {
8482  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8483 
8484  SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
8485  if( monomialdata->exponents[j] < 0.0 )
8486  {
8487  SCIPmessageFPrintInfo(messagehdlr, file, "^(%.15g)", monomialdata->exponents[j]);
8488  }
8489  else if( monomialdata->exponents[j] != 1.0 )
8490  {
8491  SCIPmessageFPrintInfo(messagehdlr, file, "^%.15g", monomialdata->exponents[j]);
8492  }
8493  }
8494  }
8495 
8496  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8497  break;
8498  }
8499 
8500  case SCIP_EXPR_USER:
8501  {
8502  SCIP_EXPRDATA_USER* exprdata;
8503  int i;
8504 
8505  exprdata = (SCIP_EXPRDATA_USER*)expr->data.data;
8506  assert(exprdata != NULL);
8507 
8508  if( exprdata->print != NULL )
8509  {
8510  exprdata->print(exprdata->userdata, messagehdlr, file);
8511  }
8512  else
8513  {
8514  SCIPmessageFPrintInfo(messagehdlr, file, "user");
8515  }
8516 
8517  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8518  for( i = 0; i < expr->nchildren; ++i )
8519  {
8520  if( i > 0 )
8521  {
8522  SCIPmessageFPrintInfo(messagehdlr, file, ",");
8523  }
8524  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8525  }
8526  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8527 
8528  break;
8529  }
8530 
8531  case SCIP_EXPR_LAST:
8532  {
8533  SCIPerrorMessage("invalid expression\n");
8534  SCIPABORT();
8535  }
8536  }
8537 }
8538 
8539 /** parses an expression from a string */
8541  BMS_BLKMEM* blkmem, /**< block memory data structure */
8542  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8543  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
8544  const char* str, /**< pointer to the string to be parsed */
8545  const char* lastchar, /**< pointer to the last char of str that should be parsed */
8546  int* nvars, /**< buffer to store number of variables */
8547  int* varnames, /**< buffer to store variable names, prefixed by index (as int) */
8548  int varnameslength /**< length of the varnames buffer array */
8549  )
8550 {
8551  SCIP_HASHTABLE* vartable;
8552  SCIP_RETCODE retcode;
8553 
8554  assert(blkmem != NULL);
8555  assert(expr != NULL);
8556  assert(str != NULL);
8557  assert(lastchar != NULL);
8558  assert(nvars != NULL);
8559  assert(varnames != NULL);
8560 
8561  *nvars = 0;
8562 
8563  /* create a hash table for variable names and corresponding expression index
8564  * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
8565  */
8566  SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString,
8567  SCIPhashKeyValString, NULL) );
8568 
8569  retcode = exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames,
8570  &varnameslength, vartable, 0);
8571 
8572  SCIPhashtableFree(&vartable);
8573 
8574  return retcode;
8575 }
8576 
8577 
8578 /**@} */
8579 
8580 /**@name Expression tree methods */
8581 /**@{ */
8582 
8583 /* In debug mode, the following methods are implemented as function calls to ensure
8584  * type validity.
8585  * In optimized mode, the methods are implemented as defines to improve performance.
8586  * However, we want to have them in the library anyways, so we have to undef the defines.
8587  */
8588 
8589 #undef SCIPexprtreeGetRoot
8590 #undef SCIPexprtreeGetNVars
8591 #undef SCIPexprtreeGetNParams
8592 #undef SCIPexprtreeGetParamVals
8593 #undef SCIPexprtreeSetParamVal
8594 #undef SCIPexprtreeGetInterpreterData
8595 #undef SCIPexprtreeSetInterpreterData
8596 #undef SCIPexprtreeFreeInterpreterData
8597 #undef SCIPexprtreeHasParam
8598 #undef SCIPexprtreeGetMaxDegree
8599 #undef SCIPexprtreeEval
8600 #undef SCIPexprtreeEvalInt
8601 #undef SCIPexprtreePrint
8602 
8603 /** returns root expression of an expression tree */
8605  SCIP_EXPRTREE* tree /**< expression tree */
8606  )
8607 {
8608  assert(tree != NULL);
8609 
8610  return tree->root;
8611 }
8612 
8613 /** returns number of variables in expression tree */
8615  SCIP_EXPRTREE* tree /**< expression tree */
8616  )
8617 {
8618  assert(tree != NULL);
8619 
8620  return tree->nvars;
8621 }
8622 
8623 /** returns number of parameters in expression tree */
8625  SCIP_EXPRTREE* tree /**< expression tree */
8626  )
8627 {
8628  assert(tree != NULL);
8629 
8630  return tree->nparams;
8631 }
8632 
8633 /** returns values of parameters or NULL if none */
8635  SCIP_EXPRTREE* tree /**< expression tree */
8636  )
8637 {
8638  assert(tree != NULL);
8639 
8640  return tree->params;
8641 }
8642 
8643 /** sets value of a single parameter in expression tree */
8645  SCIP_EXPRTREE* tree, /**< expression tree */
8646  int paramidx, /**< index of parameter */
8647  SCIP_Real paramval /**< new value of parameter */
8648  )
8649 {
8650  assert(tree != NULL);
8651  assert(paramidx >= 0);
8652  assert(paramidx < tree->nparams);
8653  assert(tree->params != NULL);
8654 
8655  tree->params[paramidx] = paramval;
8656 }
8657 
8658 /** gets data of expression tree interpreter, or NULL if not set */
8660  SCIP_EXPRTREE* tree /**< expression tree */
8661  )
8662 {
8663  assert(tree != NULL);
8664 
8665  return tree->interpreterdata;
8666 }
8667 
8668 /** sets data of expression tree interpreter */
8670  SCIP_EXPRTREE* tree, /**< expression tree */
8671  SCIP_EXPRINTDATA* interpreterdata /**< expression interpreter data */
8672  )
8673 {
8674  assert(tree != NULL);
8675  assert(interpreterdata != NULL);
8676  assert(tree->interpreterdata == NULL);
8677 
8678  tree->interpreterdata = interpreterdata;
8679 }
8680 
8681 /** frees data of expression tree interpreter, if any */
8683  SCIP_EXPRTREE* tree /**< expression tree */
8684  )
8685 {
8686  if( tree->interpreterdata != NULL )
8687  {
8689  assert(tree->interpreterdata == NULL);
8690  }
8691 
8692  return SCIP_OKAY;
8693 }
8694 
8695 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
8697  SCIP_EXPRTREE* tree /**< expression tree */
8698  )
8699 {
8700  assert(tree != NULL);
8701 
8702  return SCIPexprHasParam(tree->root);
8703 }
8704 
8705 /** Gives maximal degree of expression in expression tree.
8706  *
8707  * If constant expression, gives 0,
8708  * if linear expression, gives 1,
8709  * if polynomial expression, gives its maximal degree,
8710  * otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8711  */
8713  SCIP_EXPRTREE* tree, /**< expression tree */
8714  int* maxdegree /**< buffer to store maximal degree */
8715  )
8716 {
8717  assert(tree != NULL);
8718 
8719  SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8720 
8721  return SCIP_OKAY;
8722 }
8723 
8724 /** evaluates an expression tree w.r.t. a point */
8726  SCIP_EXPRTREE* tree, /**< expression tree */
8727  SCIP_Real* varvals, /**< values for variables */
8728  SCIP_Real* val /**< buffer to store expression tree value */
8729  )
8730 {
8731  assert(tree != NULL);
8732  assert(varvals != NULL || tree->nvars == 0);
8733  assert(val != NULL);
8734 
8735  SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8736 
8737  return SCIP_OKAY;
8738 }
8739 
8740 /** evaluates an expression tree w.r.t. an interval */
8742  SCIP_EXPRTREE* tree, /**< expression tree */
8743  SCIP_Real infinity, /**< value for infinity */
8744  SCIP_INTERVAL* varvals, /**< intervals for variables */
8745  SCIP_INTERVAL* val /**< buffer to store expression tree value */
8746  )
8747 {
8748  assert(tree != NULL);
8749  assert(varvals != NULL || tree->nvars == 0);
8750  assert(val != NULL);
8751 
8752  SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8753 
8754  return SCIP_OKAY;
8755 }
8756 
8757 /** prints an expression tree */
8759  SCIP_EXPRTREE* tree, /**< expression tree */
8760  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8761  FILE* file, /**< file for printing, or NULL for stdout */
8762  const char** varnames, /**< names of variables, or NULL for default names */
8763  const char** paramnames /**< names of parameters, or NULL for default names */
8764  )
8765 {
8766  assert(tree != NULL);
8767 
8768  SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8769 }
8770 
8771 
8772 /** creates an expression tree */
8774  BMS_BLKMEM* blkmem, /**< block memory data structure */
8775  SCIP_EXPRTREE** tree, /**< buffer to store address of created expression tree */
8776  SCIP_EXPR* root, /**< pointer to root expression, not copied deep !, can be NULL */
8777  int nvars, /**< number of variables in variable mapping */
8778  int nparams, /**< number of parameters in expression */
8779  SCIP_Real* params /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8780  )
8781 {
8782  assert(blkmem != NULL);
8783  assert(tree != NULL);
8784 
8785  SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8786 
8787  (*tree)->blkmem = blkmem;
8788  (*tree)->root = root;
8789  (*tree)->nvars = nvars;
8790  (*tree)->vars = NULL;
8791  (*tree)->nparams = nparams;
8792  (*tree)->interpreterdata = NULL;
8793 
8794  if( params != NULL )
8795  {
8796  assert(nparams > 0);
8797  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8798  }
8799  else if( nparams > 0 )
8800  {
8801  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8802  BMSclearMemoryArray((*tree)->params, nparams);
8803  }
8804  else
8805  {
8806  assert(nparams == 0);
8807  (*tree)->params = NULL;
8808  }
8809 
8810  return SCIP_OKAY;
8811 }
8812 
8813 /** copies an expression tree */
8815  BMS_BLKMEM* blkmem, /**< block memory that should be used in new expression tree */
8816  SCIP_EXPRTREE** targettree, /**< buffer to store address of copied expression tree */
8817  SCIP_EXPRTREE* sourcetree /**< expression tree to copy */
8818  )
8819 {
8820  assert(blkmem != NULL);
8821  assert(targettree != NULL);
8822  assert(sourcetree != NULL);
8823 
8824  /* copy expression tree "header" */
8825  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8826 
8827  /* we may have a new block memory; and we do not want to keep the others interpreter data */
8828  (*targettree)->blkmem = blkmem;
8829  (*targettree)->interpreterdata = NULL;
8830 
8831  /* copy variables, if any */
8832  if( sourcetree->vars != NULL )
8833  {
8834  assert(sourcetree->nvars > 0);
8835 
8836  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8837  }
8838 
8839  /* copy parameters, if any */
8840  if( sourcetree->params != NULL )
8841  {
8842  assert(sourcetree->nparams > 0);
8843 
8844  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8845  }
8846 
8847  /* copy expression */
8848  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8849 
8850  return SCIP_OKAY;
8851 }
8852 
8853 /** frees an expression tree */
8855  SCIP_EXPRTREE** tree /**< pointer to expression tree that is freed */
8856  )
8857 {
8858  assert( tree != NULL);
8859  assert(*tree != NULL);
8860 
8862 
8863  if( (*tree)->root != NULL )
8864  {
8865  SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8866  assert((*tree)->root == NULL);
8867  }
8868 
8869  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars, (*tree)->nvars );
8870  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8871 
8872  BMSfreeBlockMemory((*tree)->blkmem, tree);
8873 
8874  return SCIP_OKAY;
8875 }
8876 
8877 /** sets number and values of all parameters in expression tree */
8879  SCIP_EXPRTREE* tree, /**< expression tree */
8880  int nparams, /**< number of parameters */
8881  SCIP_Real* paramvals /**< values of parameters, can be NULL if nparams == 0 */
8882  )
8883 {
8884  assert(tree != NULL);
8885  assert(paramvals != NULL || nparams == 0);
8886 
8887  if( nparams == 0 )
8888  {
8889  BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8890  }
8891  else if( tree->params != NULL )
8892  {
8893  SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8894  BMScopyMemoryArray(tree->params, paramvals, nparams);
8895  }
8896  else
8897  {
8898  SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8899  }
8900 
8901  tree->nparams = nparams;
8902  assert(tree->params != NULL || tree->nparams == 0);
8903 
8904  return SCIP_OKAY;
8905 }
8906 
8907 
8908 /** gives the number of usages for each variable in the expression tree */
8910  SCIP_EXPRTREE* tree, /**< expression tree */
8911  int* varsusage /**< array where to store for each variable how often it is used in the tree */
8912  )
8913 {
8914  assert(tree != NULL);
8915  assert(varsusage != NULL);
8916 
8917  if( tree->nvars == 0 )
8918  return;
8919 
8920  BMSclearMemoryArray(varsusage, tree->nvars);
8921  SCIPexprGetVarsUsage(tree->root, varsusage);
8922 }
8923 
8924 /** aims at simplifying an expression and splitting of a linear expression
8925  *
8926  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
8927  */
8929  SCIP_EXPRTREE* tree, /**< expression tree */
8930  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8931  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
8932  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8933  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8934  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8935  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
8936  )
8937 {
8938 #ifndef NDEBUG
8939  SCIP_RANDNUMGEN* randnumgen;
8940  SCIP_Real* testx;
8941  SCIP_Real testval_before;
8942  SCIP_Real testval_after;
8943  int i;
8944 #endif
8945 
8946  assert(tree != NULL);
8947 
8948 #ifndef NDEBUG
8949  SCIP_CALL( SCIPrandomCreate(&randnumgen, tree->blkmem, 42) );
8950 
8951  SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) ); /*lint !e666*/
8952  for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8953  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
8954  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8955 
8956  SCIPrandomFree(&randnumgen, tree->blkmem);
8957 #endif
8958 
8959  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8960  SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8961 
8962 #ifndef NDEBUG
8963  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8964  if( nlinvars != NULL && testval_before == testval_before ) /*lint !e777*/
8965  for( i = 0; i < *nlinvars; ++i )
8966  testval_after += lincoefs[i] * testx[linidxs[i]];
8967  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
8968  BMSfreeMemoryArray(&testx);
8969 #endif
8970 
8971  /* removing something from the the tree may invalidate the interpreter data */
8972  if( nlinvars != NULL && *nlinvars > 0 )
8974 
8975  return SCIP_OKAY;
8976 }
8977 
8978 /** adds an expression to the root expression of the tree
8979  *
8980  * The root is replaced with an SCIP_EXPR_PLUS expression which has the previous root and the given expression (or a copy of it) as children.
8981  * If no root existed yet, then the root is set to the given expression (or a copy of it).
8982  */
8984  SCIP_EXPRTREE* tree, /**< expression tree */
8985  SCIP_EXPR* expr, /**< expression to add to tree */
8986  SCIP_Bool copyexpr /**< whether expression should be copied */
8987  )
8988 {
8989  assert(tree != NULL);
8990 
8991  /* adding something to the tree may invalidate the interpreter data */
8993 
8994  if( copyexpr )
8995  {
8996  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &expr, expr) );
8997  }
8998 
8999  if( tree->root == NULL )
9000  {
9001  tree->root = expr;
9002  }
9003  else
9004  {
9005  SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
9006  }
9007 
9008  return SCIP_OKAY;
9009 }
9010 
9011 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
9013  SCIP_EXPRTREE* tree, /**< expression tree */
9014  SCIP_Real infinity, /**< value for infinity */
9015  SCIP_INTERVAL* varbounds, /**< domains of variables */
9016  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
9017  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression, or NULL if not needed */
9018  )
9019 {
9020  SCIP_INTERVAL exprbounds;
9021 
9022  assert(tree != NULL);
9023 
9024  if( tree->root == NULL )
9025  {
9026  *curv = SCIP_EXPRCURV_LINEAR;
9027 
9028  if( bounds != NULL )
9029  SCIPintervalSet(bounds, 0.0);
9030 
9031  return SCIP_OKAY;
9032  }
9033 
9034  SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
9035 
9036  if( bounds != NULL )
9037  *bounds = exprbounds;
9038 
9039  return SCIP_OKAY;
9040 }
9041 
9042 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
9043  *
9044  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL.
9045  * If substexprs[i] == NULL, then the variable expression i is not touched.
9046  */
9048  SCIP_EXPRTREE* tree, /**< expression tree */
9049  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
9050  )
9051 {
9052  assert(tree != NULL);
9053 
9054  if( tree->root == NULL )
9055  return SCIP_OKAY;
9056 
9057  if( tree->root->op == SCIP_EXPR_VARIDX )
9058  {
9059  int varidx;
9060 
9061  varidx = tree->root->data.intval;
9062  assert(varidx >= 0);
9063  if( substexprs[varidx] != NULL )
9064  {
9065  /* substitute root expression */
9066  SCIPexprFreeDeep(tree->blkmem, &tree->root);
9067  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
9068  }
9069  }
9070  else
9071  {
9072  /* check children (and grandchildren and so on...) of root expression */
9073  SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
9074  }
9075 
9076  /* substitution of variables should invalidate interpreter data */
9078 
9079  return SCIP_OKAY;
9080 }
9081 
9082 /**@} */
9083 
9084 /**@name Quadratic element methods */
9085 /**@{ */
9086 
9087 /** comparing two quadratic elements
9088  *
9089  * a is better than b if index1 of a is smaller than index1 of b or index1 of both is equal but index2 of a is smaller than index2 of b
9090  */
9091 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
9092 
9093 /** swaps two quadratic elements */
9094 #define QUADELEMS_SWAP(x,y) \
9095  { \
9096  SCIP_QUADELEM temp = x; \
9097  x = y; \
9098  y = temp; \
9099  }
9100 
9101 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
9102 static
9104  SCIP_QUADELEM* elems, /**< array to be sorted */
9105  int start, /**< starting index */
9106  int end /**< ending index */
9107  )
9108 {
9109  assert(start <= end);
9110 
9111  /* use quick sort for long lists */
9112  while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
9113  {
9114  SCIP_QUADELEM pivotkey;
9115  int lo;
9116  int hi;
9117  int mid;
9118 
9119  /* select pivot element */
9120  mid = (start+end)/2;
9121  pivotkey = elems[mid];
9122 
9123  /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
9124  lo = start;
9125  hi = end;
9126  for( ;; )
9127  {
9128  while( lo < end && QUADELEMS_ISBETTER(elems[lo], pivotkey) )
9129  lo++;
9130  while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
9131  hi--;
9132 
9133  if( lo >= hi )
9134  break;
9135 
9136  QUADELEMS_SWAP(elems[lo], elems[hi]);
9137 
9138  lo++;
9139  hi--;
9140  }
9141  assert(hi == lo-1 || hi == start);
9142 
9143  /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
9144  while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
9145  lo++;
9146 
9147  /* make sure that we have at least one element in the smaller partition */
9148  if( lo == start )
9149  {
9150  /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
9151  assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
9152  assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
9153  QUADELEMS_SWAP(elems[lo], elems[mid]);
9154  lo++;
9155  }
9156 
9157  /* sort the smaller partition by a recursive call, sort the larger part without recursion */
9158  if( hi - start <= end - lo )
9159  {
9160  /* sort [start,hi] with a recursive call */
9161  if( start < hi )
9162  quadelemsQuickSort(elems, start, hi);
9163 
9164  /* now focus on the larger part [lo,end] */
9165  start = lo;
9166  }
9167  else
9168  {
9169  /* sort [lo,end] with a recursive call */
9170  if( lo < end )
9171  quadelemsQuickSort(elems, lo, end);
9172 
9173  /* now focus on the larger part [start,hi] */
9174  end = hi;
9175  }
9176  }
9177 
9178  /* use shell sort on the remaining small list */
9179  if( end - start >= 1 )
9180  {
9181  static const int incs[3] = {1, 5, 19}; /* sequence of increments */
9182  int k;
9183 
9184  for( k = 2; k >= 0; --k )
9185  {
9186  int h;
9187  int i;
9188 
9189  for( h = incs[k], i = h + start; i <= end; ++i )
9190  {
9191  int j;
9192  SCIP_QUADELEM tempkey = elems[i];
9193 
9194  j = i;
9195  while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
9196  {
9197  elems[j] = elems[j-h];
9198  j -= h;
9199  }
9200 
9201  elems[j] = tempkey;
9202  }
9203  }
9204  }
9205 }
9206 
9207 /** sorts an array of quadratic elements
9208  *
9209  * The elements are sorted such that the first index is increasing and
9210  * such that among elements with the same first index, the second index is increasing.
9211  * For elements with same first and second index, the order is not defined.
9212  */
9214  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9215  int nquadelems /**< number of quadratic elements */
9216  )
9217 {
9218  if( nquadelems == 0 )
9219  return;
9220 
9221 #ifndef NDEBUG
9222  {
9223  int i;
9224  for( i = 0; i < nquadelems; ++i )
9225  assert(quadelems[i].idx1 <= quadelems[i].idx2);
9226  }
9227 #endif
9228 
9229  quadelemsQuickSort(quadelems, 0, nquadelems-1);
9230 }
9231 
9232 /** Finds an index pair in a sorted array of quadratic elements.
9233  *
9234  * If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
9235  * If (idx1,idx2) is not found in quadelems, then returns FALSE and stores position where a quadratic element with these indices would be inserted in *pos.
9236  * Assumes that idx1 <= idx2.
9237  */
9239  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9240  int idx1, /**< index of first variable in element to search for */
9241  int idx2, /**< index of second variable in element to search for */
9242  int nquadelems, /**< number of quadratic elements in array */
9243  int* pos /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
9244  )
9245 {
9246  int left;
9247  int right;
9248 
9249  assert(quadelems != NULL || nquadelems == 0);
9250  assert(idx1 <= idx2);
9251 
9252  if( nquadelems == 0 )
9253  {
9254  if( pos != NULL )
9255  *pos = 0;
9256  return FALSE;
9257  }
9258 
9259  left = 0;
9260  right = nquadelems - 1;
9261  while( left <= right )
9262  {
9263  int middle;
9264 
9265  middle = (left+right)/2;
9266  assert(0 <= middle && middle < nquadelems);
9267 
9268  if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) ) /*lint !e613*/
9269  right = middle - 1;
9270  else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) ) /*lint !e613*/
9271  left = middle + 1;
9272  else
9273  {
9274  if( pos != NULL )
9275  *pos = middle;
9276  return TRUE;
9277  }
9278  }
9279  assert(left == right+1);
9280 
9281  if( pos != NULL )
9282  *pos = left;
9283  return FALSE;
9284 }
9285 
9286 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
9287  *
9288  * Assumes that elements have been sorted before.
9289  */
9291  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9292  int nquadelems, /**< number of quadratic elements */
9293  int* nquadelemsnew /**< pointer to store new (reduced) number of quadratic elements */
9294  )
9295 {
9296  int i;
9297  int next;
9298 
9299  assert(quadelems != NULL);
9300  assert(nquadelemsnew != NULL);
9301  assert(nquadelems >= 0);
9302 
9303  i = 0;
9304  next = 0;
9305  while( next < nquadelems )
9306  {
9307  /* assert that array is sorted */
9308  assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
9309  (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
9310 
9311  /* skip elements with coefficient 0.0 */
9312  if( quadelems[next].coef == 0.0 )
9313  {
9314  ++next;
9315  continue;
9316  }
9317 
9318  /* if next element has same index as previous one, add it to the previous one */
9319  if( i >= 1 &&
9320  quadelems[i-1].idx1 == quadelems[next].idx1 &&
9321  quadelems[i-1].idx2 == quadelems[next].idx2 )
9322  {
9323  quadelems[i-1].coef += quadelems[next].coef;
9324  ++next;
9325  continue;
9326  }
9327 
9328  /* otherwise, move next element to current position */
9329  quadelems[i] = quadelems[next];
9330  ++i;
9331  ++next;
9332  }
9333  assert(next == nquadelems);
9334 
9335  /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
9336  *nquadelemsnew = i;
9337 }
9338 
9339 /**@} */
9340 
9341 /**@name Expression graph node private methods */
9342 /**@{ */
9343 
9344 /** adds a parent to an expression graph node */
9345 static
9347  BMS_BLKMEM* blkmem, /**< block memory */
9348  SCIP_EXPRGRAPHNODE* node, /**< expression graph node where to add a parent */
9349  SCIP_EXPRGRAPHNODE* parent /**< parent node */
9350  )
9351 {
9352  assert(blkmem != NULL);
9353  assert(node != NULL);
9354  assert(node->depth >= 0);
9355  assert(node->pos >= 0);
9356  assert(parent != NULL);
9357  assert(parent->depth >= 0);
9358  assert(parent->pos >= 0);
9359  assert(parent->depth > node->depth); /* a parent node need to have larger depth */
9360 
9361  ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
9362  assert(node->nparents < node->parentssize);
9363 
9364  node->parents[node->nparents] = parent;
9365  ++node->nparents;
9366 
9367  /* update sorted flag */
9368  node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (exprgraphnodecomp((void*)node->parents[node->nparents-2], (void*)parent) <= 0));
9369 
9370  return SCIP_OKAY;
9371 }
9372 
9373 /** ensures that array of parents in a node is sorted */
9374 static
9376  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
9377  )
9378 {
9379  assert(node != NULL);
9380 
9381  if( node->parentssorted )
9382  {
9383 #ifndef NDEBUG
9384  int i;
9385  for( i = 1; i < node->nparents; ++i )
9386  assert(exprgraphnodecomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
9387 #endif
9388  return;
9389  }
9390 
9391  SCIPsortPtr((void**)node->parents, exprgraphnodecomp, node->nparents);
9392 
9393  node->parentssorted = TRUE;
9394 }
9395 
9396 /** removes a parent from an expression graph node
9397  *
9398  * If the node is not used and has no other parents, then it is freed.
9399  */
9400 static
9402  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9403  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to remove a parent, *node will be set to NULL */
9404  SCIP_EXPRGRAPHNODE* parent /**< parent node to remove */
9405  )
9406 {
9407  SCIP_EXPRGRAPHNODE* node_;
9408  int pos;
9409  int i;
9410 
9411  assert(exprgraph != NULL);
9412  assert(node != NULL);
9413  assert(*node != NULL);
9414  assert((*node)->depth >= 0);
9415  assert((*node)->pos >= 0);
9416  assert((*node)->nparents > 0);
9417  assert(parent != NULL);
9418  assert(parent->depth >= 0);
9419  assert(parent->pos >= 0);
9420  assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
9421 
9422  /* find parent */
9423  exprgraphNodeSortParents(*node);
9424  (void) SCIPsortedvecFindPtr((void**)(*node)->parents, exprgraphnodecomp, (void*)parent, (*node)->nparents, &pos);
9425  assert(pos >= 0);
9426  assert(pos < (*node)->nparents);
9427  assert((*node)->parents[pos] == parent);
9428 
9429 #ifdef SCIP_DISABLED_CODE
9430  /* move last parent to pos, if pos is before last
9431  * update sorted flag */
9432  if( pos < (*node)->nparents-1 )
9433  {
9434  (*node)->parents[pos] = (*node)->parents[(*node)->nparents-1];
9435  (*node)->parentssorted = ((*node)->nparents <= 2);
9436  }
9437 #else
9438  /* move all parents behind pos one position up
9439  * this is faster than moving the last parent to position pos if there are many repeated calls to this function as the parents array remains sorted
9440  */
9441  for( i = pos+1; i < (*node)->nparents; ++i )
9442  (*node)->parents[i-1] = (*node)->parents[i];
9443 #endif
9444  --(*node)->nparents;
9445 
9446  /* keep pointer to *node in case it is still used */
9447  node_ = (*node)->nuses > 0 ? *node : NULL;
9448 
9449  /* capture and release node so it is freed if possible */
9450  SCIPexprgraphCaptureNode(*node);
9451  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
9452 
9453  /* restore pointer, if node still exists */
9454  *node = node_;
9455 
9456  return SCIP_OKAY;
9457 }
9458 
9459 /** checks if a node is parent of a node */
9460 static
9462  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9463  SCIP_EXPRGRAPHNODE* parent /**< parent to look for */
9464  )
9465 {
9466  int pos;
9467 
9468  assert(node != NULL);
9469  assert(parent != NULL);
9470 
9471  /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
9472  if( node->depth >= parent->depth || node->nparents == 0 )
9473  return FALSE;
9474  assert(node->parents != NULL);
9475 
9476  /* ensure parents array is sorted */
9478 
9479  return SCIPsortedvecFindPtr((void**)node->parents, exprgraphnodecomp, (void*)parent, node->nparents, &pos);
9480 }
9481 
9482 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
9483  *
9484  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
9485  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
9486  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
9487  *
9488  * It is assumed that node and all exprs are in the expression graph already.
9489  * It is assumed that all expressions that are added have lower depth than node.
9490  */
9491 static
9493  BMS_BLKMEM* blkmem, /**< block memory */
9494  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9495  int nexprs, /**< number of children to add */
9496  SCIP_EXPRGRAPHNODE** exprs, /**< children nodes to add */
9497  int* childmap /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
9498  )
9499 {
9500  int i;
9501  int j;
9502  int orignchildren;
9503  SCIP_Bool existsalready;
9504 
9505  assert(blkmem != NULL);
9506  assert(node != NULL);
9507  assert(node->depth > 0);
9508  assert(node->pos >= 0);
9509  assert(node->op == SCIP_EXPR_SUM || node->op == SCIP_EXPR_PRODUCT || node->op == SCIP_EXPR_LINEAR || node->op == SCIP_EXPR_QUADRATIC || node->op == SCIP_EXPR_POLYNOMIAL);
9510  assert(exprs != NULL || nexprs == 0);
9511 
9512  if( nexprs == 0 )
9513  return SCIP_OKAY;
9514 
9515  orignchildren = node->nchildren;
9516  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
9517 
9518  for( i = 0; i < nexprs; ++i )
9519  {
9520  assert(exprs[i]->depth >= 0); /*lint !e613*/
9521  assert(exprs[i]->pos >= 0); /*lint !e613*/
9522  assert(exprs[i]->depth < node->depth); /*lint !e613*/
9523 
9524  /* check if exprs[i] is a child already, if not SUM or PRODUCT */
9525  existsalready = FALSE;
9526  if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
9527  for( j = 0; j < orignchildren; ++j )
9528  /* during simplification of polynomials, their may be NULL's in children array */
9529  if( node->children[j] != NULL && node->children[j] == exprs[i] ) /*lint !e613*/
9530  {
9531  existsalready = TRUE;
9532  break;
9533  }
9534 
9535  if( !existsalready )
9536  {
9537  /* add exprs[i] to children array */
9538  node->children[node->nchildren] = exprs[i]; /*lint !e613*/
9539  SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) ); /*lint !e613*/
9540  if( childmap != NULL )
9541  childmap[i] = node->nchildren;
9542  ++node->nchildren;
9543  }
9544  else
9545  {
9546  if( childmap != NULL )
9547  childmap[i] = j; /*lint !e644*/
9548  if( node->op == SCIP_EXPR_LINEAR )
9549  {
9550  /* if linear expression, increase coefficient by 1.0 */
9551  ((SCIP_Real*)node->data.data)[j] += 1.0;
9552  }
9553  }
9554  }
9555 
9556  /* shrink children array to actually used size */
9557  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
9558 
9559  if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
9560  {
9561  /* if linear expression, then add 1.0 coefficients for new expressions */
9562  SCIP_Real* data;
9563 
9564  data = (SCIP_Real*)node->data.data;
9565  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
9566  data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
9567  for( i = orignchildren; i < node->nchildren; ++i )
9568  data[i] = 1.0;
9569  node->data.data = (void*)data;
9570  }
9571  else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
9572  {
9573  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
9575 
9576  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9577  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
9578  BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren); /*lint !e866*/
9579  }
9580 
9581  node->simplified = FALSE;
9582 
9583  return SCIP_OKAY;
9584 }
9585 
9586 /** replaces a child node by another node
9587  *
9588  * Assumes that both nodes represent the same expression.
9589  * If this node was the last parent of oldchild and oldchild is not in use, then it is freed.
9590  * newchild must have deeper depth than node.
9591  */
9592 static
9594  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9595  SCIP_EXPRGRAPHNODE* node, /**< pointer to expression graph node */
9596  SCIP_EXPRGRAPHNODE** oldchild, /**< child node that should be replaced, it may be freed */
9597  SCIP_EXPRGRAPHNODE* newchild /**< node that should take position of oldchild */
9598  )
9599 {
9600  int childpos = -1;
9601 
9602  assert(exprgraph != NULL);
9603  assert(node != NULL);
9604  assert(oldchild != NULL);
9605  assert(*oldchild != NULL);
9606  assert(newchild != NULL);
9607 
9608  if( *oldchild == newchild )
9609  return SCIP_OKAY;
9610 
9611  SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
9612 
9613  /* let's see if child is just next to the place where we looked in a previous call to this function */
9614  if( exprgraph->lastreplacechildpos >= 0 && exprgraph->lastreplacechildpos+1 < node->nchildren && node->children[exprgraph->lastreplacechildpos+1] == *oldchild )
9615  {
9616  childpos = exprgraph->lastreplacechildpos+1;
9617  }
9618  else for( childpos = 0; childpos < node->nchildren; ++childpos )
9619  {
9620  /* search for oldchild in children array */
9621  if( node->children[childpos] == *oldchild )
9622  break;
9623  }
9624  assert(childpos >= 0);
9625  assert(childpos < node->nchildren);
9626  assert(node->children[childpos] == *oldchild);
9627 
9628  /* add as parent to newchild */
9629  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
9630 
9631  /* remove as parent from oldchild */
9632  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
9633 
9634  /* set newchild as child i */
9635  node->children[childpos] = newchild;
9636 
9637  node->simplified = FALSE;
9638 
9639  /* remember to look next to childpos first next time */
9640  exprgraph->lastreplacechildpos = childpos;
9641 
9642  return SCIP_OKAY;
9643 }
9644 
9645 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
9646  *
9647  * A node is larger than another node, if their corresponding constants are related that way.
9648  */
9649 static
9650 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
9651 {
9652  assert(elem1 != NULL);
9653  assert(elem2 != NULL);
9654  assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
9655  assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
9656  assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9657  assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9658 
9659  if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9660  return 1;
9661  else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9662  return -1;
9663  else
9664  return 0;
9665 }
9666 
9667 /** sort array of nodes that holds constants */
9668 static
9670  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
9671  )
9672 {
9673  assert(exprgraph != NULL);
9674 
9675  if( exprgraph->constssorted )
9676  return;
9677 
9678  SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
9679 
9680  exprgraph->constssorted = TRUE;
9681 }
9682 
9683 /** finds position of expression graph node corresponding to a constant in constnodes array */
9684 static
9686  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9687  SCIP_EXPRGRAPHNODE* node, /**< node to search for */
9688  int* pos /**< buffer to store position of node, if found */
9689  )
9690 {
9691  int left;
9692  int right;
9693  int middle;
9694 
9695  assert(exprgraph != NULL);
9696  assert(node != NULL);
9697  assert(node->op == SCIP_EXPR_CONST);
9698  assert(node->depth == 0);
9699  assert(node->pos >= 0);
9700  assert(pos != NULL);
9701 
9702  exprgraphSortConstNodes(exprgraph);
9703  assert(exprgraph->constssorted);
9704 
9705  /* find a node with constant node->data.dbl using binary search */
9706  left = 0;
9707  right = exprgraph->nconsts-1;
9708  *pos = -1;
9709  while( left <= right )
9710  {
9711  middle = (left+right)/2;
9712  assert(0 <= middle && middle < exprgraph->nconsts);
9713 
9714  if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9715  right = middle - 1;
9716  else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9717  left = middle + 1;
9718  else
9719  {
9720  *pos = middle;
9721  break;
9722  }
9723  }
9724  assert(left == right+1 || *pos >= 0);
9725  if( left == right+1 )
9726  return FALSE;
9727 
9728  /* search left of *pos to find node */
9729  while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl ) /*lint !e777*/
9730  --*pos;
9731  /* search right of *pos to find node */
9732  while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl ) /*lint !e777*/
9733  ++*pos;
9734 
9735  return exprgraph->constnodes[*pos] == node;
9736 }
9737 
9738 /** creates an expression graph node */
9739 static
9741  BMS_BLKMEM* blkmem, /**< block memory */
9742  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
9743  SCIP_EXPROP op, /**< operator type of expression */
9744  SCIP_EXPROPDATA opdata /**< operator data of expression */
9745  )
9746 {
9747  assert(blkmem != NULL);
9748  assert(node != NULL);
9749 
9750  SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9751  BMSclearMemory(*node);
9752 
9753  (*node)->op = op;
9754  (*node)->data = opdata;
9755 
9756  /* mark graph position as not in graph yet */
9757  (*node)->depth = -1;
9758  (*node)->pos = -1;
9759 
9760  /* arrays of length 0 are trivially sorted */
9761  (*node)->parentssorted = TRUE;
9762 
9763  /* set bounds interval to entire */
9764  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9765  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9766 
9767  /* set initial value to invalid */
9768  (*node)->value = SCIP_INVALID;
9769 
9770  /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9771  if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9772  (*node)->curv = SCIP_EXPRCURV_LINEAR;
9773  else
9774  (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9775 
9776  /* per default, a node is enabled */
9777  (*node)->enabled = TRUE;
9778 
9779  return SCIP_OKAY;
9780 }
9781 
9782 /** prints the expression corresponding to a node (not recursively) */
9783 static
9785  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9786  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9787  FILE* file, /**< file to print to, or NULL for stdout */
9788  const char** varnames, /**< variable names, or NULL for generic names */
9789  SCIP_Bool printchildrenbounds /**< whether to print bounds of children */
9790  )
9791 {
9792  int i;
9793 
9794  assert(node != NULL);
9795 
9796  switch( node->op )
9797  {
9798  case SCIP_EXPR_VARIDX:
9799  if( varnames != NULL )
9800  {
9801  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9802  }
9803  else
9804  SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9805  break;
9806 
9807  case SCIP_EXPR_CONST:
9808  SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9809  break;
9810 
9811  case SCIP_EXPR_PARAM:
9812  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9813  break;
9814 
9815  case SCIP_EXPR_PLUS:
9816  if( printchildrenbounds )
9817  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9818  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9819  if( printchildrenbounds )
9820  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9821  break;
9822 
9823  case SCIP_EXPR_MINUS:
9824  if( printchildrenbounds )
9825  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9826  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9827  if( printchildrenbounds )
9828  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9829  break;
9830 
9831  case SCIP_EXPR_MUL:
9832  if( printchildrenbounds )
9833  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9834  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9835  if( printchildrenbounds )
9836  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9837  break;
9838 
9839  case SCIP_EXPR_DIV:
9840  if( printchildrenbounds )
9841  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9842  SCIPmessageFPrintInfo(messagehdlr, file, "/");
9843  if( printchildrenbounds )
9844  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9845  break;
9846 
9847  case SCIP_EXPR_SQUARE:
9848  if( printchildrenbounds )
9849  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9850  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9851  break;
9852 
9853  case SCIP_EXPR_REALPOWER:
9854  if( printchildrenbounds )
9855  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9856  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9857  break;
9858 
9859  case SCIP_EXPR_SIGNPOWER:
9860  if( printchildrenbounds )
9861  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9862  node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9863  else
9864  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9865  break;
9866 
9867  case SCIP_EXPR_INTPOWER:
9868  SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9869  if( printchildrenbounds )
9870  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9871  SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9872  break;
9873 
9874  case SCIP_EXPR_SQRT:
9875  case SCIP_EXPR_EXP:
9876  case SCIP_EXPR_LOG:
9877  case SCIP_EXPR_SIN:
9878  case SCIP_EXPR_COS:
9879  case SCIP_EXPR_TAN:
9880  /* SCIP_EXPR_ERF = 20, */ /**< gaussian error function (1 operand) */
9881  /* SCIP_EXPR_ERFI = 21, */ /**< imaginary part of gaussian error function (1 operand) */
9882  case SCIP_EXPR_MIN:
9883  case SCIP_EXPR_MAX:
9884  case SCIP_EXPR_ABS:
9885  case SCIP_EXPR_SIGN:
9886  SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9887  if( printchildrenbounds )
9888  {
9889  SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9890  if( node->nchildren == 2 )
9891  SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9892  SCIPmessageFPrintInfo(messagehdlr, file, ")");
9893  }
9894  break;
9895 
9896  case SCIP_EXPR_SUM:
9897  if( printchildrenbounds )
9898  for( i = 0; i < node->nchildren; ++i )
9899  {
9900  if( i > 0 )
9901  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9902  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9903  }
9904  else
9905  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9906  break;
9907 
9908  case SCIP_EXPR_PRODUCT:
9909  if( printchildrenbounds )
9910  for( i = 0; i < node->nchildren; ++i )
9911  {
9912  if( i > 0 )
9913  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9914  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9915  }
9916  else
9917  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9918  break;
9919 
9920  case SCIP_EXPR_LINEAR:
9921  {
9922  SCIP_Real constant;
9923 
9924  constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9925 
9926  if( constant != 0.0 || node->nchildren == 0 )
9927  SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9928 
9929  for( i = 0; i < node->nchildren; ++i )
9930  {
9931  if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9932  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9933  else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9934  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9935  else
9936  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9937  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9938  if( printchildrenbounds )
9939  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9940  }
9941 
9942  break;
9943  }
9944 
9945  case SCIP_EXPR_QUADRATIC:
9946  {
9947  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9948 
9949  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9950  assert(quadraticdata != NULL);
9951 
9952  if( quadraticdata->constant != 0.0 )
9953  SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9954 
9955  if( quadraticdata->lincoefs != NULL )
9956  for( i = 0; i < node->nchildren; ++i )
9957  {
9958  if( quadraticdata->lincoefs[i] == 0.0 )
9959  continue;
9960  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9961  if( printchildrenbounds )
9962  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9963  }
9964 
9965  for( i = 0; i < quadraticdata->nquadelems; ++i )
9966  {
9967  if( quadraticdata->quadelems[i].coef == 1.0 )
9968  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9969  else if( quadraticdata->quadelems[i].coef == -1.0 )
9970  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9971  else
9972  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9973  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9974  if( printchildrenbounds )
9975  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9976  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9977  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9978  else
9979  {
9980  SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9981  if( printchildrenbounds )
9982  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9983  }
9984  }
9985 
9986  break;
9987  }
9988 
9989  case SCIP_EXPR_POLYNOMIAL:
9990  {
9991  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9992  SCIP_EXPRDATA_MONOMIAL* monomialdata;
9993  int j;
9994 
9995  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9996  assert(polynomialdata != NULL);
9997 
9998  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
9999  {
10000  SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
10001  }
10002 
10003  for( i = 0; i < polynomialdata->nmonomials; ++i )
10004  {
10005  monomialdata = polynomialdata->monomials[i];
10006  if( monomialdata->coef == 1.0 )
10007  SCIPmessageFPrintInfo(messagehdlr, file, "+");
10008  else if( monomialdata->coef == -1.0 )
10009  SCIPmessageFPrintInfo(messagehdlr, file, "-");
10010  else
10011  SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
10012 
10013  for( j = 0; j < monomialdata->nfactors; ++j )
10014  {
10015  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
10016  if( printchildrenbounds )
10017  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
10018  if( monomialdata->exponents[j] < 0.0 )
10019  SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
10020  else if( monomialdata->exponents[j] != 1.0 )
10021  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
10022  }
10023  }
10024 
10025  break;
10026  }
10027 
10028  case SCIP_EXPR_LAST:
10029  SCIPABORT();
10030  break;
10031 
10032  default:
10033  SCIPmessageFPrintInfo(messagehdlr, file, "%s", SCIPexpropGetName(node->op));
10034  break;
10035  } /*lint !e788*/
10036 }
10037 
10038 /** prints a node of an expression graph */
10039 static
10041  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10042  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10043  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
10044  FILE* file, /**< file to print to, or NULL for stdout */
10045  const char** varnames /**< variable names, or NULL for generic names */
10046  )
10047 {
10048  SCIP_Real color;
10049  int i;
10050 
10051  assert(exprgraph != NULL);
10052  assert(node != NULL);
10053  assert(file != NULL);
10054 
10055  color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
10056  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
10057 
10058  exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
10059 
10060  SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
10062  SCIPmessageFPrintInfo(messagehdlr, file, "!");
10064  SCIPmessageFPrintInfo(messagehdlr, file, "*");
10066  SCIPmessageFPrintInfo(messagehdlr, file, "+");
10067 
10068  SCIPmessageFPrintInfo(messagehdlr, file, "\"");
10069 
10070  if( !node->enabled )
10071  SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
10072 
10073  SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
10074 
10075  /* add edges from node to children */
10076  for( i = 0; i < node->nchildren; ++i )
10077  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d -> n%d_%d [label=\"c%d\"]\n", node->depth, node->pos, node->children[i]->depth, node->children[i]->pos, i);
10078 }
10079 
10080 /** evaluate node of expression graph w.r.t. values stored in children */
10081 static
10083  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10084  SCIP_Real* varvals /**< values for variables */
10085  )
10086 {
10087  int i;
10089  SCIP_Real* buf;
10090 
10091  assert(node != NULL);
10092 
10093  /* if many children, get large enough memory to store argument values */
10095  {
10096  SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
10097  }
10098  else
10099  {
10100  buf = staticbuf;
10101  }
10102 
10103  /* get values of children */
10104  for( i = 0; i < node->nchildren; ++i )
10105  {
10106  assert(node->children[i]->value != SCIP_INVALID); /*lint !e777*/
10107  buf[i] = node->children[i]->value; /*lint !e644*/
10108  }
10109 
10110  /* evaluate this expression */
10111  assert(exprOpTable[node->op].eval != NULL);
10112  SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
10113  assert(node->value != SCIP_INVALID); /*lint !e777*/
10114 
10115  /* free memory, if allocated before */
10116  if( staticbuf != buf )
10117  {
10118  BMSfreeMemoryArray(&buf);
10119  }
10120 
10121  return SCIP_OKAY;
10122 }
10123 
10124 /** evaluates node including subtree */
10125 static
10127  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10128  SCIP_Real* varvals /**< values for variables */
10129  )
10130 {
10131  int i;
10132 
10133  assert(node != NULL);
10134 
10135  for( i = 0; i < node->nchildren; ++i )
10136  {
10137  SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
10138  }
10139 
10140  SCIP_CALL( exprgraphNodeEval(node, varvals) );
10141 
10142  return SCIP_OKAY;
10143 }
10144 
10145 /** updates bounds of a node if a children has changed its bounds */
10146 static
10148  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10149  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10150  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
10151  SCIP_Bool parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
10152  )
10153 {
10154  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
10155  SCIP_INTERVAL* childbounds;
10156  SCIP_INTERVAL newbounds;
10157  int i;
10158 
10159  assert(node != NULL);
10160  assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
10161  assert(node->pos >= 0); /* node should be in graph */
10162  assert(node->op != SCIP_EXPR_VARIDX);
10163  assert(node->op != SCIP_EXPR_PARAM);
10164 
10165  /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
10166  * if node is disabled, then also do nothing */
10167  if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
10168  return SCIP_OKAY;
10169 
10170  /* if many children, get large enough memory to store children bounds */
10172  {
10173  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
10174  }
10175  else
10176  {
10177  childbounds = childboundsstatic;
10178  }
10179 
10180  /* assemble bounds of children */
10181  for( i = 0; i < node->nchildren; ++i )
10182  {
10183  /* child should have valid and non-empty bounds */
10185  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10186 
10187  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
10188  }
10189 
10190  /* call interval evaluation function for this operand */
10191  assert( exprOpTable[node->op].inteval != NULL );
10192  SCIPintervalSet(&newbounds, 0.0);
10193  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
10194 
10195  /* free memory, if allocated before */
10196  if( childbounds != childboundsstatic )
10197  {
10198  BMSfreeMemoryArray(&childbounds);
10199  }
10200 
10201  /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
10202 
10203  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
10204  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
10205  *
10206  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
10207  *
10208  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
10209  */
10210  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
10211  ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
10212  {
10213  for( i = 0; i < node->nparents; ++i )
10215 
10216  node->bounds = newbounds;
10217  }
10218  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
10219  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
10220  {
10221  for( i = 0; i < node->nparents; ++i )
10223 
10224  node->bounds = newbounds;
10225  }
10226  else
10227  {
10228  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
10229  }
10230 
10231  SCIPdebugMessage("updated bounds of node %p (%d,%d) op %s to [%g,%g]\n", (void*)node, node->depth, node->pos, SCIPexpropGetName(node->op), node->bounds.inf, node->bounds.sup);
10232 
10233  /* node now has valid bounds */
10234  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
10235 
10236  return SCIP_OKAY;
10237 }
10238 
10239 /** propagate bounds of a node into children by reverting the nodes expression */
10240 static
10242  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10243  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
10244  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10245  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
10246  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
10247  )
10248 {
10249  SCIP_INTERVAL childbounds;
10250  int i;
10251 
10252  assert(exprgraph != NULL);
10253  assert(node != NULL);
10254  assert(node->depth >= 0); /* node should be in graph */
10255  assert(node->pos >= 0); /* node should be in graph */
10256  assert(minstrength >= 0.0);
10257  assert(cutoff != NULL);
10258  assert(!SCIPintervalIsEmpty(infinity, node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
10259  assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
10260 
10261  /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
10263  return;
10264 
10265  /* if node is not enabled, then do nothing */
10266  if( !node->enabled )
10267  return;
10268 
10269  /* tell children that they should propagate their bounds even if not tightened */
10271  minstrength = -1.0;
10272 
10273  /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
10275 
10276  /* SCIPdebugMessage("propagating node %p (%d,%d) op %s: [%10g,%10g] = ", (void*)node, node->depth, node->pos, SCIPexpropGetName(node->op), node->bounds.inf, node->bounds.sup);
10277  * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10278  * SCIPdebugPrintf("\n");
10279  */
10280 
10281  /* @todo add callback to exprOpTable for this */
10282 
10283  switch( node->op )
10284  {
10285  case SCIP_EXPR_VARIDX:
10286  case SCIP_EXPR_CONST:
10287  case SCIP_EXPR_PARAM:
10288  /* cannot propagate bound changes further */
10289  break;
10290 
10291  case SCIP_EXPR_PLUS:
10292  {
10293  assert(node->nchildren == 2);
10294  /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
10295 
10296  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10297  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10298 
10299  if( *cutoff )
10300  break;
10301 
10302  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10303  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10304 
10305  break;
10306  }
10307 
10308  case SCIP_EXPR_MINUS:
10309  {
10310  assert(node->nchildren == 2);
10311  /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
10312 
10313  SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10314  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10315 
10316  if( *cutoff )
10317  break;
10318 
10319  SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10320  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10321 
10322  break;
10323  }
10324 
10325  case SCIP_EXPR_MUL:
10326  {
10327  assert(node->nchildren == 2);
10328  /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
10329 
10330  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10331  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10332 
10333  if( *cutoff )
10334  break;
10335 
10336  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10337  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10338 
10339  break;
10340  }
10341 
10342  case SCIP_EXPR_DIV:
10343  {
10344  assert(node->nchildren == 2);
10345  /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
10346 
10347  SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10348  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10349 
10350  if( *cutoff )
10351  break;
10352 
10353  SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10354  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10355 
10356  break;
10357  }
10358 
10359  case SCIP_EXPR_SQUARE:
10360  {
10361  assert(node->nchildren == 1);
10362  /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
10363 
10364  if( node->bounds.sup < 0.0 )
10365  {
10366  *cutoff = TRUE;
10367  break;
10368  }
10369 
10370  SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
10371  if( node->children[0]->bounds.inf <= -childbounds.inf )
10372  SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
10373  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10374 
10375  break;
10376  }
10377 
10378  case SCIP_EXPR_SQRT:
10379  {
10380  assert(node->nchildren == 1);
10381  /* f = sqrt(c0) -> c0 = f^2 */
10382 
10383  SCIPintervalSquare(infinity, &childbounds, node->bounds);
10384  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10385 
10386  break;
10387  }
10388 
10389  case SCIP_EXPR_REALPOWER:
10390  {
10391  assert(node->nchildren == 1);
10392 
10393  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
10394 
10395  if( SCIPintervalIsEmpty(infinity, childbounds) )
10396  {
10397  *cutoff = TRUE;
10398  break;
10399  }
10400  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10401 
10402  break;
10403  }
10404 
10405  case SCIP_EXPR_SIGNPOWER:
10406  {
10407  assert(node->nchildren == 1);
10408 
10409  if( node->data.dbl != 0.0 )
10410  {
10411  SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
10412  }
10413  else
10414  {
10415  /* behaves like SCIP_EXPR_SIGN */
10416  SCIPintervalSetBounds(&childbounds,
10417  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10418  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10419  }
10420 
10421  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10422 
10423  break;
10424  }
10425 
10426  case SCIP_EXPR_INTPOWER:
10427  {
10428  assert(node->nchildren == 1);
10429 
10430  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
10431 
10432  if( SCIPintervalIsEmpty(infinity, childbounds) )
10433  {
10434  *cutoff = TRUE;
10435  break;
10436  }
10437  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10438 
10439  break;
10440  }
10441 
10442  case SCIP_EXPR_EXP:
10443  {
10444  assert(node->nchildren == 1);
10445  /* f = exp(c0) -> c0 = log(f) */
10446 
10447  if( node->bounds.sup < 0.0 )
10448  {
10449  *cutoff = TRUE;
10450  break;
10451  }
10452 
10453  SCIPintervalLog(infinity, &childbounds, node->bounds);
10454  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10455 
10456  break;
10457  }
10458 
10459  case SCIP_EXPR_LOG:
10460  {
10461  assert(node->nchildren == 1);
10462  /* f = log(c0) -> c0 = exp(f) */
10463 
10464  SCIPintervalExp(infinity, &childbounds, node->bounds);
10465  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10466 
10467  break;
10468  }
10469 
10470  case SCIP_EXPR_SIN:
10471  case SCIP_EXPR_COS:
10472  case SCIP_EXPR_TAN:
10473  /* case SCIP_EXPR_ERF: */
10474  /* case SCIP_EXPR_ERFI: */
10475  {
10476  assert(node->nchildren == 1);
10477 
10478  /* @todo implement */
10479 
10480  break;
10481  }
10482 
10483  case SCIP_EXPR_ABS:
10484  {
10485  assert(node->nchildren == 1);
10486 
10487  /* use identity if child bounds are non-negative */
10488  if( node->children[0]->bounds.inf >= 0 )
10489  {
10490  SCIPintervalSetBounds(&childbounds, node->bounds.inf, node->bounds.sup);
10491  }
10492  /* use -identity if child bounds are non-positive */
10493  else if( node->children[0]->bounds.sup <= 0 )
10494  {
10495  assert(node->bounds.inf <= node->bounds.sup);
10496  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, -node->bounds.inf);
10497  }
10498  /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
10499  else
10500  {
10501  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
10502  }
10503 
10504  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10505 
10506  break;
10507  }
10508 
10509  case SCIP_EXPR_SIGN:
10510  {
10511  assert(node->nchildren == 1);
10512  /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
10513 
10514  SCIPintervalSetBounds(&childbounds,
10515  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10516  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10517  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10518 
10519  break;
10520  }
10521 
10522  case SCIP_EXPR_MIN:
10523  {
10524  assert(node->nchildren == 2);
10525  /* f = min(c0,c1) -> f <= c0, f <= c1
10526  * if c1 > f -> c0 = f
10527  * if c0 > f -> c1 = f
10528  */
10529 
10530  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10531  node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10532  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10533 
10534  if( *cutoff )
10535  break;
10536 
10537  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10538  node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10539  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10540 
10541  break;
10542  }
10543 
10544  case SCIP_EXPR_MAX:
10545  {
10546  assert(node->nchildren == 2);
10547  /* f = max(c0, c1) -> f >= c0, f >= c1
10548  * if c1 < f -> c0 = f
10549  * if c0 < f -> c1 = f
10550  */
10551 
10552  SCIPintervalSetBounds(&childbounds,
10553  node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10554  node->bounds.sup);
10555  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10556 
10557  SCIPintervalSetBounds(&childbounds,
10558  node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10559  node->bounds.sup);
10560  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10561 
10562  break;
10563  }
10564 
10565  case SCIP_EXPR_SUM:
10566  {
10567  SCIP_ROUNDMODE prevroundmode;
10568 
10569  /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
10570 
10571  SCIP_Real minlinactivity;
10572  SCIP_Real maxlinactivity;
10573  int minlinactivityinf;
10574  int maxlinactivityinf;
10575 
10576  if( node->nchildren == 0 )
10577  break;
10578 
10579  if( SCIPintervalIsEntire(infinity, node->bounds) )
10580  break;
10581 
10582  minlinactivity = 0.0;
10583  maxlinactivity = 0.0;
10584  minlinactivityinf = 0;
10585  maxlinactivityinf = 0;
10586 
10587  prevroundmode = SCIPintervalGetRoundingMode();
10589 
10590  for( i = 0; i < node->nchildren; ++i )
10591  {
10592  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10593 
10594  /* minimal activity is only useful if node has a finite upper bound */
10595  if( node->bounds.sup < infinity )
10596  {
10597  if( node->children[i]->bounds.inf <= -infinity )
10598  {
10599  ++minlinactivityinf;
10600  }
10601  else
10602  {
10603  assert(node->children[i]->bounds.inf < infinity);
10604  minlinactivity += node->children[i]->bounds.inf;
10605  }
10606  }
10607 
10608  /* maximal activity is only useful if node has a finite lower bound
10609  * we compute negated maximal activity here so we can keep downward rounding
10610  */
10611  if( node->bounds.inf > -infinity )
10612  {
10613  if( node->children[i]->bounds.sup >= infinity )
10614  {
10615  ++maxlinactivityinf;
10616  }
10617  else
10618  {
10619  assert(node->children[i]->bounds.sup > -infinity);
10620  maxlinactivity -= node->children[i]->bounds.sup;
10621  }
10622  }
10623  }
10624  maxlinactivity = -maxlinactivity; /* correct sign */
10625 
10626  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10627  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10628  ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10629  )
10630  {
10631  SCIPintervalSetRoundingMode(prevroundmode);
10632  break;
10633  }
10634 
10635  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10636  {
10637  /* upper bounds of c_i is
10638  * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
10639  * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
10640  */
10641  SCIPintervalSetEntire(infinity, &childbounds);
10642  if( node->bounds.sup < infinity )
10643  {
10644  /* we are still in downward rounding mode, so negate and negate to get upward rounding */
10645  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10646  {
10647  assert(minlinactivityinf == 1);
10648  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
10649  }
10650  else if( minlinactivityinf == 0 )
10651  {
10652  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
10653  }
10654  }
10655 
10656  /* lower bounds of c_i is
10657  * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
10658  * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
10659  */
10660  if( node->bounds.inf > -infinity )
10661  {
10662  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10663  {
10664  assert(maxlinactivityinf == 1);
10665  childbounds.inf = node->bounds.inf - maxlinactivity;
10666  }
10667  else if( maxlinactivityinf == 0 )
10668  {
10669  childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
10670  }
10671  }
10672 
10673  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10674  }
10675 
10676  SCIPintervalSetRoundingMode(prevroundmode);
10677 
10678  break;
10679  }
10680 
10681  case SCIP_EXPR_PRODUCT:
10682  {
10683  int j;
10684  /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
10685 
10686  /* too expensive (runtime here is quadratic in number of children) */
10687  if( node->nchildren > 10 )
10688  break;
10689 
10690  /* useless */
10691  if( SCIPintervalIsEntire(infinity, node->bounds) )
10692  break;
10693 
10694  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10695  {
10696  /* compute prod_{j:j!=i} c_j */
10697  SCIPintervalSet(&childbounds, 1.0);
10698  for( j = 0; j < node->nchildren; ++j )
10699  {
10700  if( i == j )
10701  continue;
10702  SCIPintervalMul(infinity, &childbounds, childbounds, node->children[j]->bounds);
10703 
10704  /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
10705  if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
10706  break;
10707  }
10708 
10709  if( j == node->nchildren )
10710  {
10711  SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
10712  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10713  }
10714  }
10715 
10716  break;
10717  }
10718 
10719  case SCIP_EXPR_LINEAR:
10720  {
10721  SCIP_ROUNDMODE prevroundmode;
10722  SCIP_Real* coefs;
10723 
10724  /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10725 
10726  SCIP_Real minlinactivity;
10727  SCIP_Real maxlinactivity;
10728  int minlinactivityinf;
10729  int maxlinactivityinf;
10730 
10731  if( node->nchildren == 0 )
10732  break;
10733 
10734  if( SCIPintervalIsEntire(infinity, node->bounds) )
10735  break;
10736 
10737  coefs = (SCIP_Real*)node->data.data;
10738 
10739  minlinactivity = coefs[node->nchildren];
10740  maxlinactivity = -coefs[node->nchildren];
10741  minlinactivityinf = 0;
10742  maxlinactivityinf = 0;
10743 
10744  prevroundmode = SCIPintervalGetRoundingMode();
10746 
10747  for( i = 0; i < node->nchildren; ++i )
10748  {
10749  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10750 
10751  /* minimal activity is only useful if node has a finite upper bound */
10752  if( node->bounds.sup < infinity )
10753  {
10754  if( coefs[i] >= 0.0 )
10755  {
10756  if( node->children[i]->bounds.inf <= -infinity )
10757  {
10758  ++minlinactivityinf;
10759  }
10760  else
10761  {
10762  assert(node->children[i]->bounds.inf < infinity);
10763  minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10764  }
10765  }
10766  else
10767  {
10768  if( node->children[i]->bounds.sup >= infinity )
10769  {
10770  ++minlinactivityinf;
10771  }
10772  else
10773  {
10774  assert(node->children[i]->bounds.sup > -infinity);
10775  minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10776  }
10777  }
10778  }
10779 
10780  /* maximal activity is only useful if node has a finite lower bound
10781  * we compute negated maximal activity here so we can keep downward rounding
10782  */
10783  if( node->bounds.inf > -infinity )
10784  {
10785  if( coefs[i] >= 0.0 )
10786  {
10787  if( node->children[i]->bounds.sup >= infinity )
10788  {
10789  ++maxlinactivityinf;
10790  }
10791  else
10792  {
10793  assert(node->children[i]->bounds.sup > -infinity);
10794  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.sup;
10795  }
10796  }
10797  else
10798  {
10799  if( node->children[i]->bounds.inf <= -infinity )
10800  {
10801  ++maxlinactivityinf;
10802  }
10803  else
10804  {
10805  assert(node->children[i]->bounds.inf < infinity);
10806  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.inf;
10807  }
10808  }
10809  }
10810  }
10811  maxlinactivity = SCIPintervalNegateReal(maxlinactivity); /* correct sign */
10812 
10813  /* SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]; bounds = [%10g,%10g]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf, node->bounds.inf, node->bounds.sup); */
10814 
10815  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10816  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10817  (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10818  )
10819  {
10820  SCIPintervalSetRoundingMode(prevroundmode);
10821  break;
10822  }
10823 
10824  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10825  {
10826  SCIP_INTERVAL ac;
10827 
10828  if( coefs[i] == 0.0 )
10829  continue;
10830 
10831  /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10832  SCIPintervalSet(&ac, 0.0);
10833  if( coefs[i] >= 0.0 )
10834  {
10835  if( node->children[i]->bounds.inf > -infinity )
10836  ac.inf = coefs[i] * node->children[i]->bounds.inf;
10837  if( node->children[i]->bounds.sup < infinity )
10839  }
10840  else
10841  {
10842  if( node->children[i]->bounds.sup < infinity )
10843  ac.inf = coefs[i] * node->children[i]->bounds.sup;
10844  if( node->children[i]->bounds.inf > -infinity )
10845  ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10846  }
10847 
10848  SCIPintervalSetEntire(infinity, &childbounds);
10849  if( coefs[i] > 0.0 )
10850  {
10851  /* upper bounds of c_i is
10852  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10853  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10854  */
10855  if( node->bounds.sup < infinity )
10856  {
10857  /* we are still in downward rounding mode, so negate to get upward rounding */
10858  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10859  {
10860  assert(minlinactivityinf == 1);
10861  childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10862  }
10863  else if( minlinactivityinf == 0 )
10864  {
10865  childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10866  }
10867  }
10868 
10869  /* lower bounds of c_i is
10870  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10871  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10872  */
10873  if( node->bounds.inf > -infinity )
10874  {
10875  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10876  {
10877  assert(maxlinactivityinf == 1);
10878  childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10879  }
10880  else if( maxlinactivityinf == 0 )
10881  {
10882  childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10883  }
10884  }
10885  }
10886  else
10887  {
10888  /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10889  * thus, we do (b-a)/(-c) in downward rounding
10890  */
10891  /* lower bounds of c_i is
10892  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10893  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10894  */
10895  if( node->bounds.sup < infinity )
10896  {
10897  if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10898  {
10899  assert(minlinactivityinf == 1);
10900  childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10901  }
10902  else if( minlinactivityinf == 0 )
10903  {
10904  childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10905  }
10906  }
10907 
10908  /* upper bounds of c_i is
10909  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10910  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10911  */
10912  if( node->bounds.inf > -infinity )
10913  {
10914  /* we are still in downward rounding mode, so negate to get upward rounding */
10915  if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10916  {
10917  assert(maxlinactivityinf == 1);
10918  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10919  }
10920  else if( maxlinactivityinf == 0 )
10921  {
10922  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10923  }
10924  }
10925  }
10926 
10927  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10928  }
10929 
10930  SCIPintervalSetRoundingMode(prevroundmode);
10931 
10932  break;
10933  }
10934 
10935  case SCIP_EXPR_QUADRATIC:
10936  {
10937  SCIP_EXPRDATA_QUADRATIC* quaddata;
10938  SCIP_INTERVAL tmp;
10939  SCIP_INTERVAL a;
10940  SCIP_INTERVAL b;
10941  SCIP_INTERVAL c;
10942  SCIP_QUADELEM* quadelems;
10943  int nquadelems;
10944  SCIP_Real* lincoefs;
10945  int k;
10946 
10947  /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10948  * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10949  */
10950 
10951  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10952  quadelems = quaddata->quadelems;
10953  nquadelems = quaddata->nquadelems;
10954  lincoefs = quaddata->lincoefs;
10955 
10956  /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10957  if( nquadelems > 10 )
10958  break;
10959 
10960  if( SCIPintervalIsEntire(infinity, node->bounds) )
10961  break;
10962 
10963  if( node->nchildren == 2 && nquadelems > 0 )
10964  {
10965  /* if it's a bivariate quadratic expression with bilinear term, do something special */
10966  SCIP_Real ax; /* square coefficient of first child */
10967  SCIP_Real ay; /* square coefficient of second child */
10968  SCIP_Real axy; /* bilinear coefficient */
10969 
10970  ax = 0.0;
10971  ay = 0.0;
10972  axy = 0.0;
10973  for( i = 0; i < nquadelems; ++i )
10974  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10975  ax += quadelems[i].coef;
10976  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10977  ay += quadelems[i].coef;
10978  else
10979  axy += quadelems[i].coef;
10980 
10981  c = node->bounds;
10982  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10983 
10984  /* compute bounds for x */
10986  infinity, &childbounds, ax, ay, axy,
10987  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10988  c, node->children[0]->bounds, node->children[1]->bounds
10989  );
10990  if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10991  {
10992  SCIPdebugMessage("%g x^2 + %g y^2 + %g xy + %g x + %g y in [%g,%g], x = [%g,%g], y = [%g,%g] -> x in [%g,%g], cutoff = %d\n",
10993  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10994  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10995  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10996  );
10997  }
10998 
10999  if( SCIPintervalIsEmpty(infinity, childbounds) )
11000  *cutoff = TRUE;
11001  else
11002  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11003  if( *cutoff )
11004  break;
11005 
11006  /* compute bounds for y */
11008  infinity, &childbounds, ay, ax, axy,
11009  lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
11010  c, node->children[1]->bounds, node->children[0]->bounds
11011  );
11012 
11013  if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
11014  {
11015  SCIPdebugMessage("%g x^2 + %g y^2 + %g xy + %g x + %g y in [%g,%g], x = [%g,%g], y = [%g,%g] -> y in [%g,%g], cutoff = %d\n",
11016  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
11017  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
11018  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
11019  );
11020  }
11021 
11022  if( SCIPintervalIsEmpty(infinity, childbounds) )
11023  *cutoff = TRUE;
11024  else
11025  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
11026  if( *cutoff )
11027  break;
11028 
11029  break;
11030  }
11031 
11032  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11033  {
11034  SCIPintervalSet(&a, 0.0);
11035  SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
11036  c = node->bounds;
11037  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
11038 
11039  /* move linear terms not corresponding to i into c
11040  * @todo do this faster, see EXPR_LINEAR
11041  */
11042  if( lincoefs != NULL )
11043  for( k = 0; k < node->nchildren; ++k )
11044  if( i != k && lincoefs[k] != 0.0 )
11045  {
11046  SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
11047  SCIPintervalSub(infinity, &c, c, tmp);
11048  }
11049 
11050  for( k = 0; k < nquadelems; ++k )
11051  {
11052  if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
11053  {
11054  SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
11055  }
11056  else if( quadelems[k].idx1 == i )
11057  {
11058  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
11059  SCIPintervalAdd(infinity, &b, b, tmp);
11060  }
11061  else if( quadelems[k].idx2 == i )
11062  {
11063  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
11064  SCIPintervalAdd(infinity, &b, b, tmp);
11065  }
11066  else if( quadelems[k].idx1 == quadelems[k].idx2 )
11067  {
11068  SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
11069  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11070  SCIPintervalSub(infinity, &c, c, tmp);
11071  }
11072  else
11073  {
11074  SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
11075  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
11076  SCIPintervalSub(infinity, &c, c, tmp);
11077  }
11078  }
11079 
11080  SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
11081  a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
11082  SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c, node->children[i]->bounds);
11083  if( SCIPintervalIsEmpty(infinity, childbounds) )
11084  *cutoff = TRUE;
11085  else
11086  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11087  }
11088 
11089  break;
11090  }
11091 
11092  case SCIP_EXPR_POLYNOMIAL:
11093  {
11094  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11095  SCIP_EXPRDATA_MONOMIAL** monomials;
11096  SCIP_EXPRDATA_MONOMIAL* monomial;
11097  int nmonomials;
11098  int j;
11099  int k;
11100  SCIP_Real n;
11101  int nexpisdoublen;
11102  int nexpishalfn;
11103  char abc_flag;
11104 
11105  SCIP_INTERVAL monomialcoef;
11106  SCIP_INTERVAL tmp;
11107  SCIP_INTERVAL a;
11108  SCIP_INTERVAL b;
11109  SCIP_INTERVAL c;
11110  SCIP_INTERVAL childpowbounds;
11111 
11112  /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
11113  * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
11114  *
11115  * we determine n by setting n to the first exponent of x that we see
11116  * then we count how often we see x^(2n) and x^(n/2)
11117  * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
11118  */
11119 
11120  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11121  monomials = polynomialdata->monomials;
11122  nmonomials = polynomialdata->nmonomials;
11123 
11124  if( SCIPintervalIsEntire(infinity, node->bounds) )
11125  break;
11126 
11127  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11128  {
11129  n = 0.0;
11130  nexpisdoublen = 0;
11131  nexpishalfn = 0;
11132  for( j = 0; j < nmonomials; ++j )
11133  {
11134  monomial = monomials[j];
11135  for( k = 0; k < monomial->nfactors; ++k )
11136  {
11137  if( monomial->childidxs[k] == i )
11138  {
11139  if( n == 0.0 )
11140  n = monomial->exponents[k];
11141  else if( n == 2*monomial->exponents[k] ) /*lint !e777*/
11142  ++nexpishalfn;
11143  else if( 2*n == monomial->exponents[k] ) /*lint !e777*/
11144  ++nexpisdoublen;
11145  }
11146  }
11147  }
11148 
11149  if( n == 0.0 )
11150  {
11151  /* child does not appear in polynomial -> cannot deduce bound */
11152  continue;
11153  }
11154 
11155  /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
11156  if( nexpishalfn > nexpisdoublen )
11157  n /= 2.0;
11158 
11159  SCIPintervalSet(&a, 0.0);
11160  SCIPintervalSet(&b, 0.0);
11161  SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
11162 
11163  for( j = 0; j < nmonomials; ++j )
11164  {
11165  monomial = monomials[j];
11166  SCIPintervalSet(&monomialcoef, monomial->coef);
11167  abc_flag = 'c';
11168  for( k = 0; k < monomial->nfactors; ++k )
11169  {
11170  if( monomial->childidxs[k] == i )
11171  {
11172  assert(abc_flag == 'c'); /* child should appear only once per monom */
11173  if( n > 0.0 )
11174  {
11175  if( monomial->exponents[k] > 2.0*n )
11176  {
11177  abc_flag = 'a';
11178  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11179  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11180  }
11181  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11182  {
11183  abc_flag = 'a';
11184  }
11185  else if( monomial->exponents[k] > n )
11186  {
11187  abc_flag = 'b';
11188  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11189  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11190  }
11191  else if( monomial->exponents[k] == n ) /*lint !e777*/
11192  {
11193  abc_flag = 'b';
11194  }
11195  else
11196  {
11197  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11198  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11199  }
11200  }
11201  else
11202  {
11203  assert(n < 0.0);
11204  if( monomial->exponents[k] < 2.0*n )
11205  {
11206  abc_flag = 'a';
11207  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11208  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11209  }
11210  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11211  {
11212  abc_flag = 'a';
11213  }
11214  else if( monomial->exponents[k] < n )
11215  {
11216  abc_flag = 'b';
11217  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11218  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11219  }
11220  else if( monomial->exponents[k] == n ) /*lint !e777*/
11221  {
11222  abc_flag = 'b';
11223  }
11224  else
11225  {
11226  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11227  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11228  }
11229  }
11230  }
11231  else
11232  {
11233  SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
11234  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11235  }
11236  }
11237 
11238  if( abc_flag == 'a' )
11239  {
11240  SCIPintervalAdd(infinity, &a, a, monomialcoef);
11241  /* if monomialcoef is such that a exceeds value for infinity, then stop */
11242  if( a.inf >= infinity || a.sup <= -infinity )
11243  break;
11244  }
11245  else if( abc_flag == 'b' )
11246  {
11247  SCIPintervalAdd(infinity, &b, b, monomialcoef);
11248  /* if monomialcoef is such that b exceeds value for infinity, then stop */
11249  if( b.inf >= infinity || b.sup <= -infinity )
11250  break;
11251  }
11252  else
11253  {
11254  SCIPintervalSub(infinity, &c, c, monomialcoef);
11255  /* if monomialcoef is such that c exceeds value for infinity, then stop */
11256  if( c.inf >= infinity || c.sup <= -infinity )
11257  break;
11258  }
11259  }
11260 
11261  /* if we run out of numbers (within -infinity,infinity) above, then stop */
11262  if( j < nmonomials )
11263  continue;
11264 
11265  /* now have equation a*child^(2n) + b*child^n = c
11266  * solve a*y^2 + b*y = c (for y in childbounds^n), then child^n = y
11267  */
11268  SCIPintervalPowerScalar(infinity, &childpowbounds, node->children[i]->bounds, n);
11269  SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g] for c%d^%g in [%10g,%10g]",
11270  a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup, i, n, childpowbounds.inf, childpowbounds.sup);
11271  SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c, childpowbounds);
11272  SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
11273 
11274  if( SCIPintervalIsEmpty(infinity, tmp) )
11275  {
11276  *cutoff = TRUE;
11277  break;
11278  }
11279 
11280  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
11281  SCIPdebugPrintf(" with c%d = [%10g, %10g] -> c%d = [%10g, %10g]\n", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup, i, childbounds.inf, childbounds.sup);
11282  if( SCIPintervalIsEmpty(infinity, childbounds) )
11283  {
11284  SCIPdebugMessage(" -> cutoff\n");
11285  *cutoff = TRUE;
11286  break;
11287  }
11288 
11289  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11290 
11291  /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
11292  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11293  SCIPdebugPrintf("\n"); */
11294  }
11295 
11296  break;
11297  }
11298 
11299  case SCIP_EXPR_USER:
11300  {
11301  SCIP_INTERVAL* childrenbounds;
11302  SCIP_EXPRDATA_USER* exprdata;
11303  int c;
11304 
11305  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11306 
11307  /* do nothing if callback not implemented */
11308  if( exprdata->prop == NULL )
11309  break;
11310 
11311  /* if only one child, do faster */
11312  if( node->nchildren == 1 )
11313  {
11314  childbounds = node->children[0]->bounds;
11315  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, 1, &childbounds, node->bounds, cutoff) );
11316 
11317  if( !*cutoff )
11318  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11319 
11320  break;
11321  }
11322 
11323  SCIP_ALLOC_ABORT( BMSallocBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren) );
11324  for( c = 0; c < node->nchildren; ++c )
11325  childrenbounds[c] = node->children[c]->bounds;
11326 
11327  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, node->nchildren, childrenbounds, node->bounds, cutoff) );
11328 
11329  for( c = 0; !*cutoff && c < node->nchildren; ++c )
11330  {
11331  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[c], childrenbounds[c], minstrength, infinity, cutoff);
11332  }
11333 
11334  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren);
11335 
11336  break;
11337  }
11338 
11339  case SCIP_EXPR_LAST:
11340  SCIPABORT();
11341  break;
11342  }
11343 }
11344 
11345 /** removes duplicate children in a polynomial expression node
11346  *
11347  * Leaves NULL's in children array.
11348  */
11349 static
11351  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11352  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11353  )
11354 {
11355  SCIP_Bool foundduplicates;
11356  int* childmap;
11357  int i;
11358  int j;
11359 
11360  assert(exprgraph != NULL);
11361  assert(node != NULL);
11362  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11363 
11364  if( node->nchildren == 0 )
11365  return SCIP_OKAY;
11366 
11367  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
11368 
11369  foundduplicates = FALSE;
11370  for( i = 0; i < node->nchildren; ++i )
11371  {
11372  if( node->children[i] == NULL )
11373  continue;
11374  childmap[i] = i; /*lint !e644*/
11375 
11376  for( j = i+1; j < node->nchildren; ++j )
11377  {
11378  if( node->children[j] == NULL )
11379  continue;
11380 
11381  if( node->children[i] == node->children[j] )
11382  {
11383  /* node should be parent of children[j] at least twice,
11384  * so we remove it once
11385  */
11386  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
11387  node->children[j] = NULL;
11388  assert(exprgraphNodeIsParent(node->children[i], node));
11389 
11390  childmap[j] = i;
11391  foundduplicates = TRUE;
11392  }
11393  }
11394  }
11395 
11396  /* apply childmap to monomials */
11397  if( foundduplicates )
11399 
11400  /* free childmap */
11401  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
11402 
11403  return SCIP_OKAY;
11404 }
11405 
11406 /** eliminates NULL's in children array and shrinks it to actual size */
11407 static
11409  BMS_BLKMEM* blkmem, /**< block memory */
11410  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11411  )
11412 {
11413  int* childmap;
11414  int lastnonnull;
11415  int i;
11416 
11417  assert(blkmem != NULL);
11418  assert(node != NULL);
11419  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11420 
11421  if( node->nchildren == 0 )
11422  return SCIP_OKAY;
11423 
11424  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
11425 
11426  /* close gaps in children array */
11427  lastnonnull = node->nchildren-1;
11428  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11429  --lastnonnull;
11430  for( i = 0; i <= lastnonnull; ++i )
11431  {
11432  if( node->children[i] != NULL )
11433  {
11434  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
11435  continue;
11436  }
11437  assert(node->children[lastnonnull] != NULL);
11438 
11439  /* move child at lastnonnull to position i */
11440  node->children[i] = node->children[lastnonnull];
11441  node->children[lastnonnull] = NULL;
11442  childmap[lastnonnull] = i;
11443 
11444  /* update lastnonnull */
11445  --lastnonnull;
11446  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11447  --lastnonnull;
11448  }
11449  assert(i > lastnonnull);
11450 
11451  /* apply childmap to monomials */
11452  if( lastnonnull < node->nchildren-1 )
11454 
11455  BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
11456 
11457  /* shrink children array */
11458  if( lastnonnull >= 0 )
11459  {
11460  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
11461  node->nchildren = lastnonnull+1;
11462  }
11463  else
11464  {
11465  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11466  node->nchildren = 0;
11467  }
11468 
11469  return SCIP_OKAY;
11470 }
11471 
11472 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
11473  *
11474  * Converts node into polynomial, if possible and not constant.
11475  */
11476 static
11478  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11479  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
11480  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
11481  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
11482  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
11483  SCIP_Bool* havechange /**< flag to set if the node has been changed */
11484  )
11485 {
11486  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11487  SCIP_EXPRDATA_MONOMIAL* monomial;
11488  BMS_BLKMEM* blkmem;
11489  SCIP_Bool removechild;
11490  SCIP_Bool* childinuse;
11491  int* childmap;
11492  int childmapsize;
11493  int i;
11494  int j;
11495  int orignchildren;
11496 
11497  assert(exprgraph != NULL);
11498  assert(node != NULL);
11499  assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
11500  assert(havechange != NULL);
11501 
11502  blkmem = exprgraph->blkmem;
11503  assert(blkmem != NULL);
11504 
11505  SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
11506 
11507  /* if all children are constants, then turn this node into constant */
11508  for( i = 0; i < node->nchildren; ++i )
11509  if( node->children[i]->op != SCIP_EXPR_CONST )
11510  break;
11511  if( node->nchildren > 0 && i == node->nchildren )
11512  {
11513  /* get value of node */
11515  assert(node->value != SCIP_INVALID); /*lint !e777*/
11516 
11517  SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
11518  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11519  SCIPdebugPrintf("\n");
11520 
11521  /* free expression data */
11522  if( exprOpTable[node->op].freedata != NULL )
11523  exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
11524 
11525  /* disconnect from children */
11526  for( i = 0; i < node->nchildren; ++i )
11527  {
11528  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11529  }
11530  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11531  node->nchildren = 0;
11532 
11533  /* turn into constant expression */
11534  node->op = SCIP_EXPR_CONST;
11535  node->data.dbl = node->value;
11536 
11537  *havechange = TRUE;
11538  node->simplified = TRUE;
11539 
11540  return SCIP_OKAY;
11541  }
11542 
11543  /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
11544  * @todo log(product) -> sum(log)
11545  * @todo product(exp) -> exp(sum)
11546  * @todo exp(x)^p -> exp(p*x)
11547  * @todo exp(const*log(x)) -> x^const
11548  */
11549 
11550  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
11551 
11552  if( node->op != SCIP_EXPR_POLYNOMIAL )
11553  {
11554  node->simplified = TRUE;
11555  return SCIP_OKAY;
11556  }
11557 
11558  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11559  assert(polynomialdata != NULL);
11560 
11561  orignchildren = node->nchildren;
11562 
11563  /* check if we have duplicate children and merge */
11565  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11566 
11567  SCIPdebugMessage("expand factors in expression node ");
11568  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11569  SCIPdebugPrintf("\n");
11570 
11571  childmap = NULL;
11572  childmapsize = 0;
11573 
11574  /* resolve children that are constants
11575  * we do this first, because it reduces the degree and number of factors in the monomials,
11576  * thereby allowing some expansions of polynomials that may not be possible otherwise, e.g., turning c0*c1 with c0=quadratic and c1=constant into a single monomial
11577  */
11578  for( i = 0; i < node->nchildren; ++i )
11579  {
11580  if( node->children[i] == NULL )
11581  continue;
11582 
11583  /* convert children to polynomial, if not constant or polynomial
11584  * if child was simplified in this round, it may have already been converted, and then nothing happens
11585  * but if child was already simplified, then it was not converted, and thus we try it here
11586  */
11587  if( node->children[i]->op != SCIP_EXPR_CONST )
11588  continue;
11589 
11590  SCIPdebugMessage("expand child %d in expression node ", i);
11591  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11592  SCIPdebugPrintf("\n\tchild = ");
11593  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11594  SCIPdebugPrintf("\n");
11595 
11596  removechild = TRUE; /* we intend to release children[i] */
11597 
11598  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11599 
11600  /* put constant of child i into every monomial where child i is used */
11601  for( j = 0; j < polynomialdata->nmonomials; ++j )
11602  {
11603  int factorpos;
11604 
11605  monomial = polynomialdata->monomials[j];
11606  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11607  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11608 
11609  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11610  {
11611  assert(factorpos >= 0);
11612  assert(factorpos < monomial->nfactors);
11613  /* assert that factors have been merged */
11614  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11615  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11616 
11617  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11618 
11619  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 ) /*lint !e835*/
11620  {
11621  /* if constant is negative and our exponent is not integer, then cannot do expansion */
11622  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
11623  removechild = FALSE;
11624  }
11625  else
11626  {
11627  monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
11628 
11629  /* move last factor to position factorpos */
11630  if( factorpos < monomial->nfactors-1 )
11631  {
11632  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
11633  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
11634  }
11635  --monomial->nfactors;
11636  monomial->sorted = FALSE;
11637  polynomialdata->sorted = FALSE;
11638 
11639  *havechange = TRUE;
11640  }
11641  }
11642  }
11643 
11644  /* forget about child i, if it is not used anymore */
11645  if( removechild )
11646  {
11647  /* remove node from list of parents of child i */
11648  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11649  node->children[i] = NULL;
11650  }
11651 
11652  /* simplify current polynomial again */
11653  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11654  }
11655 
11656  /* resolve children that are polynomials itself */
11657  for( i = 0; i < node->nchildren; ++i )
11658  {
11659  if( node->children[i] == NULL )
11660  continue;
11661 
11662  /* convert children to polynomial, if not constant or polynomial
11663  * if child was simplified in this round, it may have already been converted, and then nothing happens
11664  * but if child was already simplified, then it was not converted, and thus we try it here
11665  */
11666  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
11667 
11668  if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
11669  continue;
11670 
11671  SCIPdebugMessage("expand child %d in expression node %p = ", i, (void*)node);
11672  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11673  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n\tchild = ") );
11674  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11675  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
11676 
11677  removechild = TRUE; /* we intend to release children[i] */
11678 
11679  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11680 
11681  /* add children of child i to node */
11682  SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
11683 
11684  /* put polynomial of child i into every monomial where child i is used */
11685  j = 0;
11686  while( j < polynomialdata->nmonomials )
11687  {
11688  int factorpos;
11689  SCIP_Bool success;
11690 
11691  monomial = polynomialdata->monomials[j];
11692  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11693  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11694 
11695  /* make sure factors are merged, should only be potentially necessary if not sorted, see also #1848 */
11696  if( !monomial->sorted )
11697  SCIPexprMergeMonomialFactors(monomial, eps);
11698 
11699  if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11700  {
11701  ++j;
11702  continue;
11703  }
11704 
11705  assert(factorpos >= 0);
11706  assert(factorpos < monomial->nfactors);
11707  /* assert that factors have been merged */
11708  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11709  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11710 
11711  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11712 
11713  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
11714  (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
11715 
11716  if( !success )
11717  {
11718  removechild = FALSE;
11719  ++j;
11720  }
11721  else
11722  *havechange = TRUE;
11723 
11724  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
11725  * we thus repeat with index j, if a factor was successfully expanded
11726  */
11727  }
11728 
11729  /* forget about child i, if it is not used anymore */
11730  if( removechild )
11731  {
11732  /* remove node from list of parents of child i */
11733  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11734  node->children[i] = NULL;
11735  }
11736  }
11737 
11738  /* simplify current polynomial again */
11739  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11740 
11741  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
11742 
11743  /* check which children are still in use */
11744  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
11745  BMSclearMemoryArray(childinuse, node->nchildren); /*lint !e644*/
11746  for( i = 0; i < polynomialdata->nmonomials; ++i )
11747  {
11748  monomial = polynomialdata->monomials[i];
11749  assert(monomial != NULL);
11750 
11751  for( j = 0; j < monomial->nfactors; ++j )
11752  {
11753  assert(monomial->childidxs[j] >= 0);
11754  assert(monomial->childidxs[j] < node->nchildren);
11755  childinuse[monomial->childidxs[j]] = TRUE;
11756  }
11757  }
11758 
11759  /* free children that are not used in any monomial */
11760  for( i = 0; i < node->nchildren; ++i )
11761  if( node->children[i] != NULL && !childinuse[i] )
11762  {
11763  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11764  node->children[i] = NULL;
11765  }
11766 
11767  BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
11768 
11769  /* remove NULLs from children array */
11771 
11772  /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
11773  if( node->nchildren == 0 )
11774  {
11775  SCIP_Real val;
11776 
11777  /* if no children, then it should also have no monomials */
11778  assert(polynomialdata->nmonomials == 0);
11779 
11780  val = polynomialdata->constant;
11781  polynomialdataFree(blkmem, &polynomialdata);
11782 
11783  node->op = SCIP_EXPR_CONST;
11784  node->data.dbl = val;
11785  node->value = val;
11786  }
11787 
11788  /* if no factor in a monomial was replaced, the number of children should not have changed
11789  * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11790  */
11791  *havechange |= (node->nchildren < orignchildren); /*lint !e514*/
11792 
11793  node->simplified = TRUE;
11794 
11795  SCIPdebugMessage("-> %p = ", (void*)node);
11796  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11797  SCIPdebugPrintf("\n");
11798 
11799  return SCIP_OKAY;
11800 }
11801 
11802 /** creates an expression from a given node in an expression graph
11803  *
11804  * Assembles mapping of variables from graph to tree.
11805  */
11806 static
11808  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11809  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which expression should be created */
11810  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
11811  int* nexprvars, /**< current number of variables in expression */
11812  int* varidx /**< current mapping of variable indices from graph to expression */
11813  )
11814 {
11815  SCIP_EXPR** childexprs;
11816  int i;
11817 
11818  assert(exprgraph != NULL);
11819  assert(node != NULL);
11820  assert(expr != NULL);
11821  assert(nexprvars != NULL);
11822  assert(*nexprvars >= 0);
11823  assert(varidx != NULL);
11824 
11825  childexprs = NULL;
11826  if( node->nchildren > 0 )
11827  {
11828  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11829  for( i = 0; i < node->nchildren; ++i )
11830  {
11831  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) ); /*lint !e613*/
11832  }
11833  }
11834 
11835  switch( node->op )
11836  {
11837  case SCIP_EXPR_VARIDX:
11838  {
11839  /* check if the variable already has an index assigned in the expression tree
11840  * if not, create one and increase nexprvars
11841  */
11842  assert(node->data.intval >= 0);
11843  assert(node->data.intval < exprgraph->nvars);
11844  assert(varidx[node->data.intval] >= -1);
11845  assert(varidx[node->data.intval] < *nexprvars);
11846  if( varidx[node->data.intval] == -1 )
11847  {
11848  varidx[node->data.intval] = *nexprvars;
11849  ++*nexprvars;
11850  }
11851 
11852  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11853  break;
11854  }
11855 
11856  case SCIP_EXPR_CONST:
11857  {
11858  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11859  break;
11860  }
11861 
11862  case SCIP_EXPR_REALPOWER:
11863  case SCIP_EXPR_SIGNPOWER:
11864  {
11865  assert(node->nchildren == 1);
11866  assert(childexprs != NULL);
11867  /* coverity[var_deref_op] */
11868  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11869  break;
11870  }
11871 
11872  case SCIP_EXPR_INTPOWER:
11873  {
11874  assert(node->nchildren == 1);
11875  assert(childexprs != NULL);
11876  /* coverity[var_deref_op] */
11877  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11878  break;
11879  }
11880 
11881  case SCIP_EXPR_PLUS:
11882  case SCIP_EXPR_MINUS:
11883  case SCIP_EXPR_MUL:
11884  case SCIP_EXPR_DIV:
11885  case SCIP_EXPR_MIN:
11886  case SCIP_EXPR_MAX:
11887  {
11888  assert(node->nchildren == 2);
11889  assert(childexprs != NULL);
11890  /* coverity[var_deref_op] */
11891  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11892  break;
11893  }
11894 
11895  case SCIP_EXPR_SQUARE:
11896  case SCIP_EXPR_SQRT:
11897  case SCIP_EXPR_EXP:
11898  case SCIP_EXPR_LOG:
11899  case SCIP_EXPR_SIN:
11900  case SCIP_EXPR_COS:
11901  case SCIP_EXPR_TAN:
11902  /* case SCIP_EXPR_ERF: */
11903  /* case SCIP_EXPR_ERFI: */
11904  case SCIP_EXPR_ABS:
11905  case SCIP_EXPR_SIGN:
11906  {
11907  assert(node->nchildren == 1);
11908  assert(childexprs != NULL);
11909  /* coverity[var_deref_op] */
11910  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11911  break;
11912  }
11913 
11914  case SCIP_EXPR_SUM:
11915  case SCIP_EXPR_PRODUCT:
11916  {
11917  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11918  break;
11919  }
11920 
11921  case SCIP_EXPR_LINEAR:
11922  {
11923  assert(node->data.data != NULL);
11924 
11925  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11926  break;
11927  }
11928 
11929  case SCIP_EXPR_QUADRATIC:
11930  {
11931  SCIP_EXPRDATA_QUADRATIC* quaddata;
11932 
11933  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11934  assert(quaddata != NULL);
11935 
11936  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11937  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11938  break;
11939  }
11940 
11941  case SCIP_EXPR_POLYNOMIAL:
11942  {
11943  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11944 
11945  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11946  assert(polynomialdata != NULL);
11947 
11948  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11949  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11950 
11951  break;
11952  }
11953 
11954  case SCIP_EXPR_USER:
11955  {
11956  SCIP_EXPRDATA_USER* exprdata;
11957  SCIP_USEREXPRDATA* userdata;
11958 
11959  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11960  assert(exprdata != NULL);
11961 
11962  if( exprdata->copydata != NULL )
11963  {
11964  SCIP_CALL( exprdata->copydata(exprgraph->blkmem, node->nchildren, exprdata->userdata, &userdata) );
11965  }
11966  else
11967  userdata = exprdata->userdata;
11968 
11969  /* coverity[var_deref_op] */
11970  /* coverity[var_deref_model] */
11971  SCIP_CALL( SCIPexprCreateUser(exprgraph->blkmem, expr, node->nchildren, childexprs,
11972  userdata, exprdata->evalcapability, exprdata->eval, exprdata->inteval, exprdata->curv, exprdata->prop, exprdata->estimate, exprdata->copydata, exprdata->freedata, exprdata->print) );
11973 
11974  break;
11975  }
11976 
11977  case SCIP_EXPR_LAST:
11978  case SCIP_EXPR_PARAM:
11979  {
11980  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11981  return SCIP_ERROR;
11982  }
11983  }
11984 
11985  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11986 
11987  return SCIP_OKAY;
11988 }
11989 
11990 /** counts how often expression graph variables are used in a subtree of the expression graph
11991  *
11992  * @note The function does not clear the array first, but only increases already existing counts.
11993  */
11994 static
11996  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11997  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11998  )
11999 {
12000  int i;
12001 
12002  assert(node != NULL);
12003  assert(varsusage != NULL);
12004 
12005  if( node->op == SCIP_EXPR_VARIDX )
12006  {
12007  ++varsusage[node->data.intval];
12008  return;
12009  }
12010 
12011  for( i = 0; i < node->nchildren; ++i )
12012  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
12013 }
12014 
12015 /** checks whether a node can be put into a component when checking block separability of an expression
12016  *
12017  * If a variable used by node is already in another component, components are merged and component number is updated.
12018  */
12019 static
12021  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
12022  int* compnr, /**< component number to assign, may be reduced if variables overlap */
12023  int nchildcomps, /**< number of entries for which childcomps have been set already */
12024  int* childcomps, /**< component numbers of children */
12025  int nvars, /**< number of variables */
12026  int* varcomps /**< component numbers of variables */
12027  )
12028 {
12029  int varidx;
12030  int i;
12031 
12032  assert(node != NULL);
12033  assert(compnr != NULL);
12034  assert(*compnr >= 0);
12035  assert(childcomps != NULL);
12036  assert(varcomps != NULL);
12037 
12038  if( node->op != SCIP_EXPR_VARIDX )
12039  {
12040  for( i = 0; i < node->nchildren; ++i )
12041  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
12042  return;
12043  }
12044 
12045  varidx = node->data.intval;
12046  assert(varidx >= 0);
12047  assert(varidx < nvars);
12048 
12049  if( varcomps[varidx] == -1 )
12050  {
12051  /* first time we get to this variable, so set it's component to compnr and we are done */
12052  varcomps[varidx] = *compnr;
12053  return;
12054  }
12055 
12056  if( varcomps[varidx] == *compnr )
12057  {
12058  /* variable is already in current component, that's also good and we are done */
12059  return;
12060  }
12061 
12062  /* variable is already in another component, so have to merge component compnr into that component
12063  * do this by updating varcomps and childcomps */
12064  for( i = 0; i < nvars; ++i )
12065  if( varcomps[i] == *compnr )
12066  varcomps[i] = varcomps[varidx];
12067  for( i = 0; i < nchildcomps; ++i )
12068  if( childcomps[i] == *compnr )
12069  /* coverity[copy_paste_error] */
12070  childcomps[i] = varcomps[varidx];
12071  *compnr = varcomps[varidx];
12072 }
12073 
12074 /**@} */
12075 
12076 /**@name Expression graph private methods */
12077 /**@{ */
12078 
12079 /** assert that expression graph has at least a given depth */
12080 static
12082  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
12083  int mindepth /**< minimal depth that should be ensured */
12084  )
12085 {
12086  int olddepth;
12087 
12088  assert(exprgraph != NULL);
12089  assert(exprgraph->blkmem != NULL);
12090 
12091  if( mindepth <= exprgraph->depth )
12092  return SCIP_OKAY;
12093 
12094  olddepth = exprgraph->depth;
12095  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
12096  assert(exprgraph->depth >= mindepth);
12097 
12098  /* initialize new array entries to 0 and NULL, resp. */
12099  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12100  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12101  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12102 
12103  return SCIP_OKAY;
12104 }
12105 
12106 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
12107 static
12109  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12110  int varidx /**< variable index */
12111  )
12112 {
12113  SCIP_EXPRGRAPHNODE* varnode;
12114  void* var;
12115 
12116  assert(exprgraph != NULL);
12117  assert(varidx >= 0);
12118  assert(varidx < exprgraph->nvars);
12119 
12120  varnode = exprgraph->varnodes[varidx];
12121  assert(varnode->data.intval == varidx);
12122 
12123  var = exprgraph->vars[varidx];
12124 
12125  /* call varremove callback method, if set */
12126  if( exprgraph->exprgraphvarremove != NULL )
12127  {
12128  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
12129  }
12130 
12131  /* remove variable from hashmap */
12132  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
12133 
12134  /* move last variable to position varidx and give it the new index */
12135  if( varidx < exprgraph->nvars-1 )
12136  {
12137  /* call callback method, if set */
12138  if( exprgraph->exprgraphvarchgidx != NULL )
12139  {
12140  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
12141  }
12142 
12143  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
12144  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
12145  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
12146  exprgraph->varnodes[varidx]->data.intval = varidx;
12147  SCIP_CALL( SCIPhashmapSetImageInt(exprgraph->varidxs, exprgraph->vars[varidx], varidx) );
12148  }
12149  --exprgraph->nvars;
12150 
12151  return SCIP_OKAY;
12152 }
12153 
12154 /** moves a node in an expression graph to a different depth
12155  *
12156  * New depth must be larger than children depth.
12157  * Moves parent nodes to higher depth, if needed.
12158  * Variable nodes cannot be moved.
12159  */
12160 static
12162  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12163  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
12164  int newdepth /**< new depth to which to move node */
12165  )
12166 {
12167  int olddepth;
12168  int oldpos;
12169  int i;
12170 
12171  assert(exprgraph != NULL);
12172  assert(node != NULL);
12173  assert(node->depth >= 0); /* node should be in graph */
12174  assert(newdepth >= 0);
12175 
12176  /* if already on aimed depth, then don't need to move */
12177  if( node->depth == newdepth )
12178  return SCIP_OKAY;
12179 
12180  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
12181 
12182 #ifndef NDEBUG
12183  /* assert that children are at lower depth than new depth */
12184  for( i = 0; i < node->nchildren; ++i )
12185  assert(node->children[i]->depth < newdepth);
12186 #endif
12187 
12188  /* move parents to higher depth, if needed */
12189  for( i = 0; i < node->nparents; ++i )
12190  {
12191  if( node->parents[i]->depth <= newdepth )
12192  {
12193  /* move parent to depth+1 */
12194  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
12195  assert(node->parents[i]->depth > newdepth);
12196  }
12197  }
12198 
12199  /* ensure that graph is deep enough */
12200  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
12201  assert(exprgraph->depth > newdepth);
12202 
12203  olddepth = node->depth;
12204  oldpos = node->pos;
12205 
12206  /* add node to new depth */
12207  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
12208  node->depth = newdepth;
12209  node->pos = exprgraph->nnodes[newdepth];
12210  exprgraph->nodes[newdepth][node->pos] = node;
12211  ++exprgraph->nnodes[newdepth];
12212 
12213  /* 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) */
12214  for( i = 0; i < node->nchildren; ++i )
12215  node->children[i]->parentssorted = FALSE;
12216 
12217  /* move last node at previous depth to previous position, if it wasn't last */
12218  if( oldpos < exprgraph->nnodes[olddepth]-1 )
12219  {
12220  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
12221  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
12222 
12223  /* 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) */
12224  for( i = 0; i < exprgraph->nodes[olddepth][oldpos]->nchildren; ++i )
12225  exprgraph->nodes[olddepth][oldpos]->children[i]->parentssorted = FALSE;
12226  }
12227  --exprgraph->nnodes[olddepth];
12228 
12229  if( node->depth == 0 )
12230  {
12231  /* if at depth 0, then it need to be a node for either a constant or a variable */
12232  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
12233  if( node->op == SCIP_EXPR_CONST )
12234  {
12235  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
12236  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
12237  exprgraph->constnodes[exprgraph->nconsts] = node;
12238  ++exprgraph->nconsts;
12239  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
12240  }
12241  else
12242  {
12243  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
12244  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
12245  return SCIP_ERROR;
12246  }
12247 
12248  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
12249  node->curv = SCIP_EXPRCURV_LINEAR;
12250  }
12251 
12252  return SCIP_OKAY;
12253 }
12254 
12255 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
12256 static
12258  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12259  int nchildren, /**< number of children */
12260  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
12261  SCIP_EXPROP op, /**< operator */
12262  SCIP_EXPROPDATA opdata, /**< operator data */
12263  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
12264  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
12265  )
12266 {
12267  SCIP_EXPRGRAPHNODE** parentcands;
12268  int nparentcands;
12269  int parentcandssize;
12270  int i;
12271  int p;
12272 
12273  assert(exprgraph != NULL);
12274  assert(nchildren > 0);
12275  assert(children != NULL);
12276  assert(parent != NULL);
12277 
12278  *parent = NULL;
12279 
12280  /* create initial set of parent candidates as
12281  * all parents of first child that have the same operator type and the same number of children
12282  * additionally, some easy conditions for complex expression types:
12283  * if expression type is int/real/signpower, then compare also exponent,
12284  * if expression type is linear, then compare also constant part,
12285  * if expression type is quadratic, then compare also number of quadratic elements,
12286  * if expression type is polynomial, then compare also number of monmials and constant part
12287  */
12288  parentcandssize = children[0]->nparents;
12289  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
12290  nparentcands = 0;
12291  for( p = 0; p < children[0]->nparents; ++p )
12292  if( children[0]->parents[p]->op == op &&
12293  children[0]->parents[p]->nchildren == nchildren &&
12294  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
12295  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12296  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12297  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
12298  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
12299  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
12300  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
12301  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
12302  )
12303  {
12304  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
12305  }
12306 
12307  /* for all remaining children, remove parent candidates, that are not in their list of parents */
12308  for( i = 1; i < nchildren && nparentcands > 0; ++i )
12309  {
12310  p = 0;
12311  while( p < nparentcands )
12312  {
12313  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
12314  * otherwise keep candidate and check next one
12315  */
12316  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
12317  {
12318  parentcands[p] = parentcands[nparentcands-1];
12319  --nparentcands;
12320  }
12321  else
12322  ++p;
12323  }
12324  }
12325 
12326  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
12327 
12328  if( nparentcands == 0 )
12329  {
12330  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
12331  return SCIP_OKAY;
12332  }
12333 
12334  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
12335  * check if there is also one which corresponds to same expression and store that one in *parent
12336  */
12337  switch( op )
12338  {
12339  /* commutative operands with no data */
12340  case SCIP_EXPR_PLUS :
12341  case SCIP_EXPR_MUL :
12342  case SCIP_EXPR_MIN :
12343  case SCIP_EXPR_MAX :
12344  case SCIP_EXPR_SUM :
12345  case SCIP_EXPR_PRODUCT:
12346  case SCIP_EXPR_SQUARE :
12347  case SCIP_EXPR_SQRT :
12348  case SCIP_EXPR_EXP :
12349  case SCIP_EXPR_LOG :
12350  case SCIP_EXPR_SIN :
12351  case SCIP_EXPR_COS :
12352  case SCIP_EXPR_TAN :
12353  /* case SCIP_EXPR_ERF : */
12354  /* case SCIP_EXPR_ERFI : */
12355  case SCIP_EXPR_ABS :
12356  case SCIP_EXPR_SIGN :
12357  {
12358  /* sort childnodes, if needed for later */
12359  if( nchildren > 2 )
12360  SCIPsortPtr((void**)children, exprgraphnodecomp, nchildren);
12361  for( p = 0; p < nparentcands; ++p )
12362  {
12363  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12364  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12365 
12366  if( nchildren == 1 )
12367  {
12368  assert(parentcands[p]->children[0] == children[0]);
12369  /* same operand, same child, so same expression */
12370  *parent = parentcands[p];
12371  break;
12372  }
12373  else if( nchildren == 2 )
12374  {
12375  /* We know that every node in children is also a child of parentcands[p].
12376  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
12377  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
12378  */
12379  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
12380  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
12381  {
12382  *parent = parentcands[p];
12383  break;
12384  }
12385  }
12386  else
12387  {
12388  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
12389 
12390  /* sort children of parent candidate */
12391  SCIPsortPtr((void**)parentcands[p]->children, exprgraphnodecomp, nchildren);
12392 
12393  /* check if childnodes and parentcands[p]->children are the same */
12394  for( i = 0; i < nchildren; ++i )
12395  if( children[i] != parentcands[p]->children[i] )
12396  break;
12397  if( i == nchildren )
12398  {
12399  /* yeah, found an exact match */
12400  *parent = parentcands[p];
12401  break;
12402  }
12403  }
12404  }
12405 
12406  break;
12407  }
12408 
12409  /* non-commutative operands with two children */
12410  case SCIP_EXPR_MINUS :
12411  case SCIP_EXPR_DIV :
12412  {
12413  for( p = 0; p < nparentcands; ++p )
12414  {
12415  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12416  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
12417  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
12418  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
12419  {
12420  /* yeah, found one */
12421  *parent = parentcands[p];
12422  break;
12423  }
12424  }
12425 
12426  break;
12427  }
12428 
12429  /* operands with one child and data */
12430  case SCIP_EXPR_INTPOWER:
12431  {
12432  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12433  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12434  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12435  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
12436 
12437  /* yeah, have one with same exponent */
12438  *parent = parentcands[0];
12439 
12440  break;
12441  }
12442 
12443  case SCIP_EXPR_REALPOWER:
12444  case SCIP_EXPR_SIGNPOWER:
12445  {
12446  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12447  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12448  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12449  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
12450 
12451  /* yeah, have one with same exponent */
12452  *parent = parentcands[0];
12453 
12454  break;
12455  }
12456 
12457  /* commutative operands with n children and data */
12458  case SCIP_EXPR_LINEAR:
12459  {
12460  SCIP_Real* exprcoef;
12461  SCIP_Real* candcoef;
12462 
12463  exprcoef = (SCIP_Real*)opdata.data;
12464  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
12465  if( exprchildren != NULL )
12466  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, exprgraphnodecomp, nchildren);
12467  else
12468  SCIPsortPtrReal((void**)children, exprcoef, exprgraphnodecomp, nchildren);
12469  for( p = 0; p < nparentcands; ++p )
12470  {
12471  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12472  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12473 
12474  candcoef = (SCIP_Real*)parentcands[p]->data.data;
12475  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12476 
12477  /* sort children of parent candidate */
12478  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, exprgraphnodecomp, nchildren);
12479 
12480  /* check if children and coefficients in parent candidate and expression are the same */
12481  for( i = 0; i < nchildren; ++i )
12482  {
12483  if( children[i] != parentcands[p]->children[i] )
12484  break;
12485  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
12486  break;
12487  }
12488  if( i < nchildren )
12489  continue;
12490 
12491  /* yeah, found an exact match */
12492  *parent = parentcands[p];
12493  break;
12494  }
12495 
12496  break;
12497  }
12498 
12499  case SCIP_EXPR_QUADRATIC:
12500  {
12501  SCIP_EXPRDATA_QUADRATIC* exprdata;
12502  SCIP_Real* exprlincoef;
12503  SCIP_Real* candlincoef;
12504  SCIP_EXPRDATA_QUADRATIC* canddata;
12505  int* perm;
12506  int* invperm;
12507 
12508  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
12509  exprlincoef = exprdata->lincoefs;
12510 
12511  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
12512 
12513  /* sort expr->children and childnodes and store inverse permutation in invperm */
12514  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12515  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12516  for( i = 0; i < nchildren; ++i )
12517  invperm[i] = i; /*lint !e644*/
12518 
12519  if( exprlincoef != NULL )
12520  if( exprchildren != NULL )
12521  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12522  else
12523  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12524  else
12525  if( exprchildren != NULL )
12526  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12527  else
12528  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12529 
12530  /* compute permutation from its inverse */
12531  for( i = 0; i < nchildren; ++i )
12532  perm[invperm[i]] = i; /*lint !e644*/
12533 
12534  /* apply permuation to exprdata->quadelems and sort again */
12535  for( i = 0; i < exprdata->nquadelems; ++i )
12536  {
12537  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
12538  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
12539  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
12540  {
12541  int tmp;
12542  tmp = exprdata->quadelems[i].idx1;
12543  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
12544  exprdata->quadelems[i].idx2 = tmp;
12545  }
12546  }
12547  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
12548  exprdata->sorted = TRUE;
12549 
12550  for( p = 0; p < nparentcands; ++p )
12551  {
12552  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12553  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12554 
12555  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
12556  candlincoef = canddata->lincoefs;
12557  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
12558  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12559 
12560  /* sort parentcands[p]->children and store inverse permutation in invperm */
12561  for( i = 0; i < nchildren; ++i )
12562  invperm[i] = i;
12563 
12564  if( candlincoef != NULL )
12565  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, exprgraphnodecomp, parentcands[p]->nchildren);
12566  else
12567  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12568 
12569  /* compute permutation from its inverse */
12570  for( i = 0; i < nchildren; ++i )
12571  perm[invperm[i]] = i;
12572 
12573  /* apply permutation to canddata->quadelems */
12574  for( i = 0; i < canddata->nquadelems; ++i )
12575  {
12576  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
12577  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
12578  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
12579  {
12580  int tmp;
12581  tmp = canddata->quadelems[i].idx1;
12582  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
12583  canddata->quadelems[i].idx2 = tmp;
12584  }
12585  }
12586  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
12587  canddata->sorted = TRUE;
12588 
12589  /* check if children and linear coefficients in parent candidate and expression are the same */
12590  for( i = 0; i < nchildren; ++i )
12591  {
12592  if( children[i] != parentcands[p]->children[i] )
12593  break;
12594  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
12595  break;
12596  }
12597  if( i < nchildren )
12598  continue;
12599 
12600  assert(exprdata->nquadelems == canddata->nquadelems);
12601  for( i = 0; i < exprdata->nquadelems; ++i )
12602  {
12603  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
12604  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
12605  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
12606  break;
12607  }
12608  if( i == exprdata->nquadelems )
12609  {
12610  /* yeah, parentcands[p] is same quadratic expression as expr */
12611  *parent = parentcands[p];
12612  break;
12613  }
12614  }
12615 
12616  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12617  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12618 
12619  break;
12620  }
12621 
12622  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
12623  case SCIP_EXPR_POLYNOMIAL:
12624  {
12625  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
12626  SCIP_EXPRDATA_POLYNOMIAL* canddata;
12627  int* perm;
12628  int* invperm;
12629 
12630  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
12631 
12632  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
12633 
12634  /* sort exprchildren and childnodes and store inverse permutation in invperm */
12635  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12636  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12637  for( i = 0; i < nchildren; ++i )
12638  invperm[i] = i; /*lint !e644*/
12639 
12640  if( exprchildren != NULL )
12641  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12642  else
12643  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12644 
12645  /* compute permutation from its inverse */
12646  for( i = 0; i < nchildren; ++i )
12647  perm[invperm[i]] = i; /*lint !e644*/
12648 
12649  /* apply permutation to exprdata and sort again */
12650  polynomialdataApplyChildmap(exprdata, perm);
12651  polynomialdataSortMonomials(exprdata);
12652 
12653  for( p = 0; p < nparentcands; ++p )
12654  {
12655  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12656  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12657 
12658  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
12659  assert(canddata->nmonomials == exprdata->nmonomials); /* that was a criterium for adding a node to parentcands */
12660  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12661 
12662  /* sort parentcands[p]->children and store inverse permutation in invperm */
12663  for( i = 0; i < nchildren; ++i )
12664  invperm[i] = i;
12665 
12666  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12667 
12668  /* compute permutation from its inverse */
12669  for( i = 0; i < nchildren; ++i )
12670  perm[invperm[i]] = i;
12671 
12672  /* apply permutation to canddata and sort again */
12673  polynomialdataApplyChildmap(canddata, perm);
12674  polynomialdataSortMonomials(canddata);
12675 
12676  /* check if children are equal */
12677  for( i = 0; i < nchildren; ++i )
12678  if( children[i] != parentcands[p]->children[i] )
12679  break;
12680  if( i < nchildren )
12681  continue;
12682 
12683  /* check if monomials are equal */
12684  for( i = 0; i < exprdata->nmonomials; ++i )
12685  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
12686  break;
12687  if( i == exprdata->nmonomials )
12688  {
12689  /* yeah, parentcands[p] is same polynomial expression as expr */
12690  *parent = parentcands[p];
12691  break;
12692  }
12693  }
12694 
12695  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12696  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12697 
12698  break;
12699  }
12700 
12701  case SCIP_EXPR_USER:
12702  {
12703  /* @todo need comparison function on user data to decide whether a parent candidate fits */
12704  break;
12705  }
12706 
12707  case SCIP_EXPR_VARIDX:
12708  case SCIP_EXPR_PARAM:
12709  case SCIP_EXPR_CONST:
12710  case SCIP_EXPR_LAST:
12711  SCIPerrorMessage("expression operand %d unexpected here\n", op);
12712  return SCIP_ERROR;
12713  }
12714 
12715  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
12716 
12717  return SCIP_OKAY;
12718 }
12719 
12720 /** adds an expression into an expression graph
12721  *
12722  * Enables corresponding nodes.
12723  */
12724 static
12726  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12727  SCIP_EXPR* expr, /**< expression to add */
12728  void** vars, /**< variables corresponding to VARIDX expressions */
12729  SCIP_Real* params, /**< parameter values */
12730  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
12731  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12732  )
12733 {
12734  SCIP_EXPRGRAPHNODE** childnodes;
12735  SCIP_Bool childisnew;
12736  SCIP_Bool nochildisnew;
12737  SCIP_EXPROPDATA opdata;
12738  int i;
12739 
12740  assert(exprgraph != NULL);
12741  assert(expr != NULL);
12742  assert(exprnode != NULL);
12743  assert(exprnodeisnew != NULL);
12744 
12745  if( expr->op == SCIP_EXPR_VARIDX )
12746  {
12747  /* find node corresponding to variable and add if not existing yet */
12748  assert(expr->nchildren == 0);
12749 
12750  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12751  assert(*exprnode != NULL);
12752  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12753  assert((*exprnode)->data.intval >= 0);
12754  assert((*exprnode)->data.intval < exprgraph->nvars);
12755  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12756 
12757  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12758 
12759  return SCIP_OKAY;
12760  }
12761 
12762  if( expr->op == SCIP_EXPR_CONST )
12763  {
12764  /* find node corresponding to constant and add if not existing yet */
12765  assert(expr->nchildren == 0);
12766 
12767  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12768  assert(*exprnode != NULL);
12769  assert((*exprnode)->op == SCIP_EXPR_CONST);
12770  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
12771 
12772  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12773 
12774  return SCIP_OKAY;
12775  }
12776 
12777  if( expr->op == SCIP_EXPR_PARAM )
12778  {
12779  /* find node corresponding to constant corresponding to parameter and add if not existing yet */
12780  assert(expr->nchildren == 0);
12781  assert(params != NULL);
12782 
12783  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, params[expr->data.intval], exprnode) );
12784  assert(*exprnode != NULL);
12785  assert((*exprnode)->op == SCIP_EXPR_CONST);
12786  assert((*exprnode)->data.dbl == params[expr->data.intval]); /*lint !e777*/
12787 
12788  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12789 
12790  return SCIP_OKAY;
12791  }
12792 
12793  /* expression should be variable or constant or have children */
12794  assert(expr->nchildren > 0);
12795 
12796  /* add children expressions into expression graph
12797  * check if we can find a common parent
12798  */
12799  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12800  nochildisnew = TRUE;
12801  for( i = 0; i < expr->nchildren; ++i )
12802  {
12803  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, params, &childnodes[i], &childisnew) ); /*lint !e644*/
12804  assert(childnodes[i] != NULL);
12805  nochildisnew &= !childisnew; /*lint !e514*/
12806  }
12807 
12808  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12809  if( nochildisnew )
12810  {
12811  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12812 
12813  if( *exprnode != NULL )
12814  {
12815  /* node already existing, make sure it is enabled */
12816  (*exprnode)->enabled = TRUE;
12817  *exprnodeisnew = FALSE;
12818 
12819  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12820  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12821  * SCIPdebugPrintf("\n");
12822  */
12823 
12824  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12825  return SCIP_OKAY;
12826  }
12827  }
12828 
12829  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12830 
12831  /* copy expression data */
12832  if( exprOpTable[expr->op].copydata != NULL )
12833  {
12834  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12835  }
12836  else
12837  {
12838  opdata = expr->data;
12839  }
12840 
12841  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12842  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12843  *exprnodeisnew = TRUE;
12844 
12845  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12846 
12847  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12848  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12849  * SCIPdebugPrintf("\n");
12850  */
12851 
12852  return SCIP_OKAY;
12853 }
12854 
12855 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12856 static
12858  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12859  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12860  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12861  )
12862 {
12863  SCIP_EXPRGRAPHNODE* node;
12864  int i;
12865  int p;
12866 
12867  assert(exprgraph != NULL);
12868  assert(clearreverseprop != NULL);
12869  assert(boundchanged != NULL);
12870 
12871  *boundchanged = FALSE;
12872  for( i = 0; i < exprgraph->nvars; ++i )
12873  {
12874  node = exprgraph->varnodes[i];
12875 
12876  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12877  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12878  {
12880  continue;
12881  }
12882 
12883  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12884  {
12885  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12886  SCIP_Real tmp;
12887 
12888  tmp = exprgraph->varbounds[i].inf;
12889  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12890  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12891  }
12892 
12893  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12894  +exprgraph->varbounds[i].sup > node->bounds.sup )
12895  {
12896  for( p = 0; p < node->nparents; ++p )
12898 
12899  node->bounds = exprgraph->varbounds[i];
12900  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12901 
12902  *boundchanged = TRUE;
12903 
12904  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12905  *clearreverseprop = TRUE;
12906  }
12907  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12908  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12909  {
12910  for( p = 0; p < node->nparents; ++p )
12912 
12913  node->bounds = exprgraph->varbounds[i];
12914  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12915 
12916  *boundchanged = TRUE;
12917  }
12918  else
12919  {
12920  node->bounds = exprgraph->varbounds[i];
12921  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12922  }
12923 
12925  }
12926 }
12927 
12928 /**@} */
12929 
12930 /**@name Expression graph node methods */
12931 /**@{ */
12932 
12933 /* In debug mode, the following methods are implemented as function calls to ensure
12934  * type validity.
12935  * In optimized mode, the methods are implemented as defines to improve performance.
12936  * However, we want to have them in the library anyways, so we have to undef the defines.
12937  */
12938 
12939 #undef SCIPexprgraphCaptureNode
12940 #undef SCIPexprgraphIsNodeEnabled
12941 #undef SCIPexprgraphGetNodeNChildren
12942 #undef SCIPexprgraphGetNodeChildren
12943 #undef SCIPexprgraphGetNodeNParents
12944 #undef SCIPexprgraphGetNodeParents
12945 #undef SCIPexprgraphGetNodeDepth
12946 #undef SCIPexprgraphGetNodePosition
12947 #undef SCIPexprgraphGetNodeOperator
12948 #undef SCIPexprgraphGetNodeOperatorIndex
12949 #undef SCIPexprgraphGetNodeOperatorReal
12950 #undef SCIPexprgraphGetNodeVar
12951 #undef SCIPexprgraphGetNodeRealPowerExponent
12952 #undef SCIPexprgraphGetNodeIntPowerExponent
12953 #undef SCIPexprgraphGetNodeSignPowerExponent
12954 #undef SCIPexprgraphGetNodeLinearCoefs
12955 #undef SCIPexprgraphGetNodeLinearConstant
12956 #undef SCIPexprgraphGetNodeQuadraticConstant
12957 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12958 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12959 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12960 #undef SCIPexprgraphGetNodePolynomialMonomials
12961 #undef SCIPexprgraphGetNodePolynomialNMonomials
12962 #undef SCIPexprgraphGetNodePolynomialConstant
12963 #undef SCIPexprgraphGetNodeUserData
12964 #undef SCIPexprgraphHasNodeUserEstimator
12965 #undef SCIPexprgraphGetNodeBounds
12966 #undef SCIPexprgraphGetNodeVal
12967 #undef SCIPexprgraphGetNodeCurvature
12968 
12969 /** captures node, i.e., increases number of uses */
12971  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12972  )
12973 {
12974  assert(node->nuses >= 0);
12975 
12976  SCIPdebugMessage("capture node %p\n", (void*)node);
12977 
12978  ++node->nuses;
12979 }
12980 
12981 /** returns whether a node is currently enabled */
12983  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12984  )
12985 {
12986  assert(node != NULL);
12987 
12988  return node->enabled;
12989 }
12990 
12991 /** gets number of children of a node in an expression graph */
12993  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12994  )
12995 {
12996  assert(node != NULL);
12997 
12998  return node->nchildren;
12999 }
13000 
13001 /** gets children of a node in an expression graph */
13003  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13004  )
13005 {
13006  assert(node != NULL);
13007 
13008  return node->children;
13009 }
13010 
13011 /** gets number of parents of a node in an expression graph */
13013  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13014  )
13015 {
13016  assert(node != NULL);
13017 
13018  return node->nparents;
13019 }
13020 
13021 /** gets parents of a node in an expression graph */
13023  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13024  )
13025 {
13026  assert(node != NULL);
13027 
13028  return node->parents;
13029 }
13030 
13031 /** gets depth of node in expression graph */
13033  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13034  )
13035 {
13036  assert(node != NULL);
13037 
13038  return node->depth;
13039 }
13040 
13041 /** gets position of node in expression graph at its depth level */
13043  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13044  )
13045 {
13046  assert(node != NULL);
13047 
13048  return node->pos;
13049 }
13050 
13051 /** gets operator of a node in an expression graph */
13053  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13054  )
13055 {
13056  assert(node != NULL);
13057 
13058  return node->op;
13059 }
13060 
13061 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
13063  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13064  )
13065 {
13066  assert(node != NULL);
13067  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
13068 
13069  return node->data.intval;
13070 }
13071 
13072 /** gives real belonging to a SCIP_EXPR_CONST operand */
13074  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13075  )
13076 {
13077  assert(node != NULL);
13078  assert(node->op == SCIP_EXPR_CONST);
13079 
13080  return node->data.dbl;
13081 }
13082 
13083 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
13085  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13086  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13087  )
13088 {
13089  assert(exprgraph != NULL);
13090  assert(node != NULL);
13091  assert(node->op == SCIP_EXPR_VARIDX);
13092  assert(node->data.intval >= 0);
13093  assert(node->data.intval < exprgraph->nvars);
13094 
13095  return exprgraph->vars[node->data.intval];
13096 }
13097 
13098 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
13100  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13101  )
13102 {
13103  assert(node != NULL);
13104  assert(node->op == SCIP_EXPR_REALPOWER);
13105 
13106  return node->data.dbl;
13107 }
13108 
13109 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
13111  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13112  )
13113 {
13114  assert(node != NULL);
13115  assert(node->op == SCIP_EXPR_INTPOWER);
13116 
13117  return node->data.intval;
13118 }
13119 
13120 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
13122  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13123  )
13124 {
13125  assert(node != NULL);
13126  assert(node->op == SCIP_EXPR_SIGNPOWER);
13127 
13128  return node->data.dbl;
13129 }
13130 
13131 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
13133  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13134  )
13135 {
13136  assert(node != NULL);
13137  assert(node->op == SCIP_EXPR_LINEAR);
13138 
13139  return (SCIP_Real*)node->data.data;
13140 }
13141 
13142 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
13144  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13145  )
13146 {
13147  assert(node != NULL);
13148  assert(node->op == SCIP_EXPR_LINEAR);
13149  assert(node->data.data != NULL);
13150 
13151  return ((SCIP_Real*)node->data.data)[node->nchildren];
13152 }
13153 
13154 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
13156  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13157  )
13158 {
13159  assert(node != NULL);
13160  assert(node->op == SCIP_EXPR_QUADRATIC);
13161  assert(node->data.data != NULL);
13162 
13163  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
13164 }
13165 
13166 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
13168  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13169  )
13170 {
13171  assert(node != NULL);
13172  assert(node->op == SCIP_EXPR_QUADRATIC);
13173  assert(node->data.data != NULL);
13174 
13175  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
13176 }
13177 
13178 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13180  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13181  )
13182 {
13183  assert(node != NULL);
13184  assert(node->op == SCIP_EXPR_QUADRATIC);
13185  assert(node->data.data != NULL);
13186 
13187  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
13188 }
13189 
13190 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13192  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13193  )
13194 {
13195  assert(node != NULL);
13196  assert(node->op == SCIP_EXPR_QUADRATIC);
13197  assert(node->data.data != NULL);
13198 
13199  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
13200 }
13201 
13202 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13204  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13205  )
13206 {
13207  assert(node != NULL);
13208  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13209  assert(node->data.data != NULL);
13210 
13211  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
13212 }
13213 
13214 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13216  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13217  )
13218 {
13219  assert(node != NULL);
13220  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13221  assert(node->data.data != NULL);
13222 
13223  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
13224 }
13225 
13226 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
13228  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13229  )
13230 {
13231  assert(node != NULL);
13232  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13233  assert(node->data.data != NULL);
13234 
13235  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
13236 }
13237 
13238 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
13239  *
13240  * Assumes that curvature of children and bounds of children and node itself are valid.
13241  */
13243  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13244  int monomialidx, /**< index of monomial */
13245  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
13246  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
13247  )
13248 {
13249  SCIP_EXPRDATA_MONOMIAL* monomial;
13250  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13251  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13252  SCIP_INTERVAL* childbounds = NULL;
13253  SCIP_EXPRCURV* childcurv = NULL;
13254  SCIP_EXPRGRAPHNODE* child;
13255  SCIP_RETCODE retcode = SCIP_OKAY;
13256  int i;
13257 
13258  assert(node != NULL);
13259  assert(node->depth >= 0); /* node should be in graph */
13260  assert(node->pos >= 0); /* node should be in graph */
13261  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13262  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
13263  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13264  assert(node->data.data != NULL);
13265  assert(monomialidx >= 0);
13266  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
13267  assert(curv != NULL);
13268 
13269  if( SCIPintervalIsEmpty(infinity, node->bounds) )
13270  {
13271  *curv = SCIP_EXPRCURV_LINEAR;
13272  return SCIP_OKAY;
13273  }
13274 
13275  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
13276  assert(monomial != NULL);
13277 
13278  /* if many children, get large enough memory to store children bounds */
13279  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13280  {
13281  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13282  SCIP_ALLOC_TERMINATE( retcode, BMSallocMemoryArray(&childcurv, monomial->nfactors), TERMINATE );
13283  }
13284  else
13285  {
13286  childbounds = childboundsstatic;
13287  childcurv = childcurvstatic;
13288  }
13289 
13290  /* assemble bounds and curvature of children */
13291  for( i = 0; i < monomial->nfactors; ++i )
13292  {
13293  child = node->children[monomial->childidxs[i]];
13294  assert(child != NULL);
13295 
13296  /* child should have valid and non-empty bounds */
13297  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13298  assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13299  /* nodes at depth 0 are always linear */
13300  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13301 
13302  childbounds[i] = child->bounds; /*lint !e644*/
13303  childcurv[i] = child->curv; /*lint !e644*/
13304  }
13305 
13306  /* check curvature */
13307  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13308  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13309 
13310  /* free memory, if allocated before */
13311 TERMINATE:
13312  if( childbounds != childboundsstatic )
13313  {
13314  BMSfreeMemoryArrayNull(&childbounds);
13315  BMSfreeMemoryArrayNull(&childcurv);
13316  }
13317 
13318  return retcode;
13319 }
13320 
13321 /** gives the user data belonging to a SCIP_EXPR_USER expression */
13323  SCIP_EXPRGRAPHNODE* node
13324  )
13325 {
13326  assert(node != NULL);
13327  assert(node->op == SCIP_EXPR_USER);
13328  assert(node->data.data != NULL);
13329 
13330  return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13331 }
13332 
13333 /** indicates whether a user expression has the estimator callback defined */
13335  SCIP_EXPRGRAPHNODE* node
13336  )
13337 {
13338  assert(node != NULL);
13339  assert(node->op == SCIP_EXPR_USER);
13340  assert(node->data.data != NULL);
13341 
13342  return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13343 }
13344 
13345 /** gets bounds of a node in an expression graph */
13347  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13348  )
13349 {
13350  assert(node != NULL);
13351 
13352  return node->bounds;
13353 }
13354 
13355 /** gets value of expression associated to node from last evaluation call */
13357  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13358  )
13359 {
13360  assert(node != NULL);
13361 
13362  return node->value;
13363 }
13364 
13365 /** gets curvature of expression associated to node from last curvature check call */
13367  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13368  )
13369 {
13370  assert(node != NULL);
13371 
13372  return node->curv;
13373 }
13374 
13375 /** creates an expression graph node */
13377  BMS_BLKMEM* blkmem, /**< block memory */
13378  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13379  SCIP_EXPROP op, /**< operator type of expression */
13380  ...
13381  )
13382 {
13383  va_list ap;
13384  SCIP_EXPROPDATA opdata;
13385 
13386  assert(blkmem != NULL);
13387  assert(node != NULL);
13388 
13389  *node = NULL;
13390 
13391  switch( op )
13392  {
13393  case SCIP_EXPR_VARIDX :
13394  case SCIP_EXPR_PARAM :
13395  case SCIP_EXPR_CONST :
13396  case SCIP_EXPR_LINEAR :
13397  case SCIP_EXPR_QUADRATIC :
13398  case SCIP_EXPR_POLYNOMIAL:
13399  case SCIP_EXPR_USER :
13400  {
13401  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n", op);
13402  SCIPABORT();
13403  return SCIP_ERROR; /*lint !e527*/
13404  }
13405 
13406  /* operands without data */
13407  case SCIP_EXPR_PLUS :
13408  case SCIP_EXPR_MINUS :
13409  case SCIP_EXPR_MUL :
13410  case SCIP_EXPR_DIV :
13411  case SCIP_EXPR_MIN :
13412  case SCIP_EXPR_MAX :
13413  case SCIP_EXPR_SQUARE :
13414  case SCIP_EXPR_SQRT :
13415  case SCIP_EXPR_EXP :
13416  case SCIP_EXPR_LOG :
13417  case SCIP_EXPR_SIN :
13418  case SCIP_EXPR_COS :
13419  case SCIP_EXPR_TAN :
13420  /* case SCIP_EXPR_ERF : */
13421  /* case SCIP_EXPR_ERFI: */
13422  case SCIP_EXPR_ABS :
13423  case SCIP_EXPR_SIGN :
13424  case SCIP_EXPR_SUM :
13425  case SCIP_EXPR_PRODUCT:
13426  opdata.data = NULL;
13427  break;
13428 
13429  case SCIP_EXPR_REALPOWER:
13430  case SCIP_EXPR_SIGNPOWER:
13431  {
13432  va_start(ap, op ); /*lint !e838*/
13433  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
13434  va_end( ap ); /*lint !e826*/
13435 
13436  break;
13437  }
13438 
13439  case SCIP_EXPR_INTPOWER:
13440  {
13441  va_start(ap, op ); /*lint !e838*/
13442  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
13443  va_end( ap ); /*lint !e826*/
13444 
13445  break;
13446  }
13447 
13448  case SCIP_EXPR_LAST:
13449  SCIPABORT();
13450  return SCIP_INVALIDDATA; /*lint !e527*/
13451  }
13452 
13453  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13454 
13455  return SCIP_OKAY;
13456 }
13457 
13458 /** creates an expression graph node for a linear expression */
13460  BMS_BLKMEM* blkmem, /**< block memory */
13461  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13462  int ncoefs, /**< number of coefficients */
13463  SCIP_Real* coefs, /**< coefficients of linear expression */
13464  SCIP_Real constant /**< constant of linear expression */
13465  )
13466 {
13467  SCIP_EXPROPDATA opdata;
13468  SCIP_Real* data;
13469 
13470  assert(blkmem != NULL);
13471  assert(node != NULL);
13472 
13473  /* we store the coefficients and the constant in a single array and make this our operand data */
13474  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13475  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
13476  data[ncoefs] = constant;
13477 
13478  opdata.data = data;
13479  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13480 
13481  return SCIP_OKAY;
13482 }
13483 
13484 /** creates an expression graph node for a quadratic expression */
13486  BMS_BLKMEM* blkmem, /**< block memory */
13487  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13488  int nchildren, /**< number of children */
13489  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
13490  int nquadelems, /**< number of quadratic elements */
13491  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
13492  SCIP_Real constant /**< constant */
13493  )
13494 {
13495  SCIP_EXPROPDATA opdata;
13497 
13498  assert(blkmem != NULL);
13499  assert(node != NULL);
13500  assert(quadelems != NULL || nquadelems == 0);
13501 
13502  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13503 
13504  opdata.data = data;
13505  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13506 
13507  return SCIP_OKAY;
13508 }
13509 
13510 /** creates an expression graph node for a polynomial expression */
13512  BMS_BLKMEM* blkmem, /**< block memory */
13513  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13514  int nmonomials, /**< number of monomials */
13515  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13516  SCIP_Real constant, /**< constant of polynomial */
13517  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13518  )
13519 {
13520  SCIP_EXPROPDATA opdata;
13522 
13523  assert(blkmem != NULL);
13524  assert(node != NULL);
13525  assert(monomials != NULL || nmonomials == 0);
13526 
13527  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13528 
13529  opdata.data = data;
13530  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13531 
13532  return SCIP_OKAY;
13533 }
13534 
13535 /** adds monomials to an expression graph node that is a polynomial expression */
13537  BMS_BLKMEM* blkmem, /**< block memory */
13538  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
13539  int nmonomials, /**< number of monomials */
13540  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13541  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13542  )
13543 {
13544  assert(blkmem != NULL);
13545  assert(node != NULL);
13547  assert(monomials != NULL || nmonomials == 0);
13548 
13549  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13550 
13551  return SCIP_OKAY;
13552 }
13553 
13554 /** creates an expression graph node for a user expression */
13556  BMS_BLKMEM* blkmem, /**< block memory */
13557  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13558  SCIP_USEREXPRDATA* data, /**< user data for expression, node assumes ownership */
13559  SCIP_EXPRINTCAPABILITY evalcapability, /**< evaluation capability */
13560  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
13561  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function */
13562  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
13563  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function */
13564  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13565  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13566  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
13567  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
13568  )
13569 {
13570  SCIP_EXPROPDATA opdata;
13571  SCIP_EXPRDATA_USER* exprdata;
13572 
13573  assert(blkmem != NULL);
13574  assert(node != NULL);
13575  assert(eval != NULL);
13576  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
13577  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13578  assert(copydata != NULL || data == NULL);
13579  assert(freedata != NULL || data == NULL);
13580 
13581  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13582 
13583  exprdata->userdata = data;
13584  exprdata->evalcapability = evalcapability;
13585  exprdata->eval = eval;
13586  exprdata->estimate = estimate;
13587  exprdata->inteval = inteval;
13588  exprdata->curv = curv;
13589  exprdata->prop = prop;
13590  exprdata->copydata = copydata;
13591  exprdata->freedata = freedata;
13592  exprdata->print = print;
13593 
13594  opdata.data = (void*) exprdata;
13595 
13596  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13597 
13598  return SCIP_OKAY;
13599 }
13600 
13601 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13602  *
13603  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13604  * If the node is a linear expression, it may be freed.
13605  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13606  * It is assumed that the user had captured the node.
13607  * It is assumed that the expression graph has been simplified before.
13608  */
13610  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13611  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
13612  int linvarssize, /**< length of linvars and lincoefs arrays */
13613  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
13614  void** linvars, /**< buffer to store variables of linear part */
13615  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
13616  SCIP_Real* constant /**< buffer to store constant part */
13617  )
13618 {
13619  int orignvars;
13620  int* varsusage;
13621  SCIP_EXPRGRAPHNODE* orignode;
13622  SCIP_Bool havechange;
13623  int i;
13624 
13625  assert(exprgraph != NULL);
13626  assert(node != NULL);
13627  assert(*node != NULL);
13628  assert((*node)->nuses > 0);
13629  assert(nlinvars != NULL);
13630  assert(linvars != NULL || linvarssize == 0);
13631  assert(lincoefs != NULL || linvarssize == 0);
13632  assert(constant != NULL);
13633 
13634  *constant = 0.0;
13635  *nlinvars = 0;
13636 
13637  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13638 
13639  /* do some obvious and easy cases */
13640  switch( (*node)->op )
13641  {
13642  case SCIP_EXPR_VARIDX:
13643  {
13644  if( linvarssize >= 1 )
13645  {
13646  *nlinvars = 1;
13647  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
13648  lincoefs[0] = 1.0; /*lint !e613*/
13649 
13650  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13651  }
13652  return SCIP_OKAY;
13653  }
13654 
13655  case SCIP_EXPR_CONST:
13656  {
13657  *constant = (*node)->data.dbl;
13658  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13659 
13660  return SCIP_OKAY;
13661  }
13662 
13663  case SCIP_EXPR_REALPOWER:
13664  case SCIP_EXPR_SIGNPOWER:
13665  {
13666  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13667  {
13668  *nlinvars = 1;
13669  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13670  lincoefs[0] = 1.0; /*lint !e613*/
13671 
13672  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13673  }
13674  return SCIP_OKAY;
13675  }
13676 
13677  case SCIP_EXPR_INTPOWER:
13678  {
13679  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13680  {
13681  *nlinvars = 1;
13682  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13683  lincoefs[0] = 1.0; /*lint !e613*/
13684 
13685  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13686  }
13687  return SCIP_OKAY;
13688  }
13689 
13690  case SCIP_EXPR_PLUS:
13691  {
13692  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13693  {
13694  *constant = (*node)->children[0]->data.dbl;
13695  *nlinvars = 1;
13696  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13697  lincoefs[0] = 1.0; /*lint !e613*/
13698 
13699  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13700 
13701  return SCIP_OKAY;
13702  }
13703  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13704  {
13705  *constant = (*node)->children[1]->data.dbl;
13706  *nlinvars = 1;
13707  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13708  lincoefs[0] = 1.0; /*lint !e613*/
13709 
13710  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13711 
13712  return SCIP_OKAY;
13713  }
13714  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13715  {
13716  *nlinvars = 2;
13717  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13718  lincoefs[0] = 1.0; /*lint !e613*/
13719  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13720  lincoefs[1] = 1.0; /*lint !e613*/
13721 
13722  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13723 
13724  return SCIP_OKAY;
13725  }
13726  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13727  {
13728  /* handle this one later */
13729  break;
13730  }
13731  return SCIP_OKAY;
13732  }
13733 
13734  case SCIP_EXPR_MINUS:
13735  {
13736  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13737  {
13738  *constant = (*node)->children[0]->data.dbl;
13739  *nlinvars = 1;
13740  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13741  lincoefs[0] = -1.0; /*lint !e613*/
13742 
13743  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13744 
13745  return SCIP_OKAY;
13746  }
13747  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13748  {
13749  *constant = -(*node)->children[1]->data.dbl;
13750  *nlinvars = 1;
13751  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13752  lincoefs[0] = 1.0; /*lint !e613*/
13753 
13754  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13755 
13756  return SCIP_OKAY;
13757  }
13758  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13759  {
13760  *nlinvars = 2;
13761  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13762  lincoefs[0] = 1.0; /*lint !e613*/
13763  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13764  lincoefs[1] = -1.0; /*lint !e613*/
13765 
13766  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13767 
13768  return SCIP_OKAY;
13769  }
13770  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13771  {
13772  /* handle this one later */
13773  break;
13774  }
13775  return SCIP_OKAY;
13776  }
13777 
13778  case SCIP_EXPR_MUL:
13779  {
13780  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13781  {
13782  *nlinvars = 1;
13783  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13784  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
13785 
13786  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13787  }
13788  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13789  {
13790  *nlinvars = 1;
13791  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13792  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
13793 
13794  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13795  }
13796  return SCIP_OKAY;
13797  }
13798 
13799  case SCIP_EXPR_DIV:
13800  {
13801  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13802  return SCIP_OKAY;
13803 
13804  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13805  {
13806  *nlinvars = 1;
13807  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13808  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
13809 
13810  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13811  }
13812  return SCIP_OKAY;
13813  }
13814 
13815  case SCIP_EXPR_SQUARE:
13816  case SCIP_EXPR_SQRT:
13817  case SCIP_EXPR_EXP:
13818  case SCIP_EXPR_LOG:
13819  case SCIP_EXPR_SIN:
13820  case SCIP_EXPR_COS:
13821  case SCIP_EXPR_TAN:
13822  /* case SCIP_EXPR_ERF: */
13823  /* case SCIP_EXPR_ERFI: */
13824  case SCIP_EXPR_ABS:
13825  case SCIP_EXPR_SIGN:
13826  case SCIP_EXPR_MIN:
13827  case SCIP_EXPR_MAX:
13828  return SCIP_OKAY;
13829 
13830  case SCIP_EXPR_PRODUCT:
13831  case SCIP_EXPR_USER:
13832  return SCIP_OKAY;
13833 
13834  case SCIP_EXPR_SUM:
13835  case SCIP_EXPR_LINEAR:
13836  case SCIP_EXPR_QUADRATIC:
13837  case SCIP_EXPR_POLYNOMIAL:
13838  default:
13839  {
13840  /* check if there is a child that is a variable */
13841  for( i = 0; i < (*node)->nchildren; ++i )
13842  {
13843  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13844  break;
13845  }
13846 
13847  if( i == (*node)->nchildren )
13848  return SCIP_OKAY;
13849 
13850  break;
13851  }
13852  } /*lint !e788*/
13853 
13854  /* count how often variables are used in this expression */
13855  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13856  orignvars = exprgraph->nvars;
13857  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13858  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
13859 
13860  exprgraphNodeGetVarsUsage(*node, varsusage);
13861 
13862  /* duplicate node if it has parents or more than one user */
13863  orignode = NULL;
13864  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13865  {
13866  SCIP_EXPROPDATA data;
13867 
13868  orignode = *node;
13869 
13870  if( exprOpTable[orignode->op].copydata != NULL )
13871  {
13872  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13873  }
13874  else
13875  data = orignode->data;
13876 
13877  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13878  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13879  SCIPexprgraphCaptureNode(*node);
13880  }
13881 
13882  havechange = FALSE;
13883  /* split up constant and linear part */
13884  switch( (*node)->op )
13885  {
13886  case SCIP_EXPR_PLUS:
13887  case SCIP_EXPR_MINUS:
13888  {
13889  SCIP_EXPRGRAPHNODE* varchild;
13890  SCIP_EXPRGRAPHNODE* otherchild;
13891  int varidx;
13892 
13893  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13894  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13895  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13896  assert(linvarssize >= 1);
13897 
13898  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13899  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13900  varidx = varchild->data.intval;
13901  /* if variable is used in other child (which should be nonlinear), we don't take it */
13902  if( varsusage[varidx] > 1 )
13903  break;
13904 
13905  /* add to linear variables */
13906  *nlinvars = 1;
13907  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13908  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13909  lincoefs[0] = -1.0; /*lint !e613*/
13910  else
13911  lincoefs[0] = 1.0; /*lint !e613*/
13912 
13913  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13914  {
13915  /* replace *node by otherchild */
13916  SCIPexprgraphCaptureNode(otherchild);
13917  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13918  *node = otherchild;
13919  }
13920  else
13921  {
13922  SCIP_Real* lindata;
13923 
13924  /* turn *node into linear expression -1.0 * otherchild */
13925 
13926  /* reduce to one child */
13927  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13928  (*node)->children[0] = otherchild;
13929  (*node)->nchildren = 1;
13930  (*node)->op = SCIP_EXPR_LINEAR;
13931 
13932  /* setup linear data -1.0 * child0 + 0.0 */
13933  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13934  lindata[0] = -1.0;
13935  lindata[1] = 0.0;
13936  (*node)->data.data = (void*)lindata;
13937 
13938  /* remove *node as parent of varchild */
13939  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13940  }
13941 
13942  havechange = TRUE;
13943 
13944  break;
13945  }
13946 
13947  case SCIP_EXPR_SUM:
13948  {
13949  int nchildren;
13950 
13951  i = 0;
13952  nchildren = (*node)->nchildren;
13953  while( i < nchildren )
13954  {
13955  /* sort out constants */
13956  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13957  {
13958  *constant += (*node)->children[i]->data.dbl;
13959  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13960 
13961  if( i < nchildren-1 )
13962  {
13963  (*node)->children[i] = (*node)->children[nchildren-1];
13964  (*node)->children[nchildren-1] = NULL;
13965  }
13966  --nchildren;
13967 
13968  continue;
13969  }
13970 
13971  /* keep every child that is not a constant or variable */
13972  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13973  {
13974  ++i;
13975  continue;
13976  }
13977 
13978  /* skip variables that are used in other parts of the expression */
13979  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13980  {
13981  ++i;
13982  continue;
13983  }
13984 
13985  /* move variable into linear part, if still space */
13986  if( *nlinvars < linvarssize )
13987  {
13988  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13989  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13990  ++*nlinvars;
13991 
13992  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13993  if( i < nchildren-1 )
13994  {
13995  (*node)->children[i] = (*node)->children[nchildren-1];
13996  (*node)->children[nchildren-1] = NULL;
13997  }
13998  --nchildren;
13999 
14000  continue;
14001  }
14002  }
14003  assert(i == nchildren);
14004 
14005  if( nchildren == 0 )
14006  {
14007  /* all children were removed */
14008  havechange = TRUE;
14009  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14010  (*node)->nchildren = 0;
14011  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14012  break;
14013  }
14014 
14015  if( nchildren < (*node)->nchildren )
14016  {
14017  /* some children were removed */
14018  havechange = TRUE;
14019  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14020  (*node)->nchildren = nchildren;
14021  }
14022 
14023  if( havechange && (*node)->nchildren == 1 )
14024  {
14025  /* replace node by its child */
14026  SCIP_EXPRGRAPHNODE* child;
14027 
14028  child = (*node)->children[0];
14029  SCIPexprgraphCaptureNode(child);
14030  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14031  *node = child;
14032 
14033  break;
14034  }
14035 
14036  break;
14037  }
14038 
14039  case SCIP_EXPR_LINEAR:
14040  {
14041  int nchildren;
14042  SCIP_Real* coefs;
14043 
14044  coefs = (SCIP_Real*)(*node)->data.data;
14045  assert(coefs != NULL);
14046 
14047  /* remove constant, if nonzero */
14048  if( coefs[(*node)->nchildren] != 0.0 )
14049  {
14050  *constant = coefs[(*node)->nchildren];
14051  coefs[(*node)->nchildren] = 0.0;
14052  havechange = TRUE;
14053  }
14054 
14055  i = 0;
14056  nchildren = (*node)->nchildren;
14057  while( i < nchildren )
14058  {
14059  /* sort out constants */
14060  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
14061  {
14062  *constant += coefs[i] * (*node)->children[i]->data.dbl;
14063  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14064 
14065  if( i < nchildren-1 )
14066  {
14067  (*node)->children[i] = (*node)->children[nchildren-1];
14068  (*node)->children[nchildren-1] = NULL;
14069  coefs[i] = coefs[nchildren-1];
14070  coefs[nchildren-1] = 0.0;
14071  }
14072  --nchildren;
14073 
14074  continue;
14075  }
14076 
14077  /* keep everything that is not a constant or variable */
14078  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14079  {
14080  ++i;
14081  continue;
14082  }
14083 
14084  /* skip variables that are used in other parts of the expression */
14085  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14086  {
14087  ++i;
14088  continue;
14089  }
14090 
14091  /* move variable into linear part, if still space */
14092  if( *nlinvars < linvarssize )
14093  {
14094  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14095  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
14096  ++*nlinvars;
14097 
14098  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14099  if( i < nchildren-1 )
14100  {
14101  (*node)->children[i] = (*node)->children[nchildren-1];
14102  (*node)->children[nchildren-1] = NULL;
14103  coefs[i] = coefs[nchildren-1];
14104  coefs[nchildren-1] = 0.0;
14105  }
14106  --nchildren;
14107 
14108  continue;
14109  }
14110  }
14111  assert(i == nchildren);
14112 
14113  if( nchildren == 0 )
14114  {
14115  /* all children were removed */
14116  havechange = TRUE;
14117  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14118  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
14119  (*node)->data.data = NULL;
14120  (*node)->nchildren = 0;
14121  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
14122  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14123  break;
14124  }
14125 
14126  if( nchildren < (*node)->nchildren )
14127  {
14128  /* some children were removed */
14129  havechange = TRUE;
14130  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14131  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
14132  coefs[nchildren] = 0.0;
14133  (*node)->data.data = (void*)coefs;
14134  (*node)->nchildren = nchildren;
14135  }
14136 
14137  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
14138  {
14139  /* replace node by its child */
14140  SCIP_EXPRGRAPHNODE* child;
14141 
14142  child = (*node)->children[0];
14143  SCIPexprgraphCaptureNode(child);
14144  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14145  *node = child;
14146 
14147  break;
14148  }
14149 
14150  break;
14151  }
14152 
14153  case SCIP_EXPR_QUADRATIC:
14154  {
14155  SCIP_EXPRDATA_QUADRATIC* quaddata;
14156  SCIP_Bool* childused;
14157  int* childmap;
14158  int nchildren;
14159 
14160  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
14161  assert(quaddata != NULL);
14162 
14163  /* remove constant, if nonzero */
14164  if( quaddata->constant != 0.0 )
14165  {
14166  *constant = quaddata->constant;
14167  quaddata->constant = 0.0;
14168  havechange = TRUE;
14169  }
14170 
14171  /* if there is no linear part or no space left for linear variables, then stop */
14172  if( quaddata->lincoefs == NULL || linvarssize == 0 )
14173  break;
14174 
14175  /* check which childs are used in quadratic terms */
14176  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14177  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14178 
14179  for( i = 0; i < quaddata->nquadelems; ++i )
14180  {
14181  childused[quaddata->quadelems[i].idx1] = TRUE;
14182  childused[quaddata->quadelems[i].idx2] = TRUE;
14183  }
14184 
14185  /* alloc space for mapping of children indices */
14186  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
14187 
14188  nchildren = (*node)->nchildren;
14189  for( i = 0; i < nchildren; ++i )
14190  {
14191  childmap[i] = i; /*lint !e644*/
14192  if( *nlinvars >= linvarssize )
14193  continue;
14194  /* skip child if not variable or also used in quadratic part or other parts of expression */
14195  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14196  continue;
14197  if( childused[i] )
14198  continue;
14199  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14200  continue;
14201 
14202  /* put variable into linear part */
14203  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14204  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
14205  quaddata->lincoefs[i] = 0.0;
14206  ++*nlinvars;
14207 
14208  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14209 
14210  /* move last child to position i */
14211  if( i < nchildren-1 )
14212  {
14213  (*node)->children[i] = (*node)->children[nchildren-1];
14214  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
14215  childused[i] = childused[nchildren-1];
14216  childmap[nchildren-1] = i;
14217  }
14218  --nchildren;
14219  childmap[i] = -1;
14220 
14221  havechange = TRUE;
14222  --i; /* look at i again */
14223  }
14224 
14225  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
14226 
14227  if( nchildren < (*node)->nchildren )
14228  {
14229  /* apply childmap to quadratic term */
14230  for( i = 0; i < quaddata->nquadelems; ++i )
14231  {
14232  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
14233  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
14234  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
14235  {
14236  int tmp;
14237  tmp = quaddata->quadelems[i].idx1;
14238  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
14239  quaddata->quadelems[i].idx2 = tmp;
14240  }
14241  }
14242  quaddata->sorted = FALSE;
14243  }
14244  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
14245 
14246  if( nchildren == 0 )
14247  {
14248  /* all children were removed (so it was actually a linear expression) */
14249  havechange = TRUE;
14250  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14251  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
14252  (*node)->data.data = NULL;
14253  (*node)->nchildren = 0;
14254  (*node)->op = SCIP_EXPR_SUM;
14255  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14256  break;
14257  }
14258 
14259  if( nchildren < (*node)->nchildren )
14260  {
14261  /* reduce number of children */
14262  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14263  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
14264  (*node)->nchildren = nchildren;
14265  }
14266 
14267  break;
14268  }
14269 
14270  case SCIP_EXPR_POLYNOMIAL:
14271  {
14272  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
14273  SCIP_EXPRDATA_MONOMIAL* monomial;
14274  SCIP_Bool* childused;
14275  int childidx;
14276  int j;
14277 
14278  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
14279  assert(polynomialdata != NULL);
14280 
14281  /* make sure linear monomials are merged */
14282  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14283 
14284  /* remove constant, if nonzero */
14285  if( polynomialdata->constant != 0.0 )
14286  {
14287  *constant = polynomialdata->constant;
14288  polynomialdata->constant = 0.0;
14289  havechange = TRUE;
14290  }
14291 
14292  /* if there is no space for linear variables, then stop */
14293  if( linvarssize == 0 )
14294  break;
14295 
14296  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14297  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14298  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14299  for( i = 0; i < polynomialdata->nmonomials; ++i )
14300  {
14301  monomial = polynomialdata->monomials[i];
14302  assert(monomial != NULL);
14303  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14304  continue;
14305  for( j = 0; j < monomial->nfactors; ++j )
14306  {
14307  assert(monomial->childidxs[j] >= 0);
14308  assert(monomial->childidxs[j] < (*node)->nchildren);
14309  childused[monomial->childidxs[j]] = TRUE;
14310  }
14311  }
14312 
14313  /* move linear monomials out of polynomial */
14314  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14315  {
14316  monomial = polynomialdata->monomials[i];
14317  assert(monomial != NULL);
14318 
14319  /* sort out constants */
14320  if( monomial->nfactors == 0 )
14321  {
14322  if( monomial->coef != 0.0 )
14323  {
14324  *constant += monomial->coef;
14325  havechange = TRUE;
14326  }
14327  continue;
14328  }
14329 
14330  if( monomial->nfactors != 1 )
14331  continue;
14332  if( monomial->exponents[0] != 1.0 )
14333  continue;
14334  childidx = monomial->childidxs[0];
14335  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14336  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14337  continue;
14338  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14339  continue;
14340 
14341  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14342 
14343  /* put variable into linear part */
14344  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
14345  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
14346  ++*nlinvars;
14347 
14348  monomial->coef = 0.0;
14349  monomial->nfactors = 0;
14350  polynomialdata->sorted = FALSE;
14351 
14352  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14353  (*node)->children[childidx] = NULL;
14354 
14355  havechange = TRUE;
14356  }
14357 
14358  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14359 
14360  if( *nlinvars > 0 )
14361  {
14362  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14363  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14365  }
14366 
14367  if( (*node)->nchildren == 0 )
14368  {
14369  assert(polynomialdata->nmonomials == 0);
14370  assert(polynomialdata->constant == 0.0);
14371  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14372  havechange = TRUE;
14373  break;
14374  }
14375 
14376  break;
14377  }
14378 
14379  default: ;
14380  } /*lint !e788*/
14381 
14382  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14383 
14384  if( orignode != NULL )
14385  {
14386  /* if node was duplicated, we need to forget about original or duplicate */
14387  if( !havechange )
14388  {
14389  /* if nothing has changed, then forget about duplicate */
14390  assert(*constant == 0.0);
14391  assert(*nlinvars == 0);
14392  assert(*node != NULL);
14393  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14394  *node = orignode;
14395  }
14396  else
14397  {
14398  /* if something changed, then release original node */
14399  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14400  }
14401  }
14402  else if( havechange && *node != NULL )
14403  {
14404  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14405  (*node)->value = SCIP_INVALID;
14406  (*node)->simplified = FALSE;
14407  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14408  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14409  exprgraph->needvarboundprop = TRUE;
14410  }
14411 
14412  return SCIP_OKAY;
14413 }
14414 
14415 /** moves parents from a one node to another node
14416  *
14417  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14418  * srcnode may be freed, if not captured.
14419  * It is assumed that targetnode represents the same expression as srcnode.
14420  */
14422  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14423  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
14424  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
14425  )
14426 {
14427  assert(exprgraph != NULL);
14428  assert(srcnode != NULL);
14429  assert(*srcnode != NULL);
14430  assert(targetnode != NULL);
14431 
14432  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14433  {
14434  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14435  {
14436  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14437  }
14438  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14439  }
14440  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14441 
14442  return SCIP_OKAY;
14443 }
14444 
14445 /** releases node, i.e., decreases number of uses
14446  *
14447  * node is freed if no parents and no other uses.
14448  * Children are recursively released if they have no other parents.
14449  * Nodes that are removed are also freed.
14450  * If node correspond to a variable, then the variable is removed from the expression graph;
14451  * similarly for constants.
14452  */
14454  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14455  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
14456  )
14457 {
14458  int i;
14459 
14460  assert(exprgraph != NULL);
14461  assert(node != NULL);
14462  assert(*node != NULL);
14463  assert((*node)->depth >= 0); /* node should be in graph */
14464  assert((*node)->pos >= 0); /* node should be in graph */
14465  assert((*node)->depth < exprgraph->depth);
14466  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14467  assert((*node)->nuses >= 1);
14468  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14469 
14470  SCIPdebugMessage("release node %p\n", (void*)*node);
14471 
14472  --(*node)->nuses;
14473 
14474  /* do nothing if node still has parents or is still in use */
14475  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14476  {
14477  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);
14478  *node = NULL;
14479  return SCIP_OKAY;
14480  }
14481 
14482  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14483 
14484  /* notify children about removal of its parent
14485  * they are also freed, if possible */
14486  for( i = 0; i < (*node)->nchildren; ++i )
14487  {
14488  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14489  (*node)->children[i] = NULL;
14490  }
14491 
14492  if( (*node)->op == SCIP_EXPR_VARIDX )
14493  {
14494  assert((*node)->depth == 0);
14495  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14496  }
14497  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14498  {
14499  int constidx;
14500 
14501  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14502  assert(constidx >= 0);
14503  assert(constidx < exprgraph->nconsts);
14504  assert(exprgraph->constnodes[constidx] == *node);
14505 
14506  /* move last constant to position constidx */
14507  if( constidx < exprgraph->nconsts-1 )
14508  {
14509  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14510  exprgraph->constssorted = (exprgraph->nconsts <= 2);
14511  }
14512  --exprgraph->nconsts;
14513  }
14514  else
14515  {
14516  /* only variables and constants are allowed at depth 0 */
14517  assert((*node)->depth > 0);
14518  }
14519 
14520  /* remove node from nodes array in expression graph */
14521  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14522  {
14523  /* move last node at depth of *node to position of *node */
14524  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14525  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14526 
14527  /* moving the node may change the order in the parents array of each child */
14528  for( i = 0; i < exprgraph->nodes[(*node)->depth][(*node)->pos]->nchildren; ++i )
14529  exprgraph->nodes[(*node)->depth][(*node)->pos]->children[i]->parentssorted = FALSE;
14530  }
14531  --exprgraph->nnodes[(*node)->depth];
14532 
14533  /* node is now not in graph anymore */
14534  (*node)->depth = -1;
14535  (*node)->pos = -1;
14536 
14537  /* free node */
14538  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14539 
14540  *node = NULL;
14541 
14542  return SCIP_OKAY;
14543 }
14544 
14545 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14546 /** frees a node of an expression graph */
14548  BMS_BLKMEM* blkmem, /**< block memory */
14549  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
14550  )
14551 {
14552  assert(blkmem != NULL);
14553  assert( node != NULL);
14554  assert(*node != NULL);
14555  assert((*node)->depth == -1); /* node should not be in graph anymore */
14556  assert((*node)->pos == -1); /* node should not be in graph anymore */
14557  assert((*node)->nuses == 0); /* node should not be in use */
14558 
14559  /* free operator data, if needed */
14560  if( exprOpTable[(*node)->op].freedata != NULL )
14561  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14562 
14563  /* free arrays of children and parent nodes */
14564  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14565  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
14566 
14567  /* free node struct */
14568  BMSfreeBlockMemory(blkmem, node);
14569 }
14570 
14571 /** enables a node and recursively all its children in an expression graph */
14573  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14574  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14575  )
14576 {
14577  int i;
14578 
14579  assert(exprgraph != NULL);
14580  assert(node != NULL);
14581  assert(node->depth >= 0);
14582  assert(node->pos >= 0);
14583 
14584  if( node->enabled )
14585  return;
14586 
14587  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14588 
14589  node->enabled = TRUE;
14590  for( i = 0; i < node->nchildren; ++i )
14591  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14592 
14593  /* make sure bounds are updated in next bound propagation round */
14594  SCIPintervalSetEntire(SCIP_REAL_MAX, &node->bounds);
14595  exprgraph->needvarboundprop = TRUE;
14596 }
14597 
14598 /** disables a node and recursively all children which have no enabled parents in an expression graph */
14600  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14601  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14602  )
14603 {
14604  int i;
14605 
14606  assert(exprgraph != NULL);
14607  assert(node != NULL);
14608  assert(node->depth >= 0);
14609  assert(node->pos >= 0);
14610 
14611  if( !node->enabled )
14612  return;
14613 
14614  /* workaround: don't disable nodes if there could be more users than the one who is disabling the node
14615  * otherwise, if there are several nonlinear constraints using the same expression graph node as root node,
14616  * we might get enabled constraints with disabled node
14617  */
14618  if( node->nuses > 1 )
14619  return;
14620 
14621  /* if all parents of node are disabled, then also node can be disabled */
14622  node->enabled = FALSE;
14623  for( i = 0; i < node->nparents; ++i )
14624  if( node->parents[i]->enabled )
14625  {
14626  node->enabled = TRUE;
14627  return;
14628  }
14629 
14630  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14631 
14632  for( i = 0; i < node->nchildren; ++i )
14633  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14634 }
14635 
14636 /** returns whether the node has siblings in the expression graph */
14638  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14639  )
14640 {
14641  int p;
14642 
14643  assert(node != NULL);
14644 
14645  for( p = 0; p < node->nparents; ++p )
14646  if( node->parents[p]->nchildren > 1 )
14647  return TRUE;
14648 
14649  return FALSE;
14650 }
14651 
14652 /** returns whether all children of an expression graph node are variable nodes
14653  *
14654  * Returns TRUE for nodes without children.
14655  */
14657  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14658  )
14659 {
14660  int i;
14661 
14662  assert(node != NULL);
14663 
14664  for( i = 0; i < node->nchildren; ++i )
14665  if( node->children[i]->op != SCIP_EXPR_VARIDX )
14666  return FALSE;
14667 
14668  return TRUE;
14669 }
14670 
14671 /** returns whether the node has an ancestor which has a nonlinear expression operand */
14673  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14674  )
14675 {
14676  int p;
14677 
14678  for( p = 0; p < node->nparents; ++p )
14679  {
14680  assert(node->parents[p]->depth > node->depth);
14681  switch( node->parents[p]->op )
14682  {
14683  case SCIP_EXPR_PLUS:
14684  case SCIP_EXPR_MINUS:
14685  case SCIP_EXPR_SUM:
14686  case SCIP_EXPR_LINEAR:
14688  return TRUE;
14689  break;
14690 
14691 #ifndef NDEBUG
14692  case SCIP_EXPR_VARIDX:
14693  case SCIP_EXPR_CONST:
14694  case SCIP_EXPR_PARAM:
14695  assert(0); /* these expressions cannot have children */
14696  break;
14697 #endif
14698 
14699  default:
14700  /* parent has nonlinear expression operand */
14701  return TRUE;
14702  }/*lint !e788*/
14703  }
14704 
14705  return FALSE;
14706 }
14707 
14708 /** prints an expression graph node */
14710  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14711  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14712  FILE* file /**< file to print to, or NULL for stdout */
14713  )
14714 {
14715  assert(node != NULL);
14716 
14717  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14718 }
14719 
14720 /** tightens the bounds in a node of the graph
14721  *
14722  * Preparation for reverse propagation.
14723  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14724  */
14726  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14727  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
14728  SCIP_INTERVAL nodebounds, /**< new bounds for node */
14729  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) */
14730  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14731  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14732  )
14733 {
14734  assert(exprgraph != NULL);
14735  assert(node != NULL);
14736  assert(node->depth >= 0);
14737  assert(node->pos >= 0);
14738  assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14739  assert(cutoff != NULL);
14740 
14741  *cutoff = FALSE;
14742 
14743  /* if node is disabled, then ignore new bounds */
14744  if( !node->enabled )
14745  {
14746  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14747  return;
14748  }
14749 
14750  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14751  (void*)node, node->depth, node->pos,
14752  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14753 
14754  /* bounds in node should be valid */
14755  assert(!(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
14756 
14757  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14758  {
14759  *cutoff = TRUE;
14760  SCIPdebugPrintf(" -> cutoff\n");
14761  return;
14762  }
14763 
14764  /* if minstrength is negative, always mark that node has recently tightened bounds,
14765  * if bounds are considerably improved or tightening leads to an empty interval,
14766  * mark that node has recently tightened bounds
14767  * if bounds are only slightly improved, set the status to tightened by parent,
14768  * so next propagateVarBound round will reset the bounds
14769  */
14770  if( minstrength < 0.0 )
14771  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE;
14772  else if(
14773  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14774  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14775  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT;
14776  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14777  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT;
14778 
14779  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14780  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14781 }
14782 
14783 /** ensures that bounds and curvature information in a node is uptodate
14784  *
14785  * Assumes that bounds and curvature in children are uptodate.
14786  */
14788  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14789  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14790  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14791  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14792  )
14793 {
14794  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14795  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14796  SCIP_INTERVAL* childbounds = NULL;
14797  SCIP_EXPRCURV* childcurv = NULL;
14798  SCIP_RETCODE retcode = SCIP_OKAY;
14799  int i;
14800 
14801  assert(node != NULL);
14802  assert(node->depth >= 0); /* node should be in graph */
14803  assert(node->pos >= 0); /* node should be in graph */
14804  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14805 
14806  if( node->depth == 0 )
14807  {
14808  /* we cannot update bound tightenings in variable nodes here */
14809  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14810  return SCIP_OKAY;
14811  }
14812 
14813  assert(node->op != SCIP_EXPR_VARIDX);
14814  assert(node->op != SCIP_EXPR_PARAM);
14815 
14816  /* if many children, get large enough memory to store children bounds */
14818  {
14819  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14820  SCIP_ALLOC_TERMINATE(retcode, BMSallocMemoryArray(&childcurv, node->nchildren), TERMINATE);
14821  }
14822  else
14823  {
14824  childbounds = childboundsstatic;
14825  childcurv = childcurvstatic;
14826  }
14827 
14828  /* assemble bounds and curvature of children */
14829  for( i = 0; i < node->nchildren; ++i )
14830  {
14831  /* child should have valid and non-empty bounds */
14833  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14834  /* nodes at depth 0 are always linear */
14835  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14836 
14837  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
14838  childcurv[i] = node->children[i]->curv; /*lint !e644*/
14839  }
14840 
14841  /* if we do not have valid bounds, then update
14842  * code below is copied from exprgraphNodeUpdateBounds */
14844  {
14845  SCIP_INTERVAL newbounds;
14846 
14847  /* calling interval evaluation function for this operand */
14848  assert( exprOpTable[node->op].inteval != NULL );
14849  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds), TERMINATE );
14850 
14851  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14852  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14853  *
14854  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14855  *
14856  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14857  */
14858  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14860  {
14861  for( i = 0; i < node->nparents; ++i )
14863 
14864  node->bounds = newbounds;
14865  }
14866  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14867  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14868  {
14869  for( i = 0; i < node->nparents; ++i )
14871 
14872  node->bounds = newbounds;
14873  }
14874  else
14875  {
14876  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14877  }
14878 
14879  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);
14880 
14881  /* node now has valid bounds */
14882  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
14883  }
14884 
14885  /* update curvature */
14886  if( SCIPintervalIsEmpty(infinity, node->bounds) )
14887  {
14888  node->curv = SCIP_EXPRCURV_LINEAR;
14889 
14890  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14891  }
14892  else
14893  {
14894  SCIP_CALL_TERMINATE( retcode, exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv), TERMINATE );
14895 
14896  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14897  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14898  * SCIPdebugPrintf("\n");
14899  */
14900  }
14901 TERMINATE:
14902  /* free memory, if allocated before */
14903  if( childbounds != childboundsstatic )
14904  {
14905  BMSfreeMemoryArrayNull(&childbounds);
14906  BMSfreeMemoryArrayNull(&childcurv);
14907  }
14908 
14909  return retcode;
14910 }
14911 
14912 /**@} */
14913 
14914 /**@name Expression graph methods */
14915 /**@{ */
14916 
14917 /* In debug mode, the following methods are implemented as function calls to ensure
14918  * type validity.
14919  * In optimized mode, the methods are implemented as defines to improve performance.
14920  * However, we want to have them in the library anyways, so we have to undef the defines.
14921  */
14922 
14923 #undef SCIPexprgraphGetDepth
14924 #undef SCIPexprgraphGetNNodes
14925 #undef SCIPexprgraphGetNodes
14926 #undef SCIPexprgraphGetNVars
14927 #undef SCIPexprgraphGetVars
14928 #undef SCIPexprgraphGetVarNodes
14929 #undef SCIPexprgraphSetVarNodeValue
14930 #undef SCIPexprgraphSetVarsBounds
14931 #undef SCIPexprgraphSetVarBounds
14932 #undef SCIPexprgraphSetVarNodeBounds
14933 #undef SCIPexprgraphSetVarNodeLb
14934 #undef SCIPexprgraphSetVarNodeUb
14935 #undef SCIPexprgraphGetVarsBounds
14936 
14937 /** get current maximal depth of expression graph */
14939  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14940  )
14941 {
14942  assert(exprgraph != NULL);
14943 
14944  return exprgraph->depth;
14945 }
14946 
14947 /** gets array with number of nodes at each depth of expression graph */
14949  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14950  )
14951 {
14952  assert(exprgraph != NULL);
14953 
14954  return exprgraph->nnodes;
14955 }
14956 
14957 /** gets nodes of expression graph, one array per depth */
14959  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14960  )
14961 {
14962  assert(exprgraph != NULL);
14963 
14964  return exprgraph->nodes;
14965 }
14966 
14967 /** gets number of variables in expression graph */
14969  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14970  )
14971 {
14972  assert(exprgraph != NULL);
14973 
14974  return exprgraph->nvars;
14975 }
14976 
14977 /** gets array of variables in expression graph */
14979  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14980  )
14981 {
14982  assert(exprgraph != NULL);
14983 
14984  return exprgraph->vars;
14985 }
14986 
14987 /** gets array of expression graph nodes corresponding to variables */
14989  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14990  )
14991 {
14992  assert(exprgraph != NULL);
14993 
14994  return exprgraph->varnodes;
14995 }
14996 
14997 /** sets value for a single variable given as expression graph node */
14999  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15000  SCIP_Real value /**< new value for variable */
15001  )
15002 {
15003  assert(varnode != NULL);
15004  assert(varnode->op == SCIP_EXPR_VARIDX);
15005 
15006  varnode->value = value;
15007 }
15008 
15009 /** sets bounds for variables */
15011  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15012  SCIP_INTERVAL* varbounds /**< new bounds for variables */
15013  )
15014 {
15015  assert(exprgraph != NULL);
15016  assert(varbounds != NULL || exprgraph->nvars == 0);
15017 
15018  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
15019 }
15020 
15021 /** sets bounds for a single variable */
15023  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15024  void* var, /**< variable */
15025  SCIP_INTERVAL varbounds /**< new bounds of variable */
15026  )
15027 {
15028  int pos;
15029 
15030  assert(exprgraph != NULL);
15031  assert(var != NULL);
15032  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15033 
15034  pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15035  assert(pos < exprgraph->nvars);
15036  assert(exprgraph->vars[pos] == var);
15037 
15038  exprgraph->varbounds[pos] = varbounds;
15039 }
15040 
15041 /** sets bounds for a single variable given as expression graph node */
15043  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15044  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15045  SCIP_INTERVAL varbounds /**< new bounds of variable */
15046  )
15047 {
15048  int pos;
15049 
15050  assert(exprgraph != NULL);
15051  assert(varnode != NULL);
15052 
15053  pos = varnode->data.intval;
15054  assert(pos >= 0);
15055  assert(pos < exprgraph->nvars);
15056  assert(exprgraph->varnodes[pos] == varnode);
15057 
15058  exprgraph->varbounds[pos] = varbounds;
15059 }
15060 
15061 /** sets lower bound for a single variable given as expression graph node */
15063  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15064  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15065  SCIP_Real lb /**< new lower bound for variable */
15066  )
15067 {
15068  int pos;
15069 
15070  assert(exprgraph != NULL);
15071  assert(varnode != NULL);
15072 
15073  pos = varnode->data.intval;
15074  assert(pos >= 0);
15075  assert(pos < exprgraph->nvars);
15076  assert(exprgraph->varnodes[pos] == varnode);
15077 
15078  exprgraph->varbounds[pos].inf = lb;
15079 }
15080 
15081 /** sets upper bound for a single variable given as expression graph node */
15083  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15084  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
15085  SCIP_Real ub /**< new upper bound for variable */
15086  )
15087 {
15088  int pos;
15089 
15090  assert(exprgraph != NULL);
15091  assert(varnode != NULL);
15092 
15093  pos = varnode->data.intval;
15094  assert(pos >= 0);
15095  assert(pos < exprgraph->nvars);
15096  assert(exprgraph->varnodes[pos] == varnode);
15097 
15098  exprgraph->varbounds[pos].sup = ub;
15099 }
15100 
15101 /** gets bounds that are stored for all variables */
15103  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
15104  )
15105 {
15106  return exprgraph->varbounds;
15107 }
15108 
15109 /** creates an empty expression graph */
15111  BMS_BLKMEM* blkmem, /**< block memory */
15112  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
15113  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
15114  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
15115  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /**< callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
15116  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /**< callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
15117  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /**< callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
15118  void* userdata /**< user data to pass to callback functions */
15119  )
15120 {
15121  assert(blkmem != NULL);
15122  assert(exprgraph != NULL);
15123 
15124  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
15125  BMSclearMemory(*exprgraph);
15126  (*exprgraph)->blkmem = blkmem;
15127 
15128  /* create nodes's arrays */
15129  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
15130  assert((*exprgraph)->depth >= 1);
15131 
15132  /* create var's arrays and hashmap */
15133  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
15134  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, (*exprgraph)->varssize) );
15135 
15136  /* empty array of constants is sorted */
15137  (*exprgraph)->constssorted = TRUE;
15138 
15139  /* store callback functions and user data */
15140  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
15141  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
15142  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
15143  (*exprgraph)->userdata = userdata;
15144 
15145  return SCIP_OKAY;
15146 }
15147 
15148 /** frees an expression graph */
15150  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
15151  )
15152 {
15153  BMS_BLKMEM* blkmem;
15154  int d;
15155 
15156  assert( exprgraph != NULL);
15157  assert(*exprgraph != NULL);
15158  assert((*exprgraph)->nvars == 0);
15159  assert((*exprgraph)->nconsts == 0);
15160 
15161  blkmem = (*exprgraph)->blkmem;
15162  assert(blkmem != NULL);
15163 
15164  /* free nodes arrays */
15165  for( d = 0; d < (*exprgraph)->depth; ++d )
15166  {
15167  assert((*exprgraph)->nnodes[d] == 0);
15168  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
15169  }
15170  assert((*exprgraph)->nodes != NULL);
15171  assert((*exprgraph)->nnodes != NULL);
15172  assert((*exprgraph)->nodessize != NULL);
15173  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
15174  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
15175  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
15176 
15177  /* free variables arrays and hashmap */
15178  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
15179  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
15180  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
15181  SCIPhashmapFree(&(*exprgraph)->varidxs);
15182 
15183  /* free constants array */
15184  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
15185 
15186  /* free graph struct */
15187  BMSfreeBlockMemory(blkmem, exprgraph);
15188 
15189  return SCIP_OKAY;
15190 }
15191 
15192 /** adds an expression graph node to an expression graph
15193  *
15194  * Expression graph assumes ownership of node.
15195  * Children are notified about new parent.
15196  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
15197  */
15199  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15200  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
15201  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
15202  int nchildren, /**< number of children */
15203  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
15204  )
15205 {
15206  SCIP_Bool childvalsvalid;
15207  int depth;
15208  int i;
15209 
15210  assert(exprgraph != NULL);
15211  assert(node != NULL);
15212  assert(node->pos < 0); /* node should have no position in graph yet */
15213  assert(node->depth < 0); /* node should have no position in graph yet */
15214  assert(node->nchildren == 0); /* node should not have stored children yet */
15215  assert(node->children == NULL); /* node should not have stored children yet */
15216  assert(node->nparents == 0); /* node should not have parents stored yet */
15217  assert(children != NULL || nchildren == 0);
15218 
15219  /* choose depth as maximal depth of children + 1, and at least mindepth */
15220  depth = MAX(0, mindepth);
15221  for( i = 0; i < nchildren; ++i )
15222  {
15223  if( children[i]->depth >= depth ) /*lint !e613*/
15224  depth = children[i]->depth + 1; /*lint !e613*/
15225  }
15226 
15227  /* ensure that expression graph is deep enough */
15228  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
15229  assert(exprgraph->depth > depth);
15230 
15231  /* ensure enough space for nodes at depth depth */
15232  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
15233 
15234  /* add node to graph */
15235  node->depth = depth;
15236  node->pos = exprgraph->nnodes[depth];
15237  exprgraph->nodes[depth][node->pos] = node;
15238  ++exprgraph->nnodes[depth];
15239 
15240  /* add as parent to children
15241  * and check if children has valid values */
15242  childvalsvalid = TRUE;
15243  for( i = 0; i < nchildren; ++i )
15244  {
15245  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
15246  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
15247  }
15248  /* store children */
15249  if( nchildren > 0 )
15250  {
15251  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
15252  node->nchildren = nchildren;
15253  }
15254 
15255  if( node->op == SCIP_EXPR_CONST )
15256  {
15257  /* set bounds to constant value of node */
15259  SCIPintervalSet(&node->bounds, node->data.dbl);
15260  }
15261  else
15262  {
15263  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
15266  exprgraph->needvarboundprop = TRUE;
15267  }
15268 
15269  /* if not a variable, set value of node according to values of children (if all have valid values) */
15270  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
15271  {
15272  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15273  }
15274 
15275  return SCIP_OKAY;
15276 }
15277 
15278 /** adds variables to an expression graph, if not existing yet
15279  *
15280  * Also already existing nodes are enabled.
15281  */
15283  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15284  int nvars, /**< number of variables to add */
15285  void** vars, /**< variables to add */
15286  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
15287  )
15288 {
15289  SCIP_EXPRGRAPHNODE* node;
15290  SCIP_EXPROPDATA opdata;
15291  int i;
15292 
15293  assert(exprgraph != NULL);
15294  assert(exprgraph->depth >= 1);
15295  assert(vars != NULL || nvars == 0);
15296 
15297  /* 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 */
15298  if( exprgraph->nvars == 0 )
15299  {
15300  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15301  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15302  }
15303 
15304  for( i = 0; i < nvars; ++i )
15305  {
15306  /* skip variables that exist already */
15307  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15308  {
15309  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
15310  assert(node != NULL);
15311 
15312  /* enable node */
15313  node->enabled = TRUE;
15314 
15315  if( varnodes != NULL )
15316  varnodes[i] = node;
15317 
15318  continue;
15319  }
15320 
15321  /* create new variable expression */
15322  opdata.intval = exprgraph->nvars;
15323  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15324 
15325  /* add expression node to expression graph at depth 0 */
15326  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15327 
15328  /* add variable node to vars arrays and hashmap */
15329  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15330  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
15331  exprgraph->varnodes[exprgraph->nvars] = node;
15332  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15333  SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[i], exprgraph->nvars) ); /*lint !e613*/
15334  ++exprgraph->nvars;
15335 
15336  if( varnodes != NULL )
15337  varnodes[i] = node;
15338 
15339  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15340 
15341  /* call callback method, if set */
15342  if( exprgraph->exprgraphvaradded != NULL )
15343  {
15344  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
15345  }
15346  }
15347 
15348  return SCIP_OKAY;
15349 }
15350 
15351 /** adds a constant to an expression graph, if not existing yet
15352  *
15353  * Also already existing nodes are enabled.
15354  */
15356  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15357  SCIP_Real constant, /**< constant to add */
15358  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
15359  )
15360 {
15361  SCIP_EXPROPDATA opdata;
15362 
15363  assert(exprgraph != NULL);
15364  assert(constnode != NULL);
15365 
15366  /* check if there is already an expression for this constant */
15367  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15368  {
15369  assert(*constnode != NULL);
15370  assert((*constnode)->op == SCIP_EXPR_CONST);
15371  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15372  (*constnode)->enabled = TRUE;
15373  return SCIP_OKAY;
15374  }
15375 
15376  /* create new node for constant */
15377  opdata.dbl = constant;
15378  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15379 
15380  /* add node to expression graph at depth 0 */
15381  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15382  assert((*constnode)->depth == 0);
15383  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
15384 
15385  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15386  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15387  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15388  ++exprgraph->nconsts;
15389  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15390 
15391  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15392 
15393  return SCIP_OKAY;
15394 }
15395 
15396 /** adds sum of expression trees into expression graph
15397  *
15398  * node will also be captured.
15399  *
15400  * @note Parameters will be converted into constants
15401  */
15403  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15404  int nexprtrees, /**< number of expression trees to add */
15405  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
15406  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
15407  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
15408  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) */
15409  )
15410 {
15411  SCIP_Bool allone;
15412 
15413  assert(exprgraph != NULL);
15414  assert(nexprtrees > 0);
15415  assert(exprtrees != NULL);
15416  assert(rootnode != NULL);
15417  assert(rootnodeisnew != NULL);
15418 
15419  *rootnode = NULL;
15420 
15421  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15422  {
15423  assert(exprtrees[0] != NULL);
15424  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15425 
15426  /* coverity[var_deref_model] */
15427  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, exprtrees[0]->params, rootnode, rootnodeisnew) );
15428  }
15429  else
15430  {
15431  SCIP_EXPROP op;
15432  SCIP_EXPRGRAPHNODE** rootnodes;
15433  SCIP_Bool rootnodeisnew_;
15434  int i;
15435 
15436  *rootnodeisnew = TRUE;
15437  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15438 
15439  allone = TRUE;
15440  for( i = 0; i < nexprtrees; ++i )
15441  {
15442  assert(exprtrees[i] != NULL);
15443  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15444 
15445  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, exprtrees[i]->params, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
15446  assert(rootnodes[i] != NULL);
15447  *rootnodeisnew &= rootnodeisnew_;
15448 
15449  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
15450  }
15451 
15452  /* decide which operand we want to use for the root node */
15453  if( coefs == NULL || allone )
15454  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15455  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15456  op = SCIP_EXPR_MINUS;
15457  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15458  {
15459  SCIP_EXPRGRAPHNODE* tmp;
15460 
15461  tmp = rootnodes[0];
15462  rootnodes[0] = rootnodes[1];
15463  rootnodes[1] = tmp;
15464  op = SCIP_EXPR_MINUS;
15465  }
15466  else
15467  op = SCIP_EXPR_LINEAR;
15468 
15469  if( op != SCIP_EXPR_LINEAR )
15470  {
15471  SCIP_EXPROPDATA data;
15472  data.data = NULL;
15473 
15474  if( !*rootnodeisnew )
15475  {
15476  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15477  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15478  }
15479 
15480  if( *rootnode == NULL )
15481  {
15482  /* create new node for sum of rootnodes and add to exprgraph */
15483  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15484  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15485  *rootnodeisnew = TRUE;
15486  }
15487  else
15488  {
15489  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15490  *rootnodeisnew = FALSE;
15491  }
15492  }
15493  else
15494  {
15495  SCIP_EXPROPDATA data;
15496  SCIP_Real* lindata;
15497 
15498  assert(op == SCIP_EXPR_LINEAR);
15499 
15500  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15501  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15502  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
15503  lindata[nexprtrees] = 0.0;
15504  data.data = lindata;
15505 
15506  if( !*rootnodeisnew )
15507  {
15508  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15509  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15510  }
15511 
15512  if( *rootnode == NULL )
15513  {
15514  /* create new node for linear combination of rootnodes and add to exprgraph */
15515  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15516  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15517  *rootnodeisnew = TRUE;
15518  }
15519  else
15520  {
15521  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15522  *rootnodeisnew = FALSE;
15523  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15524  }
15525  }
15526 
15527  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15528  }
15529  assert(*rootnode != NULL);
15530 
15531  SCIPexprgraphCaptureNode(*rootnode);
15532 
15533  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15534  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15535 
15536  return SCIP_OKAY;
15537 }
15538 
15539 /** replaces variable in expression graph by a linear sum of variables
15540  *
15541  * Variables will be added if not in the graph yet.
15542  */
15544  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15545  void* var, /**< variable to replace */
15546  int ncoefs, /**< number of coefficients in linear term */
15547  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
15548  void** vars, /**< variables in linear term */
15549  SCIP_Real constant /**< constant offset */
15550  )
15551 {
15552  SCIP_EXPRGRAPHNODE* varnode;
15553  SCIP_Real* lindata;
15554  int varidx;
15555  int i;
15556 
15557  assert(exprgraph != NULL);
15558  assert(var != NULL);
15559  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15560  assert(coefs != NULL || ncoefs == 0);
15561  assert(vars != NULL || ncoefs == 0);
15562 
15563  varidx = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15564  assert(varidx < exprgraph->nvars);
15565  assert(exprgraph->vars[varidx] == var);
15566  varnode = exprgraph->varnodes[varidx];
15567  assert(varnode != NULL);
15568  assert(varnode->data.intval == varidx);
15569 
15570  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
15571  {
15572  /* variable is replaced by constant or variable */
15573  SCIP_EXPRGRAPHNODE* node;
15574 
15575  /* check if there is already a node for this constant or variable */
15576  node = NULL;
15577  if( ncoefs == 0 )
15578  {
15579  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15580  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
15581  }
15582  else
15583  {
15584  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
15585  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
15586  }
15587 
15588  if( node != NULL )
15589  {
15590  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15591 
15592  /* tell parents of varnode to replace child varnode by node, this may free varnode */
15593  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15594 
15595  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15596  if( varnode != NULL )
15597  {
15598  assert(varnode->nuses > 0);
15599  assert(varnode->nparents == 0);
15600 
15601  /* remove variable (but don't free it's node) from graph */
15602  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15603 
15604  /* move varnode up to depth 1 */
15605  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15606 
15607  /* turn into EXPR_SUM expression */
15608  varnode->op = SCIP_EXPR_SUM;
15609  varnode->data.data = NULL;
15610  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
15611  varnode->children[0] = node;
15612  varnode->nchildren = 1;
15613  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15614 
15615  varnode->value = node->value;
15616  varnode->bounds = node->bounds;
15617  varnode->boundstatus = (node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID) ? SCIP_EXPRBOUNDSTATUS_VALID : SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
15618  }
15619  }
15620  else if( ncoefs == 0 )
15621  {
15622  /* turn node into EXPR_CONST node */
15623 
15624  /* remove variable (but don't free it's node) from graph */
15625  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15626 
15627  /* convert into EXPR_CONST node */
15628  varnode->op = SCIP_EXPR_CONST;
15629  varnode->data.dbl = constant;
15630 
15631  varnode->value = constant;
15632  SCIPintervalSet(&varnode->bounds, constant);
15634 
15635  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15636  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15637  exprgraph->constnodes[exprgraph->nconsts] = varnode;
15638  ++exprgraph->nconsts;
15639  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15640  }
15641  else
15642  {
15643  /* turn node into EXPR_VARIDX node for new variable */
15644 
15645  /* remove variable (but don't free it's node) from graph */
15646  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15647 
15648  varnode->data.intval = exprgraph->nvars;
15649 
15650  /* add variable node to vars arrays and hashmap */
15651  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15652  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
15653  exprgraph->varnodes[exprgraph->nvars] = varnode;
15654  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15655  SCIP_CALL( SCIPhashmapInsertInt(exprgraph->varidxs, vars[0], exprgraph->nvars) ); /*lint !e613*/
15656  ++exprgraph->nvars;
15657 
15658  /* call callback method, if set */
15659  if( exprgraph->exprgraphvaradded != NULL )
15660  {
15661  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
15662  }
15663  }
15664 
15665  /* mark varnode and its parents as not simplified */
15666  if( varnode != NULL )
15667  {
15668  varnode->simplified = FALSE;
15669  for( i = 0; i < varnode->nparents; ++i )
15670  varnode->parents[i]->simplified = FALSE;
15671  }
15672 
15673  return SCIP_OKAY;
15674  }
15675 
15676  /* turn varnode into EXPR_LINEAR */
15677 
15678  /* remove variable (but don't free it's node) from graph */
15679  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15680 
15681  /* move varnode up to depth 1 */
15682  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15683 
15684  /* convert into EXPR_LINEAR node */
15685  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15686  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
15687  lindata[ncoefs] = constant;
15688  varnode->data.data = (void*)lindata;
15689  varnode->op = SCIP_EXPR_LINEAR;
15690 
15691  /* add nodes corresponding to vars to expression graph, if not existing yet */
15692  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15693  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15694  varnode->nchildren = ncoefs;
15695 
15696  /* notify vars about new parent varnode */
15697  for( i = 0; i < ncoefs; ++i )
15698  {
15699  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15700  }
15701 
15702  /* set value and bounds to invalid, curvature can remain (still linear) */
15703  varnode->value = SCIP_INVALID;
15705 
15706  /* mark varnode and its parents as not simplified */
15707  varnode->simplified = FALSE;
15708  for( i = 0; i < varnode->nparents; ++i )
15709  varnode->parents[i]->simplified = FALSE;
15710 
15711  return SCIP_OKAY;
15712 }
15713 
15714 /** finds expression graph node corresponding to a variable */
15716  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15717  void* var, /**< variable to search for */
15718  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15719  )
15720 {
15721  int pos;
15722 
15723  assert(exprgraph != NULL);
15724  assert(var != NULL);
15725  assert(varnode != NULL);
15726 
15727  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15728  {
15729  *varnode = NULL;
15730  return FALSE;
15731  }
15732 
15733  pos = SCIPhashmapGetImageInt(exprgraph->varidxs, var);
15734  assert(pos < exprgraph->nvars);
15735 
15736  *varnode = exprgraph->varnodes[pos];
15737  assert(*varnode != NULL);
15738  assert((*varnode)->op == SCIP_EXPR_VARIDX);
15739 
15740  return TRUE;
15741 }
15742 
15743 /** finds expression graph node corresponding to a constant */
15745  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15746  SCIP_Real constant, /**< constant to search for */
15747  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15748  )
15749 {
15750  int left;
15751  int right;
15752  int middle;
15753 
15754  assert(exprgraph != NULL);
15755  assert(constnode != NULL);
15756  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
15757 
15758  exprgraphSortConstNodes(exprgraph);
15759  assert(exprgraph->constssorted);
15760 
15761  /* find node using binary search */
15762  left = 0;
15763  right = exprgraph->nconsts-1;
15764  *constnode = NULL;
15765 
15766  while( left <= right )
15767  {
15768  middle = (left+right)/2;
15769  assert(0 <= middle && middle < exprgraph->nconsts);
15770 
15771  if( constant < exprgraph->constnodes[middle]->data.dbl )
15772  right = middle - 1;
15773  else if( constant > exprgraph->constnodes[middle]->data.dbl )
15774  left = middle + 1;
15775  else
15776  {
15777  *constnode = exprgraph->constnodes[middle];
15778  break;
15779  }
15780  }
15781  if( left == right+1 )
15782  return FALSE;
15783 
15784  assert(*constnode != NULL);
15785  assert((*constnode)->op == SCIP_EXPR_CONST);
15786  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15787 
15788  return TRUE;
15789 }
15790 
15791 /** prints an expression graph in dot format */
15793  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15794  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15795  FILE* file, /**< file to print to, or NULL for stdout */
15796  const char** varnames /**< variable names, or NULL for generic names */
15797  )
15798 {
15799  int d;
15800  int i;
15801 
15802  assert(exprgraph != NULL);
15803 
15804  if( file == NULL )
15805  file = stdout;
15806 
15807  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15808  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15809 
15810  for( d = 0; d < exprgraph->depth; ++d )
15811  {
15812  if( exprgraph->nnodes[d] == 0 )
15813  continue;
15814 
15815  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15816  {
15817  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15818  }
15819  }
15820 
15821  /* tell dot that all nodes of depth 0 have the same rank */
15822  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15823  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15824  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15825  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15826 
15827  /* tell dot that all nodes without parent have the same rank */
15828  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15829  for( d = 0; d < exprgraph->depth; ++d )
15830  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15831  if( exprgraph->nodes[d][i]->nparents == 0 )
15832  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15833  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15834 
15835  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15836 
15837  return SCIP_OKAY;
15838 }
15839 
15840 /** evaluates nodes of expression graph for given values of variables */
15842  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15843  SCIP_Real* varvals /**< values for variables */
15844  )
15845 {
15846  int d;
15847  int i;
15848 
15849  assert(exprgraph != NULL);
15850  assert(varvals != NULL || exprgraph->nvars == 0);
15851 
15852  for( d = 0; d < exprgraph->depth; ++d )
15853  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15854  {
15855  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15856  }
15857 
15858  return SCIP_OKAY;
15859 }
15860 
15861 /** propagates bound changes in variables forward through the expression graph */
15863  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15864  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15865  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
15866  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15867  )
15868 {
15869  SCIP_EXPRGRAPHNODE* node;
15870  SCIP_Bool boundchanged;
15871  int d;
15872  int i;
15873 
15874  assert(exprgraph != NULL);
15875  assert(domainerror != NULL);
15876 
15877  *domainerror = FALSE;
15878 
15879  /* update bounds in varnodes of expression graph */
15880  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15881 
15882  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15883  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15884  {
15885  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15886  return SCIP_OKAY;
15887  }
15888 
15889  /* propagate bound changes, interrupt if we get to a node with empty bounds */
15890  for( d = 1; d < exprgraph->depth; ++d )
15891  {
15892  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15893  {
15894  node = exprgraph->nodes[d][i];
15895  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15896  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15897  {
15898  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15899  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15900  *domainerror = TRUE;
15901  return SCIP_OKAY;
15902  }
15903  }
15904  }
15905 
15906  exprgraph->needvarboundprop = FALSE;
15907 
15908  return SCIP_OKAY;
15909 }
15910 
15911 /** propagates bound changes in nodes backward through the graph
15912  *
15913  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15914  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15915  */
15917  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15918  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15919  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15920  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15921  )
15922 {
15923  SCIP_EXPRGRAPHNODE* node;
15924  int d;
15925  int i;
15926 
15927  assert(exprgraph != NULL);
15928  assert(cutoff != NULL);
15929 
15930  *cutoff = FALSE;
15931 
15932  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15933  {
15934  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15935  {
15936  node = exprgraph->nodes[d][i];
15937  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15938  }
15939  }
15940  if( *cutoff )
15941  return;
15942 }
15943 
15944 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15945  *
15946  * Implies update of bounds in expression graph.
15947  */
15949  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15950  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15951  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15952  )
15953 {
15954  SCIP_EXPRGRAPHNODE* node;
15955  SCIP_Bool boundchanged;
15956  int d;
15957  int i;
15958 
15959  assert(exprgraph != NULL);
15960 
15961  /* update bounds in varnodes of expression graph */
15962  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15963 
15964 #ifndef NDEBUG
15965  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15966  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15967 #endif
15968 
15969  for( d = 1; d < exprgraph->depth; ++d )
15970  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15971  {
15972  node = exprgraph->nodes[d][i];
15973  assert(node != NULL);
15974 
15975  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15976 
15977  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15978  {
15979  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15980  return SCIP_OKAY;
15981  }
15982  }
15983 
15984  return SCIP_OKAY;
15985 }
15986 
15987 /** aims at simplifying an expression graph
15988  *
15989  * 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)).
15990  */
15992  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15993  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15994  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15995  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15996  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15997  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15998  )
15999 {
16000  SCIP_EXPRGRAPHNODE* node;
16001  SCIP_Bool havechangenode;
16002  SCIP_Bool allsimplified;
16003  int d;
16004  int i;
16005  int j;
16006 
16007 #ifndef NDEBUG
16008  SCIP_Real* testx;
16009  SCIP_HASHMAP* testvalidx;
16010  SCIP_Real* testvals;
16011  SCIP_RANDNUMGEN* randnumgen;
16012  int testvalssize;
16013  int ntestvals;
16014 #endif
16015 
16016  assert(exprgraph != NULL);
16017  assert(eps >= 0.0);
16018  assert(havechange != NULL);
16019  assert(domainerror != NULL);
16020 
16021 #ifndef NDEBUG
16022  SCIP_CALL( SCIPrandomCreate(&randnumgen, exprgraph->blkmem, 862) ); /* see also #1848 */
16023  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
16024  testvals = NULL;
16025  ntestvals = 0;
16026  testvalssize = 0;
16027 
16028  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
16029  for( i = 0; i < exprgraph->nvars; ++i )
16030  testx[i] = SCIPrandomGetReal(randnumgen,
16031  exprgraph->varbounds[i].inf < -100.0 ? MIN(-100.0, exprgraph->varbounds[i].sup) : exprgraph->varbounds[i].inf,
16032  exprgraph->varbounds[i].sup > 100.0 ? MAX( 100.0, exprgraph->varbounds[i].inf) : exprgraph->varbounds[i].sup); /*lint !e644*/
16033  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
16034  for( d = 1; d < exprgraph->depth; ++d )
16035  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16036  {
16037  node = exprgraph->nodes[d][i];
16038  assert(node != NULL);
16039 
16040  /* 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 */
16041  if( node->nuses > 0 )
16042  {
16043  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
16044  SCIP_CALL( SCIPhashmapInsertInt(testvalidx, (void*)node, ntestvals) );
16045  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
16046  ++ntestvals;
16047  }
16048  }
16049 
16050  SCIPrandomFree(&randnumgen, exprgraph->blkmem);
16051 #endif
16052 
16053 #ifdef SCIP_OUTPUT
16054  {
16055  FILE* file;
16056  file = fopen("exprgraph_beforesimplify.dot", "w");
16057  if( file != NULL )
16058  {
16059  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16060  fclose(file);
16061  }
16062  }
16063 #endif
16064 
16065  *havechange = FALSE; /* we have not changed any node yet */
16066  *domainerror = FALSE; /* no domain errors encountered so far */
16067  allsimplified = TRUE; /* all nodes we looked at are simplified */
16068 
16069  /* call node simplifier from bottom up
16070  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
16071  */
16072  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
16073  {
16074  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16075  {
16076  node = exprgraph->nodes[d][i];
16077  assert(node != NULL);
16078 
16079  havechangenode = FALSE; /* node did not change yet */
16080 
16081  if( node->op != SCIP_EXPR_CONST )
16082  {
16083  /* skip nodes that are already simplified */
16084  if( node->simplified )
16085  continue;
16086 
16087  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
16088 
16089  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
16090  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
16091  assert(node->simplified == TRUE);
16092  *havechange |= havechangenode;
16093  }
16094 
16095  /* if node was or has been converted into constant, may move to depth 0 */
16096  if( node->op == SCIP_EXPR_CONST )
16097  {
16098  SCIP_EXPRGRAPHNODE* constnode;
16099 
16100  if( !SCIPisFinite(node->value) ) /*lint !e777*/
16101  {
16102  SCIPdebugMessage("Expression graph simplify turned node into NaN or inf.\n");
16103  *domainerror = TRUE;
16104  break;
16105  }
16106 
16107  /* check if there is already a node for this constant */
16108  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
16109  {
16110  assert(constnode->op == SCIP_EXPR_CONST);
16111  assert(constnode->data.dbl == node->value); /*lint !e777*/
16112 
16113  if( node->nparents > 0 )
16114  {
16115  /* move parents of this node to constnode, node may be freed if not in use */
16116  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
16117  /* node should have no parents anymore, so it should have been freed if not in use */
16118  assert(node == NULL || node->nuses > 0);
16119  havechangenode = TRUE;
16120 
16121  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
16122  if( node == NULL )
16123  {
16124  --i;
16125  continue;
16126  }
16127  }
16128  assert(node != NULL);
16129  assert(node->nuses > 0);
16130 
16131  if( constnode->nuses == 0 )
16132  {
16133  /* move node to depth 0, adding it to constnodes */
16134  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16135 
16136  /* move parents of constnode to node, so constnode is freed */
16137  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
16138  assert(constnode == NULL);
16139  havechangenode = TRUE;
16140 
16141  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16142  --i;
16143  continue;
16144  }
16145  }
16146  else
16147  {
16148  /* move to depth 0, adding it to constnodes */
16149  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16150 
16151  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16152  --i;
16153  }
16154  }
16155 
16156  /* if there was a change, mark parents as not simplified */
16157  if( havechangenode )
16158  for( j = 0; j < node->nparents; ++j )
16159  node->parents[j]->simplified = FALSE;
16160  }
16161  } /*lint !e850*/
16162 
16163  /* if we did nothing, clean up and escape from here */
16164  if( allsimplified || *domainerror )
16165  goto EXPRGRAPHSIMPLIFY_CLEANUP;
16166 
16167  /* @todo find duplicate subexpressions in expression graph */
16168 
16169  /* unconvert polynomials into simpler expressions, where possible */
16170  for( d = 1; d < exprgraph->depth; ++d )
16171  {
16172  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16173  {
16174  node = exprgraph->nodes[d][i];
16175  assert(node != NULL);
16176 
16177  if( node->op != SCIP_EXPR_POLYNOMIAL )
16178  continue;
16179 
16180  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
16181 
16182  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
16183  {
16184  /* node is identity w.r.t only child
16185  * replace node as child of parents by child of node
16186  */
16187 
16188  for( j = 0; node != NULL && j < node->nparents; ++j )
16189  {
16190  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
16191  }
16192  /* node should have no parents anymore, so it should have been freed if not in use */
16193  assert(node == NULL || node->nuses > 0);
16194 
16195  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
16196  if( node == NULL )
16197  --i;
16198  }
16199  }
16200  } /*lint !e850*/
16201 
16202 #ifdef SCIP_OUTPUT
16203  {
16204  FILE* file;
16205  file = fopen("exprgraph_aftersimplify.dot", "w");
16206  if( file != NULL )
16207  {
16208  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16209  fclose(file);
16210  }
16211  }
16212 #endif
16213 
16214 #ifndef NDEBUG
16215  for( d = 1; d < exprgraph->depth; ++d )
16216  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16217  {
16218  int idx;
16219  SCIP_Real testval_before;
16220  SCIP_Real testval_after;
16221 
16222  node = exprgraph->nodes[d][i];
16223  assert(node != NULL);
16224 
16225  SCIP_CALL( exprgraphNodeEval(node, NULL) );
16226 
16227  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
16228  if( node->nuses > 0 )
16229  {
16230  assert(SCIPhashmapExists(testvalidx, (void*)node));
16231 
16232  idx = SCIPhashmapGetImageInt(testvalidx, (void*)node);
16233  assert(idx < ntestvals);
16234  assert(testvals != NULL);
16235 
16236  testval_before = testvals[idx]; /*lint !e613*/
16237  testval_after = SCIPexprgraphGetNodeVal(node);
16238 
16239  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), 10*eps)); /*lint !e777*/
16240  }
16241  }
16242 #endif
16243 
16244  EXPRGRAPHSIMPLIFY_CLEANUP:
16245 #ifndef NDEBUG
16246  BMSfreeMemoryArray(&testx);
16247  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
16248  SCIPhashmapFree(&testvalidx);
16249 #endif
16250 
16251  return SCIP_OKAY;
16252 }
16253 
16254 /** creates an expression tree from a given node in an expression graph */
16256  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16257  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
16258  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
16259  )
16260 {
16261  SCIP_EXPR* root;
16262  int nexprvars;
16263  int* varidx;
16264  int i;
16265 
16266  assert(exprgraph != NULL);
16267  assert(rootnode != NULL);
16268  assert(rootnode->depth >= 0);
16269  assert(rootnode->pos >= 0);
16270  assert(exprtree != NULL);
16271 
16272  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16273  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16274 
16275  /* initially, no variable appears in the expression tree */
16276  for( i = 0; i < exprgraph->nvars; ++i )
16277  varidx[i] = -1; /*lint !e644*/
16278  nexprvars = 0;
16279 
16280  /* create expression from the subgraph that has rootnode as root */
16281  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
16282 
16283  /* create expression tree for this expression */
16284  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
16285 
16286  /* copy variables into expression tree */
16287  if( nexprvars > 0 )
16288  {
16289  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
16290  for( i = 0; i < exprgraph->nvars; ++i )
16291  {
16292  assert(varidx[i] >= -1);
16293  assert(varidx[i] < nexprvars);
16294  if( varidx[i] >= 0 )
16295  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
16296  }
16297  }
16298 
16299  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16300 
16301  return SCIP_OKAY;
16302 }
16303 
16304 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16305  *
16306  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16307  */
16309  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16310  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16311  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16312  int* nexprtrees, /**< buffer to store number of expression trees */
16313  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16314  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16315  )
16316 {
16317  int ncomponents;
16318  int* childcomp;
16319  int* varcomp;
16320  int compnr;
16321  SCIP_Bool haveoverlap;
16322  int i;
16323  int j;
16324  int k;
16325 
16326  SCIP_EXPR** exprs;
16327  int nexprs;
16328  int* childmap;
16329  int* childmapinv;
16330  int* varidx;
16331  int nexprvars;
16332 
16333  assert(exprgraph != NULL);
16334  assert(node != NULL);
16335  assert(node->depth >= 0);
16336  assert(node->pos >= 0);
16337  assert(exprtreessize > 0);
16338  assert(nexprtrees != NULL);
16339  assert(exprtrees != NULL);
16340  assert(exprtreecoefs != NULL);
16341 
16342  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16343  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16344  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16345  ( node->op != SCIP_EXPR_PLUS &&
16346  node->op != SCIP_EXPR_MINUS &&
16347  node->op != SCIP_EXPR_SUM &&
16348  node->op != SCIP_EXPR_LINEAR &&
16349  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16350  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16351  {
16352  *nexprtrees = 1;
16353  exprtreecoefs[0] = 1.0;
16354  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16355 
16356  return SCIP_OKAY;
16357  }
16358 
16359  /* find components in node->children <-> variables graph */
16360  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16361  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16362  for( i = 0; i < exprgraph->nvars; ++i )
16363  varcomp[i] = -1; /*lint !e644*/
16364 
16365  haveoverlap = FALSE;
16366  for( i = 0; i < node->nchildren; ++i )
16367  {
16368  compnr = i;
16369  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
16370  assert(compnr >= 0);
16371  assert(compnr < node->nchildren);
16372  childcomp[i] = compnr;
16373 
16374  /* remember if component number was changed by CheckComponent */
16375  if( compnr != i )
16376  haveoverlap = TRUE;
16377  }
16378 
16379  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16380 
16381  if( node->op == SCIP_EXPR_QUADRATIC )
16382  {
16383  /* merge components for products of children from different components */
16385 
16386  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16387  assert(data != NULL);
16388 
16389  for( i = 0; i < data->nquadelems; ++i )
16390  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16391  {
16392  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16393  compnr = childcomp[data->quadelems[i].idx2];
16394  for( j = 0; j < node->nchildren; ++j )
16395  if( childcomp[j] == compnr )
16396  childcomp[j] = childcomp[data->quadelems[i].idx1];
16397  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16398  haveoverlap = TRUE;
16399  }
16400  }
16401  else if( node->op == SCIP_EXPR_POLYNOMIAL )
16402  {
16403  /* merge components for monomials of children from different components */
16405 
16406  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16407  assert(data != NULL);
16408 
16409  for( i = 0; i < data->nmonomials; ++i )
16410  for( j = 1; j < data->monomials[i]->nfactors; ++j )
16411  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16412  {
16413  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16414  compnr = childcomp[data->monomials[i]->childidxs[j]];
16415  for( k = 0; k < node->nchildren; ++k )
16416  if( childcomp[k] == compnr )
16417  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16418  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16419  haveoverlap = TRUE;
16420  }
16421  }
16422 
16423  if( haveoverlap )
16424  {
16425  /* some component numbers are unused, thus relabel and count final number of components */
16426  int* compmap;
16427 
16428  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16429  for( i = 0; i < node->nchildren; ++i )
16430  compmap[i] = -1; /*lint !e644*/
16431 
16432  ncomponents = 0;
16433  for( i = 0; i < node->nchildren; ++i )
16434  {
16435  if( compmap[childcomp[i]] == -1 )
16436  compmap[childcomp[i]] = ncomponents++;
16437  childcomp[i] = compmap[childcomp[i]];
16438  }
16439 
16440  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16441  }
16442  else
16443  {
16444  ncomponents = node->nchildren;
16445  }
16446 
16447  if( ncomponents == 1 )
16448  {
16449  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16450  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16451 
16452  *nexprtrees = 1;
16453  exprtreecoefs[0] = 1.0;
16454  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16455 
16456  return SCIP_OKAY;
16457  }
16458 
16459  if( ncomponents > exprtreessize )
16460  {
16461  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16462  for( i = 0; i < node->nchildren; ++i )
16463  if( childcomp[i] >= exprtreessize )
16464  childcomp[i] = exprtreessize-1;
16465  ncomponents = exprtreessize;
16466  }
16467 
16468  assert(ncomponents >= 2);
16469 
16470  /* setup expression trees for each component */
16471  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16472  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16473  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16474  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16475  for( i = 0; i < ncomponents; ++i )
16476  {
16477  /* initially, no variable appears in the expression tree */
16478  for( j = 0; j < exprgraph->nvars; ++j )
16479  varidx[j] = -1; /*lint !e644*/
16480  nexprvars = 0;
16481 
16482  /* collect expressions from children belonging to component i */
16483  nexprs = 0;
16484  for( j = 0; j < node->nchildren; ++j )
16485  {
16486  assert(childcomp[j] >= 0);
16487  assert(childcomp[j] < ncomponents);
16488  if( childcomp[j] != i )
16489  continue;
16490 
16491  /* create expression from the subgraph that has child j as root */
16492  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
16493  childmap[j] = nexprs; /*lint !e644*/
16494  childmapinv[nexprs] = j; /*lint !e644*/
16495  ++nexprs;
16496  }
16497 
16498  /* setup expression tree for component i */
16499  switch( node->op )
16500  {
16501  case SCIP_EXPR_PLUS:
16502  {
16503  assert(ncomponents == 2);
16504  assert(nexprs == 1);
16505 
16506  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16507  exprtreecoefs[i] = 1.0;
16508 
16509  break;
16510  }
16511 
16512  case SCIP_EXPR_MINUS:
16513  {
16514  assert(ncomponents == 2);
16515  assert(nexprs == 1);
16516 
16517  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16518  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16519  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16520  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16521 
16522  break;
16523  }
16524 
16525  case SCIP_EXPR_SUM:
16526  {
16527  if( nexprs == 1 )
16528  {
16529  /* component corresponds to exactly one child of node */
16530  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16531  }
16532  else
16533  {
16534  /* component corresponds to a sum of children of node */
16535  SCIP_EXPR* sumexpr;
16536 
16537  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16538  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16539  }
16540  exprtreecoefs[i] = 1.0;
16541 
16542  break;
16543  }
16544 
16545  case SCIP_EXPR_LINEAR:
16546  {
16547  SCIP_Real* nodecoefs;
16548  SCIP_EXPR* sumexpr;
16549 
16550  nodecoefs = (SCIP_Real*)node->data.data;
16551 
16552  /* if there is a constant, then we put it into the expression of the first component */
16553  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16554  {
16555  /* component corresponds to exactly one child of node */
16556  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16557  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16558  }
16559  else if( nexprs == 1 )
16560  {
16561  /* component corresponds to a sum of one child and a constant */
16562  assert(i == 0);
16563  assert(nodecoefs[node->nchildren] != 0.0);
16564  assert(nodecoefs[childmapinv[0]] != 0.0);
16565  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16566  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16567  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16568  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16569  }
16570  else
16571  {
16572  /* component corresponds to a linear combination of children of node */
16573 
16574  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16575  {
16576  /* if two expressions with equal sign, then create PLUS expression */
16577  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16578  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16579  }
16580  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16581  {
16582  /* if two expressions with opposite sign, then create MINUS expression */
16583  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16584  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16585  }
16586  else
16587  {
16588  /* assemble coefficents and create SUM or LINEAR expression */
16589  SCIP_Real* coefs;
16590  SCIP_Bool allcoefsequal;
16591 
16592  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16593  allcoefsequal = TRUE;
16594  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
16595  for( j = 0; j < nexprs; ++j )
16596  {
16597  coefs[j] = nodecoefs[childmapinv[j]];
16598  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
16599  }
16600 
16601  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16602  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16603  {
16604  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16605  exprtreecoefs[i] = coefs[0];
16606  }
16607  else
16608  {
16609  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16610  exprtreecoefs[i] = 1.0;
16611  }
16612 
16613  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16614  }
16615 
16616  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16617  }
16618 
16619  break;
16620  }
16621 
16622  case SCIP_EXPR_QUADRATIC:
16623  {
16624  SCIP_EXPR* quadexpr;
16626  SCIP_Real* lincoefs;
16627  SCIP_QUADELEM* quadelems;
16628  int nquadelems;
16629 
16630  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16631 
16632  exprtreecoefs[i] = 1.0;
16633 
16634  /* assemble coefficients corresponding to component i */
16635  if( nodedata->lincoefs != NULL )
16636  {
16637  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16638  for( j = 0; j < nexprs; ++j )
16639  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
16640  }
16641  else
16642  lincoefs = NULL;
16643 
16644  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16645  nquadelems = 0;
16646  for( j = 0; j < nodedata->nquadelems; ++j )
16647  {
16648  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16649  if( childcomp[nodedata->quadelems[j].idx1] != i )
16650  continue;
16651  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
16652  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16653  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16654  ++nquadelems;
16655  }
16656 
16657  /* put constant into first component */
16658  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16659  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16660 
16661  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16662  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16663 
16664  break;
16665  }
16666 
16667  case SCIP_EXPR_POLYNOMIAL:
16668  {
16669  SCIP_EXPR* polyexpr;
16671  SCIP_EXPRDATA_MONOMIAL** monomials;
16672  SCIP_Real constant;
16673  int nmonomials;
16674 
16675  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16676 
16677  constant = nodedata->constant;
16678  exprtreecoefs[i] = 1.0;
16679 
16680  /* collect monomials belonging to component i */
16681  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16682  nmonomials = 0;
16683  for( j = 0; j < nodedata->nmonomials; ++j )
16684  {
16685  if( nodedata->monomials[j]->nfactors == 0 )
16686  {
16687  constant += nodedata->monomials[j]->coef;
16688  continue;
16689  }
16690  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16691  continue;
16692 
16693  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16694  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
16695  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16696  {
16697  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16698  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16699  }
16700  ++nmonomials;
16701  }
16702 
16703  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16704  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16705 
16706  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16707 
16708  break;
16709  }
16710 
16711  default:
16712  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16713  return SCIP_ERROR;
16714  } /*lint !e788*/
16715 
16716  /* copy variables into expression tree */
16717  if( nexprvars > 0 )
16718  {
16719  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16720  for( j = 0; j < exprgraph->nvars; ++j )
16721  {
16722  assert(varidx[j] >= -1);
16723  assert(varidx[j] < nexprvars);
16724  if( varidx[j] >= 0 )
16725  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16726  }
16727  }
16728  }
16729 
16730  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16731  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16732  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16733  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16734  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16735 
16736  *nexprtrees = ncomponents;
16737 
16738  return SCIP_OKAY;
16739 }
16740 
16741 /** returns how often expression graph variables are used in a subtree of the expression graph */
16743  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16744  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
16745  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16746  )
16747 {
16748  assert(exprgraph != NULL);
16749  assert(node != NULL);
16750  assert(varsusage != NULL);
16751 
16752  BMSclearMemoryArray(varsusage, exprgraph->nvars);
16753 
16754  exprgraphNodeGetVarsUsage(node, varsusage);
16755 }
16756 
16757 /** gives the number of summands which the expression of an expression graph node consists of */
16759  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
16760  )
16761 {
16762  switch( node->op )
16763  {
16764  case SCIP_EXPR_PLUS:
16765  case SCIP_EXPR_MINUS:
16766  return 2;
16767 
16768  case SCIP_EXPR_SUM:
16769  case SCIP_EXPR_LINEAR:
16770  return node->nchildren;
16771 
16772  case SCIP_EXPR_QUADRATIC:
16773  {
16775 
16776  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16777  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16778  }
16779 
16780  case SCIP_EXPR_POLYNOMIAL:
16781  {
16783 
16784  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16785  return nodedata->nmonomials;
16786  }
16787 
16788  default:
16789  return 1;
16790  } /*lint !e788*/
16791 }
16792 
16793 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
16795  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16796  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16797  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16798  int* nexprtrees, /**< buffer to store number of expression trees */
16799  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16800  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16801  )
16802 {
16803  int* varidx;
16804  int nexprvars;
16805  int i;
16806 
16807  assert(exprgraph != NULL);
16808  assert(node != NULL);
16809  assert(node->depth >= 0);
16810  assert(node->pos >= 0);
16811  assert(exprtreessize > 0);
16812  assert(nexprtrees != NULL);
16813  assert(exprtrees != NULL);
16814  assert(exprtreecoefs != NULL);
16815 
16816  /* if node is not separable, fallback to SCIPexprgraphGetTree */
16817  if( node->op != SCIP_EXPR_PLUS &&
16818  node->op != SCIP_EXPR_MINUS &&
16819  node->op != SCIP_EXPR_SUM &&
16820  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16821  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16822  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16823  {
16824  *nexprtrees = 1;
16825  exprtreecoefs[0] = 1.0;
16826  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16827 
16828  return SCIP_OKAY;
16829  }
16830 
16831  switch( node->op )
16832  {
16833  case SCIP_EXPR_PLUS:
16834  {
16835  assert(exprtreessize >= 2);
16836 
16837  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16838  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16839 
16840  exprtreecoefs[0] = 1.0;
16841  exprtreecoefs[1] = 1.0;
16842 
16843  *nexprtrees = 2;
16844  break;
16845  }
16846 
16847  case SCIP_EXPR_MINUS:
16848  {
16849  assert(exprtreessize >= 2);
16850 
16851  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16852  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16853 
16854  exprtreecoefs[0] = 1.0;
16855  exprtreecoefs[1] = -1.0;
16856 
16857  *nexprtrees = 2;
16858  break;
16859  }
16860 
16861  case SCIP_EXPR_SUM:
16862  {
16863  assert(exprtreessize >= node->nchildren);
16864 
16865  for( i = 0; i < node->nchildren; ++i )
16866  {
16867  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16868  exprtreecoefs[i] = 1.0;
16869  }
16870 
16871  *nexprtrees = node->nchildren;
16872  break;
16873  }
16874 
16875  case SCIP_EXPR_LINEAR:
16876  {
16877  SCIP_Real* nodecoefs;
16878 
16879  assert(exprtreessize >= node->nchildren);
16880  assert(node->nchildren > 0);
16881 
16882  nodecoefs = (SCIP_Real*)node->data.data;
16883  assert(nodecoefs != NULL);
16884 
16885  for( i = 0; i < node->nchildren; ++i )
16886  {
16887  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16888  exprtreecoefs[i] = nodecoefs[i];
16889  }
16890 
16891  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16892  if( nodecoefs[node->nchildren] != 0.0 )
16893  {
16894  SCIP_EXPR* constexpr_;
16895 
16896  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16897  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16898  }
16899 
16900  *nexprtrees = node->nchildren;
16901  break;
16902  }
16903 
16904  case SCIP_EXPR_QUADRATIC:
16905  {
16907  SCIP_Real* lincoefs;
16908  SCIP_QUADELEM* quadelems;
16909  int nquadelems;
16910  SCIP_EXPR* expr;
16911  int j;
16912 
16913  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16914  lincoefs = nodedata->lincoefs;
16915  quadelems = nodedata->quadelems;
16916  nquadelems = nodedata->nquadelems;
16917 
16918  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16919  assert(node->nchildren > 0);
16920 
16921  *nexprtrees = 0;
16922  if( lincoefs != NULL )
16923  {
16924  for( i = 0; i < node->nchildren; ++i )
16925  {
16926  if( lincoefs[i] == 0.0 )
16927  continue;
16928  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16929  exprtreecoefs[*nexprtrees] = lincoefs[i];
16930  ++*nexprtrees;
16931  }
16932  }
16933 
16934  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16935  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16936 
16937  for( i = 0; i < nquadelems; ++i )
16938  {
16939  /* initially, no variable appears in the expression tree */
16940  for( j = 0; j < exprgraph->nvars; ++j )
16941  varidx[j] = -1; /*lint !e644*/
16942  nexprvars = 0;
16943 
16944  /* create expression from the subgraph at quadelems[i].idx1 */
16945  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16946 
16947  if( quadelems[i].idx1 == quadelems[i].idx2 )
16948  {
16949  /* create expression for square of expr */
16950  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16951  }
16952  else
16953  {
16954  SCIP_EXPR* expr2;
16955 
16956  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16957  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16958  /* create expression for product */
16959  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16960  }
16961 
16962  /* create expression tree for expr */
16963  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16964 
16965  /* copy variables into expression tree */
16966  if( nexprvars > 0 )
16967  {
16968  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16969  for( j = 0; j < exprgraph->nvars; ++j )
16970  {
16971  assert(varidx[j] >= -1);
16972  assert(varidx[j] < nexprvars);
16973  if( varidx[j] >= 0 )
16974  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16975  }
16976  }
16977 
16978  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16979 
16980  ++*nexprtrees;
16981  }
16982 
16983  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16984  if( nodedata->constant != 0.0 )
16985  {
16986  SCIP_EXPR* constexpr_;
16987 
16988  assert(*nexprtrees > 0);
16989  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16990  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16991  }
16992 
16993  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16994 
16995  break;
16996  }
16997 
16998  case SCIP_EXPR_POLYNOMIAL:
16999  {
17001  SCIP_EXPRDATA_MONOMIAL** monomials;
17002  SCIP_Real constant;
17003  int nmonomials;
17004  SCIP_EXPR* expr;
17005  int* childidxs;
17006  int j;
17007 
17008  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
17009  monomials = nodedata->monomials;
17010  nmonomials = nodedata->nmonomials;
17011  constant = nodedata->constant;
17012 
17013  assert(exprtreessize >= nmonomials);
17014  assert(node->nchildren > 0);
17015 
17016  *nexprtrees = 0;
17017 
17018  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
17019  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
17020 
17021  for( i = 0; i < nmonomials; ++i )
17022  {
17023  /* initially, no variable appears in the expression tree */
17024  for( j = 0; j < exprgraph->nvars; ++j )
17025  varidx[j] = -1;
17026  nexprvars = 0;
17027 
17028  if( monomials[i]->nfactors == 1 )
17029  {
17030  /* create expression from the subgraph at only factor */
17031  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17032 
17033  /* put exponent in, if not 1.0 */
17034  if( monomials[i]->exponents[0] == 1.0 )
17035  ;
17036  else if( monomials[i]->exponents[0] == 2.0 )
17037  {
17038  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
17039  }
17040  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
17041  {
17042  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
17043  }
17044  else
17045  {
17046  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
17047  }
17048  }
17049  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
17050  {
17051  SCIP_EXPR* expr2;
17052 
17053  /* create expressions for both factors */
17054  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
17055  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
17056 
17057  /* create expression for product of factors */
17058  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
17059  }
17060  else
17061  {
17062  SCIP_EXPRDATA_MONOMIAL* monomial;
17063  SCIP_EXPR** exprs;
17064  int f;
17065 
17066  /* create expression for each factor, assemble varidx and nexprvars
17067  * create child indices (= identity) */
17068  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
17069  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
17070  for( f = 0; f < monomials[i]->nfactors; ++f )
17071  {
17072  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
17073  childidxs[f] = f; /*lint !e644*/
17074  }
17075 
17076  /* create monomial and polynomial expression for this monomial
17077  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
17078  */
17079  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
17080  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
17081  constant = 0.0;
17082 
17083  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
17084  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
17085  }
17086 
17087  /* create expression tree for expr */
17088  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
17089 
17090  /* copy variables into expression tree */
17091  if( nexprvars > 0 )
17092  {
17093  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
17094  for( j = 0; j < exprgraph->nvars; ++j )
17095  {
17096  assert(varidx[j] >= -1);
17097  assert(varidx[j] < nexprvars);
17098  if( varidx[j] >= 0 )
17099  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
17100  }
17101  }
17102 
17103  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
17104 
17105  ++*nexprtrees;
17106  }
17107 
17108  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
17109  if( constant != 0.0 )
17110  {
17111  SCIP_EXPR* constexpr_;
17112 
17113  assert(*nexprtrees > 0);
17114  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
17115  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
17116  }
17117 
17118  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
17119 
17120  break;
17121  }
17122 
17123  default:
17124  SCIPerrorMessage("unexpected operator type %d\n", node->op);
17125  return SCIP_ERROR;
17126  } /*lint !e788*/
17127 
17128  return SCIP_OKAY;
17129 }
17130 
17131 /**@} */
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:13356
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15862
void SCIPexprFreeDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6187
void SCIPexprtreeGetVarsUsage(SCIP_EXPRTREE *tree, int *varsusage)
Definition: expr.c:8909
void SCIPquadelemSort(SCIP_QUADELEM *quadelems, int nquadelems)
Definition: expr.c:9213
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15543
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:9094
void SCIPintervalMax(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:459
SCIP_EXPROPDATA data
Definition: struct_expr.h:51
static void exprgraphSortConstNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:9669
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14998
static SCIP_RETCODE exprgraphNodeAddParent(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9346
SCIP_RETCODE SCIPexprSubstituteVars(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR **substexprs)
Definition: expr.c: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:15198
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:9091
static SCIP_RETCODE eval(SCIP_EXPR *expr, const vector< Type > &x, SCIP_Real *param, Type &val)
static SCIP_RETCODE exprsimplifyRemoveDuplicatePolynomialChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps)
Definition: expr.c:4292
SCIP_RETCODE SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16794
SCIP_RETCODE SCIPexprtreeEvalInt(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_INTERVAL *val)
Definition: expr.c:8741
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:15282
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:140
methods to interpret (evaluate) an expression tree "fast"
void SCIPexprtreePrint(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, const char **paramnames)
Definition: expr.c:8758
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5924
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:14787
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:9492
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12992
static SCIP_RETCODE exprgraphNodeCreateExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPR **expr, int *nexprvars, int *varidx)
Definition: expr.c:11807
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c: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:14968
static SCIP_RETCODE exprgraphEnsureDepth(SCIP_EXPRGRAPH *exprgraph, int mindepth)
Definition: expr.c:12081
#define SCIP_MAXSTRLEN
Definition: def.h:279
static void polynomialdataSortMonomials(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata)
Definition: expr.c:801
static SCIP_RETCODE exprgraphNodeSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange)
Definition: expr.c:11477
#define SCIP_VARTYPE_INTEGER_CHAR
Definition: def.h:135
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
SCIP_Real * exponents
Definition: struct_expr.h:95
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c: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:14938
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:11408
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:15355
SCIP_RETCODE SCIPexprtreeGetMaxDegree(SCIP_EXPRTREE *tree, int *maxdegree)
Definition: expr.c:8712
SCIP_Real * SCIPexprtreeGetParamVals(SCIP_EXPRTREE *tree)
Definition: expr.c:8634
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:15042
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:12970
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:13485
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:15916
#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:14988
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:12020
static SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11350
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13121
#define TRUE
Definition: def.h:72
#define SCIPdebug(x)
Definition: pub_message.h:84
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static int calcGrowSize(int num)
Definition: expr.c:107
static SCIP_RETCODE exprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op, int nchildren, SCIP_EXPR **children, SCIP_EXPROPDATA opdata)
Definition: expr.c:3294
SCIP_RETCODE SCIPexprtreeCopy(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **targettree, SCIP_EXPRTREE *sourcetree)
Definition: expr.c:8814
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13012
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:13346
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15841
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:14948
#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:15402
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:8773
SCIP_Bool SCIPquadelemSortedFind(SCIP_QUADELEM *quadelems, int idx1, int idx2, int nquadelems, int *pos)
Definition: expr.c:9238
unsigned int SCIP_EXPRINTCAPABILITY
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8644
BMS_BLKMEM * blkmem
Definition: struct_expr.h:157
SCIP_EXPRCURV curv
Definition: struct_expr.h:144
SCIP_EXPR * root
Definition: struct_expr.h:58
#define exprevalIntTan
Definition: expr.c:2122
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:15149
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13215
int nchildren
Definition: struct_expr.h:49
static void exprgraphPrintNodeDot(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:10040
real eps
#define SCIP_EXPRESSION_MAXCHILDEST
Definition: expr.c:41
static void exprgraphUpdateVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Bool *clearreverseprop, SCIP_Bool *boundchanged)
Definition: expr.c:12857
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:14421
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:9012
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13052
static SCIP_RETCODE exprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op, SCIP_EXPROPDATA opdata)
Definition: expr.c:9740
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13203
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:15110
#define SCIP_ALLOC_ABORT(x)
Definition: def.h:360
#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:13062
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:13143
#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:13227
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:14672
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13366
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:15744
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:15010
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:15948
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:13555
SCIP_Real * SCIPexprGetQuadLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5844
SCIP_EXPRGRAPHNODE *** SCIPexprgraphGetNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14958
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16758
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:13334
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:9593
void SCIPmessagePrintWarning(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:418
SCIP_EXPRGRAPHNODE *** nodes
Definition: struct_expr.h:162
SCIP_EXPORT SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
#define EXPROPEMPTY
Definition: expr.c:3214
internal miscellaneous methods
#define NULL
Definition: lpi_spx1.cpp:155
void SCIPrandomFree(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem)
Definition: misc.c:9943
static SCIP_Bool exprgraphNodeIsParent(SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9461
static void polynomialdataFree(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata)
Definition: expr.c:713
#define REALABS(x)
Definition: def.h:187
void SCIPexprMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:6809
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:8614
SCIP_Bool SCIPexprAreMonomialsEqual(SCIP_EXPRDATA_MONOMIAL *monomial1, SCIP_EXPRDATA_MONOMIAL *monomial2, SCIP_Real eps)
Definition: expr.c: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:13459
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16308
#define SCIP_CALL(x)
Definition: def.h:370
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12982
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:15102
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:14725
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:10147
#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:8604
SCIP_RETCODE SCIPexprCreateUser(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_USEREXPRDATA *data, SCIP_EXPRINTCAPABILITY evalcapability, SCIP_DECL_USEREXPREVAL((*eval)), SCIP_DECL_USEREXPRINTEVAL((*inteval)), SCIP_DECL_USEREXPRCURV((*curv)), SCIP_DECL_USEREXPRPROP((*prop)), SCIP_DECL_USEREXPRESTIMATE((*estimate)), SCIP_DECL_USEREXPRCOPYDATA((*copydata)), SCIP_DECL_USEREXPRFREEDATA((*freedata)), SCIP_DECL_USEREXPRPRINT((*print)))
Definition: expr.c:7157
SCIP_Bool SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14637
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:13242
#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:13073
#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:13155
#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:10082
SCIP_USEREXPRDATA * userdata
Definition: struct_expr.h:103
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14656
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:15062
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:9401
BMS_BLKMEM * blkmem
Definition: struct_expr.h:57
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8659
SCIP_RETCODE SCIPexprtreeFreeInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8682
void SCIPintervalSolveBivariateQuadExpressionAllScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real ax, SCIP_Real ay, SCIP_Real axy, SCIP_Real bx, SCIP_Real by, SCIP_INTERVAL rhs, SCIP_INTERVAL xbnds, SCIP_INTERVAL ybnds)
#define BMSfreeBlockMemoryArray(mem, ptr, num)
Definition: memory.h:458
void SCIPquadelemSqueeze(SCIP_QUADELEM *quadelems, int nquadelems, int *nquadelemsnew)
Definition: expr.c:9290
SCIP_Bool SCIPexprHasUserEstimator(SCIP_EXPR *expr)
Definition: expr.c: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:16742
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:15082
static SCIP_Bool exprgraphFindConstNodePos(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *pos)
Definition: expr.c:9685
void SCIPintervalSquare(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprgraphNodeSplitOffLinear(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, int linvarssize, int *nlinvars, void **linvars, SCIP_Real *lincoefs, SCIP_Real *constant)
Definition: expr.c:13609
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:8854
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:14547
void SCIPintervalAdd(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static void exprgraphNodePropagateBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool *cutoff)
Definition: expr.c:10241
#define SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED
Definition: type_expr.h:212
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14599
#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:8983
#define SCIP_EXPR_DEGREEINFINITY
Definition: type_expr.h:116
SCIP_EXPROPDATA data
Definition: struct_expr.h:120
SCIP_EXPRGRAPHNODE ** parents
Definition: struct_expr.h:133
static long * number
void SCIPintervalAbs(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define BMSclearMemory(ptr)
Definition: memory.h:121
SCIP_Real SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c: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:13084
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:13167
#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:13110
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13022
SCIP_QUADELEM * quadelems
Definition: struct_expr.h:71
static void exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:9375
#define EPSLT(x, y, eps)
Definition: def.h:189
#define SCIP_DECL_EXPRGRAPHVARREMOVE(x)
Definition: type_expr.h:193
static SCIP_RETCODE exprgraphAddExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPR *expr, void **vars, SCIP_Real *params, SCIP_EXPRGRAPHNODE **exprnode, SCIP_Bool *exprnodeisnew)
Definition: expr.c:12725
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:15715
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8208
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13132
#define SCIP_EXPRINTCAPABILITY_FUNCVALUE
SCIP_Real * SCIPexprGetLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5793
SCIP_Bool SCIPexprtreeHasParam(SCIP_EXPRTREE *tree)
Definition: expr.c:8696
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Real SCIPexprGetOpReal(SCIP_EXPR *expr)
Definition: expr.c:5738
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13042
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:13536
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:13511
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:13322
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:13376
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:14453
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
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:8928
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:16255
#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:391
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:13002
#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:14709
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:9047
SCIP_RETCODE SCIPexprParse(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR **expr, const char *str, const char *lastchar, int *nvars, int *varnames, int varnameslength)
Definition: expr.c:8540
#define SCIPisFinite(x)
Definition: pub_misc.h:1861
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:10126
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:134
int SCIPexprtreeGetNParams(SCIP_EXPRTREE *tree)
Definition: expr.c:8624
SCIP_RETCODE SCIPexprgraphSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange, SCIP_Bool *domainerror)
Definition: expr.c:15991
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:12161
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:13099
#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:13191
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:10674
#define SCIP_ALLOC_TERMINATE(retcode, x, TERM)
Definition: def.h:401
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:349
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14978
#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:381
#define SCIPABORT()
Definition: def.h:342
SCIP_Real SCIPexprGetLinearConstant(SCIP_EXPR *expr)
Definition: expr.c:5806
void SCIPexprtreeSetInterpreterData(SCIP_EXPRTREE *tree, SCIP_EXPRINTDATA *interpreterdata)
Definition: expr.c:8669
SCIP_EXPRCURV SCIPexprcurvAdd(SCIP_EXPRCURV curv1, SCIP_EXPRCURV curv2)
Definition: expr.c:206
struct SCIP_ExprIntData SCIP_EXPRINTDATA
static void quadelemsQuickSort(SCIP_QUADELEM *elems, int start, int end)
Definition: expr.c:9103
static SCIP_RETCODE polynomialdataEnsureMonomialsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int minsize)
Definition: expr.c:742
SCIP_RETCODE SCIPexprtreeSetParams(SCIP_EXPRTREE *tree, int nparams, SCIP_Real *paramvals)
Definition: expr.c:8878
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
int SCIPexprGetNQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5856
static void exprgraphPrintNodeExpression(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, SCIP_Bool printchildrenbounds)
Definition: expr.c:9784
#define SCIP_DECL_USEREXPRFREEDATA(x)
Definition: type_expr.h:301
static SCIP_RETCODE exprgraphFindParentByOperator(SCIP_EXPRGRAPH *exprgraph, int nchildren, SCIP_EXPRGRAPHNODE **children, SCIP_EXPROP op, SCIP_EXPROPDATA opdata, SCIP_EXPR **exprchildren, SCIP_EXPRGRAPHNODE **parent)
Definition: expr.c:12257
static void exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:11995
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15792
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:13032
#define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize)
Definition: expr.c:53
SCIP_EXPRCURV SCIPexprcurvNegate(SCIP_EXPRCURV curvature)
Definition: expr.c:215
SCIP_RETCODE SCIPexprtreeEval(SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
Definition: expr.c:8725
SCIP_EXPRINTCAPABILITY evalcapability
Definition: struct_expr.h:104
void SCIPexprgraphSetVarBounds(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_INTERVAL varbounds)
Definition: expr.c:15022
static SCIP_RETCODE exprgraphRemoveVar(SCIP_EXPRGRAPH *exprgraph, int varidx)
Definition: expr.c:12108
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:14572
SCIP_RETCODE SCIPhashmapSetImageInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3297
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13179