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-2017 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file nlpi/expr.c
17  * @brief methods for expressions, expression trees, expression graphs, and related
18  * @author Stefan Vigerske
19  * @author Thorsten Gellermann
20  * @author Ingmar Vierhaus (exprparse)
21  */
22 
23 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24 
25 #include <stdarg.h>
26 #include <string.h>
27 #include <math.h>
28 #include <ctype.h>
29 
30 #include "nlpi/pub_expr.h"
31 #include "nlpi/struct_expr.h"
32 #include "nlpi/exprinterpret.h"
33 
34 #include "scip/intervalarith.h"
35 #include "scip/pub_misc.h"
36 #include "scip/pub_message.h"
37 
38 
39 #define SCIP_EXPRESSION_MAXCHILDEST 16 /**< estimate on maximal number of children */
40 #define DEFAULT_RANDSEED 73 /**< initial random seed */
41 
42 /** sign of a value (-1 or +1)
43  *
44  * 0.0 has sign +1
45  */
46 #define SIGN(x) ((x) >= 0.0 ? 1.0 : -1.0)
47 
48 /** ensures that a block memory array has at least a given size
49  *
50  * if cursize is 0, then *array1 can be NULL
51  */
52 #define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize) \
53  do { \
54  int __newsize; \
55  assert((blkmem) != NULL); \
56  if( *(cursize) >= (minsize) ) \
57  break; \
58  __newsize = calcGrowSize(minsize); \
59  assert(__newsize >= (minsize)); \
60  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
61  *(cursize) = __newsize; \
62  } while( FALSE )
63 
64 #ifdef SCIP_DISABLED_CODE /* this macro is currently not used, which offends lint, so disable it */
65 /** ensures that two block memory arrays have at least a given size
66  *
67  * if cursize is 0, then arrays can be NULL
68  */
69 #define ensureBlockMemoryArraySize2(blkmem, array1, array2, cursize, minsize) \
70  do { \
71  int __newsize; \
72  assert((blkmem) != NULL); \
73  if( *(cursize) >= (minsize) ) \
74  break; \
75  __newsize = calcGrowSize(minsize); \
76  assert(__newsize >= (minsize)); \
77  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
78  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
79  *(cursize) = __newsize; \
80  } while( FALSE )
81 #endif
82 
83 /** ensures that three block memory arrays have at least a given size
84  *
85  * if cursize is 0, then arrays can be NULL
86  */
87 #define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize) \
88  do { \
89  int __newsize; \
90  assert((blkmem) != NULL); \
91  if( *(cursize) >= (minsize) ) \
92  break; \
93  __newsize = calcGrowSize(minsize); \
94  assert(__newsize >= (minsize)); \
95  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array1, *(cursize), __newsize) ); \
96  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array2, *(cursize), __newsize) ); \
97  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, array3, *(cursize), __newsize) ); \
98  *(cursize) = __newsize; \
99  } while( FALSE )
100 
101 /**@name Miscellaneous private methods */
102 /**@{ */
103 
104 /** calculate memory size for dynamically allocated arrays (copied from scip/set.c) */
105 static
107  int num /**< minimum number of entries to store */
108  )
109 {
110  int size;
111 
112  /* calculate the size with this loop, such that the resulting numbers are always the same (-> block memory) */
113  size = 4;
114  while( size < num )
115  size = (int)(1.2 * size + 4);
116 
117  return size;
118 }
119 
120 /** expression graph nodes comparison to use in sorting methods
121  *
122  * The nodes need to have been added to the expression graph (depth,pos >= 0).
123  * The better node is the one with the lower depth and lower position, if depth is equal.
124  */
125 static
126 SCIP_DECL_SORTPTRCOMP(exprgraphnodecomp)
127 {
128  SCIP_EXPRGRAPHNODE* node1 = (SCIP_EXPRGRAPHNODE*)elem1;
129  SCIP_EXPRGRAPHNODE* node2 = (SCIP_EXPRGRAPHNODE*)elem2;
130 
131  assert(node1 != NULL);
132  assert(node2 != NULL);
133  assert(node1->depth >= 0);
134  assert(node1->pos >= 0);
135  assert(node2->depth >= 0);
136  assert(node2->pos >= 0);
137 
138  if( node1->depth != node2->depth )
139  return node1->depth - node2->depth;
140 
141  /* there should be no two nodes on the same position */
142  assert((node1->pos != node2->pos) || (node1 == node2));
143 
144  return node1->pos - node2->pos;
145 }
146 
147 /** checks if a given new lower bound is tighter (w.r.t. given bound strengthening epsilon) than the old one (copied from scip/set.c) */
148 static
150  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
151  SCIP_Real newlb, /**< new lower bound */
152  SCIP_Real oldlb, /**< old lower bound */
153  SCIP_Real oldub /**< old upper bound */
154  )
155 {
156  SCIP_Real eps;
157 
158  /* nothing can be tighter than an empty interval */
159  if( oldlb > oldub )
160  return FALSE;
161 
162  eps = REALABS(oldlb);
163  eps = MIN(oldub - oldlb, eps);
164  return EPSGT(newlb, oldlb, minstrength * MAX(eps, 1e-3));
165 }
166 
167 /** checks if a given new upper bound is tighter (w.r.t. given bound strengthening epsilon) than the old one (copied from scip/set.c) */
168 static
170  SCIP_Real minstrength, /**< minimal relative improvement required to be a better bound */
171  SCIP_Real newub, /**< new upper bound */
172  SCIP_Real oldlb, /**< old lower bound */
173  SCIP_Real oldub /**< old upper bound */
174  )
175 {
176  SCIP_Real eps;
177 
178  /* nothing can be tighter than an empty interval */
179  if( oldlb > oldub )
180  return FALSE;
181 
182  eps = REALABS(oldub);
183  eps = MIN(oldub - oldlb, eps);
184  return EPSLT(newub, oldub, minstrength * MAX(eps, 1e-3));
185 }
186 
187 /**@} */
188 
189 /**@name Expression curvature methods */
190 /**@{ */
191 
192 /** curvature names as strings */
193 static
194 const char* curvnames[4] =
195  {
196  "unknown",
197  "convex",
198  "concave",
199  "linear"
200  };
201 
202 #undef SCIPexprcurvAdd
203 
204 /** gives curvature for a sum of two functions with given curvature */
206  SCIP_EXPRCURV curv1, /**< curvature of first summand */
207  SCIP_EXPRCURV curv2 /**< curvature of second summand */
208  )
209 {
210  return (SCIP_EXPRCURV) (curv1 & curv2);
211 }
212 
213 /** gives the curvature for the negation of a function with given curvature */
215  SCIP_EXPRCURV curvature /**< curvature of function */
216  )
217 {
218  switch( curvature )
219  {
221  return SCIP_EXPRCURV_CONVEX;
222 
224  return SCIP_EXPRCURV_CONCAVE;
225 
228  /* can return curvature, do this below */
229  break;
230 
231  default:
232  SCIPerrorMessage("unknown curvature status.\n");
233  SCIPABORT();
234  }
235 
236  return curvature;
237 }
238 
239 /** gives curvature for a functions with given curvature multiplied by a constant factor */
241  SCIP_Real factor, /**< constant factor */
242  SCIP_EXPRCURV curvature /**< curvature of other factor */
243  )
244 {
245  if( factor == 0.0 )
246  return SCIP_EXPRCURV_LINEAR;
247  if( factor > 0.0 )
248  return curvature;
249  return SCIPexprcurvNegate(curvature);
250 }
251 
252 /** gives curvature for base^exponent for given bounds and curvature of base-function and constant exponent */
254  SCIP_INTERVAL basebounds, /**< bounds on base function */
255  SCIP_EXPRCURV basecurv, /**< curvature of base function */
256  SCIP_Real exponent /**< exponent */
257  )
258 {
259  SCIP_Bool expisint;
260 
261  assert(basebounds.inf <= basebounds.sup);
262 
263  if( exponent == 0.0 )
264  return SCIP_EXPRCURV_LINEAR;
265 
266  if( exponent == 1.0 )
267  return basecurv;
268 
269  expisint = EPSISINT(exponent, 0.0); /*lint !e835*/
270 
271  /* if exponent is fractional, then power is not defined for a negative base
272  * thus, consider only positive part of basebounds
273  */
274  if( !expisint && basebounds.inf < 0.0 )
275  {
276  basebounds.inf = 0.0;
277  if( basebounds.sup < 0.0 )
278  return SCIP_EXPRCURV_LINEAR;
279  }
280 
281  /* if basebounds contains 0.0, consider negative and positive interval separately, if possible */
282  if( basebounds.inf < 0.0 && basebounds.sup > 0.0 )
283  {
284  SCIP_INTERVAL leftbounds;
285  SCIP_INTERVAL rightbounds;
286 
287  /* something like x^(-2) may look convex on each side of zero, but is not convex on the whole interval due to the singularity at 0.0 */
288  if( exponent < 0.0 )
289  return SCIP_EXPRCURV_UNKNOWN;
290 
291  SCIPintervalSetBounds(&leftbounds, basebounds.inf, 0.0);
292  SCIPintervalSetBounds(&rightbounds, 0.0, basebounds.sup);
293 
294  return (SCIP_EXPRCURV) (SCIPexprcurvPower(leftbounds, basecurv, exponent) & SCIPexprcurvPower(rightbounds, basecurv, exponent));
295  }
296  assert(basebounds.inf >= 0.0 || basebounds.sup <= 0.0);
297 
298  /* (base^exponent)'' = exponent * ( (exponent-1) base^(exponent-2) (base')^2 + base^(exponent-1) base'' )
299  *
300  * if base'' is positive, i.e., base is convex, then
301  * - for base > 0.0 and exponent > 1.0, the second deriv. is positive -> convex
302  * - for base < 0.0 and exponent > 1.0, we can't say (first and second summand opposite signs)
303  * - for base > 0.0 and 0.0 < exponent < 1.0, we can't say (first sommand negative, second summand positive)
304  * - for base > 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
305  * - for base < 0.0 and exponent < 0.0 and even, the second deriv. is positive -> convex
306  * - for base < 0.0 and exponent < 0.0 and odd, the second deriv. is negative -> concave
307  *
308  * if base'' is negative, i.e., base is concave, then
309  * - for base > 0.0 and exponent > 1.0, we can't say (first summand positive, second summand negative)
310  * - for base < 0.0 and exponent > 1.0 and even, the second deriv. is positive -> convex
311  * - for base < 0.0 and exponent > 1.0 and odd, the second deriv. is negative -> concave
312  * - for base > 0.0 and 0.0 < exponent < 1.0, the second deriv. is negative -> concave
313  * - for base > 0.0 and exponent < 0.0, the second deriv. is positive -> convex
314  * - for base < 0.0 and exponent < 0.0, we can't say (first and second summand opposite signs)
315  *
316  * if base'' is zero, i.e., base is linear, then
317  * (base^exponent)'' = exponent * (exponent-1) base^(exponent-2) (base')^2
318  * - just multiply signs
319  */
320 
321  if( basecurv == SCIP_EXPRCURV_LINEAR )
322  {
323  SCIP_Real sign;
324 
325  /* base^(exponent-2) is negative, if base < 0.0 and exponent is odd */
326  sign = exponent * (exponent - 1.0);
327  assert(basebounds.inf >= 0.0 || expisint);
328  if( basebounds.inf < 0.0 && ((int)exponent)%2 != 0 )
329  sign *= -1.0;
330  assert(sign != 0.0);
331 
332  return sign > 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
333  }
334 
335  if( basecurv == SCIP_EXPRCURV_CONVEX )
336  {
337  if( basebounds.sup <= 0.0 && exponent < 0.0 && expisint )
338  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
339  if( basebounds.inf >= 0.0 && exponent > 1.0 )
340  return SCIP_EXPRCURV_CONVEX ;
341  return SCIP_EXPRCURV_UNKNOWN;
342  }
343 
344  if( basecurv == SCIP_EXPRCURV_CONCAVE )
345  {
346  if( basebounds.sup <= 0.0 && exponent > 1.0 && expisint )
347  return ((int)exponent)%2 == 0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
348  if( basebounds.inf >= 0.0 && exponent < 1.0 )
349  return exponent < 0.0 ? SCIP_EXPRCURV_CONVEX : SCIP_EXPRCURV_CONCAVE;
350  return SCIP_EXPRCURV_UNKNOWN;
351  }
352 
353  return SCIP_EXPRCURV_UNKNOWN;
354 }
355 
356 /** gives curvature for a monomial with given curvatures and bounds for each factor
357  *
358  * See Maranas and Floudas, Finding All Solutions of Nonlinearly Constrained Systems of Equations, JOGO 7, 1995
359  * for the categorization in the case that all factors are linear.
360  */
362  int nfactors, /**< number of factors in monomial */
363  SCIP_Real* exponents, /**< exponents in monomial, or NULL if all 1.0 */
364  int* factoridxs, /**< indices of factors (but not exponents), or NULL if identity mapping */
365  SCIP_EXPRCURV* factorcurv, /**< curvature of each factor */
366  SCIP_INTERVAL* factorbounds /**< bounds of each factor */
367  )
368 {
369  SCIP_Real mult;
370  SCIP_Real e;
371  SCIP_EXPRCURV curv;
372  SCIP_EXPRCURV fcurv;
373  int nnegative;
374  int npositive;
375  SCIP_Real sum;
376  SCIP_Bool expcurvpos;
377  SCIP_Bool expcurvneg;
378  int j;
379  int f;
380 
381  assert(nfactors >= 0);
382  assert(factorcurv != NULL || nfactors == 0);
383  assert(factorbounds != NULL || nfactors == 0);
384 
385  if( nfactors == 0 )
386  return SCIP_EXPRCURV_LINEAR;
387 
388  if( nfactors == 1 )
389  {
390  f = factoridxs != NULL ? factoridxs[0] : 0;
391  e = exponents != NULL ? exponents[0] : 1.0;
392  /* SCIPdebugMessage("monomial [%g,%g]^%g is %s\n",
393  factorbounds[f].inf, factorbounds[f].sup, e,
394  SCIPexprcurvGetName(SCIPexprcurvPower(factorbounds[f], factorcurv[f], e))); */
395  return SCIPexprcurvPower(factorbounds[f], factorcurv[f], e); /*lint !e613*/
396  }
397 
398  mult = 1.0;
399 
400  nnegative = 0; /* number of negative exponents */
401  npositive = 0; /* number of positive exponents */
402  sum = 0.0; /* sum of exponents */
403  expcurvpos = TRUE; /* whether exp_j * f_j''(x) >= 0 for all factors (assuming f_j >= 0) */
404  expcurvneg = TRUE; /* whether exp_j * f_j''(x) <= 0 for all factors (assuming f_j >= 0) */
405 
406  for( j = 0; j < nfactors; ++j )
407  {
408  f = factoridxs != NULL ? factoridxs[j] : j;
409  if( factorcurv[f] == SCIP_EXPRCURV_UNKNOWN ) /*lint !e613*/
410  return SCIP_EXPRCURV_UNKNOWN;
411  if( factorbounds[f].inf < 0.0 && factorbounds[f].sup > 0.0 ) /*lint !e613*/
412  return SCIP_EXPRCURV_UNKNOWN;
413 
414  e = exponents != NULL ? exponents[j] : 1.0;
415  if( e < 0.0 )
416  ++nnegative;
417  else
418  ++npositive;
419  sum += e;
420 
421  if( factorbounds[f].inf < 0.0 ) /*lint !e613*/
422  {
423  /* if argument is negative, then exponent should be integer */
424  assert(EPSISINT(e, 0.0)); /*lint !e835*/
425 
426  /* flip j'th argument: (f_j)^(exp_j) = (-1)^(exp_j) (-f_j)^(exp_j) */
427 
428  /* -f_j has negated curvature of f_j */
429  fcurv = SCIPexprcurvNegate(factorcurv[f]); /*lint !e613*/
430 
431  /* negate monomial, if exponent is odd, i.e., (-1)^(exp_j) = -1 */
432  if( (int)e % 2 != 0 )
433  mult *= -1.0;
434  }
435  else
436  {
437  fcurv = factorcurv[f]; /*lint !e613*/
438  }
439 
440  /* check if exp_j * fcurv is convex (>= 0) and/or concave */
441  fcurv = SCIPexprcurvMultiply(e, fcurv);
442  if( !(fcurv & SCIP_EXPRCURV_CONVEX) )
443  expcurvpos = FALSE;
444  if( !(fcurv & SCIP_EXPRCURV_CONCAVE) )
445  expcurvneg = FALSE;
446  }
447 
448  /* if all factors are linear, then a product f_j^exp_j with f_j >= 0 is convex if
449  * - all exponents are negative, or
450  * - all except one exponent j* are negative and exp_j* >= 1 - sum_{j!=j*}exp_j, but the latter is equivalent to sum_j exp_j >= 1
451  * further, the product is concave if
452  * - all exponents are positive and the sum of exponents is <= 1.0
453  *
454  * if factors are nonlinear, then we require additionally, that for convexity
455  * - each factor is convex if exp_j >= 0, or concave if exp_j <= 0, i.e., exp_j*f_j'' >= 0
456  * and for concavity, we require that
457  * - all factors are concave, i.e., exp_j*f_j'' <= 0
458  */
459 
460  if( nnegative == nfactors && expcurvpos )
461  curv = SCIP_EXPRCURV_CONVEX;
462  else if( nnegative == nfactors-1 && EPSGE(sum, 1.0, 1e-9) && expcurvpos )
463  curv = SCIP_EXPRCURV_CONVEX;
464  else if( npositive == nfactors && EPSLE(sum, 1.0, 1e-9) && expcurvneg )
465  curv = SCIP_EXPRCURV_CONCAVE;
466  else
467  curv = SCIP_EXPRCURV_UNKNOWN;
468  curv = SCIPexprcurvMultiply(mult, curv);
469 
470  return curv;
471 }
472 
473 /** gives name as string for a curvature */
475  SCIP_EXPRCURV curv /**< curvature */
476  )
477 {
478  assert(curv <= SCIP_EXPRCURV_LINEAR); /*lint !e685*/
479 
480  return curvnames[curv];
481 }
482 
483 /**@} */
484 
485 /**@name Quadratic expression data private methods */
486 /**@{ */
487 
488 /** creates SCIP_EXPRDATA_QUADRATIC data structure from given quadratic elements */
489 static
491  BMS_BLKMEM* blkmem, /**< block memory data structure */
492  SCIP_EXPRDATA_QUADRATIC** quadraticdata, /**< buffer to store pointer to quadratic data */
493  SCIP_Real constant, /**< constant */
494  int nchildren, /**< number of children */
495  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
496  int nquadelems, /**< number of quadratic elements */
497  SCIP_QUADELEM* quadelems /**< quadratic elements */
498  )
499 {
500  assert(blkmem != NULL);
501  assert(quadraticdata != NULL);
502  assert(quadelems != NULL || nquadelems == 0);
503  assert(nchildren >= 0);
504 
505  SCIP_ALLOC( BMSallocBlockMemory(blkmem, quadraticdata) );
506 
507  (*quadraticdata)->constant = constant;
508  (*quadraticdata)->lincoefs = NULL;
509  (*quadraticdata)->nquadelems = nquadelems;
510  (*quadraticdata)->quadelems = NULL;
511  (*quadraticdata)->sorted = (nquadelems <= 1);
512 
513  if( lincoefs != NULL )
514  {
515  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->lincoefs, lincoefs, nchildren) );
516  }
517 
518  if( nquadelems > 0 )
519  {
520  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*quadraticdata)->quadelems, quadelems, nquadelems) );
521  }
522 
523  return SCIP_OKAY;
524 }
525 
526 /** sorts quadratic elements in a SCIP_EXPRDATA_QUADRATIC data structure */
527 static
529  SCIP_EXPRDATA_QUADRATIC* quadraticdata /**< quadratic data */
530  )
531 {
532  assert(quadraticdata != NULL);
533 
534  if( quadraticdata->sorted )
535  {
536 #ifndef NDEBUG
537  int i;
538  for( i = 1; i < quadraticdata->nquadelems; ++i )
539  {
540  assert(quadraticdata->quadelems[i].idx1 <= quadraticdata->quadelems[i].idx2);
541  assert(quadraticdata->quadelems[i-1].idx1 <= quadraticdata->quadelems[i].idx1);
542  assert(quadraticdata->quadelems[i-1].idx1 < quadraticdata->quadelems[i].idx1 ||
543  quadraticdata->quadelems[i-1].idx2 <= quadraticdata->quadelems[i].idx2);
544  }
545 #endif
546  return;
547  }
548 
549  if( quadraticdata->nquadelems > 0 )
550  SCIPquadelemSort(quadraticdata->quadelems, quadraticdata->nquadelems);
551 
552  quadraticdata->sorted = TRUE;
553 }
554 
555 /**@} */
556 
557 /**@name Polynomial expression data private methods */
558 /**@{ */
559 
560 /** compares two monomials
561  *
562  * gives 0 if monomials are equal */
563 static
564 SCIP_DECL_SORTPTRCOMP(monomialdataCompare)
565 {
566  SCIP_EXPRDATA_MONOMIAL* monomial1;
567  SCIP_EXPRDATA_MONOMIAL* monomial2;
568 
569  int i;
570 
571  assert(elem1 != NULL);
572  assert(elem2 != NULL);
573 
574  monomial1 = (SCIP_EXPRDATA_MONOMIAL*)elem1;
575  monomial2 = (SCIP_EXPRDATA_MONOMIAL*)elem2;
576 
577  /* make sure, both monomials are equal */
578  SCIPexprSortMonomialFactors(monomial1);
579  SCIPexprSortMonomialFactors(monomial2);
580 
581  /* for the first factor where both monomials differ,
582  * we return either the difference in the child indices, if children are different
583  * or the sign of the difference in the exponents
584  */
585  for( i = 0; i < monomial1->nfactors && i < monomial2->nfactors; ++i )
586  {
587  if( monomial1->childidxs[i] != monomial2->childidxs[i] )
588  return monomial1->childidxs[i] - monomial2->childidxs[i];
589  if( monomial1->exponents[i] > monomial2->exponents[i] )
590  return 1;
591  else if( monomial1->exponents[i] < monomial2->exponents[i] )
592  return -1;
593  }
594 
595  /* if the factors of one monomial are a proper subset of the factors of the other monomial,
596  * we return the difference in the number of monomials
597  */
598  return monomial1->nfactors - monomial2->nfactors;
599 }
600 
601 /** ensures that the factors arrays of a monomial have at least a given size */
602 static
604  BMS_BLKMEM* blkmem, /**< block memory data structure */
605  SCIP_EXPRDATA_MONOMIAL* monomialdata, /**< monomial data */
606  int minsize /**< minimal size of factors arrays */
607  )
608 {
609  assert(blkmem != NULL);
610  assert(monomialdata != NULL);
611 
612  if( minsize > monomialdata->factorssize )
613  {
614  int newsize;
615 
616  newsize = calcGrowSize(minsize);
617  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->childidxs, monomialdata->factorssize, newsize) );
618  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &monomialdata->exponents, monomialdata->factorssize, newsize) );
619  monomialdata->factorssize = newsize;
620  }
621  assert(minsize <= monomialdata->factorssize);
622 
623  return SCIP_OKAY;
624 }
625 
626 /** creates SCIP_EXPRDATA_POLYNOMIAL data structure from given monomials */
627 static
629  BMS_BLKMEM* blkmem, /**< block memory data structure */
630  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
631  int nmonomials, /**< number of monomials */
632  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
633  SCIP_Real constant, /**< constant part */
634  SCIP_Bool copymonomials /**< whether to copy monomials, or copy only given pointers, in which case polynomialdata assumes ownership of monomial structure */
635  )
636 {
637  assert(blkmem != NULL);
638  assert(polynomialdata != NULL);
639  assert(monomials != NULL || nmonomials == 0);
640 
641  SCIP_ALLOC( BMSallocBlockMemory(blkmem, polynomialdata) );
642 
643  (*polynomialdata)->constant = constant;
644  (*polynomialdata)->nmonomials = nmonomials;
645  (*polynomialdata)->monomialssize = nmonomials;
646  (*polynomialdata)->monomials = NULL;
647  (*polynomialdata)->sorted = (nmonomials <= 1);
648 
649  if( nmonomials > 0 )
650  {
651  int i;
652 
653  if( copymonomials )
654  {
655  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, nmonomials) );
656 
657  for( i = 0; i < nmonomials; ++i )
658  {
659  assert(monomials[i] != NULL); /*lint !e613*/
660  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i],
661  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
662  }
663  }
664  else
665  {
666  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, monomials, nmonomials) );
667  }
668  }
669 
670  return SCIP_OKAY;
671 }
672 
673 /** creates a copy of a SCIP_EXPRDATA_POLYNOMIAL data structure */
674 static
676  BMS_BLKMEM* blkmem, /**< block memory data structure */
677  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata,/**< buffer to store pointer to polynomial data */
678  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata /**< polynomial data to copy */
679  )
680 {
681  assert(blkmem != NULL);
682  assert(polynomialdata != NULL);
683  assert(sourcepolynomialdata != NULL);
684 
685  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, polynomialdata, sourcepolynomialdata) );
686 
687  (*polynomialdata)->monomialssize = sourcepolynomialdata->nmonomials;
688  if( sourcepolynomialdata->nmonomials > 0 )
689  {
690  int i;
691 
692  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize) );
693 
694  for( i = 0; i < sourcepolynomialdata->nmonomials; ++i )
695  {
696  assert(sourcepolynomialdata->monomials[i] != NULL); /*lint !e613*/
697  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &(*polynomialdata)->monomials[i], sourcepolynomialdata->monomials[i]->coef,
698  sourcepolynomialdata->monomials[i]->nfactors, sourcepolynomialdata->monomials[i]->childidxs, sourcepolynomialdata->monomials[i]->exponents) );
699  (*polynomialdata)->monomials[i]->sorted = sourcepolynomialdata->monomials[i]->sorted;
700  }
701  }
702  else
703  {
704  (*polynomialdata)->monomials = NULL;
705  }
706 
707  return SCIP_OKAY;
708 }
709 
710 /** frees a SCIP_EXPRDATA_POLYNOMIAL data structure */
711 static
713  BMS_BLKMEM* blkmem, /**< block memory data structure */
714  SCIP_EXPRDATA_POLYNOMIAL** polynomialdata /**< pointer to polynomial data to free */
715  )
716 {
717  assert(blkmem != NULL);
718  assert(polynomialdata != NULL);
719  assert(*polynomialdata != NULL);
720 
721  if( (*polynomialdata)->monomialssize > 0 )
722  {
723  int i;
724 
725  for( i = 0; i < (*polynomialdata)->nmonomials; ++i )
726  {
727  assert((*polynomialdata)->monomials[i] != NULL);
728  SCIPexprFreeMonomial(blkmem, &(*polynomialdata)->monomials[i]);
729  assert((*polynomialdata)->monomials[i] == NULL);
730  }
731 
732  BMSfreeBlockMemoryArray(blkmem, &(*polynomialdata)->monomials, (*polynomialdata)->monomialssize);
733  }
734  assert((*polynomialdata)->monomials == NULL);
735 
736  BMSfreeBlockMemory(blkmem, polynomialdata);
737 }
738 
739 /** ensures that the monomials array of a polynomial has at least a given size */
740 static
742  BMS_BLKMEM* blkmem, /**< block memory data structure */
743  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
744  int minsize /**< minimal size of monomials array */
745  )
746 {
747  assert(blkmem != NULL);
748  assert(polynomialdata != NULL);
749 
750  ensureBlockMemoryArraySize(blkmem, &polynomialdata->monomials, &polynomialdata->monomialssize, minsize);
751  assert(minsize <= polynomialdata->monomialssize);
752 
753  return SCIP_OKAY;
754 }
755 
756 /** adds an array of monomials to a polynomial */
757 static
759  BMS_BLKMEM* blkmem, /**< block memory of expression */
760  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
761  int nmonomials, /**< number of monomials to add */
762  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
763  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
764  )
765 {
766  int i;
767 
768  assert(blkmem != NULL);
769  assert(polynomialdata != NULL);
770  assert(monomials != NULL || nmonomials == 0);
771 
772  if( nmonomials == 0 )
773  return SCIP_OKAY;
774 
775  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials + nmonomials) );
776  assert(polynomialdata->monomialssize >= polynomialdata->nmonomials + nmonomials);
777 
778  if( copymonomials )
779  {
780  for( i = 0; i < nmonomials; ++i )
781  {
782  assert(monomials[i] != NULL); /*lint !e613*/
783  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials + i],
784  monomials[i]->coef, monomials[i]->nfactors, monomials[i]->childidxs, monomials[i]->exponents) ); /*lint !e613*/
785  }
786  }
787  else
788  {
789  BMScopyMemoryArray(&polynomialdata->monomials[polynomialdata->nmonomials], monomials, nmonomials); /*lint !e866*/
790  }
791  polynomialdata->nmonomials += nmonomials;
792 
793  polynomialdata->sorted = (polynomialdata->nmonomials <= 1);
794 
795  return SCIP_OKAY;
796 }
797 
798 /** ensures that monomials of a polynomial are sorted */
799 static
801  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata /**< polynomial expression */
802  )
803 {
804  assert(polynomialdata != NULL);
805 
806  if( polynomialdata->sorted )
807  {
808 #ifndef NDEBUG
809  int i;
810 
811  /* a polynom with more than one monoms can only be sorted if its monoms are sorted */
812  for( i = 1; i < polynomialdata->nmonomials; ++i )
813  {
814  assert(polynomialdata->monomials[i-1]->sorted);
815  assert(polynomialdata->monomials[i]->sorted);
816  assert(monomialdataCompare(polynomialdata->monomials[i-1], polynomialdata->monomials[i]) <= 0);
817  }
818 #endif
819  return;
820  }
821 
822  if( polynomialdata->nmonomials > 0 )
823  SCIPsortPtr((void**)polynomialdata->monomials, monomialdataCompare, polynomialdata->nmonomials);
824 
825  polynomialdata->sorted = TRUE;
826 }
827 
828 /** merges monomials that differ only in coefficient into a single monomial
829  *
830  * Eliminates monomials with coefficient between -eps and eps.
831  */
832 static
834  BMS_BLKMEM* blkmem, /**< block memory */
835  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
836  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
837  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
838  )
839 {
840  int i;
841  int offset;
842  int oldnfactors;
843 
844  assert(polynomialdata != NULL);
845  assert(eps >= 0.0);
846 
847  polynomialdataSortMonomials(polynomialdata);
848 
849  /* merge monomials by adding their coefficients, eliminate monomials with no factors or zero coefficient*/
850  offset = 0;
851  i = 0;
852  while( i + offset < polynomialdata->nmonomials )
853  {
854  if( offset > 0 )
855  {
856  assert(polynomialdata->monomials[i] == NULL);
857  assert(polynomialdata->monomials[i+offset] != NULL);
858  polynomialdata->monomials[i] = polynomialdata->monomials[i+offset];
859 #ifndef NDEBUG
860  polynomialdata->monomials[i+offset] = NULL;
861 #endif
862  }
863 
864  if( mergefactors )
865  {
866  oldnfactors = polynomialdata->monomials[i]->nfactors;
867  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i], eps);
868 
869  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
870  if( oldnfactors != polynomialdata->monomials[i]->nfactors )
871  polynomialdata->sorted = FALSE;
872  }
873 
874  while( i+offset+1 < polynomialdata->nmonomials )
875  {
876  assert(polynomialdata->monomials[i+offset+1] != NULL);
877  if( mergefactors )
878  {
879  oldnfactors = polynomialdata->monomials[i+offset+1]->nfactors;
880  SCIPexprMergeMonomialFactors(polynomialdata->monomials[i+offset+1], eps);
881 
882  /* if monomial has changed, then we cannot assume anymore that polynomial is sorted */
883  if( oldnfactors != polynomialdata->monomials[i+offset+1]->nfactors )
884  polynomialdata->sorted = FALSE;
885  }
886  if( monomialdataCompare((void*)polynomialdata->monomials[i], (void*)polynomialdata->monomials[i+offset+1]) != 0 )
887  break;
888  polynomialdata->monomials[i]->coef += polynomialdata->monomials[i+offset+1]->coef;
889  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i+offset+1]);
890  ++offset;
891  }
892 
893  if( polynomialdata->monomials[i]->nfactors == 0 )
894  {
895  /* constant monomial */
896  polynomialdata->constant += polynomialdata->monomials[i]->coef;
897  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
898  ++offset;
899  continue;
900  }
901 
902  if( EPSZ(polynomialdata->monomials[i]->coef, eps) )
903  {
904  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
905  ++offset;
906  continue;
907  }
908 
909  ++i;
910  }
911 
912 #ifndef NDEBUG
913  for( ; i < polynomialdata->nmonomials; ++i )
914  assert(polynomialdata->monomials[i] == NULL);
915 #endif
916 
917  polynomialdata->nmonomials -= offset;
918 
919  if( EPSZ(polynomialdata->constant, eps) )
920  polynomialdata->constant = 0.0;
921 }
922 
923 /** multiplies each summand of a polynomial by a given constant */
924 static
926  BMS_BLKMEM* blkmem, /**< block memory */
927  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
928  SCIP_Real factor /**< constant factor */
929  )
930 {
931  int i;
932 
933  assert(polynomialdata != NULL);
934 
935  if( factor == 1.0 )
936  return;
937 
938  if( factor == 0.0 )
939  {
940  for( i = 0; i < polynomialdata->nmonomials; ++i )
941  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
942  polynomialdata->nmonomials = 0;
943  }
944  else
945  {
946  for( i = 0; i < polynomialdata->nmonomials; ++i )
947  SCIPexprChgMonomialCoef(polynomialdata->monomials[i], polynomialdata->monomials[i]->coef * factor);
948  }
949 
950  polynomialdata->constant *= factor;
951 }
952 
953 /** multiplies each summand of a polynomial by a given monomial */
954 static
956  BMS_BLKMEM* blkmem, /**< block memory */
957  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
958  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
959  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
960  )
961 {
962  int i;
963 
964  assert(blkmem != NULL);
965  assert(factor != NULL);
966  assert(polynomialdata != NULL);
967 
968  if( factor->nfactors == 0 )
969  {
970  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factor->coef);
971  return SCIP_OKAY;
972  }
973 
974  /* multiply each monomial by factor */
975  for( i = 0; i < polynomialdata->nmonomials; ++i )
976  {
977  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i], factor, childmap) );
978  }
979 
980  /* add new monomial for constant multiplied by factor */
981  if( polynomialdata->constant != 0.0 )
982  {
983  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
984  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
985  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[polynomialdata->nmonomials], factor, childmap) );
986  ++polynomialdata->nmonomials;
987  polynomialdata->sorted = FALSE;
988  polynomialdata->constant = 0.0;
989  }
990 
991  return SCIP_OKAY;
992 }
993 
994 /** multiplies a polynomial by a polynomial
995  *
996  * Factors need to be different.
997  */
998 static
1000  BMS_BLKMEM* blkmem, /**< block memory */
1001  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1002  SCIP_EXPRDATA_POLYNOMIAL* factordata, /**< polynomial factor data */
1003  int* childmap /**< map children in factor to children in polynomialdata, or NULL for 1:1 */
1004  )
1005 {
1006  int i1;
1007  int i2;
1008  int orignmonomials;
1009 
1010  assert(blkmem != NULL);
1011  assert(polynomialdata != NULL);
1012  assert(factordata != NULL);
1013  assert(polynomialdata != factordata);
1014 
1015  if( factordata->nmonomials == 0 )
1016  {
1017  polynomialdataMultiplyByConstant(blkmem, polynomialdata, factordata->constant);
1018  return SCIP_OKAY;
1019  }
1020 
1021  if( factordata->nmonomials == 1 && factordata->constant == 0.0 )
1022  {
1023  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, polynomialdata, factordata->monomials[0], childmap) );
1024  return SCIP_OKAY;
1025  }
1026 
1027  /* turn constant into a monomial, so we can assume below that constant is 0.0 */
1028  if( polynomialdata->constant != 0.0 )
1029  {
1030  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials+1) );
1031  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &polynomialdata->monomials[polynomialdata->nmonomials], polynomialdata->constant, 0, NULL, NULL) );
1032  ++polynomialdata->nmonomials;
1033  polynomialdata->sorted = FALSE;
1034  polynomialdata->constant = 0.0;
1035  }
1036 
1037  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, polynomialdata->nmonomials * (factordata->nmonomials + (factordata->constant == 0.0 ? 0 : 1))) );
1038 
1039  /* for each monomial in factordata (except the last, if factordata->constant is 0),
1040  * duplicate monomials from polynomialdata and multiply them by the monomial for factordata */
1041  orignmonomials = polynomialdata->nmonomials;
1042  for( i2 = 0; i2 < factordata->nmonomials; ++i2 )
1043  {
1044  /* add a copy of original monomials to end of polynomialdata's monomials array */
1045  assert(polynomialdata->nmonomials + orignmonomials <= polynomialdata->monomialssize); /* reallocating in polynomialdataAddMonomials would make the polynomialdata->monomials invalid, so assert that above the monomials array was made large enough */
1046  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, orignmonomials, polynomialdata->monomials, TRUE) );
1047  assert(polynomialdata->nmonomials == (i2+2) * orignmonomials);
1048 
1049  /* multiply each copied monomial by current monomial from factordata */
1050  for( i1 = (i2+1) * orignmonomials; i1 < (i2+2) * orignmonomials; ++i1 )
1051  {
1052  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1053  }
1054 
1055  if( factordata->constant == 0.0 && i2 == factordata->nmonomials - 2 )
1056  {
1057  ++i2;
1058  break;
1059  }
1060  }
1061 
1062  if( factordata->constant != 0.0 )
1063  {
1064  assert(i2 == factordata->nmonomials);
1065  /* multiply original monomials in polynomialdata by constant in factordata */
1066  for( i1 = 0; i1 < orignmonomials; ++i1 )
1067  SCIPexprChgMonomialCoef(polynomialdata->monomials[i1], polynomialdata->monomials[i1]->coef * factordata->constant);
1068  }
1069  else
1070  {
1071  assert(i2 == factordata->nmonomials - 1);
1072  /* multiply original monomials in polynomialdata by last monomial in factordata */
1073  for( i1 = 0; i1 < orignmonomials; ++i1 )
1074  {
1075  SCIP_CALL( SCIPexprMultiplyMonomialByMonomial(blkmem, polynomialdata->monomials[i1], factordata->monomials[i2], childmap) );
1076  }
1077  }
1078 
1079  return SCIP_OKAY;
1080 }
1081 
1082 /** takes a power of a polynomial
1083  *
1084  * Exponent needs to be an integer,
1085  * polynomial needs to be a monomial, if exponent is negative.
1086  */
1087 static
1089  BMS_BLKMEM* blkmem, /**< block memory */
1090  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1091  int exponent /**< exponent of power operation */
1092  )
1093 {
1094  SCIP_EXPRDATA_POLYNOMIAL* factor;
1095  int i;
1096 
1097  assert(blkmem != NULL);
1098  assert(polynomialdata != NULL);
1099 
1100  if( exponent == 0 )
1101  {
1102  /* x^0 = 1, except if x = 0 */
1103  if( polynomialdata->nmonomials == 0 && polynomialdata->constant == 0.0 )
1104  {
1105  polynomialdata->constant = 0.0;
1106  }
1107  else
1108  {
1109  polynomialdata->constant = 1.0;
1110 
1111  for( i = 0; i < polynomialdata->nmonomials; ++i )
1112  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[i]);
1113  polynomialdata->nmonomials = 0;
1114  }
1115 
1116  return SCIP_OKAY;
1117  }
1118 
1119  if( exponent == 1 )
1120  return SCIP_OKAY;
1121 
1122  if( polynomialdata->nmonomials == 1 && polynomialdata->constant == 0.0 )
1123  {
1124  /* polynomial is a single monomial */
1125  SCIPexprMonomialPower(polynomialdata->monomials[0], exponent);
1126  return SCIP_OKAY;
1127  }
1128 
1129  if( polynomialdata->nmonomials == 0 )
1130  {
1131  /* polynomial is a constant */
1132  polynomialdata->constant = pow(polynomialdata->constant, (SCIP_Real)exponent);
1133  return SCIP_OKAY;
1134  }
1135 
1136  assert(exponent >= 2); /* negative exponents not allowed if more than one monom */
1137 
1138  /* todo improve, look how SCIPintervalPowerScalar in intervalarith.c does it */
1139 
1140  /* get copy of our polynomial */
1141  SCIP_CALL( polynomialdataCopy(blkmem, &factor, polynomialdata) );
1142 
1143  /* do repeated multiplication */
1144  for( i = 2; i <= exponent; ++i )
1145  {
1146  SCIP_CALL( polynomialdataMultiplyByPolynomial(blkmem, polynomialdata, factor, NULL) );
1147  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
1148  }
1149 
1150  /* free copy again */
1151  polynomialdataFree(blkmem, &factor);
1152 
1153  return SCIP_OKAY;
1154 }
1155 
1156 /** applies a mapping of child indices to the indices used in polynomial monomials */
1157 static
1159  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data */
1160  int* childmap /**< mapping of child indices */
1161  )
1162 {
1163  SCIP_EXPRDATA_MONOMIAL* monomial;
1164  int i;
1165  int j;
1166 
1167  assert(polynomialdata != NULL);
1168 
1169  for( i = 0; i < polynomialdata->nmonomials; ++i )
1170  {
1171  monomial = polynomialdata->monomials[i];
1172  assert(monomial != NULL);
1173 
1174  for( j = 0; j < monomial->nfactors; ++j )
1175  {
1176  monomial->childidxs[j] = childmap[monomial->childidxs[j]];
1177  assert(monomial->childidxs[j] >= 0);
1178  }
1179  monomial->sorted = FALSE;
1180  }
1181 
1182  polynomialdata->sorted = FALSE;
1183 }
1184 
1185 /** replaces a factor in a monomial by a polynomial and expands the result */
1186 static
1188  BMS_BLKMEM* blkmem, /**< block memory data structure */
1189  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1190  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata, /**< polynomial data where to expand a monomial */
1191  int monomialpos, /**< position of monomial which factor to expand */
1192  int factorpos, /**< position of factor in monomial to expand */
1193  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomial,/**< polynomial that should replace factor */
1194  int* childmap, /**< map of child indices in factorpolynomial to children of polynomial */
1195  int maxexpansionexponent,/**< maximal exponent for which polynomials (with > 1 summands) are expanded */
1196  SCIP_Bool* success /**< buffer to store whether expansion has been done */
1197  )
1198 {
1199  SCIP_EXPRDATA_POLYNOMIAL* factorpolynomialcopy;
1200  SCIP_EXPRDATA_MONOMIAL* monomial;
1201  int i;
1202 
1203  assert(blkmem != NULL);
1204  assert(polynomialdata != NULL);
1205  assert(factorpolynomial != NULL);
1206  assert(childmap != NULL || factorpolynomial->nmonomials == 0);
1207  assert(success != NULL);
1208  assert(monomialpos >= 0);
1209  assert(monomialpos < polynomialdata->nmonomials);
1210  assert(factorpos >= 0);
1211 
1212  monomial = polynomialdata->monomials[monomialpos];
1213  assert(monomial != NULL);
1214  assert(factorpos < monomial->nfactors);
1215 
1216  *success = TRUE;
1217 
1218  if( factorpolynomial->nmonomials == 0 )
1219  {
1220  /* factorpolynomial is a constant */
1221 
1222  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && factorpolynomial->constant < 0.0 ) /*lint !e835*/
1223  {
1224  /* if polynomial is a negative constant and our exponent is not integer, then cannot do expansion */
1225  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", factorpolynomial->constant, monomial->exponents[factorpos]);
1226  *success = FALSE;
1227  return SCIP_OKAY;
1228  }
1229  monomial->coef *= pow(factorpolynomial->constant, monomial->exponents[factorpos]);
1230 
1231  /* move last factor to position factorpos */
1232  if( factorpos < monomial->nfactors-1 )
1233  {
1234  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1235  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1236  }
1237  --monomial->nfactors;
1238  monomial->sorted = FALSE;
1239  polynomialdata->sorted = FALSE;
1240 
1241  return SCIP_OKAY;
1242  }
1243 
1244  if( factorpolynomial->constant == 0.0 && factorpolynomial->nmonomials == 1 )
1245  {
1246  /* factorpolynomial is a single monomial */
1247  SCIP_EXPRDATA_MONOMIAL* factormonomial;
1248  int childidx;
1249  SCIP_Real exponent;
1250 
1251  factormonomial = factorpolynomial->monomials[0];
1252  assert(factormonomial != NULL);
1253 
1254  if( !EPSISINT(monomial->exponents[factorpos], 0.0) ) /*lint !e835*/
1255  {
1256  if( factormonomial->coef < 0.0 )
1257  {
1258  /* if coefficient of monomial is negative and our exponent is not integer, then do not do expansion
1259  * @todo the only case where this could make sense is if the factors can be negative, i.e., when we have negative arguments with an odd exponent: (-x^a)^b = (-x)^(ab) for a odd
1260  */
1261  *success = FALSE;
1262  return SCIP_OKAY;
1263  }
1264  if( factormonomial->nfactors > 1 )
1265  {
1266  /* @todo if there is an even number of factors in factormonomial that are negative, then they always multiply to something positive
1267  * however, we cannot expand them as below, since we cannot compute the single powers
1268  * since we do not have the bounds on the factors here, we skip expansion in this case
1269  * MINLPLib instances tls2,4,6 are examples where we are loosing here (do not recognize convexity)
1270  */
1271  *success = FALSE;
1272  return SCIP_OKAY;
1273  }
1274  }
1275 
1276  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + factormonomial->nfactors) );
1277 
1278  for( i = 0; i < factormonomial->nfactors; ++i )
1279  {
1280  childidx = childmap[factormonomial->childidxs[i]]; /*lint !e613*/
1281  /* can do this because monomial->exponents[factorpos] is assumed to be integer or factormonomial has positive coefficient and only one factor
1282  * thus, if factormonomial->exponents[i] is fractional, then we can assume that it's argument is positive
1283  */
1284  exponent = factormonomial->exponents[i] * monomial->exponents[factorpos];
1285  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
1286  }
1287 
1288  monomial->coef *= pow(factormonomial->coef, monomial->exponents[factorpos]);
1289 
1290  /* move last factor to position factorpos */
1291  if( factorpos < monomial->nfactors-1 )
1292  {
1293  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1294  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1295  }
1296  --monomial->nfactors;
1297  monomial->sorted = FALSE;
1298  polynomialdata->sorted = FALSE;
1299 
1300  return SCIP_OKAY;
1301  }
1302 
1303  /* if exponent is negative or fractional and the polynomial is not just a monomial, then we cannot do expansion */
1304  if( !EPSISINT(monomial->exponents[factorpos], 0.0) || monomial->exponents[factorpos] < 0.0 ) /*lint !e835*/
1305  {
1306  *success = FALSE;
1307  return SCIP_OKAY;
1308  }
1309 
1310  /* if exponent is too large, skip expansion */
1311  if( monomial->exponents[factorpos] > maxexpansionexponent )
1312  {
1313  *success = FALSE;
1314  return SCIP_OKAY;
1315  }
1316 
1317  /* check whether maximal degree of expansion would exceed maxexpansionexponent
1318  * that is, assume monomial is f1^a1 f2^a2 ... and we want to expand f1 = (g11^beta11 g12^beta12... + g21^beta21 g22^beta22 ... + ...)
1319  * then we do this only if all ai and all beta are > 0.0 and a1 max(beta11+beta12+..., beta21+beta22+..., ...) + a2 + ... < maxexpansionexponent
1320  * exception (there need to be one) is if monomial is just f1
1321  */
1322  if( maxexpansionexponent < INT_MAX && (monomial->nfactors > 1 || monomial->exponents[factorpos] != 1.0) )
1323  {
1324  SCIP_Real restdegree;
1325  SCIP_Real degree;
1326  int j;
1327 
1328  restdegree = -monomial->exponents[factorpos];
1329  for( i = 0; i < monomial->nfactors; ++i )
1330  {
1331  if( monomial->exponents[i] < 0.0 )
1332  {
1333  /* ai < 0.0 */
1334  SCIPdebugMessage("skip expansion because factor %d in monomial has negative exponent\n", i);
1335  *success = FALSE;
1336  return SCIP_OKAY;
1337  }
1338  restdegree += monomial->exponents[i];
1339  }
1340 
1341  for( i = 0; i < factorpolynomial->nmonomials; ++i )
1342  {
1343  degree = 0.0;
1344  for( j = 0; j < factorpolynomial->monomials[i]->nfactors; ++j )
1345  {
1346  if( factorpolynomial->monomials[i]->exponents[j] < 0.0 )
1347  {
1348  /* beta_ij < 0.0 */
1349  SCIPdebugMessage("skip expansion because %d'th factor in %d'th monomial of factorpolynomial is negative\n", i, j);
1350  *success = FALSE;
1351  return SCIP_OKAY;
1352  }
1353  degree += factorpolynomial->monomials[i]->exponents[j];
1354  }
1355  if( degree * monomial->exponents[factorpos] + restdegree > maxexpansionexponent )
1356  {
1357  /* (beta_i1+beta_i2+...)*monomial->exponents[factorpos] + rest > maxexpansion */
1358  SCIPdebugMessage("skip expansion because degree of %d'th monomial would yield degree %g > max = %d in expansion\n",
1359  i, degree * monomial->exponents[factorpos] + restdegree, maxexpansionexponent);
1360  *success = FALSE;
1361  return SCIP_OKAY;
1362  }
1363  }
1364  }
1365 
1366  /* create a copy of factor */
1367  SCIP_CALL( polynomialdataCopy(blkmem, &factorpolynomialcopy, factorpolynomial) );
1368  /* apply childmap to copy */
1369  polynomialdataApplyChildmap(factorpolynomialcopy, childmap);
1370  /* create power of factor */
1371  SCIP_CALL( polynomialdataPower(blkmem, factorpolynomialcopy, (int)EPSFLOOR(monomial->exponents[factorpos], 0.0)) ); /*lint !e835*/
1372 
1373  /* remove factor from monomial by moving last factor to position factorpos */
1374  if( factorpos < monomial->nfactors-1 )
1375  {
1376  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
1377  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
1378  }
1379  --monomial->nfactors;
1380  monomial->sorted = FALSE;
1381 
1382  /* multiply factor with this reduced monomial */
1383  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, factorpolynomialcopy, monomial, NULL) );
1384 
1385  /* remove monomial from polynomial and move last monomial to monomialpos */
1386  SCIPexprFreeMonomial(blkmem, &polynomialdata->monomials[monomialpos]);
1387  if( monomialpos < polynomialdata->nmonomials-1 )
1388  polynomialdata->monomials[monomialpos] = polynomialdata->monomials[polynomialdata->nmonomials-1];
1389  --polynomialdata->nmonomials;
1390  polynomialdata->sorted = FALSE;
1391 
1392  /* add factorpolynomialcopy to polynomial */
1393  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, factorpolynomialcopy->nmonomials, factorpolynomialcopy->monomials, FALSE) );
1394  polynomialdata->constant += factorpolynomialcopy->constant;
1395 
1396  factorpolynomialcopy->nmonomials = 0;
1397  polynomialdataFree(blkmem, &factorpolynomialcopy);
1398 
1399  return SCIP_OKAY;
1400 }
1401 
1402 /**@} */
1403 
1404 /**@name Expression operand private methods */
1405 /**@{ */
1406 
1407 /** a default implementation of expression interval evaluation that always gives a correct result */
1408 static
1409 SCIP_DECL_EXPRINTEVAL( exprevalIntDefault )
1410 { /*lint --e{715}*/
1412 
1413  return SCIP_OKAY;
1414 }
1415 
1416 /** a default implementation of expression curvature check that always gives a correct result */
1417 static
1418 SCIP_DECL_EXPRCURV( exprcurvDefault )
1419 { /*lint --e{715}*/
1420  *result = SCIP_EXPRCURV_UNKNOWN;
1421 
1422  return SCIP_OKAY;
1423 }
1424 
1425 /** point evaluation for EXPR_VAR */
1426 static
1427 SCIP_DECL_EXPREVAL( exprevalVar )
1428 { /*lint --e{715}*/
1429  assert(result != NULL);
1430  assert(varvals != NULL);
1431 
1432  *result = varvals[opdata.intval];
1433 
1434  return SCIP_OKAY;
1435 }
1436 
1437 /** interval evaluation for EXPR_VAR */
1438 static
1439 SCIP_DECL_EXPRINTEVAL( exprevalIntVar )
1440 { /*lint --e{715}*/
1441  assert(result != NULL);
1442  assert(varvals != NULL);
1443 
1444  *result = varvals[opdata.intval];
1445 
1446  return SCIP_OKAY;
1447 }
1448 
1449 /** curvature for EXPR_VAR */
1450 static
1451 SCIP_DECL_EXPRCURV( exprcurvVar )
1452 { /*lint --e{715}*/
1453  assert(result != NULL);
1454 
1455  *result = SCIP_EXPRCURV_LINEAR;
1456 
1457  return SCIP_OKAY;
1458 }
1459 
1460 /** point evaluation for EXPR_CONST */
1461 static
1462 SCIP_DECL_EXPREVAL( exprevalConst )
1463 { /*lint --e{715}*/
1464  assert(result != NULL);
1465 
1466  *result = opdata.dbl;
1467 
1468  return SCIP_OKAY;
1469 }
1470 
1471 /** interval evaluation for EXPR_CONST */
1472 static
1473 SCIP_DECL_EXPRINTEVAL( exprevalIntConst )
1474 { /*lint --e{715}*/
1475  assert(result != NULL);
1476 
1477  SCIPintervalSet(result, opdata.dbl);
1478 
1479  return SCIP_OKAY;
1480 }
1481 
1482 /** curvature for EXPR_CONST */
1483 static
1484 SCIP_DECL_EXPRCURV( exprcurvConst )
1485 { /*lint --e{715}*/
1486  assert(result != NULL);
1487 
1488  *result = SCIP_EXPRCURV_LINEAR;
1489 
1490  return SCIP_OKAY;
1491 }
1492 
1493 /** point evaluation for EXPR_PARAM */
1494 static
1495 SCIP_DECL_EXPREVAL( exprevalParam )
1496 { /*lint --e{715}*/
1497  assert(result != NULL);
1498  assert(paramvals != NULL );
1499 
1500  *result = paramvals[opdata.intval];
1501 
1502  return SCIP_OKAY;
1503 }
1504 
1505 /** interval evaluation for EXPR_PARAM */
1506 static
1507 SCIP_DECL_EXPRINTEVAL( exprevalIntParam )
1508 { /*lint --e{715}*/
1509  assert(result != NULL);
1510  assert(paramvals != NULL );
1511 
1512  SCIPintervalSet(result, paramvals[opdata.intval]);
1513 
1514  return SCIP_OKAY;
1515 }
1516 
1517 /** curvature for EXPR_PARAM */
1518 static
1519 SCIP_DECL_EXPRCURV( exprcurvParam )
1520 { /*lint --e{715}*/
1521  assert(result != NULL);
1522 
1523  *result = SCIP_EXPRCURV_LINEAR;
1524 
1525  return SCIP_OKAY;
1526 }
1527 
1528 /** point evaluation for EXPR_PLUS */
1529 static
1530 SCIP_DECL_EXPREVAL( exprevalPlus )
1531 { /*lint --e{715}*/
1532  assert(result != NULL);
1533  assert(argvals != NULL);
1534 
1535  *result = argvals[0] + argvals[1];
1536 
1537  return SCIP_OKAY;
1538 }
1539 
1540 /** interval evaluation for EXPR_PLUS */
1541 static
1542 SCIP_DECL_EXPRINTEVAL( exprevalIntPlus )
1543 { /*lint --e{715}*/
1544  assert(result != NULL);
1545  assert(argvals != NULL);
1546 
1547  SCIPintervalAdd(infinity, result, argvals[0], argvals[1]);
1548 
1549  return SCIP_OKAY;
1550 }
1551 
1552 /** curvature for EXPR_PLUS */
1553 static
1554 SCIP_DECL_EXPRCURV( exprcurvPlus )
1555 { /*lint --e{715}*/
1556  assert(result != NULL);
1557  assert(argcurv != NULL);
1558 
1559  *result = SCIPexprcurvAdd(argcurv[0], argcurv[1]);
1560 
1561  return SCIP_OKAY;
1562 }
1563 
1564 /** point evaluation for EXPR_MINUS */
1565 static
1566 SCIP_DECL_EXPREVAL( exprevalMinus )
1567 { /*lint --e{715}*/
1568  assert(result != NULL);
1569  assert(argvals != NULL);
1570 
1571  *result = argvals[0] - argvals[1];
1572 
1573  return SCIP_OKAY;
1574 }
1575 
1576 /** interval evaluation for EXPR_MINUS */
1577 static
1578 SCIP_DECL_EXPRINTEVAL( exprevalIntMinus )
1579 { /*lint --e{715}*/
1580  assert(result != NULL);
1581  assert(argvals != NULL);
1582 
1583  SCIPintervalSub(infinity, result, argvals[0], argvals[1]);
1584 
1585  return SCIP_OKAY;
1586 }
1587 
1588 /** curvature for EXPR_MINUS */
1589 static
1590 SCIP_DECL_EXPRCURV( exprcurvMinus )
1591 { /*lint --e{715}*/
1592  assert(result != NULL);
1593  assert(argcurv != NULL);
1594 
1595  *result = SCIPexprcurvAdd(argcurv[0], SCIPexprcurvNegate(argcurv[1]));
1596 
1597  return SCIP_OKAY;
1598 }
1599 
1600 /** point evaluation for EXPR_MUL */
1601 static
1602 SCIP_DECL_EXPREVAL( exprevalMult )
1603 { /*lint --e{715}*/
1604  assert(result != NULL);
1605  assert(argvals != NULL);
1606 
1607  *result = argvals[0] * argvals[1];
1608 
1609  return SCIP_OKAY;
1610 }
1611 
1612 /** interval evaluation for EXPR_MUL */
1613 static
1614 SCIP_DECL_EXPRINTEVAL( exprevalIntMult )
1615 { /*lint --e{715}*/
1616  assert(result != NULL);
1617  assert(argvals != NULL);
1618 
1619  SCIPintervalMul(infinity, result, argvals[0], argvals[1]);
1620 
1621  return SCIP_OKAY;
1622 }
1623 
1624 /** curvature for EXPR_MUL */
1625 static
1626 SCIP_DECL_EXPRCURV( exprcurvMult )
1627 { /*lint --e{715}*/
1628  assert(result != NULL);
1629  assert(argcurv != NULL);
1630  assert(argbounds != NULL);
1631 
1632  /* if one factor is constant, then product is
1633  * - linear, if constant is 0.0
1634  * - same curvature as other factor, if constant is positive
1635  * - negated curvature of other factor, if constant is negative
1636  *
1637  * if both factors are not constant, then product may not be convex nor concave
1638  */
1639  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1640  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1641  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1642  *result = SCIPexprcurvMultiply(argbounds[0].inf, argcurv[1]);
1643  else
1644  *result = SCIP_EXPRCURV_UNKNOWN;
1645 
1646  return SCIP_OKAY;
1647 }
1648 
1649 /** point evaluation for EXPR_DIV */
1650 static
1651 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1652 __attribute__((no_sanitize_undefined))
1653 #endif
1654 SCIP_DECL_EXPREVAL( exprevalDiv )
1655 { /*lint --e{715}*/
1656  assert(result != NULL);
1657  assert(argvals != NULL);
1658 
1659  *result = argvals[0] / argvals[1];
1660 
1661  return SCIP_OKAY;
1662 }
1663 
1664 /** interval evaluation for EXPR_DIV */
1665 static
1666 SCIP_DECL_EXPRINTEVAL( exprevalIntDiv )
1667 { /*lint --e{715}*/
1668  assert(result != NULL);
1669  assert(argvals != NULL);
1670 
1671  SCIPintervalDiv(infinity, result, argvals[0], argvals[1]);
1672 
1673  return SCIP_OKAY;
1674 }
1675 
1676 /** curvature for EXPR_DIV */
1677 static
1678 SCIP_DECL_EXPRCURV( exprcurvDiv )
1679 { /*lint --e{715}*/
1680  assert(result != NULL);
1681  assert(argcurv != NULL);
1682  assert(argbounds != NULL);
1683 
1684  /* if denominator is constant, then quotient has curvature sign(denominator) * curv(nominator)
1685  *
1686  * if nominator is a constant, then quotient is
1687  * - sign(nominator) * convex, if denominator is concave and positive
1688  * - sign(nominator) * concave, if denominator is convex and negative
1689  *
1690  * if denominator is positive but convex, then we don't know, e.g.,
1691  * - 1/x^2 is convex for x>=0
1692  * - 1/(1+(x-1)^2) is neither convex nor concave for x >= 0
1693  *
1694  * if both nominator and denominator are not constant, then quotient may not be convex nor concave
1695  */
1696  if( argbounds[1].inf == argbounds[1].sup ) /*lint !e777*/
1697  {
1698  /* denominator is constant */
1699  *result = SCIPexprcurvMultiply(argbounds[1].inf, argcurv[0]);
1700  }
1701  else if( argbounds[0].inf == argbounds[0].sup ) /*lint !e777*/
1702  {
1703  /* nominator is constant */
1704  if( argbounds[1].inf >= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
1705  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONVEX);
1706  else if( argbounds[1].sup <= 0.0 && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
1707  *result = SCIPexprcurvMultiply(argbounds[0].inf, SCIP_EXPRCURV_CONCAVE);
1708  else
1709  *result = SCIP_EXPRCURV_UNKNOWN;
1710  }
1711  else
1712  {
1713  /* denominator and nominator not constant */
1714  *result = SCIP_EXPRCURV_UNKNOWN;
1715  }
1716 
1717  return SCIP_OKAY;
1718 }
1719 
1720 /** point evaluation for EXPR_SQUARE */
1721 static
1722 SCIP_DECL_EXPREVAL( exprevalSquare )
1723 { /*lint --e{715}*/
1724  assert(result != NULL);
1725  assert(argvals != NULL);
1726 
1727  *result = argvals[0] * argvals[0];
1728 
1729  return SCIP_OKAY;
1730 }
1731 
1732 /** interval evaluation for EXPR_SQUARE */
1733 static
1734 SCIP_DECL_EXPRINTEVAL( exprevalIntSquare )
1735 { /*lint --e{715}*/
1736  assert(result != NULL);
1737  assert(argvals != NULL);
1738 
1739  SCIPintervalSquare(infinity, result, argvals[0]);
1740 
1741  return SCIP_OKAY;
1742 }
1743 
1744 /** curvature for EXPR_SQUARE */
1745 static
1746 SCIP_DECL_EXPRCURV( exprcurvSquare )
1747 { /*lint --e{715}*/
1748  assert(result != NULL);
1749  assert(argcurv != NULL);
1750  assert(argbounds != NULL);
1751 
1752  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], 2.0);
1753 
1754  return SCIP_OKAY;
1755 }
1756 
1757 /** point evaluation for EXPR_SQRT */
1758 static
1759 SCIP_DECL_EXPREVAL( exprevalSquareRoot )
1760 { /*lint --e{715}*/
1761  assert(result != NULL);
1762  assert(argvals != NULL);
1763 
1764  *result = sqrt(argvals[0]);
1765 
1766  return SCIP_OKAY;
1767 }
1768 
1769 /** interval evaluation for EXPR_SQRT */
1770 static
1771 SCIP_DECL_EXPRINTEVAL( exprevalIntSquareRoot )
1772 { /*lint --e{715}*/
1773  assert(result != NULL);
1774  assert(argvals != NULL);
1775 
1776  SCIPintervalSquareRoot(infinity, result, argvals[0]);
1777 
1778  return SCIP_OKAY;
1779 }
1780 
1781 /** curvature for EXPR_SQRT */
1782 static
1783 SCIP_DECL_EXPRCURV( exprcurvSquareRoot )
1784 { /*lint --e{715}*/
1785  assert(result != NULL);
1786  assert(argcurv != NULL);
1787 
1788  /* square-root is concave, if child is concave
1789  * otherwise, we don't know
1790  */
1791 
1792  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
1793  *result = SCIP_EXPRCURV_CONCAVE;
1794  else
1795  *result = SCIP_EXPRCURV_UNKNOWN;
1796 
1797  return SCIP_OKAY;
1798 }
1799 
1800 /** point evaluation for EXPR_REALPOWER */
1801 static
1802 SCIP_DECL_EXPREVAL( exprevalRealPower )
1803 { /*lint --e{715}*/
1804  assert(result != NULL);
1805  assert(argvals != NULL);
1806 
1807  *result = pow(argvals[0], opdata.dbl);
1808 
1809  return SCIP_OKAY;
1810 }
1811 
1812 /** interval evaluation for EXPR_REALPOWER */
1813 static
1814 SCIP_DECL_EXPRINTEVAL( exprevalIntRealPower )
1815 { /*lint --e{715}*/
1816  assert(result != NULL);
1817  assert(argvals != NULL);
1818 
1819  SCIPintervalPowerScalar(infinity, result, argvals[0], opdata.dbl);
1820 
1821  return SCIP_OKAY;
1822 }
1823 
1824 /** curvature for EXPR_REALPOWER */
1825 static
1826 SCIP_DECL_EXPRCURV( exprcurvRealPower )
1827 { /*lint --e{715}*/
1828  assert(result != NULL);
1829  assert(argcurv != NULL);
1830  assert(argbounds != NULL);
1831 
1832  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], opdata.dbl);
1833 
1834  return SCIP_OKAY;
1835 }
1836 
1837 /** point evaluation for EXPR_INTPOWER */
1838 static
1839 #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ * 10 >= 490 && !defined(__INTEL_COMPILER)
1840 __attribute__((no_sanitize_undefined))
1841 #endif
1842 SCIP_DECL_EXPREVAL( exprevalIntPower )
1843 { /*lint --e{715}*/
1844  assert(result != NULL);
1845  assert(argvals != NULL);
1846 
1847  switch( opdata.intval )
1848  {
1849  case -1:
1850  *result = 1.0 / argvals[0];
1851  return SCIP_OKAY;
1852 
1853  case 0:
1854  *result = 1.0;
1855  return SCIP_OKAY;
1856 
1857  case 1:
1858  *result = argvals[0];
1859  return SCIP_OKAY;
1860 
1861  case 2:
1862  *result = argvals[0] * argvals[0];
1863  return SCIP_OKAY;
1864 
1865  default:
1866  *result = pow(argvals[0], (SCIP_Real)opdata.intval);
1867  }
1868 
1869  return SCIP_OKAY;
1870 }
1871 
1872 /** interval evaluation for EXPR_INTPOWER */
1873 static
1874 SCIP_DECL_EXPRINTEVAL( exprevalIntIntPower )
1875 { /*lint --e{715}*/
1876  assert(result != NULL);
1877  assert(argvals != NULL);
1878 
1879  SCIPintervalPowerScalar(infinity, result, argvals[0], (SCIP_Real)opdata.intval);
1880 
1881  return SCIP_OKAY;
1882 }
1883 
1884 /** curvature for EXPR_INTPOWER */
1885 static
1886 SCIP_DECL_EXPRCURV( exprcurvIntPower )
1887 { /*lint --e{715}*/
1888  assert(result != NULL);
1889  assert(argcurv != NULL);
1890  assert(argbounds != NULL);
1891 
1892  *result = SCIPexprcurvPower(argbounds[0], argcurv[0], (SCIP_Real)opdata.intval);
1893 
1894  return SCIP_OKAY;
1895 }
1896 
1897 /** point evaluation for EXPR_SIGNPOWER */
1898 static
1899 SCIP_DECL_EXPREVAL( exprevalSignPower )
1900 { /*lint --e{715}*/
1901  assert(result != NULL);
1902  assert(argvals != NULL);
1903 
1904  if( argvals[0] > 0 )
1905  *result = pow( argvals[0], opdata.dbl);
1906  else
1907  *result = -pow(-argvals[0], opdata.dbl);
1908 
1909  return SCIP_OKAY;
1910 }
1911 
1912 /** interval evaluation for EXPR_SIGNPOWER */
1913 static
1914 SCIP_DECL_EXPRINTEVAL( exprevalIntSignPower )
1915 { /*lint --e{715}*/
1916  assert(result != NULL);
1917  assert(argvals != NULL);
1918 
1919  SCIPintervalSignPowerScalar(infinity, result, argvals[0], opdata.dbl);
1920 
1921  return SCIP_OKAY;
1922 }
1923 
1924 /** curvature for EXPR_SIGNPOWER */
1925 static
1926 SCIP_DECL_EXPRCURV( exprcurvSignPower )
1927 { /*lint --e{715}*/
1928  SCIP_INTERVAL tmp;
1929  SCIP_EXPRCURV left;
1930  SCIP_EXPRCURV right;
1931 
1932  assert(result != NULL);
1933  assert(argcurv != NULL);
1934  assert(argbounds != NULL);
1935 
1936  /* for x <= 0, signpower(x,c) = -(-x)^c
1937  * for x >= 0, signpower(x,c) = ( x)^c
1938  *
1939  * thus, get curvatures for both parts and "intersect" them
1940  */
1941 
1942  if( argbounds[0].inf < 0 )
1943  {
1944  SCIPintervalSetBounds(&tmp, 0.0, -argbounds[0].inf);
1945  left = SCIPexprcurvNegate(SCIPexprcurvPower(tmp, SCIPexprcurvNegate(argcurv[0]), opdata.dbl));
1946  }
1947  else
1948  {
1949  left = SCIP_EXPRCURV_LINEAR;
1950  }
1951 
1952  if( argbounds[0].sup > 0 )
1953  {
1954  SCIPintervalSetBounds(&tmp, 0.0, argbounds[0].sup);
1955  right = SCIPexprcurvPower(tmp, argcurv[0], opdata.dbl);
1956  }
1957  else
1958  {
1959  right = SCIP_EXPRCURV_LINEAR;
1960  }
1961 
1962  *result = (SCIP_EXPRCURV) (left & right);
1963 
1964  return SCIP_OKAY;
1965 }
1966 
1967 /** point evaluation for EXPR_EXP */
1968 static
1969 SCIP_DECL_EXPREVAL( exprevalExp )
1970 { /*lint --e{715}*/
1971  assert(result != NULL);
1972  assert(argvals != NULL);
1973 
1974  *result = exp(argvals[0]);
1975 
1976  return SCIP_OKAY;
1977 }
1978 
1979 /** interval evaluation for EXPR_EXP */
1980 static
1981 SCIP_DECL_EXPRINTEVAL( exprevalIntExp )
1982 { /*lint --e{715}*/
1983  assert(result != NULL);
1984  assert(argvals != NULL);
1985 
1986  SCIPintervalExp(infinity, result, argvals[0]);
1987 
1988  return SCIP_OKAY;
1989 }
1990 
1991 /** curvature for EXPR_EXP */
1992 static
1993 SCIP_DECL_EXPRCURV( exprcurvExp )
1994 { /*lint --e{715}*/
1995  assert(result != NULL);
1996  assert(argcurv != NULL);
1997 
1998  /* expression is convex if child is convex
1999  * otherwise, we don't know
2000  */
2001  if( argcurv[0] & SCIP_EXPRCURV_CONVEX )
2002  *result = SCIP_EXPRCURV_CONVEX;
2003  else
2004  *result = SCIP_EXPRCURV_UNKNOWN;
2005 
2006  return SCIP_OKAY;
2007 }
2008 
2009 /** point evaluation for EXPR_LOG */
2010 static
2011 SCIP_DECL_EXPREVAL( exprevalLog )
2012 { /*lint --e{715}*/
2013  assert(result != NULL);
2014  assert(argvals != NULL);
2015 
2016  *result = log(argvals[0]);
2017 
2018  return SCIP_OKAY;
2019 }
2020 
2021 /** interval evaluation for EXPR_LOG */
2022 static
2023 SCIP_DECL_EXPRINTEVAL( exprevalIntLog )
2024 { /*lint --e{715}*/
2025  assert(result != NULL);
2026  assert(argvals != NULL);
2027 
2028  SCIPintervalLog(infinity, result, argvals[0]);
2029 
2030  return SCIP_OKAY;
2031 }
2032 
2033 /** curvature for EXPR_LOG */
2034 static
2035 SCIP_DECL_EXPRCURV( exprcurvLog )
2036 { /*lint --e{715}*/
2037  assert(result != NULL);
2038  assert(argcurv != NULL);
2039 
2040  /* expression is concave if child is concave
2041  * otherwise, we don't know
2042  */
2043  if( argcurv[0] & SCIP_EXPRCURV_CONCAVE )
2044  *result = SCIP_EXPRCURV_CONCAVE;
2045  else
2046  *result = SCIP_EXPRCURV_UNKNOWN;
2047 
2048  return SCIP_OKAY;
2049 }
2050 
2051 /** point evaluation for EXPR_SIN */
2052 static
2053 SCIP_DECL_EXPREVAL( exprevalSin )
2054 { /*lint --e{715}*/
2055  assert(result != NULL);
2056  assert(argvals != NULL);
2057 
2058  *result = sin(argvals[0]);
2059 
2060  return SCIP_OKAY;
2061 }
2062 
2063 /** interval evaluation for EXPR_SIN */
2064 static
2065 SCIP_DECL_EXPRINTEVAL( exprevalIntSin )
2066 { /*lint --e{715}*/
2067  assert(result != NULL);
2068  assert(argvals != NULL);
2069  assert(nargs == 1);
2070 
2071  SCIPintervalSin(infinity, result, *argvals);
2072 
2073  return SCIP_OKAY;
2074 }
2075 
2076 /* @todo implement exprcurvSin */
2077 #define exprcurvSin exprcurvDefault
2078 
2079 /** point evaluation for EXPR_COS */
2080 static
2081 SCIP_DECL_EXPREVAL( exprevalCos )
2082 { /*lint --e{715}*/
2083  assert(result != NULL);
2084  assert(argvals != NULL);
2085 
2086  *result = cos(argvals[0]);
2087 
2088  return SCIP_OKAY;
2089 }
2090 
2091 /** interval evaluation for EXPR_COS */
2092 static
2093 SCIP_DECL_EXPRINTEVAL( exprevalIntCos )
2094 { /*lint --e{715}*/
2095  assert(result != NULL);
2096  assert(argvals != NULL);
2097  assert(nargs == 1);
2098 
2099  SCIPintervalCos(infinity, result, *argvals);
2100 
2101  return SCIP_OKAY;
2102 }
2103 
2104 /* @todo implement exprcurvCos */
2105 #define exprcurvCos exprcurvDefault
2106 
2107 /** point evaluation for EXPR_TAN */
2108 static
2109 SCIP_DECL_EXPREVAL( exprevalTan )
2110 { /*lint --e{715}*/
2111  assert(result != NULL);
2112  assert(argvals != NULL);
2113 
2114  *result = tan(argvals[0]);
2115 
2116  return SCIP_OKAY;
2117 }
2118 
2119 /* @todo implement SCIPintervalTan */
2120 #define exprevalIntTan exprevalIntDefault
2121 
2122 /* @todo implement exprcurvTan */
2123 #define exprcurvTan exprcurvDefault
2124 
2125 /* erf and erfi do not seem to exist on every system, and we cannot really handle them anyway, so they are currently disabled */
2126 #ifdef SCIP_DISABLED_CODE
2127 static
2128 SCIP_DECL_EXPREVAL( exprevalErf )
2129 { /*lint --e{715}*/
2130  assert(result != NULL);
2131  assert(argvals != NULL);
2132 
2133  *result = erf(argvals[0]);
2134 
2135  return SCIP_OKAY;
2136 }
2137 
2138 /* @todo implement SCIPintervalErf */
2139 #define exprevalIntErf exprevalIntDefault
2140 
2141 /* @todo implement SCIPintervalErf */
2142 #define exprcurvErf exprcurvDefault
2143 
2144 static
2145 SCIP_DECL_EXPREVAL( exprevalErfi )
2146 { /*lint --e{715}*/
2147  assert(result != NULL);
2148  assert(argvals != NULL);
2149 
2150  /* @TODO implement erfi evaluation */
2151  SCIPerrorMessage("erfi not implemented");
2152 
2153  return SCIP_ERROR;
2154 }
2155 
2156 /* @todo implement SCIPintervalErfi */
2157 #define exprevalIntErfi NULL
2158 
2159 #define exprcurvErfi exprcurvDefault
2160 #endif
2161 
2162 /** point evaluation for EXPR_MIN */
2163 static
2164 SCIP_DECL_EXPREVAL( exprevalMin )
2165 { /*lint --e{715}*/
2166  assert(result != NULL);
2167  assert(argvals != NULL);
2168 
2169  *result = MIN(argvals[0], argvals[1]);
2170 
2171  return SCIP_OKAY;
2172 }
2173 
2174 /** interval evaluation for EXPR_MIN */
2175 static
2176 SCIP_DECL_EXPRINTEVAL( exprevalIntMin )
2177 { /*lint --e{715}*/
2178  assert(result != NULL);
2179  assert(argvals != NULL);
2180 
2181  SCIPintervalMin(infinity, result, argvals[0], argvals[1]);
2182 
2183  return SCIP_OKAY;
2184 }
2185 
2186 /** curvature for EXPR_MIN */
2187 static
2188 SCIP_DECL_EXPRCURV( exprcurvMin )
2189 { /*lint --e{715}*/
2190  assert(result != NULL);
2191  assert(argcurv != NULL);
2192 
2193  /* the minimum of two concave functions is concave
2194  * otherwise, we don't know
2195  */
2196 
2197  if( (argcurv[0] & SCIP_EXPRCURV_CONCAVE) && (argcurv[1] & SCIP_EXPRCURV_CONCAVE) )
2198  *result = SCIP_EXPRCURV_CONCAVE;
2199  else
2200  *result = SCIP_EXPRCURV_UNKNOWN;
2201 
2202  return SCIP_OKAY;
2203 }
2204 
2205 /** point evaluation for EXPR_MAX */
2206 static
2207 SCIP_DECL_EXPREVAL( exprevalMax )
2208 { /*lint --e{715}*/
2209  assert(result != NULL);
2210  assert(argvals != NULL);
2211 
2212  *result = MAX(argvals[0], argvals[1]);
2213 
2214  return SCIP_OKAY;
2215 }
2216 
2217 /** interval evaluation for EXPR_MAX */
2218 static
2219 SCIP_DECL_EXPRINTEVAL( exprevalIntMax )
2220 { /*lint --e{715}*/
2221  assert(result != NULL);
2222  assert(argvals != NULL);
2223 
2224  SCIPintervalMax(infinity, result, argvals[0], argvals[1]);
2225 
2226  return SCIP_OKAY;
2227 }
2228 
2229 /** curvature for EXPR_MAX */
2230 static
2231 SCIP_DECL_EXPRCURV( exprcurvMax )
2232 { /*lint --e{715}*/
2233  assert(result != NULL);
2234  assert(argcurv != NULL);
2235 
2236  /* the maximum of two convex functions is convex
2237  * otherwise, we don't know
2238  */
2239  if( (argcurv[0] & SCIP_EXPRCURV_CONVEX) && (argcurv[1] & SCIP_EXPRCURV_CONVEX) )
2240  *result = SCIP_EXPRCURV_CONVEX;
2241  else
2242  *result = SCIP_EXPRCURV_UNKNOWN;
2243 
2244  return SCIP_OKAY;
2245 }
2246 
2247 /** point evaluation for EXPR_ABS */
2248 static
2249 SCIP_DECL_EXPREVAL( exprevalAbs )
2250 { /*lint --e{715}*/
2251  assert(result != NULL);
2252  assert(argvals != NULL);
2253 
2254  *result = ABS(argvals[0]);
2255 
2256  return SCIP_OKAY;
2257 }
2258 
2259 /** interval evaluation for EXPR_ABS */
2260 static
2261 SCIP_DECL_EXPRINTEVAL( exprevalIntAbs )
2262 { /*lint --e{715}*/
2263  assert(result != NULL);
2264  assert(argvals != NULL);
2265 
2266  SCIPintervalAbs(infinity, result, argvals[0]);
2267 
2268  return SCIP_OKAY;
2269 }
2270 
2271 /** curvature for EXPR_ABS */
2272 static
2273 SCIP_DECL_EXPRCURV( exprcurvAbs )
2274 { /*lint --e{715}*/
2275  assert(result != NULL);
2276  assert(argcurv != NULL);
2277  assert(argbounds != NULL);
2278 
2279  /* if child is only negative, then abs(child) = -child
2280  * if child is only positive, then abs(child) = child
2281  * if child is both positive and negative, but also linear, then abs(child) is convex
2282  * otherwise, we don't know
2283  */
2284  if( argbounds[0].sup <= 0.0 )
2285  *result = SCIPexprcurvMultiply(-1.0, argcurv[0]);
2286  else if( argbounds[0].inf >= 0.0 )
2287  *result = argcurv[0];
2288  else if( argcurv[0] == SCIP_EXPRCURV_LINEAR )
2289  *result = SCIP_EXPRCURV_CONVEX;
2290  else
2291  *result = SCIP_EXPRCURV_UNKNOWN;
2292 
2293  return SCIP_OKAY;
2294 }
2295 
2296 /** point evaluation for EXPR_SIGN */
2297 static
2298 SCIP_DECL_EXPREVAL( exprevalSign )
2299 { /*lint --e{715}*/
2300  assert(result != NULL);
2301  assert(argvals != NULL);
2302 
2303  *result = SIGN(argvals[0]);
2304 
2305  return SCIP_OKAY;
2306 }
2307 
2308 /** interval evaluation for EXPR_SIGN */
2309 static
2310 SCIP_DECL_EXPRINTEVAL( exprevalIntSign )
2311 { /*lint --e{715}*/
2312  assert(result != NULL);
2313  assert(argvals != NULL);
2314 
2315  SCIPintervalSign(infinity, result, argvals[0]);
2316 
2317  return SCIP_OKAY;
2318 }
2319 
2320 /** curvature for EXPR_SIGN */
2321 static
2322 SCIP_DECL_EXPRCURV( exprcurvSign )
2323 { /*lint --e{715}*/
2324  assert(result != NULL);
2325  assert(argbounds != NULL);
2326 
2327  /* if sign of child is clear, then sign is linear otherwise, we don't know */
2328  if( argbounds[0].sup <= 0.0 || argbounds[0].inf >= 0.0 )
2329  *result = SCIP_EXPRCURV_LINEAR;
2330  else
2331  *result = SCIP_EXPRCURV_UNKNOWN;
2332 
2333  return SCIP_OKAY;
2334 }
2335 
2336 /** point evaluation for EXPR_SUM */
2337 static
2338 SCIP_DECL_EXPREVAL( exprevalSum )
2339 { /*lint --e{715}*/
2340  int i;
2341 
2342  assert(result != NULL);
2343  assert(argvals != NULL);
2344 
2345  *result = 0.0;
2346  for( i = 0; i < nargs; ++i )
2347  *result += argvals[i];
2348 
2349  return SCIP_OKAY;
2350 }
2351 
2352 /** interval evaluation for EXPR_SUM */
2353 static
2354 SCIP_DECL_EXPRINTEVAL( exprevalIntSum )
2355 { /*lint --e{715}*/
2356  int i;
2357 
2358  assert(result != NULL);
2359  assert(argvals != NULL);
2360 
2361  SCIPintervalSet(result, 0.0);
2362 
2363  for( i = 0; i < nargs; ++i )
2364  SCIPintervalAdd(infinity, result, *result, argvals[i]);
2365 
2366  return SCIP_OKAY;
2367 }
2368 
2369 /** curvature for EXPR_SUM */
2370 static
2371 SCIP_DECL_EXPRCURV( exprcurvSum )
2372 { /*lint --e{715}*/
2373  int i;
2374 
2375  assert(result != NULL);
2376  assert(argcurv != NULL);
2377 
2378  *result = SCIP_EXPRCURV_LINEAR;
2379 
2380  for( i = 0; i < nargs; ++i )
2381  *result = SCIPexprcurvAdd(*result, argcurv[i]);
2382 
2383  return SCIP_OKAY;
2384 }
2385 
2386 /** point evaluation for EXPR_PRODUCT */
2387 static
2388 SCIP_DECL_EXPREVAL( exprevalProduct )
2389 { /*lint --e{715}*/
2390  int i;
2391 
2392  assert(result != NULL);
2393  assert(argvals != NULL);
2394 
2395  *result = 1.0;
2396  for( i = 0; i < nargs; ++i )
2397  *result *= argvals[i];
2398 
2399  return SCIP_OKAY;
2400 }
2401 
2402 /** interval evaluation for EXPR_PRODUCT */
2403 static
2404 SCIP_DECL_EXPRINTEVAL( exprevalIntProduct )
2405 { /*lint --e{715}*/
2406  int i;
2407 
2408  assert(result != NULL);
2409  assert(argvals != NULL);
2410 
2411  SCIPintervalSet(result, 1.0);
2412 
2413  for( i = 0; i < nargs; ++i )
2414  SCIPintervalMul(infinity, result, *result, argvals[i]);
2415 
2416  return SCIP_OKAY;
2417 }
2418 
2419 /** curvature for EXPR_PRODUCT */
2420 static
2421 SCIP_DECL_EXPRCURV( exprcurvProduct )
2422 { /*lint --e{715}*/
2423  SCIP_Bool hadnonconst;
2424  SCIP_Real constants;
2425  int i;
2426 
2427  assert(result != NULL);
2428  assert(argcurv != NULL);
2429  assert(argbounds != NULL);
2430 
2431  /* if all factors are constant, then product is linear (even constant)
2432  * if only one factor is not constant, then product is curvature of this factor, multiplied by sign of product of remaining factors
2433  */
2434  *result = SCIP_EXPRCURV_LINEAR;
2435  hadnonconst = FALSE;
2436  constants = 1.0;
2437 
2438  for( i = 0; i < nargs; ++i )
2439  {
2440  if( argbounds[i].inf == argbounds[i].sup ) /*lint !e777*/
2441  {
2442  constants *= argbounds[i].inf;
2443  }
2444  else if( !hadnonconst )
2445  {
2446  /* first non-constant child */
2447  *result = argcurv[i];
2448  hadnonconst = TRUE;
2449  }
2450  else
2451  {
2452  /* more than one non-constant child, thus don't know curvature */
2453  *result = SCIP_EXPRCURV_UNKNOWN;
2454  break;
2455  }
2456  }
2457 
2458  *result = SCIPexprcurvMultiply(constants, *result);
2459 
2460  return SCIP_OKAY;
2461 }
2462 
2463 /** point evaluation for EXPR_LINEAR */
2464 static
2465 SCIP_DECL_EXPREVAL( exprevalLinear )
2466 { /*lint --e{715}*/
2467  SCIP_Real* coef;
2468  int i;
2469 
2470  assert(result != NULL);
2471  assert(argvals != NULL || nargs == 0);
2472  assert(opdata.data != NULL);
2473 
2474  coef = &((SCIP_Real*)opdata.data)[nargs];
2475 
2476  *result = *coef;
2477  for( i = nargs-1, --coef; i >= 0; --i, --coef )
2478  *result += *coef * argvals[i]; /*lint !e613*/
2479 
2480  assert(++coef == (SCIP_Real*)opdata.data);
2481 
2482  return SCIP_OKAY;
2483 }
2484 
2485 /** interval evaluation for EXPR_LINEAR */
2486 static
2487 SCIP_DECL_EXPRINTEVAL( exprevalIntLinear )
2488 { /*lint --e{715}*/
2489  assert(result != NULL);
2490  assert(argvals != NULL || nargs == 0);
2491  assert(opdata.data != NULL);
2492 
2493  SCIPintervalScalprodScalars(infinity, result, nargs, argvals, (SCIP_Real*)opdata.data);
2494  SCIPintervalAddScalar(infinity, result, *result, ((SCIP_Real*)opdata.data)[nargs]);
2495 
2496  return SCIP_OKAY;
2497 }
2498 
2499 /** curvature for EXPR_LINEAR */
2500 static
2501 SCIP_DECL_EXPRCURV( exprcurvLinear )
2502 { /*lint --e{715}*/
2503  SCIP_Real* data;
2504  int i;
2505 
2506  assert(result != NULL);
2507  assert(argcurv != NULL);
2508 
2509  data = (SCIP_Real*)opdata.data;
2510  assert(data != NULL);
2511 
2512  *result = SCIP_EXPRCURV_LINEAR;
2513 
2514  for( i = 0; i < nargs; ++i )
2515  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(data[i], argcurv[i]));
2516 
2517  return SCIP_OKAY;
2518 }
2519 
2520 /** expression data copy for EXPR_LINEAR */
2521 static
2522 SCIP_DECL_EXPRCOPYDATA( exprCopyDataLinear )
2523 { /*lint --e{715}*/
2524  SCIP_Real* targetdata;
2525 
2526  assert(blkmem != NULL);
2527  assert(nchildren >= 0);
2528  assert(opdatatarget != NULL);
2529 
2530  /* for a linear expression, we need to copy the array that holds the coefficients and constant term */
2531  assert(opdatasource.data != NULL);
2532  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &targetdata, (SCIP_Real*)opdatasource.data, nchildren + 1) ); /*lint !e866*/
2533  opdatatarget->data = targetdata;
2534 
2535  return SCIP_OKAY;
2536 }
2537 
2538 /** expression data free for EXPR_LINEAR */
2539 static
2540 SCIP_DECL_EXPRFREEDATA( exprFreeDataLinear )
2541 { /*lint --e{715}*/
2542  SCIP_Real* freedata;
2543 
2544  assert(blkmem != NULL);
2545  assert(nchildren >= 0);
2546 
2547  freedata = (SCIP_Real*)opdata.data;
2548  assert(freedata != NULL);
2549 
2550  BMSfreeBlockMemoryArray(blkmem, &freedata, nchildren + 1); /*lint !e866*/
2551 }
2552 
2553 /** point evaluation for EXPR_QUADRATIC */
2554 static
2555 SCIP_DECL_EXPREVAL( exprevalQuadratic )
2556 { /*lint --e{715}*/
2557  SCIP_EXPRDATA_QUADRATIC* quaddata;
2558  SCIP_Real* lincoefs;
2559  SCIP_QUADELEM* quadelems;
2560  int nquadelems;
2561  int i;
2562 
2563  assert(result != NULL);
2564  assert(argvals != NULL || nargs == 0);
2565 
2566  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2567  assert(quaddata != NULL);
2568 
2569  lincoefs = quaddata->lincoefs;
2570  nquadelems = quaddata->nquadelems;
2571  quadelems = quaddata->quadelems;
2572 
2573  assert(quadelems != NULL || nquadelems == 0);
2574  assert(argvals != NULL || nquadelems == 0);
2575 
2576  *result = quaddata->constant;
2577 
2578  if( lincoefs != NULL )
2579  {
2580  for( i = nargs-1; i >= 0; --i )
2581  *result += lincoefs[i] * argvals[i]; /*lint !e613*/
2582  }
2583 
2584  for( i = 0; i < nquadelems; ++i, ++quadelems ) /*lint !e613*/
2585  *result += quadelems->coef * argvals[quadelems->idx1] * argvals[quadelems->idx2]; /*lint !e613*/
2586 
2587  return SCIP_OKAY;
2588 }
2589 
2590 /** interval evaluation for EXPR_QUADRATIC */
2591 static
2592 SCIP_DECL_EXPRINTEVAL( exprevalIntQuadratic )
2593 { /*lint --e{715}*/
2594  SCIP_EXPRDATA_QUADRATIC* quaddata;
2595  SCIP_Real* lincoefs;
2596  SCIP_QUADELEM* quadelems;
2597  int nquadelems;
2598  int i;
2599  int argidx;
2600  SCIP_Real sqrcoef;
2601  SCIP_INTERVAL lincoef;
2602  SCIP_INTERVAL tmp;
2603 
2604  assert(result != NULL);
2605  assert(argvals != NULL || nargs == 0);
2606 
2607  quaddata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2608  assert(quaddata != NULL);
2609 
2610  lincoefs = quaddata->lincoefs;
2611  nquadelems = quaddata->nquadelems;
2612  quadelems = quaddata->quadelems;
2613 
2614  assert(quadelems != NULL || nquadelems == 0);
2615  assert(argvals != NULL || nargs == 0);
2616 
2617  /* something fast for case of only one child */
2618  if( nargs == 1 )
2619  {
2620  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[0] : 0.0);
2621 
2622  sqrcoef = 0.0;
2623  for( i = 0; i < nquadelems; ++i )
2624  {
2625  assert(quadelems[i].idx1 == 0); /*lint !e613*/
2626  assert(quadelems[i].idx2 == 0); /*lint !e613*/
2627  sqrcoef += quadelems[i].coef; /*lint !e613*/
2628  }
2629 
2630  SCIPintervalQuad(infinity, result, sqrcoef, lincoef, argvals[0]); /*lint !e613*/
2631  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2632 
2633  return SCIP_OKAY;
2634  }
2635 
2636  if( nargs == 2 && nquadelems > 0 )
2637  {
2638  /* if it's a bivariate quadratic expression with bilinear term, do something special */
2639  SCIP_Real ax; /* square coefficient of first child */
2640  SCIP_Real ay; /* square coefficient of second child */
2641  SCIP_Real axy; /* bilinear coefficient */
2642 
2643  ax = 0.0;
2644  ay = 0.0;
2645  axy = 0.0;
2646  for( i = 0; i < nquadelems; ++i )
2647  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 ) /*lint !e613*/
2648  ax += quadelems[i].coef; /*lint !e613*/
2649  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 ) /*lint !e613*/
2650  ay += quadelems[i].coef; /*lint !e613*/
2651  else
2652  axy += quadelems[i].coef; /*lint !e613*/
2653 
2654  SCIPintervalQuadBivar(infinity, result, ax, ay, axy,
2655  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2656  argvals[0], argvals[1]); /*lint !e613*/
2657  SCIPdebugMessage("%g x^2 + %g y^2 + %g x y + %g x + %g y = [%g,%g] for x = [%g,%g], y = [%g,%g]\n",
2658  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
2659  result->inf, result->sup, argvals[0].inf, argvals[0].sup, argvals[1].inf, argvals[1].sup); /*lint !e613*/
2660 
2661  SCIPintervalAddScalar(infinity, result, *result, quaddata->constant);
2662 
2663  return SCIP_OKAY;
2664  }
2665 
2666  /* make sure coefficients are sorted */
2667  quadraticdataSort(quaddata);
2668 
2669  SCIPintervalSet(result, quaddata->constant);
2670 
2671  /* for each argument, we collect it's linear index from lincoefs, it's square coefficients and all factors from bilinear terms
2672  * then we compute the interval sqrcoef*x^2 + lincoef*x and add it to result
2673  * @todo split quadratic expression into bivariate quadratic terms and apply the above method
2674  */
2675  i = 0;
2676  for( argidx = 0; argidx < nargs; ++argidx )
2677  {
2678  if( i == nquadelems || quadelems[i].idx1 > argidx ) /*lint !e613*/
2679  {
2680  /* there are no quadratic terms with argidx in its first argument, that should be easy to handle */
2681  if( lincoefs != NULL )
2682  {
2683  SCIPintervalMulScalar(infinity, &tmp, argvals[argidx], lincoefs[argidx]); /*lint !e613*/
2684  SCIPintervalAdd(infinity, result, *result, tmp);
2685  }
2686  continue;
2687  }
2688 
2689  sqrcoef = 0.0;
2690  SCIPintervalSet(&lincoef, lincoefs != NULL ? lincoefs[argidx] : 0.0);
2691 
2692  assert(i < nquadelems && quadelems[i].idx1 == argidx); /*lint !e613*/
2693  do
2694  {
2695  if( quadelems[i].idx2 == argidx ) /*lint !e613*/
2696  {
2697  sqrcoef += quadelems[i].coef; /*lint !e613*/
2698  }
2699  else
2700  {
2701  SCIPintervalMulScalar(infinity, &tmp, argvals[quadelems[i].idx2], quadelems[i].coef); /*lint !e613*/
2702  SCIPintervalAdd(infinity, &lincoef, lincoef, tmp);
2703  }
2704  ++i;
2705  }
2706  while( i < nquadelems && quadelems[i].idx1 == argidx ); /*lint !e613*/
2707  assert(i == nquadelems || quadelems[i].idx1 > argidx); /*lint !e613*/
2708 
2709  SCIPintervalQuad(infinity, &tmp, sqrcoef, lincoef, argvals[argidx]); /*lint !e613*/
2710  SCIPintervalAdd(infinity, result, *result, tmp);
2711  }
2712  assert(i == nquadelems);
2713 
2714  return SCIP_OKAY;
2715 }
2716 
2717 /** curvature for EXPR_QUADRATIC */
2718 static
2719 SCIP_DECL_EXPRCURV( exprcurvQuadratic )
2720 { /*lint --e{715}*/
2722  SCIP_QUADELEM* quadelems;
2723  int nquadelems;
2724  SCIP_Real* lincoefs;
2725  int i;
2726 
2727  assert(result != NULL);
2728  assert(argcurv != NULL);
2729  assert(argbounds != NULL);
2730 
2731  data = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2732  assert(data != NULL);
2733 
2734  lincoefs = data->lincoefs;
2735  quadelems = data->quadelems;
2736  nquadelems = data->nquadelems;
2737 
2738  *result = SCIP_EXPRCURV_LINEAR;
2739 
2740  if( lincoefs != NULL )
2741  for( i = 0; i < nargs; ++i )
2742  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(lincoefs[i], argcurv[i]));
2743 
2744  /* @todo could try cholesky factorization if all children linear...
2745  * @todo should then cache the result
2746  */
2747  for( i = 0; i < nquadelems && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
2748  {
2749  if( quadelems[i].coef == 0.0 )
2750  continue;
2751 
2752  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup && /*lint !e777*/
2753  +argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup
2754  ) /*lint !e777*/
2755  {
2756  /* both factors are constants -> curvature does not change */
2757  continue;
2758  }
2759 
2760  if( argbounds[quadelems[i].idx1].inf == argbounds[quadelems[i].idx1].sup ) /*lint !e777*/
2761  {
2762  /* first factor is constant, second is not -> add curvature of second */
2763  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx1].inf, argcurv[quadelems[i].idx2]));
2764  }
2765  else if( argbounds[quadelems[i].idx2].inf == argbounds[quadelems[i].idx2].sup ) /*lint !e777*/
2766  {
2767  /* first factor is not constant, second is -> add curvature of first */
2768  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef * argbounds[quadelems[i].idx2].inf, argcurv[quadelems[i].idx1]));
2769  }
2770  else if( quadelems[i].idx1 == quadelems[i].idx2 )
2771  {
2772  /* both factors not constant, but the same (square term) */
2773  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(quadelems[i].coef, SCIPexprcurvPower(argbounds[quadelems[i].idx1], argcurv[quadelems[i].idx1], 2.0)));
2774  }
2775  else
2776  {
2777  /* two different non-constant factors -> can't tell about curvature */
2778  *result = SCIP_EXPRCURV_UNKNOWN;
2779  }
2780  }
2781 
2782  return SCIP_OKAY;
2783 }
2784 
2785 /** expression data copy for EXPR_QUADRATIC */
2786 static
2787 SCIP_DECL_EXPRCOPYDATA( exprCopyDataQuadratic )
2788 { /*lint --e{715}*/
2789  SCIP_EXPRDATA_QUADRATIC* sourcedata;
2790 
2791  assert(blkmem != NULL);
2792  assert(opdatatarget != NULL);
2793 
2794  sourcedata = (SCIP_EXPRDATA_QUADRATIC*)opdatasource.data;
2795  assert(sourcedata != NULL);
2796 
2797  SCIP_CALL( quadraticdataCreate(blkmem, (SCIP_EXPRDATA_QUADRATIC**)&opdatatarget->data,
2798  sourcedata->constant, nchildren, sourcedata->lincoefs, sourcedata->nquadelems, sourcedata->quadelems) );
2799 
2800  return SCIP_OKAY;
2801 }
2802 
2803 /** expression data free for EXPR_QUADRATIC */
2804 static
2805 SCIP_DECL_EXPRFREEDATA( exprFreeDataQuadratic )
2806 { /*lint --e{715}*/
2807  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
2808 
2809  assert(blkmem != NULL);
2810  assert(nchildren >= 0);
2811 
2812  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
2813  assert(quadraticdata != NULL);
2814 
2815  if( quadraticdata->lincoefs != NULL )
2816  {
2817  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->lincoefs, nchildren);
2818  }
2819 
2820  if( quadraticdata->nquadelems > 0 )
2821  {
2822  assert(quadraticdata->quadelems != NULL);
2823  BMSfreeBlockMemoryArray(blkmem, &quadraticdata->quadelems, quadraticdata->nquadelems);
2824  }
2825 
2826  BMSfreeBlockMemory(blkmem, &quadraticdata);
2827 }
2828 
2829 /** point evaluation for EXPR_POLYNOMIAL */
2830 static
2831 SCIP_DECL_EXPREVAL( exprevalPolynomial )
2832 { /*lint --e{715}*/
2833  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2834  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2835  SCIP_Real childval;
2836  SCIP_Real exponent;
2837  SCIP_Real monomialval;
2838  int i;
2839  int j;
2840 
2841  assert(result != NULL);
2842  assert(argvals != NULL || nargs == 0);
2843  assert(opdata.data != NULL);
2844 
2845  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2846  assert(polynomialdata != NULL);
2847 
2848  *result = polynomialdata->constant;
2849 
2850  for( i = 0; i < polynomialdata->nmonomials; ++i )
2851  {
2852  monomialdata = polynomialdata->monomials[i];
2853  assert(monomialdata != NULL);
2854 
2855  monomialval = monomialdata->coef;
2856  for( j = 0; j < monomialdata->nfactors; ++j )
2857  {
2858  assert(monomialdata->childidxs[j] >= 0);
2859  assert(monomialdata->childidxs[j] < nargs);
2860 
2861  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2862  if( childval == 1.0 ) /* 1^anything == 1 */
2863  continue;
2864 
2865  exponent = monomialdata->exponents[j];
2866 
2867  if( childval == 0.0 )
2868  {
2869  if( exponent > 0.0 )
2870  {
2871  /* 0^positive == 0 */
2872  monomialval = 0.0;
2873  break;
2874  }
2875  else if( exponent < 0.0 )
2876  {
2877  /* 0^negative = nan (or should it be +inf?, doesn't really matter) */
2878 #ifdef NAN
2879  *result = NAN;
2880 #else
2881  /* cppcheck-suppress wrongmathcall */
2882  *result = pow(0.0, -1.0);
2883 #endif
2884  return SCIP_OKAY;
2885  }
2886  /* 0^0 == 1 */
2887  continue;
2888  }
2889 
2890  /* cover some special exponents separately to avoid calling expensive pow function */
2891  if( exponent == 0.0 )
2892  continue;
2893  if( exponent == 1.0 )
2894  {
2895  monomialval *= childval;
2896  continue;
2897  }
2898  if( exponent == 2.0 )
2899  {
2900  monomialval *= childval * childval;
2901  continue;
2902  }
2903  if( exponent == 0.5 )
2904  {
2905  monomialval *= sqrt(childval);
2906  continue;
2907  }
2908  if( exponent == -1.0 )
2909  {
2910  monomialval /= childval;
2911  continue;
2912  }
2913  if( exponent == -2.0 )
2914  {
2915  monomialval /= childval * childval;
2916  continue;
2917  }
2918  monomialval *= pow(childval, exponent);
2919  }
2920 
2921  *result += monomialval;
2922  }
2923 
2924  return SCIP_OKAY;
2925 }
2926 
2927 /** interval evaluation for EXPR_POLYNOMIAL */
2928 static
2929 SCIP_DECL_EXPRINTEVAL( exprevalIntPolynomial )
2930 { /*lint --e{715}*/
2931  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
2932  SCIP_EXPRDATA_MONOMIAL* monomialdata;
2933  SCIP_INTERVAL childval;
2934  SCIP_INTERVAL monomialval;
2935  SCIP_Real exponent;
2936  int i;
2937  int j;
2938 
2939  assert(result != NULL);
2940  assert(argvals != NULL || nargs == 0);
2941  assert(opdata.data != NULL);
2942 
2943  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
2944  assert(polynomialdata != NULL);
2945 
2946  SCIPintervalSet(result, polynomialdata->constant);
2947 
2948  for( i = 0; i < polynomialdata->nmonomials; ++i )
2949  {
2950  monomialdata = polynomialdata->monomials[i];
2951  assert(monomialdata != NULL);
2952 
2953  SCIPintervalSet(&monomialval, monomialdata->coef);
2954  for( j = 0; j < monomialdata->nfactors && !SCIPintervalIsEntire(infinity, monomialval); ++j )
2955  {
2956  assert(monomialdata->childidxs[j] >= 0);
2957  assert(monomialdata->childidxs[j] < nargs);
2958 
2959  childval = argvals[monomialdata->childidxs[j]]; /*lint !e613*/
2960 
2961  exponent = monomialdata->exponents[j];
2962 
2963  /* cover some special exponents separately to avoid calling expensive pow function */
2964  if( exponent == 0.0 )
2965  continue;
2966 
2967  if( exponent == 1.0 )
2968  {
2969  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2970  continue;
2971  }
2972 
2973  if( exponent == 2.0 )
2974  {
2975  SCIPintervalSquare(infinity, &childval, childval);
2976  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2977  continue;
2978  }
2979 
2980  if( exponent == 0.5 )
2981  {
2982  SCIPintervalSquareRoot(infinity, &childval, childval);
2983  if( SCIPintervalIsEmpty(infinity, childval) )
2984  {
2985  SCIPintervalSetEmpty(result);
2986  break;
2987  }
2988  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
2989  continue;
2990  }
2991  else if( exponent == -1.0 )
2992  {
2993  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2994  }
2995  else if( exponent == -2.0 )
2996  {
2997  SCIPintervalSquare(infinity, &childval, childval);
2998  SCIPintervalDiv(infinity, &monomialval, monomialval, childval);
2999  }
3000  else
3001  {
3002  SCIPintervalPowerScalar(infinity, &childval, childval, exponent);
3003  if( SCIPintervalIsEmpty(infinity, childval) )
3004  {
3005  SCIPintervalSetEmpty(result);
3006  return SCIP_OKAY;
3007  }
3008  SCIPintervalMul(infinity, &monomialval, monomialval, childval);
3009  }
3010 
3011  /* the cases in which monomialval gets empty should have been catched */
3012  assert(!SCIPintervalIsEmpty(infinity, monomialval));
3013  }
3014 
3015  SCIPintervalAdd(infinity, result, *result, monomialval);
3016  }
3017 
3018  return SCIP_OKAY;
3019 }
3020 
3021 /** curvature for EXPR_POLYNOMIAL */
3022 static
3023 SCIP_DECL_EXPRCURV( exprcurvPolynomial )
3024 { /*lint --e{715}*/
3026  SCIP_EXPRDATA_MONOMIAL** monomials;
3027  SCIP_EXPRDATA_MONOMIAL* monomial;
3028  int nmonomials;
3029  int i;
3030 
3031  assert(result != NULL);
3032  assert(argcurv != NULL);
3033  assert(argbounds != NULL);
3034 
3035  data = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3036  assert(data != NULL);
3037 
3038  monomials = data->monomials;
3039  nmonomials = data->nmonomials;
3040 
3041  *result = SCIP_EXPRCURV_LINEAR;
3042 
3043  for( i = 0; i < nmonomials && *result != SCIP_EXPRCURV_UNKNOWN; ++i )
3044  {
3045  /* we assume that some simplifier was running, so that monomials do not have constants in their factors and such that all factors are different
3046  * (result would still be correct)
3047  */
3048  monomial = monomials[i];
3049  *result = SCIPexprcurvAdd(*result, SCIPexprcurvMultiply(monomial->coef, SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, monomial->childidxs, argcurv, argbounds)));
3050  }
3051 
3052  return SCIP_OKAY;
3053 }
3054 
3055 /** expression data copy for EXPR_POLYNOMIAL */
3056 static
3057 SCIP_DECL_EXPRCOPYDATA( exprCopyDataPolynomial )
3058 { /*lint --e{715}*/
3059  SCIP_EXPRDATA_POLYNOMIAL* sourcepolynomialdata;
3060  SCIP_EXPRDATA_POLYNOMIAL* targetpolynomialdata;
3061 
3062  assert(blkmem != NULL);
3063  assert(opdatatarget != NULL);
3064 
3065  sourcepolynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdatasource.data;
3066  assert(sourcepolynomialdata != NULL);
3067 
3068  SCIP_CALL( polynomialdataCopy(blkmem, &targetpolynomialdata, sourcepolynomialdata) );
3069 
3070  opdatatarget->data = (void*)targetpolynomialdata;
3071 
3072  return SCIP_OKAY;
3073 }
3074 
3075 /** expression data free for EXPR_POLYNOMIAL */
3076 static
3077 SCIP_DECL_EXPRFREEDATA( exprFreeDataPolynomial )
3078 { /*lint --e{715}*/
3079  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3080 
3081  assert(blkmem != NULL);
3082 
3083  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
3084  assert(polynomialdata != NULL);
3085 
3086  polynomialdataFree(blkmem, &polynomialdata);
3087 }
3088 
3089 /** point evaluation for user expression */
3090 static
3091 SCIP_DECL_EXPREVAL( exprevalUser )
3092 { /*lint --e{715}*/
3093  SCIP_EXPRDATA_USER* exprdata;
3094 
3095  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3096 
3097  SCIP_CALL( exprdata->eval(exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3098 
3099  return SCIP_OKAY;
3100 }
3101 
3102 /** interval evaluation for user expression */
3103 static
3104 SCIP_DECL_EXPRINTEVAL( exprevalIntUser )
3105 { /*lint --e{715}*/
3106  SCIP_EXPRDATA_USER* exprdata;
3107 
3108  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3109 
3110  if( exprdata->inteval != NULL )
3111  {
3112  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, nargs, argvals, result, NULL, NULL) );
3113  }
3114  else
3115  {
3116  /* if user does not provide interval evaluation, then return a result that is always correct */
3118  }
3119 
3120  return SCIP_OKAY;
3121 }
3122 
3123 /** curvature check for user expression */
3124 static
3125 SCIP_DECL_EXPRCURV( exprcurvUser )
3126 {
3127  SCIP_EXPRDATA_USER* exprdata;
3128 
3129  exprdata = (SCIP_EXPRDATA_USER*) opdata.data;
3130 
3131  if( exprdata->curv != NULL )
3132  {
3133  SCIP_CALL( exprdata->curv(infinity, exprdata->userdata, nargs, argbounds, argcurv, result) );
3134  }
3135  else
3136  {
3137  /* if user does not provide curvature check, then return unknown (which is handled like indefinite) */
3138  *result = SCIP_EXPRCURV_UNKNOWN;
3139  }
3140 
3141  return SCIP_OKAY;
3142 }
3143 
3144 /** data copy for user expression */
3145 static
3146 SCIP_DECL_EXPRCOPYDATA( exprCopyDataUser )
3147 {
3148  SCIP_EXPRDATA_USER* exprdatasource;
3149  SCIP_EXPRDATA_USER* exprdatatarget;
3150 
3151  assert(blkmem != NULL);
3152  assert(opdatatarget != NULL);
3153 
3154  exprdatasource = (SCIP_EXPRDATA_USER*)opdatasource.data;
3155  assert(exprdatasource != NULL);
3156 
3157  /* duplicate expression data */
3158  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, &exprdatatarget, exprdatasource) );
3159 
3160  /* duplicate user expression data, if any */
3161  if( exprdatasource->copydata != NULL )
3162  {
3163  SCIP_CALL( exprdatasource->copydata(blkmem, nchildren, exprdatasource->userdata, &exprdatatarget->userdata) );
3164  }
3165  else
3166  {
3167  /* if no copy function for data, then there has to be no data */
3168  assert(exprdatatarget->userdata == NULL);
3169  }
3170 
3171  opdatatarget->data = (void*)exprdatatarget;
3172 
3173  return SCIP_OKAY;
3174 }
3175 
3176 /** data free for user expression */
3177 static
3178 SCIP_DECL_EXPRFREEDATA( exprFreeDataUser )
3179 {
3180  SCIP_EXPRDATA_USER* exprdata;
3181 
3182  assert(blkmem != NULL);
3183 
3184  exprdata = (SCIP_EXPRDATA_USER*)opdata.data;
3185 
3186  /* free user expression data, if any */
3187  if( exprdata->freedata != NULL )
3188  {
3189  exprdata->freedata(blkmem, nchildren, exprdata->userdata);
3190  }
3191  else
3192  {
3193  assert(exprdata->userdata == NULL);
3194  }
3195 
3196  /* free expression data */
3197  BMSfreeBlockMemory(blkmem, &exprdata);
3198 }
3199 
3200 /** element in table of expression operands */
3201 struct exprOpTableElement
3202 {
3203  const char* name; /**< name of operand (used for printing) */
3204  int nargs; /**< number of arguments (negative if not fixed) */
3205  SCIP_DECL_EXPREVAL ((*eval)); /**< evaluation function */
3206  SCIP_DECL_EXPRINTEVAL ((*inteval)); /**< interval evaluation function */
3207  SCIP_DECL_EXPRCURV ((*curv)); /**< curvature check function */
3208  SCIP_DECL_EXPRCOPYDATA ((*copydata)); /**< expression data copy function, or NULL to only opdata union */
3209  SCIP_DECL_EXPRFREEDATA ((*freedata)); /**< expression data free function, or NULL if nothing to free */
3210 };
3211 
3212 #define EXPROPEMPTY {NULL, -1, NULL, NULL, NULL, NULL, NULL}
3213 
3214 /** table containing for each operand the name, the number of children, and some evaluation functions */
3215 static
3216 struct exprOpTableElement exprOpTable[] =
3217  {
3218  EXPROPEMPTY,
3219  { "variable", 0, exprevalVar, exprevalIntVar, exprcurvVar, NULL, NULL },
3220  { "constant", 0, exprevalConst, exprevalIntConst, exprcurvConst, NULL, NULL },
3221  { "parameter", 0, exprevalParam, exprevalIntParam, exprcurvParam, NULL, NULL },
3223  { "plus", 2, exprevalPlus, exprevalIntPlus, exprcurvPlus, NULL, NULL },
3224  { "minus", 2, exprevalMinus, exprevalIntMinus, exprcurvMinus, NULL, NULL },
3225  { "mul", 2, exprevalMult, exprevalIntMult, exprcurvMult, NULL, NULL },
3226  { "div", 2, exprevalDiv, exprevalIntDiv, exprcurvDiv, NULL, NULL },
3227  { "sqr", 1, exprevalSquare, exprevalIntSquare, exprcurvSquare, NULL, NULL },
3228  { "sqrt", 1, exprevalSquareRoot, exprevalIntSquareRoot, exprcurvSquareRoot, NULL, NULL },
3229  { "realpower", 1, exprevalRealPower, exprevalIntRealPower, exprcurvRealPower, NULL, NULL },
3230  { "intpower", 1, exprevalIntPower, exprevalIntIntPower, exprcurvIntPower, NULL, NULL },
3231  { "signpower", 1, exprevalSignPower, exprevalIntSignPower, exprcurvSignPower, NULL, NULL },
3232  { "exp", 1, exprevalExp, exprevalIntExp, exprcurvExp, NULL, NULL },
3233  { "log", 1, exprevalLog, exprevalIntLog, exprcurvLog, NULL, NULL },
3234  { "sin", 1, exprevalSin, exprevalIntSin, exprcurvSin, NULL, NULL },
3235  { "cos", 1, exprevalCos, exprevalIntCos, exprcurvCos, NULL, NULL },
3236  { "tan", 1, exprevalTan, exprevalIntTan, exprcurvTan, NULL, NULL },
3237  /* { "erf", 1, exprevalErf, exprevalIntErf, exprcurvErf, NULL, NULL }, */
3238  /* { "erfi", 1, exprevalErfi, exprevalIntErfi exprcurvErfi, NULL, NULL }, */
3240  { "min", 2, exprevalMin, exprevalIntMin, exprcurvMin, NULL, NULL },
3241  { "max", 2, exprevalMax, exprevalIntMax, exprcurvMax, NULL, NULL },
3242  { "abs", 1, exprevalAbs, exprevalIntAbs, exprcurvAbs, NULL, NULL },
3243  { "sign", 1, exprevalSign, exprevalIntSign, exprcurvSign, NULL, NULL },
3249  { "sum", -2, exprevalSum, exprevalIntSum, exprcurvSum, NULL, NULL },
3250  { "prod", -2, exprevalProduct, exprevalIntProduct, exprcurvProduct, NULL, NULL },
3251  { "linear", -2, exprevalLinear, exprevalIntLinear, exprcurvLinear, exprCopyDataLinear, exprFreeDataLinear },
3252  { "quadratic", -2, exprevalQuadratic, exprevalIntQuadratic, exprcurvQuadratic, exprCopyDataQuadratic, exprFreeDataQuadratic },
3253  { "polynomial", -2, exprevalPolynomial, exprevalIntPolynomial, exprcurvPolynomial, exprCopyDataPolynomial, exprFreeDataPolynomial },
3254  { "user", -2, exprevalUser, exprevalIntUser, exprcurvUser, exprCopyDataUser, exprFreeDataUser }
3255  };
3256 
3257 /**@} */
3258 
3259 /**@name Expression operand methods */
3260 /**@{ */
3261 
3262 /** gives the name of an operand as string */
3263 const char* SCIPexpropGetName(
3264  SCIP_EXPROP op /**< expression operand */
3265  )
3266 {
3267  assert(op < SCIP_EXPR_LAST);
3268 
3269  return exprOpTable[op].name;
3270 }
3271 
3272 /** gives the number of children of a simple operand */
3274  SCIP_EXPROP op /**< expression operand */
3275  )
3276 {
3277  assert(op < SCIP_EXPR_LAST);
3278 
3279  return exprOpTable[op].nargs;
3280 }
3281 
3282 /**@} */
3283 
3284 /**@name Expressions private methods */
3285 /**@{ */
3286 
3287 /** creates an expression
3288  *
3289  * Note, that the expression is allocated but for the children only the pointer is copied.
3290  */
3291 static
3293  BMS_BLKMEM* blkmem, /**< block memory data structure */
3294  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
3295  SCIP_EXPROP op, /**< operand of expression */
3296  int nchildren, /**< number of children */
3297  SCIP_EXPR** children, /**< children */
3298  SCIP_EXPROPDATA opdata /**< operand data */
3299  )
3300 {
3301  assert(blkmem != NULL);
3302  assert(expr != NULL);
3303  assert(children != NULL || nchildren == 0);
3304  assert(children == NULL || nchildren > 0);
3305 
3306  SCIP_ALLOC( BMSallocBlockMemory(blkmem, expr) );
3307 
3308  (*expr)->op = op;
3309  (*expr)->nchildren = nchildren;
3310  (*expr)->children = children;
3311  (*expr)->data = opdata;
3312 
3313  return SCIP_OKAY;
3314 }
3315 
3316 /** tries to convert a given (operator,operatordata) pair into a polynomial operator with corresponding data
3317  *
3318  * Does not do this for constants.
3319  * If conversion is not possible or operator is already polynomial, *op and *data are
3320  * left untouched.
3321  */
3322 static
3324  BMS_BLKMEM* blkmem, /**< block memory */
3325  SCIP_EXPROP* op, /**< pointer to expression operator */
3326  SCIP_EXPROPDATA* data, /**< pointer to expression data */
3327  int nchildren /**< number of children of operator */
3328  )
3329 {
3330  assert(blkmem != NULL);
3331  assert(op != NULL);
3332  assert(data != NULL);
3333 
3334  switch( *op )
3335  {
3336  case SCIP_EXPR_VARIDX:
3337  case SCIP_EXPR_PARAM:
3338  case SCIP_EXPR_CONST:
3339  break;
3340 
3341  case SCIP_EXPR_PLUS:
3342  {
3343  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3344  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3345  int childidx;
3346  SCIP_Real exponent;
3347 
3348  assert(nchildren == 2);
3349 
3350  /* create monomial for first child */
3351  childidx = 0;
3352  exponent = 1.0;
3353  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3354 
3355  /* create monomial for second child */
3356  childidx = 1;
3357  exponent = 1.0;
3358  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], 1.0, 1, &childidx, &exponent) );
3359 
3360  /* create polynomial for sum of children */
3361  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3362 
3363  *op = SCIP_EXPR_POLYNOMIAL;
3364  data->data = (void*)polynomialdata;
3365 
3366  break;
3367  }
3368 
3369  case SCIP_EXPR_MINUS:
3370  {
3371  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3372  SCIP_EXPRDATA_MONOMIAL* monomials[2];
3373  int childidx;
3374  SCIP_Real exponent;
3375 
3376  assert(nchildren == 2);
3377 
3378  /* create monomial for first child */
3379  childidx = 0;
3380  exponent = 1.0;
3381  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[0], 1.0, 1, &childidx, &exponent) );
3382 
3383  /* create monomial for second child */
3384  childidx = 1;
3385  exponent = 1.0;
3386  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomials[1], -1.0, 1, &childidx, &exponent) );
3387 
3388  /* create polynomial for difference of children */
3389  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 2, monomials, 0.0, FALSE) );
3390 
3391  *op = SCIP_EXPR_POLYNOMIAL;
3392  data->data = (void*)polynomialdata;
3393 
3394  break;
3395  }
3396 
3397  case SCIP_EXPR_MUL:
3398  {
3399  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3400  SCIP_EXPRDATA_MONOMIAL* monomial;
3401  int childidx[2];
3402  SCIP_Real exponent[2];
3403 
3404  assert(nchildren == 2);
3405 
3406  /* create monomial for product of children */
3407  childidx[0] = 0;
3408  childidx[1] = 1;
3409  exponent[0] = 1.0;
3410  exponent[1] = 1.0;
3411  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3412 
3413  /* create polynomial */
3414  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3415 
3416  *op = SCIP_EXPR_POLYNOMIAL;
3417  data->data = (void*)polynomialdata;
3418 
3419  break;
3420  }
3421 
3422  case SCIP_EXPR_DIV:
3423  {
3424  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3425  SCIP_EXPRDATA_MONOMIAL* monomial;
3426  int childidx[2];
3427  SCIP_Real exponent[2];
3428 
3429  assert(nchildren == 2);
3430 
3431  /* create monomial for division of children */
3432  childidx[0] = 0;
3433  childidx[1] = 1;
3434  exponent[0] = 1.0;
3435  exponent[1] = -1.0;
3436  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 2, childidx, exponent) );
3437 
3438  /* create polynomial */
3439  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3440 
3441  *op = SCIP_EXPR_POLYNOMIAL;
3442  data->data = (void*)polynomialdata;
3443 
3444  break;
3445  }
3446 
3447  case SCIP_EXPR_SQUARE:
3448  {
3449  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3450  SCIP_EXPRDATA_MONOMIAL* monomial;
3451  int childidx;
3452  SCIP_Real exponent;
3453 
3454  assert(nchildren == 1);
3455 
3456  /* create monomial for square of child */
3457  childidx = 0;
3458  exponent = 2.0;
3459  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3460 
3461  /* create polynomial */
3462  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3463 
3464  *op = SCIP_EXPR_POLYNOMIAL;
3465  data->data = (void*)polynomialdata;
3466 
3467  break;
3468  }
3469 
3470  case SCIP_EXPR_SQRT:
3471  {
3472  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3473  SCIP_EXPRDATA_MONOMIAL* monomial;
3474  int childidx;
3475  SCIP_Real exponent;
3476 
3477  assert(nchildren == 1);
3478 
3479  /* create monomial for square root of child */
3480  childidx = 0;
3481  exponent = 0.5;
3482  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3483 
3484  /* create polynomial */
3485  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3486 
3487  *op = SCIP_EXPR_POLYNOMIAL;
3488  data->data = (void*)polynomialdata;
3489 
3490  break;
3491  }
3492 
3493  case SCIP_EXPR_REALPOWER:
3494  {
3495  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3496  SCIP_EXPRDATA_MONOMIAL* monomial;
3497  int childidx;
3498 
3499  assert(nchildren == 1);
3500 
3501  /* convert to child0 to the power of exponent */
3502 
3503  /* create monomial for power of first child */
3504  childidx = 0;
3505  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &data->dbl) );
3506 
3507  /* create polynomial */
3508  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3509 
3510  *op = SCIP_EXPR_POLYNOMIAL;
3511  data->data = (void*)polynomialdata;
3512 
3513  break;
3514  }
3515 
3516  case SCIP_EXPR_SIGNPOWER:
3517  {
3518  SCIP_Real exponent;
3519 
3520  assert(nchildren == 1);
3521 
3522  /* check if exponent is an odd integer */
3523  exponent = data->dbl;
3524  if( EPSISINT(exponent, 0.0) && (int)exponent % 2 != 0 ) /*lint !e835*/
3525  {
3526  /* convert to child0 to the power of exponent, since sign is kept by taking power */
3527  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3528  SCIP_EXPRDATA_MONOMIAL* monomial;
3529  int childidx;
3530 
3531  /* create monomial for power of first child */
3532  childidx = 0;
3533  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3534 
3535  /* create polynomial */
3536  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3537 
3538  *op = SCIP_EXPR_POLYNOMIAL;
3539  data->data = (void*)polynomialdata;
3540  }
3541  /* if exponent is not an odd integer constant, then keep it as signpower expression */
3542  break;
3543  }
3544 
3545  case SCIP_EXPR_INTPOWER:
3546  {
3547  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3548  SCIP_EXPRDATA_MONOMIAL* monomial;
3549  int childidx;
3550  SCIP_Real exponent;
3551 
3552  assert(nchildren == 1);
3553 
3554  /* create monomial for power of child */
3555  childidx = 0;
3556  exponent = data->intval;
3557  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3558 
3559  /* create polynomial */
3560  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3561 
3562  *op = SCIP_EXPR_POLYNOMIAL;
3563  data->data = (void*)polynomialdata;
3564 
3565  break;
3566  }
3567 
3568  case SCIP_EXPR_EXP:
3569  case SCIP_EXPR_LOG:
3570  case SCIP_EXPR_SIN:
3571  case SCIP_EXPR_COS:
3572  case SCIP_EXPR_TAN:
3573  /* case SCIP_EXPR_ERF: */
3574  /* case SCIP_EXPR_ERFI: */
3575  case SCIP_EXPR_MIN:
3576  case SCIP_EXPR_MAX:
3577  case SCIP_EXPR_ABS:
3578  case SCIP_EXPR_SIGN:
3579  case SCIP_EXPR_USER:
3580  break;
3581 
3582  case SCIP_EXPR_SUM:
3583  {
3584  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3585  SCIP_EXPRDATA_MONOMIAL* monomial;
3586  int childidx;
3587  int i;
3588  SCIP_Real exponent;
3589 
3590  /* create empty polynomial */
3591  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, 0.0, FALSE) );
3592  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3593  assert(polynomialdata->monomialssize >= nchildren);
3594 
3595  /* add summands as monomials */
3596  childidx = 0;
3597  exponent = 1.0;
3598  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3599  for( i = 0; i < nchildren; ++i )
3600  {
3601  monomial->childidxs[0] = i;
3602  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3603  }
3604  SCIPexprFreeMonomial(blkmem, &monomial);
3605 
3606  *op = SCIP_EXPR_POLYNOMIAL;
3607  data->data = (void*)polynomialdata;
3608 
3609  break;
3610  }
3611 
3612  case SCIP_EXPR_PRODUCT:
3613  {
3614  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3615  SCIP_EXPRDATA_MONOMIAL* monomial;
3616  int childidx;
3617  int i;
3618  SCIP_Real exponent;
3619 
3620  /* create monomial */
3621  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 0, NULL, NULL) );
3622  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, nchildren) );
3623  exponent = 1.0;
3624  for( i = 0; i < nchildren; ++i )
3625  {
3626  childidx = i;
3627  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, 1, &childidx, &exponent) );
3628  }
3629 
3630  /* create polynomial */
3631  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 1, &monomial, 0.0, FALSE) );
3632 
3633  *op = SCIP_EXPR_POLYNOMIAL;
3634  data->data = (void*)polynomialdata;
3635 
3636  break;
3637  }
3638 
3639  case SCIP_EXPR_LINEAR:
3640  {
3641  SCIP_Real* lineardata;
3642  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3643  SCIP_EXPRDATA_MONOMIAL* monomial;
3644  int childidx;
3645  int i;
3646  SCIP_Real exponent;
3647 
3648  /* get coefficients of linear term */
3649  lineardata = (SCIP_Real*)data->data;
3650  assert(lineardata != NULL);
3651 
3652  /* create polynomial consisting of constant from linear term */
3653  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, lineardata[nchildren], FALSE) );
3654  /* ensure space for linear coefficients */
3655  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, nchildren) );
3656  assert(polynomialdata->monomialssize >= nchildren);
3657 
3658  /* add summands as monomials */
3659  childidx = 0;
3660  exponent = 1.0;
3661  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &monomial, 1.0, 1, &childidx, &exponent) );
3662  for( i = 0; i < nchildren; ++i )
3663  {
3664  monomial->coef = lineardata[i];
3665  monomial->childidxs[0] = i;
3666  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &monomial, TRUE) );
3667  }
3668  SCIPexprFreeMonomial(blkmem, &monomial);
3669 
3670  /* free linear expression data */
3671  exprFreeDataLinear(blkmem, nchildren, *data);
3672 
3673  *op = SCIP_EXPR_POLYNOMIAL;
3674  data->data = (void*)polynomialdata;
3675 
3676  break;
3677  }
3678 
3679  case SCIP_EXPR_QUADRATIC:
3680  {
3681  SCIP_EXPRDATA_QUADRATIC* quaddata;
3682  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3683  SCIP_EXPRDATA_MONOMIAL* squaremonomial;
3684  SCIP_EXPRDATA_MONOMIAL* bilinmonomial;
3685  SCIP_EXPRDATA_MONOMIAL* linmonomial;
3686  int childidx[2];
3687  SCIP_Real exponent[2];
3688  int i;
3689 
3690  /* get data of quadratic expression */
3691  quaddata = (SCIP_EXPRDATA_QUADRATIC*)data->data;
3692  assert(quaddata != NULL);
3693 
3694  /* create empty polynomial */
3695  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, quaddata->constant, FALSE) );
3696  /* ensure space for linear and quadratic terms */
3697  SCIP_CALL( polynomialdataEnsureMonomialsSize(blkmem, polynomialdata, (quaddata->lincoefs != NULL ? nchildren : 0) + quaddata->nquadelems) );
3698  assert(polynomialdata->monomialssize >= quaddata->nquadelems);
3699 
3700  childidx[0] = 0;
3701  childidx[1] = 0;
3702 
3703  /* create monomial templates */
3704  exponent[0] = 2.0;
3705  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &squaremonomial, 1.0, 1, childidx, exponent) );
3706  exponent[0] = 1.0;
3707  exponent[1] = 1.0;
3708  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &bilinmonomial, 1.0, 2, childidx, exponent) );
3709  SCIP_CALL( SCIPexprCreateMonomial(blkmem, &linmonomial, 1.0, 1, childidx, exponent) );
3710 
3711  /* add linear terms as monomials */
3712  if( quaddata->lincoefs != NULL )
3713  for( i = 0; i < nchildren; ++i )
3714  if( quaddata->lincoefs[i] != 0.0 )
3715  {
3716  linmonomial->childidxs[0] = i;
3717  linmonomial->coef = quaddata->lincoefs[i];
3718  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &linmonomial, TRUE) );
3719  }
3720 
3721  /* add quadratic terms as monomials */
3722  for( i = 0; i < quaddata->nquadelems; ++i )
3723  {
3724  if( quaddata->quadelems[i].idx1 == quaddata->quadelems[i].idx2 )
3725  {
3726  squaremonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3727  squaremonomial->coef = quaddata->quadelems[i].coef;
3728  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &squaremonomial, TRUE) );
3729  }
3730  else
3731  {
3732  bilinmonomial->childidxs[0] = quaddata->quadelems[i].idx1;
3733  bilinmonomial->childidxs[1] = quaddata->quadelems[i].idx2;
3734  bilinmonomial->coef = quaddata->quadelems[i].coef;
3735  SCIP_CALL( polynomialdataAddMonomials(blkmem, polynomialdata, 1, &bilinmonomial, TRUE) );
3736  }
3737  }
3738  SCIPexprFreeMonomial(blkmem, &squaremonomial);
3739  SCIPexprFreeMonomial(blkmem, &bilinmonomial);
3740  SCIPexprFreeMonomial(blkmem, &linmonomial);
3741 
3742  /* free quadratic expression data */
3743  exprFreeDataQuadratic(blkmem, nchildren, *data);
3744 
3745  *op = SCIP_EXPR_POLYNOMIAL;
3746  data->data = (void*)polynomialdata;
3747 
3748  break;
3749  }
3750 
3751  case SCIP_EXPR_POLYNOMIAL:
3752  case SCIP_EXPR_LAST:
3753  break;
3754  } /*lint !e788*/
3755 
3756  return SCIP_OKAY;
3757 }
3758 
3759 /** converts polynomial expression back into simpler expression, if possible */
3760 static
3762  BMS_BLKMEM* blkmem, /**< block memory data structure */
3763  SCIP_EXPROP* op, /**< pointer to expression operator */
3764  SCIP_EXPROPDATA* data, /**< pointer to expression data holding polynomial data */
3765  int nchildren, /**< number of children of operator */
3766  void** children /**< children array */
3767  )
3768 {
3769  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
3770  SCIP_EXPRDATA_MONOMIAL* monomial;
3771  int maxdegree;
3772  int nlinmonomials;
3773  int i;
3774  int j;
3775 
3776  assert(blkmem != NULL);
3777  assert(op != NULL);
3778  assert(*op == SCIP_EXPR_POLYNOMIAL);
3779  assert(data != NULL);
3780  assert(children != NULL || nchildren == 0);
3781 
3782  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)data->data;
3783  assert(polynomialdata != NULL);
3784 
3785  /* make sure monomials are sorted and merged */
3786  polynomialdataMergeMonomials(blkmem, polynomialdata, 0.0, TRUE);
3787 
3788  /* if no monomials, then leave as it is */
3789  if( polynomialdata->nmonomials == 0 )
3790  return SCIP_OKAY;
3791 
3792  /* check maximal degree of polynomial only - not considering children expressions
3793  * check number of linear monomials */
3794  maxdegree = 0;
3795  nlinmonomials = 0;
3796  for( i = 0; i < polynomialdata->nmonomials; ++i )
3797  {
3798  int monomialdegree;
3799 
3800  monomial = polynomialdata->monomials[i];
3801  assert(monomial != NULL);
3802 
3803  monomialdegree = 0;
3804  for(j = 0; j < monomial->nfactors; ++j )
3805  {
3806  if( !EPSISINT(monomial->exponents[j], 0.0) || monomial->exponents[j] < 0.0 ) /*lint !e835*/
3807  {
3808  monomialdegree = SCIP_EXPR_DEGREEINFINITY;
3809  break;
3810  }
3811 
3812  monomialdegree += (int)EPSROUND(monomial->exponents[j], 0.0); /*lint !e835*/
3813  }
3814 
3815  if( monomialdegree == SCIP_EXPR_DEGREEINFINITY )
3816  {
3817  maxdegree = SCIP_EXPR_DEGREEINFINITY;
3818  break;
3819  }
3820 
3821  if( monomialdegree == 1 )
3822  ++nlinmonomials;
3823 
3824  if( monomialdegree > maxdegree )
3825  maxdegree = monomialdegree;
3826  }
3827  assert(maxdegree > 0 );
3828 
3829  if( maxdegree == 1 )
3830  {
3831  /* polynomial is a linear expression in children */
3832 
3833  /* polynomial simplification and monomial merging should ensure that monomial i corresponds to child i and that there are not unused children */
3834  assert(polynomialdata->nmonomials == nchildren);
3835  assert(polynomialdata->nmonomials == nlinmonomials);
3836 
3837  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3838  {
3839  /* polynomial is addition of two expressions, so turn into SCIP_EXPR_PLUS */
3840  assert(polynomialdata->monomials[0]->nfactors == 1);
3841  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3842  assert(polynomialdata->monomials[1]->nfactors == 1);
3843  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3844 
3845  polynomialdataFree(blkmem, &polynomialdata);
3846  data->data = NULL;
3847 
3848  /* change operator type to PLUS */
3849  *op = SCIP_EXPR_PLUS;
3850 
3851  return SCIP_OKAY;
3852  }
3853 
3854  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == 1.0 && polynomialdata->monomials[1]->coef == -1.0 )
3855  {
3856  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3857  assert(polynomialdata->monomials[0]->nfactors == 1);
3858  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3859  assert(polynomialdata->monomials[1]->nfactors == 1);
3860  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3861 
3862  polynomialdataFree(blkmem, &polynomialdata);
3863  data->data = NULL;
3864 
3865  /* change operator type to MINUS */
3866  *op = SCIP_EXPR_MINUS;
3867 
3868  return SCIP_OKAY;
3869  }
3870 
3871  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 2 && polynomialdata->monomials[0]->coef == -1.0 && polynomialdata->monomials[1]->coef == 1.0 )
3872  {
3873  /* polynomial is substraction of two expressions, so turn into SCIP_EXPR_MINUS */
3874  void* tmp;
3875 
3876  assert(polynomialdata->monomials[0]->nfactors == 1);
3877  assert(polynomialdata->monomials[0]->exponents[0] == 1.0);
3878  assert(polynomialdata->monomials[1]->nfactors == 1);
3879  assert(polynomialdata->monomials[1]->exponents[0] == 1.0);
3880 
3881  polynomialdataFree(blkmem, &polynomialdata);
3882  data->data = NULL;
3883 
3884  /* swap children */
3885  tmp = children[1]; /*lint !e613*/
3886  children[1] = children[0]; /*lint !e613*/
3887  children[0] = tmp; /*lint !e613*/
3888 
3889  /* change operator type to MINUS */
3890  *op = SCIP_EXPR_MINUS;
3891 
3892  return SCIP_OKAY;
3893  }
3894 
3895  if( polynomialdata->constant == 0.0 )
3896  {
3897  /* check if all monomials have coefficient 1.0 */
3898  for( i = 0; i < polynomialdata->nmonomials; ++i )
3899  if( polynomialdata->monomials[i]->coef != 1.0 )
3900  break;
3901 
3902  if( i == polynomialdata->nmonomials )
3903  {
3904  /* polynomial is sum of children, so turn into SCIP_EXPR_SUM */
3905 
3906  polynomialdataFree(blkmem, &polynomialdata);
3907  data->data = NULL;
3908 
3909  /* change operator type to MINUS */
3910  *op = SCIP_EXPR_SUM;
3911 
3912  return SCIP_OKAY;
3913  }
3914  }
3915 
3916  /* turn polynomial into linear expression */
3917  {
3918  SCIP_Real* lindata;
3919 
3920  /* monomial merging should ensure that each child appears in at most one monomial,
3921  * that monomials are ordered according to the child index, and that constant monomials have been removed
3922  */
3923 
3924  /* setup data of linear expression */
3925  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &lindata, polynomialdata->nmonomials + 1) );
3926 
3927  for( i = 0; i < polynomialdata->nmonomials; ++i )
3928  {
3929  assert(polynomialdata->monomials[i]->childidxs[0] == i);
3930  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3931  lindata[i] = polynomialdata->monomials[i]->coef; /*lint !e644*/
3932  }
3933  lindata[i] = polynomialdata->constant;
3934 
3935  polynomialdataFree(blkmem, &polynomialdata);
3936  *op = SCIP_EXPR_LINEAR;
3937  data->data = (void*)lindata;
3938 
3939  return SCIP_OKAY;
3940  }
3941  }
3942 
3943  if( maxdegree == 2 && (polynomialdata->nmonomials > 1 || polynomialdata->constant != 0.0 || polynomialdata->monomials[0]->coef != 1.0) )
3944  {
3945  /* polynomial is quadratic expression with more than one summand or with a constant or a square or bilinear term with coefficient != 1.0, so turn into SCIP_EXPR_QUADRATIC */
3946  SCIP_EXPRDATA_QUADRATIC* quaddata;
3947  int quadelemidx;
3948 
3949  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &quaddata) );
3950  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->quadelems, polynomialdata->nmonomials - nlinmonomials) );
3951  quaddata->nquadelems = polynomialdata->nmonomials - nlinmonomials;
3952  quaddata->constant = polynomialdata->constant;
3953  quaddata->sorted = FALSE; /* quadratic data is sorted different than polynomials */
3954 
3955  if( nlinmonomials > 0 )
3956  {
3957  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &quaddata->lincoefs, nchildren) );
3958  BMSclearMemoryArray(quaddata->lincoefs, nchildren);
3959  }
3960  else
3961  quaddata->lincoefs = NULL;
3962 
3963  quadelemidx = 0;
3964  for( i = 0; i < polynomialdata->nmonomials; ++i )
3965  {
3966  assert(polynomialdata->monomials[i]->nfactors == 1 || polynomialdata->monomials[i]->nfactors == 2);
3967  if( polynomialdata->monomials[i]->nfactors == 1 )
3968  {
3969  if( polynomialdata->monomials[i]->exponents[0] == 1.0 )
3970  {
3971  /* monomial is a linear term */
3972  assert(quaddata->lincoefs != NULL);
3973  quaddata->lincoefs[polynomialdata->monomials[i]->childidxs[0]] += polynomialdata->monomials[i]->coef;
3974  }
3975  else
3976  {
3977  /* monomial should be a square term */
3978  assert(polynomialdata->monomials[i]->exponents[0] == 2.0);
3979  assert(quadelemidx < quaddata->nquadelems);
3980  quaddata->quadelems[quadelemidx].idx1 = polynomialdata->monomials[i]->childidxs[0];
3981  quaddata->quadelems[quadelemidx].idx2 = polynomialdata->monomials[i]->childidxs[0];
3982  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3983  ++quadelemidx;
3984  }
3985  }
3986  else
3987  {
3988  /* monomial should be a bilinear term */
3989  assert(polynomialdata->monomials[i]->exponents[0] == 1.0);
3990  assert(polynomialdata->monomials[i]->exponents[1] == 1.0);
3991  assert(quadelemidx < quaddata->nquadelems);
3992  quaddata->quadelems[quadelemidx].idx1 = MIN(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3993  quaddata->quadelems[quadelemidx].idx2 = MAX(polynomialdata->monomials[i]->childidxs[0], polynomialdata->monomials[i]->childidxs[1]);
3994  quaddata->quadelems[quadelemidx].coef = polynomialdata->monomials[i]->coef;
3995  ++quadelemidx;
3996  }
3997  }
3998  assert(quadelemidx == quaddata->nquadelems);
3999 
4000  polynomialdataFree(blkmem, &polynomialdata);
4001 
4002  *op = SCIP_EXPR_QUADRATIC;
4003  data->data = (void*)quaddata;
4004 
4005  return SCIP_OKAY;
4006  }
4007 
4008  if( polynomialdata->constant == 0.0 && polynomialdata->nmonomials == 1 && polynomialdata->monomials[0]->coef == 1.0 )
4009  {
4010  /* polynomial is product of children */
4011  monomial = polynomialdata->monomials[0];
4012  assert(monomial->nfactors == nchildren);
4013 
4014  if( monomial->nfactors == 1 )
4015  {
4016  /* polynomial is x^k for some k */
4017  assert(monomial->exponents[0] != 1.0); /* should have been handled before */
4018  assert(monomial->childidxs[0] == 0);
4019 
4020  if( monomial->exponents[0] == 2.0 )
4021  {
4022  /* polynomial is x^2, so turn into SCIP_EXPR_SQUARE */
4023 
4024  polynomialdataFree(blkmem, &polynomialdata);
4025  data->data = NULL;
4026 
4027  *op = SCIP_EXPR_SQUARE;
4028 
4029  return SCIP_OKAY;
4030  }
4031 
4032  if( EPSISINT(monomial->exponents[0], 0.0) ) /*lint !e835*/
4033  {
4034  /* k is an integer, so turn into SCIP_EXPR_INTPOWER */
4035  int exponent;
4036 
4037  exponent = (int)EPSROUND(monomial->exponents[0], 0.0); /*lint !e835*/
4038 
4039  polynomialdataFree(blkmem, &polynomialdata);
4040 
4041  *op = SCIP_EXPR_INTPOWER;
4042  data->intval = exponent;
4043 
4044  return SCIP_OKAY;
4045  }
4046 
4047  if( monomial->exponents[0] == 0.5 )
4048  {
4049  /* polynomial is sqrt(x), so turn into SCIP_EXPR_SQRT */
4050 
4051  polynomialdataFree(blkmem, &polynomialdata);
4052  data->data = NULL;
4053 
4054  *op = SCIP_EXPR_SQRT;
4055 
4056  return SCIP_OKAY;
4057  }
4058 
4059  {
4060  /* polynomial is x^a with a some real number, so turn into SCIP_EXPR_REALPOWER */
4061  SCIP_Real exponent;
4062 
4063  exponent = monomial->exponents[0];
4064 
4065  polynomialdataFree(blkmem, &polynomialdata);
4066 
4067  *op = SCIP_EXPR_REALPOWER;
4068  data->dbl = exponent;
4069 
4070  return SCIP_OKAY;
4071  }
4072  }
4073 
4074  if( maxdegree == 2 && monomial->nfactors == 2 )
4075  {
4076  /* polynomial is product of two children, so turn into SCIP_EXPR_MUL */
4077  assert(monomial->exponents[0] == 1.0);
4078  assert(monomial->exponents[1] == 1.0);
4079 
4080  polynomialdataFree(blkmem, &polynomialdata);
4081  data->data = NULL;
4082 
4083  *op = SCIP_EXPR_MUL;
4084 
4085  return SCIP_OKAY;
4086  }
4087 
4088  if( maxdegree == monomial->nfactors )
4089  {
4090  /* polynomial is a product of n children, so turn into SCIP_EXPR_PRODUCT */
4091 
4092  polynomialdataFree(blkmem, &polynomialdata);
4093  data->data = NULL;
4094 
4095  *op = SCIP_EXPR_PRODUCT;
4096 
4097  return SCIP_OKAY;
4098  }
4099 
4100  if( monomial->nfactors == 2 && monomial->exponents[0] == 1.0 && monomial->exponents[1] == -1.0 )
4101  {
4102  /* polynomial is x/y, so turn into SCIP_EXPR_DIV */
4103  assert(monomial->childidxs[0] == 0);
4104  assert(monomial->childidxs[1] == 1);
4105 
4106  polynomialdataFree(blkmem, &polynomialdata);
4107  data->data = NULL;
4108 
4109  *op = SCIP_EXPR_DIV;
4110 
4111  return SCIP_OKAY;
4112  }
4113 
4114  if( monomial->nfactors == 2 && monomial->exponents[0] == -1.0 && monomial->exponents[1] == 1.0 )
4115  {
4116  /* polynomial is y/x, so turn into SCIP_EXPR_DIV */
4117  void* tmp;
4118 
4119  assert(monomial->childidxs[0] == 0);
4120  assert(monomial->childidxs[1] == 1);
4121 
4122  polynomialdataFree(blkmem, &polynomialdata);
4123  data->data = NULL;
4124 
4125  /* swap children */
4126  tmp = children[1]; /*lint !e613*/
4127  children[1] = children[0]; /*lint !e613*/
4128  children[0] = tmp; /*lint !e613*/
4129 
4130  *op = SCIP_EXPR_DIV;
4131 
4132  return SCIP_OKAY;
4133  }
4134  }
4135 
4136  return SCIP_OKAY;
4137 }
4138 
4139 /** adds copies of expressions to the array of children of a sum, product, linear, quadratic, or polynomial expression
4140  *
4141  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
4142  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
4143  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
4144  */
4145 static
4147  BMS_BLKMEM* blkmem, /**< block memory */
4148  SCIP_EXPR* expr, /**< quadratic or polynomial expression */
4149  int nexprs, /**< number of expressions to add */
4150  SCIP_EXPR** exprs, /**< expressions to add */
4151  SCIP_Bool comparechildren, /**< whether to compare expressions with already existing children (no effect for sum and product) */
4152  SCIP_Real eps, /**< which epsilon to use when comparing expressions */
4153  int* childmap /**< array where to store mapping of indices from exprs to children array in expr, or NULL if not of interest */
4154  )
4155 {
4156  int i;
4157 
4158  assert(blkmem != NULL);
4159  assert(expr != NULL);
4160  assert(expr->op == SCIP_EXPR_SUM || expr->op == SCIP_EXPR_PRODUCT || expr->op == SCIP_EXPR_LINEAR || expr->op == SCIP_EXPR_QUADRATIC || expr->op == SCIP_EXPR_POLYNOMIAL);
4161  assert(exprs != NULL || nexprs == 0);
4162 
4163  if( nexprs == 0 )
4164  return SCIP_OKAY;
4165 
4166  switch( expr->op )
4167  {
4168  case SCIP_EXPR_SUM:
4169  case SCIP_EXPR_PRODUCT:
4170  {
4171  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4172  for( i = 0; i < nexprs; ++i )
4173  {
4174  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren + i], exprs[i]) ); /*lint !e613*/
4175  if( childmap != NULL )
4176  childmap[i] = expr->nchildren + i;
4177  }
4178  expr->nchildren += nexprs;
4179 
4180  break;
4181  }
4182 
4183  case SCIP_EXPR_LINEAR:
4184  case SCIP_EXPR_QUADRATIC:
4185  case SCIP_EXPR_POLYNOMIAL:
4186  {
4187  int j;
4188  int orignchildren;
4189  SCIP_Bool existsalready;
4190 
4191  orignchildren = expr->nchildren;
4192  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nexprs) );
4193 
4194  for( i = 0; i < nexprs; ++i )
4195  {
4196  existsalready = FALSE;
4197  if( comparechildren )
4198  for( j = 0; j < orignchildren; ++j )
4199  /* during simplification of polynomials, their may be NULL's in children array */
4200  if( expr->children[j] != NULL && SCIPexprAreEqual(expr->children[j], exprs[i], eps) ) /*lint !e613*/
4201  {
4202  existsalready = TRUE;
4203  break;
4204  }
4205 
4206  if( !existsalready )
4207  {
4208  /* add copy of exprs[j] to children array */
4209  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[expr->nchildren], exprs[i]) ); /*lint !e613*/
4210  if( childmap != NULL )
4211  childmap[i] = expr->nchildren;
4212  ++expr->nchildren;
4213  }
4214  else
4215  {
4216  if( childmap != NULL )
4217  childmap[i] = j; /*lint !e644*/
4218  if( expr->op == SCIP_EXPR_LINEAR )
4219  {
4220  /* if linear expression, increase coefficient by 1.0 */
4221  ((SCIP_Real*)expr->data.data)[j] += 1.0;
4222  }
4223  }
4224  }
4225 
4226  /* shrink children array to actually used size */
4227  assert(comparechildren || expr->nchildren == orignchildren + nexprs);
4228  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, orignchildren + nexprs, expr->nchildren) );
4229 
4230  if( expr->op == SCIP_EXPR_LINEAR && expr->nchildren > orignchildren )
4231  {
4232  /* if linear expression, then add 1.0 coefficients for new expressions */
4233  SCIP_Real* data;
4234 
4235  data = (SCIP_Real*)expr->data.data;
4236  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, expr->nchildren + 1) );
4237  data[expr->nchildren] = data[orignchildren]; /* move constant from old end to new end */
4238  for( i = orignchildren; i < expr->nchildren; ++i )
4239  data[i] = 1.0;
4240  expr->data.data = (void*)data;
4241  }
4242  else if( expr->op == SCIP_EXPR_QUADRATIC && expr->nchildren > orignchildren )
4243  {
4244  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
4246 
4247  data = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
4248  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, expr->nchildren) );
4249  BMSclearMemoryArray(&data->lincoefs[orignchildren], expr->nchildren - orignchildren); /*lint !e866*/
4250  }
4251 
4252  break;
4253  }
4254 
4255  default:
4256  SCIPerrorMessage("exprsimplifyAddChildren cannot be called for operand %d\n", expr->op);
4257  return SCIP_INVALIDDATA;
4258  } /*lint !e788*/
4259 
4260  return SCIP_OKAY;
4261 }
4262 
4263 /** converts expressions into polynomials, where possible and obvious */
4264 static
4266  BMS_BLKMEM* blkmem, /**< block memory data structure */
4267  SCIP_EXPR* expr /**< expression to convert */
4268  )
4269 {
4270  int i;
4271 
4272  assert(expr != NULL);
4273 
4274  for( i = 0; i < expr->nchildren; ++i )
4275  {
4277  }
4278 
4279  SCIP_CALL( exprConvertToPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren) );
4280 
4281  return SCIP_OKAY;
4282 }
4283 
4284 /** removes duplicate children in a polynomial expression
4285  *
4286  * Leaves NULL's in children array.
4287  */
4288 static
4290  BMS_BLKMEM* blkmem, /**< block memory data structure */
4291  SCIP_EXPR* expr, /**< expression */
4292  SCIP_Real eps /**< threshold for zero */
4293  )
4294 {
4295  SCIP_Bool foundduplicates;
4296  int* childmap;
4297  int i;
4298  int j;
4299 
4300  assert(blkmem != NULL);
4301  assert(expr != NULL);
4302  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4303 
4304  if( expr->nchildren == 0 )
4305  return SCIP_OKAY;
4306 
4307  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4308 
4309  foundduplicates = FALSE;
4310  for( i = 0; i < expr->nchildren; ++i )
4311  {
4312  if( expr->children[i] == NULL )
4313  continue;
4314  childmap[i] = i; /*lint !e644*/
4315 
4316  for( j = i+1; j < expr->nchildren; ++j )
4317  {
4318  if( expr->children[j] == NULL )
4319  continue;
4320 
4321  if( SCIPexprAreEqual(expr->children[i], expr->children[j], eps) )
4322  {
4323  /* forget about expr j and remember that is to be replaced by i */
4324  SCIPexprFreeDeep(blkmem, &expr->children[j]);
4325  childmap[j] = i;
4326  foundduplicates = TRUE;
4327  }
4328  }
4329  }
4330 
4331  /* apply childmap to monomials */
4332  if( foundduplicates )
4334 
4335  /* free childmap */
4336  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4337 
4338  return SCIP_OKAY;
4339 }
4340 
4341 /** eliminates NULL's in children array and shrinks it to actual size */
4342 static
4344  BMS_BLKMEM* blkmem, /**< block memory data structure */
4345  SCIP_EXPR* expr /**< expression */
4346  )
4347 {
4348  int* childmap;
4349  int lastnonnull;
4350  int i;
4351 
4352  assert(blkmem != NULL);
4353  assert(expr != NULL);
4354  assert(SCIPexprGetOperator(expr) == SCIP_EXPR_POLYNOMIAL);
4355 
4356  if( expr->nchildren == 0 )
4357  return SCIP_OKAY;
4358 
4359  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, expr->nchildren) );
4360 
4361  /* close gaps in children array */
4362  lastnonnull = expr->nchildren-1;
4363  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4364  --lastnonnull;
4365  for( i = 0; i <= lastnonnull; ++i )
4366  {
4367  if( expr->children[i] != NULL )
4368  {
4369  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
4370  continue;
4371  }
4372  assert(expr->children[lastnonnull] != NULL);
4373 
4374  /* move child at lastnonnull to position i */
4375  expr->children[i] = expr->children[lastnonnull];
4376  expr->children[lastnonnull] = NULL;
4377  childmap[lastnonnull] = i;
4378 
4379  /* update lastnonnull */
4380  --lastnonnull;
4381  while( lastnonnull >= 0 && expr->children[lastnonnull] == NULL )
4382  --lastnonnull;
4383  }
4384  assert(i > lastnonnull);
4385 
4386  /* apply childmap to monomials */
4387  if( lastnonnull < expr->nchildren-1 )
4389 
4390  BMSfreeBlockMemoryArray(blkmem, &childmap, expr->nchildren);
4391 
4392  /* shrink children array */
4393  if( lastnonnull >= 0 )
4394  {
4395  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, lastnonnull+1) );
4396  expr->nchildren = lastnonnull+1;
4397  }
4398  else
4399  {
4400  BMSfreeBlockMemoryArray(blkmem, &expr->children, expr->nchildren);
4401  expr->nchildren = 0;
4402  }
4403 
4404  return SCIP_OKAY;
4405 }
4406 
4407 /** checks which children are still in use and frees those which are not */
4408 static
4410  BMS_BLKMEM* blkmem, /**< block memory data structure */
4411  SCIP_EXPR* expr /**< polynomial expression */
4412  )
4413 {
4414  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4415  SCIP_EXPRDATA_MONOMIAL* monomial;
4416  SCIP_Bool* childinuse;
4417  int i;
4418  int j;
4419 
4420  assert(blkmem != NULL);
4421  assert(expr != NULL);
4422 
4423  if( expr->nchildren == 0 )
4424  return SCIP_OKAY;
4425 
4426  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4427  assert(polynomialdata != NULL);
4428 
4429  /* check which children are still in use */
4430  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, expr->nchildren) );
4431  BMSclearMemoryArray(childinuse, expr->nchildren); /*lint !e644*/
4432  for( i = 0; i < polynomialdata->nmonomials; ++i )
4433  {
4434  monomial = polynomialdata->monomials[i];
4435  assert(monomial != NULL);
4436 
4437  for( j = 0; j < monomial->nfactors; ++j )
4438  {
4439  assert(monomial->childidxs[j] >= 0);
4440  assert(monomial->childidxs[j] < expr->nchildren);
4441  childinuse[monomial->childidxs[j]] = TRUE;
4442  }
4443  }
4444 
4445  /* free children that are not used in any monomial */
4446  for( i = 0; i < expr->nchildren; ++i )
4447  if( expr->children[i] != NULL && !childinuse[i] )
4448  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4449 
4450  BMSfreeBlockMemoryArray(blkmem, &childinuse, expr->nchildren);
4451 
4452  return SCIP_OKAY;
4453 }
4454 
4455 /** flattens polynomials in polynomials, check for constants in non-polynomials expressions
4456  *
4457  * exprsimplifyConvertToPolynomials should have been called before to eliminate simple polynomial operands.
4458  */
4459 static
4461  BMS_BLKMEM* blkmem, /**< block memory data structure */
4462  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
4463  SCIP_EXPR* expr, /**< expression */
4464  SCIP_Real eps, /**< threshold, under which values are treat as 0 */
4465  int maxexpansionexponent/**< maximal exponent for which we still expand non-monomial polynomials */
4466  )
4467 {
4468  int i;
4469 
4470  assert(expr != NULL);
4471 
4472  for( i = 0; i < expr->nchildren; ++i )
4473  {
4474  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr->children[i], eps, maxexpansionexponent) );
4475  }
4476 
4477  switch( SCIPexprGetOperator(expr) )
4478  {
4479  case SCIP_EXPR_VARIDX:
4480  case SCIP_EXPR_CONST:
4481  case SCIP_EXPR_PARAM:
4482  case SCIP_EXPR_PLUS:
4483  case SCIP_EXPR_MINUS:
4484  case SCIP_EXPR_MUL:
4485  case SCIP_EXPR_DIV:
4486  case SCIP_EXPR_SQUARE:
4487  case SCIP_EXPR_SQRT:
4488  case SCIP_EXPR_INTPOWER:
4489  case SCIP_EXPR_REALPOWER:
4490  case SCIP_EXPR_SIGNPOWER:
4491  break;
4492 
4493  case SCIP_EXPR_EXP:
4494  case SCIP_EXPR_LOG:
4495  case SCIP_EXPR_SIN:
4496  case SCIP_EXPR_COS:
4497  case SCIP_EXPR_TAN:
4498  /* case SCIP_EXPR_ERF: */
4499  /* case SCIP_EXPR_ERFI: */
4500  case SCIP_EXPR_ABS:
4501  case SCIP_EXPR_SIGN:
4502  {
4503  /* check if argument is a constant */
4504  if( (expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) ||
4505  expr->children[0]->op == SCIP_EXPR_CONST )
4506  {
4507  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4508  SCIP_Real exprval;
4509 
4510  /* since child0 has no children and it's polynomial was flattened, it should have no monomials */
4511  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4512 
4513  /* evaluate expression in constant polynomial */
4514  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4515 
4516  /* create polynomial */
4517  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4518 
4519  expr->op = SCIP_EXPR_POLYNOMIAL;
4520  expr->data.data = (void*)polynomialdata;
4521 
4522  /* forget child */
4523  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4524  BMSfreeBlockMemoryArray(blkmem, &expr->children, 1);
4525  expr->nchildren = 0;
4526  }
4527 
4528  break;
4529  }
4530 
4531  case SCIP_EXPR_MIN:
4532  case SCIP_EXPR_MAX:
4533  {
4534  /* check if both arguments are constants */
4535  if( ((expr->children[0]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[0]) == 0) || expr->children[0]->op == SCIP_EXPR_CONST) &&
4536  ((expr->children[1]->op == SCIP_EXPR_POLYNOMIAL && SCIPexprGetNChildren(expr->children[1]) == 0) || expr->children[1]->op == SCIP_EXPR_CONST) )
4537  {
4538  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4539  SCIP_Real exprval;
4540 
4541  /* since children have no children and it's polynomial was flattened, it should have no monomials */
4542  assert(expr->children[0]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[0]) == 0);
4543  assert(expr->children[1]->op != SCIP_EXPR_POLYNOMIAL || SCIPexprGetNMonomials(expr->children[1]) == 0);
4544 
4545  /* evaluate expression in constants */
4546  SCIP_CALL( SCIPexprEval(expr, NULL, NULL, &exprval) );
4547 
4548  /* create polynomial */
4549  SCIP_CALL( polynomialdataCreate(blkmem, &polynomialdata, 0, NULL, exprval, FALSE) );
4550 
4551  expr->op = SCIP_EXPR_POLYNOMIAL;
4552  expr->data.data = (void*)polynomialdata;
4553 
4554  /* forget children */
4555  SCIPexprFreeDeep(blkmem, &expr->children[0]);
4556  SCIPexprFreeDeep(blkmem, &expr->children[1]);
4557  BMSfreeBlockMemoryArray(blkmem, &expr->children, 2);
4558  expr->nchildren = 0;
4559  }
4560 
4561  break;
4562  }
4563 
4564  case SCIP_EXPR_SUM:
4565  case SCIP_EXPR_PRODUCT:
4566  case SCIP_EXPR_LINEAR:
4567  case SCIP_EXPR_QUADRATIC:
4568  case SCIP_EXPR_USER:
4569  break;
4570 
4571  case SCIP_EXPR_POLYNOMIAL:
4572  {
4573  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4574  SCIP_EXPRDATA_MONOMIAL* monomial;
4575  SCIP_Bool removechild;
4576  int* childmap;
4577  int childmapsize;
4578  int j;
4579 
4580  /* simplify current polynomial */
4582  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4583 
4584  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4585  assert(polynomialdata != NULL);
4586 
4587  SCIPdebugMessage("expand factors in expression ");
4588  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4589  SCIPdebugPrintf("\n");
4590 
4591  childmap = NULL;
4592  childmapsize = 0;
4593 
4594  /* resolve children that are constants
4595  * we do this first, because it reduces the degree and number of factors in the monomials,
4596  * thereby allowing some expansions of polynomials that may not be possible otherwise, e.g., turning c0*c1 with c0=quadratic and c1=constant into a single monomial
4597  */
4598  for( i = 0; i < expr->nchildren; ++i )
4599  {
4600  if( expr->children[i] == NULL )
4601  continue;
4602 
4603  if( SCIPexprGetOperator(expr->children[i]) != SCIP_EXPR_CONST )
4604  continue;
4605 
4606  removechild = TRUE; /* we intend to delete children[i] */
4607 
4608  if( childmapsize < expr->children[i]->nchildren )
4609  {
4610  int newsize;
4611 
4612  newsize = calcGrowSize(expr->children[i]->nchildren);
4613  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4614  childmapsize = newsize;
4615  }
4616 
4617  /* put constant of child i into every monomial where child i is used */
4618  for( j = 0; j < polynomialdata->nmonomials; ++j )
4619  {
4620  int factorpos;
4621  SCIP_Bool success;
4622 
4623  monomial = polynomialdata->monomials[j];
4624  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4625  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4626 
4627  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4628  {
4629  assert(factorpos >= 0);
4630  assert(factorpos < monomial->nfactors);
4631  /* assert that factors have been merged */
4632  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4633  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4634 
4635  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4636  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4637  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4638 
4639  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && SCIPexprGetOpReal(expr->children[i]) < 0.0 ) /*lint !e835*/
4640  {
4641  /* if constant is negative and our exponent is not integer, then cannot do expansion */
4642  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n",
4643  SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4644  success = FALSE;
4645  }
4646  else
4647  {
4648  monomial->coef *= pow(SCIPexprGetOpReal(expr->children[i]), monomial->exponents[factorpos]);
4649 
4650  /* move last factor to position factorpos */
4651  if( factorpos < monomial->nfactors-1 )
4652  {
4653  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
4654  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
4655  }
4656  --monomial->nfactors;
4657  monomial->sorted = FALSE;
4658  polynomialdata->sorted = FALSE;
4659 
4660  success = TRUE;
4661  }
4662 
4663  if( !success )
4664  removechild = FALSE;
4665  }
4666  }
4667 
4668  /* forget about child i, if it is not used anymore */
4669  if( removechild )
4670  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4671 
4672  /* simplify current polynomial again */
4673  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4674  }
4675 
4676  /* try to resolve children that are polynomials itself */
4677  for( i = 0; i < expr->nchildren; ++i )
4678  {
4679  if( expr->children[i] == NULL )
4680  continue;
4681 
4683  continue;
4684 
4685  removechild = TRUE; /* we intend to delete children[i] */
4686 
4687  if( childmapsize < expr->children[i]->nchildren )
4688  {
4689  int newsize;
4690 
4691  newsize = calcGrowSize(expr->children[i]->nchildren);
4692  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &childmap, childmapsize, newsize) );
4693  childmapsize = newsize;
4694  }
4695 
4696  /* add children of child i */
4697  SCIP_CALL( exprsimplifyAddChildren(blkmem, expr, expr->children[i]->nchildren, expr->children[i]->children, TRUE, eps, childmap) );
4698 
4699  /* put polynomial of child i into every monomial where child i is used */
4700  j = 0;
4701  while( j < polynomialdata->nmonomials )
4702  {
4703  int factorpos;
4704  SCIP_Bool success;
4705 
4706  monomial = polynomialdata->monomials[j];
4707  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
4708  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
4709 
4710  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
4711  {
4712  assert(factorpos >= 0);
4713  assert(factorpos < monomial->nfactors);
4714  /* assert that factors have been merged */
4715  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
4716  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
4717 
4718  /* SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
4719  SCIPdebug( SCIPexprPrint(expr, NULL, NULL, NULL) ); SCIPdebugPrintf("\n");
4720  SCIPdebug( SCIPexprPrint(expr->children[i], NULL, NULL, NULL) ); SCIPdebugPrintf("\n"); */
4721 
4722  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
4723  (SCIP_EXPRDATA_POLYNOMIAL*)expr->children[i]->data.data, childmap, maxexpansionexponent, &success) );
4724 
4725  if( !success )
4726  {
4727  removechild = FALSE;
4728  ++j;
4729  }
4730  }
4731  else
4732  ++j;
4733 
4734  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
4735  * we thus repeat with index j, if a factor was successfully expanded
4736  */
4737  }
4738 
4739  /* forget about child i, if it is not used anymore */
4740  if( removechild )
4741  SCIPexprFreeDeep(blkmem, &expr->children[i]);
4742 
4743  /* simplify current polynomial again */
4744  SCIPexprMergeMonomials(blkmem, expr, eps, TRUE);
4745  }
4746 
4747  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
4748 
4749  /* free children that are not in use anymore */
4751 
4752  /* remove NULLs from children array */
4754 
4755  /* if no children left, then it's a constant polynomial -> change into EXPR_CONST */
4756  if( expr->nchildren == 0 )
4757  {
4758  SCIP_Real val;
4759 
4760  /* if no children, then it should also have no monomials */
4761  assert(polynomialdata->nmonomials == 0);
4762 
4763  val = polynomialdata->constant;
4764  polynomialdataFree(blkmem, &polynomialdata);
4765 
4766  expr->op = SCIP_EXPR_CONST;
4767  expr->data.dbl = val;
4768  }
4769 
4770  SCIPdebugMessage("-> ");
4771  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
4772  SCIPdebugPrintf("\n");
4773 
4774  break;
4775  }
4776 
4777  case SCIP_EXPR_LAST:
4778  break;
4779  } /*lint !e788*/
4780 
4781  return SCIP_OKAY;
4782 }
4783 
4784 /** separates linear monomials from an expression, if it is a polynomial expression
4785  *
4786  * Separates only those linear terms whose variable is not used otherwise in the expression.
4787  */
4788 static
4790  BMS_BLKMEM* blkmem, /**< block memory data structure */
4791  SCIP_EXPR* expr, /**< expression */
4792  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
4793  int nvars, /**< number of variables in expression */
4794  int* nlinvars, /**< buffer to store number of linear variables in linear part */
4795  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part */
4796  SCIP_Real* lincoefs /**< array to store coefficients of linear part */
4797  )
4798 {
4799  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
4800  SCIP_EXPRDATA_MONOMIAL* monomial;
4801  int* varsusage;
4802  int* childusage;
4803  int childidx;
4804  int i;
4805  int j;
4806 
4807  assert(blkmem != NULL);
4808  assert(expr != NULL);
4809  assert(nlinvars != NULL);
4810  assert(linidxs != NULL);
4811  assert(lincoefs != NULL);
4812 
4813  *nlinvars = 0;
4814 
4816  return SCIP_OKAY;
4817 
4818  if( SCIPexprGetNChildren(expr) == 0 )
4819  return SCIP_OKAY;
4820 
4821  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
4822  assert(polynomialdata != NULL);
4823 
4824  /* get variable usage */
4825  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &varsusage, nvars) );
4826  BMSclearMemoryArray(varsusage, nvars); /*lint !e644*/
4827  SCIPexprGetVarsUsage(expr, varsusage);
4828 
4829  /* get child usage: how often each child is used in the polynomial */
4830  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childusage, expr->nchildren) );
4831  BMSclearMemoryArray(childusage, expr->nchildren); /*lint !e644*/
4832  for( i = 0; i < polynomialdata->nmonomials; ++i )
4833  {
4834  monomial = polynomialdata->monomials[i];
4835  assert(monomial != NULL);
4836  for( j = 0; j < monomial->nfactors; ++j )
4837  {
4838  assert(monomial->childidxs[j] >= 0);
4839  assert(monomial->childidxs[j] < expr->nchildren);
4840  ++childusage[monomial->childidxs[j]];
4841  }
4842  }
4843 
4844  /* move linear monomials out of polynomial */
4845  for( i = 0; i < polynomialdata->nmonomials; ++i )
4846  {
4847  monomial = polynomialdata->monomials[i];
4848  assert(monomial != NULL);
4849  if( monomial->nfactors != 1 )
4850  continue;
4851  if( monomial->exponents[0] != 1.0 )
4852  continue;
4853  childidx = monomial->childidxs[0];
4854  if( SCIPexprGetOperator(expr->children[childidx]) != SCIP_EXPR_VARIDX )
4855  continue;
4856 
4857  /* we are at a linear monomial in a variable */
4858  assert(SCIPexprGetOpIndex(expr->children[childidx]) < nvars);
4859  if( childusage[childidx] == 1 && varsusage[SCIPexprGetOpIndex(expr->children[childidx])] == 1 )
4860  {
4861  /* if the child expression is not used in another monomial (which would due to merging be not linear)
4862  * and if the variable is not used somewhere else in the tree,
4863  * then move this monomial into linear part and free child
4864  */
4865  linidxs[*nlinvars] = SCIPexprGetOpIndex(expr->children[childidx]);
4866  lincoefs[*nlinvars] = monomial->coef;
4867  ++*nlinvars;
4868 
4869  SCIPexprFreeDeep(blkmem, &expr->children[childidx]);
4870  monomial->coef = 0.0;
4871  monomial->nfactors = 0;
4872  }
4873  }
4874 
4875  BMSfreeBlockMemoryArray(blkmem, &varsusage, nvars);
4876  BMSfreeBlockMemoryArray(blkmem, &childusage, expr->nchildren);
4877 
4878  if( *nlinvars > 0 )
4879  {
4880  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
4881  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, FALSE);
4883  }
4884 
4885  return SCIP_OKAY;
4886 }
4887 
4888 /** converts polynomial expressions back into simpler expressions, where possible */
4889 static
4891  BMS_BLKMEM* blkmem, /**< block memory data structure */
4892  SCIP_EXPR* expr /**< expression to convert back */
4893  )
4894 {
4895  int i;
4896 
4897  assert(blkmem != NULL);
4898  assert(expr != NULL);
4899 
4900  for( i = 0; i < expr->nchildren; ++i )
4901  {
4903  }
4904 
4905  if( expr->op != SCIP_EXPR_POLYNOMIAL )
4906  return SCIP_OKAY;
4907 
4908  SCIP_CALL( exprUnconvertPolynomial(blkmem, &expr->op, &expr->data, expr->nchildren, (void**)expr->children) );
4909 
4910  return SCIP_OKAY;
4911 }
4912 
4913 static
4914 SCIP_DECL_HASHGETKEY( exprparseVarTableGetKey )
4915 { /*lint --e{715}*/
4916  return (void*)((char*)elem + sizeof(int));
4917 }
4918 
4919 /** parses a variable name from a string and creates corresponding expression
4920  *
4921  * Creates a new variable index if variable not seen before, updates varnames and vartable structures.
4922  */
4923 static
4925  BMS_BLKMEM* blkmem, /**< block memory data structure */
4926  const char** str, /**< pointer to the string to be parsed */
4927  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
4928  int* nvars, /**< running number of encountered variables so far */
4929  int** varnames, /**< pointer to buffer to store new variable names */
4930  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
4931  SCIP_Real coefficient, /**< coefficient to be used when creating the expression */
4932  const char* varnameendptr /**< if a <varname> should be parsed, set this to NULL. Then, str points to the '<'
4933  else, str should point to the first letter of the varname, and varnameendptr should
4934  point one char behind the last char of the variable name */
4935  )
4936 {
4937  int namelength;
4938  int varidx;
4939  char varname[SCIP_MAXSTRLEN];
4940  void* element;
4941 
4942  assert(blkmem != NULL);
4943  assert(str != NULL);
4944  assert(expr != NULL);
4945  assert(nvars != NULL);
4946  assert(varnames != NULL);
4947  assert(vartable != NULL);
4948 
4949  if( varnameendptr == NULL )
4950  {
4951  ++*str;
4952  varnameendptr = *str;
4953  while( varnameendptr[0] != '>' )
4954  ++varnameendptr;
4955  }
4956 
4957  namelength = varnameendptr - *str; /*lint !e712*/
4958  if( namelength >= SCIP_MAXSTRLEN )
4959  {
4960  SCIPerrorMessage("Variable name %.*s is too long for buffer in exprparseReadVariable.\n", namelength, str);
4961  return SCIP_READERROR;
4962  }
4963 
4964  memcpy(varname, *str, namelength * sizeof(char));
4965  varname[namelength] = '\0';
4966 
4967  element = SCIPhashtableRetrieve(vartable, varname);
4968  if( element != NULL )
4969  {
4970  /* variable is old friend */
4971  assert(strcmp((char*)element + sizeof(int), varname) == 0);
4972 
4973  varidx = *(int*)element;
4974  }
4975  else
4976  {
4977  /* variable is new */
4978  varidx = *nvars;
4979 
4980  /* store index of variable and variable name in varnames buffer */
4981  **varnames = varidx;
4982  strcpy((char*)(*varnames + 1), varname);
4983 
4984  /* insert variable into hashtable */
4985  SCIP_CALL( SCIPhashtableInsert(vartable, (void*)*varnames) );
4986 
4987  ++*nvars;
4988  *varnames += 1 + (strlen(varname) + 1) / sizeof(int) + 1;
4989  }
4990 
4991  /* create VARIDX expression, put into LINEAR expression if we have coefficient != 1 */
4992  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_VARIDX, varidx) ); /*lint !e613*/
4993  if( coefficient != 1.0 )
4994  {
4995  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, expr, &coefficient, 0.0) );
4996  }
4997 
4998  /* Move pointer to char behind end of variable */
4999  *str = varnameendptr + 1;
5000 
5001  /* consprint sometimes prints a variable type identifier which we don't need */
5002  if( (*str)[0] == '[' && (*str)[2] == ']' &&
5003  ((*str)[1] == SCIP_VARTYPE_BINARY_CHAR ||
5004  (*str)[1] == SCIP_VARTYPE_INTEGER_CHAR ||
5005  (*str)[1] == SCIP_VARTYPE_IMPLINT_CHAR ||
5006  (*str)[1] == SCIP_VARTYPE_CONTINUOUS_CHAR ) )
5007  *str += 3;
5008 
5009  return SCIP_OKAY;
5010 }
5011 
5012 /** if str[0] points to an opening parenthesis, this function sets endptr to point to the matching closing bracket in str
5013  *
5014  * Searches for at most length characters.
5015  */
5016 static
5018  const char* str, /**< pointer to the string to be parsed */
5019  const char** endptr, /**< pointer to point to the closing parenthesis */
5020  int length /**< length of the string to be parsed */
5021  )
5022 {
5023  int nopenbrackets;
5024 
5025  assert(str[0] == '(');
5026 
5027  *endptr = str;
5028 
5029  /* find the end of this expression */
5030  nopenbrackets = 0;
5031  while( (*endptr - str ) < length && !(nopenbrackets == 1 && *endptr[0] == ')') )
5032  {
5033  if( *endptr[0] == '(')
5034  ++nopenbrackets;
5035  if( *endptr[0] == ')')
5036  --nopenbrackets;
5037  ++*endptr;
5038  }
5039 
5040  if( *endptr[0] != ')' )
5041  {
5042  SCIPerrorMessage("unable to find closing parenthesis in unbalanced expression %.*s\n", length, str);
5043  return SCIP_READERROR;
5044  }
5045 
5046  return SCIP_OKAY;
5047 }
5048 
5049 /** this function sets endptr to point to the next separating comma in str
5050  *
5051  * That is, for a given string like "x+f(x,y),z", endptr will point to the comma before "z"
5052  *
5053  * Searches for at most length characters.
5054  */
5055 static
5057  const char* str, /**< pointer to the string to be parsed */
5058  const char** endptr, /**< pointer to point to the comma */
5059  int length /**< length of the string to be parsed */
5060  )
5061 {
5062  int nopenbrackets;
5063 
5064  *endptr = str;
5065 
5066  /* find a comma without open brackets */
5067  nopenbrackets = 0;
5068  while( (*endptr - str ) < length && !(nopenbrackets == 0 && *endptr[0] == ',') )
5069  {
5070  if( *endptr[0] == '(')
5071  ++nopenbrackets;
5072  if( *endptr[0] == ')')
5073  --nopenbrackets;
5074  ++*endptr;
5075  }
5076 
5077  if( *endptr[0] != ',' )
5078  {
5079  SCIPerrorMessage("unable to find separating comma in unbalanced expression %.*s\n", length, str);
5080  return SCIP_READERROR;
5081  }
5082 
5083  return SCIP_OKAY;
5084 }
5085 
5086 /** parses an expression from a string */
5087 static
5089  BMS_BLKMEM* blkmem, /**< block memory data structure */
5090  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
5091  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
5092  const char* str, /**< pointer to the string to be parsed */
5093  int length, /**< length of the string to be parsed */
5094  const char* lastchar, /**< pointer to the last char of str that should be parsed */
5095  int* nvars, /**< running number of encountered variables so far */
5096  int** varnames, /**< pointer to buffer to store new variable names */
5097  SCIP_HASHTABLE* vartable, /**< hash table for variable names and corresponding expression index */
5098  int recursiondepth /**< current recursion depth */
5099  )
5100 { /*lint --e{712,747}*/
5101  SCIP_EXPR* arg1;
5102  SCIP_EXPR* arg2;
5103  const char* subexpptr;
5104  const char* subexpendptr;
5105  const char* strstart;
5106  const char* endptr;
5107  char* nonconstendptr;
5108  SCIP_Real number;
5109  int subexplength;
5110  int nopenbrackets;
5111 
5112  assert(blkmem != NULL);
5113  assert(expr != NULL);
5114  assert(str != NULL);
5115  assert(lastchar >= str);
5116  assert(nvars != NULL);
5117  assert(varnames != NULL);
5118  assert(vartable != NULL);
5119 
5120  assert(recursiondepth < 100);
5121 
5122  strstart = str; /* might be needed for error message... */
5123 
5124  SCIPdebugMessage("exprParse (%i): parsing %.*s\n", recursiondepth, (int) (lastchar-str + 1), str);
5125 
5126  /* ignore whitespace */
5127  while( isspace((unsigned char)*str) )
5128  ++str;
5129 
5130  /* look for a sum or difference not contained in brackets */
5131  subexpptr = str;
5132  nopenbrackets = 0;
5133 
5134  /* find the end of this expression
5135  * a '+' right at the beginning indicates a coefficient, not treated here, or a summation
5136  */
5137  while( subexpptr != lastchar && !(nopenbrackets == 0 && (subexpptr[0] == '+' || subexpptr[0] == '-') && subexpptr != str) )
5138  {
5139  if( subexpptr[0] == '(')
5140  ++nopenbrackets;
5141  if( subexpptr[0] == ')')
5142  --nopenbrackets;
5143  ++subexpptr;
5144  }
5145 
5146  if( subexpptr != lastchar )
5147  {
5148  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str, (int) ((subexpptr - 1) - str + 1), subexpptr - 1, nvars, varnames, vartable, recursiondepth + 1) );
5149 
5150  if( subexpptr[0] == '+' )
5151  ++subexpptr;
5152  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, subexpptr , (int) (lastchar - (subexpptr ) + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5153 
5154  /* make new expression from two arguments
5155  * we always use add, because we leave the operator between the found expressions in the second argument
5156  * this way, we do not have to worry about ''minus brackets'' in the case of more then two summands:
5157  * a - b - c = a + (-b -c)
5158  */
5159  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5160 
5161  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5162  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5163  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5164 
5165  return SCIP_OKAY;
5166  }
5167 
5168  /* check for a bracketed subexpression */
5169  if( str[0] == '(' )
5170  {
5171  nopenbrackets = 0;
5172 
5173  subexplength = -1; /* we do not want the closing bracket in the string */
5174  subexpptr = str + 1; /* leave out opening bracket */
5175 
5176  /* find the end of this expression */
5177  while( subexplength < length && !(nopenbrackets == 1 && str[0] == ')') )
5178  {
5179  if( str[0] == '(' )
5180  ++nopenbrackets;
5181  if( str[0] == ')' )
5182  --nopenbrackets;
5183  ++str;
5184  ++subexplength;
5185  }
5186  subexpendptr = str - 1; /* leave out closing bracket */
5187 
5188  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, subexpptr, subexplength, subexpendptr, nvars, varnames, vartable, recursiondepth + 1) );
5189  ++str;
5190  }
5191  else if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+')
5192  && (isdigit((unsigned char)str[1]) || str[1] == ' ')) )
5193  {
5194  /* check if there is a lonely minus coming, indicating a -1.0 */
5195  if( str[0] == '-' && str[1] == ' ' )
5196  {
5197  number = -1.0;
5198  nonconstendptr = (char*) str + 1;
5199  }
5200  /* check if there is a number coming */
5201  else if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5202  {
5203  SCIPerrorMessage("error parsing number from <%s>\n", str);
5204  return SCIP_READERROR;
5205  }
5206  str = nonconstendptr;
5207 
5208  /* ignore whitespace */
5209  while( isspace((unsigned char)*str) && str != lastchar )
5210  ++str;
5211 
5212  if( str[0] != '*' && str[0] != '/' && str[0] != '+' && str[0] != '-' && str[0] != '^' )
5213  {
5214  if( str < lastchar )
5215  {
5216  SCIP_CALL( exprParse(blkmem, messagehdlr, expr, str, (int)(lastchar - str) + 1, lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5217  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, *expr, number) );
5218  }
5219  else
5220  {
5221  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5222  }
5223  str = lastchar + 1;
5224  }
5225  else
5226  {
5227  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, number) );
5228  }
5229  }
5230  else if( str[0] == '<' )
5231  {
5232  /* check if expressions begins with a variable */
5233  SCIP_CALL( exprparseReadVariable(blkmem, &str, expr, nvars, varnames, vartable, 1.0, NULL) );
5234  }
5235  /* four character operators */
5236  else if( strncmp(str, "sqrt", 4) == 0 )
5237  {
5238  str += 4;
5239  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5240  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5241  str = endptr + 1;
5242 
5243  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQRT, arg1) );
5244  }
5245  /* three character operators with 1 argument */
5246  else if(
5247  strncmp(str, "abs", 3) == 0 ||
5248  strncmp(str, "cos", 3) == 0 ||
5249  strncmp(str, "exp", 3) == 0 ||
5250  strncmp(str, "log", 3) == 0 ||
5251  strncmp(str, "sin", 3) == 0 ||
5252  strncmp(str, "sqr", 3) == 0 ||
5253  strncmp(str, "tan", 3) == 0 )
5254  {
5255  const char* opname = str;
5256 
5257  str += 3;
5258  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5259  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5260  str = endptr + 1;
5261 
5262  if( strncmp(opname, "abs", 3) == 0 )
5263  {
5264  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_ABS, arg1) );
5265  }
5266  else if( strncmp(opname, "cos", 3) == 0 )
5267  {
5268  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_COS, arg1) );
5269  }
5270  else if( strncmp(opname, "exp", 3) == 0 )
5271  {
5272  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, arg1) );
5273  }
5274  else if( strncmp(opname, "log", 3) == 0 )
5275  {
5276  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5277  }
5278  else if( strncmp(opname, "sin", 3) == 0 )
5279  {
5280  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIN, arg1) );
5281  }
5282  else if( strncmp(opname, "sqr", 3) == 0 )
5283  {
5284  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SQUARE, arg1) );
5285  }
5286  else
5287  {
5288  assert(strncmp(opname, "tan", 3) == 0);
5289  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_TAN, arg1) );
5290  }
5291  }
5292  /* three character operators with 2 arguments */
5293  else if(
5294  strncmp(str, "max", 3) == 0 ||
5295  strncmp(str, "min", 3) == 0 )
5296  {
5297  /* we have a string of the form "min(...,...)" or "max(...,...)"
5298  * first find the closing parenthesis, then the comma
5299  */
5300  const char* comma;
5301  SCIP_EXPROP op;
5302 
5303  op = (str[1] == 'a' ? SCIP_EXPR_MAX : SCIP_EXPR_MIN);
5304 
5305  str += 3;
5306  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5307 
5308  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5309 
5310  /* parse first argument [str+1..comma-1] */
5311  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames, vartable, recursiondepth + 1) );
5312 
5313  /* parse second argument [comma+1..endptr] */
5314  ++comma;
5315  while( comma < endptr && *comma == ' ' )
5316  ++comma;
5317 
5318  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, comma, endptr - comma, endptr - 1, nvars, varnames, vartable, recursiondepth + 1) );
5319 
5320  SCIP_CALL( SCIPexprCreate(blkmem, expr, op, arg1, arg2) );
5321 
5322  str = endptr + 1;
5323  }
5324  else if( strncmp(str, "power", 5) == 0 )
5325  {
5326  /* we have a string of the form "power(...,integer)" (thus, intpower)
5327  * first find the closing parenthesis, then the comma
5328  */
5329  const char* comma;
5330  int exponent;
5331 
5332  str += 5;
5333  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5334 
5335  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5336 
5337  /* parse first argument [str+1..comma-1] */
5338  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames, vartable, recursiondepth + 1) );
5339 
5340  ++comma;
5341  /* parse second argument [comma, endptr-1]: it needs to be an integer */
5342  while( comma < endptr && *comma == ' ' )
5343  ++comma;
5344  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5345  {
5346  SCIPerrorMessage("error parsing integer exponent from <%s>\n", comma);
5347  }
5348  if( !SCIPstrToIntValue(comma, &exponent, &nonconstendptr) )
5349  {
5350  SCIPerrorMessage("error parsing integer from <%s>\n", comma);
5351  return SCIP_READERROR;
5352  }
5353 
5354  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, exponent) );
5355 
5356  str = endptr + 1;
5357  }
5358  else if( strncmp(str, "realpower", 9) == 0 || strncmp(str, "signpower", 9) == 0 )
5359  {
5360  /* we have a string of the form "realpower(...,double)" or "signpower(...,double)"
5361  * first find the closing parenthesis, then the comma
5362  */
5363  const char* opname = str;
5364  const char* comma;
5365 
5366  str += 9;
5367  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5368 
5369  SCIP_CALL( exprparseFindSeparatingComma(str+1, &comma, endptr - str - 1) );
5370 
5371  /* parse first argument [str+1..comma-1] */
5372  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg1, str + 1, comma - str - 1, comma - 1, nvars, varnames, vartable, recursiondepth + 1) );
5373 
5374  ++comma;
5375  /* parse second argument [comma, endptr-1]: it needs to be an number */
5376  while( comma < endptr && *comma == ' ' )
5377  ++comma;
5378  if( !isdigit((unsigned char)comma[0]) && !((comma[0] == '-' || comma[0] == '+') && isdigit((unsigned char)comma[1])) )
5379  {
5380  SCIPerrorMessage("error parsing number exponent from <%s>\n", comma);
5381  }
5382  if( !SCIPstrToRealValue(comma, &number, &nonconstendptr) )
5383  {
5384  SCIPerrorMessage("error parsing number from <%s>\n", comma);
5385  return SCIP_READERROR;
5386  }
5387 
5388  if( strncmp(opname, "realpower", 9) == 0 )
5389  {
5390  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, number) );
5391  }
5392  else
5393  {
5394  assert(strncmp(opname, "signpower", 9) == 0);
5395  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_SIGNPOWER, arg1, number) );
5396  }
5397 
5398  str = endptr + 1;
5399  }
5400  else if( isalpha(*str) || *str == '_' || *str == '#' )
5401  {
5402  /* check for a variable, that was not recognized earlier because somebody omitted the '<' and '>' we need for
5403  * SCIPparseVarName, making everyones life harder;
5404  * we allow only variable names starting with a character or underscore here
5405  */
5406  const char* varnamestartptr = str;
5407 
5408  /* allow only variable names containing characters, digits, hash marks, and underscores here */
5409  while( isalnum(str[0]) || str[0] == '_' || str[0] == '#' )
5410  ++str;
5411 
5412  SCIP_CALL( exprparseReadVariable(blkmem, &varnamestartptr, expr, nvars, varnames, vartable, 1.0, str) );
5413  }
5414  else
5415  {
5416  SCIPerrorMessage("parsing of invalid expression %.*s.\n", (int) (lastchar - str + 1), str);
5417  return SCIP_READERROR;
5418  }
5419 
5420  /* if we are one char behind lastchar, we are done */
5421  if( str == lastchar + 1)
5422  {
5423  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5424  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5425  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5426 
5427  return SCIP_OKAY;
5428  }
5429 
5430  /* check if we are still in bounds */
5431  if( str > lastchar + 1)
5432  {
5433  SCIPerrorMessage("error finding first expression in \"%.*s\" took us outside of given subexpression length\n", length, strstart);
5434  return SCIP_READERROR;
5435  }
5436 
5437  /* ignore whitespace */
5438  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5439  ++str;
5440 
5441  /* maybe now we're done? */
5442  if( str >= lastchar + 1)
5443  {
5444  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5445  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5446  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5447 
5448  return SCIP_OKAY;
5449  }
5450 
5451  if( str[0] == '^' )
5452  {
5453  /* a '^' behind the found expression indicates a power */
5454  SCIP_Real constant;
5455 
5456  arg1 = *expr;
5457  ++str;
5458  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5459  ++str;
5460 
5461  if( isdigit((unsigned char)str[0]) || ((str[0] == '-' || str[0] == '+') && isdigit((unsigned char)str[1])) )
5462  {
5463  /* there is a number coming */
5464  if( !SCIPstrToRealValue(str, &number, &nonconstendptr) )
5465  {
5466  SCIPerrorMessage("error parsing number from <%s>\n", str);
5467  return SCIP_READERROR;
5468  }
5469 
5470  SCIP_CALL( SCIPexprCreate(blkmem, &arg2, SCIP_EXPR_CONST, number) );
5471  str = nonconstendptr;
5472 
5473  constant = SCIPexprGetOpReal(arg2);
5474  SCIPexprFreeDeep(blkmem, &arg2);
5475 
5476  /* expr^number is intpower or realpower */
5477  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5478  {
5479  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5480  }
5481  else
5482  {
5483  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5484  }
5485  }
5486  else if( str[0] == '(' )
5487  {
5488  /* we use exprParse to evaluate the exponent */
5489 
5490  SCIP_CALL( exprparseFindClosingParenthesis(str, &endptr, length) );
5491  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str + 1, endptr - str - 1, endptr -1, nvars, varnames, vartable, recursiondepth + 1) );
5492 
5493  if( SCIPexprGetOperator(arg2) != SCIP_EXPR_CONST )
5494  {
5495  /* reformulate arg1^arg2 as exp(arg2 * log(arg1)) */
5496  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_LOG, arg1) );
5497  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, *expr, arg2) );
5498  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_EXP, *expr) );
5499  }
5500  else
5501  {
5502  /* expr^number is intpower or realpower */
5503  constant = SCIPexprGetOpReal(arg2);
5504  SCIPexprFreeDeep(blkmem, &arg2);
5505  if( EPSISINT(constant, 0.0) ) /*lint !e835*/
5506  {
5507  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_INTPOWER, arg1, (int)constant) );
5508  }
5509  else
5510  {
5511  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_REALPOWER, arg1, constant) );
5512  }
5513  }
5514  str = endptr + 1;
5515  }
5516  else
5517  {
5518  SCIPerrorMessage("unexpected string following ^ in %.*s\n", length, str);
5519  return SCIP_READERROR;
5520  }
5521 
5522  /* ignore whitespace */
5523  while( isspace((unsigned char)*str) && str != lastchar + 1 )
5524  ++str;
5525  }
5526 
5527  /* check for a two argument operator that is not a multiplication */
5528  if( str <= lastchar && (str[0] == '+' || str[0] == '-' || str[0] == '/') )
5529  {
5530  char op;
5531 
5532  op = str[0];
5533  arg1 = *expr;
5534 
5535  /* step forward over the operator to go to the beginning of the second argument */
5536  ++str;
5537 
5538  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5539  str = lastchar + 1;
5540 
5541  /* make new expression from two arguments */
5542  if( op == '+')
5543  {
5544  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, 1.0, arg2, 0.0) );
5545  }
5546  else if( op == '-')
5547  {
5548  SCIP_CALL( SCIPexprAdd(blkmem, expr, 1.0, arg1, -1.0, arg2, 0.0) );
5549  }
5550  else if( op == '*' )
5551  {
5552  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5553  {
5554  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5555  }
5556  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5557  {
5558  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5559  }
5560  else
5561  {
5562  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5563  }
5564  }
5565  else
5566  {
5567  assert(op == '/');
5568 
5569  if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5570  {
5571  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, 1.0 / SCIPexprGetOpReal(arg2)) );
5572  SCIPexprFreeShallow(blkmem, &arg2);
5573  }
5574  else
5575  {
5576  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_DIV, arg1, arg2) );
5577  }
5578  }
5579  }
5580 
5581  /* ignore whitespace */
5582  while( isspace((unsigned char)*str) )
5583  ++str;
5584 
5585  /* we are either done or we have a multiplication? */
5586  if( str >= lastchar + 1 )
5587  {
5588  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5589  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5590  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5591 
5592  return SCIP_OKAY;
5593  }
5594 
5595  /* if there is a part of the string left to be parsed, we assume that this as a multiplication */
5596  arg1 = *expr;
5597 
5598  /* stepping over multiplication operator if needed */
5599  if( str[0] == '*' )
5600  {
5601  ++str;
5602  }
5603  else if( str[0] != '(' )
5604  {
5605  SCIPdebugMessage("No operator found, assuming a multiplication before %.*s\n", (int) (lastchar - str + 1), str);
5606  }
5607 
5608  SCIP_CALL( exprParse(blkmem, messagehdlr, &arg2, str, (int) (lastchar - str + 1), lastchar, nvars, varnames, vartable, recursiondepth + 1) );
5609 
5610  if( SCIPexprGetOperator(arg1) == SCIP_EXPR_CONST )
5611  {
5612  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg2, SCIPexprGetOpReal(arg1)) );
5613  SCIPexprFreeDeep(blkmem, &arg1);
5614  }
5615  else if( SCIPexprGetOperator(arg2) == SCIP_EXPR_CONST )
5616  {
5617  SCIP_CALL( SCIPexprMulConstant(blkmem, expr, arg1, SCIPexprGetOpReal(arg2)) );
5618  SCIPexprFreeDeep(blkmem, &arg2);
5619  }
5620  else
5621  {
5622  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_MUL, arg1, arg2) );
5623  }
5624 
5625  SCIPdebugMessage("exprParse (%i): returns expression ", recursiondepth);
5626  SCIPdebug( SCIPexprPrint(*expr, messagehdlr, NULL, NULL, NULL, NULL) );
5627  SCIPdebug( SCIPmessagePrintInfo(messagehdlr, "\n") );
5628 
5629  return SCIP_OKAY;
5630 }
5631 
5632 /**@} */
5633 
5634 /**@name Expression methods */
5635 /**@{ */
5636 
5637 /* In debug mode, the following methods are implemented as function calls to ensure
5638  * type validity.
5639  * In optimized mode, the methods are implemented as defines to improve performance.
5640  * However, we want to have them in the library anyways, so we have to undef the defines.
5641  */
5642 
5643 #undef SCIPexprGetOperator
5644 #undef SCIPexprGetNChildren
5645 #undef SCIPexprGetChildren
5646 #undef SCIPexprGetOpIndex
5647 #undef SCIPexprGetOpReal
5648 #undef SCIPexprGetOpData
5649 #undef SCIPexprGetRealPowerExponent
5650 #undef SCIPexprGetIntPowerExponent
5651 #undef SCIPexprGetSignPowerExponent
5652 #undef SCIPexprGetLinearCoefs
5653 #undef SCIPexprGetLinearConstant
5654 #undef SCIPexprGetQuadElements
5655 #undef SCIPexprGetQuadConstant
5656 #undef SCIPexprGetQuadLinearCoefs
5657 #undef SCIPexprGetNQuadElements
5658 #undef SCIPexprGetMonomials
5659 #undef SCIPexprGetNMonomials
5660 #undef SCIPexprGetPolynomialConstant
5661 #undef SCIPexprGetMonomialCoef
5662 #undef SCIPexprGetMonomialNFactors
5663 #undef SCIPexprGetMonomialChildIndices
5664 #undef SCIPexprGetMonomialExponents
5665 #undef SCIPexprGetUserData
5666 #undef SCIPexprHasUserEstimator
5667 #undef SCIPexprGetUserEvalCapability
5668 
5669 /** gives operator of expression */
5671  SCIP_EXPR* expr /**< expression */
5672  )
5673 {
5674  assert(expr != NULL);
5675 
5676  return expr->op;
5677 }
5678 
5679 /** gives number of children of an expression */
5681  SCIP_EXPR* expr /**< expression */
5682  )
5683 {
5684  assert(expr != NULL);
5685 
5686  return expr->nchildren;
5687 }
5688 
5689 /** gives pointer to array with children of an expression */
5691  SCIP_EXPR* expr /**< expression */
5692  )
5693 {
5694  assert(expr != NULL);
5695 
5696  return expr->children;
5697 }
5698 
5699 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
5701  SCIP_EXPR* expr /**< expression */
5702  )
5703 {
5704  assert(expr != NULL);
5705  assert(expr->op == SCIP_EXPR_VARIDX || expr->op == SCIP_EXPR_PARAM);
5706 
5707  return expr->data.intval;
5708 }
5709 
5710 /** gives real belonging to a SCIP_EXPR_CONST operand */
5712  SCIP_EXPR* expr /**< expression */
5713  )
5714 {
5715  assert(expr != NULL);
5716  assert(expr->op == SCIP_EXPR_CONST);
5717 
5718  return expr->data.dbl;
5719 }
5720 
5721 /** gives void* belonging to a complex operand */
5723  SCIP_EXPR* expr /**< expression */
5724  )
5725 {
5726  assert(expr != NULL);
5727  assert(expr->op >= SCIP_EXPR_SUM); /* only complex operands store their data as void* */
5728 
5729  return expr->data.data;
5730 }
5731 
5732 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
5734  SCIP_EXPR* expr /**< expression */
5735  )
5736 {
5737  assert(expr != NULL);
5738  assert(expr->op == SCIP_EXPR_REALPOWER);
5739 
5740  return expr->data.dbl;
5741 }
5742 
5743 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
5745  SCIP_EXPR* expr /**< expression */
5746  )
5747 {
5748  assert(expr != NULL);
5749  assert(expr->op == SCIP_EXPR_INTPOWER);
5750 
5751  return expr->data.intval;
5752 }
5753 
5754 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
5756  SCIP_EXPR* expr /**< expression */
5757  )
5758 {
5759  assert(expr != NULL);
5760  assert(expr->op == SCIP_EXPR_SIGNPOWER);
5761 
5762  return expr->data.dbl;
5763 }
5764 
5765 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
5767  SCIP_EXPR* expr /**< expression */
5768  )
5769 {
5770  assert(expr != NULL);
5771  assert(expr->op == SCIP_EXPR_LINEAR);
5772  assert(expr->data.data != NULL);
5773 
5774  /* the coefficients are stored in the first nchildren elements of the array stored as expression data */
5775  return (SCIP_Real*)expr->data.data;
5776 }
5777 
5778 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
5780  SCIP_EXPR* expr /**< expression */
5781  )
5782 {
5783  assert(expr != NULL);
5784  assert(expr->op == SCIP_EXPR_LINEAR);
5785  assert(expr->data.data != NULL);
5786 
5787  /* the constant is stored in the nchildren's element of the array stored as expression data */
5788  return ((SCIP_Real*)expr->data.data)[expr->nchildren];
5789 }
5790 
5791 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5793  SCIP_EXPR* expr /**< quadratic expression */
5794  )
5795 {
5796  assert(expr != NULL);
5797  assert(expr->op == SCIP_EXPR_QUADRATIC);
5798  assert(expr->data.data != NULL);
5799 
5800  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->quadelems;
5801 }
5802 
5803 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
5805  SCIP_EXPR* expr /**< quadratic expression */
5806  )
5807 {
5808  assert(expr != NULL);
5809  assert(expr->op == SCIP_EXPR_QUADRATIC);
5810  assert(expr->data.data != NULL);
5811 
5812  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->constant;
5813 }
5814 
5815 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression
5816  * can be NULL if all coefficients are 0.0 */
5818  SCIP_EXPR* expr /**< quadratic expression */
5819  )
5820 {
5821  assert(expr != NULL);
5822  assert(expr->op == SCIP_EXPR_QUADRATIC);
5823  assert(expr->data.data != NULL);
5824 
5825  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->lincoefs;
5826 }
5827 
5828 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
5830  SCIP_EXPR* expr /**< quadratic expression */
5831  )
5832 {
5833  assert(expr != NULL);
5834  assert(expr->op == SCIP_EXPR_QUADRATIC);
5835  assert(expr->data.data != NULL);
5836 
5837  return ((SCIP_EXPRDATA_QUADRATIC*)expr->data.data)->nquadelems;
5838 }
5839 
5840 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5842  SCIP_EXPR* expr /**< expression */
5843  )
5844 {
5845  assert(expr != NULL);
5846  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5847  assert(expr->data.data != NULL);
5848 
5849  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->monomials;
5850 }
5851 
5852 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
5854  SCIP_EXPR* expr /**< expression */
5855  )
5856 {
5857  assert(expr != NULL);
5858  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5859  assert(expr->data.data != NULL);
5860 
5861  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->nmonomials;
5862 }
5863 
5864 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
5866  SCIP_EXPR* expr /**< expression */
5867  )
5868 {
5869  assert(expr != NULL);
5870  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
5871  assert(expr->data.data != NULL);
5872 
5873  return ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant;
5874 }
5875 
5876 /** gets coefficient of a monomial */
5878  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5879  )
5880 {
5881  assert(monomial != NULL);
5882 
5883  return monomial->coef;
5884 }
5885 
5886 /** gets number of factors of a monomial */
5888  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5889  )
5890 {
5891  assert(monomial != NULL);
5892 
5893  return monomial->nfactors;
5894 }
5895 
5896 /** gets indices of children corresponding to factors of a monomial */
5898  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5899  )
5900 {
5901  assert(monomial != NULL);
5902 
5903  return monomial->childidxs;
5904 }
5905 
5906 /** gets exponents in factors of a monomial */
5908  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
5909  )
5910 {
5911  assert(monomial != NULL);
5912 
5913  return monomial->exponents;
5914 }
5915 
5916 /** gets user data of a user expression */
5918  SCIP_EXPR* expr
5919  )
5920 {
5921  assert(expr != NULL);
5922  assert(expr->data.data != NULL);
5923 
5924  return ((SCIP_EXPRDATA_USER*)expr->data.data)->userdata;
5925 }
5926 
5927 /** indicates whether a user expression has the estimator callback defined */
5929  SCIP_EXPR* expr
5930  )
5931 {
5932  assert(expr != NULL);
5933  assert(expr->data.data != NULL);
5934 
5935  return ((SCIP_EXPRDATA_USER*)expr->data.data)->estimate != NULL;
5936 }
5937 
5938 /** gives the evaluation capability of a user expression */
5940  SCIP_EXPR* expr
5941  )
5942 {
5943  assert(expr != NULL);
5944  assert(expr->data.data != NULL);
5945 
5946  return ((SCIP_EXPRDATA_USER*)expr->data.data)->evalcapability;
5947 }
5948 
5949 /** creates a simple expression */
5951  BMS_BLKMEM* blkmem, /**< block memory data structure */
5952  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
5953  SCIP_EXPROP op, /**< operand of expression */
5954  ... /**< arguments of operand */
5955  )
5956 {
5957  va_list ap;
5958  SCIP_EXPR** children;
5959  SCIP_EXPROPDATA opdata;
5960 
5961  assert(blkmem != NULL);
5962  assert(expr != NULL);
5963 
5964  switch( op )
5965  {
5966  case SCIP_EXPR_VARIDX:
5967  case SCIP_EXPR_PARAM:
5968  {
5969  va_start( ap, op ); /*lint !e838*/
5970  opdata.intval = va_arg( ap, int ); /*lint !e416 !e826*/
5971  va_end( ap ); /*lint !e826*/
5972 
5973  assert( opdata.intval >= 0 );
5974 
5975  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5976  break;
5977  }
5978 
5979  case SCIP_EXPR_CONST:
5980  {
5981  va_start(ap, op ); /*lint !e838*/
5982  opdata.dbl = va_arg( ap, SCIP_Real ); /*lint !e416 !e826*/
5983  va_end( ap ); /*lint !e826*/
5984 
5985  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata ) );
5986  break;
5987  }
5988 
5989  /* operands with two children */
5990  case SCIP_EXPR_PLUS :
5991  case SCIP_EXPR_MINUS :
5992  case SCIP_EXPR_MUL :
5993  case SCIP_EXPR_DIV :
5994  case SCIP_EXPR_MIN :
5995  case SCIP_EXPR_MAX :
5996  {
5997  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 2) ); /*lint !e506*/
5998 
5999  va_start(ap, op ); /*lint !e838*/
6000  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6001  children[1] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6002  assert(children[0] != NULL);
6003  assert(children[1] != NULL);
6004  va_end( ap ); /*lint !e826*/
6005  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6006 
6007  SCIP_CALL( exprCreate( blkmem, expr, op, 2, children, opdata ) );
6008  break;
6009  }
6010 
6011  /* operands with one child */
6012  case SCIP_EXPR_SQUARE:
6013  case SCIP_EXPR_SQRT :
6014  case SCIP_EXPR_EXP :
6015  case SCIP_EXPR_LOG :
6016  case SCIP_EXPR_SIN :
6017  case SCIP_EXPR_COS :
6018  case SCIP_EXPR_TAN :
6019  /* case SCIP_EXPR_ERF : */
6020  /* case SCIP_EXPR_ERFI : */
6021  case SCIP_EXPR_ABS :
6022  case SCIP_EXPR_SIGN :
6023  {
6024  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6025 
6026  va_start(ap, op ); /*lint !e838*/
6027  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6028  assert(children[0] != NULL);
6029  va_end( ap ); /*lint !e826*/
6030  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6031 
6032  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6033  break;
6034  }
6035 
6036  case SCIP_EXPR_REALPOWER:
6037  case SCIP_EXPR_SIGNPOWER:
6038  {
6039  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6040 
6041  va_start(ap, op ); /*lint !e838*/
6042  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6043  assert(children[0] != NULL);
6044  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
6045  va_end( ap ); /*lint !e826*/
6046 
6047  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6048  break;
6049  }
6050 
6051  case SCIP_EXPR_INTPOWER:
6052  {
6053  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &children, 1) ); /*lint !e506*/
6054 
6055  va_start(ap, op ); /*lint !e838*/
6056  children[0] = va_arg( ap, SCIP_EXPR* ); /*lint !e416 !e826*/
6057  assert(children[0] != NULL);
6058  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
6059  va_end( ap ); /*lint !e826*/
6060 
6061  SCIP_CALL( exprCreate( blkmem, expr, op, 1, children, opdata ) );
6062  break;
6063  }
6064 
6065  /* complex operands */
6066  case SCIP_EXPR_SUM :
6067  case SCIP_EXPR_PRODUCT:
6068  {
6069  int nchildren;
6070  SCIP_EXPR** childrenarg;
6071 
6072  opdata.data = NULL; /* to avoid compiler warning about use of uninitialised value */
6073 
6074  va_start(ap, op ); /*lint !e838*/
6075  /* first argument should be number of children */
6076  nchildren = va_arg( ap, int ); /*lint !e416 !e826*/
6077  assert(nchildren >= 0);
6078 
6079  /* for a sum or product of 0 terms we can finish here */
6080  if( nchildren == 0 )
6081  {
6082  SCIP_CALL( exprCreate( blkmem, expr, op, 0, NULL, opdata) );
6083  va_end( ap ); /*lint !e826*/
6084  break;
6085  }
6086 
6087  /* next argument should be array of children expressions */
6088  childrenarg = va_arg( ap, SCIP_EXPR** ); /*lint !e416 !e826*/
6089  assert(childrenarg != NULL);
6090  va_end( ap ); /*lint !e826*/
6091 
6092  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &children, childrenarg, nchildren) );
6093 
6094  SCIP_CALL( exprCreate( blkmem, expr, op, nchildren, children, opdata) );
6095  break;
6096  }
6097 
6098  case SCIP_EXPR_LINEAR :
6099  case SCIP_EXPR_QUADRATIC:
6100  case SCIP_EXPR_POLYNOMIAL:
6101  case SCIP_EXPR_USER:
6102  {
6103  SCIPerrorMessage("cannot create complex expression linear, quadratic, polynomial, or user with SCIPexprCreate\n");
6104  return SCIP_INVALIDDATA;
6105  }
6106 
6107  case SCIP_EXPR_LAST:
6108  SCIPABORT();
6109  break;
6110  }
6111 
6112  return SCIP_OKAY;
6113 }
6114 
6115 /** copies an expression including its children */
6117  BMS_BLKMEM* blkmem, /**< block memory data structure */
6118  SCIP_EXPR** targetexpr, /**< buffer to store pointer to copied expression */
6119  SCIP_EXPR* sourceexpr /**< expression to copy */
6120  )
6121 {
6122  assert(blkmem != NULL);
6123  assert(targetexpr != NULL);
6124  assert(sourceexpr != NULL);
6125 
6126  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targetexpr, sourceexpr) );
6127 
6128  if( sourceexpr->nchildren )
6129  {
6130  int i;
6131 
6132  /* alloc memory for children expressions */
6133  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*targetexpr)->children, sourceexpr->nchildren) );
6134 
6135  /* copy children expressions */
6136  for( i = 0; i < sourceexpr->nchildren; ++i )
6137  {
6138  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targetexpr)->children[i], sourceexpr->children[i]) );
6139  }
6140  }
6141  else
6142  {
6143  assert((*targetexpr)->children == NULL); /* otherwise, sourceexpr->children was not NULL, which is wrong */
6144  }
6145 
6146  /* call operands data copy callback for complex operands
6147  * for simple operands BMSduplicate above should have done the job
6148  */
6149  if( exprOpTable[sourceexpr->op].copydata != NULL )
6150  {
6151  SCIP_CALL( exprOpTable[sourceexpr->op].copydata(blkmem, sourceexpr->nchildren, sourceexpr->data, &(*targetexpr)->data) );
6152  }
6153 
6154  return SCIP_OKAY;
6155 }
6156 
6157 /** frees an expression including its children */
6159  BMS_BLKMEM* blkmem, /**< block memory data structure */
6160  SCIP_EXPR** expr /**< pointer to expression to free */
6161  )
6162 {
6163  assert(blkmem != NULL);
6164  assert(expr != NULL);
6165  assert(*expr != NULL);
6166 
6167  /* call operands data free callback, if given */
6168  if( exprOpTable[(*expr)->op].freedata != NULL )
6169  {
6170  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6171  }
6172 
6173  if( (*expr)->nchildren )
6174  {
6175  int i;
6176 
6177  assert( (*expr)->children != NULL );
6178 
6179  for( i = 0; i < (*expr)->nchildren; ++i )
6180  {
6181  SCIPexprFreeDeep(blkmem, &(*expr)->children[i]);
6182  assert((*expr)->children[i] == NULL);
6183  }
6184 
6185  BMSfreeBlockMemoryArray(blkmem, &(*expr)->children, (*expr)->nchildren);
6186  }
6187  else
6188  {
6189  assert( (*expr)->children == NULL );
6190  }
6191 
6192  BMSfreeBlockMemory(blkmem, expr);
6193 }
6194 
6195 /** frees an expression but not its children */
6197  BMS_BLKMEM* blkmem, /**< block memory data structure */
6198  SCIP_EXPR** expr /**< pointer to expression to free */
6199  )
6200 {
6201  assert(blkmem != NULL);
6202  assert(expr != NULL);
6203  assert(*expr != NULL);
6204 
6205  /* call operands data free callback, if given */
6206  if( exprOpTable[(*expr)->op].freedata != NULL )
6207  {
6208  exprOpTable[(*expr)->op].freedata(blkmem, (*expr)->nchildren, (*expr)->data);
6209  }
6210 
6211  BMSfreeBlockMemoryArrayNull(blkmem, &(*expr)->children, (*expr)->nchildren);
6212 
6213  BMSfreeBlockMemory(blkmem, expr);
6214 }
6215 
6216 /** creates an expression from the addition of two given expression, with coefficients, and a constant
6217  *
6218  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6219  * Favors creation and maintaining of SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6220  */
6222  BMS_BLKMEM* blkmem, /**< block memory data structure */
6223  SCIP_EXPR** expr, /**< pointer to store pointer to created expression */
6224  SCIP_Real coef1, /**< coefficient of first term */
6225  SCIP_EXPR* term1, /**< expression of first term, or NULL */
6226  SCIP_Real coef2, /**< coefficient of second term */
6227  SCIP_EXPR* term2, /**< expression of second term, or NULL */
6228  SCIP_Real constant /**< constant term to add */
6229  )
6230 {
6231  assert(blkmem != NULL);
6232  assert(expr != NULL);
6233 
6234  /* @todo could do something special with quadratic and polynomial expressions */
6235 
6236  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_CONST )
6237  {
6238  constant += coef1 * SCIPexprGetOpReal(term1);
6239  SCIPexprFreeDeep(blkmem, &term1);
6240  }
6241 
6242  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_CONST )
6243  {
6244  constant += coef2 * SCIPexprGetOpReal(term2);
6245  SCIPexprFreeDeep(blkmem, &term2);
6246  }
6247 
6248  if( term1 == NULL && term2 == NULL )
6249  {
6250  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, constant) );
6251  return SCIP_OKAY;
6252  }
6253 
6254  if( term1 != NULL && SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR && coef1 != 1.0 )
6255  {
6256  /* multiply coefficients and constant of linear expression term1 by coef1 */
6257  SCIP_Real* data;
6258  int i;
6259 
6260  data = (SCIP_Real*)term1->data.data;
6261  assert(data != NULL);
6262 
6263  /* loop one more index to multiply also constant of linear expression */
6264  for( i = 0; i <= term1->nchildren; ++i )
6265  data[i] *= coef1;
6266 
6267  coef1 = 1.0;
6268  }
6269 
6270  if( term2 != NULL && SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR && coef2 != 1.0 )
6271  {
6272  /* multiply coefficients and constant of linear expression term2 by coef2 */
6273  SCIP_Real* data;
6274  int i;
6275 
6276  data = (SCIP_Real*)term2->data.data;
6277  assert(data != NULL);
6278 
6279  /* loop one more index to multiply also constant of linear expression */
6280  for( i = 0; i <= term2->nchildren; ++i )
6281  data[i] *= coef2;
6282 
6283  coef2 = 1.0;
6284  }
6285 
6286  if( term1 == NULL || term2 == NULL )
6287  {
6288  if( term1 == NULL )
6289  {
6290  term1 = term2;
6291  coef1 = coef2;
6292  }
6293  if( constant != 0.0 || coef1 != 1.0 )
6294  {
6295  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6296  {
6297  assert(coef1 == 1.0);
6298 
6299  /* add constant to existing linear expression */
6300  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 0, NULL, NULL, constant) );
6301  *expr = term1;
6302  }
6303  else
6304  {
6305  /* create new linear expression for coef1 * term1 + constant */
6306  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term1, &coef1, constant) );
6307  }
6308  }
6309  else
6310  {
6311  assert(constant == 0.0);
6312  assert(coef1 == 1.0);
6313  *expr = term1;
6314  }
6315 
6316  return SCIP_OKAY;
6317  }
6318 
6320  {
6321  /* add 2nd linear expression to first one */
6322  assert(coef1 == 1.0);
6323  assert(coef2 == 1.0);
6324 
6326  SCIPexprFreeShallow(blkmem, &term2);
6327 
6328  *expr = term1;
6329 
6330  return SCIP_OKAY;
6331  }
6332 
6333  if( SCIPexprGetOperator(term2) == SCIP_EXPR_LINEAR )
6334  {
6335  /* if only term2 is linear, then swap */
6336  SCIP_EXPR* tmp;
6337 
6338  tmp = term2;
6339  assert(coef2 == 1.0);
6340 
6341  term2 = term1;
6342  coef2 = coef1;
6343  term1 = tmp;
6344  coef1 = 1.0;
6345  }
6346 
6347  if( SCIPexprGetOperator(term1) == SCIP_EXPR_LINEAR )
6348  {
6349  /* add coef2*term2 as extra child to linear expression term1 */
6350  assert(coef1 == 1.0);
6351 
6352  SCIP_CALL( SCIPexprAddToLinear(blkmem, term1, 1, &coef2, &term2, constant) );
6353  *expr = term1;
6354 
6355  return SCIP_OKAY;
6356  }
6357 
6358  /* both terms are not linear, then create new linear term for sum */
6359  {
6360  SCIP_Real coefs[2];
6361  SCIP_EXPR* children[2];
6362 
6363  coefs[0] = coef1;
6364  coefs[1] = coef2;
6365  children[0] = term1;
6366  children[1] = term2;
6367 
6368  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 2, children, coefs, constant) );
6369  }
6370 
6371  return SCIP_OKAY;
6372 }
6373 
6374 /** creates an expression from the multiplication of an expression with a constant
6375  *
6376  * The given expressions may be modified or freed, otherwise it will be used a child expression.
6377  * Favors creation and maintaining SCIP_EXPR_LINEAR over SCIP_EXPR_PLUS or SCIP_EXPR_SUM.
6378  */
6380  BMS_BLKMEM* blkmem, /**< block memory data structure */
6381  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
6382  SCIP_EXPR* term, /**< term to multiply by factor */
6383  SCIP_Real factor /**< factor */
6384  )
6385 {
6386  assert(blkmem != NULL);
6387  assert(expr != NULL);
6388  assert(term != NULL);
6389 
6390  if( factor == 0.0 )
6391  {
6392  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, 0.0) );
6393 
6394  SCIPexprFreeDeep(blkmem, &term);
6395 
6396  return SCIP_OKAY;
6397  }
6398  if( factor == 1.0 )
6399  {
6400  *expr = term;
6401  return SCIP_OKAY;
6402  }
6403 
6404  switch( SCIPexprGetOperator(term) )
6405  {
6406  case SCIP_EXPR_CONST :
6407  {
6408  SCIP_CALL( SCIPexprCreate(blkmem, expr, SCIP_EXPR_CONST, factor * SCIPexprGetOpReal(term)) );
6409  SCIPexprFreeDeep(blkmem, &term);
6410  break;
6411  }
6412 
6413  case SCIP_EXPR_LINEAR :
6414  {
6415  SCIP_Real* data;
6416  int i;
6417 
6418  data = (SCIP_Real*)term->data.data;
6419  assert(data != NULL);
6420 
6421  /* loop one more index to multiply also constant of linear expression */
6422  for( i = 0; i <= SCIPexprGetNChildren(term); ++i )
6423  data[i] *= factor;
6424 
6425  *expr = term;
6426  break;
6427  }
6428 
6429  case SCIP_EXPR_QUADRATIC :
6430  {
6432  int i;
6433 
6434  data = (SCIP_EXPRDATA_QUADRATIC*)term->data.data;
6435 
6436  data->constant *= factor;
6437 
6438  if( data->lincoefs != NULL )
6439  for( i = 0; i < term->nchildren; ++i )
6440  data->lincoefs[i] *= factor;
6441 
6442  for( i = 0; i < data->nquadelems; ++i )
6443  data->quadelems[i].coef *= factor;
6444 
6445  *expr = term;
6446  break;
6447  }
6448 
6449  case SCIP_EXPR_POLYNOMIAL :
6450  {
6452  int i;
6453 
6454  data = (SCIP_EXPRDATA_POLYNOMIAL*)term->data.data;
6455 
6456  data->constant *= factor;
6457 
6458  for( i = 0; i < data->nmonomials; ++i )
6459  data->monomials[i]->coef *= factor;
6460 
6461  *expr = term;
6462  break;
6463  }
6464 
6465  default:
6466  {
6467  SCIP_CALL( SCIPexprCreateLinear(blkmem, expr, 1, &term, &factor, 0.0) );
6468  break;
6469  }
6470 
6471  } /*lint !e788 */
6472 
6473  return SCIP_OKAY;
6474 }
6475 
6476 /** creates a SCIP_EXPR_LINEAR expression that is (affine) linear in its children: constant + sum_i coef_i child_i */
6478  BMS_BLKMEM* blkmem, /**< block memory data structure */
6479  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6480  int nchildren, /**< number of children */
6481  SCIP_EXPR** children, /**< children of expression */
6482  SCIP_Real* coefs, /**< coefficients of children */
6483  SCIP_Real constant /**< constant part */
6484  )
6485 {
6486  SCIP_EXPROPDATA opdata;
6487  SCIP_EXPR** childrencopy;
6488  SCIP_Real* data;
6489 
6490  assert(nchildren >= 0);
6491  assert(children != NULL || nchildren == 0);
6492  assert(coefs != NULL || nchildren == 0);
6493 
6494  if( nchildren > 0 )
6495  {
6496  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6497  }
6498  else
6499  childrencopy = NULL;
6500 
6501  /* we store the coefficients and the constant in a single array and make this our operand data */
6502  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, nchildren + 1) );
6503  BMScopyMemoryArray(data, coefs, nchildren); /*lint !e644*/
6504  data[nchildren] = constant;
6505 
6506  opdata.data = (void*)data;
6507 
6508  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_LINEAR, nchildren, childrencopy, opdata) );
6509 
6510  return SCIP_OKAY;
6511 }
6512 
6513 /** adds new terms to a linear expression */
6515  BMS_BLKMEM* blkmem, /**< block memory */
6516  SCIP_EXPR* expr, /**< linear expression */
6517  int nchildren, /**< number of children to add */
6518  SCIP_Real* coefs, /**< coefficients of additional children */
6519  SCIP_EXPR** children, /**< additional children expressions */
6520  SCIP_Real constant /**< constant to add */
6521  )
6522 {
6523  SCIP_Real* data;
6524 
6525  assert(blkmem != NULL);
6526  assert(expr != NULL);
6527  assert(expr->op == SCIP_EXPR_LINEAR);
6528  assert(nchildren >= 0);
6529  assert(coefs != NULL || nchildren == 0);
6530  assert(children != NULL || nchildren == 0);
6531 
6532  data = (SCIP_Real*)expr->data.data;
6533  assert(data != NULL);
6534 
6535  /* handle simple case of adding a constant */
6536  if( nchildren == 0 )
6537  {
6538  data[expr->nchildren] += constant;
6539 
6540  return SCIP_OKAY;
6541  }
6542 
6543  /* add new children to expr's children array */
6544  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &expr->children, expr->nchildren, expr->nchildren + nchildren) );
6545  BMScopyMemoryArray(&expr->children[expr->nchildren], children, nchildren); /*lint !e866*/
6546 
6547  /* add constant and new coefs to expr's data array */
6548  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, expr->nchildren + 1, expr->nchildren + nchildren + 1) );
6549  data[expr->nchildren + nchildren] = data[expr->nchildren] + constant;
6550  BMScopyMemoryArray(&data[expr->nchildren], coefs, nchildren); /*lint !e866*/
6551  expr->data.data = (void*)data;
6552 
6553  expr->nchildren += nchildren;
6554 
6555  return SCIP_OKAY;
6556 }
6557 
6558 /** creates a SCIP_EXPR_QUADRATIC expression: constant + sum_i coef_i child_i + sum_i coef_i child1_i child2_i */
6560  BMS_BLKMEM* blkmem, /**< block memory data structure */
6561  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6562  int nchildren, /**< number of children */
6563  SCIP_EXPR** children, /**< children of expression */
6564  SCIP_Real constant, /**< constant */
6565  SCIP_Real* lincoefs, /**< linear coefficients of children, or NULL if all 0.0 */
6566  int nquadelems, /**< number of quadratic elements */
6567  SCIP_QUADELEM* quadelems /**< quadratic elements specifying coefficients and child indices */
6568  )
6569 {
6570  SCIP_EXPROPDATA opdata;
6571  SCIP_EXPR** childrencopy;
6573 
6574  assert(nchildren >= 0);
6575  assert(children != NULL || nchildren == 0);
6576  assert(quadelems != NULL || nquadelems == 0);
6577 
6578  if( nchildren > 0 )
6579  {
6580  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6581  }
6582  else
6583  childrencopy = NULL;
6584 
6585  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
6586 
6587  opdata.data = (void*)data;
6588 
6589  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_QUADRATIC, nchildren, childrencopy, opdata) );
6590 
6591  return SCIP_OKAY;
6592 }
6593 
6594 /** ensures that quadratic elements of a quadratic expression are sorted */
6596  SCIP_EXPR* expr /**< quadratic expression */
6597  )
6598 {
6599  assert(expr != NULL);
6600  assert(expr->op == SCIP_EXPR_QUADRATIC);
6601  assert(expr->data.data != NULL);
6602 
6604 }
6605 
6606 /** creates a SCIP_EXPR_POLYNOMIAL expression from an array of monomials: constant + sum_i monomial_i */
6608  BMS_BLKMEM* blkmem, /**< block memory data structure */
6609  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
6610  int nchildren, /**< number of children */
6611  SCIP_EXPR** children, /**< children of expression */
6612  int nmonomials, /**< number of monomials */
6613  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
6614  SCIP_Real constant, /**< constant part */
6615  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6616  )
6617 {
6618  SCIP_EXPROPDATA opdata;
6619  SCIP_EXPR** childrencopy;
6621 
6622  assert(nchildren >= 0);
6623  assert(children != NULL || nchildren == 0);
6624  assert(monomials != NULL || nmonomials == 0);
6625 
6626  if( nchildren > 0 )
6627  {
6628  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
6629  }
6630  else
6631  childrencopy = NULL;
6632 
6633  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
6634  opdata.data = (void*)data;
6635 
6636  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_POLYNOMIAL, nchildren, childrencopy, opdata) );
6637 
6638  return SCIP_OKAY;
6639 }
6640 
6641 /** adds an array of monomials to a SCIP_EXPR_POLYNOMIAL expression */
6643  BMS_BLKMEM* blkmem, /**< block memory of expression */
6644  SCIP_EXPR* expr, /**< expression */
6645  int nmonomials, /**< number of monomials to add */
6646  SCIP_EXPRDATA_MONOMIAL** monomials, /**< the monomials to add */
6647  SCIP_Bool copymonomials /**< should monomials by copied or ownership be assumed? */
6648  )
6649 {
6650  assert(blkmem != NULL);
6651  assert(expr != NULL);
6652  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6653  assert(monomials != NULL || nmonomials == 0);
6654 
6655  if( nmonomials == 0 )
6656  return SCIP_OKAY;
6657 
6658  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, nmonomials, monomials, copymonomials) );
6659 
6660  return SCIP_OKAY;
6661 }
6662 
6663 /** changes the constant in a SCIP_EXPR_POLYNOMIAL expression */
6665  SCIP_EXPR* expr, /**< expression */
6666  SCIP_Real constant /**< new value for constant */
6667  )
6668 {
6669  assert(expr != NULL);
6670  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6671  assert(expr->data.data != NULL);
6672 
6673  ((SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data)->constant = constant;
6674 }
6675 
6676 /** multiplies each summand of a polynomial by a given constant */
6678  BMS_BLKMEM* blkmem, /**< block memory */
6679  SCIP_EXPR* expr, /**< polynomial expression */
6680  SCIP_Real factor /**< constant factor */
6681  )
6682 {
6683  assert(expr != NULL);
6684  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6685  assert(expr->data.data != NULL);
6686 
6687  polynomialdataMultiplyByConstant(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor);
6688 }
6689 
6690 /** multiplies each summand of a polynomial by a given monomial */
6692  BMS_BLKMEM* blkmem, /**< block memory */
6693  SCIP_EXPR* expr, /**< polynomial expression */
6694  SCIP_EXPRDATA_MONOMIAL* factor, /**< monomial factor */
6695  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6696  )
6697 {
6698  assert(blkmem != NULL);
6699  assert(factor != NULL);
6700  assert(expr != NULL);
6701  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6702  assert(expr->data.data != NULL);
6703 
6704  SCIP_CALL( polynomialdataMultiplyByMonomial(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, factor, childmap) );
6705 
6706  return SCIP_OKAY;
6707 }
6708 
6709 /** multiplies this polynomial by a polynomial
6710  *
6711  * Factor needs to be different from expr.
6712  * Children of factor need to be children of expr already, w.r.t. an optional mapping of child indices.
6713  */
6715  BMS_BLKMEM* blkmem, /**< block memory */
6716  SCIP_EXPR* expr, /**< polynomial expression */
6717  SCIP_EXPR* factor, /**< polynomial factor */
6718  int* childmap /**< map children in factor to children in expr, or NULL for 1:1 */
6719  )
6720 {
6721  assert(blkmem != NULL);
6722  assert(expr != NULL);
6723  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6724  assert(expr->data.data != NULL);
6725  assert(factor != NULL);
6726  assert(factor->op == SCIP_EXPR_POLYNOMIAL);
6727  assert(factor->data.data != NULL);
6728  assert(expr != factor);
6729 
6730 #ifndef NDEBUG
6731  if( childmap == NULL )
6732  {
6733  int i;
6734  assert(factor->nchildren == expr->nchildren);
6735  for( i = 0; i < factor->nchildren; ++i )
6736  assert(SCIPexprAreEqual(expr->children[i], factor->children[i], 0.0));
6737  }
6738  else
6739  {
6740  int i;
6741  for( i = 0; i < factor->nchildren; ++i )
6742  {
6743  assert(childmap[i] >= 0);
6744  assert(childmap[i] < expr->nchildren);
6745  assert(SCIPexprAreEqual(expr->children[childmap[i]], factor->children[i], 0.0));
6746  }
6747  }
6748 #endif
6749 
6751 
6752  return SCIP_OKAY;
6753 }
6754 
6755 /** takes a power of the polynomial
6756  *
6757  * Exponent need to be an integer.
6758  * Polynomial needs to be a monomial, if exponent is negative.
6759  */
6761  BMS_BLKMEM* blkmem, /**< block memory */
6762  SCIP_EXPR* expr, /**< polynomial expression */
6763  int exponent /**< exponent of power operation */
6764  )
6765 {
6766  assert(blkmem != NULL);
6767  assert(expr != NULL);
6768  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6769  assert(expr->data.data != NULL);
6770 
6771  SCIP_CALL( polynomialdataPower(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, exponent) );
6772 
6773  return SCIP_OKAY;
6774 }
6775 
6776 /** merges monomials in a polynomial expression that differ only in coefficient into a single monomial
6777  *
6778  * Eliminates monomials with coefficient between -eps and eps.
6779  */
6781  BMS_BLKMEM* blkmem, /**< block memory */
6782  SCIP_EXPR* expr, /**< polynomial expression */
6783  SCIP_Real eps, /**< threshold under which numbers are treat as zero */
6784  SCIP_Bool mergefactors /**< whether to merge factors in monomials too */
6785  )
6786 {
6787  assert(expr != NULL);
6788  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
6789  assert(expr->data.data != NULL);
6790 
6791  polynomialdataMergeMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data, eps, mergefactors);
6792 }
6793 
6794 /** checks if two monomials are equal */
6796  SCIP_EXPRDATA_MONOMIAL* monomial1, /**< first monomial */
6797  SCIP_EXPRDATA_MONOMIAL* monomial2, /**< second monomial */
6798  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6799  )
6800 {
6801  int i;
6802 
6803  assert(monomial1 != NULL);
6804  assert(monomial2 != NULL);
6805 
6806  if( monomial1->nfactors != monomial2->nfactors )
6807  return FALSE;
6808 
6809  if( !EPSEQ(monomial1->coef, monomial2->coef, eps) )
6810  return FALSE;
6811 
6812  SCIPexprSortMonomialFactors(monomial1);
6813  SCIPexprSortMonomialFactors(monomial2);
6814 
6815  for( i = 0; i < monomial1->nfactors; ++i )
6816  {
6817  if( monomial1->childidxs[i] != monomial2->childidxs[i] ||
6818  !EPSEQ(monomial1->exponents[i], monomial2->exponents[i], eps) )
6819  return FALSE;
6820  }
6821 
6822  return TRUE;
6823 }
6824 
6825 /** changes coefficient of monomial */
6827  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6828  SCIP_Real newcoef /**< new coefficient */
6829  )
6830 {
6831  assert(monomial != NULL);
6832 
6833  monomial->coef = newcoef;
6834 }
6835 
6836 /** adds factors to a monomial */
6838  BMS_BLKMEM* blkmem, /**< block memory */
6839  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6840  int nfactors, /**< number of factors to add */
6841  int* childidxs, /**< indices of children corresponding to factors */
6842  SCIP_Real* exponents /**< exponent in each factor */
6843  )
6844 {
6845  assert(monomial != NULL);
6846  assert(nfactors >= 0);
6847  assert(childidxs != NULL || nfactors == 0);
6848  assert(exponents != NULL || nfactors == 0);
6849 
6850  if( nfactors == 0 )
6851  return SCIP_OKAY;
6852 
6853  SCIP_CALL( monomialdataEnsureFactorsSize(blkmem, monomial, monomial->nfactors + nfactors) );
6854  assert(monomial->nfactors + nfactors <= monomial->factorssize);
6855 
6856  BMScopyMemoryArray(&monomial->childidxs[monomial->nfactors], childidxs, nfactors); /*lint !e866*/
6857  BMScopyMemoryArray(&monomial->exponents[monomial->nfactors], exponents, nfactors); /*lint !e866*/
6858 
6859  monomial->nfactors += nfactors;
6860  monomial->sorted = (monomial->nfactors <= 1);
6861 
6862  return SCIP_OKAY;
6863 }
6864 
6865 /** multiplies a monomial with a monomial */
6867  BMS_BLKMEM* blkmem, /**< block memory */
6868  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6869  SCIP_EXPRDATA_MONOMIAL* factor, /**< factor monomial */
6870  int* childmap /**< map to apply to children in factor, or NULL for 1:1 */
6871  )
6872 {
6873  assert(monomial != NULL);
6874  assert(factor != NULL);
6875 
6876  if( factor->coef == 0.0 )
6877  {
6878  monomial->nfactors = 0;
6879  monomial->coef = 0.0;
6880  return SCIP_OKAY;
6881  }
6882 
6883  SCIP_CALL( SCIPexprAddMonomialFactors(blkmem, monomial, factor->nfactors, factor->childidxs, factor->exponents) );
6884 
6885  if( childmap != NULL )
6886  {
6887  int i;
6888  for( i = monomial->nfactors - factor->nfactors; i < monomial->nfactors; ++i )
6889  monomial->childidxs[i] = childmap[monomial->childidxs[i]];
6890  }
6891 
6892  monomial->coef *= factor->coef;
6893 
6894  return SCIP_OKAY;
6895 }
6896 
6897 /** replaces the monomial by a power of the monomial
6898  *
6899  * Allows only integers as exponent.
6900  */
6902  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6903  int exponent /**< integer exponent of power operation */
6904  )
6905 {
6906  int i;
6907 
6908  assert(monomial != NULL);
6909 
6910  if( exponent == 1 )
6911  return;
6912 
6913  if( exponent == 0 )
6914  {
6915  /* x^0 = 1, unless x = 0; 0^0 = 0 */
6916  if( monomial->coef != 0.0 )
6917  monomial->coef = 1.0;
6918  monomial->nfactors = 0;
6919  return;
6920  }
6921 
6922  monomial->coef = pow(monomial->coef, (SCIP_Real)exponent);
6923  for( i = 0; i < monomial->nfactors; ++i )
6924  monomial->exponents[i] *= exponent;
6925 }
6926 
6927 /** merges factors that correspond to the same child by adding exponents
6928  *
6929  * Eliminates factors with exponent between -eps and eps.
6930  */
6932  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
6933  SCIP_Real eps /**< threshold under which numbers are treated as 0.0 */
6934  )
6935 {
6936  int i;
6937  int offset;
6938 
6939  assert(monomial != NULL);
6940  assert(eps >= 0.0);
6941 
6942  SCIPexprSortMonomialFactors(monomial);
6943 
6944  /* merge factors with same child index by adding up their exponents
6945  * delete factors with exponent 0.0 */
6946  offset = 0;
6947  i = 0;
6948  while( i + offset < monomial->nfactors )
6949  {
6950  if( offset > 0 )
6951  {
6952  assert(monomial->childidxs[i] == -1);
6953  assert(monomial->childidxs[i+offset] >= 0);
6954  monomial->childidxs[i] = monomial->childidxs[i+offset];
6955  monomial->exponents[i] = monomial->exponents[i+offset];
6956 #ifndef NDEBUG
6957  monomial->childidxs[i+offset] = -1;
6958 #endif
6959  }
6960 
6961  while( i+offset+1 < monomial->nfactors && monomial->childidxs[i] == monomial->childidxs[i+offset+1] )
6962  {
6963  monomial->exponents[i] += monomial->exponents[i+offset+1];
6964 #ifndef NDEBUG
6965  monomial->childidxs[i+offset+1] = -1;
6966 #endif
6967  ++offset;
6968  }
6969 
6970  if( EPSZ(monomial->exponents[i], eps) )
6971  {
6972 #ifndef NDEBUG
6973  monomial->childidxs[i] = -1;
6974 #endif
6975  ++offset;
6976  continue;
6977  }
6978  else if( EPSISINT(monomial->exponents[i], eps) )
6979  monomial->exponents[i] = EPSROUND(monomial->exponents[i], eps);
6980 
6981  ++i;
6982  }
6983 
6984 #ifndef NDEBUG
6985  for( ; i < monomial->nfactors; ++i )
6986  assert(monomial->childidxs[i] == -1);
6987 #endif
6988 
6989  monomial->nfactors -= offset;
6990 
6991  if( EPSEQ(monomial->coef, 1.0, eps) )
6992  monomial->coef = 1.0;
6993  else if( EPSEQ(monomial->coef, -1.0, eps) )
6994  monomial->coef = -1.0;
6995 }
6996 
6997 /** ensures that monomials of a polynomial are sorted */
6999  SCIP_EXPR* expr /**< polynomial expression */
7000  )
7001 {
7002  assert(expr != NULL);
7003  assert(expr->op == SCIP_EXPR_POLYNOMIAL);
7004  assert(expr->data.data != NULL);
7005 
7007 }
7008 
7009 /** creates a monomial */
7011  BMS_BLKMEM* blkmem, /**< block memory */
7012  SCIP_EXPRDATA_MONOMIAL** monomial, /**< buffer where to store pointer to new monomial */
7013  SCIP_Real coef, /**< coefficient of monomial */
7014  int nfactors, /**< number of factors in monomial */
7015  int* childidxs, /**< indices of children corresponding to factors, or NULL if identity */
7016  SCIP_Real* exponents /**< exponent in each factor, or NULL if all 1.0 */
7017  )
7018 {
7019  assert(blkmem != NULL);
7020  assert(monomial != NULL);
7021 
7022  SCIP_ALLOC( BMSallocBlockMemory(blkmem, monomial) );
7023 
7024  (*monomial)->coef = coef;
7025  (*monomial)->nfactors = nfactors;
7026  (*monomial)->factorssize = nfactors;
7027  (*monomial)->sorted = (nfactors <= 1);
7028 
7029  if( nfactors > 0 )
7030  {
7031  if( childidxs != NULL )
7032  {
7033  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->childidxs, childidxs, nfactors) );
7034  }
7035  else
7036  {
7037  int i;
7038 
7039  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->childidxs, nfactors) );
7040  for( i = 0; i < nfactors; ++i )
7041  (*monomial)->childidxs[i] = i;
7042  }
7043 
7044  if( exponents != NULL )
7045  {
7046  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*monomial)->exponents, exponents, nfactors) );
7047  }
7048  else
7049  {
7050  int i;
7051 
7052  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*monomial)->exponents, nfactors) );
7053  for( i = 0; i < nfactors; ++i )
7054  (*monomial)->exponents[i] = 1.0;
7055  }
7056  }
7057  else
7058  {
7059  (*monomial)->childidxs = NULL;
7060  (*monomial)->exponents = NULL;
7061  }
7062 
7063  return SCIP_OKAY;
7064 }
7065 
7066 /** frees a monomial */
7068  BMS_BLKMEM* blkmem, /**< block memory */
7069  SCIP_EXPRDATA_MONOMIAL** monomial /**< pointer to monomial that should be freed */
7070  )
7071 {
7072  assert(blkmem != NULL);
7073  assert( monomial != NULL);
7074  assert(*monomial != NULL);
7075 
7076  if( (*monomial)->factorssize > 0 )
7077  {
7078  assert((*monomial)->childidxs != NULL);
7079  assert((*monomial)->exponents != NULL);
7080 
7081  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->childidxs, (*monomial)->factorssize);
7082  BMSfreeBlockMemoryArray(blkmem, &(*monomial)->exponents, (*monomial)->factorssize);
7083  }
7084  assert((*monomial)->childidxs == NULL);
7085  assert((*monomial)->exponents == NULL);
7086 
7087  BMSfreeBlockMemory(blkmem, monomial);
7088 }
7089 
7090 /** ensures that factors in a monomial are sorted */
7092  SCIP_EXPRDATA_MONOMIAL* monomial /**< monomial */
7093  )
7094 {
7095  assert(monomial != NULL);
7096 
7097  if( monomial->sorted )
7098  return;
7099 
7100  if( monomial->nfactors > 0 )
7101  SCIPsortIntReal(monomial->childidxs, monomial->exponents, monomial->nfactors);
7102 
7103  monomial->sorted = TRUE;
7104 }
7105 
7106 /** finds a factor corresponding to a given child index in a monomial
7107  *
7108  * Note that if the factors have not been merged, the position of some factor corresponding to a given child is given.
7109  * Returns TRUE if a factor is found, FALSE if not.
7110  */
7112  SCIP_EXPRDATA_MONOMIAL* monomial, /**< monomial */
7113  int childidx, /**< index of the child which factor to search for */
7114  int* pos /**< buffer to store position of factor */
7115  )
7116 {
7117  assert(monomial != NULL);
7118 
7119  if( monomial->nfactors == 0 )
7120  return FALSE;
7121 
7122  SCIPexprSortMonomialFactors(monomial);
7123 
7124  return SCIPsortedvecFindInt(monomial->childidxs, childidx, monomial->nfactors, pos);
7125 }
7126 
7127 /** creates a user expression */
7129  BMS_BLKMEM* blkmem, /**< block memory data structure */
7130  SCIP_EXPR** expr, /**< pointer to buffer for expression address */
7131  int nchildren, /**< number of children */
7132  SCIP_EXPR** children, /**< children of expression */
7133  SCIP_USEREXPRDATA* data, /**< user data for expression, expression assumes ownership */
7134  SCIP_EXPRINTCAPABILITY evalcapability, /**< capability of evaluation functions (partially redundant, currently) */
7135  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
7136  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function, or NULL if not implemented */
7137  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
7138  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function, or NULL if not implemented */
7139  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
7140  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
7141  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
7142  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
7143  )
7144 {
7145  SCIP_EXPROPDATA opdata;
7146  SCIP_EXPRDATA_USER* userexprdata;
7147  SCIP_EXPR** childrencopy;
7148 
7149  assert(blkmem != NULL);
7150  assert(expr != NULL);
7151  assert(eval != NULL);
7152  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
7153  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
7154  assert(curv != NULL);
7155  assert(copydata != NULL || data == NULL);
7156  assert(freedata != NULL || data == NULL);
7157 
7158  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &userexprdata) );
7159 
7160  userexprdata->userdata = data;
7161  userexprdata->evalcapability = evalcapability;
7162  userexprdata->eval = eval;
7163  userexprdata->inteval = inteval;
7164  userexprdata->curv = curv;
7165  userexprdata->prop = prop;
7166  userexprdata->estimate = estimate;
7167  userexprdata->copydata = copydata;
7168  userexprdata->freedata = freedata;
7169  userexprdata->print = print;
7170 
7171  opdata.data = (void*) userexprdata;
7172 
7173  if( nchildren == 0 )
7174  {
7175  SCIP_CALL( exprCreate(blkmem, expr, SCIP_EXPR_USER, 0, NULL, opdata) );
7176  return SCIP_OKAY;
7177  }
7178  assert(children != NULL);
7179 
7180  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &childrencopy, children, nchildren) );
7181 
7182  SCIP_CALL( exprCreate( blkmem, expr, SCIP_EXPR_USER, nchildren, childrencopy, opdata) );
7183 
7184  return SCIP_OKAY;
7185 }
7186 
7187 /** indicates whether the expression contains a SCIP_EXPR_PARAM */
7189  SCIP_EXPR* expr /**< expression */
7190  )
7191 {
7192  int i;
7193 
7194  assert(expr != NULL);
7195 
7196  if( expr->op == SCIP_EXPR_PARAM )
7197  return TRUE;
7198 
7199  for( i = 0; i < expr->nchildren; ++i )
7200  if( SCIPexprHasParam(expr->children[i]) )
7201  return TRUE;
7202 
7203  return FALSE;
7204 }
7205 
7206 /** gets maximal degree of expression, or SCIP_EXPR_DEGREEINFINITY if not a polynomial */
7208  SCIP_EXPR* expr, /**< expression */
7209  int* maxdegree /**< buffer to store maximal degree */
7210  )
7211 {
7212  int child1;
7213  int child2;
7214 
7215  assert(expr != NULL);
7216  assert(maxdegree != NULL);
7217 
7218  switch( expr->op )
7219  {
7220  case SCIP_EXPR_VARIDX:
7221  *maxdegree = 1;
7222  break;
7223 
7224  case SCIP_EXPR_CONST:
7225  case SCIP_EXPR_PARAM:
7226  *maxdegree = 0;
7227  break;
7228 
7229  case SCIP_EXPR_PLUS:
7230  case SCIP_EXPR_MINUS:
7231  {
7232  assert(expr->children[0] != NULL);
7233  assert(expr->children[1] != NULL);
7234 
7235  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7236  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7237 
7238  *maxdegree = MAX(child1, child2);
7239  break;
7240  }
7241 
7242  case SCIP_EXPR_MUL:
7243  {
7244  assert(expr->children[0] != NULL);
7245  assert(expr->children[1] != NULL);
7246 
7247  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7248  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7249 
7250  *maxdegree = child1 + child2;
7251  break;
7252  }
7253 
7254  case SCIP_EXPR_DIV:
7255  {
7256  assert(expr->children[0] != NULL);
7257  assert(expr->children[1] != NULL);
7258 
7259  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7260  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7261 
7262  /* if not division by constant, then it is not a polynomial */
7263  *maxdegree = (child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : child1;
7264  break;
7265  }
7266 
7267  case SCIP_EXPR_SQUARE:
7268  {
7269  assert(expr->children[0] != NULL);
7270 
7271  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7272 
7273  *maxdegree = 2 * child1;
7274  break;
7275  }
7276 
7277  case SCIP_EXPR_SQRT:
7278  {
7279  assert(expr->children[0] != NULL);
7280 
7281  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7282 
7283  /* if not squareroot of constant, then no polynomial */
7284  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7285  break;
7286  }
7287 
7288  case SCIP_EXPR_REALPOWER:
7289  {
7290  assert(expr->children[0] != NULL);
7291 
7292  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7293 
7294  /* constant ^ constant has degree 0 */
7295  if( child1 == 0 )
7296  {
7297  *maxdegree = 0;
7298  break;
7299  }
7300 
7301  /* non-polynomial ^ constant is not a polynomial */
7302  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7303  {
7304  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7305  break;
7306  }
7307 
7308  /* so it is polynomial ^ constant
7309  * let's see whether the constant is integral */
7310 
7311  if( expr->data.dbl == 0.0 ) /* polynomial ^ 0 == 0 */
7312  *maxdegree = 0;
7313  else if( expr->data.dbl > 0.0 && (int)expr->data.dbl == expr->data.dbl ) /* natural exponent gives polynomial again */ /*lint !e777*/
7314  *maxdegree = child1 * (int)expr->data.dbl;
7315  else /* negative or nonintegral exponent does not give polynomial */
7316  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7317 
7318  break;
7319  }
7320 
7321  case SCIP_EXPR_INTPOWER:
7322  {
7323  assert(expr->children[0] != NULL);
7324 
7325  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7326 
7327  /* constant ^ integer or something ^ 0 has degree 0 */
7328  if( child1 == 0 || expr->data.intval == 0 )
7329  {
7330  *maxdegree = 0;
7331  break;
7332  }
7333 
7334  /* non-polynomial ^ integer or something ^ negative is not a polynomial */
7335  if( child1 >= SCIP_EXPR_DEGREEINFINITY || expr->data.intval < 0 )
7336  {
7337  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7338  break;
7339  }
7340 
7341  /* so it is polynomial ^ natural, which gives a polynomial again */
7342  *maxdegree = child1 * expr->data.intval;
7343 
7344  break;
7345  }
7346 
7347  case SCIP_EXPR_SIGNPOWER:
7348  {
7349  assert(expr->children[0] != NULL);
7350 
7351  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7352 
7353  /* if child is not constant, then it is no polynomial */
7354  *maxdegree = child1 != 0 ? SCIP_EXPR_DEGREEINFINITY : 0;
7355  break;
7356  }
7357 
7358  case SCIP_EXPR_EXP:
7359  case SCIP_EXPR_LOG:
7360  case SCIP_EXPR_SIN:
7361  case SCIP_EXPR_COS:
7362  case SCIP_EXPR_TAN:
7363  /* case SCIP_EXPR_ERF: */
7364  /* case SCIP_EXPR_ERFI: */
7365  case SCIP_EXPR_ABS:
7366  case SCIP_EXPR_SIGN:
7367  case SCIP_EXPR_USER:
7368  {
7369  assert(expr->children[0] != NULL);
7370 
7371  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7372 
7373  /* if argument is not a constant, then no polynomial, otherwise it is a constant */
7374  *maxdegree = (child1 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7375  break;
7376  }
7377 
7378  case SCIP_EXPR_MIN:
7379  case SCIP_EXPR_MAX:
7380  {
7381  assert(expr->children[0] != NULL);
7382  assert(expr->children[1] != NULL);
7383 
7384  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[0], &child1) );
7385  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[1], &child2) );
7386 
7387  /* if any of the operands is not constant, then it is no polynomial */
7388  *maxdegree = (child1 != 0 || child2 != 0) ? SCIP_EXPR_DEGREEINFINITY : 0;
7389  break;
7390  }
7391 
7392  case SCIP_EXPR_SUM:
7393  case SCIP_EXPR_LINEAR:
7394  {
7395  int i;
7396 
7397  *maxdegree = 0;
7398  for( i = 0; i < expr->nchildren && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7399  {
7400  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7401  if( child1 > *maxdegree )
7402  *maxdegree = child1;
7403  }
7404 
7405  break;
7406  }
7407 
7408  case SCIP_EXPR_PRODUCT:
7409  {
7410  int i;
7411 
7412  *maxdegree = 0;
7413  for( i = 0; i < expr->nchildren; ++i )
7414  {
7415  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[i], &child1) );
7416  if( child1 >= SCIP_EXPR_DEGREEINFINITY )
7417  {
7418  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7419  break;
7420  }
7421  *maxdegree += child1;
7422  }
7423 
7424  break;
7425  }
7426 
7427  case SCIP_EXPR_QUADRATIC:
7428  {
7429  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
7430  int childidx;
7431  int quadidx;
7432 
7433  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
7434 
7435  /* make sure quadratic elements are sorted */
7436  quadraticdataSort(quadraticdata);
7437 
7438  *maxdegree = 0;
7439  quadidx = 0;
7440  for( childidx = 0; childidx < expr->nchildren; ++childidx )
7441  {
7442  /* if no linear or no quadratic coefficient with current child on first position, then nothing to do */
7443  if( (quadraticdata->lincoefs == NULL || quadraticdata->lincoefs[childidx] == 0.0) &&
7444  (quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 > childidx) )
7445  continue;
7446 
7447  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[childidx], &child1) );
7448  if( child1 == SCIP_EXPR_DEGREEINFINITY )
7449  {
7450  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7451  break;
7452  }
7453 
7454  while( quadidx < quadraticdata->nquadelems && quadraticdata->quadelems[quadidx].idx1 == childidx )
7455  {
7456  if( quadraticdata->quadelems[quadidx].idx2 == childidx )
7457  {
7458  /* square term */
7459  if( 2*child1 > *maxdegree )
7460  *maxdegree = 2*child1;
7461  }
7462  else
7463  {
7464  /* bilinear term */
7465  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[quadraticdata->quadelems[quadidx].idx2], &child2) );
7466  if( child2 == SCIP_EXPR_DEGREEINFINITY )
7467  {
7468  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7469  break;
7470  }
7471  if( child1 + child2 > *maxdegree )
7472  *maxdegree = child1 + child2;
7473  }
7474  ++quadidx;
7475  }
7476  if( *maxdegree == SCIP_EXPR_DEGREEINFINITY )
7477  break;
7478  }
7479 
7480  break;
7481  }
7482 
7483  case SCIP_EXPR_POLYNOMIAL:
7484  {
7485  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
7486  SCIP_EXPRDATA_MONOMIAL* monomialdata;
7487  int monomialdegree;
7488  int i;
7489  int j;
7490 
7491  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
7492 
7493  *maxdegree = 0;
7494  for( i = 0; i < polynomialdata->nmonomials && *maxdegree < SCIP_EXPR_DEGREEINFINITY; ++i )
7495  {
7496  monomialdata = polynomialdata->monomials[i];
7497  assert(monomialdata != NULL);
7498 
7499  /* compute degree of monomial = sum of degree of factors */
7500  monomialdegree = 0;
7501  for( j = 0; j < monomialdata->nfactors; ++j )
7502  {
7503  SCIP_CALL( SCIPexprGetMaxDegree(expr->children[monomialdata->childidxs[j]], &child1) );
7504 
7505  /* if the exponent of the factor is not a natural number and the child is not constant (degree 0),
7506  * then we report that we are not really a polynomial */
7507  if( child1 != 0 && (monomialdata->exponents[j] < 0.0 || (int)monomialdata->exponents[j] != monomialdata->exponents[j]) )
7508  {
7509  *maxdegree = SCIP_EXPR_DEGREEINFINITY;
7510  break;
7511  }
7512 
7513  monomialdegree += child1 * (int)monomialdata->exponents[j];
7514  }
7515 
7516  if( monomialdegree > *maxdegree )
7517  *maxdegree = monomialdegree;
7518  }
7519 
7520  break;
7521  }
7522 
7523  case SCIP_EXPR_LAST:
7524  SCIPABORT();
7525  break;
7526  }
7527 
7528  return SCIP_OKAY;
7529 }
7530 
7531 /** counts usage of variables in expression */
7533  SCIP_EXPR* expr, /**< expression to update */
7534  int* varsusage /**< array with counters of variable usage */
7535  )
7536 {
7537  int i;
7538 
7539  assert(expr != NULL);
7540  assert(varsusage != NULL);
7541 
7542  if( expr->op == SCIP_EXPR_VARIDX )
7543  {
7544  ++varsusage[expr->data.intval];
7545  }
7546 
7547  for( i = 0; i < expr->nchildren; ++i )
7548  SCIPexprGetVarsUsage(expr->children[i], varsusage);
7549 }
7550 
7551 /** compares whether two expressions are the same
7552  *
7553  * Inconclusive, i.e., may give FALSE even if expressions are equivalent (x*y != y*x).
7554  */
7556  SCIP_EXPR* expr1, /**< first expression */
7557  SCIP_EXPR* expr2, /**< second expression */
7558  SCIP_Real eps /**< threshold under which numbers are assumed to be zero */
7559  )
7560 {
7561  assert(expr1 != NULL);
7562  assert(expr2 != NULL);
7563 
7564  if( expr1 == expr2 )
7565  return TRUE;
7566 
7567  if( expr1->op != expr2->op )
7568  return FALSE;
7569 
7570  switch( expr1->op )
7571  {
7572  case SCIP_EXPR_VARIDX:
7573  case SCIP_EXPR_PARAM:
7574  return expr1->data.intval == expr2->data.intval;
7575 
7576  case SCIP_EXPR_CONST:
7577  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps);
7578 
7579  /* operands with two children */
7580  case SCIP_EXPR_PLUS :
7581  case SCIP_EXPR_MINUS :
7582  case SCIP_EXPR_MUL :
7583  case SCIP_EXPR_DIV :
7584  case SCIP_EXPR_MIN :
7585  case SCIP_EXPR_MAX :
7586  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps) && SCIPexprAreEqual(expr1->children[1], expr2->children[1], eps);
7587 
7588  /* operands with one child */
7589  case SCIP_EXPR_SQUARE:
7590  case SCIP_EXPR_SQRT :
7591  case SCIP_EXPR_EXP :
7592  case SCIP_EXPR_LOG :
7593  case SCIP_EXPR_SIN :
7594  case SCIP_EXPR_COS :
7595  case SCIP_EXPR_TAN :
7596  /* case SCIP_EXPR_ERF : */
7597  /* case SCIP_EXPR_ERFI : */
7598  case SCIP_EXPR_ABS :
7599  case SCIP_EXPR_SIGN :
7600  return SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7601 
7602  case SCIP_EXPR_REALPOWER:
7603  case SCIP_EXPR_SIGNPOWER:
7604  return EPSEQ(expr1->data.dbl, expr2->data.dbl, eps) && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7605 
7606  case SCIP_EXPR_INTPOWER:
7607  return expr1->data.intval == expr2->data.intval && SCIPexprAreEqual(expr1->children[0], expr2->children[0], eps);
7608 
7609  /* complex operands */
7610  case SCIP_EXPR_SUM :
7611  case SCIP_EXPR_PRODUCT:
7612  {
7613  int i;
7614 
7615  /* @todo sort children and have sorted flag in data? */
7616 
7617  if( expr1->nchildren != expr2->nchildren )
7618  return FALSE;
7619 
7620  for( i = 0; i < expr1->nchildren; ++i )
7621  {
7622  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7623  return FALSE;
7624  }
7625 
7626  return TRUE;
7627  }
7628 
7629  case SCIP_EXPR_LINEAR :
7630  {
7631  SCIP_Real* data1;
7632  SCIP_Real* data2;
7633  int i;
7634 
7635  /* @todo sort children and have sorted flag in data? */
7636 
7637  if( expr1->nchildren != expr2->nchildren )
7638  return FALSE;
7639 
7640  data1 = (SCIP_Real*)expr1->data.data;
7641  data2 = (SCIP_Real*)expr2->data.data;
7642 
7643  /* check if constant and coefficients are equal */
7644  for( i = 0; i < expr1->nchildren + 1; ++i )
7645  if( !EPSEQ(data1[i], data2[i], eps) )
7646  return FALSE;
7647 
7648  /* check if children are equal */
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_QUADRATIC:
7659  {
7660  SCIP_EXPRDATA_QUADRATIC* data1;
7661  SCIP_EXPRDATA_QUADRATIC* data2;
7662  int i;
7663 
7664  if( expr1->nchildren != expr2->nchildren )
7665  return FALSE;
7666 
7667  data1 = (SCIP_EXPRDATA_QUADRATIC*)expr1->data.data;
7668  data2 = (SCIP_EXPRDATA_QUADRATIC*)expr2->data.data;
7669 
7670  if( data1->nquadelems != data2->nquadelems )
7671  return FALSE;
7672 
7673  if( !EPSEQ(data1->constant, data2->constant, eps) )
7674  return FALSE;
7675 
7676  /* check if linear part is equal */
7677  if( data1->lincoefs != NULL || data2->lincoefs != NULL )
7678  for( i = 0; i < expr1->nchildren; ++i )
7679  {
7680  if( data1->lincoefs == NULL )
7681  {
7682  if( !EPSZ(data2->lincoefs[i], eps) )
7683  return FALSE;
7684  }
7685  else if( data2->lincoefs == NULL )
7686  {
7687  if( !EPSZ(data1->lincoefs[i], eps) )
7688  return FALSE;
7689  }
7690  else if( !EPSEQ(data1->lincoefs[i], data2->lincoefs[i], eps) )
7691  return FALSE;
7692  }
7693 
7694  SCIPexprSortQuadElems(expr1);
7695  SCIPexprSortQuadElems(expr2);
7696 
7697  /* check if quadratic elements are equal */
7698  for( i = 0; i < data1->nquadelems; ++i )
7699  if( data1->quadelems[i].idx1 != data2->quadelems[i].idx1 ||
7700  data1->quadelems[i].idx2 != data2->quadelems[i].idx2 ||
7701  !EPSEQ(data1->quadelems[i].coef, data2->quadelems[i].coef, eps) )
7702  return FALSE;
7703 
7704  /* check if children are equal */
7705  for( i = 0; i < expr1->nchildren; ++i )
7706  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7707  return FALSE;
7708 
7709  return TRUE;
7710  }
7711 
7712  case SCIP_EXPR_POLYNOMIAL:
7713  {
7714  SCIP_EXPRDATA_POLYNOMIAL* data1;
7715  SCIP_EXPRDATA_POLYNOMIAL* data2;
7716  int i;
7717 
7718  if( expr1->nchildren != expr2->nchildren )
7719  return FALSE;
7720 
7721  data1 = (SCIP_EXPRDATA_POLYNOMIAL*)expr1->data.data;
7722  data2 = (SCIP_EXPRDATA_POLYNOMIAL*)expr2->data.data;
7723 
7724  if( data1->nmonomials != data2->nmonomials )
7725  return FALSE;
7726 
7727  if( !EPSEQ(data1->constant, data2->constant, eps) )
7728  return FALSE;
7729 
7730  /* make sure polynomials are sorted */
7731  SCIPexprSortMonomials(expr1);
7732  SCIPexprSortMonomials(expr2);
7733 
7734  /* check if monomials are equal */
7735  for( i = 0; i < data1->nmonomials; ++i )
7736  {
7737  if( !SCIPexprAreMonomialsEqual(data1->monomials[i], data2->monomials[i], eps) )
7738  return FALSE;
7739  }
7740 
7741  /* check if children are equal */
7742  for( i = 0; i < expr1->nchildren; ++i )
7743  {
7744  if( !SCIPexprAreEqual(expr1->children[i], expr2->children[i], eps) )
7745  return FALSE;
7746  }
7747 
7748  return TRUE;
7749  }
7750 
7751  case SCIP_EXPR_USER:
7752  {
7753  /* @todo could implement this via another user callback */
7754  return FALSE;
7755  }
7756 
7757  case SCIP_EXPR_LAST:
7758  break;
7759  }
7760 
7761  SCIPerrorMessage("this should never happen\n");
7762  SCIPABORT();
7763  return FALSE; /*lint !e527*/
7764 }
7765 
7766 /** aims at simplifying an expression and splitting of a linear expression
7767  *
7768  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
7769  */
7771  BMS_BLKMEM* blkmem, /**< block memory data structure */
7772  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
7773  SCIP_EXPR* expr, /**< expression */
7774  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
7775  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
7776  int nvars, /**< number of variables in expression */
7777  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
7778  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
7779  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
7780  )
7781 {
7782  assert(blkmem != NULL);
7783  assert(expr != NULL);
7784  assert(eps >= 0.0);
7785 
7786  SCIPdebugMessage("simplify expression: ");
7787  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7788  SCIPdebugPrintf("\n");
7789 
7791 
7792  SCIPdebugMessage("converted to polynomials: ");
7793  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7794  SCIPdebugPrintf("\n");
7795 
7796  SCIP_CALL( exprsimplifyFlattenPolynomials(blkmem, messagehdlr, expr, eps, maxexpansionexponent) );
7797 
7798  SCIPdebugMessage("polynomials flattened: ");
7799  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7800  SCIPdebugPrintf("\n");
7801 
7802  if( nlinvars != NULL )
7803  {
7804  /* separate linear part from root polynomial */
7805  SCIP_CALL( exprsimplifySeparateLinearFromPolynomial(blkmem, expr, eps, nvars, nlinvars, linidxs, lincoefs) );
7806 
7807  SCIPdebugMessage("separated linear part: ");
7808  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7809  SCIPdebugPrintf("\n");
7810  }
7811 
7813 
7814  SCIPdebugMessage("converted back from polynomials: ");
7815  SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
7816  SCIPdebugPrintf("\n");
7817 
7818  return SCIP_OKAY;
7819 }
7820 
7821 /** evaluates an expression w.r.t. given values for children expressions */
7823  SCIP_EXPR* expr, /**< expression */
7824  SCIP_Real* argvals, /**< values for children, can be NULL if the expression has no children */
7825  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression operand is not a variable */
7826  SCIP_Real* param, /**< values for parameters, can be NULL if the expression operand is not a parameter */
7827  SCIP_Real* val /**< buffer to store value */
7828  )
7829 {
7830  assert(expr != NULL);
7831  assert(argvals != NULL || expr->nchildren == 0);
7832 
7833  /* evaluate this expression */
7834  assert( exprOpTable[expr->op].eval != NULL );
7835  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, argvals, varvals, param, val) );
7836 
7837  return SCIP_OKAY;
7838 }
7839 
7840 /** evaluates an expression w.r.t. a point */
7842  SCIP_EXPR* expr, /**< expression */
7843  SCIP_Real* varvals, /**< values for variables, can be NULL if the expression is constant */
7844  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7845  SCIP_Real* val /**< buffer to store value */
7846  )
7847 {
7848  int i;
7850  SCIP_Real* buf;
7851 
7852  /* if many children, get large enough memory to store argument values */
7854  {
7855  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7856  }
7857  else
7858  {
7859  buf = staticbuf;
7860  }
7861 
7862  /* evaluate children */
7863  for( i = 0; i < expr->nchildren; ++i )
7864  {
7865  SCIP_CALL( SCIPexprEval(expr->children[i], varvals, param, &buf[i]) ); /*lint !e644*/
7866  }
7867 
7868  /* evaluate this expression */
7869  assert( exprOpTable[expr->op].eval != NULL );
7870  SCIP_CALL( exprOpTable[expr->op].eval(expr->data, expr->nchildren, buf, varvals, param, val) );
7871 
7872  /* free memory, if allocated before */
7873  if( staticbuf != buf )
7874  {
7875  BMSfreeMemoryArray(&buf);
7876  }
7877 
7878  return SCIP_OKAY;
7879 }
7880 
7881 /** evaluates an expression w.r.t. given interval values for children expressions */
7883  SCIP_EXPR* expr, /**< expression */
7884  SCIP_Real infinity, /**< value to use for infinity */
7885  SCIP_INTERVAL* argvals, /**< interval values for children, can be NULL if the expression has no children */
7886  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7887  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7888  SCIP_INTERVAL* val /**< buffer to store value */
7889  )
7890 {
7891  assert(expr != NULL);
7892  assert(argvals != NULL || expr->nchildren == 0);
7893 
7894  /* evaluate this expression */
7895  assert( exprOpTable[expr->op].inteval != NULL );
7896  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, argvals, varvals, param, val) );
7897 
7898  return SCIP_OKAY;
7899 }
7900 
7901 /** evaluates an expression w.r.t. an interval */
7903  SCIP_EXPR* expr, /**< expression */
7904  SCIP_Real infinity, /**< value to use for infinity */
7905  SCIP_INTERVAL* varvals, /**< interval values for variables, can be NULL if the expression is constant */
7906  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
7907  SCIP_INTERVAL* val /**< buffer to store value */
7908  )
7909 {
7910  int i;
7912  SCIP_INTERVAL* buf;
7913 
7914  /* if many children, get large enough memory to store argument values */
7916  {
7917  SCIP_ALLOC( BMSallocMemoryArray(&buf, expr->nchildren) );
7918  }
7919  else
7920  {
7921  buf = staticbuf;
7922  }
7923 
7924  /* evaluate children */
7925  for( i = 0; i < expr->nchildren; ++i )
7926  {
7927  SCIP_CALL( SCIPexprEvalInt(expr->children[i], infinity, varvals, param, &buf[i]) ); /*lint !e644*/
7928  }
7929 
7930  /* evaluate this expression */
7931  assert( exprOpTable[expr->op].inteval != NULL );
7932  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, buf, varvals, param, val) );
7933 
7934  /* free memory, if allocated before */
7935  if( staticbuf != buf )
7936  {
7937  BMSfreeMemoryArray(&buf);
7938  }
7939 
7940  return SCIP_OKAY;
7941 }
7942 
7943 /** evaluates a user expression w.r.t. given values for children expressions */
7945  SCIP_EXPR* expr, /**< expression */
7946  SCIP_Real* argvals, /**< values for children */
7947  SCIP_Real* val, /**< buffer to store function value */
7948  SCIP_Real* gradient, /**< buffer to store gradient values, or NULL if not requested */
7949  SCIP_Real* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7950  )
7951 {
7952  SCIP_EXPRDATA_USER* exprdata;
7953 
7954  assert(expr != NULL);
7955  assert(expr->op == SCIP_EXPR_USER);
7956  assert(argvals != NULL || expr->nchildren == 0);
7957 
7958  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7959  assert(exprdata->eval != NULL);
7960 
7961  SCIP_CALL( exprdata->eval(exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7962 
7963  return SCIP_OKAY;
7964 }
7965 
7966 /** evaluates a user expression w.r.t. an interval */
7968  SCIP_EXPR* expr, /**< expression */
7969  SCIP_Real infinity, /**< value to use for infinity */
7970  SCIP_INTERVAL* argvals, /**< values for children */
7971  SCIP_INTERVAL* val, /**< buffer to store value */
7972  SCIP_INTERVAL* gradient, /**< buffer to store gradient values, or NULL if not requested */
7973  SCIP_INTERVAL* hessian /**< buffer to store values of full Hessian, or NULL if not requested */
7974  )
7975 {
7976  SCIP_EXPRDATA_USER* exprdata;
7977 
7978  assert(expr != NULL);
7979  assert(expr->op == SCIP_EXPR_USER);
7980  assert(argvals != NULL || expr->nchildren == 0);
7981 
7982  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
7983 
7984  if( exprdata->inteval == NULL )
7985  {
7986  int i;
7987 
7988  for( i = 0; i < expr->nchildren; ++i )
7989  SCIPintervalSetEntire(infinity, &argvals[i]); /*lint !e613*/
7990  }
7991  else
7992  {
7993  SCIP_CALL( exprdata->inteval(infinity, exprdata->userdata, expr->nchildren, argvals, val, gradient, hessian) );
7994  }
7995 
7996  return SCIP_OKAY;
7997 }
7998 
7999 /** tries to determine the curvature type of an expression w.r.t. given variable domains */
8001  SCIP_EXPR* expr, /**< expression to check */
8002  SCIP_Real infinity, /**< value to use for infinity */
8003  SCIP_INTERVAL* varbounds, /**< domains of variables */
8004  SCIP_Real* param, /**< values for parameters, can be NULL if the expression is not parameterized */
8005  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8006  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression */
8007  )
8008 {
8010  SCIP_INTERVAL* childbounds;
8012  SCIP_EXPRCURV* childcurv;
8013  int i;
8014 
8015  assert(expr != NULL);
8016  assert(curv != NULL);
8017  assert(bounds != NULL);
8018 
8019  /* if many children, get large enough memory to store argument values */
8021  {
8022  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, expr->nchildren) );
8023  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, expr->nchildren) );
8024  }
8025  else
8026  {
8027  childbounds = childboundsbuf;
8028  childcurv = childcurvbuf;
8029  }
8030 
8031  /* check curvature and compute bounds of children
8032  * constant children can be considered as always linear */
8033  for( i = 0; i < expr->nchildren; ++i )
8034  {
8035  SCIP_CALL( SCIPexprCheckCurvature(expr->children[i], infinity, varbounds, param, &childcurv[i], &childbounds[i]) ); /*lint !e644*/
8036  if( childbounds[i].inf == childbounds[i].sup ) /*lint !e777*/
8037  childcurv[i] = SCIP_EXPRCURV_LINEAR;
8038  }
8039 
8040  /* get curvature and bounds of expr */
8041  assert(exprOpTable[expr->op].curv != NULL);
8042  assert(exprOpTable[expr->op].inteval != NULL);
8043 
8044  SCIP_CALL( exprOpTable[expr->op].curv(infinity, expr->data, expr->nchildren, childbounds, childcurv, curv) );
8045  SCIP_CALL( exprOpTable[expr->op].inteval(infinity, expr->data, expr->nchildren, childbounds, varbounds, param, bounds) );
8046 
8047  /* free memory, if allocated before */
8048  if( childboundsbuf != childbounds )
8049  {
8050  BMSfreeMemoryArray(&childcurv);
8051  BMSfreeMemoryArray(&childbounds);
8052  }
8053 
8054  return SCIP_OKAY;
8055 }
8056 
8057 /** under-/overestimates a user expression w.r.t. to given values and bounds for children expressions */
8059  SCIP_EXPR* expr, /**< expression */
8060  SCIP_Real infinity, /**< value to use for infinity */
8061  SCIP_Real* argvals, /**< values for children */
8062  SCIP_INTERVAL* argbounds, /**< bounds for children */
8063  SCIP_Bool overestimate, /**< whether to overestimate the expression */
8064  SCIP_Real* coeffs, /**< buffer to store the linear coefficients for each child expression that gives a valid under-/overestimator */
8065  SCIP_Real* constant, /**< buffer to store the constant value of the linear under-/overestimator */
8066  SCIP_Bool* success /**< buffer to store whether an estimator was successfully computed */
8067  )
8068 {
8069  SCIP_EXPRDATA_USER* exprdata;
8070 
8071  assert(expr != NULL);
8072  assert(expr->op == SCIP_EXPR_USER);
8073  assert(argvals != NULL || expr->nchildren == 0);
8074  assert(argbounds != NULL || expr->nchildren == 0);
8075 
8076  exprdata = (SCIP_EXPRDATA_USER*) expr->data.data;
8077 
8078  if( exprdata->estimate != NULL )
8079  {
8080  SCIP_CALL( exprdata->estimate(infinity, exprdata->userdata, expr->nchildren, argvals, argbounds, overestimate, coeffs, constant, success ) );
8081  }
8082  else
8083  {
8084  *success = FALSE;
8085  }
8086 
8087  return SCIP_OKAY;
8088 }
8089 
8090 /** substitutes variables (SCIP_EXPR_VARIDX) by expressions
8091  *
8092  * Note that only the children of the given expr are checked!
8093  * A variable with index i is replaced by a copy of substexprs[i], if the latter is not NULL.
8094  * If substexprs[i] == NULL, then the variable expression i is not touched.
8095  */
8097  BMS_BLKMEM* blkmem, /**< block memory data structure */
8098  SCIP_EXPR* expr, /**< expression, which of the children may be replaced */
8099  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8100  )
8101 {
8102  int i;
8103 
8104  assert(blkmem != NULL);
8105  assert(expr != NULL);
8106  assert(substexprs != NULL);
8107 
8108  for( i = 0; i < expr->nchildren; ++i )
8109  {
8110  if( expr->children[i]->op == SCIP_EXPR_VARIDX )
8111  {
8112  int varidx;
8113  varidx = expr->children[i]->data.intval;
8114 
8115  assert(varidx >= 0);
8116  if( substexprs[varidx] != NULL )
8117  {
8118  /* replace child i by copy of substexprs[expr->children[i]->opdata.intval] */
8119  SCIPexprFreeDeep(blkmem, &expr->children[i]);
8120  SCIP_CALL( SCIPexprCopyDeep(blkmem, &expr->children[i], substexprs[varidx]) );
8121  }
8122  }
8123  else
8124  {
8125  /* call recursively */
8126  SCIP_CALL( SCIPexprSubstituteVars(blkmem, expr->children[i], substexprs) );
8127  }
8128  }
8129 
8130  return SCIP_OKAY;
8131 }
8132 
8133 /** updates variable indices in expression tree */
8135  SCIP_EXPR* expr, /**< expression to update */
8136  int* newindices /**< new indices of variables */
8137  )
8138 {
8139  int i;
8140 
8141  assert(expr != NULL);
8142  assert(newindices != NULL);
8143 
8144  if( expr->op == SCIP_EXPR_VARIDX )
8145  {
8146  expr->data.intval = newindices[expr->data.intval];
8147  assert(expr->data.intval >= 0);
8148  }
8149 
8150  for( i = 0; i < expr->nchildren; ++i )
8151  SCIPexprReindexVars(expr->children[i], newindices);
8152 }
8153 
8154 /** updates parameter indices in expression tree */
8156  SCIP_EXPR* expr, /**< expression to update */
8157  int* newindices /**< new indices of variables */
8158  )
8159 {
8160  int i;
8161 
8162  assert(expr != NULL);
8163  assert(newindices != NULL);
8164 
8165  if( expr->op == SCIP_EXPR_PARAM )
8166  {
8167  expr->data.intval = newindices[expr->data.intval];
8168  assert(expr->data.intval >= 0);
8169  }
8170 
8171  for( i = 0; i < expr->nchildren; ++i )
8172  SCIPexprReindexParams(expr->children[i], newindices);
8173 }
8174 
8175 /** prints an expression */
8177  SCIP_EXPR* expr, /**< expression */
8178  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8179  FILE* file, /**< file for printing, or NULL for stdout */
8180  const char** varnames, /**< names of variables, or NULL for default names */
8181  const char** paramnames, /**< names of parameters, or NULL for default names */
8182  SCIP_Real* paramvals /**< values of parameters, or NULL for not printing */
8183  )
8184 {
8185  assert( expr != NULL );
8186 
8187  switch( expr->op )
8188  {
8189  /* @Note: 'expr->data.intval' is either between 0 and number of variables-1, if it uses the varnames array, or
8190  * between 0 and number of params in the expression tree, if it uses the paramnames array
8191  * because, here, we cannot get the values above we cannot assert them
8192  */
8193  case SCIP_EXPR_VARIDX:
8194  if( varnames != NULL )
8195  {
8196  assert(varnames[expr->data.intval] != NULL);
8197  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", varnames[expr->data.intval]);
8198  }
8199  else
8200  {
8201  SCIPmessageFPrintInfo(messagehdlr, file, "var%d", expr->data.intval);
8202  }
8203  break;
8204 
8205  case SCIP_EXPR_PARAM:
8206  if( paramnames != NULL )
8207  {
8208  assert(paramnames[expr->data.intval] != NULL);
8209  SCIPmessageFPrintInfo(messagehdlr, file, "%s", paramnames[expr->data.intval]);
8210  }
8211  else
8212  {
8213  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", expr->data.intval );
8214  }
8215  if( paramvals != NULL )
8216  {
8217  SCIPmessageFPrintInfo(messagehdlr, file, "[%g]", paramvals[expr->data.intval] );
8218  }
8219  break;
8220 
8221  case SCIP_EXPR_CONST:
8222  if (expr->data.dbl < 0.0 )
8223  SCIPmessageFPrintInfo(messagehdlr, file, "(%g)", expr->data.dbl );
8224  else
8225  SCIPmessageFPrintInfo(messagehdlr, file, "%g", expr->data.dbl );
8226  break;
8227 
8228  case SCIP_EXPR_PLUS:
8229  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8230  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8231  SCIPmessageFPrintInfo(messagehdlr, file, " + ");
8232  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8233  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8234  break;
8235 
8236  case SCIP_EXPR_MINUS:
8237  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8238  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8239  SCIPmessageFPrintInfo(messagehdlr, file, " - ");
8240  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8241  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8242  break;
8243 
8244  case SCIP_EXPR_MUL:
8245  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8246  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8247  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8248  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8249  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8250  break;
8251 
8252  case SCIP_EXPR_DIV:
8253  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8254  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8255  SCIPmessageFPrintInfo(messagehdlr, file, " / ");
8256  SCIPexprPrint(expr->children[1], messagehdlr, file, varnames, paramnames, paramvals);
8257  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8258  break;
8259 
8260  case SCIP_EXPR_REALPOWER:
8261  case SCIP_EXPR_SIGNPOWER:
8262  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8263  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8264  SCIPmessageFPrintInfo(messagehdlr, file, ", %g)", expr->data.dbl);
8265  break;
8266 
8267  case SCIP_EXPR_INTPOWER:
8268  SCIPmessageFPrintInfo(messagehdlr, file, "power(");
8269  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8270  SCIPmessageFPrintInfo(messagehdlr, file, ", %d)", expr->data.intval);
8271  break;
8272 
8273  case SCIP_EXPR_SQUARE:
8274  case SCIP_EXPR_SQRT:
8275  case SCIP_EXPR_EXP:
8276  case SCIP_EXPR_LOG:
8277  case SCIP_EXPR_SIN:
8278  case SCIP_EXPR_COS:
8279  case SCIP_EXPR_TAN:
8280  /* case SCIP_EXPR_ERF: */
8281  /* case SCIP_EXPR_ERFI: */
8282  case SCIP_EXPR_MIN:
8283  case SCIP_EXPR_MAX:
8284  case SCIP_EXPR_ABS:
8285  case SCIP_EXPR_SIGN:
8286  {
8287  int i;
8288 
8289  SCIPmessageFPrintInfo(messagehdlr, file, "%s(", exprOpTable[expr->op].name);
8290 
8291  for( i = 0; i < expr->nchildren; ++i )
8292  {
8293  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8294  if( i + 1 < expr->nchildren )
8295  {
8296  SCIPmessageFPrintInfo(messagehdlr, file, ", ");
8297  }
8298  }
8299 
8300  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8301  break;
8302  }
8303 
8304  case SCIP_EXPR_SUM:
8305  case SCIP_EXPR_PRODUCT:
8306  {
8307  switch( expr->nchildren )
8308  {
8309  case 0:
8310  SCIPmessageFPrintInfo(messagehdlr, file, expr->op == SCIP_EXPR_SUM ? "0" : "1");
8311  break;
8312  case 1:
8313  SCIPexprPrint(expr->children[0], messagehdlr, file, varnames, paramnames, paramvals);
8314  break;
8315  default:
8316  {
8317  int i;
8318  const char* opstr = expr->op == SCIP_EXPR_SUM ? " + " : " * ";
8319 
8320  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8321  for( i = 0; i < expr->nchildren; ++i )
8322  {
8323  if( i > 0 )
8324  {
8325  SCIPmessageFPrintInfo(messagehdlr, file, opstr);
8326  }
8327  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8328  }
8329  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8330  }
8331  }
8332  break;
8333  }
8334 
8335  case SCIP_EXPR_LINEAR:
8336  {
8337  SCIP_Real constant;
8338  int i;
8339 
8340  constant = ((SCIP_Real*)expr->data.data)[expr->nchildren];
8341 
8342  if( expr->nchildren == 0 )
8343  {
8344  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
8345  break;
8346  }
8347 
8348  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8349 
8350  if( constant != 0.0 )
8351  {
8352  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", constant);
8353  }
8354 
8355  for( i = 0; i < expr->nchildren; ++i )
8356  {
8357  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", ((SCIP_Real*)expr->data.data)[i]);
8358  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8359  }
8360 
8361  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8362  break;
8363  }
8364 
8365  case SCIP_EXPR_QUADRATIC:
8366  {
8367  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
8368  int i;
8369 
8370  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)expr->data.data;
8371  assert(quadraticdata != NULL);
8372 
8373  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8374 
8375  if( quadraticdata->constant != 0.0 )
8376  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->constant);
8377 
8378  if( quadraticdata->lincoefs != NULL )
8379  for( i = 0; i < expr->nchildren; ++i )
8380  {
8381  if( quadraticdata->lincoefs[i] == 0.0 )
8382  continue;
8383  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->lincoefs[i]);
8384  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8385  }
8386 
8387  for( i = 0; i < quadraticdata->nquadelems; ++i )
8388  {
8389  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g ", quadraticdata->quadelems[i].coef);
8390  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx1], messagehdlr, file, varnames, paramnames, paramvals);
8391  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
8392  {
8393  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
8394  }
8395  else
8396  {
8397  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8398  SCIPexprPrint(expr->children[quadraticdata->quadelems[i].idx2], messagehdlr, file, varnames, paramnames, paramvals);
8399  }
8400  }
8401 
8402  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8403  break;
8404  }
8405 
8406  case SCIP_EXPR_POLYNOMIAL:
8407  {
8408  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
8409  SCIP_EXPRDATA_MONOMIAL* monomialdata;
8410  int i;
8411  int j;
8412 
8413  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8414 
8415  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)expr->data.data;
8416  assert(polynomialdata != NULL);
8417 
8418  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
8419  {
8420  SCIPmessageFPrintInfo(messagehdlr, file, "%.20g", polynomialdata->constant);
8421  }
8422 
8423  for( i = 0; i < polynomialdata->nmonomials; ++i )
8424  {
8425  monomialdata = polynomialdata->monomials[i];
8426  SCIPmessageFPrintInfo(messagehdlr, file, " %+.20g", monomialdata->coef);
8427 
8428  for( j = 0; j < monomialdata->nfactors; ++j )
8429  {
8430  SCIPmessageFPrintInfo(messagehdlr, file, " * ");
8431 
8432  SCIPexprPrint(expr->children[monomialdata->childidxs[j]], messagehdlr, file, varnames, paramnames, paramvals);
8433  if( monomialdata->exponents[j] < 0.0 )
8434  {
8435  SCIPmessageFPrintInfo(messagehdlr, file, "^(%.20g)", monomialdata->exponents[j]);
8436  }
8437  else if( monomialdata->exponents[j] != 1.0 )
8438  {
8439  SCIPmessageFPrintInfo(messagehdlr, file, "^%.20g", monomialdata->exponents[j]);
8440  }
8441  }
8442  }
8443 
8444  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8445  break;
8446  }
8447 
8448  case SCIP_EXPR_USER:
8449  {
8450  SCIP_EXPRDATA_USER* exprdata;
8451  int i;
8452 
8453  exprdata = (SCIP_EXPRDATA_USER*)expr->data.data;
8454  assert(exprdata != NULL);
8455 
8456  if( exprdata->print != NULL )
8457  {
8458  exprdata->print(exprdata->userdata, messagehdlr, file);
8459  }
8460  else
8461  {
8462  SCIPmessageFPrintInfo(messagehdlr, file, "user");
8463  }
8464 
8465  SCIPmessageFPrintInfo(messagehdlr, file, "(");
8466  for( i = 0; i < expr->nchildren; ++i )
8467  {
8468  if( i > 0 )
8469  {
8470  SCIPmessageFPrintInfo(messagehdlr, file, ",");
8471  }
8472  SCIPexprPrint(expr->children[i], messagehdlr, file, varnames, paramnames, paramvals);
8473  }
8474  SCIPmessageFPrintInfo(messagehdlr, file, ")");
8475 
8476  break;
8477  }
8478 
8479  case SCIP_EXPR_LAST:
8480  {
8481  SCIPerrorMessage("invalid expression\n");
8482  SCIPABORT();
8483  }
8484  }
8485 }
8486 
8487 /** parses an expression from a string */
8489  BMS_BLKMEM* blkmem, /**< block memory data structure */
8490  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8491  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
8492  const char* str, /**< pointer to the string to be parsed */
8493  const char* lastchar, /**< pointer to the last char of str that should be parsed */
8494  int* nvars, /**< buffer to store number of variables */
8495  int* varnames /**< buffer to store variable names, prefixed by index (as int) */
8496  )
8497 {
8498  SCIP_HASHTABLE* vartable;
8499  SCIP_RETCODE retcode;
8500 
8501  assert(blkmem != NULL);
8502  assert(expr != NULL);
8503  assert(str != NULL);
8504  assert(lastchar != NULL);
8505  assert(nvars != NULL);
8506  assert(varnames != NULL);
8507 
8508  *nvars = 0;
8509 
8510  /* create a hash table for variable names and corresponding expression index
8511  * for each variable, we store its name, prefixed with the assigned index in the first sizeof(int) bytes
8512  */
8513  SCIP_CALL( SCIPhashtableCreate(&vartable, blkmem, 10, exprparseVarTableGetKey, SCIPhashKeyEqString, SCIPhashKeyValString, NULL) );
8514 
8515  retcode = exprParse(blkmem, messagehdlr, expr, str, (int) (lastchar - str + 1), lastchar, nvars, &varnames, vartable, 0);
8516 
8517  SCIPhashtableFree(&vartable);
8518 
8519  return retcode;
8520 }
8521 
8522 
8523 /**@} */
8524 
8525 /**@name Expression tree methods */
8526 /**@{ */
8527 
8528 /* In debug mode, the following methods are implemented as function calls to ensure
8529  * type validity.
8530  * In optimized mode, the methods are implemented as defines to improve performance.
8531  * However, we want to have them in the library anyways, so we have to undef the defines.
8532  */
8533 
8534 #undef SCIPexprtreeGetRoot
8535 #undef SCIPexprtreeGetNVars
8536 #undef SCIPexprtreeGetNParams
8537 #undef SCIPexprtreeGetParamVals
8538 #undef SCIPexprtreeSetParamVal
8539 #undef SCIPexprtreeGetInterpreterData
8540 #undef SCIPexprtreeSetInterpreterData
8541 #undef SCIPexprtreeFreeInterpreterData
8542 #undef SCIPexprtreeHasParam
8543 #undef SCIPexprtreeGetMaxDegree
8544 #undef SCIPexprtreeEval
8545 #undef SCIPexprtreeEvalInt
8546 #undef SCIPexprtreePrint
8547 
8548 /** returns root expression of an expression tree */
8550  SCIP_EXPRTREE* tree /**< expression tree */
8551  )
8552 {
8553  assert(tree != NULL);
8554 
8555  return tree->root;
8556 }
8557 
8558 /** returns number of variables in expression tree */
8560  SCIP_EXPRTREE* tree /**< expression tree */
8561  )
8562 {
8563  assert(tree != NULL);
8564 
8565  return tree->nvars;
8566 }
8567 
8568 /** returns number of parameters in expression tree */
8570  SCIP_EXPRTREE* tree /**< expression tree */
8571  )
8572 {
8573  assert(tree != NULL);
8574 
8575  return tree->nparams;
8576 }
8577 
8578 /** returns values of parameters or NULL if none */
8580  SCIP_EXPRTREE* tree /**< expression tree */
8581  )
8582 {
8583  assert(tree != NULL);
8584 
8585  return tree->params;
8586 }
8587 
8588 /** sets value of a single parameter in expression tree */
8590  SCIP_EXPRTREE* tree, /**< expression tree */
8591  int paramidx, /**< index of parameter */
8592  SCIP_Real paramval /**< new value of parameter */
8593  )
8594 {
8595  assert(tree != NULL);
8596  assert(paramidx >= 0);
8597  assert(paramidx < tree->nparams);
8598  assert(tree->params != NULL);
8599 
8600  tree->params[paramidx] = paramval;
8601 }
8602 
8603 /** gets data of expression tree interpreter, or NULL if not set */
8605  SCIP_EXPRTREE* tree /**< expression tree */
8606  )
8607 {
8608  assert(tree != NULL);
8609 
8610  return tree->interpreterdata;
8611 }
8612 
8613 /** sets data of expression tree interpreter */
8615  SCIP_EXPRTREE* tree, /**< expression tree */
8616  SCIP_EXPRINTDATA* interpreterdata /**< expression interpreter data */
8617  )
8618 {
8619  assert(tree != NULL);
8620  assert(interpreterdata != NULL);
8621  assert(tree->interpreterdata == NULL);
8622 
8623  tree->interpreterdata = interpreterdata;
8624 }
8625 
8626 /** frees data of expression tree interpreter, if any */
8628  SCIP_EXPRTREE* tree /**< expression tree */
8629  )
8630 {
8631  if( tree->interpreterdata != NULL )
8632  {
8634  assert(tree->interpreterdata == NULL);
8635  }
8636 
8637  return SCIP_OKAY;
8638 }
8639 
8640 /** indicates whether there are parameterized constants (SCIP_EXPR_PARAM) in expression tree */
8642  SCIP_EXPRTREE* tree /**< expression tree */
8643  )
8644 {
8645  assert(tree != NULL);
8646 
8647  return SCIPexprHasParam(tree->root);
8648 }
8649 
8650 /** Gives maximal degree of expression in expression tree.
8651  *
8652  * If constant expression, gives 0,
8653  * if linear expression, gives 1,
8654  * if polynomial expression, gives its maximal degree,
8655  * otherwise (nonpolynomial nonconstant expressions) gives at least SCIP_EXPR_DEGREEINFINITY.
8656  */
8658  SCIP_EXPRTREE* tree, /**< expression tree */
8659  int* maxdegree /**< buffer to store maximal degree */
8660  )
8661 {
8662  assert(tree != NULL);
8663 
8664  SCIP_CALL( SCIPexprGetMaxDegree(tree->root, maxdegree) );
8665 
8666  return SCIP_OKAY;
8667 }
8668 
8669 /** evaluates an expression tree w.r.t. a point */
8671  SCIP_EXPRTREE* tree, /**< expression tree */
8672  SCIP_Real* varvals, /**< values for variables */
8673  SCIP_Real* val /**< buffer to store expression tree value */
8674  )
8675 {
8676  assert(tree != NULL);
8677  assert(varvals != NULL || tree->nvars == 0);
8678  assert(val != NULL);
8679 
8680  SCIP_CALL( SCIPexprEval(tree->root, varvals, tree->params, val) );
8681 
8682  return SCIP_OKAY;
8683 }
8684 
8685 /** evaluates an expression tree w.r.t. an interval */
8687  SCIP_EXPRTREE* tree, /**< expression tree */
8688  SCIP_Real infinity, /**< value for infinity */
8689  SCIP_INTERVAL* varvals, /**< intervals for variables */
8690  SCIP_INTERVAL* val /**< buffer to store expression tree value */
8691  )
8692 {
8693  assert(tree != NULL);
8694  assert(varvals != NULL || tree->nvars == 0);
8695  assert(val != NULL);
8696 
8697  SCIP_CALL( SCIPexprEvalInt(tree->root, infinity, varvals, tree->params, val) );
8698 
8699  return SCIP_OKAY;
8700 }
8701 
8702 /** prints an expression tree */
8704  SCIP_EXPRTREE* tree, /**< expression tree */
8705  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8706  FILE* file, /**< file for printing, or NULL for stdout */
8707  const char** varnames, /**< names of variables, or NULL for default names */
8708  const char** paramnames /**< names of parameters, or NULL for default names */
8709  )
8710 {
8711  assert(tree != NULL);
8712 
8713  SCIPexprPrint(tree->root, messagehdlr, file, varnames, paramnames, tree->params);
8714 }
8715 
8716 
8717 /** creates an expression tree */
8719  BMS_BLKMEM* blkmem, /**< block memory data structure */
8720  SCIP_EXPRTREE** tree, /**< buffer to store address of created expression tree */
8721  SCIP_EXPR* root, /**< pointer to root expression, not copied deep !, can be NULL */
8722  int nvars, /**< number of variables in variable mapping */
8723  int nparams, /**< number of parameters in expression */
8724  SCIP_Real* params /**< values for parameters, or NULL (if NULL but nparams > 0, then params is initialized with zeros) */
8725  )
8726 {
8727  assert(blkmem != NULL);
8728  assert(tree != NULL);
8729 
8730  SCIP_ALLOC( BMSallocBlockMemory(blkmem, tree) );
8731 
8732  (*tree)->blkmem = blkmem;
8733  (*tree)->root = root;
8734  (*tree)->nvars = nvars;
8735  (*tree)->vars = NULL;
8736  (*tree)->nparams = nparams;
8737  (*tree)->interpreterdata = NULL;
8738 
8739  if( params != NULL )
8740  {
8741  assert(nparams > 0);
8742  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*tree)->params, params, nparams) );
8743  }
8744  else if( nparams > 0 )
8745  {
8746  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &(*tree)->params, nparams) );
8747  BMSclearMemoryArray((*tree)->params, nparams);
8748  }
8749  else
8750  {
8751  assert(nparams == 0);
8752  (*tree)->params = NULL;
8753  }
8754 
8755  return SCIP_OKAY;
8756 }
8757 
8758 /** copies an expression tree */
8760  BMS_BLKMEM* blkmem, /**< block memory that should be used in new expression tree */
8761  SCIP_EXPRTREE** targettree, /**< buffer to store address of copied expression tree */
8762  SCIP_EXPRTREE* sourcetree /**< expression tree to copy */
8763  )
8764 {
8765  assert(blkmem != NULL);
8766  assert(targettree != NULL);
8767  assert(sourcetree != NULL);
8768 
8769  /* copy expression tree "header" */
8770  SCIP_ALLOC( BMSduplicateBlockMemory(blkmem, targettree, sourcetree) );
8771 
8772  /* we may have a new block memory; and we do not want to keep the others interpreter data */
8773  (*targettree)->blkmem = blkmem;
8774  (*targettree)->interpreterdata = NULL;
8775 
8776  /* copy variables, if any */
8777  if( sourcetree->vars != NULL )
8778  {
8779  assert(sourcetree->nvars > 0);
8780 
8781  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->vars, sourcetree->vars, sourcetree->nvars) );
8782  }
8783 
8784  /* copy parameters, if any */
8785  if( sourcetree->params != NULL )
8786  {
8787  assert(sourcetree->nparams > 0);
8788 
8789  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*targettree)->params, sourcetree->params, sourcetree->nparams) );
8790  }
8791 
8792  /* copy expression */
8793  SCIP_CALL( SCIPexprCopyDeep(blkmem, &(*targettree)->root, sourcetree->root) );
8794 
8795  return SCIP_OKAY;
8796 }
8797 
8798 /** frees an expression tree */
8800  SCIP_EXPRTREE** tree /**< pointer to expression tree that is freed */
8801  )
8802 {
8803  assert( tree != NULL);
8804  assert(*tree != NULL);
8805 
8807 
8808  if( (*tree)->root != NULL )
8809  {
8810  SCIPexprFreeDeep((*tree)->blkmem, &(*tree)->root);
8811  assert((*tree)->root == NULL);
8812  }
8813 
8814  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->vars, (*tree)->nvars );
8815  BMSfreeBlockMemoryArrayNull((*tree)->blkmem, &(*tree)->params, (*tree)->nparams);
8816 
8817  BMSfreeBlockMemory((*tree)->blkmem, tree);
8818 
8819  return SCIP_OKAY;
8820 }
8821 
8822 /** sets number and values of all parameters in expression tree */
8824  SCIP_EXPRTREE* tree, /**< expression tree */
8825  int nparams, /**< number of parameters */
8826  SCIP_Real* paramvals /**< values of parameters, can be NULL if nparams == 0 */
8827  )
8828 {
8829  assert(tree != NULL);
8830  assert(paramvals != NULL || nparams == 0);
8831 
8832  if( nparams == 0 )
8833  {
8834  BMSfreeBlockMemoryArrayNull(tree->blkmem, &tree->params, tree->nparams);
8835  }
8836  else if( tree->params != NULL )
8837  {
8838  SCIP_ALLOC( BMSreallocBlockMemoryArray(tree->blkmem, &tree->params, tree->nparams, nparams) );
8839  BMScopyMemoryArray(tree->params, paramvals, nparams);
8840  }
8841  else
8842  {
8843  SCIP_ALLOC( BMSduplicateBlockMemoryArray(tree->blkmem, &tree->params, paramvals, nparams) );
8844  }
8845 
8846  tree->nparams = nparams;
8847  assert(tree->params != NULL || tree->nparams == 0);
8848 
8849  return SCIP_OKAY;
8850 }
8851 
8852 
8853 /** gives the number of usages for each variable in the expression tree */
8855  SCIP_EXPRTREE* tree, /**< expression tree */
8856  int* varsusage /**< array where to store for each variable how often it is used in the tree */
8857  )
8858 {
8859  assert(tree != NULL);
8860  assert(varsusage != NULL);
8861 
8862  if( tree->nvars == 0 )
8863  return;
8864 
8865  BMSclearMemoryArray(varsusage, tree->nvars);
8866  SCIPexprGetVarsUsage(tree->root, varsusage);
8867 }
8868 
8869 /** aims at simplifying an expression and splitting of a linear expression
8870  *
8871  * If linear variables are split off, expression interpreter data, if stored in the tree, is freed.
8872  */
8874  SCIP_EXPRTREE* tree, /**< expression tree */
8875  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
8876  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
8877  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
8878  int* nlinvars, /**< buffer to store number of linear variables in linear part, or NULL if linear part should not be separated */
8879  int* linidxs, /**< array to store indices of variables in expression tree which belong to linear part, or NULL */
8880  SCIP_Real* lincoefs /**< array to store coefficients of linear part, or NULL */
8881  )
8882 {
8883 #ifndef NDEBUG
8884  SCIP_RANDNUMGEN* randnumgen;
8885  SCIP_Real* testx;
8886  SCIP_Real testval_before;
8887  SCIP_Real testval_after;
8888  int i;
8889 #endif
8890 
8891  assert(tree != NULL);
8892 
8893 #ifndef NDEBUG
8894  SCIP_CALL( SCIPrandomCreate(&randnumgen, tree->blkmem, 42) );
8895 
8896  SCIP_ALLOC( BMSallocMemoryArray(&testx, SCIPexprtreeGetNVars(tree)) ); /*lint !e666*/
8897  for( i = 0; i < SCIPexprtreeGetNVars(tree); ++i )
8898  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
8899  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_before) );
8900 
8901  SCIPrandomFree(&randnumgen);
8902 #endif
8903 
8904  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
8905  SCIP_CALL( SCIPexprSimplify(tree->blkmem, messagehdlr, tree->root, eps*eps, maxexpansionexponent, tree->nvars, nlinvars, linidxs, lincoefs) );
8906 
8907 #ifndef NDEBUG
8908  SCIP_CALL( SCIPexprtreeEval(tree, testx, &testval_after) );
8909  if( nlinvars != NULL && testval_before == testval_before ) /*lint !e777*/
8910  for( i = 0; i < *nlinvars; ++i )
8911  testval_after += lincoefs[i] * testx[linidxs[i]];
8912  assert(testval_before != testval_before || testval_before == testval_after || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
8913  BMSfreeMemoryArray(&testx);
8914 #endif
8915 
8916  /* removing something from the the tree may invalidate the interpreter data */
8917  if( nlinvars != NULL && *nlinvars > 0 )
8919 
8920  return SCIP_OKAY;
8921 }
8922 
8923 /** adds an expression to the root expression of the tree
8924  *
8925  * 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.
8926  */
8928  SCIP_EXPRTREE* tree, /**< expression tree */
8929  SCIP_EXPR* expr, /**< expression to add to tree */
8930  SCIP_Bool copyexpr /**< whether expression should be copied */
8931  )
8932 {
8933  assert(tree != NULL);
8934  assert(tree->root != NULL);
8935 
8936  /* adding something to the tree may invalidate the interpreter data */
8938 
8939  if( copyexpr )
8940  {
8941  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &expr, expr) );
8942  }
8943 
8944  SCIP_CALL( SCIPexprCreate(tree->blkmem, &tree->root, SCIP_EXPR_PLUS, tree->root, expr) );
8945 
8946  return SCIP_OKAY;
8947 }
8948 
8949 /** tries to determine the curvature type of an expression tree w.r.t. given variable domains */
8951  SCIP_EXPRTREE* tree, /**< expression tree */
8952  SCIP_Real infinity, /**< value for infinity */
8953  SCIP_INTERVAL* varbounds, /**< domains of variables */
8954  SCIP_EXPRCURV* curv, /**< buffer to store curvature of expression */
8955  SCIP_INTERVAL* bounds /**< buffer to store bounds on expression, or NULL if not needed */
8956  )
8957 {
8958  SCIP_INTERVAL exprbounds;
8959 
8960  assert(tree != NULL);
8961  assert(tree->root != NULL);
8962 
8963  SCIP_CALL( SCIPexprCheckCurvature(tree->root, infinity, varbounds, tree->params, curv, &exprbounds) );
8964 
8965  if( bounds != NULL )
8966  *bounds = exprbounds;
8967 
8968  return SCIP_OKAY;
8969 }
8970 
8971 /** substitutes variables (SCIP_EXPR_VARIDX) in an expression tree by expressions
8972  *
8973  * A variable with index i is replaced by a copy of substexprs[i], if that latter is not NULL.
8974  * If substexprs[i] == NULL, then the variable expression i is not touched.
8975  */
8977  SCIP_EXPRTREE* tree, /**< expression tree */
8978  SCIP_EXPR** substexprs /**< array of substitute expressions; single entries can be NULL */
8979  )
8980 {
8981  assert(tree != NULL);
8982  assert(tree->root != NULL);
8983 
8984  if( tree->root->op == SCIP_EXPR_VARIDX )
8985  {
8986  int varidx;
8987 
8988  varidx = tree->root->data.intval;
8989  assert(varidx >= 0);
8990  if( substexprs[varidx] != NULL )
8991  {
8992  /* substitute root expression */
8993  SCIPexprFreeDeep(tree->blkmem, &tree->root);
8994  SCIP_CALL( SCIPexprCopyDeep(tree->blkmem, &tree->root, substexprs[varidx]) );
8995  }
8996  }
8997  else
8998  {
8999  /* check children (and grandchildren and so on...) of root expression */
9000  SCIP_CALL( SCIPexprSubstituteVars(tree->blkmem, tree->root, substexprs) );
9001  }
9002 
9003  /* substitution of variables should invalidate interpreter data */
9005 
9006  return SCIP_OKAY;
9007 }
9008 
9009 /**@} */
9010 
9011 /**@name Quadratic element methods */
9012 /**@{ */
9013 
9014 /** comparing two quadratic elements
9015  *
9016  * 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
9017  */
9018 #define QUADELEMS_ISBETTER(a, b) ( ((a).idx1 < (b).idx1) || ((a).idx1 == (b).idx1 && (a).idx2 < (b).idx2) )
9019 
9020 /** swaps two quadratic elements */
9021 #define QUADELEMS_SWAP(x,y) \
9022  { \
9023  SCIP_QUADELEM temp = x; \
9024  x = y; \
9025  y = temp; \
9026  }
9027 
9028 /** quicksort an array of quadratic elements; pivot is the medial element (taken from scip/sorttpl.c) */
9029 static
9031  SCIP_QUADELEM* elems, /**< array to be sorted */
9032  int start, /**< starting index */
9033  int end /**< ending index */
9034  )
9035 {
9036  assert(start <= end);
9037 
9038  /* use quick sort for long lists */
9039  while( end - start >= 25 ) /* 25 was SORTTPL_SHELLSORTMAX in sorttpl.c */
9040  {
9041  SCIP_QUADELEM pivotkey;
9042  int lo;
9043  int hi;
9044  int mid;
9045 
9046  /* select pivot element */
9047  mid = (start+end)/2;
9048  pivotkey = elems[mid];
9049 
9050  /* partition the array into elements < pivot [start,hi] and elements >= pivot [lo,end] */
9051  lo = start;
9052  hi = end;
9053  for( ;; )
9054  {
9055  while( lo < end && QUADELEMS_ISBETTER(elems[lo], pivotkey) )
9056  lo++;
9057  while( hi > start && !QUADELEMS_ISBETTER(elems[hi], pivotkey) )
9058  hi--;
9059 
9060  if( lo >= hi )
9061  break;
9062 
9063  QUADELEMS_SWAP(elems[lo], elems[hi]);
9064 
9065  lo++;
9066  hi--;
9067  }
9068  assert(hi == lo-1 || hi == start);
9069 
9070  /* skip entries which are equal to the pivot element (three partitions, <, =, > than pivot)*/
9071  while( lo < end && !QUADELEMS_ISBETTER(pivotkey, elems[lo]) )
9072  lo++;
9073 
9074  /* make sure that we have at least one element in the smaller partition */
9075  if( lo == start )
9076  {
9077  /* everything is greater or equal than the pivot element: move pivot to the left (degenerate case) */
9078  assert(!QUADELEMS_ISBETTER(elems[mid], pivotkey)); /* the pivot element did not change its position */
9079  assert(!QUADELEMS_ISBETTER(pivotkey, elems[mid]));
9080  QUADELEMS_SWAP(elems[lo], elems[mid]);
9081  lo++;
9082  }
9083 
9084  /* sort the smaller partition by a recursive call, sort the larger part without recursion */
9085  if( hi - start <= end - lo )
9086  {
9087  /* sort [start,hi] with a recursive call */
9088  if( start < hi )
9089  quadelemsQuickSort(elems, start, hi);
9090 
9091  /* now focus on the larger part [lo,end] */
9092  start = lo;
9093  }
9094  else
9095  {
9096  /* sort [lo,end] with a recursive call */
9097  if( lo < end )
9098  quadelemsQuickSort(elems, lo, end);
9099 
9100  /* now focus on the larger part [start,hi] */
9101  end = hi;
9102  }
9103  }
9104 
9105  /* use shell sort on the remaining small list */
9106  if( end - start >= 1 )
9107  {
9108  static const int incs[3] = {1, 5, 19}; /* sequence of increments */
9109  int k;
9110 
9111  for( k = 2; k >= 0; --k )
9112  {
9113  int h;
9114  int i;
9115 
9116  for( h = incs[k], i = h + start; i <= end; ++i )
9117  {
9118  int j;
9119  SCIP_QUADELEM tempkey = elems[i];
9120 
9121  j = i;
9122  while( j >= h && QUADELEMS_ISBETTER(tempkey, elems[j-h]) )
9123  {
9124  elems[j] = elems[j-h];
9125  j -= h;
9126  }
9127 
9128  elems[j] = tempkey;
9129  }
9130  }
9131  }
9132 }
9133 
9134 /** sorts an array of quadratic elements
9135  *
9136  * The elements are sorted such that the first index is increasing and
9137  * such that among elements with the same first index, the second index is increasing.
9138  * For elements with same first and second index, the order is not defined.
9139  */
9141  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9142  int nquadelems /**< number of quadratic elements */
9143  )
9144 {
9145  if( nquadelems == 0 )
9146  return;
9147 
9148 #ifndef NDEBUG
9149  {
9150  int i;
9151  for( i = 0; i < nquadelems; ++i )
9152  assert(quadelems[i].idx1 <= quadelems[i].idx2);
9153  }
9154 #endif
9155 
9156  quadelemsQuickSort(quadelems, 0, nquadelems-1);
9157 }
9158 
9159 /** Finds an index pair in a sorted array of quadratic elements.
9160  *
9161  * If (idx1,idx2) is found in quadelems, then returns TRUE and stores position of quadratic element in *pos.
9162  * 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.
9163  * Assumes that idx1 <= idx2.
9164  */
9166  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9167  int idx1, /**< index of first variable in element to search for */
9168  int idx2, /**< index of second variable in element to search for */
9169  int nquadelems, /**< number of quadratic elements in array */
9170  int* pos /**< buffer to store position of found quadratic element or position where it would be inserted, or NULL */
9171  )
9172 {
9173  int left;
9174  int right;
9175 
9176  assert(quadelems != NULL || nquadelems == 0);
9177  assert(idx1 <= idx2);
9178 
9179  if( nquadelems == 0 )
9180  {
9181  if( pos != NULL )
9182  *pos = 0;
9183  return FALSE;
9184  }
9185 
9186  left = 0;
9187  right = nquadelems - 1;
9188  while( left <= right )
9189  {
9190  int middle;
9191 
9192  middle = (left+right)/2;
9193  assert(0 <= middle && middle < nquadelems);
9194 
9195  if( idx1 < quadelems[middle].idx1 || (idx1 == quadelems[middle].idx1 && idx2 < quadelems[middle].idx2) ) /*lint !e613*/
9196  right = middle - 1;
9197  else if( quadelems[middle].idx1 < idx1 || (quadelems[middle].idx1 == idx1 && quadelems[middle].idx2 < idx2) ) /*lint !e613*/
9198  left = middle + 1;
9199  else
9200  {
9201  if( pos != NULL )
9202  *pos = middle;
9203  return TRUE;
9204  }
9205  }
9206  assert(left == right+1);
9207 
9208  if( pos != NULL )
9209  *pos = left;
9210  return FALSE;
9211 }
9212 
9213 /** Adds quadratic elements with same index and removes elements with coefficient 0.0.
9214  *
9215  * Assumes that elements have been sorted before.
9216  */
9218  SCIP_QUADELEM* quadelems, /**< array of quadratic elements */
9219  int nquadelems, /**< number of quadratic elements */
9220  int* nquadelemsnew /**< pointer to store new (reduced) number of quadratic elements */
9221  )
9222 {
9223  int i;
9224  int next;
9225 
9226  assert(quadelems != NULL);
9227  assert(nquadelemsnew != NULL);
9228  assert(nquadelems >= 0);
9229 
9230  i = 0;
9231  next = 0;
9232  while( next < nquadelems )
9233  {
9234  /* assert that array is sorted */
9235  assert(QUADELEMS_ISBETTER(quadelems[i], quadelems[next]) ||
9236  (quadelems[i].idx1 == quadelems[next].idx1 && quadelems[i].idx2 == quadelems[next].idx2));
9237 
9238  /* skip elements with coefficient 0.0 */
9239  if( quadelems[next].coef == 0.0 )
9240  {
9241  ++next;
9242  continue;
9243  }
9244 
9245  /* if next element has same index as previous one, add it to the previous one */
9246  if( i >= 1 &&
9247  quadelems[i-1].idx1 == quadelems[next].idx1 &&
9248  quadelems[i-1].idx2 == quadelems[next].idx2 )
9249  {
9250  quadelems[i-1].coef += quadelems[next].coef;
9251  ++next;
9252  continue;
9253  }
9254 
9255  /* otherwise, move next element to current position */
9256  quadelems[i] = quadelems[next];
9257  ++i;
9258  ++next;
9259  }
9260  assert(next == nquadelems);
9261 
9262  /* now i should point to the position after the last valid element, i.e., it is the remaining number of elements */
9263  *nquadelemsnew = i;
9264 }
9265 
9266 /**@} */
9267 
9268 /**@name Expression graph node private methods */
9269 /**@{ */
9270 
9271 /** adds a parent to an expression graph node */
9272 static
9274  BMS_BLKMEM* blkmem, /**< block memory */
9275  SCIP_EXPRGRAPHNODE* node, /**< expression graph node where to add a parent */
9276  SCIP_EXPRGRAPHNODE* parent /**< parent node */
9277  )
9278 {
9279  assert(blkmem != NULL);
9280  assert(node != NULL);
9281  assert(node->depth >= 0);
9282  assert(node->pos >= 0);
9283  assert(parent != NULL);
9284  assert(parent->depth >= 0);
9285  assert(parent->pos >= 0);
9286  assert(parent->depth > node->depth); /* a parent node need to have larger depth */
9287 
9288  ensureBlockMemoryArraySize(blkmem, &node->parents, &node->parentssize, node->nparents + 1);
9289  assert(node->nparents < node->parentssize);
9290 
9291  node->parents[node->nparents] = parent;
9292  ++node->nparents;
9293 
9294  /* update sorted flag */
9295  node->parentssorted = (node->nparents <= 1) || (node->parentssorted && (exprgraphnodecomp((void*)node->parents[node->nparents-2], (void*)parent) <= 0));
9296 
9297  return SCIP_OKAY;
9298 }
9299 
9300 /** ensures that array of parents in a node is sorted */
9301 static
9303  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
9304  )
9305 {
9306  assert(node != NULL);
9307 
9308  if( node->parentssorted )
9309  {
9310 #ifndef NDEBUG
9311  int i;
9312  for( i = 1; i < node->nparents; ++i )
9313  assert(exprgraphnodecomp((void*)node->parents[i-1], (void*)node->parents[i]) <= 0);
9314 #endif
9315  return;
9316  }
9317 
9318  SCIPsortPtr((void**)node->parents, exprgraphnodecomp, node->nparents);
9319 
9320  node->parentssorted = TRUE;
9321 }
9322 
9323 /** removes a parent from an expression graph node
9324  *
9325  * If the node is not used and has no other parents, then it is freed.
9326  */
9327 static
9329  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9330  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to remove a parent, *node will be set to NULL */
9331  SCIP_EXPRGRAPHNODE* parent /**< parent node to remove */
9332  )
9333 {
9334  SCIP_EXPRGRAPHNODE* node_;
9335  int pos;
9336 
9337  assert(exprgraph != NULL);
9338  assert(node != NULL);
9339  assert(*node != NULL);
9340  assert((*node)->depth >= 0);
9341  assert((*node)->pos >= 0);
9342  assert((*node)->nparents > 0);
9343  assert(parent != NULL);
9344  assert(parent->depth >= 0);
9345  assert(parent->pos >= 0);
9346  assert(parent->depth > (*node)->depth); /* a parent node need to have larger depth */
9347 
9348  /* find parent */
9349  exprgraphNodeSortParents(*node);
9350  (void) SCIPsortedvecFindPtr((void**)(*node)->parents, exprgraphnodecomp, (void*)parent, (*node)->nparents, &pos);
9351  assert(pos >= 0);
9352  assert(pos < (*node)->nparents);
9353  assert((*node)->parents[pos] == parent);
9354 
9355  /* move last parent to pos, if pos is before last
9356  * update sorted flag */
9357  if( pos < (*node)->nparents-1 )
9358  {
9359  (*node)->parents[pos] = (*node)->parents[(*node)->nparents-1];
9360  (*node)->parentssorted = ((*node)->nparents <= 2);
9361  }
9362  --(*node)->nparents;
9363 
9364  /* keep pointer to *node in case it is still used */
9365  node_ = (*node)->nuses > 0 ? *node : NULL;
9366 
9367  /* capture and release node so it is freed if possible */
9368  SCIPexprgraphCaptureNode(*node);
9369  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
9370 
9371  /* restore pointer, if node still exists */
9372  *node = node_;
9373 
9374  return SCIP_OKAY;
9375 }
9376 
9377 /** checks if a node is parent of a node */
9378 static
9380  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9381  SCIP_EXPRGRAPHNODE* parent /**< parent to look for */
9382  )
9383 {
9384  int pos;
9385 
9386  assert(node != NULL);
9387  assert(parent != NULL);
9388 
9389  /* if depth of node is at least as high as depth of parent, parent cannot be parent of node */
9390  if( node->depth >= parent->depth || node->nparents == 0 )
9391  return FALSE;
9392  assert(node->parents != NULL);
9393 
9394  /* ensure parents array is sorted */
9396 
9397  return SCIPsortedvecFindPtr((void**)node->parents, exprgraphnodecomp, (void*)parent, node->nparents, &pos);
9398 }
9399 
9400 /** adds expression graph nodes to the array of children of a sum, product, linear, quadratic, or polynomial expression
9401  *
9402  * For a sum or product expression, this corresponds to add additional summands and factors, resp.
9403  * For a linear expression, this corresponds to add each expression with coefficient 1.0.
9404  * For a quadratic or polynomial expression, only the children array may be enlarged, the expression itself remains the same.
9405  *
9406  * It is assumed that node and all exprs are in the expression graph already.
9407  * It is assumed that all expressions that are added have lower depth than node.
9408  */
9409 static
9411  BMS_BLKMEM* blkmem, /**< block memory */
9412  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9413  int nexprs, /**< number of children to add */
9414  SCIP_EXPRGRAPHNODE** exprs, /**< children nodes to add */
9415  int* childmap /**< array where to store mapping of indices from exprs to children array in node, or NULL if not of interest */
9416  )
9417 {
9418  int i;
9419  int j;
9420  int orignchildren;
9421  SCIP_Bool existsalready;
9422 
9423  assert(blkmem != NULL);
9424  assert(node != NULL);
9425  assert(node->depth > 0);
9426  assert(node->pos >= 0);
9427  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);
9428  assert(exprs != NULL || nexprs == 0);
9429 
9430  if( nexprs == 0 )
9431  return SCIP_OKAY;
9432 
9433  orignchildren = node->nchildren;
9434  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, node->nchildren + nexprs) );
9435 
9436  for( i = 0; i < nexprs; ++i )
9437  {
9438  assert(exprs[i]->depth >= 0); /*lint !e613*/
9439  assert(exprs[i]->pos >= 0); /*lint !e613*/
9440  assert(exprs[i]->depth < node->depth); /*lint !e613*/
9441 
9442  /* check if exprs[i] is a child already, if not SUM or PRODUCT */
9443  existsalready = FALSE;
9444  if( node->op != SCIP_EXPR_SUM && node->op != SCIP_EXPR_PRODUCT )
9445  for( j = 0; j < orignchildren; ++j )
9446  /* during simplification of polynomials, their may be NULL's in children array */
9447  if( node->children[j] != NULL && node->children[j] == exprs[i] ) /*lint !e613*/
9448  {
9449  existsalready = TRUE;
9450  break;
9451  }
9452 
9453  if( !existsalready )
9454  {
9455  /* add exprs[i] to children array */
9456  node->children[node->nchildren] = exprs[i]; /*lint !e613*/
9457  SCIP_CALL( exprgraphNodeAddParent(blkmem, exprs[i], node) ); /*lint !e613*/
9458  if( childmap != NULL )
9459  childmap[i] = node->nchildren;
9460  ++node->nchildren;
9461  }
9462  else
9463  {
9464  if( childmap != NULL )
9465  childmap[i] = j; /*lint !e644*/
9466  if( node->op == SCIP_EXPR_LINEAR )
9467  {
9468  /* if linear expression, increase coefficient by 1.0 */
9469  ((SCIP_Real*)node->data.data)[j] += 1.0;
9470  }
9471  }
9472  }
9473 
9474  /* shrink children array to actually used size */
9475  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, orignchildren + nexprs, node->nchildren) );
9476 
9477  if( node->op == SCIP_EXPR_LINEAR && node->nchildren > orignchildren )
9478  {
9479  /* if linear expression, then add 1.0 coefficients for new expressions */
9480  SCIP_Real* data;
9481 
9482  data = (SCIP_Real*)node->data.data;
9483  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data, orignchildren + 1, node->nchildren + 1) );
9484  data[node->nchildren] = data[orignchildren]; /* move constant from old end to new end */
9485  for( i = orignchildren; i < node->nchildren; ++i )
9486  data[i] = 1.0;
9487  node->data.data = (void*)data;
9488  }
9489  else if( node->op == SCIP_EXPR_QUADRATIC && node->nchildren > orignchildren )
9490  {
9491  /* if quadratic expression, then add 0.0 linear coefficients for new expressions */
9493 
9494  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9495  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &data->lincoefs, orignchildren, node->nchildren) );
9496  BMSclearMemoryArray(&data->lincoefs[orignchildren], node->nchildren - orignchildren); /*lint !e866*/
9497  }
9498 
9499  node->simplified = FALSE;
9500 
9501  return SCIP_OKAY;
9502 }
9503 
9504 /** replaces a child node by another node
9505  *
9506  * Assumes that both nodes represent the same expression.
9507  * If this node was the last parent of oldchild and oldchild is not in use, then it is freed.
9508  * newchild must have deeper depth than node.
9509  */
9510 static
9512  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9513  SCIP_EXPRGRAPHNODE* node, /**< pointer to expression graph node */
9514  SCIP_EXPRGRAPHNODE** oldchild, /**< child node that should be replaced, it may be freed */
9515  SCIP_EXPRGRAPHNODE* newchild /**< node that should take position of oldchild */
9516  )
9517 {
9518  int i;
9519 
9520  assert(exprgraph != NULL);
9521  assert(node != NULL);
9522  assert(oldchild != NULL);
9523  assert(*oldchild != NULL);
9524  assert(newchild != NULL);
9525 
9526  if( *oldchild == newchild )
9527  return SCIP_OKAY;
9528 
9529  SCIPdebugMessage("replace child %p in node %p by %p\n", (void*)*oldchild, (void*)node, (void*)newchild);
9530 
9531  /* search for oldchild in children array */
9532  for( i = 0; i < node->nchildren; ++i )
9533  {
9534  if( node->children[i] == *oldchild )
9535  {
9536  /* add as parent to newchild */
9537  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, newchild, node) );
9538 
9539  /* remove as parent from oldchild */
9540  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, oldchild, node) );
9541 
9542  /* set newchild as child i */
9543  node->children[i] = newchild;
9544 
9545  /* we're done */
9546  break;
9547  }
9548  }
9549  assert(i < node->nchildren); /* assert that oldchild has been found in children array */
9550 
9551  node->simplified = FALSE;
9552 
9553  return SCIP_OKAY;
9554 }
9555 
9556 /** comparison of SCIP_EXPRGRAPHNODE's that are of type SCIP_EXPR_CONST
9557  *
9558  * A node is larger than another node, if their corresponding constants are related that way.
9559  */
9560 static
9561 SCIP_DECL_SORTPTRCOMP(exprgraphConstNodeComp)
9562 {
9563  assert(elem1 != NULL);
9564  assert(elem2 != NULL);
9565  assert(((SCIP_EXPRGRAPHNODE*)elem1)->op == SCIP_EXPR_CONST);
9566  assert(((SCIP_EXPRGRAPHNODE*)elem2)->op == SCIP_EXPR_CONST);
9567  assert(((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9568  assert(((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl == ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl); /* assert that const value is not nan */ /*lint !e777*/
9569 
9570  if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl > ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9571  return 1;
9572  else if( ((SCIP_EXPRGRAPHNODE*)elem1)->data.dbl < ((SCIP_EXPRGRAPHNODE*)elem2)->data.dbl )
9573  return -1;
9574  else
9575  return 0;
9576 }
9577 
9578 /** sort array of nodes that holds constants */
9579 static
9581  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
9582  )
9583 {
9584  assert(exprgraph != NULL);
9585 
9586  if( exprgraph->constssorted )
9587  return;
9588 
9589  SCIPsortPtr((void**)exprgraph->constnodes, exprgraphConstNodeComp, exprgraph->nconsts);
9590 
9591  exprgraph->constssorted = TRUE;
9592 }
9593 
9594 /** finds position of expression graph node corresponding to a constant in constnodes array */
9595 static
9597  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9598  SCIP_EXPRGRAPHNODE* node, /**< node to search for */
9599  int* pos /**< buffer to store position of node, if found */
9600  )
9601 {
9602  int left;
9603  int right;
9604  int middle;
9605 
9606  assert(exprgraph != NULL);
9607  assert(node != NULL);
9608  assert(node->op == SCIP_EXPR_CONST);
9609  assert(node->depth == 0);
9610  assert(node->pos >= 0);
9611  assert(pos != NULL);
9612 
9613  exprgraphSortConstNodes(exprgraph);
9614  assert(exprgraph->constssorted);
9615 
9616  /* find a node with constant node->data.dbl using binary search */
9617  left = 0;
9618  right = exprgraph->nconsts-1;
9619  *pos = -1;
9620  while( left <= right )
9621  {
9622  middle = (left+right)/2;
9623  assert(0 <= middle && middle < exprgraph->nconsts);
9624 
9625  if( node->data.dbl < exprgraph->constnodes[middle]->data.dbl )
9626  right = middle - 1;
9627  else if( node->data.dbl > exprgraph->constnodes[middle]->data.dbl )
9628  left = middle + 1;
9629  else
9630  {
9631  *pos = middle;
9632  break;
9633  }
9634  }
9635  assert(left == right+1 || *pos >= 0);
9636  if( left == right+1 )
9637  return FALSE;
9638 
9639  /* search left of *pos to find node */
9640  while( exprgraph->constnodes[*pos] != node && *pos > 0 && exprgraph->constnodes[*pos-1]->data.dbl == node->data.dbl ) /*lint !e777*/
9641  --*pos;
9642  /* search right of *pos to find node */
9643  while( exprgraph->constnodes[*pos] != node && *pos < exprgraph->nconsts-1 && exprgraph->constnodes[*pos+1]->data.dbl == node->data.dbl ) /*lint !e777*/
9644  ++*pos;
9645 
9646  return exprgraph->constnodes[*pos] == node;
9647 }
9648 
9649 /** creates an expression graph node */
9650 static
9652  BMS_BLKMEM* blkmem, /**< block memory */
9653  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
9654  SCIP_EXPROP op, /**< operator type of expression */
9655  SCIP_EXPROPDATA opdata /**< operator data of expression */
9656  )
9657 {
9658  assert(blkmem != NULL);
9659  assert(node != NULL);
9660 
9661  SCIP_ALLOC( BMSallocBlockMemory(blkmem, node) );
9662  BMSclearMemory(*node);
9663 
9664  (*node)->op = op;
9665  (*node)->data = opdata;
9666 
9667  /* mark graph position as not in graph yet */
9668  (*node)->depth = -1;
9669  (*node)->pos = -1;
9670 
9671  /* arrays of length 0 are trivially sorted */
9672  (*node)->parentssorted = TRUE;
9673 
9674  /* set bounds interval to entire */
9675  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
9676  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
9677 
9678  /* set initial value to invalid */
9679  (*node)->value = SCIP_INVALID;
9680 
9681  /* set initial curvature to linear for variables, parameters, and constants and unknown otherwise */
9682  if( op == SCIP_EXPR_VARIDX || op == SCIP_EXPR_CONST || op == SCIP_EXPR_PARAM )
9683  (*node)->curv = SCIP_EXPRCURV_LINEAR;
9684  else
9685  (*node)->curv = SCIP_EXPRCURV_UNKNOWN;
9686 
9687  /* per default, a node is enabled */
9688  (*node)->enabled = TRUE;
9689 
9690  return SCIP_OKAY;
9691 }
9692 
9693 /** prints the expression corresponding to a node (not recursively) */
9694 static
9696  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9697  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9698  FILE* file, /**< file to print to, or NULL for stdout */
9699  const char** varnames, /**< variable names, or NULL for generic names */
9700  SCIP_Bool printchildrenbounds /**< whether to print bounds of children */
9701  )
9702 {
9703  int i;
9704 
9705  assert(node != NULL);
9706 
9707  switch( node->op )
9708  {
9709  case SCIP_EXPR_VARIDX:
9710  if( varnames != NULL )
9711  {
9712  SCIPmessageFPrintInfo(messagehdlr, file, "<%s>", (const char*)varnames[node->data.intval]);
9713  }
9714  else
9715  SCIPmessageFPrintInfo(messagehdlr, file, "x%d", node->data.intval);
9716  break;
9717 
9718  case SCIP_EXPR_CONST:
9719  SCIPmessageFPrintInfo(messagehdlr, file, "%g", node->data.dbl);
9720  break;
9721 
9722  case SCIP_EXPR_PARAM:
9723  SCIPmessageFPrintInfo(messagehdlr, file, "param%d", node->data.intval);
9724  break;
9725 
9726  case SCIP_EXPR_PLUS:
9727  if( printchildrenbounds )
9728  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9729  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9730  if( printchildrenbounds )
9731  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9732  break;
9733 
9734  case SCIP_EXPR_MINUS:
9735  if( printchildrenbounds )
9736  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9737  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9738  if( printchildrenbounds )
9739  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9740  break;
9741 
9742  case SCIP_EXPR_MUL:
9743  if( printchildrenbounds )
9744  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9745  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9746  if( printchildrenbounds )
9747  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9748  break;
9749 
9750  case SCIP_EXPR_DIV:
9751  if( printchildrenbounds )
9752  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9753  SCIPmessageFPrintInfo(messagehdlr, file, "/");
9754  if( printchildrenbounds )
9755  SCIPmessageFPrintInfo(messagehdlr, file, "c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9756  break;
9757 
9758  case SCIP_EXPR_SQUARE:
9759  if( printchildrenbounds )
9760  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9761  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9762  break;
9763 
9764  case SCIP_EXPR_REALPOWER:
9765  if( printchildrenbounds )
9766  SCIPmessageFPrintInfo(messagehdlr, file, "c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9767  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", node->data.dbl);
9768  break;
9769 
9770  case SCIP_EXPR_SIGNPOWER:
9771  if( printchildrenbounds )
9772  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0[%10g,%10g]|^%g",
9773  node->children[0]->bounds.inf, node->children[0]->bounds.sup, node->data.dbl);
9774  else
9775  SCIPmessageFPrintInfo(messagehdlr, file, "sign(c0)|c0|^%g", node->data.dbl);
9776  break;
9777 
9778  case SCIP_EXPR_INTPOWER:
9779  SCIPmessageFPrintInfo(messagehdlr, file, "c0");
9780  if( printchildrenbounds )
9781  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9782  SCIPmessageFPrintInfo(messagehdlr, file, "^%d", node->data.intval);
9783  break;
9784 
9785  case SCIP_EXPR_SQRT:
9786  case SCIP_EXPR_EXP:
9787  case SCIP_EXPR_LOG:
9788  case SCIP_EXPR_SIN:
9789  case SCIP_EXPR_COS:
9790  case SCIP_EXPR_TAN:
9791  /* SCIP_EXPR_ERF = 20, */ /**< gaussian error function (1 operand) */
9792  /* SCIP_EXPR_ERFI = 21, */ /**< imaginary part of gaussian error function (1 operand) */
9793  case SCIP_EXPR_MIN:
9794  case SCIP_EXPR_MAX:
9795  case SCIP_EXPR_ABS:
9796  case SCIP_EXPR_SIGN:
9797  SCIPmessageFPrintInfo(messagehdlr, file, "%s", (const char*)SCIPexpropGetName(node->op));
9798  if( printchildrenbounds )
9799  {
9800  SCIPmessageFPrintInfo(messagehdlr, file, "(c0[%10g,%10g]", node->children[0]->bounds.inf, node->children[0]->bounds.sup);
9801  if( node->nchildren == 2 )
9802  SCIPmessageFPrintInfo(messagehdlr, file, ",c1[%10g,%10g]", node->children[1]->bounds.inf, node->children[1]->bounds.sup);
9803  SCIPmessageFPrintInfo(messagehdlr, file, ")");
9804  }
9805  break;
9806 
9807  case SCIP_EXPR_SUM:
9808  if( printchildrenbounds )
9809  for( i = 0; i < node->nchildren; ++i )
9810  {
9811  if( i > 0 )
9812  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9813  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9814  }
9815  else
9816  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9817  break;
9818 
9819  case SCIP_EXPR_PRODUCT:
9820  if( printchildrenbounds )
9821  for( i = 0; i < node->nchildren; ++i )
9822  {
9823  if( i > 0 )
9824  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9825  SCIPmessageFPrintInfo(messagehdlr, file, "c%d[%10g,%10g]", i, node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9826  }
9827  else
9828  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9829  break;
9830 
9831  case SCIP_EXPR_LINEAR:
9832  {
9833  SCIP_Real constant;
9834 
9835  constant = ((SCIP_Real*)node->data.data)[node->nchildren];
9836 
9837  if( constant != 0.0 || node->nchildren == 0 )
9838  SCIPmessageFPrintInfo(messagehdlr, file, "%g", constant);
9839 
9840  for( i = 0; i < node->nchildren; ++i )
9841  {
9842  if( ((SCIP_Real*)node->data.data)[i] == 1.0 )
9843  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9844  else if( ((SCIP_Real*)node->data.data)[i] == -1.0 )
9845  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9846  else
9847  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", ((SCIP_Real*)node->data.data)[i]);
9848  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", i);
9849  if( printchildrenbounds )
9850  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9851  }
9852 
9853  break;
9854  }
9855 
9856  case SCIP_EXPR_QUADRATIC:
9857  {
9858  SCIP_EXPRDATA_QUADRATIC* quadraticdata;
9859 
9860  quadraticdata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
9861  assert(quadraticdata != NULL);
9862 
9863  if( quadraticdata->constant != 0.0 )
9864  SCIPmessageFPrintInfo(messagehdlr, file, "%g", quadraticdata->constant);
9865 
9866  if( quadraticdata->lincoefs != NULL )
9867  for( i = 0; i < node->nchildren; ++i )
9868  {
9869  if( quadraticdata->lincoefs[i] == 0.0 )
9870  continue;
9871  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*c%d", quadraticdata->lincoefs[i], i);
9872  if( printchildrenbounds )
9873  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[i]->bounds.inf, node->children[i]->bounds.sup);
9874  }
9875 
9876  for( i = 0; i < quadraticdata->nquadelems; ++i )
9877  {
9878  if( quadraticdata->quadelems[i].coef == 1.0 )
9879  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9880  else if( quadraticdata->quadelems[i].coef == -1.0 )
9881  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9882  else
9883  SCIPmessageFPrintInfo(messagehdlr, file, "%+g*", quadraticdata->quadelems[i].coef);
9884  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", quadraticdata->quadelems[i].idx1);
9885  if( printchildrenbounds )
9886  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx1]->bounds.inf, node->children[quadraticdata->quadelems[i].idx1]->bounds.sup);
9887  if( quadraticdata->quadelems[i].idx1 == quadraticdata->quadelems[i].idx2 )
9888  SCIPmessageFPrintInfo(messagehdlr, file, "^2");
9889  else
9890  {
9891  SCIPmessageFPrintInfo(messagehdlr, file, "*c%d", quadraticdata->quadelems[i].idx2);
9892  if( printchildrenbounds )
9893  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[quadraticdata->quadelems[i].idx2]->bounds.inf, node->children[quadraticdata->quadelems[i].idx2]->bounds.sup);
9894  }
9895  }
9896 
9897  break;
9898  }
9899 
9900  case SCIP_EXPR_POLYNOMIAL:
9901  {
9902  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
9903  SCIP_EXPRDATA_MONOMIAL* monomialdata;
9904  int j;
9905 
9906  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
9907  assert(polynomialdata != NULL);
9908 
9909  if( polynomialdata->constant != 0.0 || polynomialdata->nmonomials == 0 )
9910  {
9911  SCIPmessageFPrintInfo(messagehdlr, file, "%g", polynomialdata->constant);
9912  }
9913 
9914  for( i = 0; i < polynomialdata->nmonomials; ++i )
9915  {
9916  monomialdata = polynomialdata->monomials[i];
9917  if( monomialdata->coef == 1.0 )
9918  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9919  else if( monomialdata->coef == -1.0 )
9920  SCIPmessageFPrintInfo(messagehdlr, file, "-");
9921  else
9922  SCIPmessageFPrintInfo(messagehdlr, file, "%+g", monomialdata->coef);
9923 
9924  for( j = 0; j < monomialdata->nfactors; ++j )
9925  {
9926  SCIPmessageFPrintInfo(messagehdlr, file, "c%d", monomialdata->childidxs[j]);
9927  if( printchildrenbounds )
9928  SCIPmessageFPrintInfo(messagehdlr, file, "[%10g,%10g]", node->children[monomialdata->childidxs[j]]->bounds.inf, node->children[monomialdata->childidxs[j]]->bounds.sup);
9929  if( monomialdata->exponents[j] < 0.0 )
9930  SCIPmessageFPrintInfo(messagehdlr, file, "^(%g)", monomialdata->exponents[j]);
9931  else if( monomialdata->exponents[j] != 1.0 )
9932  SCIPmessageFPrintInfo(messagehdlr, file, "^%g", monomialdata->exponents[j]);
9933  }
9934  }
9935 
9936  break;
9937  }
9938 
9939  case SCIP_EXPR_LAST:
9940  SCIPABORT();
9941  break;
9942 
9943  default:
9944  SCIPmessageFPrintInfo(messagehdlr, file, SCIPexpropGetName(node->op));
9945  break;
9946  } /*lint !e788*/
9947 }
9948 
9949 /** prints a node of an expression graph */
9950 static
9952  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
9953  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
9954  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
9955  FILE* file, /**< file to print to, or NULL for stdout */
9956  const char** varnames /**< variable names, or NULL for generic names */
9957  )
9958 {
9959  SCIP_Real color;
9960  int i;
9961 
9962  assert(exprgraph != NULL);
9963  assert(node != NULL);
9964  assert(file != NULL);
9965 
9966  color = (SCIP_Real)node->op / (SCIP_Real)SCIP_EXPR_LAST;
9967  SCIPmessageFPrintInfo(messagehdlr, file, "n%d_%d [fillcolor=\"%g,%g,%g\", label=\"", node->depth, node->pos, color, color, color);
9968 
9969  exprgraphPrintNodeExpression(node, messagehdlr, file, varnames, FALSE);
9970 
9971  SCIPmessageFPrintInfo(messagehdlr, file, "\\n[%g,%g]", node->bounds.inf, node->bounds.sup);
9973  SCIPmessageFPrintInfo(messagehdlr, file, "!");
9975  SCIPmessageFPrintInfo(messagehdlr, file, "*");
9977  SCIPmessageFPrintInfo(messagehdlr, file, "+");
9978 
9979  SCIPmessageFPrintInfo(messagehdlr, file, "\"");
9980 
9981  if( !node->enabled )
9982  SCIPmessageFPrintInfo(messagehdlr, file, ", style=dotted");
9983 
9984  SCIPmessageFPrintInfo(messagehdlr, file, "]\n");
9985 
9986  /* add edges from node to children */
9987  for( i = 0; i < node->nchildren; ++i )
9988  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);
9989 }
9990 
9991 /** evaluate node of expression graph w.r.t. values stored in children */
9992 static
9994  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
9995  SCIP_Real* varvals /**< values for variables */
9996  )
9997 {
9998  int i;
10000  SCIP_Real* buf;
10001 
10002  assert(node != NULL);
10003 
10004  /* if many children, get large enough memory to store argument values */
10006  {
10007  SCIP_ALLOC( BMSallocMemoryArray(&buf, node->nchildren) );
10008  }
10009  else
10010  {
10011  buf = staticbuf;
10012  }
10013 
10014  /* get values of children */
10015  for( i = 0; i < node->nchildren; ++i )
10016  {
10017  assert(node->children[i]->value != SCIP_INVALID); /*lint !e777*/
10018  buf[i] = node->children[i]->value; /*lint !e644*/
10019  }
10020 
10021  /* evaluate this expression */
10022  assert(exprOpTable[node->op].eval != NULL);
10023  SCIP_CALL( exprOpTable[node->op].eval(node->data, node->nchildren, buf, varvals, NULL, &node->value) );
10024  assert(node->value != SCIP_INVALID); /*lint !e777*/
10025 
10026  /* free memory, if allocated before */
10027  if( staticbuf != buf )
10028  {
10029  BMSfreeMemoryArray(&buf);
10030  }
10031 
10032  return SCIP_OKAY;
10033 }
10034 
10035 /** evaluates node including subtree */
10036 static
10038  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
10039  SCIP_Real* varvals /**< values for variables */
10040  )
10041 {
10042  int i;
10043 
10044  assert(node != NULL);
10045 
10046  for( i = 0; i < node->nchildren; ++i )
10047  {
10048  SCIP_CALL( exprgraphNodeEvalWithChildren(node->children[i], varvals) );
10049  }
10050 
10051  SCIP_CALL( exprgraphNodeEval(node, varvals) );
10052 
10053  return SCIP_OKAY;
10054 }
10055 
10056 /** updates bounds of a node if a children has changed its bounds */
10057 static
10059  SCIP_EXPRGRAPHNODE* node, /**< node of expression graph */
10060  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10061  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a bound recalculation in parent nodes */
10062  SCIP_Bool parenttightenisinvalid /**< whether to consider bounds that have been tightened by parents as invalid */
10063  )
10064 {
10065  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
10066  SCIP_INTERVAL* childbounds;
10067  SCIP_INTERVAL newbounds;
10068  int i;
10069 
10070  assert(node != NULL);
10071  assert(node->depth >= 1); /* node should be in graph and not be at depth 0 (i.e., no variable, constant, or parameter) */
10072  assert(node->pos >= 0); /* node should be in graph */
10073  assert(node->op != SCIP_EXPR_VARIDX);
10074  assert(node->op != SCIP_EXPR_PARAM);
10075 
10076  /* if we still have valid bounds and also no child got a bound tightening, then nothing to do
10077  * if node is disabled, then also do nothing */
10078  if( node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID || !node->enabled )
10079  return SCIP_OKAY;
10080 
10081  /* if many children, get large enough memory to store children bounds */
10083  {
10084  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
10085  }
10086  else
10087  {
10088  childbounds = childboundsstatic;
10089  }
10090 
10091  /* assemble bounds of children */
10092  for( i = 0; i < node->nchildren; ++i )
10093  {
10094  /* child should have valid and non-empty bounds */
10096  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10097 
10098  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
10099  }
10100 
10101  /* call interval evaluation function for this operand */
10102  assert( exprOpTable[node->op].inteval != NULL );
10103  SCIPintervalSet(&newbounds, 0.0);
10104  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
10105 
10106  /* free memory, if allocated before */
10107  if( childbounds != childboundsstatic )
10108  {
10109  BMSfreeMemoryArray(&childbounds);
10110  }
10111 
10112  /* NOTE: if you change code below, please make analog changes also in SCIPexprgraphUpdateNodeBoundsCurvature */
10113 
10114  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
10115  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
10116  *
10117  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
10118  *
10119  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
10120  */
10121  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
10122  ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED) || ((node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT) && parenttightenisinvalid)) )
10123  {
10124  for( i = 0; i < node->nparents; ++i )
10126 
10127  node->bounds = newbounds;
10128  }
10129  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
10130  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
10131  {
10132  for( i = 0; i < node->nparents; ++i )
10134 
10135  node->bounds = newbounds;
10136  }
10137  else
10138  {
10139  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
10140  }
10141 
10142  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);
10143 
10144  /* node now has valid bounds */
10145  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
10146 
10147  return SCIP_OKAY;
10148 }
10149 
10150 /** propagate bounds of a node into children by reverting the nodes expression */
10151 static
10153  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
10154  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
10155  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
10156  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
10157  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
10158  )
10159 {
10160  SCIP_INTERVAL childbounds;
10161  int i;
10162 
10163  assert(exprgraph != NULL);
10164  assert(node != NULL);
10165  assert(node->depth >= 0); /* node should be in graph */
10166  assert(node->pos >= 0); /* node should be in graph */
10167  assert(minstrength >= 0.0);
10168  assert(cutoff != NULL);
10169  assert(!SCIPintervalIsEmpty(infinity, node->bounds)); /* should not call backward prop. for a node that yield a cutoff already */
10170  assert(!node->enabled || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED)); /* there should be no unprocessed relaxations of children bounds, if node is enabled */
10171 
10172  /* if we have no recent bound tightening from a parent, then no use in reverse-propagating our bounds */
10174  return;
10175 
10176  /* if node is not enabled, then do nothing */
10177  if( !node->enabled )
10178  return;
10179 
10180  /* tell children that they should propagate their bounds even if not tightened */
10182  minstrength = -1.0;
10183 
10184  /* we will do something, so reset boundstatus to "tightened-by-parent, but not recently" */
10186 
10187  /* 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);
10188  * SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
10189  * SCIPdebugPrintf("\n");
10190  */
10191 
10192  /* @todo add callback to exprOpTable for this */
10193 
10194  switch( node->op )
10195  {
10196  case SCIP_EXPR_VARIDX:
10197  case SCIP_EXPR_CONST:
10198  case SCIP_EXPR_PARAM:
10199  /* cannot propagate bound changes further */
10200  break;
10201 
10202  case SCIP_EXPR_PLUS:
10203  {
10204  assert(node->nchildren == 2);
10205  /* f = c0 + c1 -> c0 = f - c1, c1 = f - c0 */
10206 
10207  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10208  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10209 
10210  if( *cutoff )
10211  break;
10212 
10213  SCIPintervalSub(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10214  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10215 
10216  break;
10217  }
10218 
10219  case SCIP_EXPR_MINUS:
10220  {
10221  assert(node->nchildren == 2);
10222  /* f = c0 - c1 -> c0 = f + c1, c1 = c0 - f */
10223 
10224  SCIPintervalAdd(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10225  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10226 
10227  if( *cutoff )
10228  break;
10229 
10230  SCIPintervalSub(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10231  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10232 
10233  break;
10234  }
10235 
10236  case SCIP_EXPR_MUL:
10237  {
10238  assert(node->nchildren == 2);
10239  /* f = c0 * c1 -> c0 = f / c1, c1 = f / c0 */
10240 
10241  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10242  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10243 
10244  if( *cutoff )
10245  break;
10246 
10247  SCIPintervalDiv(infinity, &childbounds, node->bounds, node->children[0]->bounds);
10248  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10249 
10250  break;
10251  }
10252 
10253  case SCIP_EXPR_DIV:
10254  {
10255  assert(node->nchildren == 2);
10256  /* f = c0 / c1 -> c0 = f * c1, c1 = c0 / f */
10257 
10258  SCIPintervalMul(infinity, &childbounds, node->bounds, node->children[1]->bounds);
10259  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10260 
10261  if( *cutoff )
10262  break;
10263 
10264  SCIPintervalDiv(infinity, &childbounds, node->children[0]->bounds, node->bounds);
10265  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10266 
10267  break;
10268  }
10269 
10270  case SCIP_EXPR_SQUARE:
10271  {
10272  assert(node->nchildren == 1);
10273  /* f = c0^2 -> c0 = sqrt(f) union -sqrt(f) */
10274 
10275  if( node->bounds.sup < 0.0 )
10276  {
10277  *cutoff = TRUE;
10278  break;
10279  }
10280 
10281  SCIPintervalSquareRoot(infinity, &childbounds, node->bounds);
10282  if( node->children[0]->bounds.inf <= -childbounds.inf )
10283  SCIPintervalSetBounds(&childbounds, -childbounds.sup, childbounds.sup);
10284  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10285 
10286  break;
10287  }
10288 
10289  case SCIP_EXPR_SQRT:
10290  {
10291  assert(node->nchildren == 1);
10292  /* f = sqrt(c0) -> c0 = f^2 */
10293 
10294  SCIPintervalSquare(infinity, &childbounds, node->bounds);
10295  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10296 
10297  break;
10298  }
10299 
10300  case SCIP_EXPR_REALPOWER:
10301  {
10302  assert(node->nchildren == 1);
10303 
10304  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, node->data.dbl, node->bounds);
10305 
10306  if( SCIPintervalIsEmpty(infinity, childbounds) )
10307  {
10308  *cutoff = TRUE;
10309  break;
10310  }
10311  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10312 
10313  break;
10314  }
10315 
10316  case SCIP_EXPR_SIGNPOWER:
10317  {
10318  assert(node->nchildren == 1);
10319 
10320  if( node->data.dbl != 0.0 )
10321  {
10322  SCIPintervalSignPowerScalar(infinity, &childbounds, node->bounds, 1.0/node->data.dbl);
10323  }
10324  else
10325  {
10326  /* behaves like SCIP_EXPR_SIGN */
10327  SCIPintervalSetBounds(&childbounds,
10328  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10329  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10330  }
10331 
10332  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10333 
10334  break;
10335  }
10336 
10337  case SCIP_EXPR_INTPOWER:
10338  {
10339  assert(node->nchildren == 1);
10340 
10341  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[0]->bounds, (SCIP_Real)node->data.intval, node->bounds);
10342 
10343  if( SCIPintervalIsEmpty(infinity, childbounds) )
10344  {
10345  *cutoff = TRUE;
10346  break;
10347  }
10348  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10349 
10350  break;
10351  }
10352 
10353  case SCIP_EXPR_EXP:
10354  {
10355  assert(node->nchildren == 1);
10356  /* f = exp(c0) -> c0 = log(f) */
10357 
10358  if( node->bounds.sup < 0.0 )
10359  {
10360  *cutoff = TRUE;
10361  break;
10362  }
10363 
10364  SCIPintervalLog(infinity, &childbounds, node->bounds);
10365  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10366 
10367  break;
10368  }
10369 
10370  case SCIP_EXPR_LOG:
10371  {
10372  assert(node->nchildren == 1);
10373  /* f = log(c0) -> c0 = exp(f) */
10374 
10375  SCIPintervalExp(infinity, &childbounds, node->bounds);
10376  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10377 
10378  break;
10379  }
10380 
10381  case SCIP_EXPR_SIN:
10382  case SCIP_EXPR_COS:
10383  case SCIP_EXPR_TAN:
10384  /* case SCIP_EXPR_ERF: */
10385  /* case SCIP_EXPR_ERFI: */
10386  {
10387  assert(node->nchildren == 1);
10388 
10389  /* @todo implement */
10390 
10391  break;
10392  }
10393 
10394  case SCIP_EXPR_ABS:
10395  {
10396  assert(node->nchildren == 1);
10397 
10398  /* use identity if child bounds are non-negative */
10399  if( node->children[0]->bounds.inf >= 0 )
10400  {
10401  SCIPintervalSetBounds(&childbounds, node->bounds.inf, node->bounds.sup);
10402  }
10403  /* use -identity if child bounds are non-positive */
10404  else if( node->children[0]->bounds.sup <= 0 )
10405  {
10406  assert(node->bounds.inf <= node->bounds.sup);
10407  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, -node->bounds.inf);
10408  }
10409  /* f = |c0| -> c0 = -f union f = [-f.sup, f.sup] */
10410  else
10411  {
10412  SCIPintervalSetBounds(&childbounds, -node->bounds.sup, node->bounds.sup);
10413  }
10414 
10415  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10416 
10417  break;
10418  }
10419 
10420  case SCIP_EXPR_SIGN:
10421  {
10422  assert(node->nchildren == 1);
10423  /* f = sign(c0) -> c0 = ([-infty,0] if -1 in f) union ([0,infty] if 1 in f) */
10424 
10425  SCIPintervalSetBounds(&childbounds,
10426  (node->bounds.inf <= -1.0 && node->bounds.sup >= -1.0) ? -infinity : 0.0,
10427  (node->bounds.inf <= 1.0 && node->bounds.sup >= 1.0) ? infinity : 0.0);
10428  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10429 
10430  break;
10431  }
10432 
10433  case SCIP_EXPR_MIN:
10434  {
10435  assert(node->nchildren == 2);
10436  /* f = min(c0,c1) -> f <= c0, f <= c1
10437  * if c1 > f -> c0 = f
10438  * if c0 > f -> c1 = f
10439  */
10440 
10441  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10442  node->children[1]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10443  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10444 
10445  if( *cutoff )
10446  break;
10447 
10448  SCIPintervalSetBounds(&childbounds, node->bounds.inf,
10449  node->children[0]->bounds.inf > node->bounds.sup ? node->bounds.sup : infinity);
10450  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10451 
10452  break;
10453  }
10454 
10455  case SCIP_EXPR_MAX:
10456  {
10457  assert(node->nchildren == 2);
10458  /* f = max(c0, c1) -> f >= c0, f >= c1
10459  * if c1 < f -> c0 = f
10460  * if c0 < f -> c1 = f
10461  */
10462 
10463  SCIPintervalSetBounds(&childbounds,
10464  node->children[1]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10465  node->bounds.sup);
10466  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10467 
10468  SCIPintervalSetBounds(&childbounds,
10469  node->children[0]->bounds.sup < node->bounds.inf ? node->bounds.inf : -infinity,
10470  node->bounds.sup);
10471  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10472 
10473  break;
10474  }
10475 
10476  case SCIP_EXPR_SUM:
10477  {
10478  SCIP_ROUNDMODE prevroundmode;
10479 
10480  /* f = sum_i c_i -> c_i = f - sum_{j,j!=i} c_j */
10481 
10482  SCIP_Real minlinactivity;
10483  SCIP_Real maxlinactivity;
10484  int minlinactivityinf;
10485  int maxlinactivityinf;
10486 
10487  if( node->nchildren == 0 )
10488  break;
10489 
10490  if( SCIPintervalIsEntire(infinity, node->bounds) )
10491  break;
10492 
10493  minlinactivity = 0.0;
10494  maxlinactivity = 0.0;
10495  minlinactivityinf = 0;
10496  maxlinactivityinf = 0;
10497 
10498  prevroundmode = SCIPintervalGetRoundingMode();
10500 
10501  for( i = 0; i < node->nchildren; ++i )
10502  {
10503  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10504 
10505  /* minimal activity is only useful if node has a finite upper bound */
10506  if( node->bounds.sup < infinity )
10507  {
10508  if( node->children[i]->bounds.inf <= -infinity )
10509  {
10510  ++minlinactivityinf;
10511  }
10512  else
10513  {
10514  assert(node->children[i]->bounds.inf < infinity);
10515  minlinactivity += node->children[i]->bounds.inf;
10516  }
10517  }
10518 
10519  /* maximal activity is only useful if node has a finite lower bound
10520  * we compute negated maximal activity here so we can keep downward rounding
10521  */
10522  if( node->bounds.inf > -infinity )
10523  {
10524  if( node->children[i]->bounds.sup >= infinity )
10525  {
10526  ++maxlinactivityinf;
10527  }
10528  else
10529  {
10530  assert(node->children[i]->bounds.sup > -infinity);
10531  maxlinactivity -= node->children[i]->bounds.sup;
10532  }
10533  }
10534  }
10535  maxlinactivity = -maxlinactivity; /* correct sign */
10536 
10537  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10538  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10539  ( maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10540  )
10541  {
10542  SCIPintervalSetRoundingMode(prevroundmode);
10543  break;
10544  }
10545 
10546  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10547  {
10548  /* upper bounds of c_i is
10549  * node->bounds.sup - (minlinactivity - c_i.inf), if c_i.inf > -infinity and minlinactivityinf == 0
10550  * node->bounds.sup - minlinactivity, if c_i.inf == -infinity and minlinactivityinf == 1
10551  */
10552  SCIPintervalSetEntire(infinity, &childbounds);
10553  if( node->bounds.sup < infinity )
10554  {
10555  /* we are still in downward rounding mode, so negate and negate to get upward rounding */
10556  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10557  {
10558  assert(minlinactivityinf == 1);
10559  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup);
10560  }
10561  else if( minlinactivityinf == 0 )
10562  {
10563  childbounds.sup = SCIPintervalNegateReal(minlinactivity - node->bounds.sup - node->children[i]->bounds.inf);
10564  }
10565  }
10566 
10567  /* lower bounds of c_i is
10568  * node->bounds.inf - (maxlinactivity - c_i.sup), if c_i.sup < infinity and maxlinactivityinf == 0
10569  * node->bounds.inf - maxlinactivity, if c_i.sup == infinity and maxlinactivityinf == 1
10570  */
10571  if( node->bounds.inf > -infinity )
10572  {
10573  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10574  {
10575  assert(maxlinactivityinf == 1);
10576  childbounds.inf = node->bounds.inf - maxlinactivity;
10577  }
10578  else if( maxlinactivityinf == 0 )
10579  {
10580  childbounds.inf = node->bounds.inf - maxlinactivity + node->children[i]->bounds.sup;
10581  }
10582  }
10583 
10584  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10585  }
10586 
10587  SCIPintervalSetRoundingMode(prevroundmode);
10588 
10589  break;
10590  }
10591 
10592  case SCIP_EXPR_PRODUCT:
10593  {
10594  int j;
10595  /* f = prod_i c_i -> c_i = f / prod_{j:j!=i} c_j */
10596 
10597  /* too expensive (runtime here is quadratic in number of children) */
10598  if( node->nchildren > 10 )
10599  break;
10600 
10601  /* useless */
10602  if( SCIPintervalIsEntire(infinity, node->bounds) )
10603  break;
10604 
10605  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10606  {
10607  /* compute prod_{j:j!=i} c_j */
10608  SCIPintervalSet(&childbounds, 1.0);
10609  for( j = 0; j < node->nchildren; ++j )
10610  {
10611  if( i == j )
10612  continue;
10613  SCIPintervalMul(infinity, &childbounds, childbounds, node->children[j]->bounds);
10614 
10615  /* if there is 0.0 in the product, then later division will hardly give useful bounds, so giveup for this i */
10616  if( childbounds.inf <= 0.0 && childbounds.sup >= 0.0 )
10617  break;
10618  }
10619 
10620  if( j == node->nchildren )
10621  {
10622  SCIPintervalDiv(infinity, &childbounds, node->bounds, childbounds); /* f / prod_{j:j!=i} c_j */
10623  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10624  }
10625  }
10626 
10627  break;
10628  }
10629 
10630  case SCIP_EXPR_LINEAR:
10631  {
10632  SCIP_ROUNDMODE prevroundmode;
10633  SCIP_Real* coefs;
10634 
10635  /* f = constant + sum_i a_ic_i -> c_i = (f - constant - sum_{j,j!=i} a_jc_j) / c_i */
10636 
10637  SCIP_Real minlinactivity;
10638  SCIP_Real maxlinactivity;
10639  int minlinactivityinf;
10640  int maxlinactivityinf;
10641 
10642  if( node->nchildren == 0 )
10643  break;
10644 
10645  if( SCIPintervalIsEntire(infinity, node->bounds) )
10646  break;
10647 
10648  coefs = (SCIP_Real*)node->data.data;
10649 
10650  minlinactivity = coefs[node->nchildren];
10651  maxlinactivity = -coefs[node->nchildren];
10652  minlinactivityinf = 0;
10653  maxlinactivityinf = 0;
10654 
10655  prevroundmode = SCIPintervalGetRoundingMode();
10657 
10658  for( i = 0; i < node->nchildren; ++i )
10659  {
10660  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
10661 
10662  /* minimal activity is only useful if node has a finite upper bound */
10663  if( node->bounds.sup < infinity )
10664  {
10665  if( coefs[i] >= 0.0 )
10666  {
10667  if( node->children[i]->bounds.inf <= -infinity )
10668  {
10669  ++minlinactivityinf;
10670  }
10671  else
10672  {
10673  assert(node->children[i]->bounds.inf < infinity);
10674  minlinactivity += coefs[i] * node->children[i]->bounds.inf;
10675  }
10676  }
10677  else
10678  {
10679  if( node->children[i]->bounds.sup >= infinity )
10680  {
10681  ++minlinactivityinf;
10682  }
10683  else
10684  {
10685  assert(node->children[i]->bounds.sup > -infinity);
10686  minlinactivity += coefs[i] * node->children[i]->bounds.sup;
10687  }
10688  }
10689  }
10690 
10691  /* maximal activity is only useful if node has a finite lower bound
10692  * we compute negated maximal activity here so we can keep downward rounding
10693  */
10694  if( node->bounds.inf > -infinity )
10695  {
10696  if( coefs[i] >= 0.0 )
10697  {
10698  if( node->children[i]->bounds.sup >= infinity )
10699  {
10700  ++maxlinactivityinf;
10701  }
10702  else
10703  {
10704  assert(node->children[i]->bounds.sup > -infinity);
10705  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.sup;
10706  }
10707  }
10708  else
10709  {
10710  if( node->children[i]->bounds.inf <= -infinity )
10711  {
10712  ++maxlinactivityinf;
10713  }
10714  else
10715  {
10716  assert(node->children[i]->bounds.inf < infinity);
10717  maxlinactivity += SCIPintervalNegateReal(coefs[i]) * node->children[i]->bounds.inf;
10718  }
10719  }
10720  }
10721  }
10722  maxlinactivity = SCIPintervalNegateReal(maxlinactivity); /* correct sign */
10723 
10724  /* SCIPdebugMessage("activity = [%10g,%10g] ninf = [%d,%d]; bounds = [%10g,%10g]\n", minlinactivity, maxlinactivity, minlinactivityinf, maxlinactivityinf, node->bounds.inf, node->bounds.sup); */
10725 
10726  /* if there are too many unbounded bounds, then could only compute infinite bounds for children, so give up */
10727  if( (minlinactivityinf >= 2 || node->bounds.sup >= infinity) &&
10728  (maxlinactivityinf >= 2 || node->bounds.inf <= -infinity)
10729  )
10730  {
10731  SCIPintervalSetRoundingMode(prevroundmode);
10732  break;
10733  }
10734 
10735  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10736  {
10737  SCIP_INTERVAL ac;
10738 
10739  if( coefs[i] == 0.0 )
10740  continue;
10741 
10742  /* contribution of child i to activity (coefs[i] * node->children[i]->bounds) */
10743  SCIPintervalSet(&ac, 0.0);
10744  if( coefs[i] >= 0.0 )
10745  {
10746  if( node->children[i]->bounds.inf > -infinity )
10747  ac.inf = coefs[i] * node->children[i]->bounds.inf;
10748  if( node->children[i]->bounds.sup < infinity )
10750  }
10751  else
10752  {
10753  if( node->children[i]->bounds.sup < infinity )
10754  ac.inf = coefs[i] * node->children[i]->bounds.sup;
10755  if( node->children[i]->bounds.inf > -infinity )
10756  ac.sup = -SCIPintervalNegateReal(coefs[i] * node->children[i]->bounds.inf);
10757  }
10758 
10759  SCIPintervalSetEntire(infinity, &childbounds);
10760  if( coefs[i] > 0.0 )
10761  {
10762  /* upper bounds of c_i is
10763  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and minlinactivityinf == 0
10764  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.inf == -infinity and minlinactivityinf == 1
10765  */
10766  if( node->bounds.sup < infinity )
10767  {
10768  /* we are still in downward rounding mode, so negate to get upward rounding */
10769  if( node->children[i]->bounds.inf <= -infinity && minlinactivityinf <= 1 )
10770  {
10771  assert(minlinactivityinf == 1);
10772  childbounds.sup = SCIPintervalNegateReal((minlinactivity - node->bounds.sup)/coefs[i]);
10773  }
10774  else if( minlinactivityinf == 0 )
10775  {
10776  childbounds.sup = SCIPintervalNegateReal((minlinactivity - ac.inf - node->bounds.sup)/coefs[i]);
10777  }
10778  }
10779 
10780  /* lower bounds of c_i is
10781  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and maxlinactivityinf == 0
10782  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.sup == infinity and maxlinactivityinf == 1
10783  */
10784  if( node->bounds.inf > -infinity )
10785  {
10786  if( node->children[i]->bounds.sup >= infinity && maxlinactivityinf <= 1 )
10787  {
10788  assert(maxlinactivityinf == 1);
10789  childbounds.inf = (node->bounds.inf - maxlinactivity)/coefs[i];
10790  }
10791  else if( maxlinactivityinf == 0 )
10792  {
10793  childbounds.inf = (node->bounds.inf - maxlinactivity + ac.sup)/coefs[i];
10794  }
10795  }
10796  }
10797  else
10798  {
10799  /* (a-b)/c in downward rounding may not result in a lower bound on (a-b)/c if c is negative
10800  * thus, we do (b-a)/(-c) in downward rounding
10801  */
10802  /* lower bounds of c_i is
10803  * (node->bounds.sup - minlinactivity)/coefs[i] + c_i.sup, if c_i.sup < infinity and minlinactivityinf == 0
10804  * (node->bounds.sup - minlinactivity)/coefs[i], if c_i.sup == infinity and minlinactivityinf == 1
10805  */
10806  if( node->bounds.sup < infinity )
10807  {
10808  if( node->children[i]->bounds.sup >= infinity && minlinactivityinf <= 1 )
10809  {
10810  assert(minlinactivityinf == 1);
10811  childbounds.inf = (minlinactivity - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10812  }
10813  else if( minlinactivityinf == 0 )
10814  {
10815  childbounds.inf = (minlinactivity - ac.inf - node->bounds.sup)/SCIPintervalNegateReal(coefs[i]);
10816  }
10817  }
10818 
10819  /* upper bounds of c_i is
10820  * (node->bounds.inf - maxlinactivity)/coefs[i] + c_i.inf, if c_i.inf > -infinity and maxlinactivityinf == 0
10821  * (node->bounds.inf - maxlinactivity)/coefs[i], if c_i.inf == -infinity and maxlinactivityinf == 1
10822  */
10823  if( node->bounds.inf > -infinity )
10824  {
10825  /* we are still in downward rounding mode, so negate to get upward rounding */
10826  if( node->children[i]->bounds.inf <= -infinity && maxlinactivityinf <= 1 )
10827  {
10828  assert(maxlinactivityinf == 1);
10829  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity)/SCIPintervalNegateReal(coefs[i]));
10830  }
10831  else if( maxlinactivityinf == 0 )
10832  {
10833  childbounds.sup = SCIPintervalNegateReal((node->bounds.inf - maxlinactivity + ac.sup)/SCIPintervalNegateReal(coefs[i]));
10834  }
10835  }
10836  }
10837 
10838  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10839  }
10840 
10841  SCIPintervalSetRoundingMode(prevroundmode);
10842 
10843  break;
10844  }
10845 
10846  case SCIP_EXPR_QUADRATIC:
10847  {
10848  SCIP_EXPRDATA_QUADRATIC* quaddata;
10849  SCIP_INTERVAL tmp;
10850  SCIP_INTERVAL a;
10851  SCIP_INTERVAL b;
10852  SCIP_INTERVAL c;
10853  SCIP_QUADELEM* quadelems;
10854  int nquadelems;
10855  SCIP_Real* lincoefs;
10856  int k;
10857 
10858  /* f = constant + sum_i c_i + sum_k a_k c_(i_k) c_(j_k)
10859  * turn into quadratic univariate equation a*c_i^2 + b*c_i = c for each child
10860  */
10861 
10862  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
10863  quadelems = quaddata->quadelems;
10864  nquadelems = quaddata->nquadelems;
10865  lincoefs = quaddata->lincoefs;
10866 
10867  /* too expensive, runtime here is O(nchildren * nquadelems) = O(nquadelems^2) since nchildren <= 2*nquadelems usually */
10868  if( nquadelems > 10 )
10869  break;
10870 
10871  if( SCIPintervalIsEntire(infinity, node->bounds) )
10872  break;
10873 
10874  if( node->nchildren == 2 && nquadelems > 0 )
10875  {
10876  /* if it's a bivariate quadratic expression with bilinear term, do something special */
10877  SCIP_Real ax; /* square coefficient of first child */
10878  SCIP_Real ay; /* square coefficient of second child */
10879  SCIP_Real axy; /* bilinear coefficient */
10880 
10881  ax = 0.0;
10882  ay = 0.0;
10883  axy = 0.0;
10884  for( i = 0; i < nquadelems; ++i )
10885  if( quadelems[i].idx1 == 0 && quadelems[i].idx2 == 0 )
10886  ax += quadelems[i].coef;
10887  else if( quadelems[i].idx1 == 1 && quadelems[i].idx2 == 1 )
10888  ay += quadelems[i].coef;
10889  else
10890  axy += quadelems[i].coef;
10891 
10892  c = node->bounds;
10893  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10894 
10895  /* compute bounds for x */
10897  infinity, &childbounds, ax, ay, axy,
10898  lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10899  c, node->children[0]->bounds, node->children[1]->bounds
10900  );
10901  if( (childbounds.inf > node->children[0]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[0]->bounds.sup) )
10902  {
10903  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",
10904  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10905  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10906  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10907  );
10908  }
10909 
10910  if( SCIPintervalIsEmpty(infinity, childbounds) )
10911  *cutoff = TRUE;
10912  else
10913  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
10914  if( *cutoff )
10915  break;
10916 
10917  /* compute bounds for y */
10919  infinity, &childbounds, ay, ax, axy,
10920  lincoefs != NULL ? lincoefs[1] : 0.0, lincoefs != NULL ? lincoefs[0] : 0.0,
10921  c, node->children[1]->bounds, node->children[0]->bounds
10922  );
10923 
10924  if( (childbounds.inf > node->children[1]->bounds.inf + 1e-9 || childbounds.sup + 1e-9 < node->children[1]->bounds.sup) )
10925  {
10926  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",
10927  ax, ay, axy, lincoefs != NULL ? lincoefs[0] : 0.0, lincoefs != NULL ? lincoefs[1] : 0.0,
10928  c.inf, c.sup, node->children[0]->bounds.inf, node->children[0]->bounds.sup,
10929  node->children[1]->bounds.inf, node->children[1]->bounds.sup, childbounds.inf, childbounds.sup, (int)SCIPintervalIsEmpty(infinity, childbounds)
10930  );
10931  }
10932 
10933  if( SCIPintervalIsEmpty(infinity, childbounds) )
10934  *cutoff = TRUE;
10935  else
10936  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[1], childbounds, minstrength, infinity, cutoff);
10937  if( *cutoff )
10938  break;
10939 
10940  break;
10941  }
10942 
10943  for( i = 0; i < node->nchildren && !*cutoff; ++i )
10944  {
10945  SCIPintervalSet(&a, 0.0);
10946  SCIPintervalSet(&b, lincoefs != NULL ? lincoefs[i] : 0.0);
10947  c = node->bounds;
10948  SCIPintervalSubScalar(infinity, &c, c, quaddata->constant);
10949 
10950  /* move linear terms not corresponding to i into c
10951  * @todo do this faster, see EXPR_LINEAR
10952  */
10953  if( lincoefs != NULL )
10954  for( k = 0; k < node->nchildren; ++k )
10955  if( i != k && lincoefs[k] != 0.0 )
10956  {
10957  SCIPintervalMulScalar(infinity, &tmp, node->children[k]->bounds, lincoefs[k]);
10958  SCIPintervalSub(infinity, &c, c, tmp);
10959  }
10960 
10961  for( k = 0; k < nquadelems; ++k )
10962  {
10963  if( quadelems[k].idx1 == i && quadelems[k].idx2 == i )
10964  {
10965  SCIPintervalAddScalar(infinity, &a, a, quadelems[k].coef);
10966  }
10967  else if( quadelems[k].idx1 == i )
10968  {
10969  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx2]->bounds, quadelems[k].coef);
10970  SCIPintervalAdd(infinity, &b, b, tmp);
10971  }
10972  else if( quadelems[k].idx2 == i )
10973  {
10974  SCIPintervalMulScalar(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, quadelems[k].coef);
10975  SCIPintervalAdd(infinity, &b, b, tmp);
10976  }
10977  else if( quadelems[k].idx1 == quadelems[k].idx2 )
10978  {
10979  SCIPintervalSquare(infinity, &tmp, node->children[quadelems[k].idx1]->bounds);
10980  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
10981  SCIPintervalSub(infinity, &c, c, tmp);
10982  }
10983  else
10984  {
10985  SCIPintervalMul(infinity, &tmp, node->children[quadelems[k].idx1]->bounds, node->children[quadelems[k].idx2]->bounds);
10986  SCIPintervalMulScalar(infinity, &tmp, tmp, quadelems[k].coef);
10987  SCIPintervalSub(infinity, &c, c, tmp);
10988  }
10989  }
10990 
10991  SCIPdebugMessage("solve %gc%d^2 + [%10g,%10g]c%d = [%10g,%10g]\n",
10992  a.inf, i, b.inf, b.sup, i, c.inf, c.sup);
10993  SCIPintervalSolveUnivariateQuadExpression(infinity, &childbounds, a, b, c);
10994  if( SCIPintervalIsEmpty(infinity, childbounds) )
10995  *cutoff = TRUE;
10996  else
10997  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
10998  }
10999 
11000  break;
11001  }
11002 
11003  case SCIP_EXPR_POLYNOMIAL:
11004  {
11005  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11006  SCIP_EXPRDATA_MONOMIAL** monomials;
11007  SCIP_EXPRDATA_MONOMIAL* monomial;
11008  int nmonomials;
11009  int j;
11010  int k;
11011  SCIP_Real n;
11012  int nexpisdoublen;
11013  int nexpishalfn;
11014  char abc_flag;
11015 
11016  SCIP_INTERVAL monomialcoef;
11017  SCIP_INTERVAL tmp;
11018  SCIP_INTERVAL a;
11019  SCIP_INTERVAL b;
11020  SCIP_INTERVAL c;
11021 
11022  /* f = constant + sum_i coef_i prod_j c_{i_j}^e_{i_j}
11023  * for each child x, write as a*x^(2n) + b*x^n = c for some n!=0
11024  *
11025  * we determine n by setting n to the first exponent of x that we see
11026  * then we count how often we see x^(2n) and x^(n/2)
11027  * if the number of x^(n/2) exceeds the number of x^(2n), then we half n
11028  */
11029 
11030  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11031  monomials = polynomialdata->monomials;
11032  nmonomials = polynomialdata->nmonomials;
11033 
11034  if( SCIPintervalIsEntire(infinity, node->bounds) )
11035  break;
11036 
11037  for( i = 0; i < node->nchildren && !*cutoff; ++i )
11038  {
11039  n = 0.0;
11040  nexpisdoublen = 0;
11041  nexpishalfn = 0;
11042  for( j = 0; j < nmonomials; ++j )
11043  {
11044  monomial = monomials[j];
11045  for( k = 0; k < monomial->nfactors; ++k )
11046  {
11047  if( monomial->childidxs[k] == i )
11048  {
11049  if( n == 0.0 )
11050  n = monomial->exponents[k];
11051  else if( n == 2*monomial->exponents[k] ) /*lint !e777*/
11052  ++nexpishalfn;
11053  else if( 2*n == monomial->exponents[k] ) /*lint !e777*/
11054  ++nexpisdoublen;
11055  }
11056  }
11057  }
11058 
11059  if( n == 0.0 )
11060  {
11061  /* child does not appear in polynomial -> cannot deduce bound */
11062  continue;
11063  }
11064 
11065  /* half n if there are more monomials with x^(n/2) than monomials with x^(2n) */
11066  if( nexpishalfn > nexpisdoublen )
11067  n /= 2.0;
11068 
11069  SCIPintervalSet(&a, 0.0);
11070  SCIPintervalSet(&b, 0.0);
11071  SCIPintervalSubScalar(infinity, &c, node->bounds, polynomialdata->constant);
11072 
11073  for( j = 0; j < nmonomials; ++j )
11074  {
11075  monomial = monomials[j];
11076  SCIPintervalSet(&monomialcoef, monomial->coef);
11077  abc_flag = 'c';
11078  for( k = 0; k < monomial->nfactors; ++k )
11079  {
11080  if( monomial->childidxs[k] == i )
11081  {
11082  assert(abc_flag == 'c'); /* child should appear only once per monom */
11083  if( n > 0.0 )
11084  {
11085  if( monomial->exponents[k] > 2.0*n )
11086  {
11087  abc_flag = 'a';
11088  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11089  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11090  }
11091  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11092  {
11093  abc_flag = 'a';
11094  }
11095  else if( monomial->exponents[k] > n )
11096  {
11097  abc_flag = 'b';
11098  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11099  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11100  }
11101  else if( monomial->exponents[k] == n ) /*lint !e777*/
11102  {
11103  abc_flag = 'b';
11104  }
11105  else
11106  {
11107  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11108  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11109  }
11110  }
11111  else
11112  {
11113  assert(n < 0.0);
11114  if( monomial->exponents[k] < 2.0*n )
11115  {
11116  abc_flag = 'a';
11117  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - 2.0*n);
11118  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11119  }
11120  else if( monomial->exponents[k] == 2*n ) /*lint !e777*/
11121  {
11122  abc_flag = 'a';
11123  }
11124  else if( monomial->exponents[k] < n )
11125  {
11126  abc_flag = 'b';
11127  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k] - n);
11128  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11129  }
11130  else if( monomial->exponents[k] == n ) /*lint !e777*/
11131  {
11132  abc_flag = 'b';
11133  }
11134  else
11135  {
11136  SCIPintervalPowerScalar(infinity, &tmp, node->children[i]->bounds, monomial->exponents[k]);
11137  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11138  }
11139  }
11140  }
11141  else
11142  {
11143  SCIPintervalPowerScalar(infinity, &tmp, node->children[monomial->childidxs[k]]->bounds, monomial->exponents[k]);
11144  SCIPintervalMul(infinity, &monomialcoef, monomialcoef, tmp);
11145  }
11146  }
11147 
11148  if( abc_flag == 'a' )
11149  {
11150  SCIPintervalAdd(infinity, &a, a, monomialcoef);
11151  /* if monomialcoef is such that a exceeds value for infinity, then stop */
11152  if( a.inf >= infinity || a.sup <= -infinity )
11153  break;
11154  }
11155  else if( abc_flag == 'b' )
11156  {
11157  SCIPintervalAdd(infinity, &b, b, monomialcoef);
11158  /* if monomialcoef is such that b exceeds value for infinity, then stop */
11159  if( b.inf >= infinity || b.sup <= -infinity )
11160  break;
11161  }
11162  else
11163  {
11164  SCIPintervalSub(infinity, &c, c, monomialcoef);
11165  /* if monomialcoef is such that c exceeds value for infinity, then stop */
11166  if( c.inf >= infinity || c.sup <= -infinity )
11167  break;
11168  }
11169  }
11170 
11171  /* if we run out of numbers (within -infinity,infinity) above, then stop */
11172  if( j < nmonomials )
11173  continue;
11174 
11175  /* now have equation a*child^(2n) + b*child^n = c
11176  * solve a*y^2 + b*y = c, then child^n = y
11177  */
11178  SCIPdebugMessage("solve [%10g,%10g]c%d^%g + [%10g,%10g]c%d^%g = [%10g,%10g]",
11179  a.inf, a.sup, i, 2*n, b.inf, b.sup, i, n, c.inf, c.sup);
11180  SCIPintervalSolveUnivariateQuadExpression(infinity, &tmp, a, b, c);
11181  SCIPdebugPrintf(" -> c%d^%g = [%10g, %10g]", i, n, tmp.inf, tmp.sup);
11182 
11183  if( SCIPintervalIsEmpty(infinity, tmp) )
11184  {
11185  *cutoff = TRUE;
11186  break;
11187  }
11188 
11189  SCIPintervalPowerScalarInverse(infinity, &childbounds, node->children[i]->bounds, n, tmp);
11190  SCIPdebugPrintf(" -> c%d = [%10g, %10g]\n", i, childbounds.inf, childbounds.sup);
11191  if( SCIPintervalIsEmpty(infinity, childbounds) )
11192  {
11193  SCIPdebugMessage(" -> cutoff\n");
11194  *cutoff = TRUE;
11195  break;
11196  }
11197 
11198  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[i], childbounds, minstrength, infinity, cutoff);
11199 
11200  /* SCIPdebugMessage("-> node %p (%d,%d): [%10g,%10g] = ", (void*)node, node->depth, node->pos, node->bounds.inf, node->bounds.sup);
11201  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11202  SCIPdebugPrintf("\n"); */
11203  }
11204 
11205  break;
11206  }
11207 
11208  case SCIP_EXPR_USER:
11209  {
11210  SCIP_INTERVAL* childrenbounds;
11211  SCIP_EXPRDATA_USER* exprdata;
11212  int c;
11213 
11214  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11215 
11216  /* do nothing if callback not implemented */
11217  if( exprdata->prop == NULL )
11218  break;
11219 
11220  /* if only one child, do faster */
11221  if( node->nchildren == 1 )
11222  {
11223  childbounds = node->children[0]->bounds;
11224  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, 1, &childbounds, node->bounds, cutoff) );
11225 
11226  if( !*cutoff )
11227  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[0], childbounds, minstrength, infinity, cutoff);
11228 
11229  break;
11230  }
11231 
11232  SCIP_ALLOC_ABORT( BMSallocBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren) );
11233  for( c = 0; c < node->nchildren; ++c )
11234  childrenbounds[c] = node->children[c]->bounds;
11235 
11236  SCIP_CALL_ABORT( exprdata->prop(infinity, exprdata->userdata, node->nchildren, childrenbounds, node->bounds, cutoff) );
11237 
11238  for( c = 0; !*cutoff && c < node->nchildren; ++c )
11239  {
11240  SCIPexprgraphTightenNodeBounds(exprgraph, node->children[c], childrenbounds[c], minstrength, infinity, cutoff);
11241  }
11242 
11243  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childrenbounds, node->nchildren);
11244 
11245  break;
11246  }
11247 
11248  case SCIP_EXPR_LAST:
11249  SCIPABORT();
11250  break;
11251  }
11252 }
11253 
11254 /** removes duplicate children in a polynomial expression node
11255  *
11256  * Leaves NULL's in children array.
11257  */
11258 static
11260  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11261  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11262  )
11263 {
11264  SCIP_Bool foundduplicates;
11265  int* childmap;
11266  int i;
11267  int j;
11268 
11269  assert(exprgraph != NULL);
11270  assert(node != NULL);
11271  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11272 
11273  if( node->nchildren == 0 )
11274  return SCIP_OKAY;
11275 
11276  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) );
11277 
11278  foundduplicates = FALSE;
11279  for( i = 0; i < node->nchildren; ++i )
11280  {
11281  if( node->children[i] == NULL )
11282  continue;
11283  childmap[i] = i; /*lint !e644*/
11284 
11285  for( j = i+1; j < node->nchildren; ++j )
11286  {
11287  if( node->children[j] == NULL )
11288  continue;
11289 
11290  if( node->children[i] == node->children[j] )
11291  {
11292  /* node should be parent of children[j] at least twice,
11293  * so we remove it once
11294  */
11295  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[j], node) );
11296  node->children[j] = NULL;
11297  assert(exprgraphNodeIsParent(node->children[i], node));
11298 
11299  childmap[j] = i;
11300  foundduplicates = TRUE;
11301  }
11302  }
11303  }
11304 
11305  /* apply childmap to monomials */
11306  if( foundduplicates )
11308 
11309  /* free childmap */
11310  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
11311 
11312  return SCIP_OKAY;
11313 }
11314 
11315 /** eliminates NULL's in children array and shrinks it to actual size */
11316 static
11318  BMS_BLKMEM* blkmem, /**< block memory */
11319  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
11320  )
11321 {
11322  int* childmap;
11323  int lastnonnull;
11324  int i;
11325 
11326  assert(blkmem != NULL);
11327  assert(node != NULL);
11328  assert(node->op == SCIP_EXPR_POLYNOMIAL);
11329 
11330  if( node->nchildren == 0 )
11331  return SCIP_OKAY;
11332 
11333  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childmap, node->nchildren) );
11334 
11335  /* close gaps in children array */
11336  lastnonnull = node->nchildren-1;
11337  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11338  --lastnonnull;
11339  for( i = 0; i <= lastnonnull; ++i )
11340  {
11341  if( node->children[i] != NULL )
11342  {
11343  childmap[i] = i; /* child at index i is not moved */ /*lint !e644*/
11344  continue;
11345  }
11346  assert(node->children[lastnonnull] != NULL);
11347 
11348  /* move child at lastnonnull to position i */
11349  node->children[i] = node->children[lastnonnull];
11350  node->children[lastnonnull] = NULL;
11351  childmap[lastnonnull] = i;
11352 
11353  /* update lastnonnull */
11354  --lastnonnull;
11355  while( lastnonnull >= 0 && node->children[lastnonnull] == NULL )
11356  --lastnonnull;
11357  }
11358  assert(i > lastnonnull);
11359 
11360  /* apply childmap to monomials */
11361  if( lastnonnull < node->nchildren-1 )
11363 
11364  BMSfreeBlockMemoryArray(blkmem, &childmap, node->nchildren);
11365 
11366  /* shrink children array */
11367  if( lastnonnull >= 0 )
11368  {
11369  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &node->children, node->nchildren, lastnonnull+1) );
11370  node->nchildren = lastnonnull+1;
11371  }
11372  else
11373  {
11374  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11375  node->nchildren = 0;
11376  }
11377 
11378  return SCIP_OKAY;
11379 }
11380 
11381 /** aims at simplifying a node in an expression graph, assuming all children have been simplified
11382  *
11383  * Converts node into polynomial, if possible and not constant.
11384  */
11385 static
11387  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11388  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
11389  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
11390  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
11391  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
11392  SCIP_Bool* havechange /**< flag to set if the node has been changed */
11393  )
11394 {
11395  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11396  SCIP_EXPRDATA_MONOMIAL* monomial;
11397  BMS_BLKMEM* blkmem;
11398  SCIP_Bool removechild;
11399  SCIP_Bool* childinuse;
11400  int* childmap;
11401  int childmapsize;
11402  int i;
11403  int j;
11404  int orignchildren;
11405 
11406  assert(exprgraph != NULL);
11407  assert(node != NULL);
11408  assert(node->depth > 0); /* simplifier is not thought for nodes at depth 0 */
11409  assert(havechange != NULL);
11410 
11411  blkmem = exprgraph->blkmem;
11412  assert(blkmem != NULL);
11413 
11414  SCIPdebugMessage("attempt simplification of node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
11415 
11416  /* if all children are constants, then turn this node into constant */
11417  for( i = 0; i < node->nchildren; ++i )
11418  if( node->children[i]->op != SCIP_EXPR_CONST )
11419  break;
11420  if( node->nchildren > 0 && i == node->nchildren )
11421  {
11422  /* get value of node */
11424  assert(node->value != SCIP_INVALID); /*lint !e777*/
11425 
11426  SCIPdebugMessage("turn node %p (%d,%d) into constant %g\n", (void*)node, node->depth, node->pos, node->value);
11427  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, TRUE) );
11428  SCIPdebugPrintf("\n");
11429 
11430  /* free expression data */
11431  if( exprOpTable[node->op].freedata != NULL )
11432  exprOpTable[node->op].freedata(blkmem, node->nchildren, node->data);
11433 
11434  /* disconnect from children */
11435  for( i = 0; i < node->nchildren; ++i )
11436  {
11437  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11438  }
11439  BMSfreeBlockMemoryArray(blkmem, &node->children, node->nchildren);
11440  node->nchildren = 0;
11441 
11442  /* turn into constant expression */
11443  node->op = SCIP_EXPR_CONST;
11444  node->data.dbl = node->value;
11445 
11446  *havechange = TRUE;
11447  node->simplified = TRUE;
11448 
11449  return SCIP_OKAY;
11450  }
11451 
11452  /* @todo for sign, min, max, abs, knowing bounds on children may allow simplification
11453  * @todo log(product) -> sum(log)
11454  * @todo product(exp) -> exp(sum)
11455  * @todo exp(x)^p -> exp(p*x)
11456  * @todo exp(const*log(x)) -> x^const
11457  */
11458 
11459  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->op, &node->data, node->nchildren) );
11460 
11461  if( node->op != SCIP_EXPR_POLYNOMIAL )
11462  {
11463  node->simplified = TRUE;
11464  return SCIP_OKAY;
11465  }
11466 
11467  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11468  assert(polynomialdata != NULL);
11469 
11470  orignchildren = node->nchildren;
11471 
11472  /* check if we have duplicate children and merge */
11474  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11475 
11476  SCIPdebugMessage("expand factors in expression node ");
11477  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11478  SCIPdebugPrintf("\n");
11479 
11480  childmap = NULL;
11481  childmapsize = 0;
11482 
11483  /* resolve children that are constants
11484  * we do this first, because it reduces the degree and number of factors in the monomials,
11485  * 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
11486  */
11487  for( i = 0; i < node->nchildren; ++i )
11488  {
11489  if( node->children[i] == NULL )
11490  continue;
11491 
11492  /* convert children to polynomial, if not constant or polynomial
11493  * if child was simplified in this round, it may have already been converted, and then nothing happens
11494  * but if child was already simplified, then it was not converted, and thus we try it here
11495  */
11496  if( node->children[i]->op != SCIP_EXPR_CONST )
11497  continue;
11498 
11499  SCIPdebugMessage("expand child %d in expression node ", i);
11500  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11501  SCIPdebugPrintf("\n\tchild = ");
11502  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11503  SCIPdebugPrintf("\n");
11504 
11505  removechild = TRUE; /* we intend to release children[i] */
11506 
11507  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11508 
11509  /* put constant of child i into every monomial where child i is used */
11510  for( j = 0; j < polynomialdata->nmonomials; ++j )
11511  {
11512  int factorpos;
11513 
11514  monomial = polynomialdata->monomials[j];
11515  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11516  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11517 
11518  if( SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11519  {
11520  assert(factorpos >= 0);
11521  assert(factorpos < monomial->nfactors);
11522  /* assert that factors have been merged */
11523  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11524  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11525 
11526  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11527 
11528  if( !EPSISINT(monomial->exponents[factorpos], 0.0) && node->children[i]->data.dbl < 0.0 ) /*lint !e835*/
11529  {
11530  /* if constant is negative and our exponent is not integer, then cannot do expansion */
11531  SCIPmessagePrintWarning(messagehdlr, "got negative constant %g to the power of a noninteger exponent %g\n", node->children[i]->data.dbl, monomial->exponents[factorpos]);
11532  removechild = FALSE;
11533  }
11534  else
11535  {
11536  monomial->coef *= pow(node->children[i]->data.dbl, monomial->exponents[factorpos]);
11537 
11538  /* move last factor to position factorpos */
11539  if( factorpos < monomial->nfactors-1 )
11540  {
11541  monomial->exponents[factorpos] = monomial->exponents[monomial->nfactors-1];
11542  monomial->childidxs[factorpos] = monomial->childidxs[monomial->nfactors-1];
11543  }
11544  --monomial->nfactors;
11545  monomial->sorted = FALSE;
11546  polynomialdata->sorted = FALSE;
11547 
11548  *havechange = TRUE;
11549  }
11550  }
11551  }
11552 
11553  /* forget about child i, if it is not used anymore */
11554  if( removechild )
11555  {
11556  /* remove node from list of parents of child i */
11557  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11558  node->children[i] = NULL;
11559  }
11560 
11561  /* simplify current polynomial again */
11562  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11563  }
11564 
11565  /* resolve children that are polynomials itself */
11566  for( i = 0; i < node->nchildren; ++i )
11567  {
11568  if( node->children[i] == NULL )
11569  continue;
11570 
11571  /* convert children to polynomial, if not constant or polynomial
11572  * if child was simplified in this round, it may have already been converted, and then nothing happens
11573  * but if child was already simplified, then it was not converted, and thus we try it here
11574  */
11575  SCIP_CALL( exprConvertToPolynomial(blkmem, &node->children[i]->op, &node->children[i]->data, node->children[i]->nchildren) );
11576 
11577  if( node->children[i]->op != SCIP_EXPR_POLYNOMIAL )
11578  continue;
11579 
11580  SCIPdebugMessage("expand child %d in expression node ", i);
11581  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11582  SCIPdebugPrintf("\n\tchild = ");
11583  SCIPdebug( exprgraphPrintNodeExpression(node->children[i], messagehdlr, NULL, NULL, FALSE) );
11584  SCIPdebugPrintf("\n");
11585 
11586  removechild = TRUE; /* we intend to release children[i] */
11587 
11588  ensureBlockMemoryArraySize(blkmem, &childmap, &childmapsize, node->children[i]->nchildren);
11589 
11590  /* add children of child i to node */
11591  SCIP_CALL( exprgraphNodeAddChildren(blkmem, node, node->children[i]->nchildren, node->children[i]->children, childmap) );
11592 
11593  /* put polynomial of child i into every monomial where child i is used */
11594  j = 0;
11595  while( j < polynomialdata->nmonomials )
11596  {
11597  int factorpos;
11598  SCIP_Bool success;
11599 
11600  monomial = polynomialdata->monomials[j];
11601  /* if monomial is not sorted, then polynomial should not be sorted either, or have only one monomial */
11602  assert(monomial->sorted || !polynomialdata->sorted || polynomialdata->nmonomials <= 1);
11603 
11604  if( !SCIPexprFindMonomialFactor(monomial, i, &factorpos) )
11605  {
11606  ++j;
11607  continue;
11608  }
11609 
11610  assert(factorpos >= 0);
11611  assert(factorpos < monomial->nfactors);
11612  /* assert that factors have been merged */
11613  assert(factorpos == 0 || monomial->childidxs[factorpos-1] != i);
11614  assert(factorpos == monomial->nfactors-1 || monomial->childidxs[factorpos+1] != i);
11615 
11616  SCIPdebugMessage("attempt expanding child %d at monomial %d factor %d\n", i, j, factorpos);
11617 
11618  SCIP_CALL( polynomialdataExpandMonomialFactor(blkmem, messagehdlr, polynomialdata, j, factorpos,
11619  (SCIP_EXPRDATA_POLYNOMIAL*)node->children[i]->data.data, childmap, maxexpansionexponent, &success) );
11620 
11621  if( !success )
11622  {
11623  removechild = FALSE;
11624  ++j;
11625  }
11626  else
11627  *havechange = TRUE;
11628 
11629  /* expansion may remove monomials[j], move a monomial from the end to position j, or add new monomials to the end of polynomialdata
11630  * we thus repeat with index j, if a factor was successfully expanded
11631  */
11632  }
11633 
11634  /* forget about child i, if it is not used anymore */
11635  if( removechild )
11636  {
11637  /* remove node from list of parents of child i */
11638  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11639  node->children[i] = NULL;
11640  }
11641  }
11642 
11643  /* simplify current polynomial again */
11644  polynomialdataMergeMonomials(blkmem, polynomialdata, eps, TRUE);
11645 
11646  BMSfreeBlockMemoryArrayNull(blkmem, &childmap, childmapsize);
11647 
11648  /* check which children are still in use */
11649  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &childinuse, node->nchildren) );
11650  BMSclearMemoryArray(childinuse, node->nchildren); /*lint !e644*/
11651  for( i = 0; i < polynomialdata->nmonomials; ++i )
11652  {
11653  monomial = polynomialdata->monomials[i];
11654  assert(monomial != NULL);
11655 
11656  for( j = 0; j < monomial->nfactors; ++j )
11657  {
11658  assert(monomial->childidxs[j] >= 0);
11659  assert(monomial->childidxs[j] < node->nchildren);
11660  childinuse[monomial->childidxs[j]] = TRUE;
11661  }
11662  }
11663 
11664  /* free children that are not used in any monomial */
11665  for( i = 0; i < node->nchildren; ++i )
11666  if( node->children[i] != NULL && !childinuse[i] )
11667  {
11668  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &node->children[i], node) );
11669  node->children[i] = NULL;
11670  }
11671 
11672  BMSfreeBlockMemoryArray(blkmem, &childinuse, node->nchildren);
11673 
11674  /* remove NULLs from children array */
11676 
11677  /* if no children, then it's a constant polynomial -> change into EXPR_CONST */
11678  if( node->nchildren == 0 )
11679  {
11680  SCIP_Real val;
11681 
11682  /* if no children, then it should also have no monomials */
11683  assert(polynomialdata->nmonomials == 0);
11684 
11685  val = polynomialdata->constant;
11686  polynomialdataFree(blkmem, &polynomialdata);
11687 
11688  node->op = SCIP_EXPR_CONST;
11689  node->data.dbl = val;
11690  node->value = val;
11691  }
11692 
11693  /* if no factor in a monomial was replaced, the number of children should not have changed
11694  * but if we found duplicates in the children array, then it should be reduced, and we want to count this as a change too
11695  */
11696  *havechange |= (node->nchildren < orignchildren); /*lint !e514*/
11697 
11698  node->simplified = TRUE;
11699 
11700  SCIPdebugMessage("-> %p = ", (void*)node);
11701  SCIPdebug( exprgraphPrintNodeExpression(node, messagehdlr, NULL, NULL, FALSE) );
11702  SCIPdebugPrintf("\n");
11703 
11704  return SCIP_OKAY;
11705 }
11706 
11707 /** creates an expression from a given node in an expression graph
11708  *
11709  * Assembles mapping of variables from graph to tree.
11710  */
11711 static
11713  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
11714  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which expression should be created */
11715  SCIP_EXPR** expr, /**< buffer to store pointer to created expression */
11716  int* nexprvars, /**< current number of variables in expression */
11717  int* varidx /**< current mapping of variable indices from graph to expression */
11718  )
11719 {
11720  SCIP_EXPR** childexprs;
11721  int i;
11722 
11723  assert(exprgraph != NULL);
11724  assert(node != NULL);
11725  assert(expr != NULL);
11726  assert(nexprvars != NULL);
11727  assert(*nexprvars >= 0);
11728  assert(varidx != NULL);
11729 
11730  childexprs = NULL;
11731  if( node->nchildren > 0 )
11732  {
11733  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childexprs, node->nchildren) );
11734  for( i = 0; i < node->nchildren; ++i )
11735  {
11736  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[i], &childexprs[i], nexprvars, varidx) ); /*lint !e613*/
11737  }
11738  }
11739 
11740  switch( node->op )
11741  {
11742  case SCIP_EXPR_VARIDX:
11743  {
11744  /* check if the variable already has an index assigned in the expression tree
11745  * if not, create one and increase nexprvars
11746  */
11747  assert(node->data.intval >= 0);
11748  assert(node->data.intval < exprgraph->nvars);
11749  assert(varidx[node->data.intval] >= -1);
11750  assert(varidx[node->data.intval] < *nexprvars);
11751  if( varidx[node->data.intval] == -1 )
11752  {
11753  varidx[node->data.intval] = *nexprvars;
11754  ++*nexprvars;
11755  }
11756 
11757  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, SCIP_EXPR_VARIDX, varidx[node->data.intval]) );
11758  break;
11759  }
11760 
11761  case SCIP_EXPR_CONST:
11762  {
11763  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->data.dbl) );
11764  break;
11765  }
11766 
11767  case SCIP_EXPR_REALPOWER:
11768  case SCIP_EXPR_SIGNPOWER:
11769  {
11770  assert(node->nchildren == 1);
11771  assert(childexprs != NULL);
11772  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.dbl) ); /*lint !e613*/
11773  break;
11774  }
11775 
11776  case SCIP_EXPR_INTPOWER:
11777  {
11778  assert(node->nchildren == 1);
11779  assert(childexprs != NULL);
11780  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], node->data.intval) ); /*lint !e613*/
11781  break;
11782  }
11783 
11784  case SCIP_EXPR_PLUS:
11785  case SCIP_EXPR_MINUS:
11786  case SCIP_EXPR_MUL:
11787  case SCIP_EXPR_DIV:
11788  case SCIP_EXPR_MIN:
11789  case SCIP_EXPR_MAX:
11790  {
11791  assert(node->nchildren == 2);
11792  assert(childexprs != NULL);
11793  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0], childexprs[1]) ); /*lint !e613*/
11794  break;
11795  }
11796 
11797  case SCIP_EXPR_SQUARE:
11798  case SCIP_EXPR_SQRT:
11799  case SCIP_EXPR_EXP:
11800  case SCIP_EXPR_LOG:
11801  case SCIP_EXPR_SIN:
11802  case SCIP_EXPR_COS:
11803  case SCIP_EXPR_TAN:
11804  /* case SCIP_EXPR_ERF: */
11805  /* case SCIP_EXPR_ERFI: */
11806  case SCIP_EXPR_ABS:
11807  case SCIP_EXPR_SIGN:
11808  {
11809  assert(node->nchildren == 1);
11810  assert(childexprs != NULL);
11811  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, childexprs[0]) ); /*lint !e613*/
11812  break;
11813  }
11814 
11815  case SCIP_EXPR_SUM:
11816  case SCIP_EXPR_PRODUCT:
11817  {
11818  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, expr, node->op, node->nchildren, childexprs) );
11819  break;
11820  }
11821 
11822  case SCIP_EXPR_LINEAR:
11823  {
11824  assert(node->data.data != NULL);
11825 
11826  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, expr, node->nchildren, childexprs, (SCIP_Real*)node->data.data, ((SCIP_Real*)node->data.data)[node->nchildren]) );
11827  break;
11828  }
11829 
11830  case SCIP_EXPR_QUADRATIC:
11831  {
11832  SCIP_EXPRDATA_QUADRATIC* quaddata;
11833 
11834  quaddata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
11835  assert(quaddata != NULL);
11836 
11837  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, expr, node->nchildren, childexprs,
11838  quaddata->constant, quaddata->lincoefs, quaddata->nquadelems, quaddata->quadelems) );
11839  break;
11840  }
11841 
11842  case SCIP_EXPR_POLYNOMIAL:
11843  {
11844  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
11845 
11846  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
11847  assert(polynomialdata != NULL);
11848 
11849  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, expr, node->nchildren, childexprs,
11850  polynomialdata->nmonomials, polynomialdata->monomials, polynomialdata->constant, TRUE) );
11851 
11852  break;
11853  }
11854 
11855  case SCIP_EXPR_USER:
11856  {
11857  SCIP_EXPRDATA_USER* exprdata;
11858  SCIP_USEREXPRDATA* userdata;
11859 
11860  exprdata = (SCIP_EXPRDATA_USER*)node->data.data;
11861  assert(exprdata != NULL);
11862 
11863  if( exprdata->copydata != NULL )
11864  {
11865  SCIP_CALL( exprdata->copydata(exprgraph->blkmem, node->nchildren, exprdata->userdata, &userdata) );
11866  }
11867  else
11868  userdata = exprdata->userdata;
11869 
11870  SCIP_CALL( SCIPexprCreateUser(exprgraph->blkmem, expr, node->nchildren, childexprs,
11871  userdata, exprdata->evalcapability, exprdata->eval, exprdata->inteval, exprdata->curv, exprdata->prop, exprdata->estimate, exprdata->copydata, exprdata->freedata, exprdata->print) );
11872 
11873  break;
11874  }
11875 
11876  case SCIP_EXPR_LAST:
11877  case SCIP_EXPR_PARAM:
11878  {
11879  SCIPerrorMessage("expression operand %d not supported here\n", node->op);
11880  return SCIP_ERROR;
11881  }
11882  }
11883 
11884  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &childexprs, node->nchildren);
11885 
11886  return SCIP_OKAY;
11887 }
11888 
11889 /** counts how often expression graph variables are used in a subtree of the expression graph
11890  *
11891  * @note The function does not clear the array first, but only increases already existing counts.
11892  */
11893 static
11895  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
11896  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
11897  )
11898 {
11899  int i;
11900 
11901  assert(node != NULL);
11902  assert(varsusage != NULL);
11903 
11904  if( node->op == SCIP_EXPR_VARIDX )
11905  {
11906  ++varsusage[node->data.intval];
11907  return;
11908  }
11909 
11910  for( i = 0; i < node->nchildren; ++i )
11911  exprgraphNodeGetVarsUsage(node->children[i], varsusage);
11912 }
11913 
11914 /** checks whether a node can be put into a component when checking block separability of an expression
11915  *
11916  * If a variable used by node is already in another component, components are merged and component number is updated.
11917  */
11918 static
11920  SCIP_EXPRGRAPHNODE* node, /**< node to which we assign a component */
11921  int* compnr, /**< component number to assign, may be reduced if variables overlap */
11922  int nchildcomps, /**< number of entries for which childcomps have been set already */
11923  int* childcomps, /**< component numbers of children */
11924  int nvars, /**< number of variables */
11925  int* varcomps /**< component numbers of variables */
11926  )
11927 {
11928  int varidx;
11929  int i;
11930 
11931  assert(node != NULL);
11932  assert(compnr != NULL);
11933  assert(*compnr >= 0);
11934  assert(childcomps != NULL);
11935  assert(varcomps != NULL);
11936 
11937  if( node->op != SCIP_EXPR_VARIDX )
11938  {
11939  for( i = 0; i < node->nchildren; ++i )
11940  exprgraphNodeCheckSeparabilityComponent(node->children[i], compnr, nchildcomps, childcomps, nvars, varcomps);
11941  return;
11942  }
11943 
11944  varidx = node->data.intval;
11945  assert(varidx >= 0);
11946  assert(varidx < nvars);
11947 
11948  if( varcomps[varidx] == -1 )
11949  {
11950  /* first time we get to this variable, so set it's component to compnr and we are done */
11951  varcomps[varidx] = *compnr;
11952  return;
11953  }
11954 
11955  if( varcomps[varidx] == *compnr )
11956  {
11957  /* variable is already in current component, that's also good and we are done */
11958  return;
11959  }
11960 
11961  /* variable is already in another component, so have to merge component compnr into that component
11962  * do this by updating varcomps and childcomps */
11963  for( i = 0; i < nvars; ++i )
11964  if( varcomps[i] == *compnr )
11965  varcomps[i] = varcomps[varidx];
11966  for( i = 0; i < nchildcomps; ++i )
11967  if( childcomps[i] == *compnr )
11968  childcomps[i] = varcomps[varidx];
11969  *compnr = varcomps[varidx];
11970 }
11971 
11972 /**@} */
11973 
11974 /**@name Expression graph private methods */
11975 /**@{ */
11976 
11977 /** assert that expression graph has at least a given depth */
11978 static
11980  SCIP_EXPRGRAPH* exprgraph, /**< buffer to store pointer to expression graph */
11981  int mindepth /**< minimal depth that should be ensured */
11982  )
11983 {
11984  int olddepth;
11985 
11986  assert(exprgraph != NULL);
11987  assert(exprgraph->blkmem != NULL);
11988 
11989  if( mindepth <= exprgraph->depth )
11990  return SCIP_OKAY;
11991 
11992  olddepth = exprgraph->depth;
11993  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->nodessize, &exprgraph->nnodes, &exprgraph->nodes, &exprgraph->depth, mindepth);
11994  assert(exprgraph->depth >= mindepth);
11995 
11996  /* initialize new array entries to 0 and NULL, resp. */
11997  BMSclearMemoryArray(&exprgraph->nodessize[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11998  BMSclearMemoryArray(&exprgraph->nnodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
11999  BMSclearMemoryArray(&exprgraph->nodes[olddepth], exprgraph->depth - olddepth); /*lint !e866*/
12000 
12001  return SCIP_OKAY;
12002 }
12003 
12004 /** remove a variable from the variables arrays, assuming that its node will be removed or converted next */
12005 static
12007  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12008  int varidx /**< variable index */
12009  )
12010 {
12011  SCIP_EXPRGRAPHNODE* varnode;
12012  void* var;
12013 
12014  assert(exprgraph != NULL);
12015  assert(varidx >= 0);
12016  assert(varidx < exprgraph->nvars);
12017 
12018  varnode = exprgraph->varnodes[varidx];
12019  assert(varnode->data.intval == varidx);
12020 
12021  var = exprgraph->vars[varidx];
12022 
12023  /* call varremove callback method, if set */
12024  if( exprgraph->exprgraphvarremove != NULL )
12025  {
12026  SCIP_CALL( exprgraph->exprgraphvarremove(exprgraph, exprgraph->userdata, var, varnode) );
12027  }
12028 
12029  /* remove variable from hashmap */
12030  SCIP_CALL( SCIPhashmapRemove(exprgraph->varidxs, var) );
12031 
12032  /* move last variable to position varidx and give it the new index */
12033  if( varidx < exprgraph->nvars-1 )
12034  {
12035  /* call callback method, if set */
12036  if( exprgraph->exprgraphvarchgidx != NULL )
12037  {
12038  SCIP_CALL( exprgraph->exprgraphvarchgidx(exprgraph, exprgraph->userdata, exprgraph->vars[exprgraph->nvars-1], exprgraph->varnodes[exprgraph->nvars-1], exprgraph->nvars-1, varidx) );
12039  }
12040 
12041  exprgraph->vars[varidx] = exprgraph->vars[exprgraph->nvars-1];
12042  exprgraph->varbounds[varidx] = exprgraph->varbounds[exprgraph->nvars-1];
12043  exprgraph->varnodes[varidx] = exprgraph->varnodes[exprgraph->nvars-1];
12044  exprgraph->varnodes[varidx]->data.intval = varidx;
12045  SCIP_CALL( SCIPhashmapSetImage(exprgraph->varidxs, exprgraph->vars[varidx], (void*)(size_t)(varidx)) );
12046  }
12047  --exprgraph->nvars;
12048 
12049  return SCIP_OKAY;
12050 }
12051 
12052 /** moves a node in an expression graph to a different depth
12053  *
12054  * New depth must be larger than children depth.
12055  * Moves parent nodes to higher depth, if needed.
12056  * Variable nodes cannot be moved.
12057  */
12058 static
12060  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12061  SCIP_EXPRGRAPHNODE* node, /**< node that shall be moved */
12062  int newdepth /**< new depth to which to move node */
12063  )
12064 {
12065  int olddepth;
12066  int oldpos;
12067  int i;
12068 
12069  assert(exprgraph != NULL);
12070  assert(node != NULL);
12071  assert(node->depth >= 0); /* node should be in graph */
12072  assert(newdepth >= 0);
12073 
12074  /* if already on aimed depth, then don't need to move */
12075  if( node->depth == newdepth )
12076  return SCIP_OKAY;
12077 
12078  SCIPdebugMessage("move node %p (%d,%d) to depth %d\n", (void*)node, node->depth, node->pos, newdepth);
12079 
12080 #ifndef NDEBUG
12081  /* assert that children are at lower depth than new depth */
12082  for( i = 0; i < node->nchildren; ++i )
12083  assert(node->children[i]->depth < newdepth);
12084 #endif
12085 
12086  /* move parents to higher depth, if needed */
12087  for( i = 0; i < node->nparents; ++i )
12088  {
12089  if( node->parents[i]->depth <= newdepth )
12090  {
12091  /* move parent to depth+1 */
12092  SCIP_CALL( exprgraphMoveNode(exprgraph, node->parents[i], newdepth+1) );
12093  assert(node->parents[i]->depth > newdepth);
12094  }
12095  }
12096 
12097  /* ensure that graph is deep enough */
12098  SCIP_CALL( exprgraphEnsureDepth(exprgraph, newdepth+1) );
12099  assert(exprgraph->depth > newdepth);
12100 
12101  olddepth = node->depth;
12102  oldpos = node->pos;
12103 
12104  /* add node to new depth */
12105  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[newdepth], &exprgraph->nodessize[newdepth], exprgraph->nnodes[newdepth]+1); /*lint !e866*/
12106  node->depth = newdepth;
12107  node->pos = exprgraph->nnodes[newdepth];
12108  exprgraph->nodes[newdepth][node->pos] = node;
12109  ++exprgraph->nnodes[newdepth];
12110 
12111  /* 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) */
12112  for( i = 0; i < node->nchildren; ++i )
12113  node->children[i]->parentssorted = FALSE;
12114 
12115  /* move last node at previous depth to previous position, if it wasn't last */
12116  if( oldpos < exprgraph->nnodes[olddepth]-1 )
12117  {
12118  exprgraph->nodes[olddepth][oldpos] = exprgraph->nodes[olddepth][exprgraph->nnodes[olddepth]-1];
12119  exprgraph->nodes[olddepth][oldpos]->pos = oldpos;
12120 
12121  /* 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) */
12122  for( i = 0; i < exprgraph->nodes[olddepth][oldpos]->nchildren; ++i )
12123  exprgraph->nodes[olddepth][oldpos]->children[i]->parentssorted = FALSE;
12124  }
12125  --exprgraph->nnodes[olddepth];
12126 
12127  if( node->depth == 0 )
12128  {
12129  /* if at depth 0, then it need to be a node for either a constant or a variable */
12130  assert(node->op == SCIP_EXPR_CONST || node->op == SCIP_EXPR_VARIDX);
12131  if( node->op == SCIP_EXPR_CONST )
12132  {
12133  /* add node to constnodes array of exprgraph @todo should use SCIPsortedvecInsertPtr? */
12134  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
12135  exprgraph->constnodes[exprgraph->nconsts] = node;
12136  ++exprgraph->nconsts;
12137  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], node) < 0);
12138  }
12139  else
12140  {
12141  /* adding a variable by moving it from a higher depth seems awkward, how did the variable get there in the first place? */
12142  SCIPerrorMessage("cannot move variable nodes to depth 0\n");
12143  return SCIP_ERROR;
12144  }
12145 
12146  /* nodes at depth 0 always have curvature linear, even before any curvature check was running */
12147  node->curv = SCIP_EXPRCURV_LINEAR;
12148  }
12149 
12150  return SCIP_OKAY;
12151 }
12152 
12153 /** given a list of children, tries to find a common parent that represents a given operator with the same given data */
12154 static
12156  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12157  int nchildren, /**< number of children */
12158  SCIP_EXPRGRAPHNODE** children, /**< children which parents to inspect */
12159  SCIP_EXPROP op, /**< operator */
12160  SCIP_EXPROPDATA opdata, /**< operator data */
12161  SCIP_EXPR** exprchildren, /**< children of expression to consider when modifying (reordering) operator data, or NULL */
12162  SCIP_EXPRGRAPHNODE** parent /**< buffer to store parent node if any is found, or NULL if none found */
12163  )
12164 {
12165  SCIP_EXPRGRAPHNODE** parentcands;
12166  int nparentcands;
12167  int parentcandssize;
12168  int i;
12169  int p;
12170 
12171  assert(exprgraph != NULL);
12172  assert(nchildren > 0);
12173  assert(children != NULL);
12174  assert(parent != NULL);
12175 
12176  *parent = NULL;
12177 
12178  /* create initial set of parent candidates as
12179  * all parents of first child that have the same operator type and the same number of children
12180  * additionally, some easy conditions for complex expression types:
12181  * if expression type is int/real/signpower, then compare also exponent,
12182  * if expression type is linear, then compare also constant part,
12183  * if expression type is quadratic, then compare also number of quadratic elements,
12184  * if expression type is polynomial, then compare also number of monmials and constant part
12185  */
12186  parentcandssize = children[0]->nparents;
12187  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize) );
12188  nparentcands = 0;
12189  for( p = 0; p < children[0]->nparents; ++p )
12190  if( children[0]->parents[p]->op == op &&
12191  children[0]->parents[p]->nchildren == nchildren &&
12192  (op != SCIP_EXPR_INTPOWER || opdata.intval == children[0]->parents[p]->data.intval) &&
12193  (op != SCIP_EXPR_REALPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12194  (op != SCIP_EXPR_SIGNPOWER || opdata.dbl == children[0]->parents[p]->data.dbl) && /*lint !e777*/
12195  (op != SCIP_EXPR_LINEAR || ((SCIP_Real*)opdata.data)[nchildren] == ((SCIP_Real*)children[0]->parents[p]->data.data)[nchildren]) && /*lint !e777*/
12196  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->nquadelems == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->nquadelems) &&
12197  (op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)opdata.data)->constant == ((SCIP_EXPRDATA_QUADRATIC*)children[0]->parents[p]->data.data)->constant) && /*lint !e777*/
12198  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->nmonomials == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->nmonomials) &&
12199  (op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)opdata.data)->constant == ((SCIP_EXPRDATA_POLYNOMIAL*)children[0]->parents[p]->data.data)->constant) /*lint !e777*/
12200  )
12201  {
12202  parentcands[nparentcands++] = children[0]->parents[p]; /*lint !e644*/
12203  }
12204 
12205  /* for all remaining children, remove parent candidates, that are not in their list of parents */
12206  for( i = 1; i < nchildren && nparentcands > 0; ++i )
12207  {
12208  p = 0;
12209  while( p < nparentcands )
12210  {
12211  /* if parentcands[p] is a parent of childnodes[i], then move last parent candidate to position p,
12212  * otherwise keep candidate and check next one
12213  */
12214  if( !exprgraphNodeIsParent(children[i], parentcands[p]) )
12215  {
12216  parentcands[p] = parentcands[nparentcands-1];
12217  --nparentcands;
12218  }
12219  else
12220  ++p;
12221  }
12222  }
12223 
12224  SCIPdebugMessage("check %d parent candidates for expr with operator %d and %d children\n", nparentcands, op, nchildren);
12225 
12226  if( nparentcands == 0 )
12227  {
12228  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, children[0]->nparents);
12229  return SCIP_OKAY;
12230  }
12231 
12232  /* at this point, all parents in parentcands have the nodes in children as children and are of the same operator type
12233  * check if there is also one which corresponds to same expression and store that one in *parent
12234  */
12235  switch( op )
12236  {
12237  /* commutative operands with no data */
12238  case SCIP_EXPR_PLUS :
12239  case SCIP_EXPR_MUL :
12240  case SCIP_EXPR_MIN :
12241  case SCIP_EXPR_MAX :
12242  case SCIP_EXPR_SUM :
12243  case SCIP_EXPR_PRODUCT:
12244  case SCIP_EXPR_SQUARE :
12245  case SCIP_EXPR_SQRT :
12246  case SCIP_EXPR_EXP :
12247  case SCIP_EXPR_LOG :
12248  case SCIP_EXPR_SIN :
12249  case SCIP_EXPR_COS :
12250  case SCIP_EXPR_TAN :
12251  /* case SCIP_EXPR_ERF : */
12252  /* case SCIP_EXPR_ERFI : */
12253  case SCIP_EXPR_ABS :
12254  case SCIP_EXPR_SIGN :
12255  {
12256  /* sort childnodes, if needed for later */
12257  if( nchildren > 2 )
12258  SCIPsortPtr((void**)children, exprgraphnodecomp, nchildren);
12259  for( p = 0; p < nparentcands; ++p )
12260  {
12261  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12262  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12263 
12264  if( nchildren == 1 )
12265  {
12266  assert(parentcands[p]->children[0] == children[0]);
12267  /* same operand, same child, so same expression */
12268  *parent = parentcands[p];
12269  break;
12270  }
12271  else if( nchildren == 2 )
12272  {
12273  /* We know that every node in children is also a child of parentcands[p].
12274  * However, if there are duplicates in children, then it can happen that not every child of parentcands[p] is also one of the children.
12275  * So only if children equals parentcands[p]->children in some permutation, the expressions are the same.
12276  */
12277  if( (parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1]) ||
12278  ( parentcands[p]->children[0] == children[1] && parentcands[p]->children[1] == children[0]) )
12279  {
12280  *parent = parentcands[p];
12281  break;
12282  }
12283  }
12284  else
12285  {
12286  /* as in the case for two nodes, we need to check whether parentcands[p]->children and children are equal up to permutation */
12287 
12288  /* sort children of parent candidate */
12289  SCIPsortPtr((void**)parentcands[p]->children, exprgraphnodecomp, nchildren);
12290 
12291  /* check if childnodes and parentcands[p]->children are the same */
12292  for( i = 0; i < nchildren; ++i )
12293  if( children[i] != parentcands[p]->children[i] )
12294  break;
12295  if( i == nchildren )
12296  {
12297  /* yeah, found an exact match */
12298  *parent = parentcands[p];
12299  break;
12300  }
12301  }
12302  }
12303 
12304  break;
12305  }
12306 
12307  /* non-commutative operands with two children */
12308  case SCIP_EXPR_MINUS :
12309  case SCIP_EXPR_DIV :
12310  {
12311  for( p = 0; p < nparentcands; ++p )
12312  {
12313  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12314  assert(parentcands[p]->nchildren == 2); /* that was the second criterium for adding a node to parentcands */
12315  /* order of operands matters, so check if childnodes have same order as children of parent candidate (and are the same nodes too) */
12316  if( parentcands[p]->children[0] == children[0] && parentcands[p]->children[1] == children[1] )
12317  {
12318  /* yeah, found one */
12319  *parent = parentcands[p];
12320  break;
12321  }
12322  }
12323 
12324  break;
12325  }
12326 
12327  /* operands with one child and data */
12328  case SCIP_EXPR_INTPOWER:
12329  {
12330  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12331  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12332  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12333  assert(parentcands[0]->data.intval == opdata.intval); /* that was another criterium for adding a node to parentcands */
12334 
12335  /* yeah, have one with same exponent */
12336  *parent = parentcands[0];
12337 
12338  break;
12339  }
12340 
12341  case SCIP_EXPR_REALPOWER:
12342  case SCIP_EXPR_SIGNPOWER:
12343  {
12344  assert(parentcands[0]->op == op); /* that was the first criterium for adding a node to parentcands */
12345  assert(parentcands[0]->nchildren == 1); /* that was the second criterium for adding a node to parentcands */
12346  assert(parentcands[0]->children[0] == children[0]); /* that's what exprgraphNodeIsParent should have ensured */
12347  assert(parentcands[0]->data.dbl == opdata.dbl); /* that was another criterium for adding a node to parentcands */ /*lint !e777*/
12348 
12349  /* yeah, have one with same exponent */
12350  *parent = parentcands[0];
12351 
12352  break;
12353  }
12354 
12355  /* commutative operands with n children and data */
12356  case SCIP_EXPR_LINEAR:
12357  {
12358  SCIP_Real* exprcoef;
12359  SCIP_Real* candcoef;
12360 
12361  exprcoef = (SCIP_Real*)opdata.data;
12362  /* sort childnodes, take care that children in expression are sorted the same way if given (so we don't mess up assignment of coefficients) */
12363  if( exprchildren != NULL )
12364  SCIPsortPtrPtrReal((void**)children, (void**)exprchildren, exprcoef, exprgraphnodecomp, nchildren);
12365  else
12366  SCIPsortPtrReal((void**)children, exprcoef, exprgraphnodecomp, nchildren);
12367  for( p = 0; p < nparentcands; ++p )
12368  {
12369  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12370  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12371 
12372  candcoef = (SCIP_Real*)parentcands[p]->data.data;
12373  assert(exprcoef[nchildren] == candcoef[nchildren]); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12374 
12375  /* sort children of parent candidate */
12376  SCIPsortPtrReal((void**)parentcands[p]->children, candcoef, exprgraphnodecomp, nchildren);
12377 
12378  /* check if children and coefficients in parent candidate and expression are the same */
12379  for( i = 0; i < nchildren; ++i )
12380  {
12381  if( children[i] != parentcands[p]->children[i] )
12382  break;
12383  if( exprcoef[i] != candcoef[i] ) /*lint !e777*/
12384  break;
12385  }
12386  if( i < nchildren )
12387  continue;
12388 
12389  /* yeah, found an exact match */
12390  *parent = parentcands[p];
12391  break;
12392  }
12393 
12394  break;
12395  }
12396 
12397  case SCIP_EXPR_QUADRATIC:
12398  {
12399  SCIP_EXPRDATA_QUADRATIC* exprdata;
12400  SCIP_Real* exprlincoef;
12401  SCIP_Real* candlincoef;
12402  SCIP_EXPRDATA_QUADRATIC* canddata;
12403  int* perm;
12404  int* invperm;
12405 
12406  exprdata = (SCIP_EXPRDATA_QUADRATIC*)opdata.data;
12407  exprlincoef = exprdata->lincoefs;
12408 
12409  /* sort children in expr and parentcands and update indices in quadelems accordingly, then sort quadelems again and compare */
12410 
12411  /* sort expr->children and childnodes and store inverse permutation in invperm */
12412  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12413  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12414  for( i = 0; i < nchildren; ++i )
12415  invperm[i] = i; /*lint !e644*/
12416 
12417  if( exprlincoef != NULL )
12418  if( exprchildren != NULL )
12419  SCIPsortPtrPtrRealInt((void**)children, (void**)exprchildren, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12420  else
12421  SCIPsortPtrRealInt((void**)children, exprlincoef, invperm, exprgraphnodecomp, nchildren);
12422  else
12423  if( exprchildren != NULL )
12424  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12425  else
12426  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12427 
12428  /* compute permutation from its inverse */
12429  for( i = 0; i < nchildren; ++i )
12430  perm[invperm[i]] = i; /*lint !e644*/
12431 
12432  /* apply permuation to exprdata->quadelems and sort again */
12433  for( i = 0; i < exprdata->nquadelems; ++i )
12434  {
12435  exprdata->quadelems[i].idx1 = perm[exprdata->quadelems[i].idx1];
12436  exprdata->quadelems[i].idx2 = perm[exprdata->quadelems[i].idx2];
12437  if( exprdata->quadelems[i].idx1 > exprdata->quadelems[i].idx2 )
12438  {
12439  int tmp;
12440  tmp = exprdata->quadelems[i].idx1;
12441  exprdata->quadelems[i].idx1 = exprdata->quadelems[i].idx2;
12442  exprdata->quadelems[i].idx2 = tmp;
12443  }
12444  }
12445  SCIPquadelemSort(exprdata->quadelems, exprdata->nquadelems);
12446  exprdata->sorted = TRUE;
12447 
12448  for( p = 0; p < nparentcands; ++p )
12449  {
12450  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12451  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12452 
12453  canddata = (SCIP_EXPRDATA_QUADRATIC*)parentcands[p]->data.data;
12454  candlincoef = canddata->lincoefs;
12455  assert(canddata->nquadelems == exprdata->nquadelems); /* that was a criterium for adding a node to parentcands */
12456  assert(canddata->constant == exprdata->constant); /* that was a criterium for adding a node to parentcands */ /*lint !e777*/
12457 
12458  /* sort parentcands[p]->children and store inverse permutation in invperm */
12459  for( i = 0; i < nchildren; ++i )
12460  invperm[i] = i;
12461 
12462  if( candlincoef != NULL )
12463  SCIPsortPtrRealInt((void**)parentcands[p]->children, candlincoef, invperm, exprgraphnodecomp, parentcands[p]->nchildren);
12464  else
12465  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12466 
12467  /* compute permutation from its inverse */
12468  for( i = 0; i < nchildren; ++i )
12469  perm[invperm[i]] = i;
12470 
12471  /* apply permutation to canddata->quadelems */
12472  for( i = 0; i < canddata->nquadelems; ++i )
12473  {
12474  canddata->quadelems[i].idx1 = perm[canddata->quadelems[i].idx1];
12475  canddata->quadelems[i].idx2 = perm[canddata->quadelems[i].idx2];
12476  if( canddata->quadelems[i].idx1 > canddata->quadelems[i].idx2 )
12477  {
12478  int tmp;
12479  tmp = canddata->quadelems[i].idx1;
12480  canddata->quadelems[i].idx1 = canddata->quadelems[i].idx2;
12481  canddata->quadelems[i].idx2 = tmp;
12482  }
12483  }
12484  SCIPquadelemSort(canddata->quadelems, canddata->nquadelems);
12485  canddata->sorted = TRUE;
12486 
12487  /* check if children and linear coefficients in parent candidate and expression are the same */
12488  for( i = 0; i < nchildren; ++i )
12489  {
12490  if( children[i] != parentcands[p]->children[i] )
12491  break;
12492  if( (exprlincoef == NULL ? 0.0 : exprlincoef[i]) != (candlincoef == NULL ? 0.0 : candlincoef[i]) ) /*lint !e777*/
12493  break;
12494  }
12495  if( i < nchildren )
12496  continue;
12497 
12498  assert(exprdata->nquadelems == canddata->nquadelems);
12499  for( i = 0; i < exprdata->nquadelems; ++i )
12500  {
12501  if( exprdata->quadelems[i].idx1 != canddata->quadelems[i].idx1 ||
12502  exprdata->quadelems[i].idx2 != canddata->quadelems[i].idx2 ||
12503  exprdata->quadelems[i].coef != canddata->quadelems[i].coef ) /*lint !e777*/
12504  break;
12505  }
12506  if( i == exprdata->nquadelems )
12507  {
12508  /* yeah, parentcands[p] is same quadratic expression as expr */
12509  *parent = parentcands[p];
12510  break;
12511  }
12512  }
12513 
12514  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12515  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12516 
12517  break;
12518  }
12519 
12520  /* @todo in one GlobalLib instance, two polynoms differ only in the sign of all coefficients, it would be nice to recognize this somehow */
12521  case SCIP_EXPR_POLYNOMIAL:
12522  {
12523  SCIP_EXPRDATA_POLYNOMIAL* exprdata;
12524  SCIP_EXPRDATA_POLYNOMIAL* canddata;
12525  int* perm;
12526  int* invperm;
12527 
12528  exprdata = (SCIP_EXPRDATA_POLYNOMIAL*)opdata.data;
12529 
12530  /* sort children in expr and parentcands and update child indices in polynomialdata, then sort monomials again and compare */
12531 
12532  /* sort exprchildren and childnodes and store inverse permutation in invperm */
12533  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren) );
12534  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &perm, nchildren) );
12535  for( i = 0; i < nchildren; ++i )
12536  invperm[i] = i; /*lint !e644*/
12537 
12538  if( exprchildren != NULL )
12539  SCIPsortPtrPtrInt((void**)children, (void**)exprchildren, invperm, exprgraphnodecomp, nchildren);
12540  else
12541  SCIPsortPtrInt((void**)children, invperm, exprgraphnodecomp, nchildren);
12542 
12543  /* compute permutation from its inverse */
12544  for( i = 0; i < nchildren; ++i )
12545  perm[invperm[i]] = i; /*lint !e644*/
12546 
12547  /* apply permutation to exprdata and sort again */
12548  polynomialdataApplyChildmap(exprdata, perm);
12549  polynomialdataSortMonomials(exprdata);
12550 
12551  for( p = 0; p < nparentcands; ++p )
12552  {
12553  assert(parentcands[p]->op == op); /* that was the first criterium for adding a node to parentcands */
12554  assert(parentcands[p]->nchildren == nchildren); /* that was the second criterium for adding a node to parentcands */
12555 
12556  canddata = (SCIP_EXPRDATA_POLYNOMIAL*)parentcands[p]->data.data;
12557  assert(canddata->nmonomials == exprdata->nmonomials); /* 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  SCIPsortPtrInt((void**)parentcands[p]->children, invperm, exprgraphnodecomp, nchildren);
12565 
12566  /* compute permutation from its inverse */
12567  for( i = 0; i < nchildren; ++i )
12568  perm[invperm[i]] = i;
12569 
12570  /* apply permutation to canddata and sort again */
12571  polynomialdataApplyChildmap(canddata, perm);
12572  polynomialdataSortMonomials(canddata);
12573 
12574  /* check if children are equal */
12575  for( i = 0; i < nchildren; ++i )
12576  if( children[i] != parentcands[p]->children[i] )
12577  break;
12578  if( i < nchildren )
12579  continue;
12580 
12581  /* check if monomials are equal */
12582  for( i = 0; i < exprdata->nmonomials; ++i )
12583  if( !SCIPexprAreMonomialsEqual(exprdata->monomials[i], canddata->monomials[i], 0.0) )
12584  break;
12585  if( i == exprdata->nmonomials )
12586  {
12587  /* yeah, parentcands[p] is same polynomial expression as expr */
12588  *parent = parentcands[p];
12589  break;
12590  }
12591  }
12592 
12593  BMSfreeBlockMemoryArray(exprgraph->blkmem, &perm, nchildren);
12594  BMSfreeBlockMemoryArray(exprgraph->blkmem, &invperm, nchildren);
12595 
12596  break;
12597  }
12598 
12599  case SCIP_EXPR_USER:
12600  {
12601  /* @todo need comparison function on user data to decide whether a parent candidate fits */
12602  break;
12603  }
12604 
12605  case SCIP_EXPR_VARIDX:
12606  case SCIP_EXPR_PARAM:
12607  case SCIP_EXPR_CONST:
12608  case SCIP_EXPR_LAST:
12609  SCIPerrorMessage("expression operand %d unexpected here\n", op);
12610  return SCIP_ERROR;
12611  }
12612 
12613  BMSfreeBlockMemoryArray(exprgraph->blkmem, &parentcands, parentcandssize);
12614 
12615  return SCIP_OKAY;
12616 }
12617 
12618 /** adds an expression into an expression graph
12619  *
12620  * Enables corresponding nodes.
12621  */
12622 static
12624  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12625  SCIP_EXPR* expr, /**< expression to add */
12626  void** vars, /**< variables corresponding to VARIDX expressions */
12627  SCIP_Real* params, /**< parameter values */
12628  SCIP_EXPRGRAPHNODE** exprnode, /**< buffer to store expression graph node corresponding to root of this expression */
12629  SCIP_Bool* exprnodeisnew /**< buffer to indicate whether the node in *exprnode has been newly created for this expression (otherwise, expression was already in graph) */
12630  )
12631 {
12632  SCIP_EXPRGRAPHNODE** childnodes;
12633  SCIP_Bool childisnew;
12634  SCIP_Bool nochildisnew;
12635  SCIP_EXPROPDATA opdata;
12636  int i;
12637 
12638  assert(exprgraph != NULL);
12639  assert(expr != NULL);
12640  assert(exprnode != NULL);
12641  assert(exprnodeisnew != NULL);
12642 
12643  if( expr->op == SCIP_EXPR_VARIDX )
12644  {
12645  /* find node corresponding to variable and add if not existing yet */
12646  assert(expr->nchildren == 0);
12647 
12648  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, 1, &vars[expr->data.intval], exprnode) );
12649  assert(*exprnode != NULL);
12650  assert((*exprnode)->op == SCIP_EXPR_VARIDX);
12651  assert((*exprnode)->data.intval >= 0);
12652  assert((*exprnode)->data.intval < exprgraph->nvars);
12653  assert(exprgraph->vars[(*exprnode)->data.intval] == vars[expr->data.intval]);
12654 
12655  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12656 
12657  return SCIP_OKAY;
12658  }
12659 
12660  if( expr->op == SCIP_EXPR_CONST )
12661  {
12662  /* find node corresponding to constant and add if not existing yet */
12663  assert(expr->nchildren == 0);
12664 
12665  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, expr->data.dbl, exprnode) );
12666  assert(*exprnode != NULL);
12667  assert((*exprnode)->op == SCIP_EXPR_CONST);
12668  assert((*exprnode)->data.dbl == expr->data.dbl); /*lint !e777*/
12669 
12670  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12671 
12672  return SCIP_OKAY;
12673  }
12674 
12675  if( expr->op == SCIP_EXPR_PARAM )
12676  {
12677  /* find node corresponding to constant corresponding to parameter and add if not existing yet */
12678  assert(expr->nchildren == 0);
12679  assert(params != NULL);
12680 
12681  SCIP_CALL( SCIPexprgraphAddConst(exprgraph, params[expr->data.intval], exprnode) );
12682  assert(*exprnode != NULL);
12683  assert((*exprnode)->op == SCIP_EXPR_CONST);
12684  assert((*exprnode)->data.dbl == params[expr->data.intval]); /*lint !e777*/
12685 
12686  *exprnodeisnew = (*exprnode)->nuses == 0 && (*exprnode)->nparents == 0;
12687 
12688  return SCIP_OKAY;
12689  }
12690 
12691  /* expression should be variable or constant or have children */
12692  assert(expr->nchildren > 0);
12693 
12694  /* add children expressions into expression graph
12695  * check if we can find a common parent
12696  */
12697  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren) );
12698  nochildisnew = TRUE;
12699  for( i = 0; i < expr->nchildren; ++i )
12700  {
12701  SCIP_CALL( exprgraphAddExpr(exprgraph, expr->children[i], vars, params, &childnodes[i], &childisnew) ); /*lint !e644*/
12702  assert(childnodes[i] != NULL);
12703  nochildisnew &= !childisnew; /*lint !e514*/
12704  }
12705 
12706  /* if all children were known already, check if there is also already a node for the expression that we aim to add */
12707  if( nochildisnew )
12708  {
12709  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, expr->nchildren, childnodes, expr->op, expr->data, expr->children, exprnode) );
12710 
12711  if( *exprnode != NULL )
12712  {
12713  /* node already existing, make sure it is enabled */
12714  (*exprnode)->enabled = TRUE;
12715  *exprnodeisnew = FALSE;
12716 
12717  /* SCIPdebugMessage("reused node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12718  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12719  * SCIPdebugPrintf("\n");
12720  */
12721 
12722  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12723  return SCIP_OKAY;
12724  }
12725  }
12726 
12727  SCIPdebugMessage("add expr with operator %d and %d children\n", expr->op, expr->nchildren);
12728 
12729  /* copy expression data */
12730  if( exprOpTable[expr->op].copydata != NULL )
12731  {
12732  SCIP_CALL( exprOpTable[expr->op].copydata(exprgraph->blkmem, expr->nchildren, expr->data, &opdata) );
12733  }
12734  else
12735  {
12736  opdata = expr->data;
12737  }
12738 
12739  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, exprnode, expr->op, opdata) );
12740  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *exprnode, -1, expr->nchildren, childnodes) );
12741  *exprnodeisnew = TRUE;
12742 
12743  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childnodes, expr->nchildren);
12744 
12745  /* SCIPdebugMessage("created new node %p (%d,%d) for expr ", (void*)*exprnode, (*exprnode)->depth, (*exprnode)->pos);
12746  * SCIPdebug( SCIPexprPrint(expr, messagehdlr, NULL, NULL, NULL, NULL) );
12747  * SCIPdebugPrintf("\n");
12748  */
12749 
12750  return SCIP_OKAY;
12751 }
12752 
12753 /** sets bounds in variable nodes to those stored in exprgraph's varbounds array */
12754 static
12756  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12757  SCIP_Bool* clearreverseprop, /**< flag to set if we had reset bound tightenings from reverse propagation */
12758  SCIP_Bool* boundchanged /**< buffer to store whether a variables bound has changes, compared to those stored in nodes */
12759  )
12760 {
12761  SCIP_EXPRGRAPHNODE* node;
12762  int i;
12763  int p;
12764 
12765  assert(exprgraph != NULL);
12766  assert(clearreverseprop != NULL);
12767  assert(boundchanged != NULL);
12768 
12769  *boundchanged = FALSE;
12770  for( i = 0; i < exprgraph->nvars; ++i )
12771  {
12772  node = exprgraph->varnodes[i];
12773 
12774  if( node->bounds.inf == exprgraph->varbounds[i].inf && /*lint !e777*/
12775  +node->bounds.sup == exprgraph->varbounds[i].sup ) /*lint !e777*/
12776  {
12778  continue;
12779  }
12780 
12781  if( exprgraph->varbounds[i].inf > exprgraph->varbounds[i].sup )
12782  {
12783  /* hmm, may happen due to numerics, let's be conservative and relax bounds to something that seems reasonable */
12784  SCIP_Real tmp;
12785 
12786  tmp = exprgraph->varbounds[i].inf;
12787  exprgraph->varbounds[i].inf = MIN(tmp, exprgraph->varbounds[i].sup);
12788  exprgraph->varbounds[i].sup = MAX(tmp, exprgraph->varbounds[i].sup);
12789  }
12790 
12791  if( exprgraph->varbounds[i].inf < node->bounds.inf ||
12792  +exprgraph->varbounds[i].sup > node->bounds.sup )
12793  {
12794  for( p = 0; p < node->nparents; ++p )
12796 
12797  node->bounds = exprgraph->varbounds[i];
12798  SCIPdebugMessage("registered relaxed bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12799 
12800  *boundchanged = TRUE;
12801 
12802  /* if a childs bounds are relaxed, then a previous reverse propagation may be invalid, so we have to clear its remainings */
12803  *clearreverseprop = TRUE;
12804  }
12805  else if( isLbBetter(1e-9, exprgraph->varbounds[i].inf, node->bounds.inf, node->bounds.sup) ||
12806  ( isUbBetter(1e-9, exprgraph->varbounds[i].sup, node->bounds.inf, node->bounds.sup)) )
12807  {
12808  for( p = 0; p < node->nparents; ++p )
12810 
12811  node->bounds = exprgraph->varbounds[i];
12812  SCIPdebugMessage("registered tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12813 
12814  *boundchanged = TRUE;
12815  }
12816  else
12817  {
12818  node->bounds = exprgraph->varbounds[i];
12819  SCIPdebugMessage("registered slightly tightened bound [%g,%g] of var %d for propagation\n", node->bounds.inf, node->bounds.sup, i);
12820  }
12821 
12823  }
12824 }
12825 
12826 /**@} */
12827 
12828 /**@name Expression graph node methods */
12829 /**@{ */
12830 
12831 /* In debug mode, the following methods are implemented as function calls to ensure
12832  * type validity.
12833  * In optimized mode, the methods are implemented as defines to improve performance.
12834  * However, we want to have them in the library anyways, so we have to undef the defines.
12835  */
12836 
12837 #undef SCIPexprgraphCaptureNode
12838 #undef SCIPexprgraphIsNodeEnabled
12839 #undef SCIPexprgraphGetNodeNChildren
12840 #undef SCIPexprgraphGetNodeChildren
12841 #undef SCIPexprgraphGetNodeNParents
12842 #undef SCIPexprgraphGetNodeParents
12843 #undef SCIPexprgraphGetNodeDepth
12844 #undef SCIPexprgraphGetNodePosition
12845 #undef SCIPexprgraphGetNodeOperator
12846 #undef SCIPexprgraphGetNodeOperatorIndex
12847 #undef SCIPexprgraphGetNodeOperatorReal
12848 #undef SCIPexprgraphGetNodeVar
12849 #undef SCIPexprgraphGetNodeRealPowerExponent
12850 #undef SCIPexprgraphGetNodeIntPowerExponent
12851 #undef SCIPexprgraphGetNodeSignPowerExponent
12852 #undef SCIPexprgraphGetNodeLinearCoefs
12853 #undef SCIPexprgraphGetNodeLinearConstant
12854 #undef SCIPexprgraphGetNodeQuadraticConstant
12855 #undef SCIPexprgraphGetNodeQuadraticLinearCoefs
12856 #undef SCIPexprgraphGetNodeQuadraticQuadElements
12857 #undef SCIPexprgraphGetNodeQuadraticNQuadElements
12858 #undef SCIPexprgraphGetNodePolynomialMonomials
12859 #undef SCIPexprgraphGetNodePolynomialNMonomials
12860 #undef SCIPexprgraphGetNodePolynomialConstant
12861 #undef SCIPexprgraphGetNodeUserData
12862 #undef SCIPexprgraphHasNodeUserEstimator
12863 #undef SCIPexprgraphGetNodeBounds
12864 #undef SCIPexprgraphGetNodeVal
12865 #undef SCIPexprgraphGetNodeCurvature
12866 
12867 /** captures node, i.e., increases number of uses */
12869  SCIP_EXPRGRAPHNODE* node /**< expression graph node to capture */
12870  )
12871 {
12872  assert(node->nuses >= 0);
12873 
12874  SCIPdebugMessage("capture node %p\n", (void*)node);
12875 
12876  ++node->nuses;
12877 }
12878 
12879 /** returns whether a node is currently enabled */
12881  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
12882  )
12883 {
12884  assert(node != NULL);
12885 
12886  return node->enabled;
12887 }
12888 
12889 /** gets number of children of a node in an expression graph */
12891  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12892  )
12893 {
12894  assert(node != NULL);
12895 
12896  return node->nchildren;
12897 }
12898 
12899 /** gets children of a node in an expression graph */
12901  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12902  )
12903 {
12904  assert(node != NULL);
12905 
12906  return node->children;
12907 }
12908 
12909 /** gets number of parents of a node in an expression graph */
12911  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12912  )
12913 {
12914  assert(node != NULL);
12915 
12916  return node->nparents;
12917 }
12918 
12919 /** gets parents of a node in an expression graph */
12921  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12922  )
12923 {
12924  assert(node != NULL);
12925 
12926  return node->parents;
12927 }
12928 
12929 /** gets depth of node in expression graph */
12931  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12932  )
12933 {
12934  assert(node != NULL);
12935 
12936  return node->depth;
12937 }
12938 
12939 /** gets position of node in expression graph at its depth level */
12941  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12942  )
12943 {
12944  assert(node != NULL);
12945 
12946  return node->pos;
12947 }
12948 
12949 /** gets operator of a node in an expression graph */
12951  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12952  )
12953 {
12954  assert(node != NULL);
12955 
12956  return node->op;
12957 }
12958 
12959 /** gives index belonging to a SCIP_EXPR_VARIDX or SCIP_EXPR_PARAM operand */
12961  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12962  )
12963 {
12964  assert(node != NULL);
12965  assert(node->op == SCIP_EXPR_VARIDX || node->op == SCIP_EXPR_PARAM);
12966 
12967  return node->data.intval;
12968 }
12969 
12970 /** gives real belonging to a SCIP_EXPR_CONST operand */
12972  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12973  )
12974 {
12975  assert(node != NULL);
12976  assert(node->op == SCIP_EXPR_CONST);
12977 
12978  return node->data.dbl;
12979 }
12980 
12981 /** gives variable belonging to a SCIP_EXPR_VARIDX expression */
12983  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
12984  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12985  )
12986 {
12987  assert(exprgraph != NULL);
12988  assert(node != NULL);
12989  assert(node->op == SCIP_EXPR_VARIDX);
12990  assert(node->data.intval >= 0);
12991  assert(node->data.intval < exprgraph->nvars);
12992 
12993  return exprgraph->vars[node->data.intval];
12994 }
12995 
12996 /** gives exponent belonging to a SCIP_EXPR_REALPOWER expression */
12998  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
12999  )
13000 {
13001  assert(node != NULL);
13002  assert(node->op == SCIP_EXPR_REALPOWER);
13003 
13004  return node->data.dbl;
13005 }
13006 
13007 /** gives exponent belonging to a SCIP_EXPR_INTPOWER expression */
13009  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13010  )
13011 {
13012  assert(node != NULL);
13013  assert(node->op == SCIP_EXPR_INTPOWER);
13014 
13015  return node->data.intval;
13016 }
13017 
13018 /** gives exponent belonging to a SCIP_EXPR_SIGNPOWER expression */
13020  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13021  )
13022 {
13023  assert(node != NULL);
13024  assert(node->op == SCIP_EXPR_SIGNPOWER);
13025 
13026  return node->data.dbl;
13027 }
13028 
13029 /** gives linear coefficients belonging to a SCIP_EXPR_LINEAR expression */
13031  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13032  )
13033 {
13034  assert(node != NULL);
13035  assert(node->op == SCIP_EXPR_LINEAR);
13036 
13037  return (SCIP_Real*)node->data.data;
13038 }
13039 
13040 /** gives constant belonging to a SCIP_EXPR_LINEAR expression */
13042  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13043  )
13044 {
13045  assert(node != NULL);
13046  assert(node->op == SCIP_EXPR_LINEAR);
13047  assert(node->data.data != NULL);
13048 
13049  return ((SCIP_Real*)node->data.data)[node->nchildren];
13050 }
13051 
13052 /** gives constant belonging to a SCIP_EXPR_QUADRATIC expression */
13054  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13055  )
13056 {
13057  assert(node != NULL);
13058  assert(node->op == SCIP_EXPR_QUADRATIC);
13059  assert(node->data.data != NULL);
13060 
13061  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->constant;
13062 }
13063 
13064 /** gives linear coefficients belonging to a SCIP_EXPR_QUADRATIC expression, or NULL if all coefficients are 0.0 */
13066  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13067  )
13068 {
13069  assert(node != NULL);
13070  assert(node->op == SCIP_EXPR_QUADRATIC);
13071  assert(node->data.data != NULL);
13072 
13073  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs;
13074 }
13075 
13076 /** gives quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13078  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13079  )
13080 {
13081  assert(node != NULL);
13082  assert(node->op == SCIP_EXPR_QUADRATIC);
13083  assert(node->data.data != NULL);
13084 
13085  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->quadelems;
13086 }
13087 
13088 /** gives number of quadratic elements belonging to a SCIP_EXPR_QUADRATIC expression */
13090  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13091  )
13092 {
13093  assert(node != NULL);
13094  assert(node->op == SCIP_EXPR_QUADRATIC);
13095  assert(node->data.data != NULL);
13096 
13097  return ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems;
13098 }
13099 
13100 /** gives the monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13102  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13103  )
13104 {
13105  assert(node != NULL);
13106  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13107  assert(node->data.data != NULL);
13108 
13109  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials;
13110 }
13111 
13112 /** gives the number of monomials belonging to a SCIP_EXPR_POLYNOMIAL expression */
13114  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13115  )
13116 {
13117  assert(node != NULL);
13118  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13119  assert(node->data.data != NULL);
13120 
13121  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials;
13122 }
13123 
13124 /** gives the constant belonging to a SCIP_EXPR_POLYNOMIAL expression */
13126  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13127  )
13128 {
13129  assert(node != NULL);
13130  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13131  assert(node->data.data != NULL);
13132 
13133  return ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->constant;
13134 }
13135 
13136 /** gives the curvature of a single monomial belonging to a SCIP_EXPR_POLYNOMIAL expression
13137  *
13138  * Assumes that curvature of children and bounds of children and node itself are valid.
13139  */
13141  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
13142  int monomialidx, /**< index of monomial */
13143  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
13144  SCIP_EXPRCURV* curv /**< buffer to store monomial curvature */
13145  )
13146 {
13147  SCIP_EXPRDATA_MONOMIAL* monomial;
13148  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
13149  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
13150  SCIP_INTERVAL* childbounds;
13151  SCIP_EXPRCURV* childcurv;
13152  SCIP_EXPRGRAPHNODE* child;
13153  int i;
13154 
13155  assert(node != NULL);
13156  assert(node->depth >= 0); /* node should be in graph */
13157  assert(node->pos >= 0); /* node should be in graph */
13158  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
13159  assert(node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID); /* we assume node bounds to be valid */
13160  assert(node->op == SCIP_EXPR_POLYNOMIAL);
13161  assert(node->data.data != NULL);
13162  assert(monomialidx >= 0);
13163  assert(monomialidx < ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials);
13164  assert(curv != NULL);
13165 
13166  if( SCIPintervalIsEmpty(infinity, node->bounds) )
13167  {
13168  *curv = SCIP_EXPRCURV_LINEAR;
13169  return SCIP_OKAY;
13170  }
13171 
13172  monomial = ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->monomials[monomialidx];
13173  assert(monomial != NULL);
13174 
13175  /* if many children, get large enough memory to store children bounds */
13176  if( monomial->nfactors > SCIP_EXPRESSION_MAXCHILDEST )
13177  {
13178  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, monomial->nfactors) );
13179  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, monomial->nfactors) );
13180  }
13181  else
13182  {
13183  childbounds = childboundsstatic;
13184  childcurv = childcurvstatic;
13185  }
13186 
13187  /* assemble bounds and curvature of children */
13188  for( i = 0; i < monomial->nfactors; ++i )
13189  {
13190  child = node->children[monomial->childidxs[i]];
13191  assert(child != NULL);
13192 
13193  /* child should have valid and non-empty bounds */
13194  assert(!(child->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
13195  assert(!SCIPintervalIsEmpty(infinity, child->bounds));
13196  /* nodes at depth 0 are always linear */
13197  assert(child->depth > 0 || child->curv == SCIP_EXPRCURV_LINEAR);
13198 
13199  childbounds[i] = child->bounds; /*lint !e644*/
13200  childcurv[i] = child->curv; /*lint !e644*/
13201  }
13202 
13203  /* check curvature */
13204  *curv = SCIPexprcurvMonomial(monomial->nfactors, monomial->exponents, NULL, childcurv, childbounds);
13205  *curv = SCIPexprcurvMultiply(monomial->coef, *curv);
13206 
13207  /* free memory, if allocated before */
13208  if( childbounds != childboundsstatic )
13209  {
13210  BMSfreeMemoryArray(&childbounds);
13211  BMSfreeMemoryArray(&childcurv);
13212  }
13213 
13214  return SCIP_OKAY;
13215 }
13216 
13217 /** gives the user data belonging to a SCIP_EXPR_USER expression */
13219  SCIP_EXPRGRAPHNODE* node
13220  )
13221 {
13222  assert(node != NULL);
13223  assert(node->op == SCIP_EXPR_USER);
13224  assert(node->data.data != NULL);
13225 
13226  return ((SCIP_EXPRDATA_USER*)node->data.data)->userdata;
13227 }
13228 
13229 /** indicates whether a user expression has the estimator callback defined */
13231  SCIP_EXPRGRAPHNODE* node
13232  )
13233 {
13234  assert(node != NULL);
13235  assert(node->op == SCIP_EXPR_USER);
13236  assert(node->data.data != NULL);
13237 
13238  return ((SCIP_EXPRDATA_USER*)node->data.data)->estimate != NULL;
13239 }
13240 
13241 /** gets bounds of a node in an expression graph */
13243  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13244  )
13245 {
13246  assert(node != NULL);
13247 
13248  return node->bounds;
13249 }
13250 
13251 /** gets value of expression associated to node from last evaluation call */
13253  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13254  )
13255 {
13256  assert(node != NULL);
13257 
13258  return node->value;
13259 }
13260 
13261 /** gets curvature of expression associated to node from last curvature check call */
13263  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
13264  )
13265 {
13266  assert(node != NULL);
13267 
13268  return node->curv;
13269 }
13270 
13271 /** creates an expression graph node */
13273  BMS_BLKMEM* blkmem, /**< block memory */
13274  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13275  SCIP_EXPROP op, /**< operator type of expression */
13276  ...
13277  )
13278 {
13279  va_list ap;
13280  SCIP_EXPROPDATA opdata;
13281 
13282  assert(blkmem != NULL);
13283  assert(node != NULL);
13284 
13285  *node = NULL;
13286 
13287  switch( op )
13288  {
13289  case SCIP_EXPR_VARIDX :
13290  case SCIP_EXPR_PARAM :
13291  case SCIP_EXPR_CONST :
13292  case SCIP_EXPR_LINEAR :
13293  case SCIP_EXPR_QUADRATIC :
13294  case SCIP_EXPR_POLYNOMIAL:
13295  case SCIP_EXPR_USER :
13296  {
13297  SCIPerrorMessage("cannot create node with operand %d via SCIPexprgraphCreateNode\n");
13298  SCIPABORT();
13299  return SCIP_ERROR; /*lint !e527*/
13300  }
13301 
13302  /* operands without data */
13303  case SCIP_EXPR_PLUS :
13304  case SCIP_EXPR_MINUS :
13305  case SCIP_EXPR_MUL :
13306  case SCIP_EXPR_DIV :
13307  case SCIP_EXPR_MIN :
13308  case SCIP_EXPR_MAX :
13309  case SCIP_EXPR_SQUARE :
13310  case SCIP_EXPR_SQRT :
13311  case SCIP_EXPR_EXP :
13312  case SCIP_EXPR_LOG :
13313  case SCIP_EXPR_SIN :
13314  case SCIP_EXPR_COS :
13315  case SCIP_EXPR_TAN :
13316  /* case SCIP_EXPR_ERF : */
13317  /* case SCIP_EXPR_ERFI: */
13318  case SCIP_EXPR_ABS :
13319  case SCIP_EXPR_SIGN :
13320  case SCIP_EXPR_SUM :
13321  case SCIP_EXPR_PRODUCT:
13322  opdata.data = NULL;
13323  break;
13324 
13325  case SCIP_EXPR_REALPOWER:
13326  case SCIP_EXPR_SIGNPOWER:
13327  {
13328  va_start(ap, op ); /*lint !e838*/
13329  opdata.dbl = va_arg( ap, SCIP_Real); /*lint !e416 !e826*/
13330  va_end( ap ); /*lint !e826*/
13331 
13332  break;
13333  }
13334 
13335  case SCIP_EXPR_INTPOWER:
13336  {
13337  va_start(ap, op ); /*lint !e838*/
13338  opdata.intval = va_arg( ap, int); /*lint !e416 !e826*/
13339  va_end( ap ); /*lint !e826*/
13340 
13341  break;
13342  }
13343 
13344  case SCIP_EXPR_LAST:
13345  SCIPABORT();
13346  return SCIP_INVALIDDATA; /*lint !e527*/
13347  }
13348 
13349  SCIP_CALL( exprgraphCreateNode(blkmem, node, op, opdata) ); /*lint !e644*/
13350 
13351  return SCIP_OKAY;
13352 }
13353 
13354 /** creates an expression graph node for a linear expression */
13356  BMS_BLKMEM* blkmem, /**< block memory */
13357  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13358  int ncoefs, /**< number of coefficients */
13359  SCIP_Real* coefs, /**< coefficients of linear expression */
13360  SCIP_Real constant /**< constant of linear expression */
13361  )
13362 {
13363  SCIP_EXPROPDATA opdata;
13364  SCIP_Real* data;
13365 
13366  assert(blkmem != NULL);
13367  assert(node != NULL);
13368 
13369  /* we store the coefficients and the constant in a single array and make this our operand data */
13370  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &data, ncoefs + 1) );
13371  BMScopyMemoryArray(data, coefs, ncoefs); /*lint !e644*/
13372  data[ncoefs] = constant;
13373 
13374  opdata.data = data;
13375  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_LINEAR, opdata) );
13376 
13377  return SCIP_OKAY;
13378 }
13379 
13380 /** creates an expression graph node for a quadratic expression */
13382  BMS_BLKMEM* blkmem, /**< block memory */
13383  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13384  int nchildren, /**< number of children */
13385  SCIP_Real* lincoefs, /**< linear coefficients for children, or NULL */
13386  int nquadelems, /**< number of quadratic elements */
13387  SCIP_QUADELEM* quadelems, /**< quadratic elements, or NULL if nquadelems == 0 */
13388  SCIP_Real constant /**< constant */
13389  )
13390 {
13391  SCIP_EXPROPDATA opdata;
13393 
13394  assert(blkmem != NULL);
13395  assert(node != NULL);
13396  assert(quadelems != NULL || nquadelems == 0);
13397 
13398  SCIP_CALL( quadraticdataCreate(blkmem, &data, constant, nchildren, lincoefs, nquadelems, quadelems) );
13399 
13400  opdata.data = data;
13401  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_QUADRATIC, opdata) );
13402 
13403  return SCIP_OKAY;
13404 }
13405 
13406 /** creates an expression graph node for a polynomial expression */
13408  BMS_BLKMEM* blkmem, /**< block memory */
13409  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13410  int nmonomials, /**< number of monomials */
13411  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13412  SCIP_Real constant, /**< constant of polynomial */
13413  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13414  )
13415 {
13416  SCIP_EXPROPDATA opdata;
13418 
13419  assert(blkmem != NULL);
13420  assert(node != NULL);
13421  assert(monomials != NULL || nmonomials == 0);
13422 
13423  SCIP_CALL( polynomialdataCreate(blkmem, &data, nmonomials, monomials, constant, copymonomials) );
13424 
13425  opdata.data = data;
13426  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_POLYNOMIAL, opdata) );
13427 
13428  return SCIP_OKAY;
13429 }
13430 
13431 /** adds monomials to an expression graph node that is a polynomial expression */
13433  BMS_BLKMEM* blkmem, /**< block memory */
13434  SCIP_EXPRGRAPHNODE* node, /**< store expression graph node with polynomial operator */
13435  int nmonomials, /**< number of monomials */
13436  SCIP_EXPRDATA_MONOMIAL** monomials, /**< monomials */
13437  SCIP_Bool copymonomials /**< whether to copy monomials or to assume ownership */
13438  )
13439 {
13440  assert(blkmem != NULL);
13441  assert(node != NULL);
13443  assert(monomials != NULL || nmonomials == 0);
13444 
13445  SCIP_CALL( polynomialdataAddMonomials(blkmem, (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data, nmonomials, monomials, copymonomials) );
13446 
13447  return SCIP_OKAY;
13448 }
13449 
13450 /** creates an expression graph node for a user expression */
13452  BMS_BLKMEM* blkmem, /**< block memory */
13453  SCIP_EXPRGRAPHNODE** node, /**< buffer to store expression graph node */
13454  SCIP_USEREXPRDATA* data, /**< user data for expression, node assumes ownership */
13455  SCIP_EXPRINTCAPABILITY evalcapability, /**< evaluation capability */
13456  SCIP_DECL_USEREXPREVAL ((*eval)), /**< evaluation function */
13457  SCIP_DECL_USEREXPRINTEVAL ((*inteval)), /**< interval evaluation function */
13458  SCIP_DECL_USEREXPRCURV ((*curv)), /**< curvature check function */
13459  SCIP_DECL_USEREXPRPROP ((*prop)), /**< interval propagation function */
13460  SCIP_DECL_USEREXPRESTIMATE ((*estimate)), /**< estimation function, or NULL if convex, concave, or not implemented */
13461  SCIP_DECL_USEREXPRCOPYDATA ((*copydata)), /**< expression data copy function, or NULL if nothing to copy */
13462  SCIP_DECL_USEREXPRFREEDATA ((*freedata)), /**< expression data free function, or NULL if nothing to free */
13463  SCIP_DECL_USEREXPRPRINT ((*print)) /**< expression print function, or NULL for default string "user" */
13464  )
13465 {
13466  SCIP_EXPROPDATA opdata;
13467  SCIP_EXPRDATA_USER* exprdata;
13468 
13469  assert(blkmem != NULL);
13470  assert(node != NULL);
13471  assert(eval != NULL);
13472  assert((evalcapability & SCIP_EXPRINTCAPABILITY_FUNCVALUE) != 0); /* the function evaluation is not optional */
13473  assert(((evalcapability & SCIP_EXPRINTCAPABILITY_INTFUNCVALUE) == 0) || inteval != NULL); /* if capability says it can do interval evaluation, then the corresponding callback needs to be provided */
13474  assert(copydata != NULL || data == NULL);
13475  assert(freedata != NULL || data == NULL);
13476 
13477  SCIP_ALLOC( BMSallocBlockMemory(blkmem, &exprdata) );
13478 
13479  exprdata->userdata = data;
13480  exprdata->evalcapability = evalcapability;
13481  exprdata->eval = eval;
13482  exprdata->estimate = estimate;
13483  exprdata->inteval = inteval;
13484  exprdata->curv = curv;
13485  exprdata->prop = prop;
13486  exprdata->copydata = copydata;
13487  exprdata->freedata = freedata;
13488  exprdata->print = print;
13489 
13490  opdata.data = (void*) exprdata;
13491 
13492  SCIP_CALL( exprgraphCreateNode(blkmem, node, SCIP_EXPR_USER, opdata) );
13493 
13494  return SCIP_OKAY;
13495 }
13496 
13497 /** given a node of an expression graph, splitup a linear part which variables are not used somewhere else in the same expression
13498  *
13499  * E.g., if the expression is 1 + x + y + y^2, one gets 1 + x and the node remains at y + y^2.
13500  * If the node is a linear expression, it may be freed.
13501  * If it is not linear, the node may change, i.e., the remaining nonlinear part may be stored in a new node.
13502  * It is assumed that the user had captured the node.
13503  * It is assumed that the expression graph has been simplified before.
13504  */
13506  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
13507  SCIP_EXPRGRAPHNODE** node, /**< expression graph node where to splitup linear part */
13508  int linvarssize, /**< length of linvars and lincoefs arrays */
13509  int* nlinvars, /**< buffer to store length of linear term that have been splitup */
13510  void** linvars, /**< buffer to store variables of linear part */
13511  SCIP_Real* lincoefs, /**< buffer to store coefficients of linear part */
13512  SCIP_Real* constant /**< buffer to store constant part */
13513  )
13514 {
13515  int orignvars;
13516  int* varsusage;
13517  SCIP_EXPRGRAPHNODE* orignode;
13518  SCIP_Bool havechange;
13519  int i;
13520 
13521  assert(exprgraph != NULL);
13522  assert(node != NULL);
13523  assert(*node != NULL);
13524  assert((*node)->nuses > 0);
13525  assert(nlinvars != NULL);
13526  assert(linvars != NULL || linvarssize == 0);
13527  assert(lincoefs != NULL || linvarssize == 0);
13528  assert(constant != NULL);
13529 
13530  *constant = 0.0;
13531  *nlinvars = 0;
13532 
13533  SCIPdebugMessage("split off linear part for %s node %p (%d,%d)\n", SCIPexpropGetName((*node)->op), (void*)*node, (*node)->depth, (*node)->pos);
13534 
13535  /* do some obvious and easy cases */
13536  switch( (*node)->op )
13537  {
13538  case SCIP_EXPR_VARIDX:
13539  {
13540  if( linvarssize >= 1 )
13541  {
13542  *nlinvars = 1;
13543  linvars[0] = exprgraph->vars[(*node)->data.intval]; /*lint !e613*/
13544  lincoefs[0] = 1.0; /*lint !e613*/
13545 
13546  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13547  }
13548  return SCIP_OKAY;
13549  }
13550 
13551  case SCIP_EXPR_CONST:
13552  {
13553  *constant = (*node)->data.dbl;
13554  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13555 
13556  return SCIP_OKAY;
13557  }
13558 
13559  case SCIP_EXPR_REALPOWER:
13560  case SCIP_EXPR_SIGNPOWER:
13561  {
13562  if( (*node)->data.dbl == 1.0 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13563  {
13564  *nlinvars = 1;
13565  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13566  lincoefs[0] = 1.0; /*lint !e613*/
13567 
13568  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13569  }
13570  return SCIP_OKAY;
13571  }
13572 
13573  case SCIP_EXPR_INTPOWER:
13574  {
13575  if( (*node)->data.intval == 1 && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13576  {
13577  *nlinvars = 1;
13578  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13579  lincoefs[0] = 1.0; /*lint !e613*/
13580 
13581  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13582  }
13583  return SCIP_OKAY;
13584  }
13585 
13586  case SCIP_EXPR_PLUS:
13587  {
13588  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13589  {
13590  *constant = (*node)->children[0]->data.dbl;
13591  *nlinvars = 1;
13592  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13593  lincoefs[0] = 1.0; /*lint !e613*/
13594 
13595  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13596 
13597  return SCIP_OKAY;
13598  }
13599  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13600  {
13601  *constant = (*node)->children[1]->data.dbl;
13602  *nlinvars = 1;
13603  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13604  lincoefs[0] = 1.0; /*lint !e613*/
13605 
13606  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13607 
13608  return SCIP_OKAY;
13609  }
13610  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13611  {
13612  *nlinvars = 2;
13613  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13614  lincoefs[0] = 1.0; /*lint !e613*/
13615  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13616  lincoefs[1] = 1.0; /*lint !e613*/
13617 
13618  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13619 
13620  return SCIP_OKAY;
13621  }
13622  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13623  {
13624  /* handle this one later */
13625  break;
13626  }
13627  return SCIP_OKAY;
13628  }
13629 
13630  case SCIP_EXPR_MINUS:
13631  {
13632  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13633  {
13634  *constant = (*node)->children[0]->data.dbl;
13635  *nlinvars = 1;
13636  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13637  lincoefs[0] = -1.0; /*lint !e613*/
13638 
13639  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13640 
13641  return SCIP_OKAY;
13642  }
13643  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13644  {
13645  *constant = -(*node)->children[1]->data.dbl;
13646  *nlinvars = 1;
13647  linvars[0] = exprgraph->vars[(*node)->children[0]->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  else if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 2 )
13655  {
13656  *nlinvars = 2;
13657  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13658  lincoefs[0] = 1.0; /*lint !e613*/
13659  linvars[1] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13660  lincoefs[1] = -1.0; /*lint !e613*/
13661 
13662  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13663 
13664  return SCIP_OKAY;
13665  }
13666  else if( ((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX) && linvarssize >= 1 )
13667  {
13668  /* handle this one later */
13669  break;
13670  }
13671  return SCIP_OKAY;
13672  }
13673 
13674  case SCIP_EXPR_MUL:
13675  {
13676  if( (*node)->children[0]->op == SCIP_EXPR_CONST && (*node)->children[1]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13677  {
13678  *nlinvars = 1;
13679  linvars[0] = exprgraph->vars[(*node)->children[1]->data.intval]; /*lint !e613*/
13680  lincoefs[0] = (*node)->children[0]->data.dbl; /*lint !e613*/
13681 
13682  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13683  }
13684  else if( (*node)->children[1]->op == SCIP_EXPR_CONST && (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13685  {
13686  *nlinvars = 1;
13687  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13688  lincoefs[0] = (*node)->children[1]->data.dbl; /*lint !e613*/
13689 
13690  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13691  }
13692  return SCIP_OKAY;
13693  }
13694 
13695  case SCIP_EXPR_DIV:
13696  {
13697  if( (*node)->children[1]->op != SCIP_EXPR_CONST )
13698  return SCIP_OKAY;
13699 
13700  if( (*node)->children[0]->op == SCIP_EXPR_VARIDX && linvarssize >= 1 )
13701  {
13702  *nlinvars = 1;
13703  linvars[0] = exprgraph->vars[(*node)->children[0]->data.intval]; /*lint !e613*/
13704  lincoefs[0] = 1.0/(*node)->children[1]->data.dbl; /*lint !e613*/
13705 
13706  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13707  }
13708  return SCIP_OKAY;
13709  }
13710 
13711  case SCIP_EXPR_SQUARE:
13712  case SCIP_EXPR_SQRT:
13713  case SCIP_EXPR_EXP:
13714  case SCIP_EXPR_LOG:
13715  case SCIP_EXPR_SIN:
13716  case SCIP_EXPR_COS:
13717  case SCIP_EXPR_TAN:
13718  /* case SCIP_EXPR_ERF: */
13719  /* case SCIP_EXPR_ERFI: */
13720  case SCIP_EXPR_ABS:
13721  case SCIP_EXPR_SIGN:
13722  case SCIP_EXPR_MIN:
13723  case SCIP_EXPR_MAX:
13724  return SCIP_OKAY;
13725 
13726  case SCIP_EXPR_PRODUCT:
13727  case SCIP_EXPR_USER:
13728  return SCIP_OKAY;
13729 
13730  case SCIP_EXPR_SUM:
13731  case SCIP_EXPR_LINEAR:
13732  case SCIP_EXPR_QUADRATIC:
13733  case SCIP_EXPR_POLYNOMIAL:
13734  default:
13735  {
13736  /* check if there is a child that is a variable */
13737  for( i = 0; i < (*node)->nchildren; ++i )
13738  {
13739  if( (*node)->children[i]->op == SCIP_EXPR_VARIDX )
13740  break;
13741  }
13742 
13743  if( i == (*node)->nchildren )
13744  return SCIP_OKAY;
13745 
13746  break;
13747  }
13748  } /*lint !e788*/
13749 
13750  /* count how often variables are used in this expression */
13751  assert(exprgraph->nvars > 0); /* in a simplified expr graph with no variables, there can only be const nodes, but these were handled above */
13752  orignvars = exprgraph->nvars;
13753  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varsusage, exprgraph->nvars) );
13754  BMSclearMemoryArray(varsusage, exprgraph->nvars); /*lint !e644*/
13755 
13756  exprgraphNodeGetVarsUsage(*node, varsusage);
13757 
13758  /* duplicate node if it has parents or more than one user */
13759  orignode = NULL;
13760  if( (*node)->nparents > 0 || (*node)->nuses > 1 )
13761  {
13762  SCIP_EXPROPDATA data;
13763 
13764  orignode = *node;
13765 
13766  if( exprOpTable[orignode->op].copydata != NULL )
13767  {
13768  SCIP_CALL( exprOpTable[orignode->op].copydata(exprgraph->blkmem, orignode->nchildren, orignode->data, &data) );
13769  }
13770  else
13771  data = orignode->data;
13772 
13773  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, node, orignode->op, data) );
13774  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *node, -1, orignode->nchildren, orignode->children) );
13775  SCIPexprgraphCaptureNode(*node);
13776  }
13777 
13778  havechange = FALSE;
13779  /* split up constant and linear part */
13780  switch( (*node)->op )
13781  {
13782  case SCIP_EXPR_PLUS:
13783  case SCIP_EXPR_MINUS:
13784  {
13785  SCIP_EXPRGRAPHNODE* varchild;
13786  SCIP_EXPRGRAPHNODE* otherchild;
13787  int varidx;
13788 
13789  /* we had looked at this above already and only continued if exactly one node is still a child and linvarssize is >= 1 */
13790  assert((*node)->children[0]->op == SCIP_EXPR_VARIDX || (*node)->children[1]->op == SCIP_EXPR_VARIDX);
13791  assert((*node)->children[0]->op != SCIP_EXPR_VARIDX || (*node)->children[1]->op != SCIP_EXPR_VARIDX);
13792  assert(linvarssize >= 1);
13793 
13794  varchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[0] : (*node)->children[1];
13795  otherchild = (*node)->children[0]->op == SCIP_EXPR_VARIDX ? (*node)->children[1] : (*node)->children[0];
13796  varidx = varchild->data.intval;
13797  /* if variable is used in other child (which should be nonlinear), we don't take it */
13798  if( varsusage[varidx] > 1 )
13799  break;
13800 
13801  /* add to linear variables */
13802  *nlinvars = 1;
13803  linvars[0] = exprgraph->vars[varidx]; /*lint !e613*/
13804  if( (*node)->op == SCIP_EXPR_MINUS && varchild == (*node)->children[1] )
13805  lincoefs[0] = -1.0; /*lint !e613*/
13806  else
13807  lincoefs[0] = 1.0; /*lint !e613*/
13808 
13809  if( (*node)->op == SCIP_EXPR_PLUS || (*node)->children[0] == otherchild )
13810  {
13811  /* replace *node by otherchild */
13812  SCIPexprgraphCaptureNode(otherchild);
13813  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13814  *node = otherchild;
13815  }
13816  else
13817  {
13818  SCIP_Real* lindata;
13819 
13820  /* turn *node into linear expression -1.0 * otherchild */
13821 
13822  /* reduce to one child */
13823  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, 2, 1) ); /*lint !e506*/
13824  (*node)->children[0] = otherchild;
13825  (*node)->nchildren = 1;
13826  (*node)->op = SCIP_EXPR_LINEAR;
13827 
13828  /* setup linear data -1.0 * child0 + 0.0 */
13829  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, 2) ); /*lint !e506*/
13830  lindata[0] = -1.0;
13831  lindata[1] = 0.0;
13832  (*node)->data.data = (void*)lindata;
13833 
13834  /* remove *node as parent of varchild */
13835  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &varchild, *node) );
13836  }
13837 
13838  havechange = TRUE;
13839 
13840  break;
13841  }
13842 
13843  case SCIP_EXPR_SUM:
13844  {
13845  int nchildren;
13846 
13847  i = 0;
13848  nchildren = (*node)->nchildren;
13849  while( i < nchildren )
13850  {
13851  /* sort out constants */
13852  if( (*node)->children[i]->op == SCIP_EXPR_CONST )
13853  {
13854  *constant += (*node)->children[i]->data.dbl;
13855  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13856 
13857  if( i < nchildren-1 )
13858  {
13859  (*node)->children[i] = (*node)->children[nchildren-1];
13860  (*node)->children[nchildren-1] = NULL;
13861  }
13862  --nchildren;
13863 
13864  continue;
13865  }
13866 
13867  /* keep every child that is not a constant or variable */
13868  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13869  {
13870  ++i;
13871  continue;
13872  }
13873 
13874  /* skip variables that are used in other parts of the expression */
13875  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13876  {
13877  ++i;
13878  continue;
13879  }
13880 
13881  /* move variable into linear part, if still space */
13882  if( *nlinvars < linvarssize )
13883  {
13884  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13885  lincoefs[*nlinvars] = 1.0; /*lint !e613*/
13886  ++*nlinvars;
13887 
13888  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13889  if( i < nchildren-1 )
13890  {
13891  (*node)->children[i] = (*node)->children[nchildren-1];
13892  (*node)->children[nchildren-1] = NULL;
13893  }
13894  --nchildren;
13895 
13896  continue;
13897  }
13898  }
13899  assert(i == nchildren);
13900 
13901  if( nchildren == 0 )
13902  {
13903  /* all children were removed */
13904  havechange = TRUE;
13905  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
13906  (*node)->nchildren = 0;
13907  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13908  break;
13909  }
13910 
13911  if( nchildren < (*node)->nchildren )
13912  {
13913  /* some children were removed */
13914  havechange = TRUE;
13915  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
13916  (*node)->nchildren = nchildren;
13917  }
13918 
13919  if( havechange && (*node)->nchildren == 1 )
13920  {
13921  /* replace node by its child */
13922  SCIP_EXPRGRAPHNODE* child;
13923 
13924  child = (*node)->children[0];
13925  SCIPexprgraphCaptureNode(child);
13926  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
13927  *node = child;
13928 
13929  break;
13930  }
13931 
13932  break;
13933  }
13934 
13935  case SCIP_EXPR_LINEAR:
13936  {
13937  int nchildren;
13938  SCIP_Real* coefs;
13939 
13940  coefs = (SCIP_Real*)(*node)->data.data;
13941  assert(coefs != NULL);
13942 
13943  /* remove constant, if nonzero */
13944  if( coefs[(*node)->nchildren] != 0.0 )
13945  {
13946  *constant = coefs[(*node)->nchildren];
13947  coefs[(*node)->nchildren] = 0.0;
13948  havechange = TRUE;
13949  }
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 += coefs[i] * (*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  coefs[i] = coefs[nchildren-1];
13966  coefs[nchildren-1] = 0.0;
13967  }
13968  --nchildren;
13969 
13970  continue;
13971  }
13972 
13973  /* keep everything that is not a constant or variable */
13974  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
13975  {
13976  ++i;
13977  continue;
13978  }
13979 
13980  /* skip variables that are used in other parts of the expression */
13981  if( varsusage[(*node)->children[i]->data.intval] > 1 )
13982  {
13983  ++i;
13984  continue;
13985  }
13986 
13987  /* move variable into linear part, if still space */
13988  if( *nlinvars < linvarssize )
13989  {
13990  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
13991  lincoefs[*nlinvars] = coefs[i]; /*lint !e613*/
13992  ++*nlinvars;
13993 
13994  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
13995  if( i < nchildren-1 )
13996  {
13997  (*node)->children[i] = (*node)->children[nchildren-1];
13998  (*node)->children[nchildren-1] = NULL;
13999  coefs[i] = coefs[nchildren-1];
14000  coefs[nchildren-1] = 0.0;
14001  }
14002  --nchildren;
14003 
14004  continue;
14005  }
14006  }
14007  assert(i == nchildren);
14008 
14009  if( nchildren == 0 )
14010  {
14011  /* all children were removed */
14012  havechange = TRUE;
14013  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14014  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1);
14015  (*node)->data.data = NULL;
14016  (*node)->nchildren = 0;
14017  (*node)->op = SCIP_EXPR_SUM; /* because we freed the constraint data already */
14018  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14019  break;
14020  }
14021 
14022  if( nchildren < (*node)->nchildren )
14023  {
14024  /* some children were removed */
14025  havechange = TRUE;
14026  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14027  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &coefs, (*node)->nchildren+1, nchildren+1) );
14028  coefs[nchildren] = 0.0;
14029  (*node)->data.data = (void*)coefs;
14030  (*node)->nchildren = nchildren;
14031  }
14032 
14033  if( havechange && (*node)->nchildren == 1 && coefs[0] == 1.0 )
14034  {
14035  /* replace node by its child */
14036  SCIP_EXPRGRAPHNODE* child;
14037 
14038  child = (*node)->children[0];
14039  SCIPexprgraphCaptureNode(child);
14040  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14041  *node = child;
14042 
14043  break;
14044  }
14045 
14046  break;
14047  }
14048 
14049  case SCIP_EXPR_QUADRATIC:
14050  {
14051  SCIP_EXPRDATA_QUADRATIC* quaddata;
14052  SCIP_Bool* childused;
14053  int* childmap;
14054  int nchildren;
14055 
14056  quaddata = (SCIP_EXPRDATA_QUADRATIC*)(*node)->data.data;
14057  assert(quaddata != NULL);
14058 
14059  /* remove constant, if nonzero */
14060  if( quaddata->constant != 0.0 )
14061  {
14062  *constant = quaddata->constant;
14063  quaddata->constant = 0.0;
14064  havechange = TRUE;
14065  }
14066 
14067  /* if there is no linear part or no space left for linear variables, then stop */
14068  if( quaddata->lincoefs != NULL || linvarssize == 0 )
14069  break;
14070 
14071  /* check which childs are used in quadratic terms */
14072  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14073  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14074 
14075  for( i = 0; i < quaddata->nquadelems; ++i )
14076  {
14077  childused[quaddata->quadelems[i].idx1] = TRUE;
14078  childused[quaddata->quadelems[i].idx2] = TRUE;
14079  }
14080 
14081  /* alloc space for mapping of children indices */
14082  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren) );
14083 
14084  nchildren = (*node)->nchildren;
14085  for( i = 0; i < nchildren; ++i )
14086  {
14087  childmap[i] = i; /*lint !e644*/
14088  if( *nlinvars >= linvarssize )
14089  continue;
14090  /* skip child if not variable or also used in quadratic part or other parts of expression */
14091  if( (*node)->children[i]->op != SCIP_EXPR_VARIDX )
14092  continue;
14093  if( childused[i] )
14094  continue;
14095  if( varsusage[(*node)->children[i]->data.intval] > 1 )
14096  continue;
14097 
14098  /* put variable into linear part */
14099  linvars[*nlinvars] = exprgraph->vars[(*node)->children[i]->data.intval]; /*lint !e613*/
14100  lincoefs[*nlinvars] = quaddata->lincoefs[i]; /*lint !e613*/
14101  quaddata->lincoefs[i] = 0.0;
14102  ++*nlinvars;
14103 
14104  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14105 
14106  /* move last child to position i */
14107  if( i < nchildren-1 )
14108  {
14109  (*node)->children[i] = (*node)->children[nchildren-1];
14110  quaddata->lincoefs[i] = quaddata->lincoefs[nchildren-1];
14111  childused[i] = childused[nchildren-1];
14112  childmap[nchildren-1] = i;
14113  }
14114  --nchildren;
14115  childmap[i] = -1;
14116 
14117  havechange = TRUE;
14118  --i; /* look at i again */
14119  }
14120 
14121  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren); /*lint !e850*/
14122 
14123  if( nchildren < (*node)->nchildren )
14124  {
14125  /* apply childmap to quadratic term */
14126  for( i = 0; i < quaddata->nquadelems; ++i )
14127  {
14128  quaddata->quadelems[i].idx1 = childmap[quaddata->quadelems[i].idx1];
14129  quaddata->quadelems[i].idx2 = childmap[quaddata->quadelems[i].idx2];
14130  if( quaddata->quadelems[i].idx1 > quaddata->quadelems[i].idx2 )
14131  {
14132  int tmp;
14133  tmp = quaddata->quadelems[i].idx1;
14134  quaddata->quadelems[i].idx1 = quaddata->quadelems[i].idx2;
14135  quaddata->quadelems[i].idx2 = tmp;
14136  }
14137  }
14138  quaddata->sorted = FALSE;
14139  }
14140  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, (*node)->nchildren);
14141 
14142  if( nchildren == 0 )
14143  {
14144  /* all children were removed (so it was actually a linear expression) */
14145  havechange = TRUE;
14146  BMSfreeBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren);
14147  exprFreeDataQuadratic(exprgraph->blkmem, (*node)->nchildren, (*node)->data);
14148  (*node)->data.data = NULL;
14149  (*node)->nchildren = 0;
14150  (*node)->op = SCIP_EXPR_SUM;
14151  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14152  break;
14153  }
14154 
14155  if( nchildren < (*node)->nchildren )
14156  {
14157  /* reduce number of children */
14158  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &(*node)->children, (*node)->nchildren, nchildren) );
14159  SCIP_ALLOC( BMSreallocBlockMemoryArray(exprgraph->blkmem, &quaddata->lincoefs, (*node)->nchildren, nchildren) );
14160  (*node)->nchildren = nchildren;
14161  }
14162 
14163  break;
14164  }
14165 
14166  case SCIP_EXPR_POLYNOMIAL:
14167  {
14168  SCIP_EXPRDATA_POLYNOMIAL* polynomialdata;
14169  SCIP_EXPRDATA_MONOMIAL* monomial;
14170  SCIP_Bool* childused;
14171  int childidx;
14172  int j;
14173 
14174  polynomialdata = (SCIP_EXPRDATA_POLYNOMIAL*)(*node)->data.data;
14175  assert(polynomialdata != NULL);
14176 
14177  /* make sure linear monomials are merged */
14178  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14179 
14180  /* remove constant, if nonzero */
14181  if( polynomialdata->constant != 0.0 )
14182  {
14183  *constant = polynomialdata->constant;
14184  polynomialdata->constant = 0.0;
14185  havechange = TRUE;
14186  }
14187 
14188  /* if there is no space for linear variables, then stop */
14189  if( linvarssize == 0 )
14190  break;
14191 
14192  /* get nonlinear child usage: how often each child is used in the polynomial in a nonlinear monomial */
14193  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren) );
14194  BMSclearMemoryArray(childused, (*node)->nchildren); /*lint !e644*/
14195  for( i = 0; i < polynomialdata->nmonomials; ++i )
14196  {
14197  monomial = polynomialdata->monomials[i];
14198  assert(monomial != NULL);
14199  if( monomial->nfactors == 0 || (monomial->nfactors == 1 && monomial->exponents[0] == 1.0) )
14200  continue;
14201  for( j = 0; j < monomial->nfactors; ++j )
14202  {
14203  assert(monomial->childidxs[j] >= 0);
14204  assert(monomial->childidxs[j] < (*node)->nchildren);
14205  childused[monomial->childidxs[j]] = TRUE;
14206  }
14207  }
14208 
14209  /* move linear monomials out of polynomial */
14210  for( i = 0; i < polynomialdata->nmonomials && *nlinvars < linvarssize; ++i )
14211  {
14212  monomial = polynomialdata->monomials[i];
14213  assert(monomial != NULL);
14214 
14215  /* sort out constants */
14216  if( monomial->nfactors == 0 )
14217  {
14218  if( monomial->coef != 0.0 )
14219  {
14220  *constant += monomial->coef;
14221  havechange = TRUE;
14222  }
14223  continue;
14224  }
14225 
14226  if( monomial->nfactors != 1 )
14227  continue;
14228  if( monomial->exponents[0] != 1.0 )
14229  continue;
14230  childidx = monomial->childidxs[0];
14231  assert((*node)->children[childidx] != NULL); /* should be due to merge in the beginning */
14232  if( (*node)->children[childidx]->op != SCIP_EXPR_VARIDX )
14233  continue;
14234  if( childused[childidx] || varsusage[(*node)->children[childidx]->data.intval] > 1 )
14235  continue;
14236 
14237  /* we are at a linear monomial in a variable that is not used somewhere else in nonlinear form */
14238 
14239  /* put variable into linear part */
14240  linvars[*nlinvars] = exprgraph->vars[(*node)->children[childidx]->data.intval]; /*lint !e613*/
14241  lincoefs[*nlinvars] = monomial->coef; /*lint !e613*/
14242  ++*nlinvars;
14243 
14244  monomial->coef = 0.0;
14245  monomial->nfactors = 0;
14246  polynomialdata->sorted = FALSE;
14247 
14248  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[childidx], *node) );
14249  (*node)->children[childidx] = NULL;
14250 
14251  havechange = TRUE;
14252  }
14253 
14254  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childused, (*node)->nchildren);
14255 
14256  if( *nlinvars > 0 )
14257  {
14258  /* if we did something, cleanup polynomial (e.g., remove monomials with coefficient 0.0) */
14259  polynomialdataMergeMonomials(exprgraph->blkmem, polynomialdata, 0.0, FALSE);
14261  }
14262 
14263  if( (*node)->nchildren == 0 )
14264  {
14265  assert(polynomialdata->nmonomials == 0);
14266  assert(polynomialdata->constant == 0.0);
14267  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14268  havechange = TRUE;
14269  break;
14270  }
14271 
14272  break;
14273  }
14274 
14275  default: ;
14276  } /*lint !e788*/
14277 
14278  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varsusage, orignvars);
14279 
14280  if( orignode != NULL )
14281  {
14282  /* if node was duplicated, we need to forget about original or duplicate */
14283  if( !havechange )
14284  {
14285  /* if nothing has changed, then forget about duplicate */
14286  assert(*constant == 0.0);
14287  assert(*nlinvars == 0);
14288  assert(*node != NULL);
14289  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, node) );
14290  *node = orignode;
14291  }
14292  else
14293  {
14294  /* if something changed, then release original node */
14295  SCIP_CALL( SCIPexprgraphReleaseNode(exprgraph, &orignode) );
14296  }
14297  }
14298  else if( havechange && *node != NULL )
14299  {
14300  /* if node was not duplicated and not removed but changed, then invalidate value, bounds, and simplified status */
14301  (*node)->value = SCIP_INVALID;
14302  (*node)->simplified = FALSE;
14303  (*node)->boundstatus = SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED;
14304  SCIPintervalSetEntire(SCIP_REAL_MAX, &(*node)->bounds);
14305  exprgraph->needvarboundprop = TRUE;
14306  }
14307 
14308  return SCIP_OKAY;
14309 }
14310 
14311 /** moves parents from a one node to another node
14312  *
14313  * In other words, replaces the child srcnode by targetnode in all parents of srcnode.
14314  * srcnode may be freed, if not captured.
14315  * It is assumed that targetnode represents the same expression as srcnode.
14316  */
14318  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14319  SCIP_EXPRGRAPHNODE** srcnode, /**< node which parents to move */
14320  SCIP_EXPRGRAPHNODE* targetnode /**< node where to move parents to */
14321  )
14322 {
14323  assert(exprgraph != NULL);
14324  assert(srcnode != NULL);
14325  assert(*srcnode != NULL);
14326  assert(targetnode != NULL);
14327 
14328  while( *srcnode != NULL && (*srcnode)->nparents > 0 )
14329  {
14330  if( (*srcnode)->parents[0]->depth <= targetnode->depth )
14331  {
14332  SCIP_CALL( exprgraphMoveNode(exprgraph, (*srcnode)->parents[0], targetnode->depth+1) );
14333  }
14334  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, (*srcnode)->parents[0], srcnode, targetnode) );
14335  }
14336  assert(*srcnode == NULL || (*srcnode)->nuses > 0);
14337 
14338  return SCIP_OKAY;
14339 }
14340 
14341 /** releases node, i.e., decreases number of uses
14342  *
14343  * node is freed if no parents and no other uses.
14344  * Children are recursively released if they have no other parents.
14345  * Nodes that are removed are also freed.
14346  * If node correspond to a variable, then the variable is removed from the expression graph;
14347  * similarly for constants.
14348  */
14350  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14351  SCIP_EXPRGRAPHNODE** node /**< expression graph node to release */
14352  )
14353 {
14354  int i;
14355 
14356  assert(exprgraph != NULL);
14357  assert(node != NULL);
14358  assert(*node != NULL);
14359  assert((*node)->depth >= 0); /* node should be in graph */
14360  assert((*node)->pos >= 0); /* node should be in graph */
14361  assert((*node)->depth < exprgraph->depth);
14362  assert((*node)->pos < exprgraph->nnodes[(*node)->depth]);
14363  assert((*node)->nuses >= 1);
14364  assert(exprgraph->nodes[(*node)->depth][(*node)->pos] == *node);
14365 
14366  SCIPdebugMessage("release node %p\n", (void*)*node);
14367 
14368  --(*node)->nuses;
14369 
14370  /* do nothing if node still has parents or is still in use */
14371  if( (*node)->nparents > 0 || (*node)->nuses > 0 )
14372  {
14373  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);
14374  *node = NULL;
14375  return SCIP_OKAY;
14376  }
14377 
14378  SCIPdebugMessage("remove node %p (%d, %d) with op %s from expression graph\n", (void*)*node, (*node)->depth, (*node)->pos, SCIPexpropGetName((*node)->op));
14379 
14380  /* notify children about removal of its parent
14381  * they are also freed, if possible */
14382  for( i = 0; i < (*node)->nchildren; ++i )
14383  {
14384  SCIP_CALL( exprgraphNodeRemoveParent(exprgraph, &(*node)->children[i], *node) );
14385  (*node)->children[i] = NULL;
14386  }
14387 
14388  if( (*node)->op == SCIP_EXPR_VARIDX )
14389  {
14390  assert((*node)->depth == 0);
14391  SCIP_CALL( exprgraphRemoveVar(exprgraph, (*node)->data.intval) );
14392  }
14393  else if( (*node)->op == SCIP_EXPR_CONST && (*node)->depth == 0 )
14394  {
14395  int constidx;
14396 
14397  (void) exprgraphFindConstNodePos(exprgraph, *node, &constidx);
14398  assert(constidx >= 0);
14399  assert(constidx < exprgraph->nconsts);
14400  assert(exprgraph->constnodes[constidx] == *node);
14401 
14402  /* move last constant to position constidx */
14403  if( constidx < exprgraph->nconsts-1 )
14404  {
14405  exprgraph->constnodes[constidx] = exprgraph->constnodes[exprgraph->nconsts-1];
14406  exprgraph->constssorted = (exprgraph->nconsts <= 2);
14407  }
14408  --exprgraph->nconsts;
14409  }
14410  else
14411  {
14412  /* only variables and constants are allowed at depth 0 */
14413  assert((*node)->depth > 0);
14414  }
14415 
14416  /* remove node from nodes array in expression graph */
14417  if( (*node)->pos < exprgraph->nnodes[(*node)->depth]-1 )
14418  {
14419  /* move last node at depth of *node to position of *node */
14420  exprgraph->nodes[(*node)->depth][(*node)->pos] = exprgraph->nodes[(*node)->depth][exprgraph->nnodes[(*node)->depth]-1];
14421  exprgraph->nodes[(*node)->depth][(*node)->pos]->pos = (*node)->pos;
14422 
14423  /* moving the node may change the order in the parents array of each child */
14424  for( i = 0; i < exprgraph->nodes[(*node)->depth][(*node)->pos]->nchildren; ++i )
14425  exprgraph->nodes[(*node)->depth][(*node)->pos]->children[i]->parentssorted = FALSE;
14426  }
14427  --exprgraph->nnodes[(*node)->depth];
14428 
14429  /* node is now not in graph anymore */
14430  (*node)->depth = -1;
14431  (*node)->pos = -1;
14432 
14433  /* free node */
14434  SCIPexprgraphFreeNode(exprgraph->blkmem, node);
14435 
14436  *node = NULL;
14437 
14438  return SCIP_OKAY;
14439 }
14440 
14441 /* @todo should be a private method and node creation should already capture a node instead of waiting that it's added to the graph */
14442 /** frees a node of an expression graph */
14444  BMS_BLKMEM* blkmem, /**< block memory */
14445  SCIP_EXPRGRAPHNODE** node /**< pointer to expression graph node that should be freed */
14446  )
14447 {
14448  assert(blkmem != NULL);
14449  assert( node != NULL);
14450  assert(*node != NULL);
14451  assert((*node)->depth == -1); /* node should not be in graph anymore */
14452  assert((*node)->pos == -1); /* node should not be in graph anymore */
14453  assert((*node)->nuses == 0); /* node should not be in use */
14454 
14455  /* free operator data, if needed */
14456  if( exprOpTable[(*node)->op].freedata != NULL )
14457  exprOpTable[(*node)->op].freedata(blkmem, (*node)->nchildren, (*node)->data);
14458 
14459  /* free arrays of children and parent nodes */
14460  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->children, (*node)->nchildren);
14461  BMSfreeBlockMemoryArrayNull(blkmem, &(*node)->parents, (*node)->parentssize);
14462 
14463  /* free node struct */
14464  BMSfreeBlockMemory(blkmem, node);
14465 }
14466 
14467 /** enables a node and recursively all its children in an expression graph */
14469  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14470  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14471  )
14472 {
14473  int i;
14474 
14475  assert(exprgraph != NULL);
14476  assert(node != NULL);
14477  assert(node->depth >= 0);
14478  assert(node->pos >= 0);
14479 
14480  if( node->enabled )
14481  return;
14482 
14483  SCIPdebugMessage("enable node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14484 
14485  node->enabled = TRUE;
14486  for( i = 0; i < node->nchildren; ++i )
14487  SCIPexprgraphEnableNode(exprgraph, node->children[i]);
14488 
14489  /* make sure bounds are updated in next bound propagation round */
14490  SCIPintervalSetEntire(SCIP_REAL_MAX, &node->bounds);
14491  exprgraph->needvarboundprop = TRUE;
14492 }
14493 
14494 /** disables a node and recursively all children which have no enabled parents in an expression graph */
14496  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14497  SCIP_EXPRGRAPHNODE* node /**< expression graph node to enable */
14498  )
14499 {
14500  int i;
14501 
14502  assert(exprgraph != NULL);
14503  assert(node != NULL);
14504  assert(node->depth >= 0);
14505  assert(node->pos >= 0);
14506 
14507  if( !node->enabled )
14508  return;
14509 
14510  /* workaround: don't disable nodes if there could be more users than the one who is disabling the node
14511  * otherwise, if there are several nonlinear constraints using the same expression graph node as root node,
14512  * we might get enabled constraints with disabled node
14513  */
14514  if( node->nuses > 1 )
14515  return;
14516 
14517  /* if all parents of node are disabled, then also node can be disabled */
14518  node->enabled = FALSE;
14519  for( i = 0; i < node->nparents; ++i )
14520  if( node->parents[i]->enabled )
14521  {
14522  node->enabled = TRUE;
14523  return;
14524  }
14525 
14526  SCIPdebugMessage("disabled node %p (%d,%d), nuses = %d\n", (void*)node, node->depth, node->pos, node->nuses);
14527 
14528  for( i = 0; i < node->nchildren; ++i )
14529  SCIPexprgraphDisableNode(exprgraph, node->children[i]);
14530 }
14531 
14532 /** returns whether the node has siblings in the expression graph */
14534  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14535  )
14536 {
14537  int p;
14538 
14539  assert(node != NULL);
14540 
14541  for( p = 0; p < node->nparents; ++p )
14542  if( node->parents[p]->nchildren > 1 )
14543  return TRUE;
14544 
14545  return FALSE;
14546 }
14547 
14548 /** returns whether all children of an expression graph node are variable nodes
14549  *
14550  * Returns TRUE for nodes without children.
14551  */
14553  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14554  )
14555 {
14556  int i;
14557 
14558  assert(node != NULL);
14559 
14560  for( i = 0; i < node->nchildren; ++i )
14561  if( node->children[i]->op != SCIP_EXPR_VARIDX )
14562  return FALSE;
14563 
14564  return TRUE;
14565 }
14566 
14567 /** returns whether the node has an ancestor which has a nonlinear expression operand */
14569  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
14570  )
14571 {
14572  int p;
14573 
14574  for( p = 0; p < node->nparents; ++p )
14575  {
14576  assert(node->parents[p]->depth > node->depth);
14577  switch( node->parents[p]->op )
14578  {
14579  case SCIP_EXPR_PLUS:
14580  case SCIP_EXPR_MINUS:
14581  case SCIP_EXPR_SUM:
14582  case SCIP_EXPR_LINEAR:
14584  return TRUE;
14585  break;
14586 
14587 #ifndef NDEBUG
14588  case SCIP_EXPR_VARIDX:
14589  case SCIP_EXPR_CONST:
14590  case SCIP_EXPR_PARAM:
14591  assert(0); /* these expressions cannot have children */
14592  break;
14593 #endif
14594 
14595  default:
14596  /* parent has nonlinear expression operand */
14597  return TRUE;
14598  }/*lint !e788*/
14599  }
14600 
14601  return FALSE;
14602 }
14603 
14604 /** prints an expression graph node */
14606  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14607  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
14608  FILE* file /**< file to print to, or NULL for stdout */
14609  )
14610 {
14611  assert(node != NULL);
14612 
14613  exprgraphPrintNodeExpression(node, messagehdlr, file, NULL, FALSE);
14614 }
14615 
14616 /** tightens the bounds in a node of the graph
14617  *
14618  * Preparation for reverse propagation.
14619  * Sets bound status to SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT if tightening is strong enough and not cutoff.
14620  */
14622  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14623  SCIP_EXPRGRAPHNODE* node, /**< node in expression graph with no parents */
14624  SCIP_INTERVAL nodebounds, /**< new bounds for node */
14625  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) */
14626  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14627  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
14628  )
14629 {
14630  assert(exprgraph != NULL);
14631  assert(node != NULL);
14632  assert(node->depth >= 0);
14633  assert(node->pos >= 0);
14634  assert(!SCIPintervalIsEmpty(infinity, nodebounds));
14635  assert(cutoff != NULL);
14636 
14637  *cutoff = FALSE;
14638 
14639  /* if node is disabled, then ignore new bounds */
14640  if( !node->enabled )
14641  {
14642  SCIPdebugMessage("ignore bound tightening for node %p (%d,%d)\n", (void*)node, node->depth, node->pos);
14643  return;
14644  }
14645 
14646  SCIPdebugMessage("tighten bounds of node %p (%d,%d) from [%10g, %10g] by [%10g, %10g]",
14647  (void*)node, node->depth, node->pos,
14648  node->bounds.inf, node->bounds.sup, nodebounds.inf, nodebounds.sup);
14649 
14650  /* bounds in node should be valid */
14651  assert(!(node->boundstatus & SCIP_EXPRBOUNDSTATUS_CHILDRELAXED));
14652 
14653  if( nodebounds.inf > node->bounds.sup || nodebounds.sup < node->bounds.inf )
14654  {
14655  *cutoff = TRUE;
14656  SCIPdebugPrintf(" -> cutoff\n");
14657  return;
14658  }
14659 
14660  /* if minstrength is negative, always mark that node has recently tightened bounds,
14661  * if bounds are considerably improved or tightening leads to an empty interval,
14662  * mark that node has recently tightened bounds
14663  * if bounds are only slightly improved, set the status to tightened by parent,
14664  * so next propagateVarBound round will reset the bounds
14665  */
14666  if( minstrength < 0.0 )
14667  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE;
14668  else if(
14669  isLbBetter(minstrength, nodebounds.inf, node->bounds.inf, node->bounds.sup) ||
14670  isUbBetter(minstrength, nodebounds.sup, node->bounds.inf, node->bounds.sup) )
14671  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT;
14672  else if( nodebounds.inf > node->bounds.inf || nodebounds.sup < node->bounds.sup )
14673  node->boundstatus |= SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT;
14674 
14675  SCIPintervalIntersect(&node->bounds, node->bounds, nodebounds);
14676  SCIPdebugPrintf(" -> [%10g, %10g] status %d\n", node->bounds.inf, node->bounds.sup, node->boundstatus);
14677 }
14678 
14679 /** ensures that bounds and curvature information in a node is uptodate
14680  *
14681  * Assumes that bounds and curvature in children are uptodate.
14682  */
14684  SCIP_EXPRGRAPHNODE* node, /**< expression graph node */
14685  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
14686  SCIP_Real minstrength, /**< minimal required relative bound strengthening to trigger a bound recalculation in parent nodes */
14687  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
14688  )
14689 {
14690  SCIP_INTERVAL childboundsstatic[SCIP_EXPRESSION_MAXCHILDEST];
14691  SCIP_EXPRCURV childcurvstatic[SCIP_EXPRESSION_MAXCHILDEST];
14692  SCIP_INTERVAL* childbounds;
14693  SCIP_EXPRCURV* childcurv;
14694  int i;
14695 
14696  assert(node != NULL);
14697  assert(node->depth >= 0); /* node should be in graph */
14698  assert(node->pos >= 0); /* node should be in graph */
14699  assert(node->enabled); /* node should be enabled, otherwise we may not have uptodate bounds and curvatures in children */
14700 
14701  if( node->depth == 0 )
14702  {
14703  /* we cannot update bound tightenings in variable nodes here */
14704  assert(!clearreverseprop || !(node->boundstatus & SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT));
14705  return SCIP_OKAY;
14706  }
14707 
14708  assert(node->op != SCIP_EXPR_VARIDX);
14709  assert(node->op != SCIP_EXPR_PARAM);
14710 
14711  /* if many children, get large enough memory to store children bounds */
14713  {
14714  SCIP_ALLOC( BMSallocMemoryArray(&childbounds, node->nchildren) );
14715  SCIP_ALLOC( BMSallocMemoryArray(&childcurv, node->nchildren) );
14716  }
14717  else
14718  {
14719  childbounds = childboundsstatic;
14720  childcurv = childcurvstatic;
14721  }
14722 
14723  /* assemble bounds and curvature of children */
14724  for( i = 0; i < node->nchildren; ++i )
14725  {
14726  /* child should have valid and non-empty bounds */
14728  assert(!SCIPintervalIsEmpty(infinity, node->children[i]->bounds));
14729  /* nodes at depth 0 are always linear */
14730  assert(node->children[i]->depth > 0 || node->children[i]->curv == SCIP_EXPRCURV_LINEAR);
14731 
14732  childbounds[i] = node->children[i]->bounds; /*lint !e644*/
14733  childcurv[i] = node->children[i]->curv; /*lint !e644*/
14734  }
14735 
14736  /* if we do not have valid bounds, then update
14737  * code below is copied from exprgraphNodeUpdateBounds */
14739  {
14740  SCIP_INTERVAL newbounds;
14741 
14742  /* calling interval evaluation function for this operand */
14743  assert( exprOpTable[node->op].inteval != NULL );
14744  SCIP_CALL( exprOpTable[node->op].inteval(infinity, node->data, node->nchildren, childbounds, NULL, NULL, &newbounds) );
14745 
14746  /* if bounds of a children were relaxed or our bounds were tightened by a (now possibly invalid) reverse propagation from a parent
14747  * and now our bounds are relaxed, then we have to propagate this upwards to ensure valid bounds
14748  *
14749  * if bounds were tightened (considerably), then tell this to those parents which think that they have valid bounds
14750  *
14751  * finally, if there was only a little tightening, then keep this updated bounds, but don't notify parents
14752  */
14753  if( (newbounds.inf < node->bounds.inf || newbounds.sup > node->bounds.sup) &&
14755  {
14756  for( i = 0; i < node->nparents; ++i )
14758 
14759  node->bounds = newbounds;
14760  }
14761  else if( isLbBetter(minstrength, newbounds.inf, node->bounds.inf, node->bounds.sup) ||
14762  ( isUbBetter(minstrength, newbounds.sup, node->bounds.inf, node->bounds.sup)) )
14763  {
14764  for( i = 0; i < node->nparents; ++i )
14766 
14767  node->bounds = newbounds;
14768  }
14769  else
14770  {
14771  SCIPintervalIntersect(&node->bounds, node->bounds, newbounds);
14772  }
14773 
14774  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);
14775 
14776  /* node now has valid bounds */
14777  node->boundstatus = SCIP_EXPRBOUNDSTATUS_VALID;
14778  }
14779 
14780  /* update curvature */
14781  if( SCIPintervalIsEmpty(infinity, node->bounds) )
14782  {
14783  node->curv = SCIP_EXPRCURV_LINEAR;
14784 
14785  SCIPdebugMessage("node %p(%d,%d) has empty domain in SCIPexprgraphUpdateNodeBoundsCurvature\n", (void*)node, node->depth, node->pos);
14786  }
14787  else
14788  {
14789  SCIP_CALL( exprOpTable[node->op].curv(infinity, node->data, node->nchildren, childbounds, childcurv, &node->curv) );
14790 
14791  /* SCIPdebugMessage("curvature %s for %s = ", SCIPexprcurvGetName(node->curv), SCIPexpropGetName(node->op));
14792  * SCIPdebug( exprgraphPrintNodeExpression(node, NULL, NULL, TRUE) );
14793  * SCIPdebugPrintf("\n");
14794  */
14795  }
14796 
14797  /* free memory, if allocated before */
14798  if( childbounds != childboundsstatic )
14799  {
14800  BMSfreeMemoryArray(&childbounds);
14801  BMSfreeMemoryArray(&childcurv);
14802  }
14803 
14804  return SCIP_OKAY;
14805 }
14806 
14807 /**@} */
14808 
14809 /**@name Expression graph methods */
14810 /**@{ */
14811 
14812 /* In debug mode, the following methods are implemented as function calls to ensure
14813  * type validity.
14814  * In optimized mode, the methods are implemented as defines to improve performance.
14815  * However, we want to have them in the library anyways, so we have to undef the defines.
14816  */
14817 
14818 #undef SCIPexprgraphGetDepth
14819 #undef SCIPexprgraphGetNNodes
14820 #undef SCIPexprgraphGetNodes
14821 #undef SCIPexprgraphGetNVars
14822 #undef SCIPexprgraphGetVars
14823 #undef SCIPexprgraphGetVarNodes
14824 #undef SCIPexprgraphSetVarNodeValue
14825 #undef SCIPexprgraphSetVarsBounds
14826 #undef SCIPexprgraphSetVarBounds
14827 #undef SCIPexprgraphSetVarNodeBounds
14828 #undef SCIPexprgraphSetVarNodeLb
14829 #undef SCIPexprgraphSetVarNodeUb
14830 #undef SCIPexprgraphGetVarsBounds
14831 
14832 /** get current maximal depth of expression graph */
14834  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14835  )
14836 {
14837  assert(exprgraph != NULL);
14838 
14839  return exprgraph->depth;
14840 }
14841 
14842 /** gets array with number of nodes at each depth of expression graph */
14844  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14845  )
14846 {
14847  assert(exprgraph != NULL);
14848 
14849  return exprgraph->nnodes;
14850 }
14851 
14852 /** gets nodes of expression graph, one array per depth */
14854  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14855  )
14856 {
14857  assert(exprgraph != NULL);
14858 
14859  return exprgraph->nodes;
14860 }
14861 
14862 /** gets number of variables in expression graph */
14864  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14865  )
14866 {
14867  assert(exprgraph != NULL);
14868 
14869  return exprgraph->nvars;
14870 }
14871 
14872 /** gets array of variables in expression graph */
14874  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14875  )
14876 {
14877  assert(exprgraph != NULL);
14878 
14879  return exprgraph->vars;
14880 }
14881 
14882 /** gets array of expression graph nodes corresponding to variables */
14884  SCIP_EXPRGRAPH* exprgraph /**< pointer to expression graph that should be freed */
14885  )
14886 {
14887  assert(exprgraph != NULL);
14888 
14889  return exprgraph->varnodes;
14890 }
14891 
14892 /** sets value for a single variable given as expression graph node */
14894  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14895  SCIP_Real value /**< new value for variable */
14896  )
14897 {
14898  assert(varnode != NULL);
14899  assert(varnode->op == SCIP_EXPR_VARIDX);
14900 
14901  varnode->value = value;
14902 }
14903 
14904 /** sets bounds for variables */
14906  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14907  SCIP_INTERVAL* varbounds /**< new bounds for variables */
14908  )
14909 {
14910  assert(exprgraph != NULL);
14911  assert(varbounds != NULL || exprgraph->nvars == 0);
14912 
14913  BMScopyMemoryArray(exprgraph->varbounds, varbounds, exprgraph->nvars);
14914 }
14915 
14916 /** sets bounds for a single variable */
14918  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14919  void* var, /**< variable */
14920  SCIP_INTERVAL varbounds /**< new bounds of variable */
14921  )
14922 {
14923  int pos;
14924 
14925  assert(exprgraph != NULL);
14926  assert(var != NULL);
14927  assert(SCIPhashmapExists(exprgraph->varidxs, var));
14928 
14929  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
14930  assert(pos < exprgraph->nvars);
14931  assert(exprgraph->vars[pos] == var);
14932 
14933  exprgraph->varbounds[pos] = varbounds;
14934 }
14935 
14936 /** sets bounds for a single variable given as expression graph node */
14938  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14939  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14940  SCIP_INTERVAL varbounds /**< new bounds of variable */
14941  )
14942 {
14943  int pos;
14944 
14945  assert(exprgraph != NULL);
14946  assert(varnode != NULL);
14947 
14948  pos = varnode->data.intval;
14949  assert(pos >= 0);
14950  assert(pos < exprgraph->nvars);
14951  assert(exprgraph->varnodes[pos] == varnode);
14952 
14953  exprgraph->varbounds[pos] = varbounds;
14954 }
14955 
14956 /** sets lower bound for a single variable given as expression graph node */
14958  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14959  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14960  SCIP_Real lb /**< new lower bound for variable */
14961  )
14962 {
14963  int pos;
14964 
14965  assert(exprgraph != NULL);
14966  assert(varnode != NULL);
14967 
14968  pos = varnode->data.intval;
14969  assert(pos >= 0);
14970  assert(pos < exprgraph->nvars);
14971  assert(exprgraph->varnodes[pos] == varnode);
14972 
14973  exprgraph->varbounds[pos].inf = lb;
14974 }
14975 
14976 /** sets upper bound for a single variable given as expression graph node */
14978  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
14979  SCIP_EXPRGRAPHNODE* varnode, /**< expression graph node corresponding to variable */
14980  SCIP_Real ub /**< new upper bound for variable */
14981  )
14982 {
14983  int pos;
14984 
14985  assert(exprgraph != NULL);
14986  assert(varnode != NULL);
14987 
14988  pos = varnode->data.intval;
14989  assert(pos >= 0);
14990  assert(pos < exprgraph->nvars);
14991  assert(exprgraph->varnodes[pos] == varnode);
14992 
14993  exprgraph->varbounds[pos].sup = ub;
14994 }
14995 
14996 /** gets bounds that are stored for all variables */
14998  SCIP_EXPRGRAPH* exprgraph /**< expression graph */
14999  )
15000 {
15001  return exprgraph->varbounds;
15002 }
15003 
15004 /** creates an empty expression graph */
15006  BMS_BLKMEM* blkmem, /**< block memory */
15007  SCIP_EXPRGRAPH** exprgraph, /**< buffer to store pointer to expression graph */
15008  int varssizeinit, /**< minimal initial size for variables array, or -1 to choose automatically */
15009  int depthinit, /**< minimal initial depth of expression graph, or -1 to choose automatically */
15010  SCIP_DECL_EXPRGRAPHVARADDED((*exprgraphvaradded)), /**< callback method to invoke when a variable has been added to the expression graph, or NULL if not needed */
15011  SCIP_DECL_EXPRGRAPHVARREMOVE((*exprgraphvarremove)), /**< callback method to invoke when a variable will be removed from the expression graph, or NULL if not needed */
15012  SCIP_DECL_EXPRGRAPHVARCHGIDX((*exprgraphvarchgidx)), /**< callback method to invoke when a variable changes its index in the expression graph, or NULL if not needed */
15013  void* userdata /**< user data to pass to callback functions */
15014  )
15015 {
15016  assert(blkmem != NULL);
15017  assert(exprgraph != NULL);
15018 
15019  SCIP_ALLOC( BMSallocBlockMemory(blkmem, exprgraph) );
15020  BMSclearMemory(*exprgraph);
15021  (*exprgraph)->blkmem = blkmem;
15022 
15023  /* create nodes's arrays */
15024  SCIP_CALL( exprgraphEnsureDepth(*exprgraph, MAX(1, depthinit)) );
15025  assert((*exprgraph)->depth >= 1);
15026 
15027  /* create var's arrays and hashmap */
15028  ensureBlockMemoryArraySize3((*exprgraph)->blkmem, &(*exprgraph)->varnodes, &(*exprgraph)->vars, &(*exprgraph)->varbounds, &(*exprgraph)->varssize, varssizeinit);
15029  SCIP_CALL( SCIPhashmapCreate(&(*exprgraph)->varidxs, (*exprgraph)->blkmem, (*exprgraph)->varssize) );
15030 
15031  /* empty array of constants is sorted */
15032  (*exprgraph)->constssorted = TRUE;
15033 
15034  /* store callback functions and user data */
15035  (*exprgraph)->exprgraphvaradded = exprgraphvaradded;
15036  (*exprgraph)->exprgraphvarremove = exprgraphvarremove;
15037  (*exprgraph)->exprgraphvarchgidx = exprgraphvarchgidx;
15038  (*exprgraph)->userdata = userdata;
15039 
15040  return SCIP_OKAY;
15041 }
15042 
15043 /** frees an expression graph */
15045  SCIP_EXPRGRAPH** exprgraph /**< pointer to expression graph that should be freed */
15046  )
15047 {
15048  BMS_BLKMEM* blkmem;
15049  int d;
15050 
15051  assert( exprgraph != NULL);
15052  assert(*exprgraph != NULL);
15053  assert((*exprgraph)->nvars == 0);
15054  assert((*exprgraph)->nconsts == 0);
15055 
15056  blkmem = (*exprgraph)->blkmem;
15057  assert(blkmem != NULL);
15058 
15059  /* free nodes arrays */
15060  for( d = 0; d < (*exprgraph)->depth; ++d )
15061  {
15062  assert((*exprgraph)->nnodes[d] == 0);
15063  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->nodes[d], (*exprgraph)->nodessize[d]); /*lint !e866*/
15064  }
15065  assert((*exprgraph)->nodes != NULL);
15066  assert((*exprgraph)->nnodes != NULL);
15067  assert((*exprgraph)->nodessize != NULL);
15068  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodes, (*exprgraph)->depth);
15069  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nnodes, (*exprgraph)->depth);
15070  BMSfreeBlockMemoryArray(blkmem, &(*exprgraph)->nodessize, (*exprgraph)->depth);
15071 
15072  /* free variables arrays and hashmap */
15073  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->vars, (*exprgraph)->varssize);
15074  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varnodes, (*exprgraph)->varssize);
15075  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->varbounds, (*exprgraph)->varssize);
15076  SCIPhashmapFree(&(*exprgraph)->varidxs);
15077 
15078  /* free constants array */
15079  BMSfreeBlockMemoryArrayNull(blkmem, &(*exprgraph)->constnodes, (*exprgraph)->constssize);
15080 
15081  /* free graph struct */
15082  BMSfreeBlockMemory(blkmem, exprgraph);
15083 
15084  return SCIP_OKAY;
15085 }
15086 
15087 /** adds an expression graph node to an expression graph
15088  *
15089  * Expression graph assumes ownership of node.
15090  * Children are notified about new parent.
15091  * Depth will be chosen to be the maximum of mindepth and the depth of all children plus one.
15092  */
15094  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15095  SCIP_EXPRGRAPHNODE* node, /**< expression graph node to add */
15096  int mindepth, /**< minimal depth in expression graph where to add node, e.g., 0 or smaller to choose automatically */
15097  int nchildren, /**< number of children */
15098  SCIP_EXPRGRAPHNODE** children /**< children nodes, or NULL if no children */
15099  )
15100 {
15101  SCIP_Bool childvalsvalid;
15102  int depth;
15103  int i;
15104 
15105  assert(exprgraph != NULL);
15106  assert(node != NULL);
15107  assert(node->pos < 0); /* node should have no position in graph yet */
15108  assert(node->depth < 0); /* node should have no position in graph yet */
15109  assert(node->nchildren == 0); /* node should not have stored children yet */
15110  assert(node->children == NULL); /* node should not have stored children yet */
15111  assert(node->nparents == 0); /* node should not have parents stored yet */
15112  assert(children != NULL || nchildren == 0);
15113 
15114  /* choose depth as maximal depth of children + 1, and at least mindepth */
15115  depth = MAX(0, mindepth);
15116  for( i = 0; i < nchildren; ++i )
15117  {
15118  if( children[i]->depth >= depth ) /*lint !e613*/
15119  depth = children[i]->depth + 1; /*lint !e613*/
15120  }
15121 
15122  /* ensure that expression graph is deep enough */
15123  SCIP_CALL( exprgraphEnsureDepth(exprgraph, depth+1) );
15124  assert(exprgraph->depth > depth);
15125 
15126  /* ensure enough space for nodes at depth depth */
15127  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[depth], &exprgraph->nodessize[depth], exprgraph->nnodes[depth]+1); /*lint !e866*/
15128 
15129  /* add node to graph */
15130  node->depth = depth;
15131  node->pos = exprgraph->nnodes[depth];
15132  exprgraph->nodes[depth][node->pos] = node;
15133  ++exprgraph->nnodes[depth];
15134 
15135  /* add as parent to children
15136  * and check if children has valid values */
15137  childvalsvalid = TRUE;
15138  for( i = 0; i < nchildren; ++i )
15139  {
15140  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, children[i], node) ); /*lint !e613*/
15141  childvalsvalid &= (children[i]->value != SCIP_INVALID); /*lint !e777 !e514 !e613*/
15142  }
15143  /* store children */
15144  if( nchildren > 0 )
15145  {
15146  SCIP_ALLOC( BMSduplicateBlockMemoryArray(exprgraph->blkmem, &node->children, children, nchildren) );
15147  node->nchildren = nchildren;
15148  }
15149 
15150  if( node->op == SCIP_EXPR_CONST )
15151  {
15152  /* set bounds to constant value of node */
15154  SCIPintervalSet(&node->bounds, node->data.dbl);
15155  }
15156  else
15157  {
15158  /* set bounds to entire, set status to "should recompute", and note that we have to update something */
15161  exprgraph->needvarboundprop = TRUE;
15162  }
15163 
15164  /* if not a variable, set value of node according to values of children (if all have valid values) */
15165  if( node->op != SCIP_EXPR_VARIDX && childvalsvalid )
15166  {
15167  SCIP_CALL( exprgraphNodeEval(node, NULL) );
15168  }
15169 
15170  return SCIP_OKAY;
15171 }
15172 
15173 /** adds variables to an expression graph, if not existing yet
15174  *
15175  * Also already existing nodes are enabled.
15176  */
15178  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15179  int nvars, /**< number of variables to add */
15180  void** vars, /**< variables to add */
15181  SCIP_EXPRGRAPHNODE** varnodes /**< array to store nodes corresponding to variables, or NULL if not of interest */
15182  )
15183 {
15184  SCIP_EXPRGRAPHNODE* node;
15185  SCIP_EXPROPDATA opdata;
15186  int i;
15187 
15188  assert(exprgraph != NULL);
15189  assert(exprgraph->depth >= 1);
15190  assert(vars != NULL || nvars == 0);
15191 
15192  /* 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 */
15193  if( exprgraph->nvars == 0 )
15194  {
15195  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + nvars);
15196  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->nodes[0], &exprgraph->nodessize[0], exprgraph->nnodes[0] + nvars);
15197  }
15198 
15199  for( i = 0; i < nvars; ++i )
15200  {
15201  /* skip variables that exist already */
15202  if( SCIPhashmapExists(exprgraph->varidxs, vars[i]) )/*lint !e613*/
15203  {
15204  (void) SCIPexprgraphFindVarNode(exprgraph, vars[i], &node); /*lint !e613*/
15205  assert(node != NULL);
15206 
15207  /* enable node */
15208  node->enabled = TRUE;
15209 
15210  if( varnodes != NULL )
15211  varnodes[i] = node;
15212 
15213  continue;
15214  }
15215 
15216  /* create new variable expression */
15217  opdata.intval = exprgraph->nvars;
15218  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, &node, SCIP_EXPR_VARIDX, opdata) );
15219 
15220  /* add expression node to expression graph at depth 0 */
15221  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, node, 0, 0, NULL) );
15222 
15223  /* add variable node to vars arrays and hashmap */
15224  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15225  exprgraph->vars[exprgraph->nvars] = vars[i]; /*lint !e613*/
15226  exprgraph->varnodes[exprgraph->nvars] = node;
15227  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15228  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[i], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15229  ++exprgraph->nvars;
15230 
15231  if( varnodes != NULL )
15232  varnodes[i] = node;
15233 
15234  SCIPdebugMessage("added node %p (%d, %d) for new variable %d\n", (void*)node, node->depth, node->pos, node->data.intval);
15235 
15236  /* call callback method, if set */
15237  if( exprgraph->exprgraphvaradded != NULL )
15238  {
15239  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[i], node) ); /*lint !e613*/
15240  }
15241  }
15242 
15243  return SCIP_OKAY;
15244 }
15245 
15246 /** adds a constant to an expression graph, if not existing yet
15247  *
15248  * Also already existing nodes are enabled.
15249  */
15251  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15252  SCIP_Real constant, /**< constant to add */
15253  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store pointer to expression graph node corresponding to constant */
15254  )
15255 {
15256  SCIP_EXPROPDATA opdata;
15257 
15258  assert(exprgraph != NULL);
15259  assert(constnode != NULL);
15260 
15261  /* check if there is already an expression for this constant */
15262  if( SCIPexprgraphFindConstNode(exprgraph, constant, constnode) )
15263  {
15264  assert(*constnode != NULL);
15265  assert((*constnode)->op == SCIP_EXPR_CONST);
15266  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15267  (*constnode)->enabled = TRUE;
15268  return SCIP_OKAY;
15269  }
15270 
15271  /* create new node for constant */
15272  opdata.dbl = constant;
15273  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, constnode, SCIP_EXPR_CONST, opdata) );
15274 
15275  /* add node to expression graph at depth 0 */
15276  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *constnode, 0, 0, NULL) );
15277  assert((*constnode)->depth == 0);
15278  assert((*constnode)->pos == exprgraph->nnodes[0]-1);
15279 
15280  /* add node to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15281  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15282  exprgraph->constnodes[exprgraph->nconsts] = *constnode;
15283  ++exprgraph->nconsts;
15284  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], *constnode) < 0);
15285 
15286  SCIPdebugMessage("added node %p (%d, %d) for new constant %g\n", (void*)constnode, (*constnode)->depth, (*constnode)->pos, (*constnode)->data.dbl);
15287 
15288  return SCIP_OKAY;
15289 }
15290 
15291 /** adds sum of expression trees into expression graph
15292  *
15293  * node will also be captured.
15294  *
15295  * @note Parameters will be converted into constants
15296  */
15298  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15299  int nexprtrees, /**< number of expression trees to add */
15300  SCIP_EXPRTREE** exprtrees, /**< expression trees that should be added */
15301  SCIP_Real* coefs, /**< coefficients of expression trees, or NULL if all 1.0 */
15302  SCIP_EXPRGRAPHNODE** rootnode, /**< buffer to store expression graph node corresponding to root of expression tree */
15303  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) */
15304  )
15305 {
15306  SCIP_Bool allone;
15307 
15308  assert(exprgraph != NULL);
15309  assert(nexprtrees > 0);
15310  assert(exprtrees != NULL);
15311  assert(rootnode != NULL);
15312  assert(rootnodeisnew != NULL);
15313 
15314  *rootnode = NULL;
15315 
15316  if( nexprtrees == 1 && (coefs == NULL || coefs[0] == 1.0) )
15317  {
15318  assert(exprtrees[0] != NULL);
15319  assert(exprtrees[0]->vars != NULL || exprtrees[0]->nvars == 0);
15320 
15321  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[0]->root, exprtrees[0]->vars, exprtrees[0]->params, rootnode, rootnodeisnew) );
15322  }
15323  else
15324  {
15325  SCIP_EXPROP op;
15326  SCIP_EXPRGRAPHNODE** rootnodes;
15327  SCIP_Bool rootnodeisnew_;
15328  int i;
15329 
15330  *rootnodeisnew = TRUE;
15331  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees) );
15332 
15333  allone = TRUE;
15334  for( i = 0; i < nexprtrees; ++i )
15335  {
15336  assert(exprtrees[i] != NULL);
15337  assert(exprtrees[i]->vars != NULL || exprtrees[i]->nvars == 0);
15338 
15339  SCIP_CALL( exprgraphAddExpr(exprgraph, exprtrees[i]->root, exprtrees[i]->vars, exprtrees[i]->params, &rootnodes[i], &rootnodeisnew_) ); /*lint !e644*/
15340  assert(rootnodes[i] != NULL);
15341  *rootnodeisnew &= rootnodeisnew_;
15342 
15343  allone &= (coefs == NULL || coefs[i] == 1.0); /*lint !e514*/
15344  }
15345 
15346  /* decide which operand we want to use for the root node */
15347  if( coefs == NULL || allone )
15348  op = nexprtrees == 2 ? SCIP_EXPR_PLUS : SCIP_EXPR_SUM;
15349  else if( nexprtrees == 2 && coefs[0] == 1.0 && coefs[1] == -1.0 )
15350  op = SCIP_EXPR_MINUS;
15351  else if( nexprtrees == 2 && coefs[1] == 1.0 && coefs[0] == -1.0 )
15352  {
15353  SCIP_EXPRGRAPHNODE* tmp;
15354 
15355  tmp = rootnodes[0];
15356  rootnodes[0] = rootnodes[1];
15357  rootnodes[1] = tmp;
15358  op = SCIP_EXPR_MINUS;
15359  }
15360  else
15361  op = SCIP_EXPR_LINEAR;
15362 
15363  if( op != SCIP_EXPR_LINEAR )
15364  {
15365  SCIP_EXPROPDATA data;
15366  data.data = NULL;
15367 
15368  if( !*rootnodeisnew )
15369  {
15370  /* all exprtrees were in the graph already, check if we also already have a node for the sum of rootnodes */
15371  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, op, data, NULL, rootnode) );
15372  }
15373 
15374  if( *rootnode == NULL )
15375  {
15376  /* create new node for sum of rootnodes and add to exprgraph */
15377  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, op, data) );
15378  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15379  *rootnodeisnew = TRUE;
15380  }
15381  else
15382  {
15383  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15384  *rootnodeisnew = FALSE;
15385  }
15386  }
15387  else
15388  {
15389  SCIP_EXPROPDATA data;
15390  SCIP_Real* lindata;
15391 
15392  assert(op == SCIP_EXPR_LINEAR);
15393 
15394  /* setup data for linear expression: copy of coefficients and 0.0 as constant term */
15395  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1) );
15396  BMScopyMemoryArray(lindata, coefs, nexprtrees); /*lint !e644*/
15397  lindata[nexprtrees] = 0.0;
15398  data.data = lindata;
15399 
15400  if( !*rootnodeisnew )
15401  {
15402  /* all exprtrees were in the graph already, check if we also already have a node for the linear combination of rootnodes */
15403  SCIP_CALL( exprgraphFindParentByOperator(exprgraph, nexprtrees, rootnodes, SCIP_EXPR_LINEAR, data, NULL, rootnode) );
15404  }
15405 
15406  if( *rootnode == NULL )
15407  {
15408  /* create new node for linear combination of rootnodes and add to exprgraph */
15409  SCIP_CALL( exprgraphCreateNode(exprgraph->blkmem, rootnode, SCIP_EXPR_LINEAR, data) );
15410  SCIP_CALL( SCIPexprgraphAddNode(exprgraph, *rootnode, -1, nexprtrees, rootnodes) );
15411  *rootnodeisnew = TRUE;
15412  }
15413  else
15414  {
15415  /* apparently we already had a node for the sum of rootnodes, so signal this to the caller */
15416  *rootnodeisnew = FALSE;
15417  BMSfreeBlockMemoryArray(exprgraph->blkmem, &lindata, nexprtrees+1);
15418  }
15419  }
15420 
15421  BMSfreeBlockMemoryArray(exprgraph->blkmem, &rootnodes, nexprtrees);
15422  }
15423  assert(*rootnode != NULL);
15424 
15425  SCIPexprgraphCaptureNode(*rootnode);
15426 
15427  SCIPdebugMessage("%s node %p (%d,%d) is root for %d expression trees\n",
15428  rootnodeisnew ? "new" : "old", (void*)*rootnode, (*rootnode)->depth, (*rootnode)->pos, nexprtrees);
15429 
15430  return SCIP_OKAY;
15431 }
15432 
15433 /** replaces variable in expression graph by a linear sum of variables
15434  *
15435  * Variables will be added if not in the graph yet.
15436  */
15438  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15439  void* var, /**< variable to replace */
15440  int ncoefs, /**< number of coefficients in linear term */
15441  SCIP_Real* coefs, /**< coefficients in linear term, or NULL if ncoefs == 0 */
15442  void** vars, /**< variables in linear term */
15443  SCIP_Real constant /**< constant offset */
15444  )
15445 {
15446  SCIP_EXPRGRAPHNODE* varnode;
15447  SCIP_Real* lindata;
15448  int varidx;
15449  int i;
15450 
15451  assert(exprgraph != NULL);
15452  assert(var != NULL);
15453  assert(SCIPhashmapExists(exprgraph->varidxs, var));
15454  assert(coefs != NULL || ncoefs == 0);
15455  assert(vars != NULL || ncoefs == 0);
15456 
15457  varidx = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15458  assert(varidx < exprgraph->nvars);
15459  assert(exprgraph->vars[varidx] == var);
15460  varnode = exprgraph->varnodes[varidx];
15461  assert(varnode != NULL);
15462  assert(varnode->data.intval == varidx);
15463 
15464  if( ncoefs == 0 || (ncoefs == 1 && constant == 0.0 && coefs[0] == 1.0) ) /*lint !e613*/
15465  {
15466  /* variable is replaced by constant or variable */
15467  SCIP_EXPRGRAPHNODE* node;
15468 
15469  /* check if there is already a node for this constant or variable */
15470  node = NULL;
15471  if( ncoefs == 0 )
15472  {
15473  (void)SCIPexprgraphFindConstNode(exprgraph, constant, &node);
15474  assert(node == NULL || node->data.dbl == constant); /*lint !e777*/
15475  }
15476  else
15477  {
15478  (void)SCIPexprgraphFindVarNode(exprgraph, vars[0], &node); /*lint !e613*/
15479  assert(node == NULL || exprgraph->vars[node->data.intval] == vars[0]); /*lint !e613*/
15480  }
15481 
15482  if( node != NULL )
15483  {
15484  SCIPdebugMessage("try to replace varnode %p (%d uses, %d parents) by %p\n", (void*)varnode, varnode->nuses, varnode->nparents, (void*)node);
15485 
15486  /* tell parents of varnode to replace child varnode by node, this may free varnode */
15487  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &varnode, node) );
15488 
15489  /* if varnode is in use, turn it into SCIP_EXPR_SUM with node as only child */
15490  if( varnode != NULL )
15491  {
15492  assert(varnode->nuses > 0);
15493  assert(varnode->nparents == 0);
15494 
15495  /* remove variable (but don't free it's node) from graph */
15496  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15497 
15498  /* move varnode up to depth 1 */
15499  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15500 
15501  /* turn into EXPR_SUM expression */
15502  varnode->op = SCIP_EXPR_SUM;
15503  varnode->data.data = NULL;
15504  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, 1) ); /*lint !e506*/
15505  varnode->children[0] = node;
15506  varnode->nchildren = 1;
15507  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, node, varnode) );
15508 
15509  varnode->value = node->value;
15510  varnode->bounds = node->bounds;
15511  varnode->boundstatus = (node->boundstatus == SCIP_EXPRBOUNDSTATUS_VALID) ? SCIP_EXPRBOUNDSTATUS_VALID : SCIP_EXPRBOUNDSTATUS_CHILDRELAXED;
15512  }
15513  }
15514  else if( ncoefs == 0 )
15515  {
15516  /* turn node into EXPR_CONST node */
15517 
15518  /* remove variable (but don't free it's node) from graph */
15519  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15520 
15521  /* convert into EXPR_CONST node */
15522  varnode->op = SCIP_EXPR_CONST;
15523  varnode->data.dbl = constant;
15524 
15525  varnode->value = constant;
15526  SCIPintervalSet(&varnode->bounds, constant);
15528 
15529  /* add to constnodes arrays; @todo should use SCIPsortedvecInsertPtr? */
15530  ensureBlockMemoryArraySize(exprgraph->blkmem, &exprgraph->constnodes, &exprgraph->constssize, exprgraph->nconsts + 1);
15531  exprgraph->constnodes[exprgraph->nconsts] = varnode;
15532  ++exprgraph->nconsts;
15533  exprgraph->constssorted = exprgraph->nconsts <= 1 || (exprgraph->constssorted && exprgraphConstNodeComp(exprgraph->constnodes[exprgraph->nconsts-2], varnode) < 0);
15534  }
15535  else
15536  {
15537  /* turn node into EXPR_VARIDX node for new variable */
15538 
15539  /* remove variable (but don't free it's node) from graph */
15540  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15541 
15542  varnode->data.intval = exprgraph->nvars;
15543 
15544  /* add variable node to vars arrays and hashmap */
15545  ensureBlockMemoryArraySize3(exprgraph->blkmem, &exprgraph->vars, &exprgraph->varnodes, &exprgraph->varbounds, &exprgraph->varssize, exprgraph->nvars + 1);
15546  exprgraph->vars[exprgraph->nvars] = vars[0]; /*lint !e613*/
15547  exprgraph->varnodes[exprgraph->nvars] = varnode;
15548  SCIPintervalSetEntire(SCIP_REAL_MAX, &exprgraph->varbounds[exprgraph->nvars]);
15549  SCIP_CALL( SCIPhashmapInsert(exprgraph->varidxs, vars[0], (void*)(size_t)exprgraph->nvars) ); /*lint !e613*/
15550  ++exprgraph->nvars;
15551 
15552  /* call callback method, if set */
15553  if( exprgraph->exprgraphvaradded != NULL )
15554  {
15555  SCIP_CALL( exprgraph->exprgraphvaradded(exprgraph, exprgraph->userdata, vars[0], varnode) ); /*lint !e613*/
15556  }
15557  }
15558 
15559  /* mark varnode and its parents as not simplified */
15560  if( varnode != NULL )
15561  {
15562  varnode->simplified = FALSE;
15563  for( i = 0; i < varnode->nparents; ++i )
15564  varnode->parents[i]->simplified = FALSE;
15565  }
15566 
15567  return SCIP_OKAY;
15568  }
15569 
15570  /* turn varnode into EXPR_LINEAR */
15571 
15572  /* remove variable (but don't free it's node) from graph */
15573  SCIP_CALL( exprgraphRemoveVar(exprgraph, varidx) );
15574 
15575  /* move varnode up to depth 1 */
15576  SCIP_CALL( exprgraphMoveNode(exprgraph, varnode, 1) );
15577 
15578  /* convert into EXPR_LINEAR node */
15579  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lindata, ncoefs + 1) );
15580  BMScopyMemoryArray(lindata, coefs, ncoefs); /*lint !e644*/
15581  lindata[ncoefs] = constant;
15582  varnode->data.data = (void*)lindata;
15583  varnode->op = SCIP_EXPR_LINEAR;
15584 
15585  /* add nodes corresponding to vars to expression graph, if not existing yet */
15586  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varnode->children, ncoefs) );
15587  SCIP_CALL( SCIPexprgraphAddVars(exprgraph, ncoefs, vars, varnode->children) );
15588  varnode->nchildren = ncoefs;
15589 
15590  /* notify vars about new parent varnode */
15591  for( i = 0; i < ncoefs; ++i )
15592  {
15593  SCIP_CALL( exprgraphNodeAddParent(exprgraph->blkmem, varnode->children[i], varnode) );
15594  }
15595 
15596  /* set value and bounds to invalid, curvature can remain (still linear) */
15597  varnode->value = SCIP_INVALID;
15599 
15600  /* mark varnode and its parents as not simplified */
15601  varnode->simplified = FALSE;
15602  for( i = 0; i < varnode->nparents; ++i )
15603  varnode->parents[i]->simplified = FALSE;
15604 
15605  return SCIP_OKAY;
15606 }
15607 
15608 /** finds expression graph node corresponding to a variable */
15610  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15611  void* var, /**< variable to search for */
15612  SCIP_EXPRGRAPHNODE** varnode /**< buffer to store node corresponding to variable, if found, or NULL if not found */
15613  )
15614 {
15615  int pos;
15616 
15617  assert(exprgraph != NULL);
15618  assert(var != NULL);
15619  assert(varnode != NULL);
15620 
15621  if( !SCIPhashmapExists(exprgraph->varidxs, var) )
15622  {
15623  *varnode = NULL;
15624  return FALSE;
15625  }
15626 
15627  pos = (int)(size_t)SCIPhashmapGetImage(exprgraph->varidxs, var);
15628  assert(pos < exprgraph->nvars);
15629 
15630  *varnode = exprgraph->varnodes[pos];
15631  assert(*varnode != NULL);
15632  assert((*varnode)->op == SCIP_EXPR_VARIDX);
15633 
15634  return TRUE;
15635 }
15636 
15637 /** finds expression graph node corresponding to a constant */
15639  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15640  SCIP_Real constant, /**< constant to search for */
15641  SCIP_EXPRGRAPHNODE** constnode /**< buffer to store node corresponding to constant, if found, or NULL if not found */
15642  )
15643 {
15644  int left;
15645  int right;
15646  int middle;
15647 
15648  assert(exprgraph != NULL);
15649  assert(constnode != NULL);
15650  assert(constant == constant); /* cannot search for nan */ /*lint !e777*/
15651 
15652  exprgraphSortConstNodes(exprgraph);
15653  assert(exprgraph->constssorted);
15654 
15655  /* find node using binary search */
15656  left = 0;
15657  right = exprgraph->nconsts-1;
15658  *constnode = NULL;
15659 
15660  while( left <= right )
15661  {
15662  middle = (left+right)/2;
15663  assert(0 <= middle && middle < exprgraph->nconsts);
15664 
15665  if( constant < exprgraph->constnodes[middle]->data.dbl )
15666  right = middle - 1;
15667  else if( constant > exprgraph->constnodes[middle]->data.dbl )
15668  left = middle + 1;
15669  else
15670  {
15671  *constnode = exprgraph->constnodes[middle];
15672  break;
15673  }
15674  }
15675  if( left == right+1 )
15676  return FALSE;
15677 
15678  assert(*constnode != NULL);
15679  assert((*constnode)->op == SCIP_EXPR_CONST);
15680  assert((*constnode)->data.dbl == constant); /*lint !e777*/
15681 
15682  return TRUE;
15683 }
15684 
15685 /** prints an expression graph in dot format */
15687  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15688  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15689  FILE* file, /**< file to print to, or NULL for stdout */
15690  const char** varnames /**< variable names, or NULL for generic names */
15691  )
15692 {
15693  int d;
15694  int i;
15695 
15696  assert(exprgraph != NULL);
15697 
15698  if( file == NULL )
15699  file = stdout;
15700 
15701  SCIPmessageFPrintInfo(messagehdlr, file, "strict digraph exprgraph {\n");
15702  SCIPmessageFPrintInfo(messagehdlr, file, "node [fontcolor=white, style=filled, rankdir=LR]\n");
15703 
15704  for( d = 0; d < exprgraph->depth; ++d )
15705  {
15706  if( exprgraph->nnodes[d] == 0 )
15707  continue;
15708 
15709  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15710  {
15711  exprgraphPrintNodeDot(exprgraph, exprgraph->nodes[d][i], messagehdlr, file, varnames);
15712  }
15713  }
15714 
15715  /* tell dot that all nodes of depth 0 have the same rank */
15716  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15717  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15718  SCIPmessageFPrintInfo(messagehdlr, file, " n0_%d", i);
15719  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15720 
15721  /* tell dot that all nodes without parent have the same rank */
15722  SCIPmessageFPrintInfo(messagehdlr, file, "{rank=same;");
15723  for( d = 0; d < exprgraph->depth; ++d )
15724  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15725  if( exprgraph->nodes[d][i]->nparents == 0 )
15726  SCIPmessageFPrintInfo(messagehdlr, file, " n%d_%d", d, i);
15727  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15728 
15729  SCIPmessageFPrintInfo(messagehdlr, file, "}\n");
15730 
15731  return SCIP_OKAY;
15732 }
15733 
15734 /** evaluates nodes of expression graph for given values of variables */
15736  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15737  SCIP_Real* varvals /**< values for variables */
15738  )
15739 {
15740  int d;
15741  int i;
15742 
15743  assert(exprgraph != NULL);
15744  assert(varvals != NULL || exprgraph->nvars == 0);
15745 
15746  for( d = 0; d < exprgraph->depth; ++d )
15747  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15748  {
15749  SCIP_CALL( exprgraphNodeEval(exprgraph->nodes[d][i], varvals) );
15750  }
15751 
15752  return SCIP_OKAY;
15753 }
15754 
15755 /** propagates bound changes in variables forward through the expression graph */
15757  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15758  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15759  SCIP_Bool clearreverseprop, /**< whether to reset bound tightenings from reverse propagation */
15760  SCIP_Bool* domainerror /**< buffer to store whether a node with empty bounds has been found, propagation is interrupted in this case */
15761  )
15762 {
15763  SCIP_EXPRGRAPHNODE* node;
15764  SCIP_Bool boundchanged;
15765  int d;
15766  int i;
15767 
15768  assert(exprgraph != NULL);
15769  assert(domainerror != NULL);
15770 
15771  *domainerror = FALSE;
15772 
15773  /* update bounds in varnodes of expression graph */
15774  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15775 
15776  /* if variable bounds have not changed and we do not have to clear a previous backward propagation, we can just return */
15777  if( !boundchanged && !clearreverseprop && !exprgraph->needvarboundprop )
15778  {
15779  SCIPdebugMessage("no bounds changed and clearreverseprop is FALSE -> skip propagation of variable bounds\n");
15780  return SCIP_OKAY;
15781  }
15782 
15783  /* propagate bound changes, interrupt if we get to a node with empty bounds */
15784  for( d = 1; d < exprgraph->depth; ++d )
15785  {
15786  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15787  {
15788  node = exprgraph->nodes[d][i];
15789  SCIP_CALL( exprgraphNodeUpdateBounds(node, infinity, 1e-9, clearreverseprop) );
15790  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15791  {
15792  SCIPdebugMessage("bounds of node %p(%d,%d) empty, stop bounds propagation\n", (void*)node, node->depth, node->pos);
15793  /* we keep exprgraph->needvarboundprop at TRUE, since we interrupt propagation */
15794  *domainerror = TRUE;
15795  return SCIP_OKAY;
15796  }
15797  }
15798  }
15799 
15800  exprgraph->needvarboundprop = FALSE;
15801 
15802  return SCIP_OKAY;
15803 }
15804 
15805 /** propagates bound changes in nodes backward through the graph
15806  *
15807  * New bounds are not stored in varbounds, but only in nodes corresponding to variables.
15808  * NOTE: it is assumed that SCIPexprgraphPropagateVarBounds was called before if variable bounds were relaxed.
15809  */
15811  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15812  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15813  SCIP_Real minstrength, /**< minimal required relative bound strengthening in a node to trigger a propagation into children nodes */
15814  SCIP_Bool* cutoff /**< buffer to store whether a node's bounds were propagated to an empty interval */
15815  )
15816 {
15817  SCIP_EXPRGRAPHNODE* node;
15818  int d;
15819  int i;
15820 
15821  assert(exprgraph != NULL);
15822  assert(cutoff != NULL);
15823 
15824  *cutoff = FALSE;
15825 
15826  for( d = exprgraph->depth-1; d >= 0 && !*cutoff; --d )
15827  {
15828  for( i = 0; i < exprgraph->nnodes[d] && !*cutoff; ++i )
15829  {
15830  node = exprgraph->nodes[d][i];
15831  exprgraphNodePropagateBounds(exprgraph, node, infinity, minstrength, cutoff);
15832  }
15833  }
15834  if( *cutoff )
15835  return;
15836 }
15837 
15838 /** updates curvature information in expression graph nodes w.r.t. currently stored variable bounds
15839  *
15840  * Implies update of bounds in expression graph.
15841  */
15843  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15844  SCIP_Real infinity, /**< value for infinity in interval arithmetics */
15845  SCIP_Bool clearreverseprop /**< whether to reset bound tightenings from reverse propagation */
15846  )
15847 {
15848  SCIP_EXPRGRAPHNODE* node;
15849  SCIP_Bool boundchanged;
15850  int d;
15851  int i;
15852 
15853  assert(exprgraph != NULL);
15854 
15855  /* update bounds in varnodes of expression graph */
15856  exprgraphUpdateVarNodeBounds(exprgraph, &clearreverseprop, &boundchanged);
15857 
15858 #ifndef NDEBUG
15859  for( i = 0; i < exprgraph->nnodes[0]; ++i )
15860  assert(exprgraph->nodes[0][i]->curv == SCIP_EXPRCURV_LINEAR);
15861 #endif
15862 
15863  for( d = 1; d < exprgraph->depth; ++d )
15864  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15865  {
15866  node = exprgraph->nodes[d][i];
15867  assert(node != NULL);
15868 
15869  SCIP_CALL( SCIPexprgraphUpdateNodeBoundsCurvature(node, infinity, 1e-9, clearreverseprop) );
15870 
15871  if( SCIPintervalIsEmpty(infinity, node->bounds) )
15872  {
15873  SCIPerrorMessage("SCIPexprgraphCheckCurvature gets domain error while propagating variables bounds, ignoring...\n");
15874  return SCIP_OKAY;
15875  }
15876  }
15877 
15878  return SCIP_OKAY;
15879 }
15880 
15881 /** aims at simplifying an expression graph
15882  *
15883  * 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)).
15884  */
15886  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
15887  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
15888  SCIP_Real eps, /**< threshold, under which positive values are treat as 0 */
15889  int maxexpansionexponent,/**< maximal exponent for which we still expand non-monomial polynomials */
15890  SCIP_Bool* havechange, /**< buffer to indicate whether the graph has been modified */
15891  SCIP_Bool* domainerror /**< buffer to indicate whether a domain error has been encountered, i.e., some expressions turned into NaN */
15892  )
15893 {
15894  SCIP_EXPRGRAPHNODE* node;
15895  SCIP_Bool havechangenode;
15896  SCIP_Bool allsimplified;
15897  int d;
15898  int i;
15899  int j;
15900 
15901 #ifndef NDEBUG
15902  SCIP_Real* testx;
15903  SCIP_HASHMAP* testvalidx;
15904  SCIP_Real* testvals;
15905  SCIP_RANDNUMGEN* randnumgen;
15906  int testvalssize;
15907  int ntestvals;
15908 #endif
15909 
15910  assert(exprgraph != NULL);
15911  assert(eps >= 0.0);
15912  assert(havechange != NULL);
15913  assert(domainerror != NULL);
15914 
15915 #ifndef NDEBUG
15916  SCIP_CALL( SCIPrandomCreate(&randnumgen, exprgraph->blkmem, DEFAULT_RANDSEED) );
15917  SCIP_CALL( SCIPhashmapCreate(&testvalidx, exprgraph->blkmem, 1000) );
15918  testvals = NULL;
15919  ntestvals = 0;
15920  testvalssize = 0;
15921 
15922  SCIP_ALLOC( BMSallocMemoryArray(&testx, exprgraph->nvars) );
15923  for( i = 0; i < exprgraph->nvars; ++i )
15924  testx[i] = SCIPrandomGetReal(randnumgen, -100.0, 100.0); /*lint !e644*/
15925  SCIP_CALL( SCIPexprgraphEval(exprgraph, testx) );
15926  for( d = 1; d < exprgraph->depth; ++d )
15927  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15928  {
15929  node = exprgraph->nodes[d][i];
15930  assert(node != NULL);
15931 
15932  /* 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 */
15933  if( node->nuses > 0 )
15934  {
15935  ensureBlockMemoryArraySize(exprgraph->blkmem, &testvals, &testvalssize, ntestvals+1);
15936  SCIP_CALL( SCIPhashmapInsert(testvalidx, (void*)node, (void*)(size_t)ntestvals) );
15937  testvals[ntestvals] = SCIPexprgraphGetNodeVal(node); /*lint !e613 !e794*/
15938  ++ntestvals;
15939  }
15940  }
15941 
15942  SCIPrandomFree(&randnumgen);
15943 #endif
15944 
15945 #ifdef SCIP_OUTPUT
15946  {
15947  FILE* file;
15948  file = fopen("exprgraph_beforesimplify.dot", "w");
15949  if( file != NULL )
15950  {
15951  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
15952  fclose(file);
15953  }
15954  }
15955 #endif
15956 
15957  *havechange = FALSE; /* we have not changed any node yet */
15958  *domainerror = FALSE; /* no domain errors encountered so far */
15959  allsimplified = TRUE; /* all nodes we looked at are simplified */
15960 
15961  /* call node simplifier from bottom up
15962  * for each node, convert to polynomials and merge in child nodes that are not in use otherwise, if possible
15963  */
15964  for( d = 1; d < exprgraph->depth && !*domainerror; ++d )
15965  {
15966  for( i = 0; i < exprgraph->nnodes[d]; ++i )
15967  {
15968  node = exprgraph->nodes[d][i];
15969  assert(node != NULL);
15970 
15971  havechangenode = FALSE; /* node did not change yet */
15972 
15973  if( node->op != SCIP_EXPR_CONST )
15974  {
15975  /* skip nodes that are already simplified */
15976  if( node->simplified )
15977  continue;
15978 
15979  allsimplified = FALSE; /* looks like we found a node that has not been simplified */
15980 
15981  /* we should be careful about declaring numbers close to zero as zero, so take eps^2 as tolerance */
15982  SCIP_CALL( exprgraphNodeSimplify(exprgraph, node, messagehdlr, eps*eps, maxexpansionexponent, &havechangenode) );
15983  assert(node->simplified == TRUE);
15984  *havechange |= havechangenode;
15985  }
15986 
15987  /* if node was or has been converted into constant, may move to depth 0 */
15988  if( node->op == SCIP_EXPR_CONST )
15989  {
15990  SCIP_EXPRGRAPHNODE* constnode;
15991 
15992  if( !SCIPisFinite(node->value) ) /*lint !e777*/
15993  {
15994  SCIPdebugMessage("Expression graph simplify turned node into NaN or inf.\n");
15995  *domainerror = TRUE;
15996  break;
15997  }
15998 
15999  /* check if there is already a node for this constant */
16000  if( SCIPexprgraphFindConstNode(exprgraph, node->value, &constnode) )
16001  {
16002  assert(constnode->op == SCIP_EXPR_CONST);
16003  assert(constnode->data.dbl == node->value); /*lint !e777*/
16004 
16005  if( node->nparents > 0 )
16006  {
16007  /* move parents of this node to constnode, node may be freed if not in use */
16008  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &node, constnode) );
16009  /* node should have no parents anymore, so it should have been freed if not in use */
16010  assert(node == NULL || node->nuses > 0);
16011  havechangenode = TRUE;
16012 
16013  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be simplified */
16014  if( node == NULL )
16015  {
16016  --i;
16017  continue;
16018  }
16019  }
16020  assert(node != NULL);
16021  assert(node->nuses > 0);
16022 
16023  if( constnode->nuses == 0 )
16024  {
16025  /* move node to depth 0, adding it to constnodes */
16026  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16027 
16028  /* move parents of constnode to node, so constnode is freed */
16029  SCIP_CALL( SCIPexprgraphMoveNodeParents(exprgraph, &constnode, node) );
16030  assert(constnode == NULL);
16031  havechangenode = TRUE;
16032 
16033  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16034  --i;
16035  continue;
16036  }
16037  }
16038  else
16039  {
16040  /* move to depth 0, adding it to constnodes */
16041  SCIP_CALL( exprgraphMoveNode(exprgraph, node, 0) );
16042 
16043  /* node moved to depth 0, so exprgraph->nodes[i] points to the next node that need to be simplified */
16044  --i;
16045  }
16046  }
16047 
16048  /* if there was a change, mark parents as not simplified */
16049  if( havechangenode )
16050  for( j = 0; j < node->nparents; ++j )
16051  node->parents[j]->simplified = FALSE;
16052  }
16053  } /*lint !e850*/
16054 
16055  /* if we did nothing, clean up and escape from here */
16056  if( allsimplified || *domainerror )
16057  goto EXPRGRAPHSIMPLIFY_CLEANUP;
16058 
16059  /* @todo find duplicate subexpressions in expression graph */
16060 
16061  /* unconvert polynomials into simpler expressions, where possible */
16062  for( d = 1; d < exprgraph->depth; ++d )
16063  {
16064  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16065  {
16066  node = exprgraph->nodes[d][i];
16067  assert(node != NULL);
16068 
16069  if( node->op != SCIP_EXPR_POLYNOMIAL )
16070  continue;
16071 
16072  SCIP_CALL( exprUnconvertPolynomial(exprgraph->blkmem, &node->op, &node->data, node->nchildren, (void**)node->children) );
16073 
16074  if( node->op == SCIP_EXPR_SUM && node->nchildren == 1 )
16075  {
16076  /* node is identity w.r.t only child
16077  * replace node as child of parents by child of node
16078  */
16079 
16080  for( j = 0; node != NULL && j < node->nparents; ++j )
16081  {
16082  SCIP_CALL( exprgraphNodeReplaceChild(exprgraph, node->parents[j], &node, node->children[0]) );
16083  }
16084  /* node should have no parents anymore, so it should have been freed if not in use */
16085  assert(node == NULL || node->nuses > 0);
16086 
16087  /* if node was freed, exprgraph->nodes[i] points to the next node that need to be unconverted */
16088  if( node == NULL )
16089  --i;
16090  }
16091  }
16092  } /*lint !e850*/
16093 
16094 #ifdef SCIP_OUTPUT
16095  {
16096  FILE* file;
16097  file = fopen("exprgraph_aftersimplify.dot", "w");
16098  if( file != NULL )
16099  {
16100  SCIP_CALL( SCIPexprgraphPrintDot(exprgraph, messagehdlr, file, NULL) );
16101  fclose(file);
16102  }
16103  }
16104 #endif
16105 
16106 #ifndef NDEBUG
16107  for( d = 1; d < exprgraph->depth; ++d )
16108  for( i = 0; i < exprgraph->nnodes[d]; ++i )
16109  {
16110  int idx;
16111  SCIP_Real testval_before;
16112  SCIP_Real testval_after;
16113 
16114  node = exprgraph->nodes[d][i];
16115  assert(node != NULL);
16116 
16117  SCIP_CALL( exprgraphNodeEval(node, NULL) );
16118 
16119  /* nodes that are in use should not have been removed by simplifier, check if they still have the same value in our testpoint */
16120  if( node->nuses > 0 )
16121  {
16122  assert(SCIPhashmapExists(testvalidx, (void*)node));
16123 
16124  idx = (int)(size_t)(void*)SCIPhashmapGetImage(testvalidx, (void*)node);
16125  assert(idx < ntestvals);
16126 
16127  testval_before = testvals[idx]; /*lint !e613*/
16128  testval_after = SCIPexprgraphGetNodeVal(node);
16129 
16130  assert(!SCIPisFinite(testval_before) || EPSZ(SCIPrelDiff(testval_before, testval_after), eps)); /*lint !e777*/
16131  }
16132  }
16133 #endif
16134 
16135  EXPRGRAPHSIMPLIFY_CLEANUP:
16136 #ifndef NDEBUG
16137  BMSfreeMemoryArray(&testx);
16138  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &testvals, testvalssize);
16139  SCIPhashmapFree(&testvalidx);
16140 #endif
16141 
16142  return SCIP_OKAY;
16143 }
16144 
16145 /** creates an expression tree from a given node in an expression graph */
16147  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16148  SCIP_EXPRGRAPHNODE* rootnode, /**< expression graph node that should represent root of expression tree */
16149  SCIP_EXPRTREE** exprtree /**< buffer to store pointer to created expression tree */
16150  )
16151 {
16152  SCIP_EXPR* root;
16153  int nexprvars;
16154  int* varidx;
16155  int i;
16156 
16157  assert(exprgraph != NULL);
16158  assert(rootnode != NULL);
16159  assert(rootnode->depth >= 0);
16160  assert(rootnode->pos >= 0);
16161  assert(exprtree != NULL);
16162 
16163  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16164  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16165 
16166  /* initially, no variable appears in the expression tree */
16167  for( i = 0; i < exprgraph->nvars; ++i )
16168  varidx[i] = -1; /*lint !e644*/
16169  nexprvars = 0;
16170 
16171  /* create expression from the subgraph that has rootnode as root */
16172  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, rootnode, &root, &nexprvars, varidx) );
16173 
16174  /* create expression tree for this expression */
16175  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, exprtree, root, nexprvars, 0, NULL) );
16176 
16177  /* copy variables into expression tree */
16178  if( nexprvars > 0 )
16179  {
16180  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &(*exprtree)->vars, nexprvars) );
16181  for( i = 0; i < exprgraph->nvars; ++i )
16182  {
16183  assert(varidx[i] >= -1);
16184  assert(varidx[i] < nexprvars);
16185  if( varidx[i] >= 0 )
16186  (*exprtree)->vars[varidx[i]] = exprgraph->vars[i];
16187  }
16188  }
16189 
16190  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16191 
16192  return SCIP_OKAY;
16193 }
16194 
16195 /** creates a sum of expression trees with pairwise disjoint variables from a given node in an expression graph
16196  *
16197  * Giving SCIPexprgraphGetNodeNChildren() for exprtreesize is always sufficient.
16198  */
16200  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16201  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16202  int exprtreessize, /**< length of exprtrees and exprtreecoefs arrays, need to be at least one */
16203  int* nexprtrees, /**< buffer to store number of expression trees */
16204  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16205  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16206  )
16207 {
16208  int ncomponents;
16209  int* childcomp;
16210  int* varcomp;
16211  int compnr;
16212  SCIP_Bool haveoverlap;
16213  int i;
16214  int j;
16215  int k;
16216 
16217  SCIP_EXPR** exprs;
16218  int nexprs;
16219  int* childmap;
16220  int* childmapinv;
16221  int* varidx;
16222  int nexprvars;
16223 
16224  assert(exprgraph != NULL);
16225  assert(node != NULL);
16226  assert(node->depth >= 0);
16227  assert(node->pos >= 0);
16228  assert(exprtreessize > 0);
16229  assert(nexprtrees != NULL);
16230  assert(exprtrees != NULL);
16231  assert(exprtreecoefs != NULL);
16232 
16233  /* easy cases: if we have space for only one tree or there is only one child or only one variable in the graph,
16234  * or the node operator is not separable, fallback to SCIPexprgraphGetTree */
16235  if( exprtreessize == 1 || node->nchildren <= 1 || exprgraph->nvars <= 1 ||
16236  ( node->op != SCIP_EXPR_PLUS &&
16237  node->op != SCIP_EXPR_MINUS &&
16238  node->op != SCIP_EXPR_SUM &&
16239  node->op != SCIP_EXPR_LINEAR &&
16240  (node->op != SCIP_EXPR_QUADRATIC || ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1) &&
16241  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1)) )
16242  {
16243  *nexprtrees = 1;
16244  exprtreecoefs[0] = 1.0;
16245  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16246 
16247  return SCIP_OKAY;
16248  }
16249 
16250  /* find components in node->children <-> variables graph */
16251  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren) );
16252  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars) );
16253  for( i = 0; i < exprgraph->nvars; ++i )
16254  varcomp[i] = -1; /*lint !e644*/
16255 
16256  haveoverlap = FALSE;
16257  for( i = 0; i < node->nchildren; ++i )
16258  {
16259  compnr = i;
16260  exprgraphNodeCheckSeparabilityComponent(node->children[i], &compnr, i-1, childcomp, exprgraph->nvars, varcomp); /*lint !e644*/
16261  assert(compnr >= 0);
16262  assert(compnr < node->nchildren);
16263  childcomp[i] = compnr;
16264 
16265  /* remember if component number was changed by CheckComponent */
16266  if( compnr != i )
16267  haveoverlap = TRUE;
16268  }
16269 
16270  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varcomp, exprgraph->nvars);
16271 
16272  if( node->op == SCIP_EXPR_QUADRATIC )
16273  {
16274  /* merge components for products of children from different components */
16276 
16277  data = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16278  assert(data != NULL);
16279 
16280  for( i = 0; i < data->nquadelems; ++i )
16281  if( childcomp[data->quadelems[i].idx1] != childcomp[data->quadelems[i].idx2] )
16282  {
16283  /* reassign all children in component childcomp[data->quadelems[i].idx2] to component childcomp[data->quadelems[i].idx1] */
16284  compnr = childcomp[data->quadelems[i].idx2];
16285  for( j = 0; j < node->nchildren; ++j )
16286  if( childcomp[j] == compnr )
16287  childcomp[j] = childcomp[data->quadelems[i].idx1];
16288  assert(childcomp[data->quadelems[i].idx1] == childcomp[data->quadelems[i].idx2]);
16289  haveoverlap = TRUE;
16290  }
16291  }
16292  else if( node->op == SCIP_EXPR_POLYNOMIAL )
16293  {
16294  /* merge components for monomials of children from different components */
16296 
16297  data = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16298  assert(data != NULL);
16299 
16300  for( i = 0; i < data->nmonomials; ++i )
16301  for( j = 1; j < data->monomials[i]->nfactors; ++j )
16302  if( childcomp[data->monomials[i]->childidxs[j]] != childcomp[data->monomials[i]->childidxs[0]] )
16303  {
16304  /* reassign all children in component childcomp[data->monomials[i]->childidxs[j]] to component childcomp[data->monomials[i]->childidxs[0]] */
16305  compnr = childcomp[data->monomials[i]->childidxs[j]];
16306  for( k = 0; k < node->nchildren; ++k )
16307  if( childcomp[k] == compnr )
16308  childcomp[k] = childcomp[data->monomials[i]->childidxs[0]];
16309  assert(childcomp[data->monomials[i]->childidxs[j]] == childcomp[data->monomials[i]->childidxs[0]]);
16310  haveoverlap = TRUE;
16311  }
16312  }
16313 
16314  if( haveoverlap )
16315  {
16316  /* some component numbers are unused, thus relabel and count final number of components */
16317  int* compmap;
16318 
16319  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren) );
16320  for( i = 0; i < node->nchildren; ++i )
16321  compmap[i] = -1; /*lint !e644*/
16322 
16323  ncomponents = 0;
16324  for( i = 0; i < node->nchildren; ++i )
16325  {
16326  if( compmap[childcomp[i]] == -1 )
16327  compmap[childcomp[i]] = ncomponents++;
16328  childcomp[i] = compmap[childcomp[i]];
16329  }
16330 
16331  BMSfreeBlockMemoryArray(exprgraph->blkmem, &compmap, node->nchildren);
16332  }
16333  else
16334  {
16335  ncomponents = node->nchildren;
16336  }
16337 
16338  if( ncomponents == 1 )
16339  {
16340  /* it turned out that expression is not block separable, so fallback to SCIPexprgraphGetTree */
16341  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16342 
16343  *nexprtrees = 1;
16344  exprtreecoefs[0] = 1.0;
16345  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16346 
16347  return SCIP_OKAY;
16348  }
16349 
16350  if( ncomponents > exprtreessize )
16351  {
16352  /* if we have not enough space for all expressions, merge components with number > exprtreessize into component exprtreessize */
16353  for( i = 0; i < node->nchildren; ++i )
16354  if( childcomp[i] >= exprtreessize )
16355  childcomp[i] = exprtreessize-1;
16356  ncomponents = exprtreessize;
16357  }
16358 
16359  assert(ncomponents >= 2);
16360 
16361  /* setup expression trees for each component */
16362  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren) );
16363  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) ); /* mapping of expression graph variable indices to expression tree variable indices */
16364  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren) ); /* mapping of child indices from node to expressions belonging to a single component */
16365  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren) ); /* mapping of child indices from expressions belonging to a single component to node */
16366  for( i = 0; i < ncomponents; ++i )
16367  {
16368  /* initially, no variable appears in the expression tree */
16369  for( j = 0; j < exprgraph->nvars; ++j )
16370  varidx[j] = -1; /*lint !e644*/
16371  nexprvars = 0;
16372 
16373  /* collect expressions from children belonging to component i */
16374  nexprs = 0;
16375  for( j = 0; j < node->nchildren; ++j )
16376  {
16377  assert(childcomp[j] >= 0);
16378  assert(childcomp[j] < ncomponents);
16379  if( childcomp[j] != i )
16380  continue;
16381 
16382  /* create expression from the subgraph that has child j as root */
16383  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[j], &exprs[nexprs], &nexprvars, varidx) ); /*lint !e644*/
16384  childmap[j] = nexprs; /*lint !e644*/
16385  childmapinv[nexprs] = j; /*lint !e644*/
16386  ++nexprs;
16387  }
16388 
16389  /* setup expression tree for component i */
16390  switch( node->op )
16391  {
16392  case SCIP_EXPR_PLUS:
16393  {
16394  assert(ncomponents == 2);
16395  assert(nexprs == 1);
16396 
16397  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16398  exprtreecoefs[i] = 1.0;
16399 
16400  break;
16401  }
16402 
16403  case SCIP_EXPR_MINUS:
16404  {
16405  assert(ncomponents == 2);
16406  assert(nexprs == 1);
16407 
16408  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16409  /* if component i consists of first child, then it has coefficient 1.0, otherwise it has coefficient -1 */
16410  assert(childmapinv[0] == 0 || childmapinv[0] == 1);
16411  exprtreecoefs[i] = (childmapinv[0] == 0 ? 1.0 : -1.0);
16412 
16413  break;
16414  }
16415 
16416  case SCIP_EXPR_SUM:
16417  {
16418  if( nexprs == 1 )
16419  {
16420  /* component corresponds to exactly one child of node */
16421  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16422  }
16423  else
16424  {
16425  /* component corresponds to a sum of children of node */
16426  SCIP_EXPR* sumexpr;
16427 
16428  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16429  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16430  }
16431  exprtreecoefs[i] = 1.0;
16432 
16433  break;
16434  }
16435 
16436  case SCIP_EXPR_LINEAR:
16437  {
16438  SCIP_Real* nodecoefs;
16439  SCIP_EXPR* sumexpr;
16440 
16441  nodecoefs = (SCIP_Real*)node->data.data;
16442 
16443  /* if there is a constant, then we put it into the expression of the first component */
16444  if( nexprs == 1 && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16445  {
16446  /* component corresponds to exactly one child of node */
16447  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], exprs[0], nexprvars, 0, NULL) );
16448  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16449  }
16450  else if( nexprs == 1 )
16451  {
16452  /* component corresponds to a sum of one child and a constant */
16453  assert(i == 0);
16454  assert(nodecoefs[node->nchildren] != 0.0);
16455  assert(nodecoefs[childmapinv[0]] != 0.0);
16456  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_CONST, nodecoefs[node->nchildren]/nodecoefs[childmapinv[0]]) );
16457  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, sumexpr, exprs[0]) );
16458  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16459  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16460  }
16461  else
16462  {
16463  /* component corresponds to a linear combination of children of node */
16464 
16465  if( nexprs == 2 && nodecoefs[childmapinv[0]] == nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16466  {
16467  /* if two expressions with equal sign, then create PLUS expression */
16468  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_PLUS, exprs[0], exprs[1]) );
16469  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16470  }
16471  else if( nexprs == 2 && nodecoefs[childmapinv[0]] == -nodecoefs[childmapinv[1]] && (i > 0 || nodecoefs[node->nchildren] == 0.0) ) /*lint !e777*/
16472  {
16473  /* if two expressions with opposite sign, then create MINUS expression */
16474  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_MINUS, exprs[0], exprs[1]) );
16475  exprtreecoefs[i] = nodecoefs[childmapinv[0]];
16476  }
16477  else
16478  {
16479  /* assemble coefficents and create SUM or LINEAR expression */
16480  SCIP_Real* coefs;
16481  SCIP_Bool allcoefsequal;
16482 
16483  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs) );
16484  allcoefsequal = TRUE;
16485  coefs[0] = nodecoefs[childmapinv[0]]; /*lint !e644*/
16486  for( j = 0; j < nexprs; ++j )
16487  {
16488  coefs[j] = nodecoefs[childmapinv[j]];
16489  allcoefsequal &= (coefs[j] == coefs[0]); /*lint !e777 !e514*/
16490  }
16491 
16492  /* if all coefficients are equal and no constant, create SUM expression, otherwise LINEAR expression */
16493  if( allcoefsequal && (i > 0 || nodecoefs[node->nchildren] == 0.0) )
16494  {
16495  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &sumexpr, SCIP_EXPR_SUM, nexprs, exprs) );
16496  exprtreecoefs[i] = coefs[0];
16497  }
16498  else
16499  {
16500  SCIP_CALL( SCIPexprCreateLinear(exprgraph->blkmem, &sumexpr, nexprs, exprs, coefs, i == 0 ? nodecoefs[node->nchildren] : 0.0) );
16501  exprtreecoefs[i] = 1.0;
16502  }
16503 
16504  BMSfreeBlockMemoryArray(exprgraph->blkmem, &coefs, nexprs);
16505  }
16506 
16507  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], sumexpr, nexprvars, 0, NULL) );
16508  }
16509 
16510  break;
16511  }
16512 
16513  case SCIP_EXPR_QUADRATIC:
16514  {
16515  SCIP_EXPR* quadexpr;
16517  SCIP_Real* lincoefs;
16518  SCIP_QUADELEM* quadelems;
16519  int nquadelems;
16520 
16521  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16522 
16523  exprtreecoefs[i] = 1.0;
16524 
16525  /* assemble coefficients corresponding to component i */
16526  if( nodedata->lincoefs != NULL )
16527  {
16528  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &lincoefs, nexprs) );
16529  for( j = 0; j < nexprs; ++j )
16530  lincoefs[j] = nodedata->lincoefs[childmapinv[j]]; /*lint !e771*/
16531  }
16532  else
16533  lincoefs = NULL;
16534 
16535  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems) );
16536  nquadelems = 0;
16537  for( j = 0; j < nodedata->nquadelems; ++j )
16538  {
16539  assert(childcomp[nodedata->quadelems[j].idx1] == childcomp[nodedata->quadelems[j].idx2]);
16540  if( childcomp[nodedata->quadelems[j].idx1] != i )
16541  continue;
16542  quadelems[nquadelems].idx1 = MIN(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]); /*lint !e644*/
16543  quadelems[nquadelems].idx2 = MAX(childmap[nodedata->quadelems[j].idx1], childmap[nodedata->quadelems[j].idx2]);
16544  quadelems[nquadelems].coef = nodedata->quadelems[j].coef;
16545  ++nquadelems;
16546  }
16547 
16548  /* put constant into first component */
16549  SCIP_CALL( SCIPexprCreateQuadratic(exprgraph->blkmem, &quadexpr, nexprs, exprs, i == 0 ? nodedata->constant : 0.0, lincoefs, nquadelems, quadelems) );
16550  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], quadexpr, nexprvars, 0, NULL) );
16551 
16552  BMSfreeBlockMemoryArray(exprgraph->blkmem, &quadelems, nodedata->nquadelems);
16553  BMSfreeBlockMemoryArrayNull(exprgraph->blkmem, &lincoefs, nexprs);
16554 
16555  break;
16556  }
16557 
16558  case SCIP_EXPR_POLYNOMIAL:
16559  {
16560  SCIP_EXPR* polyexpr;
16562  SCIP_EXPRDATA_MONOMIAL** monomials;
16563  SCIP_Real constant;
16564  int nmonomials;
16565 
16566  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16567 
16568  constant = nodedata->constant;
16569  exprtreecoefs[i] = 1.0;
16570 
16571  /* collect monomials belonging to component i */
16572  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials) );
16573  nmonomials = 0;
16574  for( j = 0; j < nodedata->nmonomials; ++j )
16575  {
16576  if( nodedata->monomials[j]->nfactors == 0 )
16577  {
16578  constant += nodedata->monomials[j]->coef;
16579  continue;
16580  }
16581  if( childcomp[nodedata->monomials[j]->childidxs[0]] != i )
16582  continue;
16583 
16584  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomials[nmonomials], nodedata->monomials[j]->coef, nodedata->monomials[j]->nfactors,
16585  nodedata->monomials[j]->childidxs, nodedata->monomials[j]->exponents) ); /*lint !e644*/
16586  for( k = 0; k < monomials[nmonomials]->nfactors; ++k )
16587  {
16588  assert(childcomp[nodedata->monomials[j]->childidxs[k]] == i);
16589  monomials[nmonomials]->childidxs[k] = childmap[monomials[nmonomials]->childidxs[k]];
16590  }
16591  ++nmonomials;
16592  }
16593 
16594  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &polyexpr, nexprs, exprs, nmonomials, monomials, i == 0 ? constant : 0.0, FALSE) );
16595  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[i], polyexpr, nexprvars, 0, NULL) );
16596 
16597  BMSfreeBlockMemoryArray(exprgraph->blkmem, &monomials, nodedata->nmonomials);
16598 
16599  break;
16600  }
16601 
16602  default:
16603  SCIPerrorMessage("unexpected operator type %d\n", node->op);
16604  return SCIP_ERROR;
16605  } /*lint !e788*/
16606 
16607  /* copy variables into expression tree */
16608  if( nexprvars > 0 )
16609  {
16610  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[i]->vars, nexprvars) );
16611  for( j = 0; j < exprgraph->nvars; ++j )
16612  {
16613  assert(varidx[j] >= -1);
16614  assert(varidx[j] < nexprvars);
16615  if( varidx[j] >= 0 )
16616  exprtrees[i]->vars[varidx[j]] = exprgraph->vars[j];
16617  }
16618  }
16619  }
16620 
16621  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, node->nchildren);
16622  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16623  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmap, node->nchildren);
16624  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childmapinv, node->nchildren);
16625  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childcomp, node->nchildren);
16626 
16627  *nexprtrees = ncomponents;
16628 
16629  return SCIP_OKAY;
16630 }
16631 
16632 /** returns how often expression graph variables are used in a subtree of the expression graph */
16634  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16635  SCIP_EXPRGRAPHNODE* node, /**< root node of expression graph subtree */
16636  int* varsusage /**< array where to count usage of variables, length must be at least the number of variables in the graph */
16637  )
16638 {
16639  assert(exprgraph != NULL);
16640  assert(node != NULL);
16641  assert(varsusage != NULL);
16642 
16643  BMSclearMemoryArray(varsusage, exprgraph->nvars);
16644 
16645  exprgraphNodeGetVarsUsage(node, varsusage);
16646 }
16647 
16648 /** gives the number of summands which the expression of an expression graph node consists of */
16650  SCIP_EXPRGRAPHNODE* node /**< expression graph node */
16651  )
16652 {
16653  switch( node->op )
16654  {
16655  case SCIP_EXPR_PLUS:
16656  case SCIP_EXPR_MINUS:
16657  return 2;
16658 
16659  case SCIP_EXPR_SUM:
16660  case SCIP_EXPR_LINEAR:
16661  return node->nchildren;
16662 
16663  case SCIP_EXPR_QUADRATIC:
16664  {
16666 
16667  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16668  return (nodedata->lincoefs != NULL ? node->nchildren : 0) + nodedata->nquadelems;
16669  }
16670 
16671  case SCIP_EXPR_POLYNOMIAL:
16672  {
16674 
16675  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16676  return nodedata->nmonomials;
16677  }
16678 
16679  default:
16680  return 1;
16681  } /*lint !e788*/
16682 }
16683 
16684 /** creates a sum of expression trees, possibly sharing variables, from a given node in an expression graph */
16686  SCIP_EXPRGRAPH* exprgraph, /**< expression graph */
16687  SCIP_EXPRGRAPHNODE* node, /**< expression graph node which represents expression to get */
16688  int exprtreessize, /**< length of exprtrees and exptreecoefs arrays, should be at least SCIPexprgraphGetSumTreesNSummands() */
16689  int* nexprtrees, /**< buffer to store number of expression trees */
16690  SCIP_EXPRTREE** exprtrees, /**< array where to store expression trees */
16691  SCIP_Real* exprtreecoefs /**< array where to store coefficients of expression trees */
16692  )
16693 {
16694  int* varidx;
16695  int nexprvars;
16696  int i;
16697 
16698  assert(exprgraph != NULL);
16699  assert(node != NULL);
16700  assert(node->depth >= 0);
16701  assert(node->pos >= 0);
16702  assert(exprtreessize > 0);
16703  assert(nexprtrees != NULL);
16704  assert(exprtrees != NULL);
16705  assert(exprtreecoefs != NULL);
16706 
16707  /* if node is not separable, fallback to SCIPexprgraphGetTree */
16708  if( node->op != SCIP_EXPR_PLUS &&
16709  node->op != SCIP_EXPR_MINUS &&
16710  node->op != SCIP_EXPR_SUM &&
16711  (node->op != SCIP_EXPR_LINEAR || node->nchildren <= 1) &&
16712  (node->op != SCIP_EXPR_QUADRATIC || (((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->lincoefs == NULL && ((SCIP_EXPRDATA_QUADRATIC*)node->data.data)->nquadelems <= 1)) &&
16713  (node->op != SCIP_EXPR_POLYNOMIAL || ((SCIP_EXPRDATA_POLYNOMIAL*)node->data.data)->nmonomials <= 1) )
16714  {
16715  *nexprtrees = 1;
16716  exprtreecoefs[0] = 1.0;
16717  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node, exprtrees) );
16718 
16719  return SCIP_OKAY;
16720  }
16721 
16722  switch( node->op )
16723  {
16724  case SCIP_EXPR_PLUS:
16725  {
16726  assert(exprtreessize >= 2);
16727 
16728  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16729  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16730 
16731  exprtreecoefs[0] = 1.0;
16732  exprtreecoefs[1] = 1.0;
16733 
16734  *nexprtrees = 2;
16735  break;
16736  }
16737 
16738  case SCIP_EXPR_MINUS:
16739  {
16740  assert(exprtreessize >= 2);
16741 
16742  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[0], &exprtrees[0]) );
16743  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[1], &exprtrees[1]) );
16744 
16745  exprtreecoefs[0] = 1.0;
16746  exprtreecoefs[1] = -1.0;
16747 
16748  *nexprtrees = 2;
16749  break;
16750  }
16751 
16752  case SCIP_EXPR_SUM:
16753  {
16754  assert(exprtreessize >= node->nchildren);
16755 
16756  for( i = 0; i < node->nchildren; ++i )
16757  {
16758  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16759  exprtreecoefs[i] = 1.0;
16760  }
16761 
16762  *nexprtrees = node->nchildren;
16763  break;
16764  }
16765 
16766  case SCIP_EXPR_LINEAR:
16767  {
16768  SCIP_Real* nodecoefs;
16769 
16770  assert(exprtreessize >= node->nchildren);
16771  assert(node->nchildren > 0);
16772 
16773  nodecoefs = (SCIP_Real*)node->data.data;
16774  assert(nodecoefs != NULL);
16775 
16776  for( i = 0; i < node->nchildren; ++i )
16777  {
16778  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[i]) );
16779  exprtreecoefs[i] = nodecoefs[i];
16780  }
16781 
16782  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16783  if( nodecoefs[node->nchildren] != 0.0 )
16784  {
16785  SCIP_EXPR* constexpr_;
16786 
16787  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodecoefs[node->nchildren] / exprtreecoefs[0]) );
16788  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16789  }
16790 
16791  *nexprtrees = node->nchildren;
16792  break;
16793  }
16794 
16795  case SCIP_EXPR_QUADRATIC:
16796  {
16798  SCIP_Real* lincoefs;
16799  SCIP_QUADELEM* quadelems;
16800  int nquadelems;
16801  SCIP_EXPR* expr;
16802  int j;
16803 
16804  nodedata = (SCIP_EXPRDATA_QUADRATIC*)node->data.data;
16805  lincoefs = nodedata->lincoefs;
16806  quadelems = nodedata->quadelems;
16807  nquadelems = nodedata->nquadelems;
16808 
16809  assert(exprtreessize >= (lincoefs != NULL ? node->nchildren : 0) + nquadelems);
16810  assert(node->nchildren > 0);
16811 
16812  *nexprtrees = 0;
16813  if( lincoefs != NULL )
16814  {
16815  for( i = 0; i < node->nchildren; ++i )
16816  {
16817  if( lincoefs[i] == 0.0 )
16818  continue;
16819  SCIP_CALL( SCIPexprgraphGetTree(exprgraph, node->children[i], &exprtrees[*nexprtrees]) );
16820  exprtreecoefs[*nexprtrees] = lincoefs[i];
16821  ++*nexprtrees;
16822  }
16823  }
16824 
16825  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16826  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16827 
16828  for( i = 0; i < nquadelems; ++i )
16829  {
16830  /* initially, no variable appears in the expression tree */
16831  for( j = 0; j < exprgraph->nvars; ++j )
16832  varidx[j] = -1; /*lint !e644*/
16833  nexprvars = 0;
16834 
16835  /* create expression from the subgraph at quadelems[i].idx1 */
16836  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx1], &expr, &nexprvars, varidx) );
16837 
16838  if( quadelems[i].idx1 == quadelems[i].idx2 )
16839  {
16840  /* create expression for square of expr */
16841  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16842  }
16843  else
16844  {
16845  SCIP_EXPR* expr2;
16846 
16847  /* create expression from the subgraph at quadelems[i].idx2, may add more variables into varidx */
16848  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[quadelems[i].idx2], &expr2, &nexprvars, varidx) );
16849  /* create expression for product */
16850  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16851  }
16852 
16853  /* create expression tree for expr */
16854  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16855 
16856  /* copy variables into expression tree */
16857  if( nexprvars > 0 )
16858  {
16859  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16860  for( j = 0; j < exprgraph->nvars; ++j )
16861  {
16862  assert(varidx[j] >= -1);
16863  assert(varidx[j] < nexprvars);
16864  if( varidx[j] >= 0 )
16865  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16866  }
16867  }
16868 
16869  exprtreecoefs[*nexprtrees] = quadelems[i].coef;
16870 
16871  ++*nexprtrees;
16872  }
16873 
16874  /* add constant to first summand, if nonzero; need to divide by coef of this exprtree */
16875  if( nodedata->constant != 0.0 )
16876  {
16877  SCIP_EXPR* constexpr_;
16878 
16879  assert(*nexprtrees > 0);
16880  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, nodedata->constant / exprtreecoefs[0]) );
16881  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
16882  }
16883 
16884  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
16885 
16886  break;
16887  }
16888 
16889  case SCIP_EXPR_POLYNOMIAL:
16890  {
16892  SCIP_EXPRDATA_MONOMIAL** monomials;
16893  SCIP_Real constant;
16894  int nmonomials;
16895  SCIP_EXPR* expr;
16896  int* childidxs;
16897  int j;
16898 
16899  nodedata = (SCIP_EXPRDATA_POLYNOMIAL*)node->data.data;
16900  monomials = nodedata->monomials;
16901  nmonomials = nodedata->nmonomials;
16902  constant = nodedata->constant;
16903 
16904  assert(exprtreessize >= nmonomials);
16905  assert(node->nchildren > 0);
16906 
16907  *nexprtrees = 0;
16908 
16909  /* buffer where to store mapping of expression graph variable indices to expression tree variable indices */
16910  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars) );
16911 
16912  for( i = 0; i < nmonomials; ++i )
16913  {
16914  /* initially, no variable appears in the expression tree */
16915  for( j = 0; j < exprgraph->nvars; ++j )
16916  varidx[j] = -1;
16917  nexprvars = 0;
16918 
16919  if( monomials[i]->nfactors == 1 )
16920  {
16921  /* create expression from the subgraph at only factor */
16922  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16923 
16924  /* put exponent in, if not 1.0 */
16925  if( monomials[i]->exponents[0] == 1.0 )
16926  ;
16927  else if( monomials[i]->exponents[0] == 2.0 )
16928  {
16929  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_SQUARE, expr) );
16930  }
16931  else if( EPSISINT(monomials[i]->exponents[0], 0.0) ) /*lint !e835*/
16932  {
16933  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_INTPOWER, expr, (int)monomials[i]->exponents[0]) );
16934  }
16935  else
16936  {
16937  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_REALPOWER, expr, monomials[i]->exponents[0]) );
16938  }
16939  }
16940  else if( monomials[i]->nfactors == 2 && monomials[i]->exponents[0] == 1.0 && monomials[i]->exponents[1] == 1.0 )
16941  {
16942  SCIP_EXPR* expr2;
16943 
16944  /* create expressions for both factors */
16945  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[0]], &expr, &nexprvars, varidx) );
16946  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[1]], &expr2, &nexprvars, varidx) );
16947 
16948  /* create expression for product of factors */
16949  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &expr, SCIP_EXPR_MUL, expr, expr2) );
16950  }
16951  else
16952  {
16953  SCIP_EXPRDATA_MONOMIAL* monomial;
16954  SCIP_EXPR** exprs;
16955  int f;
16956 
16957  /* create expression for each factor, assemble varidx and nexprvars
16958  * create child indices (= identity) */
16959  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors) );
16960  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors) );
16961  for( f = 0; f < monomials[i]->nfactors; ++f )
16962  {
16963  SCIP_CALL( exprgraphNodeCreateExpr(exprgraph, node->children[monomials[i]->childidxs[f]], &exprs[f], &nexprvars, varidx) ); /*lint !e644*/
16964  childidxs[f] = f; /*lint !e644*/
16965  }
16966 
16967  /* create monomial and polynomial expression for this monomial
16968  * add also constant here, but need to divide by monomial coefficient, since we set the exprtreecoefs to monomial coef
16969  */
16970  SCIP_CALL( SCIPexprCreateMonomial(exprgraph->blkmem, &monomial, 1.0, monomials[i]->nfactors, childidxs, monomials[i]->exponents) );
16971  SCIP_CALL( SCIPexprCreatePolynomial(exprgraph->blkmem, &expr, monomials[i]->nfactors, exprs, 1, &monomial, constant / monomials[i]->coef, FALSE) );
16972  constant = 0.0;
16973 
16974  BMSfreeBlockMemoryArray(exprgraph->blkmem, &exprs, monomials[i]->nfactors);
16975  BMSfreeBlockMemoryArray(exprgraph->blkmem, &childidxs, monomials[i]->nfactors);
16976  }
16977 
16978  /* create expression tree for expr */
16979  SCIP_CALL( SCIPexprtreeCreate(exprgraph->blkmem, &exprtrees[*nexprtrees], expr, nexprvars, 0, NULL) );
16980 
16981  /* copy variables into expression tree */
16982  if( nexprvars > 0 )
16983  {
16984  SCIP_ALLOC( BMSallocBlockMemoryArray(exprgraph->blkmem, &exprtrees[*nexprtrees]->vars, nexprvars) );
16985  for( j = 0; j < exprgraph->nvars; ++j )
16986  {
16987  assert(varidx[j] >= -1);
16988  assert(varidx[j] < nexprvars);
16989  if( varidx[j] >= 0 )
16990  exprtrees[*nexprtrees]->vars[varidx[j]] = exprgraph->vars[j];
16991  }
16992  }
16993 
16994  exprtreecoefs[*nexprtrees] = monomials[i]->coef;
16995 
16996  ++*nexprtrees;
16997  }
16998 
16999  /* add constant to first summand, if still nonzero; need to divide by coefficient of the this exprtree */
17000  if( constant != 0.0 )
17001  {
17002  SCIP_EXPR* constexpr_;
17003 
17004  assert(*nexprtrees > 0);
17005  SCIP_CALL( SCIPexprCreate(exprgraph->blkmem, &constexpr_, SCIP_EXPR_CONST, constant / exprtreecoefs[0]) );
17006  SCIP_CALL( SCIPexprtreeAddExpr(exprtrees[0], constexpr_, FALSE) );
17007  }
17008 
17009  BMSfreeBlockMemoryArray(exprgraph->blkmem, &varidx, exprgraph->nvars);
17010 
17011  break;
17012  }
17013 
17014  default:
17015  SCIPerrorMessage("unexpected operator type %d\n", node->op);
17016  return SCIP_ERROR;
17017  } /*lint !e788*/
17018 
17019  return SCIP_OKAY;
17020 }
17021 
17022 /**@} */
void SCIPintervalSignPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
static SCIP_RETCODE exprparseReadVariable(BMS_BLKMEM *blkmem, const char **str, SCIP_EXPR **expr, int *nvars, int **varnames, SCIP_HASHTABLE *vartable, SCIP_Real coefficient, const char *varnameendptr)
Definition: expr.c:4924
#define SCIP_EXPRBOUNDSTATUS_CHILDRELAXED
Definition: type_expr.h:211
void SCIPsortPtrInt(void **ptrarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Real SCIPexprgraphGetNodeVal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13252
SCIP_RETCODE SCIPexprgraphPropagateVarBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop, SCIP_Bool *domainerror)
Definition: expr.c:15756
void SCIPexprFreeDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6158
void SCIPexprtreeGetVarsUsage(SCIP_EXPRTREE *tree, int *varsusage)
Definition: expr.c:8854
SCIP_RETCODE SCIPrandomCreate(SCIP_RANDNUMGEN **randnumgen, BMS_BLKMEM *blkmem, unsigned int initialseed)
Definition: misc.c:8693
void SCIPquadelemSort(SCIP_QUADELEM *quadelems, int nquadelems)
Definition: expr.c:9140
SCIP_RETCODE SCIPexprgraphReplaceVarByLinearSum(SCIP_EXPRGRAPH *exprgraph, void *var, int ncoefs, SCIP_Real *coefs, void **vars, SCIP_Real constant)
Definition: expr.c:15437
void SCIPexprSortMonomials(SCIP_EXPR *expr)
Definition: expr.c:6998
void SCIPintervalSubScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define exprcurvSin
Definition: expr.c:2077
#define QUADELEMS_SWAP(x, y)
Definition: expr.c:9021
void SCIPintervalMax(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:426
SCIP_EXPROPDATA data
Definition: struct_expr.h:51
static void exprgraphSortConstNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:9580
void SCIPexprgraphSetVarNodeValue(SCIP_EXPRGRAPHNODE *varnode, SCIP_Real value)
Definition: expr.c:14893
static SCIP_RETCODE exprgraphNodeAddParent(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9273
SCIP_RETCODE SCIPexprSubstituteVars(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR **substexprs)
Definition: expr.c:8096
static SCIP_RETCODE exprsimplifyConvertToPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4265
SCIP_Bool SCIPintervalIsEmpty(SCIP_Real infinity, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprgraphAddNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int mindepth, int nchildren, SCIP_EXPRGRAPHNODE **children)
Definition: expr.c:15093
void SCIPintervalSign(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define QUADELEMS_ISBETTER(a, b)
Definition: expr.c:9018
static SCIP_RETCODE eval(SCIP_EXPR *expr, const vector< Type > &x, SCIP_Real *param, Type &val)
static SCIP_RETCODE exprsimplifyRemoveDuplicatePolynomialChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps)
Definition: expr.c:4289
SCIP_RETCODE SCIPexprgraphGetSumTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16685
SCIP_RETCODE SCIPexprtreeEvalInt(SCIP_EXPRTREE *tree, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_INTERVAL *val)
Definition: expr.c:8686
SCIP_RETCODE SCIPexprgraphAddVars(SCIP_EXPRGRAPH *exprgraph, int nvars, void **vars, SCIP_EXPRGRAPHNODE **varnodes)
Definition: expr.c:15177
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:8703
int * SCIPexprGetMonomialChildIndices(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5897
SCIP_RETCODE SCIPexprgraphUpdateNodeBoundsCurvature(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool clearreverseprop)
Definition: expr.c:14683
static SCIP_RETCODE polynomialdataMultiplyByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:955
static SCIP_RETCODE exprUnconvertPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren, void **children)
Definition: expr.c:3761
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2253
SCIP_Bool constssorted
Definition: struct_expr.h:174
static SCIP_RETCODE exprgraphNodeAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nexprs, SCIP_EXPRGRAPHNODE **exprs, int *childmap)
Definition: expr.c:9410
int SCIPexprgraphGetNodeNChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12890
static SCIP_RETCODE exprgraphNodeCreateExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPR **expr, int *nexprvars, int *varidx)
Definition: expr.c:11712
SCIP_Real SCIPintervalNegateReal(SCIP_Real x)
SCIP_EXPROP SCIPexprGetOperator(SCIP_EXPR *expr)
Definition: expr.c:5670
#define infinity
Definition: gastrans.c:71
struct SCIP_UserExprData SCIP_USEREXPRDATA
Definition: type_expr.h:219
void SCIPexprPrint(SCIP_EXPR *expr, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, const char **paramnames, SCIP_Real *paramvals)
Definition: expr.c:8176
int SCIPexprgraphGetNVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14863
static SCIP_RETCODE exprgraphEnsureDepth(SCIP_EXPRGRAPH *exprgraph, int mindepth)
Definition: expr.c:11979
void SCIPsortPtrPtrRealInt(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_MAXSTRLEN
Definition: def.h:225
static void polynomialdataSortMonomials(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata)
Definition: expr.c:800
static SCIP_RETCODE exprgraphNodeSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange)
Definition: expr.c:11386
void SCIPsortPtrPtrReal(void **ptrarray1, void **ptrarray2, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_VARTYPE_INTEGER_CHAR
Definition: def.h:117
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
SCIP_Real * exponents
Definition: struct_expr.h:95
#define SCIP_DECL_USEREXPREVAL(x)
Definition: type_expr.h:246
#define SCIP_DECL_USEREXPRPRINT(x)
Definition: type_expr.h:308
int SCIPexprgraphGetDepth(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14833
static SCIP_RETCODE polynomialdataMultiplyByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *factordata, int *childmap)
Definition: expr.c:999
static SCIP_RETCODE exprparseFindSeparatingComma(const char *str, const char **endptr, int length)
Definition: expr.c:5056
static SCIP_RETCODE exprgraphNodeRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11317
const char * SCIPexpropGetName(SCIP_EXPROP op)
Definition: expr.c:3263
void SCIPexprChgPolynomialConstant(SCIP_EXPR *expr, SCIP_Real constant)
Definition: expr.c:6664
SCIP_RETCODE SCIPexprgraphAddConst(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15250
SCIP_RETCODE SCIPexprtreeGetMaxDegree(SCIP_EXPRTREE *tree, int *maxdegree)
Definition: expr.c:8657
SCIP_Real * SCIPexprtreeGetParamVals(SCIP_EXPRTREE *tree)
Definition: expr.c:8579
void SCIPexprgraphSetVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_INTERVAL varbounds)
Definition: expr.c:14937
SCIP_RETCODE SCIPexprCreateMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial, SCIP_Real coef, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:7010
static SCIP_DECL_SORTPTRCOMP(exprgraphnodecomp)
Definition: expr.c:126
void SCIPexprgraphCaptureNode(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12868
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:13381
static SCIP_DECL_EXPRFREEDATA(exprFreeDataLinear)
Definition: expr.c:2540
SCIP_Real SCIPexprGetRealPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5733
SCIP_EXPROP op
Definition: struct_expr.h:48
int SCIPexprGetOpIndex(SCIP_EXPR *expr)
Definition: expr.c:5700
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:7770
SCIP_RETCODE SCIPexprPolynomialPower(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int exponent)
Definition: expr.c:6760
void SCIPexprChgMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real newcoef)
Definition: expr.c:6826
SCIP_Bool SCIPexprHasParam(SCIP_EXPR *expr)
Definition: expr.c:7188
SCIPInterval cos(const SCIPInterval &x)
SCIP_Real SCIPexprGetPolynomialConstant(SCIP_EXPR *expr)
Definition: expr.c:5865
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:15810
#define FALSE
Definition: def.h:64
void SCIPintervalMul(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2764
#define EPSEQ(x, y, eps)
Definition: def.h:170
#define EPSISINT(x, eps)
Definition: def.h:182
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENT
Definition: type_expr.h:212
SCIP_Bool SCIPexprAreEqual(SCIP_EXPR *expr1, SCIP_EXPR *expr2, SCIP_Real eps)
Definition: expr.c:7555
void SCIPexprMonomialPower(SCIP_EXPRDATA_MONOMIAL *monomial, int exponent)
Definition: expr.c:6901
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetVarNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14883
SCIP_Real SCIPrelDiff(SCIP_Real val1, SCIP_Real val2)
Definition: misc.c:9618
static void exprgraphNodeCheckSeparabilityComponent(SCIP_EXPRGRAPHNODE *node, int *compnr, int nchildcomps, int *childcomps, int nvars, int *varcomps)
Definition: expr.c:11919
static SCIP_RETCODE exprgraphNodeRemovePolynomialDuplicateChildren(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:11259
SCIP_Real SCIPexprgraphGetNodeSignPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13019
#define TRUE
Definition: def.h:63
#define SCIPdebug(x)
Definition: pub_message.h:74
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static int calcGrowSize(int num)
Definition: expr.c:106
static SCIP_RETCODE exprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op, int nchildren, SCIP_EXPR **children, SCIP_EXPROPDATA opdata)
Definition: expr.c:3292
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, SCIP_HASHTABLE *vartable, int recursiondepth)
Definition: expr.c:5088
void SCIPsortPtrPtrInt(void **ptrarray1, void **ptrarray2, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPexprtreeCopy(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **targettree, SCIP_EXPRTREE *sourcetree)
Definition: expr.c:8759
int SCIPexprgraphGetNodeNParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12910
void SCIPexprGetVarsUsage(SCIP_EXPR *expr, int *varsusage)
Definition: expr.c:7532
void SCIPintervalMin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
SCIP_INTERVAL SCIPexprgraphGetNodeBounds(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13242
SCIPInterval exp(const SCIPInterval &x)
SCIP_RETCODE SCIPexprgraphEval(SCIP_EXPRGRAPH *exprgraph, SCIP_Real *varvals)
Definition: expr.c:15735
void SCIPexprReindexVars(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8134
void SCIPintervalSetBounds(SCIP_INTERVAL *resultant, SCIP_Real inf, SCIP_Real sup)
#define SCIP_DECL_USEREXPRINTEVAL(x)
Definition: type_expr.h:259
void SCIPintervalPowerScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
int * SCIPexprgraphGetNNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14843
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:82
SCIP_RETCODE SCIPexprEvalInt(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7902
#define EPSGE(x, y, eps)
Definition: def.h:174
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:9380
void SCIPexprSortMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:7091
static void polynomialdataApplyChildmap(SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int *childmap)
Definition: expr.c:1158
#define SCIPdebugMessage
Definition: pub_message.h:77
static SCIP_DECL_EXPRCURV(exprcurvDefault)
Definition: expr.c:1418
SCIP_EXPRDATA_MONOMIAL ** monomials
Definition: struct_expr.h:80
static struct exprOpTableElement exprOpTable[]
Definition: expr.c:3216
#define SIGN(x)
Definition: expr.c:46
#define BMSduplicateBlockMemory(mem, ptr, source)
Definition: memory.h:418
SCIP_RETCODE SCIPexprgraphAddExprtreeSum(SCIP_EXPRGRAPH *exprgraph, int nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *coefs, SCIP_EXPRGRAPHNODE **rootnode, SCIP_Bool *rootnodeisnew)
Definition: expr.c:15297
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2902
SCIP_RETCODE SCIPexprMultiplyMonomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6866
SCIP_RETCODE SCIPexprtreeCreate(BMS_BLKMEM *blkmem, SCIP_EXPRTREE **tree, SCIP_EXPR *root, int nvars, int nparams, SCIP_Real *params)
Definition: expr.c:8718
SCIP_Bool SCIPquadelemSortedFind(SCIP_QUADELEM *quadelems, int idx1, int idx2, int nquadelems, int *pos)
Definition: expr.c:9165
unsigned int SCIP_EXPRINTCAPABILITY
void SCIPexprtreeSetParamVal(SCIP_EXPRTREE *tree, int paramidx, SCIP_Real paramval)
Definition: expr.c:8589
BMS_BLKMEM * blkmem
Definition: struct_expr.h:157
SCIP_EXPRCURV curv
Definition: struct_expr.h:144
SCIP_EXPR * root
Definition: struct_expr.h:58
#define exprevalIntTan
Definition: expr.c:2120
SCIP_RETCODE SCIPexprgraphFree(SCIP_EXPRGRAPH **exprgraph)
Definition: expr.c:15044
void SCIPintervalDiv(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
int SCIPexprgraphGetNodePolynomialNMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13113
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:9951
#define SCIP_EXPRESSION_MAXCHILDEST
Definition: expr.c:39
static void exprgraphUpdateVarNodeBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_Bool *clearreverseprop, SCIP_Bool *boundchanged)
Definition: expr.c:12755
void SCIPintervalSolveUnivariateQuadExpression(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL rhs)
SCIP_RETCODE SCIPexprgraphMoveNodeParents(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **srcnode, SCIP_EXPRGRAPHNODE *targetnode)
Definition: expr.c:14317
SCIP_EXPRCURV SCIPexprcurvMonomial(int nfactors, SCIP_Real *exponents, int *factoridxs, SCIP_EXPRCURV *factorcurv, SCIP_INTERVAL *factorbounds)
Definition: expr.c:361
SCIP_EXPRDATA_MONOMIAL ** SCIPexprGetMonomials(SCIP_EXPR *expr)
Definition: expr.c:5841
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2014
static SCIP_DECL_EXPREVAL(exprevalVar)
Definition: expr.c:1427
public methods for expressions, expression trees, expression graphs, and related stuff ...
SCIP_EXPRCURV SCIPexprcurvMultiply(SCIP_Real factor, SCIP_EXPRCURV curvature)
Definition: expr.c:240
int SCIPexprGetMonomialNFactors(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5887
int SCIPexprGetIntPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5744
void SCIPintervalSin(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2996
#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:8950
SCIP_EXPROP SCIPexprgraphGetNodeOperator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12950
static SCIP_RETCODE exprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op, SCIP_EXPROPDATA opdata)
Definition: expr.c:9651
SCIP_EXPRDATA_MONOMIAL ** SCIPexprgraphGetNodePolynomialMonomials(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13101
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:15005
#define SCIP_ALLOC_ABORT(x)
Definition: def.h:306
#define SCIP_DECL_EXPRGRAPHVARADDED(x)
Definition: type_expr.h:181
SCIP_HASHMAP * varidxs
Definition: struct_expr.h:169
int SCIPexprgraphGetNodeOperatorIndex(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12960
void SCIPrandomFree(SCIP_RANDNUMGEN **randnumgen)
Definition: misc.c:8710
SCIP_Real coef
Definition: type_expr.h:102
SCIP_Real inf
Definition: intervalarith.h:39
const char * SCIPexprcurvGetName(SCIP_EXPRCURV curv)
Definition: expr.c:474
static const NodeData nodedata[]
Definition: gastrans.c:74
SCIP_Real SCIPexprgraphGetNodeLinearConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13041
#define ensureBlockMemoryArraySize3(blkmem, array1, array2, array3, cursize, minsize)
Definition: expr.c:87
SCIP_Real * params
Definition: struct_expr.h:62
#define BMSduplicateBlockMemoryArray(mem, ptr, source, num)
Definition: memory.h:420
SCIP_Real SCIPexprgraphGetNodePolynomialConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13125
SCIP_RETCODE SCIPexprAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:6642
SCIP_Bool SCIPexprgraphHasNodeNonlinearAncestor(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14568
SCIP_EXPRCURV SCIPexprgraphGetNodeCurvature(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13262
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:6559
SCIP_Bool SCIPexprgraphFindConstNode(SCIP_EXPRGRAPH *exprgraph, SCIP_Real constant, SCIP_EXPRGRAPHNODE **constnode)
Definition: expr.c:15638
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:7841
void SCIPexprgraphSetVarsBounds(SCIP_EXPRGRAPH *exprgraph, SCIP_INTERVAL *varbounds)
Definition: expr.c:14905
union SCIP_ExprOpData SCIP_EXPROPDATA
Definition: type_expr.h:90
static SCIP_Bool isUbBetter(SCIP_Real minstrength, SCIP_Real newub, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:169
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:106
SCIP_RETCODE SCIPexprgraphCheckCurvature(SCIP_EXPRGRAPH *exprgraph, SCIP_Real infinity, SCIP_Bool clearreverseprop)
Definition: expr.c:15842
SCIP_RETCODE SCIPexprGetMaxDegree(SCIP_EXPR *expr, int *maxdegree)
Definition: expr.c:7207
static void polynomialdataMultiplyByConstant(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_Real factor)
Definition: expr.c:925
#define SCIPerrorMessage
Definition: pub_message.h:45
enum SCIP_ExprOp SCIP_EXPROP
Definition: type_expr.h:89
interval arithmetics for provable bounds
#define SCIPdebugPrintf
Definition: pub_message.h:80
void SCIPintervalSetEmpty(SCIP_INTERVAL *resultant)
SCIP_RETCODE SCIPexprgraphCreateNodeUser(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_USEREXPRDATA *data, SCIP_EXPRINTCAPABILITY evalcapability, SCIP_DECL_USEREXPREVAL((*eval)), SCIP_DECL_USEREXPRINTEVAL((*inteval)), SCIP_DECL_USEREXPRCURV((*curv)), SCIP_DECL_USEREXPRPROP((*prop)), SCIP_DECL_USEREXPRESTIMATE((*estimate)), SCIP_DECL_USEREXPRCOPYDATA((*copydata)), SCIP_DECL_USEREXPRFREEDATA((*freedata)), SCIP_DECL_USEREXPRPRINT((*print)))
Definition: expr.c:13451
void SCIPsortPtrRealInt(void **ptrarray, SCIP_Real *realarray, int *intarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_Real * SCIPexprGetQuadLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5817
SCIP_EXPRGRAPHNODE *** SCIPexprgraphGetNodes(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14853
int SCIPexprgraphGetSumTreesNSummands(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:16649
SCIP_INTERVAL bounds
Definition: struct_expr.h:137
static SCIP_RETCODE exprsimplifyRemovePolynomialNullChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4343
void SCIPintervalLog(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_RETCODE SCIPexprCopyDeep(BMS_BLKMEM *blkmem, SCIP_EXPR **targetexpr, SCIP_EXPR *sourceexpr)
Definition: expr.c:6116
static const char * curvnames[4]
Definition: expr.c:194
SCIPInterval sqrt(const SCIPInterval &x)
SCIP_Bool SCIPexprgraphHasNodeUserEstimator(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13230
static SCIP_DECL_EXPRCOPYDATA(exprCopyDataLinear)
Definition: expr.c:2522
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
static SCIP_RETCODE quadraticdataCreate(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_QUADRATIC **quadraticdata, SCIP_Real constant, int nchildren, SCIP_Real *lincoefs, int nquadelems, SCIP_QUADELEM *quadelems)
Definition: expr.c:490
SCIPInterval sign(const SCIPInterval &x)
SCIP_EXPRCURV SCIPexprcurvPower(SCIP_INTERVAL basebounds, SCIP_EXPRCURV basecurv, SCIP_Real exponent)
Definition: expr.c:253
SCIP_Real SCIPexprGetQuadConstant(SCIP_EXPR *expr)
Definition: expr.c:5804
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2797
static SCIP_RETCODE exprgraphNodeReplaceChild(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE **oldchild, SCIP_EXPRGRAPHNODE *newchild)
Definition: expr.c:9511
void SCIPmessagePrintWarning(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:417
SCIP_EXPRGRAPHNODE *** nodes
Definition: struct_expr.h:162
#define EXPROPEMPTY
Definition: expr.c:3212
#define NULL
Definition: lpi_spx1.cpp:137
static SCIP_Bool exprgraphNodeIsParent(SCIP_EXPRGRAPHNODE *node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9379
static void polynomialdataFree(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata)
Definition: expr.c:712
#define REALABS(x)
Definition: def.h:169
void SCIPexprMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:6780
int SCIPexprtreeGetNVars(SCIP_EXPRTREE *tree)
Definition: expr.c:8559
SCIP_Bool SCIPexprAreMonomialsEqual(SCIP_EXPRDATA_MONOMIAL *monomial1, SCIP_EXPRDATA_MONOMIAL *monomial2, SCIP_Real eps)
Definition: expr.c:6795
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:13355
SCIP_RETCODE SCIPexprgraphGetSeparableTrees(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int exprtreessize, int *nexprtrees, SCIP_EXPRTREE **exprtrees, SCIP_Real *exprtreecoefs)
Definition: expr.c:16199
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
#define SCIP_CALL(x)
Definition: def.h:316
SCIP_Bool SCIPexprgraphIsNodeEnabled(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12880
SCIP_INTERVAL * SCIPexprgraphGetVarsBounds(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14997
SCIP_RETCODE SCIPexprParse(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR **expr, const char *str, const char *lastchar, int *nvars, int *varnames)
Definition: expr.c:8488
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:6607
SCIP_RETCODE SCIPexprCheckCurvature(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *varbounds, SCIP_Real *param, SCIP_EXPRCURV *curv, SCIP_INTERVAL *bounds)
Definition: expr.c:8000
SCIP_RETCODE SCIPexprEvalUser(SCIP_EXPR *expr, SCIP_Real *argvals, SCIP_Real *val, SCIP_Real *gradient, SCIP_Real *hessian)
Definition: expr.c:7944
SCIP_Real sup
Definition: intervalarith.h:40
void SCIPmessagePrintInfo(SCIP_MESSAGEHDLR *messagehdlr, const char *formatstr,...)
Definition: message.c:584
SCIP_RETCODE SCIPexprEvalShallow(SCIP_EXPR *expr, SCIP_Real *argvals, SCIP_Real *varvals, SCIP_Real *param, SCIP_Real *val)
Definition: expr.c:7822
void SCIPexprMultiplyPolynomialByConstant(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real factor)
Definition: expr.c:6677
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:14621
static SCIP_RETCODE exprsimplifyUnconvertPolynomials(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4890
SCIP_RETCODE SCIPexprEstimateUser(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_Real *argvals, SCIP_INTERVAL *argbounds, SCIP_Bool overestimate, SCIP_Real *coeffs, SCIP_Real *constant, SCIP_Bool *success)
Definition: expr.c:8058
static SCIP_RETCODE exprgraphNodeUpdateBounds(SCIP_EXPRGRAPHNODE *node, SCIP_Real infinity, SCIP_Real minstrength, SCIP_Bool parenttightenisinvalid)
Definition: expr.c:10058
#define SCIP_DECL_USEREXPRCURV(x)
Definition: type_expr.h:270
void SCIPexprFreeMonomial(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL **monomial)
Definition: expr.c:7067
SCIP_RETCODE SCIPexprMulConstant(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPR *term, SCIP_Real factor)
Definition: expr.c:6379
SCIP_EXPR * SCIPexprtreeGetRoot(SCIP_EXPRTREE *tree)
Definition: expr.c:8549
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:7128
SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
SCIP_Bool SCIPexprgraphHasNodeSibling(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14533
SCIP_RETCODE SCIPexprgraphGetNodePolynomialMonomialCurvature(SCIP_EXPRGRAPHNODE *node, int monomialidx, SCIP_Real infinity, SCIP_EXPRCURV *curv)
Definition: expr.c:13140
#define SCIP_DECL_USEREXPRESTIMATE(x)
Definition: type_expr.h:234
#define SCIP_DECL_USEREXPRPROP(x)
Definition: type_expr.h:282
SCIP_Real SCIPexprgraphGetNodeOperatorReal(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12971
#define SCIP_EXPRBOUNDSTATUS_VALID
Definition: type_expr.h:209
SCIP_RETCODE SCIPexprAdd(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_Real coef1, SCIP_EXPR *term1, SCIP_Real coef2, SCIP_EXPR *term2, SCIP_Real constant)
Definition: expr.c:6221
SCIP_Real SCIPexprgraphGetNodeQuadraticConstant(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13053
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:423
SCIP_RETCODE SCIPexprMultiplyPolynomialByPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPR *factor, int *childmap)
Definition: expr.c:6714
void SCIPexprMergeMonomialFactors(SCIP_EXPRDATA_MONOMIAL *monomial, SCIP_Real eps)
Definition: expr.c:6931
void SCIPintervalCos(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
SCIP_EXPRINTCAPABILITY SCIPexprGetUserEvalCapability(SCIP_EXPR *expr)
Definition: expr.c:5939
public data structures and miscellaneous methods
static void polynomialdataMergeMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, SCIP_Real eps, SCIP_Bool mergefactors)
Definition: expr.c:833
SCIP_EXPR ** SCIPexprGetChildren(SCIP_EXPR *expr)
Definition: expr.c:5690
SCIP_Real SCIPexprGetSignPowerExponent(SCIP_EXPR *expr)
Definition: expr.c:5755
SCIP_EXPRGRAPHNODE ** children
Definition: struct_expr.h:128
#define SCIP_Bool
Definition: def.h:61
void ** vars
Definition: struct_expr.h:60
SCIP_Bool needvarboundprop
Definition: struct_expr.h:181
static SCIP_RETCODE exprgraphNodeEval(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:9993
SCIP_USEREXPRDATA * userdata
Definition: struct_expr.h:103
SCIP_Bool SCIPexprgraphAreAllNodeChildrenVars(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14552
SCIPInterval sin(const SCIPInterval &x)
#define BMSallocBlockMemoryArray(mem, ptr, num)
Definition: memory.h:412
void SCIPexprSortQuadElems(SCIP_EXPR *expr)
Definition: expr.c:6595
static SCIP_RETCODE monomialdataEnsureFactorsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomialdata, int minsize)
Definition: expr.c:603
void SCIPexprgraphSetVarNodeLb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real lb)
Definition: expr.c:14957
static SCIP_RETCODE exprsimplifyFlattenPolynomials(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPR *expr, SCIP_Real eps, int maxexpansionexponent)
Definition: expr.c:4460
static SCIP_RETCODE exprgraphNodeRemoveParent(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node, SCIP_EXPRGRAPHNODE *parent)
Definition: expr.c:9328
BMS_BLKMEM * blkmem
Definition: struct_expr.h:57
SCIP_EXPRINTDATA * SCIPexprtreeGetInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8604
SCIP_RETCODE SCIPexprtreeFreeInterpreterData(SCIP_EXPRTREE *tree)
Definition: expr.c:8627
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:425
void SCIPquadelemSqueeze(SCIP_QUADELEM *quadelems, int nquadelems, int *nquadelemsnew)
Definition: expr.c:9217
SCIP_Bool SCIPexprHasUserEstimator(SCIP_EXPR *expr)
Definition: expr.c:5928
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_Bool SCIPstrToRealValue(const char *str, SCIP_Real *value, char **endptr)
Definition: misc.c:9411
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:5680
void SCIPexprgraphGetSubtreeVarsUsage(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:16633
void SCIPexprgraphSetVarNodeUb(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *varnode, SCIP_Real ub)
Definition: expr.c:14977
static SCIP_Bool exprgraphFindConstNodePos(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int *pos)
Definition: expr.c:9596
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:13505
SCIP_RETCODE SCIPexprCreate(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, SCIP_EXPROP op,...)
Definition: expr.c:5950
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:8799
SCIP_Bool SCIPexprFindMonomialFactor(SCIP_EXPRDATA_MONOMIAL *monomial, int childidx, int *pos)
Definition: expr.c:7111
static SCIP_DECL_EXPRINTEVAL(exprevalIntDefault)
Definition: expr.c:1409
#define EPSLE(x, y, eps)
Definition: def.h:172
void SCIPexprgraphFreeNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14443
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:10152
#define SCIP_EXPRBOUNDSTATUS_CHILDTIGHTENED
Definition: type_expr.h:210
void SCIPexprgraphDisableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14495
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:93
SCIPInterval log(const SCIPInterval &x)
SCIP_USEREXPRDATA * SCIPexprGetUserData(SCIP_EXPR *expr)
Definition: expr.c:5917
SCIP_RETCODE SCIPexprtreeAddExpr(SCIP_EXPRTREE *tree, SCIP_EXPR *expr, SCIP_Bool copyexpr)
Definition: expr.c:8927
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2314
#define SCIP_EXPR_DEGREEINFINITY
Definition: type_expr.h:114
SCIP_EXPROPDATA data
Definition: struct_expr.h:120
SCIP_EXPRGRAPHNODE ** parents
Definition: struct_expr.h:133
static long * number
void SCIPintervalAbs(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand)
#define BMSclearMemory(ptr)
Definition: memory.h:88
SCIP_Real SCIPexprGetMonomialCoef(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5877
static SCIP_RETCODE polynomialdataCopy(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata, SCIP_EXPRDATA_POLYNOMIAL *sourcepolynomialdata)
Definition: expr.c:675
static SCIP_RETCODE polynomialdataExpandMonomialFactor(BMS_BLKMEM *blkmem, SCIP_MESSAGEHDLR *messagehdlr, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int monomialpos, int factorpos, SCIP_EXPRDATA_POLYNOMIAL *factorpolynomial, int *childmap, int maxexpansionexponent, SCIP_Bool *success)
Definition: expr.c:1187
void * SCIPexprgraphGetNodeVar(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12982
void * SCIPexprGetOpData(SCIP_EXPR *expr)
Definition: expr.c:5722
SCIP_EXPROP op
Definition: struct_expr.h:119
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:8745
SCIP_Real * SCIPexprgraphGetNodeQuadraticLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13065
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2064
#define SCIP_REAL_MAX
Definition: def.h:146
static SCIP_RETCODE exprConvertToPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPROP *op, SCIP_EXPROPDATA *data, int nchildren)
Definition: expr.c:3323
SCIP_RETCODE SCIPexprEvalIntUser(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *val, SCIP_INTERVAL *gradient, SCIP_INTERVAL *hessian)
Definition: expr.c:7967
int SCIPexprgraphGetNodeIntPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13008
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12920
SCIP_QUADELEM * quadelems
Definition: struct_expr.h:71
static void exprgraphNodeSortParents(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:9302
#define EPSLT(x, y, eps)
Definition: def.h:171
#define SCIP_DECL_EXPRGRAPHVARREMOVE(x)
Definition: type_expr.h:191
static SCIP_RETCODE exprgraphAddExpr(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPR *expr, void **vars, SCIP_Real *params, SCIP_EXPRGRAPHNODE **exprnode, SCIP_Bool *exprnodeisnew)
Definition: expr.c:12623
static SCIP_RETCODE polynomialdataAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:758
#define EPSGT(x, y, eps)
Definition: def.h:173
enum SCIP_ExprCurv SCIP_EXPRCURV
Definition: type_expr.h:93
int SCIPexpropGetNChildren(SCIP_EXPROP op)
Definition: expr.c:3273
static void quadraticdataSort(SCIP_EXPRDATA_QUADRATIC *quadraticdata)
Definition: expr.c:528
#define SCIP_VARTYPE_IMPLINT_CHAR
Definition: def.h:118
SCIP_EXPRINTDATA * interpreterdata
Definition: struct_expr.h:63
SCIP_RETCODE SCIPhashmapRemove(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3012
#define exprcurvCos
Definition: expr.c:2105
SCIP_Bool SCIPexprgraphFindVarNode(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_EXPRGRAPHNODE **varnode)
Definition: expr.c:15609
void SCIPexprReindexParams(SCIP_EXPR *expr, int *newindices)
Definition: expr.c:8155
SCIP_Real * SCIPexprgraphGetNodeLinearCoefs(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13030
#define SCIP_EXPRINTCAPABILITY_FUNCVALUE
SCIP_Real * SCIPexprGetLinearCoefs(SCIP_EXPR *expr)
Definition: expr.c:5766
#define DEFAULT_RANDSEED
Definition: expr.c:40
SCIP_Bool SCIPexprtreeHasParam(SCIP_EXPRTREE *tree)
Definition: expr.c:8641
void SCIPintervalSetEntire(SCIP_Real infinity, SCIP_INTERVAL *resultant)
SCIP_Real SCIPexprGetOpReal(SCIP_EXPR *expr)
Definition: expr.c:5711
int SCIPexprgraphGetNodePosition(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12940
static SCIP_Bool isLbBetter(SCIP_Real minstrength, SCIP_Real newlb, SCIP_Real oldlb, SCIP_Real oldub)
Definition: expr.c:149
SCIP_RETCODE SCIPexprgraphNodePolynomialAddMonomials(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE *node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Bool copymonomials)
Definition: expr.c:13432
SCIP_Bool parentssorted
Definition: struct_expr.h:134
#define SCIP_VARTYPE_CONTINUOUS_CHAR
Definition: def.h:119
SCIP_EXPRGRAPHNODE ** constnodes
Definition: struct_expr.h:173
void SCIPexprFreeShallow(BMS_BLKMEM *blkmem, SCIP_EXPR **expr)
Definition: expr.c:6196
SCIP_QUADELEM * SCIPexprGetQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5792
SCIP_RETCODE SCIPexprgraphCreateNodePolynomial(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:13407
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:13218
static SCIP_RETCODE exprsimplifySeparateLinearFromPolynomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_Real eps, int nvars, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:4789
SCIP_RETCODE SCIPexprgraphCreateNode(BMS_BLKMEM *blkmem, SCIP_EXPRGRAPHNODE **node, SCIP_EXPROP op,...)
Definition: expr.c:13272
SCIP_RETCODE SCIPexprEvalIntShallow(SCIP_EXPR *expr, SCIP_Real infinity, SCIP_INTERVAL *argvals, SCIP_INTERVAL *varvals, SCIP_Real *param, SCIP_INTERVAL *val)
Definition: expr.c:7882
SCIP_RETCODE SCIPexprgraphReleaseNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE **node)
Definition: expr.c:14349
int SCIPexprGetNMonomials(SCIP_EXPR *expr)
Definition: expr.c:5853
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTFORCE
Definition: type_expr.h:214
void SCIPmessageFPrintInfo(SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char *formatstr,...)
Definition: message.c:608
SCIP_RETCODE SCIPhashmapSetImage(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2942
SCIP_RETCODE SCIPexprtreeSimplify(SCIP_EXPRTREE *tree, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, int *nlinvars, int *linidxs, SCIP_Real *lincoefs)
Definition: expr.c:8873
SCIP_RETCODE SCIPexprgraphGetTree(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *rootnode, SCIP_EXPRTREE **exprtree)
Definition: expr.c:16146
#define SCIP_DECL_USEREXPRCOPYDATA(x)
Definition: type_expr.h:291
#define SCIP_Real
Definition: def.h:145
#define EPSROUND(x, eps)
Definition: def.h:180
#define MIN(x, y)
Definition: memory.c:75
void SCIPintervalIntersect(SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE polynomialdataCreate(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL **polynomialdata, int nmonomials, SCIP_EXPRDATA_MONOMIAL **monomials, SCIP_Real constant, SCIP_Bool copymonomials)
Definition: expr.c:628
void SCIPintervalMulScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
SCIP_EXPRGRAPHNODE ** SCIPexprgraphGetNodeChildren(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12900
#define SCIP_INVALID
Definition: def.h:165
void SCIPsortPtrReal(void **ptrarray, SCIP_Real *realarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
SCIP_RETCODE SCIPexprAddMonomialFactors(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_MONOMIAL *monomial, int nfactors, int *childidxs, SCIP_Real *exponents)
Definition: expr.c:6837
SCIP_Real * SCIPexprGetMonomialExponents(SCIP_EXPRDATA_MONOMIAL *monomial)
Definition: expr.c:5907
void SCIPexprgraphPrintNode(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file)
Definition: expr.c:14605
SCIP_RETCODE SCIPexprtreeSubstituteVars(SCIP_EXPRTREE *tree, SCIP_EXPR **substexprs)
Definition: expr.c:8976
#define SCIPisFinite(x)
Definition: pub_misc.h:1607
static SCIP_RETCODE exprgraphNodeEvalWithChildren(SCIP_EXPRGRAPHNODE *node, SCIP_Real *varvals)
Definition: expr.c:10037
#define SCIP_VARTYPE_BINARY_CHAR
Definition: def.h:116
int SCIPexprtreeGetNParams(SCIP_EXPRTREE *tree)
Definition: expr.c:8569
SCIP_RETCODE SCIPexprgraphSimplify(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, SCIP_Real eps, int maxexpansionexponent, SCIP_Bool *havechange, SCIP_Bool *domainerror)
Definition: expr.c:15885
int SCIP_ROUNDMODE
Definition: intervalarith.h:46
static SCIP_RETCODE exprsimplifyRemovePolynomialUnusedChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr)
Definition: expr.c:4409
#define exprcurvTan
Definition: expr.c:2123
void SCIPintervalSub(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_INTERVAL operand2)
static SCIP_RETCODE exprgraphMoveNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node, int newdepth)
Definition: expr.c:12059
static SCIP_RETCODE exprparseFindClosingParenthesis(const char *str, const char **endptr, int length)
Definition: expr.c:5017
SCIP_RETCODE SCIPexprAddToLinear(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nchildren, SCIP_Real *coefs, SCIP_EXPR **children, SCIP_Real constant)
Definition: expr.c:6514
static SCIP_RETCODE exprsimplifyAddChildren(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, int nexprs, SCIP_EXPR **exprs, SCIP_Bool comparechildren, SCIP_Real eps, int *childmap)
Definition: expr.c:4146
#define nnodes
Definition: gastrans.c:65
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:410
SCIP_RETCODE SCIPexprMultiplyPolynomialByMonomial(BMS_BLKMEM *blkmem, SCIP_EXPR *expr, SCIP_EXPRDATA_MONOMIAL *factor, int *childmap)
Definition: expr.c:6691
SCIP_Real SCIPexprgraphGetNodeRealPowerExponent(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:12997
SCIP_RETCODE SCIPexprintFreeData(SCIP_EXPRINTDATA **interpreterdata)
#define EPSFLOOR(x, eps)
Definition: def.h:178
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2845
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:89
static SCIP_DECL_HASHGETKEY(exprparseVarTableGetKey)
Definition: expr.c:4914
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:396
int SCIPexprgraphGetNodeQuadraticNQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13089
static SCIP_RETCODE polynomialdataPower(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int exponent)
Definition: expr.c:1088
#define SCIP_CALL_ABORT(x)
Definition: def.h:295
void ** SCIPexprgraphGetVars(SCIP_EXPRGRAPH *exprgraph)
Definition: expr.c:14873
#define SCIP_EXPRBOUNDSTATUS_TIGHTENEDBYPARENTRECENT
Definition: type_expr.h:213
SCIP_RETCODE SCIPexprCreateLinear(BMS_BLKMEM *blkmem, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real *coefs, SCIP_Real constant)
Definition: expr.c:6477
void SCIPintervalAddScalar(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_INTERVAL operand1, SCIP_Real operand2)
#define SCIP_ALLOC(x)
Definition: def.h:327
#define SCIPABORT()
Definition: def.h:288
SCIP_Real SCIPexprGetLinearConstant(SCIP_EXPR *expr)
Definition: expr.c:5779
void SCIPexprtreeSetInterpreterData(SCIP_EXPRTREE *tree, SCIP_EXPRINTDATA *interpreterdata)
Definition: expr.c:8614
SCIP_EXPRCURV SCIPexprcurvAdd(SCIP_EXPRCURV curv1, SCIP_EXPRCURV curv2)
Definition: expr.c:205
struct SCIP_ExprIntData SCIP_EXPRINTDATA
static void quadelemsQuickSort(SCIP_QUADELEM *elems, int start, int end)
Definition: expr.c:9030
static SCIP_RETCODE polynomialdataEnsureMonomialsSize(BMS_BLKMEM *blkmem, SCIP_EXPRDATA_POLYNOMIAL *polynomialdata, int minsize)
Definition: expr.c:741
SCIP_RETCODE SCIPexprtreeSetParams(SCIP_EXPRTREE *tree, int nparams, SCIP_Real *paramvals)
Definition: expr.c:8823
SCIP_ROUNDMODE SCIPintervalGetRoundingMode(void)
int SCIPexprGetNQuadElements(SCIP_EXPR *expr)
Definition: expr.c:5829
static void exprgraphPrintNodeExpression(SCIP_EXPRGRAPHNODE *node, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames, SCIP_Bool printchildrenbounds)
Definition: expr.c:9695
#define SCIP_DECL_USEREXPRFREEDATA(x)
Definition: type_expr.h:299
static SCIP_RETCODE exprgraphFindParentByOperator(SCIP_EXPRGRAPH *exprgraph, int nchildren, SCIP_EXPRGRAPHNODE **children, SCIP_EXPROP op, SCIP_EXPROPDATA opdata, SCIP_EXPR **exprchildren, SCIP_EXPRGRAPHNODE **parent)
Definition: expr.c:12155
static void exprgraphNodeGetVarsUsage(SCIP_EXPRGRAPHNODE *node, int *varsusage)
Definition: expr.c:11894
SCIP_RETCODE SCIPexprgraphPrintDot(SCIP_EXPRGRAPH *exprgraph, SCIP_MESSAGEHDLR *messagehdlr, FILE *file, const char **varnames)
Definition: expr.c:15686
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:416
void SCIPintervalSetRoundingModeDownwards(void)
#define EPSZ(x, eps)
Definition: def.h:175
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:12930
#define ensureBlockMemoryArraySize(blkmem, array1, cursize, minsize)
Definition: expr.c:52
SCIP_EXPRCURV SCIPexprcurvNegate(SCIP_EXPRCURV curvature)
Definition: expr.c:214
SCIP_RETCODE SCIPexprtreeEval(SCIP_EXPRTREE *tree, SCIP_Real *varvals, SCIP_Real *val)
Definition: expr.c:8670
SCIP_EXPRINTCAPABILITY evalcapability
Definition: struct_expr.h:104
void SCIPexprgraphSetVarBounds(SCIP_EXPRGRAPH *exprgraph, void *var, SCIP_INTERVAL varbounds)
Definition: expr.c:14917
void SCIPsortIntReal(int *intarray, SCIP_Real *realarray, int len)
static SCIP_RETCODE exprgraphRemoveVar(SCIP_EXPRGRAPH *exprgraph, int varidx)
Definition: expr.c:12006
#define SCIP_DECL_EXPRGRAPHVARCHGIDX(x)
Definition: type_expr.h:203
void SCIPintervalQuad(SCIP_Real infinity, SCIP_INTERVAL *resultant, SCIP_Real sqrcoeff, SCIP_INTERVAL lincoeff, SCIP_INTERVAL xrng)
void SCIPexprgraphEnableNode(SCIP_EXPRGRAPH *exprgraph, SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:14468
SCIP_QUADELEM * SCIPexprgraphGetNodeQuadraticQuadElements(SCIP_EXPRGRAPHNODE *node)
Definition: expr.c:13077